📄 if_subr.c
字号:
/* if_subr.c - common routines for network interface drivers *//* Copyright 1990-1996 Wind River Systems, Inc. */#include "copyright_wrs.h"/* * Copyright (c) 1982, 1989, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)if_ethersubr.c 8.1 (Berkeley) 6/10/93 *//*modification history--------------------01h,21aug98,n_s updated if_omcast in ether_output () if_noproto in do_protocol_with_type (). spr2107401f,19sep97,vin modified build_cluster to incorporate cluster blks, removed pointers to refcounts.01g,11aug97,vin changed mBlkGet to use _pNetDpool.01e,10jul97,vin removed unsupported revarpinput() code.01f,05jun97,vin corrected processing for promiscuous interfaces in ether_input.01e,02jun97,spm updated man page for bcopy_to_mbufs()01d,15may97,vin reworked ether_input, cleanup, added copyFromMbufs(). removed support for check_trailer().01c,16dec96,vin removed unnecessary ntohs(). 01b,13nov96,vin replaced m_gethdr with mBlkGet() in buildCluster.01a,03mar96,vin created from BSD4.4 stuff,integrated with 02p of if_subr.c*/#include "vxWorks.h"#include "stdlib.h"#include "stdio.h"#include "tickLib.h"#include "logLib.h"#include "errno.h"#include "netinet/in.h"#include "netinet/in_systm.h"#include "netinet/in_var.h"#include "netinet/ip.h"#include "net/if.h"#include "net/if_arp.h"#include "netinet/if_ether.h"#include "net/if_subr.h"#include "netinet/in_var.h"#include "net/mbuf.h"#include "net/route.h"#include "net/if_llc.h"#include "net/if_dl.h"#include "net/if_types.h"#include "lstLib.h"#include "netLib.h"typedef struct net_type { NODE node; FUNCPTR inputRtn; int etherType; } NET_TYPE;/* externs */extern struct ifnet loif;extern looutput();u_char etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };u_char ether_ipmulticast_min[6] = { 0x01, 0x00, 0x5e, 0x00, 0x00, 0x00 };u_char ether_ipmulticast_max[6] = { 0x01, 0x00, 0x5e, 0x7f, 0xff, 0xff };#define senderr(e) { error = (e); goto bad;}LOCAL LIST netTypeList;/* * Ethernet output routine. * Encapsulate a packet of type family for the local net. * Use trailer local net encapsulation if enough data in first * packet leaves a multiple of 512 bytes of data in remainder. * Assumes that ifp is actually pointer to arpcom structure. */intether_output(ifp, m0, dst, rt0) register struct ifnet *ifp; struct mbuf *m0; struct sockaddr *dst; struct rtentry *rt0;{ u_short etype; int s, error = 0; u_char edst[6]; register struct mbuf *m = m0; register struct rtentry *rt; struct mbuf *mcopy = (struct mbuf *)0; register struct ether_header *eh; int off, len = m->m_pkthdr.len; struct arpcom *ac = (struct arpcom *)ifp; if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) senderr(ENETDOWN); ifp->if_lastchange = tickGet(); if ((rt = rt0)) { if ((rt->rt_flags & RTF_UP) == 0) { if ((rt0 = rt = rtalloc1(dst, 1))) rt->rt_refcnt--; else senderr(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); if ((rt = rt->rt_gwroute) == 0) senderr(EHOSTUNREACH); } } if (rt->rt_flags & RTF_REJECT) if (rt->rt_rmx.rmx_expire == 0 || tickGet() < rt->rt_rmx.rmx_expire) senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH); } switch (dst->sa_family) {#ifdef INET case AF_INET: if (!arpresolve(ac, rt, m, dst, edst)) return (0); /* if not yet resolved */ /* If broadcasting on a simplex interface, loopback a copy */ if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX)) mcopy = m_copy(m, 0, (int)M_COPYALL); off = m->m_pkthdr.len - m->m_len; etype = ETHERTYPE_IP; break;#endif case AF_UNSPEC: eh = (struct ether_header *)dst->sa_data; bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst)); etype = eh->ether_type; break; default: printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit, dst->sa_family); senderr(EAFNOSUPPORT); } if (mcopy) (void) looutput(ifp, mcopy, dst, rt); /* * Add local net header. If no space in first mbuf, * allocate another. */ M_PREPEND(m, sizeof (struct ether_header), M_DONTWAIT); if (m == 0) senderr(ENOBUFS); eh = mtod(m, struct ether_header *); etype = htons(etype); bcopy((caddr_t)&etype,(caddr_t)&eh->ether_type, sizeof(eh->ether_type)); bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst)); bcopy((caddr_t)ac->ac_enaddr, (caddr_t)eh->ether_shost, sizeof(eh->ether_shost)); s = splimp(); /* * Queue message on interface, and start output if interface * not yet active. */ if (IF_QFULL(&ifp->if_snd)) { IF_DROP(&ifp->if_snd); splx(s); senderr(ENOBUFS); } IF_ENQUEUE(&ifp->if_snd, m); if ((ifp->if_flags & IFF_OACTIVE) == 0) (*ifp->if_start)(ifp); splx(s); ifp->if_obytes += len + sizeof (struct ether_header); if (m->m_flags & M_MCAST || m->m_flags & M_BCAST) ifp->if_omcasts++; return (error);bad: if (m) m_freem(m); return (error);}/********************************************************************************* do_protocol - check the link-level type field and process IP and ARP data** This routine must not be called at interrupt level.* Process a received Ethernet packet;* the packet is in the mbuf chain m without* the ether header, which is provided separately.** NOMANUAL*/voidether_input(ifp, eh, m) struct ifnet *ifp; register struct ether_header *eh; struct mbuf *m;{ u_short etype; struct arpcom * ac = (struct arpcom *)ifp; if ((ifp->if_flags & IFF_UP) == 0) { m_freem(m); return; } ifp->if_lastchange = tickGet(); ifp->if_ibytes += m->m_pkthdr.len + sizeof (*eh); 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; ifp->if_imcasts++; } if (ifp->if_flags & IFF_PROMISC) { /* * do not hand over the non multicast packets to the ip stack * if they are not destined to us, orelse it confuses the * ip forwarding logic and keeps sending unnecessary redirects. * If packets destined for other hosts have to be snooped they * have to done through driver level hooks. */ if (!(m->m_flags & (M_BCAST | M_MCAST))) { if (bcmp ((caddr_t)ac->ac_enaddr, (caddr_t)eh->ether_dhost, sizeof(eh->ether_dhost)) != 0) { m_freem (m); /* free the packet chain */ return; } } } etype = ntohs(eh->ether_type); /* add code here to process IEEE802.3 LLC format, Hook!! */ /* demux the packet and hand off the ip layer */ do_protocol_with_type (etype, m , ac, m->m_pkthdr.len); }/* * 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; for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_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; }}/* * 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; u_char addrlo[6]; u_char addrhi[6]; int s = splimp(); switch (ifr->ifr_addr.sa_family) { case AF_UNSPEC: bcopy((char *)ifr->ifr_addr.sa_data, (char *)addrlo, 6); bcopy((char *) addrlo, (char *)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((char *)ether_ipmulticast_min, (char *)addrlo, 6); bcopy((char *)ether_ipmulticast_max, (char *)addrhi, 6); } else { ETHER_MAP_IP_MULTICAST(&sin->sin_addr, addrlo); bcopy((char *)addrlo, (char *)addrhi, 6); } break;#endif 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. */ MALLOC (enm, struct ether_multi *, sizeof(*enm), MT_IFMADDR, M_DONTWAIT); if (enm == NULL) { splx(s); return (ENOBUFS); } bcopy((char *)addrlo, (char *)enm->enm_addrlo, 6); bcopy((char *)addrhi, (char *)enm->enm_addrhi, 6); enm->enm_ac = ac; enm->enm_refcount = 1; enm->enm_next = ac->ac_multiaddrs; ac->ac_multiaddrs = enm; 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; register struct ether_multi **p; struct sockaddr_in *sin; u_char addrlo[6]; u_char addrhi[6]; int s = splimp(); switch (ifr->ifr_addr.sa_family) { case AF_UNSPEC: bcopy((char *)ifr->ifr_addr.sa_data, (char *)addrlo, 6); bcopy((char *)addrlo, (char *)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((char *)ether_ipmulticast_min, (char *)addrlo, 6); bcopy((char *)ether_ipmulticast_max, (char *)addrhi, 6); } else { ETHER_MAP_IP_MULTICAST(&sin->sin_addr, addrlo); bcopy((char *)addrlo, (char *)addrhi, 6); } break;#endif 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. */ for (p = &enm->enm_ac->ac_multiaddrs; *p != enm; p = &(*p)->enm_next) continue; *p = (*p)->enm_next; FREE(enm, MT_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);}/********************************************************************************* check_trailer - check ethernet frames that have trailers following them*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -