TCP/IP协议详解卷2 第4章 以太网
TCP/IP协议详解卷2 第4章 以太网
卜星星 发表于3年前
TCP/IP协议详解卷2 第4章 以太网
  • 发表于 3年前
  • 阅读 74
  • 收藏 1
  • 点赞 0
  • 评论 0

腾讯云 新注册用户 域名抢购1元起>>>   

摘要: TCP/IP协议详解卷2 第4章 以太网 学习记录

        这一章说是要介绍:以太网设备驱动程序在初始化后是如何接收和传输帧的;还有配置网络通用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 )); 

这7个函数就是用来调用驱动程序的。不同设备都有不同的驱动函数,比如这里说的以太网那个if_output就是ether_output

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);
}

由于我其实也不知道究竟要看什么,哪些是有用的,哪些没有用,所以只能从头看下去,争取能看完一遍,之后再回来总结一下。
共有 人打赏支持
粉丝 24
博文 110
码字总数 68736
×
卜星星
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: