/* * Transmit a packet (low level interface) * 真正的处理的发送数据包 */ void snull_hw_tx(char *buf, int len, struct net_device *dev) { printk("snull_hw_tx\n"); struct iphdr *ih;//ip头部 struct snull_priv *priv = netdev_priv(dev);//获取私有数据 u32 *saddr, *daddr;//源设备地址与目标设备地址 //检查数据长度大小 if (len < sizeof(struct ethhdr) + sizeof(struct iphdr)) { printk("snull: Hmm... packet too short (%i octets)\n",len); return; } /* 开始发送数据(此处获取了ip地址用于打印)*/ ih = (struct iphdr *)(buf + sizeof(struct ethhdr)); saddr = &ih->saddr; daddr = &ih->daddr; printk("%pI4->%pI4\n", saddr, daddr); /* 调用中断模拟发送完毕 */ priv->status = SNULL_TX_INTR; priv->rx_packetlen = len; priv->rx_packetdata = buf; snull_interrupt(0, dev, NULL); return; }
/* * Deal with a transmit timeout. */ void snull_tx_timeout (struct net_device *dev) { struct snull_priv *priv = (struct snull_priv *)dev->priv; PDEBUG("Transmit timeout at %ld, latency %ld\n", jiffies, jiffies - dev->trans_start); priv->status = SNULL_TX_INTR; snull_interrupt(0, dev, NULL); priv->stats.tx_errors++; netif_wake_queue(dev); }
/* * 一旦超出watchdog_timeo就会调用snull_tx_timeout */ void snull_tx_timeout (struct net_device *dev) { printk("snull_tx_timeout\n"); struct snull_priv *priv = netdev_priv(dev); printk(KERN_INFO"Transmit timeout at %ld, latency %ld\n", jiffies,jiffies - dev->trans_start); priv->status = SNULL_TX_INTR; snull_interrupt(0, dev, NULL);//超时后发生中断 priv->stats.tx_errors++;//发送的错误数 netif_wake_queue(dev);//为了再次发送数据,调用此函数,重新启动发送队列 return; }
/* * Transmit a packet (low level interface) */ void snull_hw_tx(char *buf, int len, struct net_device *dev) { /* * This function deals with hw details. This interface loops * back the packet to the other snull interface (if any). * In other words, this function implements the snull behaviour, * while all other procedures are rather device-independent */ struct iphdr *ih; struct net_device *dest; struct snull_priv *privp; u32 *saddr, *daddr; /* I am paranoid. Ain't I? */ if (len < sizeof(struct ethhdr) + sizeof(struct iphdr)) { printk("snull: Hmm... packet too short (%i octets)\n", len); return; } if (0) { /* enable this conditional to look at the data */ int i; PDEBUG("len is %i\n" KERN_DEBUG "data:",len); for (i=14 ; i<len; i++) printk(" %02x",buf[i]&0xff); printk("\n"); } /* * Ethhdr is 14 bytes, but the kernel arranges for iphdr * to be aligned (i.e., ethhdr is unaligned) */ ih = (struct iphdr *)(buf+sizeof(struct ethhdr)); saddr = &ih->saddr; daddr = &ih->daddr; ((u8 *)saddr)[2] ^= 1; /* change the third octet (class C) */ ((u8 *)daddr)[2] ^= 1; ih->check = 0; /* and rebuild the checksum (ip needs it) */ ih->check = ip_fast_csum((unsigned char *)ih,ih->ihl); if (dev == snull_devs) PDEBUGG("%08x:%05i --> %08x:%05i\n", ntohl(ih->saddr),ntohs(((struct tcphdr *)(ih+1))->source), ntohl(ih->daddr),ntohs(((struct tcphdr *)(ih+1))->dest)); else PDEBUGG("%08x:%05i <-- %08x:%05i\n", ntohl(ih->daddr),ntohs(((struct tcphdr *)(ih+1))->dest), ntohl(ih->saddr),ntohs(((struct tcphdr *)(ih+1))->source)); /* * Ok, now the packet is ready for transmission: first simulate a * receive interrupt on the twin device, then a * transmission-done on the transmitting device */ dest = snull_devs + (dev==snull_devs ? 1 : 0); privp = (struct snull_priv *)dest->priv; privp->status = SNULL_RX_INTR; privp->rx_packetlen = len; privp->rx_packetdata = buf; snull_interrupt(0, dest, NULL); privp = (struct snull_priv *)dev->priv; privp->status = SNULL_TX_INTR; privp->tx_packetlen = len; privp->tx_packetdata = buf; if (lockup && ((privp->stats.tx_packets + 1) % lockup) == 0) { /* Simulate a dropped transmit interrupt */ netif_stop_queue(dev); PDEBUG("Simulate lockup at %ld, txp %ld\n", jiffies, (unsigned long) privp->stats.tx_packets); } else snull_interrupt(0, dev, NULL); }