📄 if_ethersubr.c
字号:
*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
#ifdef __ECOS
sched_what = NETISR_ISO;
#else
schednetisr(NETISR_ISO);
#endif
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 */
#ifdef __ECOS
sched_what = NETISR_CCITT;
#else
schednetisr(NETISR_CCITT);
#endif
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);
#ifdef __ECOS
schednetisr(sched_what);
#endif
}
/*
* 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
*/
void
ether_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);
}
void
ether_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 INET6
u_char ether_ip6multicast_min[6] = { 0x33, 0x33, 0x00, 0x00, 0x00, 0x00 };
u_char ether_ip6multicast_max[6] = { 0x33, 0x33, 0xff, 0xff, 0xff, 0xff };
#endif
/*
* Add an Ethernet multicast address or range of addresses to the list for a
* given interface.
*/
int
ether_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 *)
&(((struct in6_ifreq *)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_ip6multicast_min, addrlo, ETHER_ADDR_LEN);
bcopy(ether_ip6multicast_max, addrhi, ETHER_ADDR_LEN);
} else {
ETHER_MAP_IPV6_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.
*/
int
ether_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_ip6multicast_min, addrlo, ETHER_ADDR_LEN);
bcopy(ether_ip6multicast_max, addrhi, ETHER_ADDR_LEN);
} else {
ETHER_MAP_IPV6_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 + -