X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/9bccf70c0258c7cac2dcb80011b2a964d884c552..36401178fd6817c043cc00b0c00c7f723e58efae:/bsd/net/ether_inet6_pr_module.c diff --git a/bsd/net/ether_inet6_pr_module.c b/bsd/net/ether_inet6_pr_module.c index 9764e8a97..979239c66 100644 --- a/bsd/net/ether_inet6_pr_module.c +++ b/bsd/net/ether_inet6_pr_module.c @@ -1,23 +1,29 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2007 Apple Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. + * 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. 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. * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * 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 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * 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 @@ -63,14 +69,15 @@ #include #include #include +#include #include -#include #include #include #include #include #include +#include #include #include @@ -104,323 +111,161 @@ extern struct ifqueue pkintrq; #include #endif /* NVLAN > 0 */ -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) - - - +#include /* * Process a received Ethernet packet; * the packet is in the mbuf chain m without * the ether header, which is provided separately. */ -int -inet6_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_inet6_input( + __unused ifnet_t ifp, + protocol_family_t protocol, + mbuf_t packet, + __unused char *header) { - 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 ((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); + errno_t error; + if ((error = proto_input(protocol, packet))) + m_freem(packet); + return error; +} - switch (ether_type) { - - case ETHERTYPE_IPV6: - schednetisr(NETISR_IPV6); - inq = &ip6intrq; - break; +static errno_t +ether_inet6_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) +{ + errno_t result; + struct sockaddr_dl sdl; + register struct mbuf *m = *m0; - default: { - return ENOENT; + /* + * Tell ether_frameout it's ok to loop packet if necessary + */ + m->m_flags |= M_LOOP; + + result = nd6_lookup_ipv6(ifp, (const struct sockaddr_in6*)dst_netaddr, + &sdl, sizeof(sdl), route, *m0); + + if (result == 0) { + *(u_int16_t*)type = htons(ETHERTYPE_IPV6); + bcopy(LLADDR(&sdl), edst, sdl.sdl_alen); } - } - - 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); - return 0; + return result; } - - - -int -inet6_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 int +ether_inet6_resolve_multi( + ifnet_t ifp, + const struct sockaddr *proto_addr, + struct sockaddr_dl *out_ll, + size_t ll_len) { - struct rtentry *rt0 = (struct rtentry *) route; - int s; - register struct mbuf *m = *m0; - register struct rtentry *rt; - register struct ether_header *eh; - int hlen; /* link layer header lenght */ - struct arpcom *ac = IFP2AC(ifp); - - - - 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); - } - } - + static const size_t minsize = offsetof(struct sockaddr_dl, sdl_data[0]) + ETHER_ADDR_LEN; + const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6*)proto_addr; - 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_INET6: - if (!nd6_storelladdr(&ac->ac_if, rt, m, dst_netaddr, (u_char *)edst)) { - /* this must be impossible, so we bark */ - printf("nd6_storelladdr failed\n"); - return(0); - } - *(u_short *)type = htons(ETHERTYPE_IPV6); - break; - - default: - printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit, - dst_netaddr->sa_family); - - return EAFNOSUPPORT; - } - - return (0); + if (proto_addr->sa_family != AF_INET6) + return EAFNOSUPPORT; + + if (proto_addr->sa_len < sizeof(struct sockaddr_in6)) + return EINVAL; + + 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_IPV6_MULTICAST(&sin6->sin6_addr, LLADDR(out_ll)); + + return 0; } -int -ether_inet6_prmod_ioctl(dl_tag, ifp, command, data) - u_long dl_tag; - struct ifnet *ifp; - int command; - caddr_t data; +static errno_t +ether_inet6_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; int error = 0; - boolean_t funnel_state; - struct arpcom *ac = (struct arpcom *) ifp; - struct sockaddr_dl *sdl; - struct sockaddr_in *sin; - struct sockaddr_in6 *sin6; - - u_char *e_addr; - - - switch (command) { - case SIOCRSLVMULTI: { - switch(rsreq->sa->sa_family) { - - case AF_INET6: - sin6 = (struct sockaddr_in6 *)rsreq->sa; - if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { - /* - * An IP6 address of 0 means listen to all - * of the Ethernet multicast address used for IP6. - * (This is used for multicast routers.) - */ - ifp->if_flags |= IFF_ALLMULTI; - *rsreq->llsa = 0; - return 0; - } - 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_IPV6_MULTICAST(&sin6->sin6_addr, e_addr); -#ifndef __APPLE__ - printf("ether_resolvemulti AF_INET6 Adding %x:%x:%x:%x:%x:%x\n", - e_addr[0], e_addr[1], e_addr[2], e_addr[3], e_addr[4], e_addr[5]); -#endif - *rsreq->llsa = (struct sockaddr *)sdl; - return 0; - - 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); - } + switch (command) { + case SIOCSIFADDR: + if ((ifp->if_flags & IFF_RUNNING) == 0) { + ifnet_set_flags(ifp, IFF_UP, IFF_UP); + ifnet_ioctl(ifp, 0, SIOCSIFFLAGS, NULL); + } + break; + case SIOCGIFADDR: + ifnet_lladdr_copy_bytes(ifp, ifr->ifr_addr.sa_data, ETHER_ADDR_LEN); 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); - default: - return EOPNOTSUPP; + error = EOPNOTSUPP; + break; } - return (error); } - - - - -u_long ether_attach_inet6(struct ifnet *ifp) +errno_t +ether_attach_inet6( + struct ifnet *ifp, + __unused protocol_family_t protocol_family) { - struct dlil_proto_reg_str reg; - struct dlil_demux_desc desc; - u_long ip_dl_tag=0; - u_short en_6native=ETHERTYPE_IPV6; - int stat; - int i; - - - stat = dlil_find_dltag(ifp->if_family, ifp->if_unit, PF_INET6, &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_6native; - TAILQ_INSERT_TAIL(®.demux_desc_head, &desc, next); - reg.interface_family = ifp->if_family; - reg.unit_number = ifp->if_unit; - reg.input = inet6_ether_input; - reg.pre_output = inet6_ether_pre_output; - reg.event = 0; - reg.offer = 0; - reg.ioctl = ether_inet6_prmod_ioctl; - reg.default_proto = 0; - reg.protocol_family = PF_INET6; - - stat = dlil_attach_protocol(®, &ip_dl_tag); - if (stat) { - printf("WARNING: ether_attach_inet6 can't attach ip to interface\n"); - return stat; - } - - return ip_dl_tag; + struct ifnet_attach_proto_param proto; + struct ifnet_demux_desc demux[1]; + u_short en_6native=htons(ETHERTYPE_IPV6); + errno_t error; + + bzero(&proto, sizeof(proto)); + demux[0].type = DLIL_DESC_ETYPE2; + demux[0].data = &en_6native; + demux[0].datalen = sizeof(en_6native); + proto.demux_list = demux; + proto.demux_count = 1; + proto.input = ether_inet6_input; + proto.pre_output = ether_inet6_pre_output; + proto.ioctl = ether_inet6_prmod_ioctl; + proto.resolve = ether_inet6_resolve_multi; + error = ifnet_attach_protocol(ifp, protocol_family, &proto); + if (error && error != EEXIST) { + printf("WARNING: ether_attach_inet6 can't attach ipv6 to %s%d\n", + ifp->if_name, ifp->if_unit); + } + + return error; } -int ether_detach_inet6(struct ifnet *ifp) +void +ether_detach_inet6( + struct ifnet *ifp, + protocol_family_t protocol_family) { - u_long ip_dl_tag = 0; - int stat; - - stat = dlil_find_dltag(ifp->if_family, ifp->if_unit, PF_INET6, &ip_dl_tag); - if (stat == 0) { - stat = dlil_detach_protocol(ip_dl_tag); - if (stat) { - printf("WARNING: ether_detach_inet6 can't detach ip6 from interface\n"); - } - } - return stat; + errno_t error; + + error = ifnet_detach_protocol(ifp, protocol_family); + if (error && error != ENOENT) { + printf("WARNING: ether_detach_inet6 can't detach ipv6 from %s%d\n", + ifp->if_name, ifp->if_unit); + } }