/*
- * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2008 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
#ifdef __APPLE__
void gifattach(void);
-static void gif_create_dev(void);
static int gif_encapcheck(const struct mbuf*, int, int, void*);
static errno_t gif_output(ifnet_t ifp, mbuf_t m);
static errno_t gif_input(ifnet_t ifp, protocol_family_t protocol_family,
mbuf_t m, char *frame_header);
-static errno_t gif_ioctl(ifnet_t ifp, u_int32_t cmd, void *data);
+static errno_t gif_ioctl(ifnet_t ifp, u_long cmd, void *data);
int ngif = 0; /* number of interfaces */
#endif
};
#endif
+static if_clone_t gif_cloner = NULL;
+static int gif_clone_create(struct if_clone *, uint32_t, void *);
+static int gif_clone_destroy(struct ifnet *);
+static void gif_delete_tunnel(struct gif_softc *);
+
#ifdef __APPLE__
/*
* Theory of operation: initially, one gif interface is created.
gifattach(void)
{
errno_t result;
+ struct ifnet_clone_params ifnet_clone_params;
+ struct if_clone *ifc = NULL;
/* Init the list of interfaces */
TAILQ_INIT(&gifs);
if (result != 0)
printf("proto_register_plumber failed for AF_INET6 error=%d\n", result);
+ ifnet_clone_params.ifc_name = "gif";
+ ifnet_clone_params.ifc_create = gif_clone_create;
+ ifnet_clone_params.ifc_destroy = gif_clone_destroy;
+
+ result = ifnet_clone_attach(&ifnet_clone_params, &gif_cloner);
+ if (result != 0)
+ printf("gifattach: ifnet_clone_attach failed %d\n", result);
+
/* Create first device */
- gif_create_dev();
+ ifc = if_clone_lookup("gif", NULL);
+ gif_clone_create(ifc, 0, NULL);
}
static errno_t
return 0;
}
-/* Creates another gif device if there are none free */
-static void
-gif_create_dev(void)
+
+static int
+gif_clone_create(struct if_clone *ifc, uint32_t unit, __unused void *params)
{
- struct gif_softc *sc;
- struct ifnet_init_params gif_init;
- errno_t result = 0;
-
-
+ struct gif_softc *sc = NULL;
+ struct ifnet_init_params gif_init;
+ errno_t result = 0;
+
/* Can't create more than GIF_MAXUNIT */
if (ngif >= GIF_MAXUNIT)
- return;
-
- /* Check for unused gif interface */
- TAILQ_FOREACH(sc, &gifs, gif_link) {
- /* If unused, return, no need to create a new interface */
- if ((ifnet_flags(sc->gif_if) & IFF_RUNNING) == 0)
- return;
- }
+ return (ENXIO);
sc = _MALLOC(sizeof(struct gif_softc), M_DEVBUF, M_WAITOK);
if (sc == NULL) {
- log(LOG_ERR, "gifattach: failed to allocate gif%d\n", ngif);
- return;
+ log(LOG_ERR, "gif_clone_create: failed to allocate gif%d\n", unit);
+ return ENOBUFS;
}
-
+ bzero(sc, sizeof(struct gif_softc));
+
+ /* use the interface name as the unique id for ifp recycle */
+ snprintf(sc->gif_ifname, sizeof(sc->gif_ifname), "%s%d",
+ ifc->ifc_name, unit);
+
bzero(&gif_init, sizeof(gif_init));
+ gif_init.uniqueid = sc->gif_ifname;
+ gif_init.uniqueid_len = strlen(sc->gif_ifname);
gif_init.name = GIFNAME;
- gif_init.unit = ngif;
+ gif_init.unit = unit;
gif_init.type = IFT_GIF;
gif_init.family = IFNET_FAMILY_GIF;
gif_init.output = gif_output;
gif_init.ioctl = gif_ioctl;
gif_init.set_bpf_tap = gif_set_bpf_tap;
- bzero(sc, sizeof(struct gif_softc));
result = ifnet_allocate(&gif_init, &sc->gif_if);
if (result != 0) {
- printf("gif_create_dev, ifnet_allocate failed - %d\n", result);
+ printf("gif_clone_create, ifnet_allocate failed - %d\n", result);
_FREE(sc, M_DEVBUF);
- return;
+ return ENOBUFS;
}
+
sc->encap_cookie4 = sc->encap_cookie6 = NULL;
#if INET
sc->encap_cookie4 = encap_attach_func(AF_INET, -1,
- gif_encapcheck, &in_gif_protosw, sc);
+ gif_encapcheck, &in_gif_protosw, sc);
if (sc->encap_cookie4 == NULL) {
printf("%s: unable to attach encap4\n", if_name(sc->gif_if));
ifnet_release(sc->gif_if);
FREE(sc, M_DEVBUF);
- return;
+ return ENOBUFS;
}
#endif
#if INET6
printf("%s: unable to attach encap6\n", if_name(sc->gif_if));
ifnet_release(sc->gif_if);
FREE(sc, M_DEVBUF);
- return;
+ return ENOBUFS;
}
#endif
sc->gif_called = 0;
#endif
result = ifnet_attach(sc->gif_if, NULL);
if (result != 0) {
- printf("gif_create_dev - ifnet_attach failed - %d\n", result);
+ printf("gif_clone_create - ifnet_attach failed - %d\n", result);
ifnet_release(sc->gif_if);
+ if (sc->encap_cookie4) {
+ encap_detach(sc->encap_cookie4);
+ sc->encap_cookie4 = NULL;
+ }
+ if (sc->encap_cookie6) {
+ encap_detach(sc->encap_cookie6);
+ sc->encap_cookie6 = NULL;
+ }
FREE(sc, M_DEVBUF);
- return;
+ return result;
}
#if CONFIG_MACF_NET
mac_ifnet_label_init(&sc->gif_if);
bpfattach(sc->gif_if, DLT_NULL, sizeof(u_int));
TAILQ_INSERT_TAIL(&gifs, sc, gif_link);
ngif++;
+ return 0;
+}
+
+static int
+gif_clone_destroy(struct ifnet *ifp)
+{
+#if defined(INET) || defined(INET6)
+ int err = 0;
+#endif
+ struct gif_softc *sc = ifp->if_softc;
+
+ TAILQ_REMOVE(&gifs, sc, gif_link);
+
+ gif_delete_tunnel(sc);
+#ifdef INET6
+ if (sc->encap_cookie6 != NULL) {
+ err = encap_detach(sc->encap_cookie6);
+ KASSERT(err == 0, ("gif_clone_destroy: Unexpected error detaching encap_cookie6"));
+ }
+#endif
+#ifdef INET
+ if (sc->encap_cookie4 != NULL) {
+ err = encap_detach(sc->encap_cookie4);
+ KASSERT(err == 0, ("gif_clone_destroy: Unexpected error detaching encap_cookie4"));
+ }
+#endif
+ err = ifnet_set_flags(ifp, 0, IFF_UP);
+ if (err != 0) {
+ printf("gif_clone_destroy: ifnet_set_flags failed %d\n", err);
+ }
+
+ err = ifnet_detach(ifp);
+ if (err != 0)
+ panic("gif_clone_destroy: ifnet_detach(%p) failed %d\n", ifp, err);
+ FREE(sc, M_DEVBUF);
+ ngif--;
+ return 0;
}
static int
return 0;
}
- mbuf_copydata(m, 0, sizeof(ip), &ip);
+ mbuf_copydata((struct mbuf *)(size_t)m, 0, sizeof(ip), &ip);
switch (ip.ip_v) {
#if INET
mbuf_t m,
__unused char *frame_header)
{
- errno_t error;
struct gif_softc *sc = ifnet_softc(ifp);
bpf_tap_in(ifp, 0, m, &sc->gif_proto, sizeof(sc->gif_proto));
* it occurs more times than we thought, we may change the policy
* again.
*/
- error = proto_input(protocol_family, m);
- ifnet_stat_increment_in(ifp, 1, m->m_pkthdr.len, 0);
+ if (proto_input(protocol_family, m) != 0) {
+ ifnet_stat_increment_in(ifp, 0, 0, 1);
+ m_freem(m);
+ } else
+ ifnet_stat_increment_in(ifp, 1, m->m_pkthdr.len, 0);
return (0);
}
static errno_t
gif_ioctl(
ifnet_t ifp,
- u_int32_t cmd,
+ u_long cmd,
void *data)
{
struct gif_softc *sc = ifnet_softc(ifp);
struct sockaddr *sa;
struct ifnet *ifp2;
struct gif_softc *sc2;
-
+
switch (cmd) {
case SIOCSIFADDR:
break;
-
+
case SIOCSIFDSTADDR:
break;
case SIOCSIFMTU:
{
- u_long mtu;
+ u_int32_t mtu;
mtu = ifr->ifr_mtu;
if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX) {
return (EINVAL);
case SIOCSIFPHYADDR:
#if INET6
- case SIOCSIFPHYADDR_IN6:
+ case SIOCSIFPHYADDR_IN6_32:
+ case SIOCSIFPHYADDR_IN6_64:
#endif /* INET6 */
case SIOCSLIFPHYADDR:
switch (cmd) {
break;
#endif
#if INET6
- case SIOCSIFPHYADDR_IN6:
- src = (struct sockaddr *)
- &(((struct in6_aliasreq *)data)->ifra_addr);
- dst = (struct sockaddr *)
- &(((struct in6_aliasreq *)data)->ifra_dstaddr);
+ case SIOCSIFPHYADDR_IN6_32: {
+ struct in6_aliasreq_32 *ifra_32 =
+ (struct in6_aliasreq_32 *)data;
+
+ src = (struct sockaddr *)&ifra_32->ifra_addr;
+ dst = (struct sockaddr *)&ifra_32->ifra_dstaddr;
+ break;
+ }
+
+ case SIOCSIFPHYADDR_IN6_64: {
+ struct in6_aliasreq_64 *ifra_64 =
+ (struct in6_aliasreq_64 *)data;
+
+ src = (struct sockaddr *)&ifra_64->ifra_addr;
+ dst = (struct sockaddr *)&ifra_64->ifra_dstaddr;
break;
+ }
#endif
case SIOCSLIFPHYADDR:
src = (struct sockaddr *)
break;
return EAFNOSUPPORT;
#if INET6
- case SIOCSIFPHYADDR_IN6:
+ case SIOCSIFPHYADDR_IN6_32:
+ case SIOCSIFPHYADDR_IN6_64:
if (src->sa_family == AF_INET6)
break;
return EAFNOSUPPORT;
if (sc->gif_psrc)
FREE((caddr_t)sc->gif_psrc, M_IFADDR);
sa = (struct sockaddr *)_MALLOC(src->sa_len, M_IFADDR, M_WAITOK);
+ if (sa == NULL)
+ return ENOBUFS;
bcopy((caddr_t)src, (caddr_t)sa, src->sa_len);
sc->gif_psrc = sa;
if (sc->gif_pdst)
FREE((caddr_t)sc->gif_pdst, M_IFADDR);
sa = (struct sockaddr *)_MALLOC(dst->sa_len, M_IFADDR, M_WAITOK);
+ if (sa == NULL)
+ return ENOBUFS;
bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len);
sc->gif_pdst = sa;
ifnet_set_flags(ifp, IFF_RUNNING | IFF_UP, IFF_RUNNING | IFF_UP);
-#ifdef __APPLE__
- /* Make sure at least one unused device is still available */
- gif_create_dev();
-#endif
-
error = 0;
break;
return error;
}
-#ifndef __APPLE__
/* This function is not used in our stack */
void
gif_delete_tunnel(sc)
}
/* change the IFF_UP flag as well? */
}
-#endif