www.pudn.com > vxworks_tcpip_code.rar > 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 (). spr21074
01f,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.
*/
int
ether_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
*/
void
ether_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
*/
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;
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.
*/
int
ether_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.
*/
int
ether_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
*
* Decypher the ethernet frames that are encoded via trailer protocol which
* has a link level type field that contains a value which is an encoding of
* the size of the data portion. The original BSD 4.2 and 4.3 TCP/IP
* implementations use the trailer protocol to accomplish more efficient
* copying of data. Basically the idea was to put the variable lenght protocol
* headers (TCP, UDP, IP headers) at the end of a page aligned data and use
* the link-level type field (ethernet type) to indicate both the use of a
* specialized framing protocol as well as the length of the data following
* the ethernet header. The original link-level type field and the length
* of the protocol headers following the data portion are attached between
* the data portion (which should be of length multiple of 512 bytes) and
* protocol headers. (size of data portion == (type - 0x1000) * 415)
*
* Upon return, 'pOff' will contain NULL if trailer protocol is not being
* used. Otherwise, 'pOff' points to the trailer header and 'pLen'
* will contain the size of the frame.
*
* NOMANUAL
*/
void check_trailer (eh, pData, pLen, pOff, ifp)
FAST struct ether_header *eh; /* ethernet header */
FAST unsigned char *pData; /* data immediately after 'eh' */
FAST int *pLen; /* value/result input data length */
FAST int *pOff; /* result -- points to trailer header */
FAST struct ifnet *ifp; /* network interface */
{
#if 0 /* XXX No support for trailers in BSD44 vxWorks */
FAST int resid;
eh->ether_type = ntohs((u_short)eh->ether_type);
if ((eh->ether_type >= ETHERTYPE_TRAIL) &&
(eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER))
{
*pOff = (eh->ether_type - ETHERTYPE_TRAIL) * 512;
if (*pOff >= ifp->if_mtu)
return; /* sanity */
eh->ether_type = ntohs (*(u_short *) (pData + *pOff));
resid = ntohs (*(u_short *) (pData + *pOff + 2));
if ((*pOff + resid) > *pLen)
return; /* sanity */
*pLen = *pOff + resid;
}
else
*pOff = 0;
#endif /* XXX No trailer support in BSD44 */
}
/*******************************************************************************
*
* bcopy_to_mbufs - copy data into mbuf chain
*
* Copies up to bytes of data from into a freshly allocated
* mbuf. The parameter indicates the amount of trailer encapsulation,
* which was formerly handled according to the trailer protocol described in
* check_trailer(). Since trailer encapsulation is not supported in BSD 4.4,
* that parameter is unused. The argument supports machines which
* have special byte alignment requirements when copying data from device
* I/O buffers to main memory. A macro function called 'copy_to_mbufs' is
* provided in the "mbuf.h" file for compatability with SunOS, which doesn't
* support the parameter. This function uses mbuf clusters when possible
* to enhance network throughput.
*
* RETURNS: first mbuf or 0 if error
*
* NOMANUAL
*/
struct mbuf *bcopy_to_mbufs (buf0, totlen, off0, ifp, width)
u_char *buf0; /* buffer to be copied into mbufs */
int totlen; /* number of bytes to be copied */
int off0; /* trailer protocol indicative */
struct ifnet *ifp; /* network interface */
int width; /* copy data by this unit width */
{
return (m_devget ((char *) buf0, totlen, width, ifp, NULL));
}
/*******************************************************************************
* copyFromMbufs - copy data from an mbuf chain
*
* This routine copies data from an mbuf chain into a given buffer.
* The length of the data copied from the mbuf chain is returned.
* The argument width is provided for machines that have special byte alignment
* requirements when copying data to an I/O buffer of the device from main
* memory. This routine frees the mbuf chain passed to it.
*
* RETURNS: length of data copied.
*
* NOMANUAL
*/
int copyFromMbufs
(
char * pIoBuf, /* buffer to copy mbufs into */
struct mbuf * pMbuf, /* pointer to an mbuf chain */
int width /* width of the copy */
)
{
FAST char * pBuf = (char *) (pIoBuf);
FAST struct mbuf * pMbufHead = pMbuf;
FAST char * adjBuf;
FAST int adjLen;
FAST int odd = 0;
FAST int ix;
char temp [4];
if (width == NONE)
{
for (; pMbuf != NULL; pBuf += pMbuf->m_len, pMbuf = pMbuf->m_next)
bcopy (mtod (pMbuf, char *), pBuf, pMbuf->m_len);
}
else if (width == 1)
{
for (; pMbuf != NULL; pBuf += pMbuf->m_len, pMbuf = pMbuf->m_next)
bcopyBytes (mtod (pMbuf, char *), pBuf, pMbuf->m_len);
}
else if (width == 2)
{
for (; pMbuf != NULL; pMbuf = pMbuf->m_next)
{
adjLen = pMbuf->m_len;
adjBuf = mtod(pMbuf, char *);
if (odd > 0)
{
--pBuf;
*((UINT16 *) temp) = *((UINT16 *) pBuf);
temp [1] = *adjBuf++;
--adjLen;
*((UINT16 *) pBuf) = *((UINT16 *) temp);
pBuf += 2;
}
bcopyWords (adjBuf, pBuf, (adjLen + 1) >> 1);
pBuf += adjLen;
odd = adjLen & 0x1;
}
}
else if (width == 4)
{
for (; pMbuf != NULL; pMbuf = pMbuf->m_next)
{
adjLen = pMbuf->m_len;
adjBuf = mtod(pMbuf, char *);
if (odd > 0)
{
pBuf -= odd;
*((UINT32 *) temp) = *((UINT32 *) pBuf);
for (ix = odd; ix < 4; ix++, adjBuf++, --adjLen)
temp [ix] = *adjBuf;
*((UINT32 *) pBuf) = *((UINT32 *) temp);
pBuf += 4;
}
bcopyLongs (adjBuf, pBuf, (adjLen + 3) >> 2);
pBuf += adjLen;
odd = adjLen & 0x3;
}
}
else
{
panic ("copyFromMbufs");
}
m_freem (pMbufHead); /* free the mbuf chain */
return ((int) pBuf - (int) pIoBuf); /* return length copied */
}
/*******************************************************************************
*
* build_cluster - encapsulate a passed buffer into a cluster mbuf.
*
* This routine is used to surround the passed buffer with a
* mbuf header and make it a pseudo cluster. It is used primarily by the
* network interface drivers to avoid copying large chunk of data incoming
* from the network. Network interface device drivers typically call this
* routine with a pointer to the memory location where the IP data reside.
* This buffer pointer is used as a cluster buffer pointer and inserted
* into mbuf along with other relevant pieces information such as the
* index into the reference count array, pointer to the reference count
* array and the driver level free routine.
*
* RETURNS: NULL if unsuccessful, pointer to if successful.
*
* SEE ALSO: do_protocol_with_type(), uipc_mbuf.c
*
* NOMANUAL
*/
struct mbuf *build_cluster (buf0, totlen, ifp, ctype, pRefCnt,
freeRtn, arg1, arg2, arg3)
u_char *buf0; /* the buffer containing data */
int totlen; /* len of the buffer */
struct ifnet *ifp; /* network interface device pointer */
u_char ctype; /* type of this cluster being built */
u_char *pRefCnt; /* type-specific ref count array */
FUNCPTR freeRtn; /* driver level free callback routine */
int arg1; /* first argument to freeRtn() */
int arg2; /* second argument to freeRtn() */
int arg3; /* third argument to freeRtn() */
{
FAST struct mbuf *m;
CL_BLK_ID pClBlk;
/* get an mbuf header, header will have ifp info in the packet header */
m = mBlkGet(_pNetDpool, M_DONTWAIT, MT_DATA);
if (m == NULL) /* out of mbufs! */
return (NULL);
pClBlk = clBlkGet (_pNetDpool, M_DONTWAIT);
if (pClBlk == NULL) /* out of cl Blks */
{
m_free (m);
return (NULL);
}
/* intialize the header */
m->m_pkthdr.rcvif = ifp;
m->m_pkthdr.len = totlen;
m->m_data = (caddr_t) buf0;
m->m_len = m->m_pkthdr.len;
m->m_flags = (M_EXT | M_PKTHDR) ;
m->pClBlk = pClBlk;
m->m_extBuf = (caddr_t) buf0;
m->m_extSize = m->m_pkthdr.len;
m->m_extFreeRtn = freeRtn;
m->m_extArg1 = arg1;
m->m_extArg2 = arg2;
m->m_extArg3 = arg3;
m->m_extRefCnt = 1;
return (m);
}
/*******************************************************************************
*
* do_protocol_with_type - demultiplex incoming packet to the protocol handlers
*
* Demultiplexes the incoming packet to the associated protocol handler. This
* version supports IP, ARP, and a generic mechanism via an external lookup
* table.
*
* This routine differs from do_protocol() in that the link-level frame type
* is passed directly, instead of passing a pointer to an Ethernet header,
* respectively.
*
* This routine must not be called interrupt level.
*
* NOMANUAL
*/
void do_protocol_with_type
(
u_short type, /* the frame type field */
struct mbuf * pMbuf, /* the frame data, in mbuf chain */
struct arpcom * pArpcom, /* the source interface information */
int len /* length of the mbuf data */
)
{
int spl;
int netIsr;
FAST struct ifqueue * inq;
switch (type)
{
#ifdef INET
case ETHERTYPE_IP:
netIsr = NETISR_IP;
inq = &ipintrq;
break;
case ETHERTYPE_ARP:
netIsr = NETISR_ARP;
inq = &arpintrq;
break;
#endif
default:
{
NET_TYPE * pType;
/* look for any other types */
for (pType = (NET_TYPE *) lstFirst (&netTypeList);
pType != NULL; pType = (NET_TYPE *) lstNext (&pType->node))
{
if (pType->etherType == type)
{
if (pType->inputRtn != NULL)
(*pType->inputRtn) (pArpcom, pMbuf, len);
return;
}
}
/* No protocol. Drop packet */
((struct ifnet *) pArpcom)->if_noproto++;
m_freem(pMbuf); /* free the mbuf chain */
return;
}
}
spl = splimp();
if (IF_QFULL(inq))
{
IF_DROP(inq);
m_freem(pMbuf); /* free the mbuf chain */
}
else
{
IF_ENQUEUE(inq, pMbuf); /* put the mbuf chain in the packet queue */
schednetisr(netIsr); /* schedule the appropriate input routine */
}
splx (spl);
}
/*******************************************************************************
*
* set_if_addr - handle SIOCSIFADDR ioctl
*
* Sets a protocol address associated with this network interface.
* This function is called by various ioctl handlers in each of the network
* interface drivers.
*
* RETURNS: 0 or appropriate errno
*
* NOMANUAL
*/
int set_if_addr (ifp, data, enaddr)
struct ifnet *ifp; /* interface */
char *data; /* usually "struct ifaddr *" */
u_char *enaddr;/* ethernet address */
{
int error = 0;
FAST struct ifaddr *ifa = (struct ifaddr *) data;
ifp->if_flags |= IFF_UP;
if ((error = (*ifp->if_init) (ifp->if_unit)) != 0)
return (error);
switch (ifa->ifa_addr->sa_family)
{
#ifdef INET
case AF_INET:
((struct arpcom *) ifp)->ac_ipaddr = IA_SIN (ifa)->sin_addr;
arpwhohas ((struct arpcom *) ifp, &IA_SIN (ifa)->sin_addr);
break;
#endif /* INET */
default:
logMsg ("eh: set_if_addr unknown family 0x%x\n",
ifa->ifa_addr->sa_family,0,0,0,0,0);
break;
}
return (0);
}
/*******************************************************************************
*
* ether_attach - attach a new network interface to the network layer.
*
* Fill in the ifnet structure and pass it off to if_attach () routine
* which will attach the network interface described in that structure
* to the network layer software for future use in routing, packet reception,
* and transmisison.
*
* NOMANUAL
*/
void ether_attach (ifp, unit, name, initRtn, ioctlRtn, outputRtn, resetRtn)
struct ifnet *ifp; /* network interface data structure */
int unit; /* unit number */
char *name; /* name of the interface */
FUNCPTR initRtn; /* initialization routine */
FUNCPTR ioctlRtn; /* ioctl handler */
FUNCPTR outputRtn; /* output routine */
FUNCPTR resetRtn; /* reset routine */
{
bzero ((char *) ifp, sizeof (*ifp));
ifp->if_unit = unit;
ifp->if_name = name;
ifp->if_mtu = ETHERMTU;
ifp->if_init = initRtn;
ifp->if_ioctl = ioctlRtn;
ifp->if_output = outputRtn;
ifp->if_reset = resetRtn;
ifp->if_flags = IFF_BROADCAST;
if_attach (ifp);
}
/*******************************************************************************
*
* netTypeAdd - add a network type to list of network types.
*
* RETURNS: OK if successful, otherwise ERROR.
*
* NOMANUAL
*/
STATUS netTypeAdd (etherType, inputRtn)
int etherType; /* ethernet type */
FUNCPTR inputRtn; /* input routine */
{
NET_TYPE * pType;
if ((pType = (NET_TYPE *) calloc (1, sizeof (NET_TYPE))) == NULL)
return (ERROR);
pType->etherType = etherType;
pType->inputRtn = inputRtn;
lstAdd (&netTypeList, &pType->node);
return (OK);
}
/*******************************************************************************
*
* netTypeDelete - delete a network type from the list of network types.
*
* RETURNS: OK if successful, otherwise ERROR.
*
* NOMANUAL
*/
STATUS netTypeDelete (etherType)
int etherType; /* ethernet type */
{
NET_TYPE * pType;
for (pType = (NET_TYPE *) lstFirst (&netTypeList);
pType != NULL; pType = (NET_TYPE *) lstNext (&pType->node))
{
if (etherType == pType->etherType)
{
lstDelete (&netTypeList, &pType->node);
free ((caddr_t) pType);
return (OK);
}
}
return (ERROR);
}
/*******************************************************************************
*
* netTypeInit - initialize list of network types.
*
* RETURNS: N/A
*
* NOMANUAL
*/
void netTypeInit ()
{
lstInit (&netTypeList);
}