X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/43866e378188c25dd1e2208016ab3cbeb086ae6c..593a1d5fd87cdf5b46dd5fcb84467b432cea0f91:/bsd/net/ether_inet_pr_module.c diff --git a/bsd/net/ether_inet_pr_module.c b/bsd/net/ether_inet_pr_module.c index f181de956..f0b0f5b54 100644 --- a/bsd/net/ether_inet_pr_module.c +++ b/bsd/net/ether_inet_pr_module.c @@ -1,16 +1,19 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2007 Apple Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ - * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER @@ -20,7 +23,7 @@ * Please see the License for the specific language governing rights and * limitations under the License. * - * @APPLE_LICENSE_HEADER_END@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ /* * Copyright (c) 1982, 1989, 1993 @@ -55,7 +58,12 @@ * SUCH DAMAGE. * */ - +/* + * NOTICE: This file was modified by SPARTA, Inc. in 2006 to introduce + * support for mandatory and extensible security protections. This notice + * is included in support of clause 2.2 (b) of the Apple Public License, + * Version 2.0. + */ #include @@ -66,29 +74,26 @@ #include #include #include +#include #include -#include #include #include #include #include +#include #include #include #include #include #include +#include #include #include -#if LLC && CCITT -extern struct ifqueue pkintrq; -#endif - - #if BRIDGE #include #endif @@ -97,295 +102,243 @@ extern struct ifqueue pkintrq; #if NVLAN > 0 #include #endif /* NVLAN > 0 */ +#include +#if CONFIG_MACF +#include +#endif -static u_long lo_dlt = 0; -static ivedonethis = 0; -static u_char etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - -#define IFP2AC(IFP) ((struct arpcom *)IFP) - +/* Local function declerations */ +extern void *kdp_get_interface(void); +extern void kdp_set_ip_and_mac_addresses(struct in_addr *ipaddr, + struct ether_addr *macaddr); +static __inline__ void +_ip_copy(struct in_addr * dst, const struct in_addr * src) +{ + *dst = *src; + return; +} +static void +ether_inet_arp_input( + struct mbuf *m) +{ + struct ether_arp *ea; + struct sockaddr_dl sender_hw; + struct sockaddr_in sender_ip; + struct sockaddr_in target_ip; + + if (mbuf_len(m) < sizeof(*ea) && + mbuf_pullup(&m, sizeof(*ea)) != 0) + return; + + ea = mbuf_data(m); + + /* Verify this is an ethernet/ip arp and address lengths are correct */ + if (ntohs(ea->arp_hrd) != ARPHRD_ETHER || + ntohs(ea->arp_pro) != ETHERTYPE_IP || + ea->arp_pln != sizeof(struct in_addr) || + ea->arp_hln != ETHER_ADDR_LEN) { + mbuf_free(m); + return; + } + + /* Verify the sender is not broadcast */ + if (bcmp(ea->arp_sha, etherbroadcastaddr, ETHER_ADDR_LEN) == 0) { + mbuf_free(m); + return; + } + + bzero(&sender_ip, sizeof(sender_ip)); + sender_ip.sin_len = sizeof(sender_ip); + sender_ip.sin_family = AF_INET; + _ip_copy(&sender_ip.sin_addr, (const struct in_addr *)ea->arp_spa); + target_ip = sender_ip; + _ip_copy(&target_ip.sin_addr, (const struct in_addr *)ea->arp_tpa); + + bzero(&sender_hw, sizeof(sender_hw)); + sender_hw.sdl_len = sizeof(sender_hw); + sender_hw.sdl_family = AF_LINK; + sender_hw.sdl_type = IFT_ETHER; + sender_hw.sdl_alen = ETHER_ADDR_LEN; + bcopy(ea->arp_sha, LLADDR(&sender_hw), ETHER_ADDR_LEN); + + arp_ip_handle_input(mbuf_pkthdr_rcvif(m), ntohs(ea->arp_op), &sender_hw, &sender_ip, &target_ip); + mbuf_free(m); +} /* * Process a received Ethernet packet; * the packet is in the mbuf chain m without * the ether header, which is provided separately. */ -int -inet_ether_input(m, frame_header, ifp, dl_tag, sync_ok) - struct mbuf *m; - char *frame_header; - struct ifnet *ifp; - u_long dl_tag; - int sync_ok; - +static errno_t +ether_inet_input( + __unused ifnet_t ifp, + __unused protocol_family_t protocol_family, + mbuf_t m_list) { - register struct ether_header *eh = (struct ether_header *) frame_header; - register struct ifqueue *inq=0; - u_short ether_type; - int s; - u_int16_t ptype = -1; - unsigned char buf[18]; - -#if ISO || LLC || NETAT - register struct llc *l; -#endif - - if ((ifp->if_flags & IFF_UP) == 0) { - m_freem(m); - return EJUSTRETURN; - } - - ifp->if_lastchange = time; - - if (eh->ether_dhost[0] & 1) { - if (bcmp((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost, - sizeof(etherbroadcastaddr)) == 0) - m->m_flags |= M_BCAST; - else - m->m_flags |= M_MCAST; - } - if (m->m_flags & (M_BCAST|M_MCAST)) - ifp->if_imcasts++; - - ether_type = ntohs(eh->ether_type); - -#if NVLAN > 0 - if (ether_type == vlan_proto) { - if (vlan_input(eh, m) < 0) - ifp->if_data.ifi_noproto++; - return EJUSTRETURN; - } -#endif /* NVLAN > 0 */ - - switch (ether_type) { - - case ETHERTYPE_IP: - if (ipflow_fastforward(m)) - return EJUSTRETURN; - ptype = mtod(m, struct ip *)->ip_p; - if ((sync_ok == 0) || - (ptype != IPPROTO_TCP && ptype != IPPROTO_UDP)) { - schednetisr(NETISR_IP); + mbuf_t m; + mbuf_t *tailptr = &m_list; + mbuf_t nextpkt; + + /* Strip ARP and non-IP packets out of the list */ + for (m = m_list; m; m = nextpkt) { + struct ether_header *eh = mbuf_pkthdr_header(m); + + nextpkt = m->m_nextpkt; + + if (eh->ether_type == htons(ETHERTYPE_IP)) { + /* put this packet in the list */ + *tailptr = m; + tailptr = &m->m_nextpkt; + } + else { + /* Pass ARP packets to arp input */ + m->m_nextpkt = NULL; + if (eh->ether_type == htons(ETHERTYPE_ARP)) + ether_inet_arp_input(m); + else + mbuf_freem(m); + } } - - inq = &ipintrq; - break; - - case ETHERTYPE_ARP: - schednetisr(NETISR_ARP); - inq = &arpintrq; - break; - - default: { - return ENOENT; + + *tailptr = NULL; + + /* Pass IP list to ip input */ + if (m_list != NULL && proto_input(PF_INET, m_list) != 0) + { + mbuf_freem_list(m_list); } - } - - if (inq == 0) - return ENOENT; - - s = splimp(); - if (IF_QFULL(inq)) { - IF_DROP(inq); - m_freem(m); - splx(s); - return EJUSTRETURN; - } else - IF_ENQUEUE(inq, m); - splx(s); - - if ((sync_ok) && - (ptype == IPPROTO_TCP || ptype == IPPROTO_UDP)) { - extern void ipintr(void); - - s = splnet(); - ipintr(); - splx(s); - } - + return 0; } - - - -int -inet_ether_pre_output(ifp, m0, dst_netaddr, route, type, edst, dl_tag ) - struct ifnet *ifp; - struct mbuf **m0; - struct sockaddr *dst_netaddr; - caddr_t route; - char *type; - char *edst; - u_long dl_tag; +static errno_t +ether_inet_pre_output( + ifnet_t ifp, + __unused protocol_family_t protocol_family, + mbuf_t *m0, + const struct sockaddr *dst_netaddr, + void* route, + char *type, + char *edst) { - struct rtentry *rt0 = (struct rtentry *) route; - int s; register struct mbuf *m = *m0; - register struct rtentry *rt; - register struct ether_header *eh; - int off, len = m->m_pkthdr.len; - int hlen; /* link layer header lenght */ - struct arpcom *ac = IFP2AC(ifp); - + const struct ether_header *eh; + errno_t result = 0; if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) - return ENETDOWN; - - rt = rt0; - if (rt) { - if ((rt->rt_flags & RTF_UP) == 0) { - rt0 = rt = rtalloc1(dst_netaddr, 1, 0UL); - if (rt0) - rtunref(rt); - else - return EHOSTUNREACH; - } - - if (rt->rt_flags & RTF_GATEWAY) { - if (rt->rt_gwroute == 0) - goto lookup; - if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) { - rtfree(rt); rt = rt0; - lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1, - 0UL); - if ((rt = rt->rt_gwroute) == 0) - return (EHOSTUNREACH); - } - } - + return ENETDOWN; - if (rt->rt_flags & RTF_REJECT) - if (rt->rt_rmx.rmx_expire == 0 || - time_second < rt->rt_rmx.rmx_expire) - return (rt == rt0 ? EHOSTDOWN : EHOSTUNREACH); - } - - hlen = ETHER_HDR_LEN; - /* * Tell ether_frameout it's ok to loop packet unless negated below. */ m->m_flags |= M_LOOP; switch (dst_netaddr->sa_family) { - - case AF_INET: - if (!arpresolve(ac, rt, m, dst_netaddr, edst, rt0)) - return (EJUSTRETURN); /* if not yet resolved */ - off = m->m_pkthdr.len - m->m_len; - *(u_short *)type = htons(ETHERTYPE_IP); - break; - - case AF_UNSPEC: - m->m_flags &= ~M_LOOP; - eh = (struct ether_header *)dst_netaddr->sa_data; - (void)memcpy(edst, eh->ether_dhost, 6); - *(u_short *)type = eh->ether_type; - break; - - default: - kprintf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit, - dst_netaddr->sa_family); - - return EAFNOSUPPORT; + + case AF_INET: { + struct sockaddr_dl ll_dest; + result = arp_lookup_ip(ifp, (const struct sockaddr_in*)dst_netaddr, + &ll_dest, sizeof(ll_dest), (route_t)route, *m0); + if (result == 0) { + bcopy(LLADDR(&ll_dest), edst, ETHER_ADDR_LEN); + *(u_int16_t*)type = htons(ETHERTYPE_IP); + } + } + break; + + case pseudo_AF_HDRCMPLT: + case AF_UNSPEC: + m->m_flags &= ~M_LOOP; + eh = (const struct ether_header *)dst_netaddr->sa_data; + (void)memcpy(edst, eh->ether_dhost, 6); + *(u_short *)type = eh->ether_type; + break; + + default: + printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit, + dst_netaddr->sa_family); + + result = EAFNOSUPPORT; } - return (0); + return result; } +static errno_t +ether_inet_resolve_multi( + ifnet_t ifp, + const struct sockaddr *proto_addr, + struct sockaddr_dl *out_ll, + size_t ll_len) +{ + static const size_t minsize = offsetof(struct sockaddr_dl, sdl_data[0]) + ETHER_ADDR_LEN; + const struct sockaddr_in *sin = (const struct sockaddr_in*)proto_addr; + + if (proto_addr->sa_family != AF_INET) + return EAFNOSUPPORT; + + if (proto_addr->sa_len < sizeof(struct sockaddr_in)) + return EINVAL; -int -ether_inet_prmod_ioctl(dl_tag, ifp, command, data) - u_long dl_tag; - struct ifnet *ifp; - int command; - caddr_t data; + if (ll_len < minsize) + return EMSGSIZE; + + bzero(out_ll, minsize); + out_ll->sdl_len = minsize; + out_ll->sdl_family = AF_LINK; + out_ll->sdl_index = ifp->if_index; + out_ll->sdl_type = IFT_ETHER; + out_ll->sdl_nlen = 0; + out_ll->sdl_alen = ETHER_ADDR_LEN; + out_ll->sdl_slen = 0; + ETHER_MAP_IP_MULTICAST(&sin->sin_addr, LLADDR(out_ll)); + + return 0; +} + +static errno_t +ether_inet_prmod_ioctl( + ifnet_t ifp, + __unused protocol_family_t protocol_family, + u_int32_t command, + void* data) { - struct ifaddr *ifa = (struct ifaddr *) data; - struct ifreq *ifr = (struct ifreq *) data; - struct rslvmulti_req *rsreq = (struct rslvmulti_req *) data; + ifaddr_t ifa = data; + struct ifreq *ifr = data; int error = 0; - boolean_t funnel_state; - struct arpcom *ac = (struct arpcom *) ifp; - struct sockaddr_dl *sdl; - struct sockaddr_in *sin; - u_char *e_addr; - -#if 0 - /* No tneeded at soo_ioctlis already funnelled */ - funnel_state = thread_funnel_set(network_flock,TRUE); -#endif switch (command) { - case SIOCRSLVMULTI: { - switch(rsreq->sa->sa_family) { - - case AF_INET: - sin = (struct sockaddr_in *)rsreq->sa; - if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) - return EADDRNOTAVAIL; - MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR, - M_WAITOK); - sdl->sdl_len = sizeof *sdl; - sdl->sdl_family = AF_LINK; - sdl->sdl_index = ifp->if_index; - sdl->sdl_type = IFT_ETHER; - sdl->sdl_nlen = 0; - sdl->sdl_alen = ETHER_ADDR_LEN; - sdl->sdl_slen = 0; - e_addr = LLADDR(sdl); - ETHER_MAP_IP_MULTICAST(&sin->sin_addr, e_addr); - *rsreq->llsa = (struct sockaddr *)sdl; - return EJUSTRETURN; - - default: - /* - * Well, the text isn't quite right, but it's the name - * that counts... - */ - return EAFNOSUPPORT; - } - - } case SIOCSIFADDR: - if ((ifp->if_flags & IFF_RUNNING) == 0) { - ifp->if_flags |= IFF_UP; - dlil_ioctl(0, ifp, SIOCSIFFLAGS, (caddr_t) 0); - } + case SIOCAIFADDR: + if ((ifnet_flags(ifp) & IFF_RUNNING) == 0) { + ifnet_set_flags(ifp, IFF_UP, IFF_UP); + ifnet_ioctl(ifp, 0, SIOCSIFFLAGS, NULL); + } - switch (ifa->ifa_addr->sa_family) { + switch (ifaddr_address_family(ifa)) { case AF_INET: - if (ifp->if_init) - ifp->if_init(ifp->if_softc); /* before arpwhohas */ - - // - // See if another station has *our* IP address. - // i.e.: There is an address conflict! If a - // conflict exists, a message is sent to the - // console. - // - if (IA_SIN(ifa)->sin_addr.s_addr != 0) - { - /* don't bother for 0.0.0.0 */ - ac->ac_ipaddr = IA_SIN(ifa)->sin_addr; - arpwhohas(ac, &IA_SIN(ifa)->sin_addr); - } - - arp_ifinit(IFP2AC(ifp), ifa); - + inet_arp_init_ifaddr(ifp, ifa); /* - * Register new IP and MAC addresses with the kernel debugger - * for the en0 interface. + * Register new IP and MAC addresses with the kernel + * debugger if the interface is the same as was registered + * by IOKernelDebugger. If no interface was registered, + * fall back and just match against en0 interface. + * Do this only for the first address of the interface + * and not for aliases. */ - if (ifp->if_unit == 0) - kdp_set_ip_and_mac_addresses(&(IA_SIN(ifa)->sin_addr), &(IFP2AC(ifp)->ac_enaddr)); + if (command == SIOCSIFADDR && + ((kdp_get_interface() != 0 && + kdp_get_interface() == ifp->if_softc) || + (kdp_get_interface() == 0 && ifp->if_unit == 0))) + kdp_set_ip_and_mac_addresses(&(IA_SIN(ifa)->sin_addr), + ifnet_lladdr(ifp)); break; @@ -396,93 +349,197 @@ ether_inet_prmod_ioctl(dl_tag, ifp, command, data) break; case SIOCGIFADDR: - { - struct sockaddr *sa; - - sa = (struct sockaddr *) & ifr->ifr_data; - bcopy(IFP2AC(ifp)->ac_enaddr, - (caddr_t) sa->sa_data, ETHER_ADDR_LEN); - } - break; - - case SIOCSIFMTU: - /* - * IOKit IONetworkFamily will set the right MTU according to the driver - */ - - return (0); + ifnet_lladdr_copy_bytes(ifp, ifr->ifr_addr.sa_data, ETHER_ADDR_LEN); + break; default: - return EOPNOTSUPP; + error = EOPNOTSUPP; + break; } - //(void) thread_funnel_set(network_flock, FALSE); - return (error); } +static void +ether_inet_event( + ifnet_t ifp, + __unused protocol_family_t protocol, + const struct kev_msg *event) +{ + ifaddr_t *addresses; + + if (event->vendor_code != KEV_VENDOR_APPLE || + event->kev_class != KEV_NETWORK_CLASS || + event->kev_subclass != KEV_DL_SUBCLASS || + event->event_code != KEV_DL_LINK_ADDRESS_CHANGED) { + return; + } + + if (ifnet_get_address_list_family(ifp, &addresses, AF_INET) == 0) { + int i; + + for (i = 0; addresses[i] != NULL; i++) { + inet_arp_init_ifaddr(ifp, addresses[i]); + } + + ifnet_free_address_list(addresses); + } +} +static errno_t +ether_inet_arp( + ifnet_t ifp, + u_short arpop, + const struct sockaddr_dl* sender_hw, + const struct sockaddr* sender_proto, + const struct sockaddr_dl* target_hw, + const struct sockaddr* target_proto) +{ + mbuf_t m; + errno_t result; + struct ether_header *eh; + struct ether_arp *ea; + const struct sockaddr_in* sender_ip = (const struct sockaddr_in*)sender_proto; + const struct sockaddr_in* target_ip = (const struct sockaddr_in*)target_proto; + char *datap; + + if (target_ip == NULL) + return EINVAL; + + if ((sender_ip && sender_ip->sin_family != AF_INET) || + target_ip->sin_family != AF_INET) + return EAFNOSUPPORT; + + result = mbuf_gethdr(MBUF_DONTWAIT, MBUF_TYPE_DATA, &m); + if (result != 0) + return result; + + mbuf_setlen(m, sizeof(*ea)); + mbuf_pkthdr_setlen(m, sizeof(*ea)); + + /* Move the data pointer in the mbuf to the end, aligned to 4 bytes */ + datap = mbuf_datastart(m); + datap += mbuf_trailingspace(m); + datap -= (((u_long)datap) & 0x3); + mbuf_setdata(m, datap, sizeof(*ea)); + ea = mbuf_data(m); + + /* + * Prepend the ethernet header, we will send the raw frame; + * callee frees the original mbuf when allocation fails. + */ + result = mbuf_prepend(&m, sizeof(*eh), MBUF_DONTWAIT); + if (result != 0) + return result; + eh = mbuf_data(m); + eh->ether_type = htons(ETHERTYPE_ARP); +#if CONFIG_MACF_NET + mac_mbuf_label_associate_linklayer(ifp, m); +#endif + + /* Fill out the arp header */ + ea->arp_pro = htons(ETHERTYPE_IP); + ea->arp_hln = sizeof(ea->arp_sha); + ea->arp_pln = sizeof(ea->arp_spa); + ea->arp_hrd = htons(ARPHRD_ETHER); + ea->arp_op = htons(arpop); + + /* Sender Hardware */ + if (sender_hw != NULL) { + bcopy(CONST_LLADDR(sender_hw), ea->arp_sha, sizeof(ea->arp_sha)); + } + else { + ifnet_lladdr_copy_bytes(ifp, ea->arp_sha, ETHER_ADDR_LEN); + } + ifnet_lladdr_copy_bytes(ifp, eh->ether_shost, sizeof(eh->ether_shost)); + + /* Sender IP */ + if (sender_ip != NULL) { + bcopy(&sender_ip->sin_addr, ea->arp_spa, sizeof(ea->arp_spa)); + } + else { + struct ifaddr *ifa; + + /* Look for an IP address to use as our source */ + ifnet_lock_shared(ifp); + TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { + if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET) + break; + } + if (ifa) { + bcopy(&((struct sockaddr_in*)ifa->ifa_addr)->sin_addr, ea->arp_spa, + sizeof(ea->arp_spa)); + } + ifnet_lock_done(ifp); + + if (ifa == NULL) { + mbuf_free(m); + return ENXIO; + } + } + + /* Target Hardware */ + if (target_hw == 0) { + bzero(ea->arp_tha, sizeof(ea->arp_tha)); + bcopy(etherbroadcastaddr, eh->ether_dhost, sizeof(eh->ether_dhost)); + } + else { + bcopy(CONST_LLADDR(target_hw), ea->arp_tha, sizeof(ea->arp_tha)); + bcopy(CONST_LLADDR(target_hw), eh->ether_dhost, sizeof(eh->ether_dhost)); + } + + /* Target IP */ + bcopy(&target_ip->sin_addr, ea->arp_tpa, sizeof(ea->arp_tpa)); + + ifnet_output_raw(ifp, PF_INET, m); + + return 0; +} -u_long -ether_attach_inet(struct ifnet *ifp) +errno_t +ether_attach_inet( + struct ifnet *ifp, + __unused protocol_family_t proto_family) { - struct dlil_proto_reg_str reg; - struct dlil_demux_desc desc; - struct dlil_demux_desc desc2; - u_long ip_dl_tag=0; - u_short en_native=ETHERTYPE_IP; - u_short arp_native=ETHERTYPE_ARP; - int stat; - int i; - - - stat = dlil_find_dltag(ifp->if_family, ifp->if_unit, PF_INET, &ip_dl_tag); - if (stat == 0) - return ip_dl_tag; - - TAILQ_INIT(®.demux_desc_head); - desc.type = DLIL_DESC_RAW; - desc.variants.bitmask.proto_id_length = 0; - desc.variants.bitmask.proto_id = 0; - desc.variants.bitmask.proto_id_mask = 0; - desc.native_type = (char *) &en_native; - TAILQ_INSERT_TAIL(®.demux_desc_head, &desc, next); - reg.interface_family = ifp->if_family; - reg.unit_number = ifp->if_unit; - reg.input = inet_ether_input; - reg.pre_output = inet_ether_pre_output; - reg.event = 0; - reg.offer = 0; - reg.ioctl = ether_inet_prmod_ioctl; - reg.default_proto = 1; - reg.protocol_family = PF_INET; - - desc2 = desc; - desc2.native_type = (char *) &arp_native; - TAILQ_INSERT_TAIL(®.demux_desc_head, &desc2, next); - - stat = dlil_attach_protocol(®, &ip_dl_tag); - if (stat) { - printf("WARNING: ether_attach_inet can't attach ip to interface\n"); - return stat; - } - return ip_dl_tag; + struct ifnet_attach_proto_param_v2 proto; + struct ifnet_demux_desc demux[2]; + u_short en_native=htons(ETHERTYPE_IP); + u_short arp_native=htons(ETHERTYPE_ARP); + errno_t error; + + bzero(&demux[0], sizeof(demux)); + demux[0].type = DLIL_DESC_ETYPE2; + demux[0].data = &en_native; + demux[0].datalen = sizeof(en_native); + demux[1].type = DLIL_DESC_ETYPE2; + demux[1].data = &arp_native; + demux[1].datalen = sizeof(arp_native); + + bzero(&proto, sizeof(proto)); + proto.demux_list = demux; + proto.demux_count = sizeof(demux) / sizeof(demux[0]); + proto.input = ether_inet_input; + proto.pre_output = ether_inet_pre_output; + proto.ioctl = ether_inet_prmod_ioctl; + proto.event = ether_inet_event; + proto.resolve = ether_inet_resolve_multi; + proto.send_arp = ether_inet_arp; + + error = ifnet_attach_protocol_v2(ifp, proto_family, &proto); + if (error && error != EEXIST) { + printf("WARNING: ether_attach_inet can't attach ip to %s%d\n", + ifp->if_name, ifp->if_unit); + } + return error; } -int ether_detach_inet(struct ifnet *ifp) +void +ether_detach_inet( + struct ifnet *ifp, + protocol_family_t proto_family) { - u_long ip_dl_tag = 0; - int stat; - - stat = dlil_find_dltag(ifp->if_family, ifp->if_unit, PF_INET, &ip_dl_tag); - if (stat == 0) { - stat = dlil_detach_protocol(ip_dl_tag); - if (stat) { - printf("WARNING: ether_detach_inet can't detach ip from interface\n"); - } - } - return stat; + (void)ifnet_detach_protocol(ifp, proto_family); }