这一章说是要介绍:以太网设备驱动程序在初始化后是如何接收和传输帧的;还有配置网络通用ioctl。
在ifnet中有7个函数:
/* 这是初始化等处理函数,这些函数就是我们访问网络设备驱动程序 */
int
(*if_init)
__P((
int
));
int
(*if_output)
__P((
struct
ifnet *,
struct
mbuf *,
struct
sockaddr *,
struct
rtentry *));
int
(*if_start)
__P((
struct
ifnet *));
int
(*if_done)
__P((
struct
ifnet *));
int
(*if_ioctl)
__P((
struct
ifnet *, u_long, caddr_t));
int
(*if_reset)
__P((
int
));
int
(*if_watchdog)
__P((
int
));
SNMP:简单网络管理协议信息库(SNMP MIB-II)
以太网封闭结构:目标地址(6) 源地址(6)协议类型(2) 共14字节 46~1500数据 CRC(4)
当设备接收到一个以太网帧,并且完整可用时,就产生中断,调用leintr,leintr调用leread把帧从接口弄到mbuf中,
所以以太网设备驱动程序将接收到的帧传给ether_input处理
leread函数第一个参数unit就是在ifnet中的那个if_unit同一类接口不同编号
leread(unit, buf, len) int unit; char *buf; int len; { register struct le_softc *le = &le_softc[unit]; register struct ether_header *et; struct mbuf *m; int off, resid, flags;
le->sc_if.if_ipackets++; et = (struct ether_header *)buf; et->ether_type = ntohs((u_short)et->ether_type); /* adjust input length to account for header and CRC */ len = len - sizeof(struct ether_header) - 4;
#define ledataaddr(et, off, type) ((type)(((caddr_t)((et)+1)+(off)))) if (et->ether_type >= ETHERTYPE_TRAIL && et->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { off = (et->ether_type - ETHERTYPE_TRAIL) * 512; if (off >= ETHERMTU) return; /* sanity */ et->ether_type = ntohs(*ledataaddr(et, off, u_short *)); resid = ntohs(*(ledataaddr(et, off+2, u_short *))); if (off + resid > len) return; /* sanity */ len = off + resid; } else off = 0;
if (len <= 0) { if (ledebug) log(LOG_WARNING, "le%d: ierror(runt packet): from %s: len=%d\n", unit, ether_sprintf(et->ether_shost), len); le->sc_runt++; le->sc_if.if_ierrors++; return; } flags = 0; if (bcmp((caddr_t)etherbroadcastaddr, (caddr_t)et->ether_dhost, sizeof(etherbroadcastaddr)) == 0) flags |= M_BCAST; if (et->ether_dhost[0] & 1) flags |= M_MCAST;
#if NBPFILTER > 0 /* * Check if there's a bpf filter listening on this interface. * If so, hand off the raw packet to enet. */ if (le->sc_if.if_bpf) { bpf_tap(le->sc_if.if_bpf, buf, len + sizeof(struct ether_header));
/* * Keep the packet if it's a broadcast or has our * physical ethernet address (or if we support * multicast and it's one). */ if ( #ifdef MULTICAST (flags & (M_BCAST | M_MCAST)) == 0 && #else (flags & M_BCAST) == 0 && #endif bcmp(et->ether_dhost, le->sc_addr, sizeof(et->ether_dhost)) != 0) return; } #endif /* * Pull packet off interface. Off is nonzero if packet * has trailing header; m_devget will then force this header * information to be at the front, but we still have to drop * the type and length which are at the front of any trailer data. */ m = m_devget((char *)(et + 1), len, off, &le->sc_if, 0); if (m == 0) return; m->m_flags |= flags; ether_input(&le->sc_if, et, m); }
void ether_input(ifp, eh, m) struct ifnet *ifp; register struct ether_header *eh; struct mbuf *m; { register struct ifqueue *inq; register struct llc *l; struct arpcom *ac = (struct arpcom *)ifp; int s;
if ((ifp->if_flags & IFF_UP) == 0) { m_freem(m); return; } ifp->if_lastchange = time; ifp->if_ibytes += m->m_pkthdr.len + sizeof (*eh); if (bcmp((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost, sizeof(etherbroadcastaddr)) == 0) m->m_flags |= M_BCAST; else if (eh->ether_dhost[0] & 1) m->m_flags |= M_MCAST; if (m->m_flags & (M_BCAST|M_MCAST)) ifp->if_imcasts++;
switch (eh->ether_type) { #ifdef INET case ETHERTYPE_IP: schednetisr(NETISR_IP); inq = &ipintrq; break;
case ETHERTYPE_ARP: schednetisr(NETISR_ARP); inq = &arpintrq; break; #endif default: if (eh->ether_type > ETHERMTU) { m_freem(m); return; } /* 下面很多都忽略掉了只留下了INET的 */
}
s = splimp(); if (IF_QFULL(inq)) { IF_DROP(inq); m_freem(m); } else IF_ENQUEUE(inq, m); splx(s); } 由于我其实也不知道究竟要看什么,哪些是有用的,哪些没有用,所以只能从头看下去,争取能看完一遍,之后再回来总结一下。