📄 if_ethersubr.c
字号:
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++;#if NBRIDGE > 0 /* * Tap the packet off here for a bridge, if configured and * active for this interface. bridge_input returns * NULL if it has consumed the packet, otherwise, it * gets processed as normal. */ if (ifp->if_bridge) { m = bridge_input(ifp, eh, m); if (m == NULL) return; /* The bridge has determined it's for us. */ goto decapsulate; }#endif /* * If packet is unicast and we're in promiscuous mode, make sure it * is for us. Drop otherwise. */ if ((m->m_flags & (M_BCAST|M_MCAST)) == 0 && (ifp->if_flags & IFF_PROMISC)) { if (bcmp(ac->ac_enaddr, (caddr_t)eh->ether_dhost, ETHER_ADDR_LEN)) { m_freem(m); return; } }decapsulate: etype = ntohs(eh->ether_type); switch (etype) {#ifdef INET case ETHERTYPE_IP: schednetisr(NETISR_IP); inq = &ipintrq; break; case ETHERTYPE_ARP: if (ifp->if_flags & IFF_NOARP) goto dropanyway; schednetisr(NETISR_ARP); inq = &arpintrq; break; case ETHERTYPE_REVARP: if (ifp->if_flags & IFF_NOARP) goto dropanyway; revarpinput(m); /* XXX queue? */ return;#endif#ifdef INET6 /* * Schedule IPv6 software interrupt for incoming IPv6 packet. */ case ETHERTYPE_IPV6: schednetisr(NETISR_IPV6); inq = &ipv6intrq; break;#endif /* INET6 */#ifdef IPX case ETHERTYPE_IPX: schednetisr(NETISR_IPX); inq = &ipxintrq; break;#endif#ifdef NS case ETHERTYPE_NS: schednetisr(NETISR_NS); inq = &nsintrq; break;#endif#ifdef NETATALK case ETHERTYPE_AT: schednetisr(NETISR_ATALK); inq = &atintrq1; break; case ETHERTYPE_AARP: /* probably this should be done with a NETISR as well */ /* XXX queue this */ aarpinput((struct arpcom *)ifp, m); return;#endif default: if (llcfound || etype > ETHERMTU) goto dropanyway; llcfound = 1; l = mtod(m, struct llc *); switch (l->llc_dsap) { case LLC_SNAP_LSAP:#ifdef NETATALK /* * Some protocols (like Appletalk) need special * handling depending on if they are type II * or SNAP encapsulated. Everything else * gets handled by stripping off the SNAP header * and going back up to decapsulate. */ if (l->llc_control == LLC_UI && l->llc_ssap == LLC_SNAP_LSAP && Bcmp(&(l->llc_snap_org_code)[0], at_org_code, sizeof(at_org_code)) == 0 && ntohs(l->llc_snap_ether_type) == ETHERTYPE_AT) { inq = &atintrq2; m_adj(m, AT_LLC_SIZE); schednetisr(NETISR_ATALK); break; } if (l->llc_control == LLC_UI && l->llc_ssap == LLC_SNAP_LSAP && Bcmp(&(l->llc_snap_org_code)[0], aarp_org_code, sizeof(aarp_org_code)) == 0 && ntohs(l->llc_snap_ether_type) == ETHERTYPE_AARP) { m_adj(m, AT_LLC_SIZE); /* XXX Really this should use netisr too */ aarpinput((struct arpcom *)ifp, m); return; }#endif /* NETATALK */ if (l->llc_control == LLC_UI && l->llc_dsap == LLC_SNAP_LSAP && l->llc_ssap == LLC_SNAP_LSAP) { /* SNAP */ if (m->m_pkthdr.len > etype) m_adj(m, etype - m->m_pkthdr.len); m->m_data += 6; /* XXX */ m->m_len -= 6; /* XXX */ m->m_pkthdr.len -= 6; /* XXX */ M_PREPEND(m, sizeof *eh, M_DONTWAIT); if (m == 0) return; *mtod(m, struct ether_header *) = *eh; goto decapsulate; } goto dropanyway;#ifdef ISO case LLC_ISO_LSAP: switch (l->llc_control) { case LLC_UI: /* LLC_UI_P forbidden in class 1 service */ if ((l->llc_dsap == LLC_ISO_LSAP) && (l->llc_ssap == LLC_ISO_LSAP)) { /* LSAP for ISO */ if (m->m_pkthdr.len > etype) m_adj(m, etype - m->m_pkthdr.len); m->m_data += 3; /* XXX */ m->m_len -= 3; /* XXX */ m->m_pkthdr.len -= 3; /* XXX */ M_PREPEND(m, sizeof *eh, M_DONTWAIT); if (m == 0) return; *mtod(m, struct ether_header *) = *eh;#ifdef ARGO_DEBUG if (argo_debug[D_ETHER]) printf("clnp packet");#endif schednetisr(NETISR_ISO); inq = &clnlintrq; break; } goto dropanyway; case LLC_XID: case LLC_XID_P: if(m->m_len < 6) goto dropanyway; l->llc_window = 0; l->llc_fid = 9; l->llc_class = 1; l->llc_dsap = l->llc_ssap = 0; /* Fall through to */ case LLC_TEST: case LLC_TEST_P: { struct sockaddr sa; register struct ether_header *eh2; int i; u_char c = l->llc_dsap; l->llc_dsap = l->llc_ssap; l->llc_ssap = c; if (m->m_flags & (M_BCAST | M_MCAST)) bcopy(ac->ac_enaddr, eh->ether_dhost, 6); sa.sa_family = AF_UNSPEC; sa.sa_len = sizeof(sa); eh2 = (struct ether_header *)sa.sa_data; for (i = 0; i < 6; i++) { eh2->ether_shost[i] = c = eh->ether_dhost[i]; eh2->ether_dhost[i] = eh->ether_dhost[i] = eh->ether_shost[i]; eh->ether_shost[i] = c; } ifp->if_output(ifp, m, &sa, NULL); return; } break; }#endif /* ISO */#ifdef CCITT case LLC_X25_LSAP: if (m->m_pkthdr.len > etype) m_adj(m, etype - m->m_pkthdr.len); M_PREPEND(m, sizeof(struct sdl_hdr) , M_DONTWAIT); if (m == 0) return; if (!sdl_sethdrif(ifp, eh->ether_shost, LLC_X25_LSAP, eh->ether_dhost, LLC_X25_LSAP, 6, mtod(m, struct sdl_hdr *))) panic("ETHER cons addr failure"); mtod(m, struct sdl_hdr *)->sdlhdr_len = etype;#ifdef LLC_DEBUG printf("llc packet\n");#endif /* LLC_DEBUG */ schednetisr(NETISR_CCITT); inq = &llcintrq; break;#endif /* CCITT */ dropanyway: default: m_freem(m); return; } } s = splimp(); if (IF_QFULL(inq)) { IF_DROP(inq); m_freem(m); } else IF_ENQUEUE(inq, m); splx(s);}/* * Convert Ethernet address to printable (loggable) representation. */static char digits[] = "0123456789abcdef";char *ether_sprintf(ap) register u_char *ap;{ register int i; static char etherbuf[18]; register char *cp = etherbuf; for (i = 0; i < 6; i++) { *cp++ = digits[*ap >> 4]; *cp++ = digits[*ap++ & 0xf]; *cp++ = ':'; } *--cp = 0; return (etherbuf);}/* * Perform common duties while attaching to interface list */voidether_ifattach(ifp) register struct ifnet *ifp;{ register struct ifaddr *ifa; register struct sockaddr_dl *sdl; ifp->if_type = IFT_ETHER; ifp->if_addrlen = 6; ifp->if_hdrlen = 14; ifp->if_mtu = ETHERMTU; ifp->if_output = ether_output; for (ifa = ifp->if_addrlist.tqh_first; ifa != 0; ifa = ifa->ifa_list.tqe_next) if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) && sdl->sdl_family == AF_LINK) { sdl->sdl_type = IFT_ETHER; sdl->sdl_alen = ifp->if_addrlen; bcopy((caddr_t)((struct arpcom *)ifp)->ac_enaddr, LLADDR(sdl), ifp->if_addrlen); break; } LIST_INIT(&((struct arpcom *)ifp)->ac_multiaddrs);}voidether_ifdetach(ifp) struct ifnet *ifp;{ struct arpcom *ac = (struct arpcom *)ifp; struct ether_multi *enm; for (enm = LIST_FIRST(&ac->ac_multiaddrs); enm; enm = LIST_FIRST(&ac->ac_multiaddrs)) { LIST_REMOVE(enm, enm_list); free(enm, M_IFMADDR); }}u_char ether_ipmulticast_min[6] = { 0x01, 0x00, 0x5e, 0x00, 0x00, 0x00 };u_char ether_ipmulticast_max[6] = { 0x01, 0x00, 0x5e, 0x7f, 0xff, 0xff };#ifdef INET6u_char ether_ipv6multicast_min[6] = { 0x33, 0x33, 0x00, 0x00, 0x00, 0x00 };u_char ether_ipv6multicast_max[6] = { 0x33, 0x33, 0xff, 0xff, 0xff, 0xff };#endif /* INET6 *//* * Add an Ethernet multicast address or range of addresses to the list for a * given interface. */intether_addmulti(ifr, ac) struct ifreq *ifr; register struct arpcom *ac;{ register struct ether_multi *enm; struct sockaddr_in *sin;#ifdef INET6 struct sockaddr_in6 *sin6;#endif /* INET6 */ u_char addrlo[6]; u_char addrhi[6]; int s = splimp(); switch (ifr->ifr_addr.sa_family) { case AF_UNSPEC: bcopy(ifr->ifr_addr.sa_data, addrlo, 6); bcopy(addrlo, addrhi, 6); break;#ifdef INET case AF_INET: sin = (struct sockaddr_in *)&(ifr->ifr_addr); if (sin->sin_addr.s_addr == INADDR_ANY) { /* * An IP address of INADDR_ANY means listen to all * of the Ethernet multicast addresses used for IP. * (This is for the sake of IP multicast routers.) */ bcopy(ether_ipmulticast_min, addrlo, 6); bcopy(ether_ipmulticast_max, addrhi, 6); } else { ETHER_MAP_IP_MULTICAST(&sin->sin_addr, addrlo); bcopy(addrlo, addrhi, 6); } break;#endif#ifdef INET6 case AF_INET6: sin6 = (struct sockaddr_in6 *)&(ifr->ifr_addr); if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { /* * An unspecified IPv6 address means listen to all * of the IPv6 multicast addresses on this Ethernet. * (Multicast routers like this.) */ bcopy(ether_ipv6multicast_min, addrlo, ETHER_ADDR_LEN); bcopy(ether_ipv6multicast_max, addrhi, ETHER_ADDR_LEN); } else { ETHER_MAP_IN6_MULTICAST(sin6->sin6_addr, addrlo); bcopy(addrlo, addrhi, ETHER_ADDR_LEN); } break;#endif /* INET6 */ default: splx(s); return (EAFNOSUPPORT); } /* * Verify that we have valid Ethernet multicast addresses. */ if ((addrlo[0] & 0x01) != 1 || (addrhi[0] & 0x01) != 1) { splx(s); return (EINVAL); } /* * See if the address range is already in the list. */ ETHER_LOOKUP_MULTI(addrlo, addrhi, ac, enm); if (enm != NULL) { /* * Found it; just increment the reference count. */ ++enm->enm_refcount; splx(s); return (0); } /* * New address or range; malloc a new multicast record * and link it into the interface's multicast list. */ enm = (struct ether_multi *)malloc(sizeof(*enm), M_IFMADDR, M_NOWAIT); if (enm == NULL) { splx(s); return (ENOBUFS); } bcopy(addrlo, enm->enm_addrlo, 6); bcopy(addrhi, enm->enm_addrhi, 6); enm->enm_ac = ac; enm->enm_refcount = 1; LIST_INSERT_HEAD(&ac->ac_multiaddrs, enm, enm_list); ac->ac_multicnt++; splx(s); /* * Return ENETRESET to inform the driver that the list has changed * and its reception filter should be adjusted accordingly. */ return (ENETRESET);}/* * Delete a multicast address record. */intether_delmulti(ifr, ac) struct ifreq *ifr; register struct arpcom *ac;{ register struct ether_multi *enm; struct sockaddr_in *sin;#ifdef INET6 struct sockaddr_in6 *sin6;#endif /* INET6 */ u_char addrlo[6]; u_char addrhi[6]; int s = splimp(); switch (ifr->ifr_addr.sa_family) { case AF_UNSPEC: bcopy(ifr->ifr_addr.sa_data, addrlo, 6); bcopy(addrlo, addrhi, 6); break;#ifdef INET case AF_INET: sin = (struct sockaddr_in *)&(ifr->ifr_addr); if (sin->sin_addr.s_addr == INADDR_ANY) { /* * An IP address of INADDR_ANY means stop listening * to the range of Ethernet multicast addresses used * for IP. */ bcopy(ether_ipmulticast_min, addrlo, 6); bcopy(ether_ipmulticast_max, addrhi, 6); } else { ETHER_MAP_IP_MULTICAST(&sin->sin_addr, addrlo); bcopy(addrlo, addrhi, 6); } break;#endif#ifdef INET6 case AF_INET6: sin6 = (struct sockaddr_in6 *)&(ifr->ifr_addr); if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { /* * An unspecified IPv6 address means stop listening to * all IPv6 multicast addresses on this Ethernet.' * * (This might not be healthy, given IPv6's reliance on * multicast for things like neighbor discovery. * Perhaps initializing all-nodes, solicited nodes, and * possibly all-routers for this interface afterwards * is not a bad idea.) */ bcopy(ether_ipv6multicast_min, addrlo, ETHER_ADDR_LEN); bcopy(ether_ipv6multicast_max, addrhi, ETHER_ADDR_LEN); } else { ETHER_MAP_IN6_MULTICAST(sin6->sin6_addr, addrlo); bcopy(addrlo, addrhi, ETHER_ADDR_LEN); } break;#endif /* INET6 */ default: splx(s); return (EAFNOSUPPORT); } /* * Look up the address in our list. */ ETHER_LOOKUP_MULTI(addrlo, addrhi, ac, enm); if (enm == NULL) { splx(s); return (ENXIO); } if (--enm->enm_refcount != 0) { /* * Still some claims to this record. */ splx(s); return (0); } /* * No remaining claims to this record; unlink and free it. */ LIST_REMOVE(enm, enm_list); free(enm, M_IFMADDR); ac->ac_multicnt--; splx(s); /* * Return ENETRESET to inform the driver that the list has changed * and its reception filter should be adjusted accordingly. */ return (ENETRESET);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -