📄 if_ethersubr.c
字号:
struct mbuf *oldm = m ;
save_eh = *eh ; /* because it might change */
m = bdg_forward(m, eh, bif); /* needs forwarding */
/*
* Do not continue if bdg_forward() processed our
* packet (and cleared the mbuf pointer m) or if
* it dropped (m_free'd) the packet itself.
*/
if (m == NULL) {
if (bif == BDG_BCAST || bif == BDG_MCAST)
printf("bdg_forward drop MULTICAST PKT\n");
return;
}
if (m != oldm) /* m changed! */
eh = &save_eh ;
}
if (bif == BDG_LOCAL
|| bif == BDG_BCAST
|| bif == BDG_MCAST)
goto recvLocal; /* receive locally */
/* If not local and not multicast, just drop it */
if (m != NULL)
m_freem(m);
return;
}
#endif
#ifdef BRIDGE
recvLocal:
#endif
/* Continue with upper layer processing */
ether_demux(ifp, eh, m);
}
/*
* Upper layer processing for a received Ethernet packet.
*/
void
ether_demux(ifp, eh, m)
struct ifnet *ifp;
struct ether_header *eh;
struct mbuf *m;
{
struct ifqueue *inq;
u_short ether_type;
int s;
#if defined(NETATALK)
register struct llc *l;
#endif
#ifdef BRIDGE
if (! (do_bridge && BDG_USED(ifp) ) )
#endif
/* Discard packet if upper layers shouldn't see it because it was
unicast to a different Ethernet address. If the driver is working
properly, then this situation can only happen when the interface
is in promiscuous mode. */
if ((ifp->if_flags & IFF_PROMISC) != 0
&& (eh->ether_dhost[0] & 1) == 0
&& bcmp(eh->ether_dhost,
IFP2AC(ifp)->ac_enaddr, ETHER_ADDR_LEN) != 0) {
m_freem(m);
return;
}
/* Discard packet if interface is not up */
if ((ifp->if_flags & IFF_UP) == 0) {
m_freem(m);
return;
}
if (eh->ether_dhost[0] & 1) {
/*
* If this is not a simplex interface, drop the packet
* if it came from us.
*/
if ((ifp->if_flags & IFF_SIMPLEX) == 0) {
struct ifaddr *ifa;
struct sockaddr_dl *sdl = NULL;
/* find link-layer address */
TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) &&
sdl->sdl_family == AF_LINK)
break;
if (sdl && bcmp(LLADDR(sdl), eh->ether_shost,
ETHER_ADDR_LEN) == 0) {
m_freem(m);
return;
}
}
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++;
ifp->if_ibytes += m->m_pkthdr.len + sizeof (*eh);
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;
}
#endif /* NVLAN > 0 */
switch (ether_type) {
#ifdef INET
case ETHERTYPE_IP:
if (ipflow_fastforward(m))
return;
schednetisr(NETISR_IP);
inq = &ipintrq;
break;
case ETHERTYPE_ARP:
if (ifp->if_flags & IFF_NOARP) {
/* Discard packet if ARP is disabled on interface */
m_freem(m);
return;
}
schednetisr(NETISR_ARP);
inq = &arpintrq;
break;
#endif
#ifdef IPX
case ETHERTYPE_IPX:
if (ef_inputp && ef_inputp(ifp, eh, m) == 0)
return;
schednetisr(NETISR_IPX);
inq = &ipxintrq;
break;
#endif
#ifdef INET6
case ETHERTYPE_IPV6:
schednetisr(NETISR_IPV6);
inq = &ip6intrq;
break;
#endif
#ifdef NS
case 0x8137: /* Novell Ethernet_II Ethernet TYPE II */
schednetisr(NETISR_NS);
inq = &nsintrq;
break;
#endif /* NS */
#ifdef NETATALK
case ETHERTYPE_AT:
schednetisr(NETISR_ATALK);
inq = &atintrq1;
break;
case ETHERTYPE_AARP:
/* probably this should be done with a NETISR as well */
aarpinput(IFP2AC(ifp), m); /* XXX */
return;
#endif /* NETATALK */
default:
#ifdef IPX
if (ef_inputp && ef_inputp(ifp, eh, m) == 0)
return;
#endif /* IPX */
#ifdef NS
checksum = mtod(m, ushort *);
/* Novell 802.3 */
if ((ether_type <= ETHERMTU) &&
((*checksum == 0xffff) || (*checksum == 0xE0E0))){
if(*checksum == 0xE0E0) {
m->m_pkthdr.len -= 3;
m->m_len -= 3;
m->m_data += 3;
}
schednetisr(NETISR_NS);
inq = &nsintrq;
break;
}
#endif /* NS */
#if defined(NETATALK)
if (ether_type > ETHERMTU)
goto dropanyway;
l = mtod(m, struct llc *);
switch (l->llc_dsap) {
case LLC_SNAP_LSAP:
switch (l->llc_control) {
case LLC_UI:
if (l->llc_ssap != LLC_SNAP_LSAP)
goto dropanyway;
if (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, sizeof( struct llc ));
schednetisr(NETISR_ATALK);
break;
}
if (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, sizeof( struct llc ));
aarpinput(IFP2AC(ifp), m); /* XXX */
return;
}
default:
goto dropanyway;
}
break;
dropanyway:
default:
if (ng_ether_input_orphan_p != NULL)
(*ng_ether_input_orphan_p)(ifp, m, eh);
else
m_freem(m);
return;
}
#else /* NETATALK */
if (ng_ether_input_orphan_p != NULL)
(*ng_ether_input_orphan_p)(ifp, m, eh);
else
m_freem(m);
return;
#endif /* NETATALK */
}
s = splimp();
if (IF_QFULL(inq)) {
IF_DROP(inq);
m_freem(m);
} else
IF_ENQUEUE(inq, m);
splx(s);
}
/*
* Perform common duties while attaching to interface list
*/
void
ether_ifattach(ifp, bpf)
register struct ifnet *ifp;
int bpf;
{
register struct ifaddr *ifa;
register struct sockaddr_dl *sdl;
if_attach(ifp);
ifp->if_type = IFT_ETHER;
ifp->if_addrlen = 6;
ifp->if_hdrlen = 14;
ifp->if_mtu = ETHERMTU;
ifp->if_resolvemulti = ether_resolvemulti;
if (ifp->if_baudrate == 0)
ifp->if_baudrate = 10000000;
ifa = ifnet_addrs[ifp->if_index - 1];
sdl = (struct sockaddr_dl *)ifa->ifa_addr;
sdl->sdl_type = IFT_ETHER;
sdl->sdl_alen = ifp->if_addrlen;
bcopy((IFP2AC(ifp))->ac_enaddr, LLADDR(sdl), ifp->if_addrlen);
#ifdef BPF
if (bpf)
bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));
#endif
if (ng_ether_attach_p != NULL)
(*ng_ether_attach_p)(ifp);
}
/*
* Perform common duties while detaching an Ethernet interface
*/
void
ether_ifdetach(ifp, bpf)
struct ifnet *ifp;
int bpf;
{
if (ng_ether_detach_p != NULL)
(*ng_ether_detach_p)(ifp);
#ifdef BPF
if (bpf)
bpfdetach(ifp);
#endif
if_detach(ifp);
}
int
ether_ioctl(ifp, command, data)
struct ifnet *ifp;
int command;
caddr_t data;
{
struct ifaddr *ifa = (struct ifaddr *) data;
struct ifreq *ifr = (struct ifreq *) data;
int error = 0;
switch (command) {
case SIOCSIFADDR:
ifp->if_flags |= IFF_UP;
switch (ifa->ifa_addr->sa_family) {
#ifdef INET
case AF_INET:
ifp->if_init(ifp->if_softc); /* before arpwhohas */
arp_ifinit(IFP2AC(ifp), ifa);
break;
#endif
#ifdef IPX
/*
* XXX - This code is probably wrong
*/
case AF_IPX:
{
register struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr);
struct arpcom *ac = IFP2AC(ifp);
if (ipx_nullhost(*ina))
ina->x_host =
*(union ipx_host *)
ac->ac_enaddr;
else {
bcopy((caddr_t) ina->x_host.c_host,
(caddr_t) ac->ac_enaddr,
sizeof(ac->ac_enaddr));
}
/*
* Set new address
*/
ifp->if_init(ifp->if_softc);
break;
}
#endif
#ifdef NS
/*
* XXX - This code is probably wrong
*/
case AF_NS:
{
register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
struct arpcom *ac = IFP2AC(ifp);
if (ns_nullhost(*ina))
ina->x_host =
*(union ns_host *) (ac->ac_enaddr);
else {
bcopy((caddr_t) ina->x_host.c_host,
(caddr_t) ac->ac_enaddr,
sizeof(ac->ac_enaddr));
}
/*
* Set new address
*/
ifp->if_init(ifp->if_softc);
break;
}
#endif
default:
ifp->if_init(ifp->if_softc);
break;
}
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:
/*
* Set the interface MTU.
*/
if (ifr->ifr_mtu > ETHERMTU) {
error = EINVAL;
} else {
ifp->if_mtu = ifr->ifr_mtu;
}
break;
}
return (error);
}
int
ether_resolvemulti(ifp, llsa, sa)
struct ifnet *ifp;
struct sockaddr **llsa;
struct sockaddr *sa;
{
struct sockaddr_dl *sdl;
struct sockaddr_in *sin;
#ifdef INET6
struct sockaddr_in6 *sin6;
#endif
u_char *e_addr;
switch(sa->sa_family) {
case AF_LINK:
/*
* No mapping needed. Just check that it's a valid MC address.
*/
sdl = (struct sockaddr_dl *)sa;
e_addr = LLADDR(sdl);
if ((e_addr[0] & 1) != 1)
return EADDRNOTAVAIL;
*llsa = 0;
return 0;
#ifdef INET
case AF_INET:
sin = (struct sockaddr_in *)sa;
if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr)))
return EADDRNOTAVAIL;
MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR,
M_WAITOK|M_ZERO);
sdl->sdl_len = sizeof *sdl;
sdl->sdl_family = AF_LINK;
sdl->sdl_index = ifp->if_index;
sdl->sdl_type = IFT_ETHER;
sdl->sdl_alen = ETHER_ADDR_LEN;
e_addr = LLADDR(sdl);
ETHER_MAP_IP_MULTICAST(&sin->sin_addr, e_addr);
*llsa = (struct sockaddr *)sdl;
return 0;
#endif
#ifdef INET6
case AF_INET6:
sin6 = (struct sockaddr_in6 *)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;
*llsa = 0;
return 0;
}
if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
return EADDRNOTAVAIL;
MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR,
M_WAITOK|M_ZERO);
sdl->sdl_len = sizeof *sdl;
sdl->sdl_family = AF_LINK;
sdl->sdl_index = ifp->if_index;
sdl->sdl_type = IFT_ETHER;
sdl->sdl_alen = ETHER_ADDR_LEN;
e_addr = LLADDR(sdl);
ETHER_MAP_IPV6_MULTICAST(&sin6->sin6_addr, e_addr);
*llsa = (struct sockaddr *)sdl;
return 0;
#endif
default:
/*
* Well, the text isn't quite right, but it's the name
* that counts...
*/
return EAFNOSUPPORT;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -