📄 snull.c
字号:
* 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); priv = (struct snull_priv *) dest->priv; priv->status = SNULL_RX_INTR; priv->rx_packetlen = len; priv->rx_packetdata = buf; snull_interrupt(0, dest, NULL); priv = (struct snull_priv *) dev->priv; priv->status = SNULL_TX_INTR; priv->tx_packetlen = len; priv->tx_packetdata = buf; if (lockup && ((priv->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) priv->stats.tx_packets); } else snull_interrupt(0, dev, NULL);}/* * Transmit a packet (called by the kernel) */int snull_tx(struct sk_buff *skb, struct net_device *dev){ int len; char *data; struct snull_priv *priv = (struct snull_priv *) dev->priv;#ifndef LINUX_24 if (dev->tbusy || skb == NULL) { PDEBUG("tint for %p, tbusy %ld, skb %p\n", dev, dev->tbusy, skb); snull_tx_timeout (dev); if (skb == NULL) return 0; }#endif len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len; data = skb->data; dev->trans_start = jiffies; /* save the timestamp */ /* Remember the skb, so we can free it at interrupt time */ priv->skb = skb; /* actual deliver of data is device-specific, and not shown here */ snull_hw_tx(data, len, dev); return 0; /* Our simple device can not fail */}/* * 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); return;}/* * Ioctl commands */int snull_ioctl(struct net_device *dev, struct ifreq *rq, int cmd){ PDEBUG("ioctl\n"); return 0;}/* * Return statistics to the caller */struct net_device_stats *snull_stats(struct net_device *dev){ struct snull_priv *priv = (struct snull_priv *) dev->priv; return &priv->stats;}/* * This function is called to fill up an eth header, since arp is not * available on the interface */#ifndef LINUX_20int snull_rebuild_header(struct sk_buff *skb){ struct ethhdr *eth = (struct ethhdr *) skb->data; struct net_device *dev = skb->dev; memcpy(eth->h_source, dev->dev_addr, dev->addr_len); memcpy(eth->h_dest, dev->dev_addr, dev->addr_len); eth->h_dest[ETH_ALEN-1] ^= 0x01; /* dest is us xor 1 */ return 0;}#else /* LINUX_20 */int snull_rebuild_header(void *buff, struct net_device *dev, unsigned long dst, struct sk_buff *skb){ struct ethhdr *eth = (struct ethhdr *)buff; memcpy(eth->h_source, dev->dev_addr, dev->addr_len); memcpy(eth->h_dest, dev->dev_addr, dev->addr_len); eth->h_dest[ETH_ALEN-1] ^= 0x01; /* dest is us xor 1 */ return 0;}#endif /* LINUX_20 */int snull_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, void *daddr, void *saddr, unsigned int len){ struct ethhdr *eth = (struct ethhdr *)skb_push(skb,ETH_HLEN); eth->h_proto = htons(type); memcpy(eth->h_source, saddr ? saddr : dev->dev_addr, dev->addr_len); memcpy(eth->h_dest, daddr ? daddr : dev->dev_addr, dev->addr_len); eth->h_dest[ETH_ALEN-1] ^= 0x01; /* dest is us xor 1 */ return (dev->hard_header_len);}/* * The "change_mtu" method is usually not needed. * If you need it, it must be like this. */int snull_change_mtu(struct net_device *dev, int new_mtu){ unsigned long flags; spinlock_t *lock = &((struct snull_priv *) dev->priv)->lock; /* check ranges */ if ((new_mtu < 68) || (new_mtu > 1500)) return -EINVAL; /* * Do anything you need, and the accept the value */ spin_lock_irqsave(lock, flags); dev->mtu = new_mtu; spin_unlock_irqrestore(lock, flags); return 0; /* success */}/* * The init function (sometimes called probe). * It is invoked by register_netdev() */int snull_init(struct net_device *dev){#if 0 /* * Make the usual checks: check_region(), probe irq, ... -ENODEV * should be returned if no device found. No resource should be * grabbed: this is done on open(). */#endif /* * Then, assign other fields in dev, using ether_setup() and some * hand assignments */ ether_setup(dev); /* assign some of the fields */ dev->open = snull_open; dev->stop = snull_release; dev->set_config = snull_config; dev->hard_start_xmit = snull_tx; dev->do_ioctl = snull_ioctl; dev->get_stats = snull_stats; dev->change_mtu = snull_change_mtu; dev->rebuild_header = snull_rebuild_header; dev->hard_header = snull_header;#ifdef HAVE_TX_TIMEOUT dev->tx_timeout = snull_tx_timeout; dev->watchdog_timeo = timeout;#endif /* keep the default flags, just add NOARP */ dev->flags |= IFF_NOARP;#ifndef LINUX_20 dev->hard_header_cache = NULL; /* Disable caching */#endif SET_MODULE_OWNER(dev); /* * Then, allocate the priv field. This encloses the statistics * and a few private fields. */ dev->priv = kmalloc(sizeof(struct snull_priv), GFP_KERNEL); if (dev->priv == NULL) return -ENOMEM; memset(dev->priv, 0, sizeof(struct snull_priv)); spin_lock_init(& ((struct snull_priv *) dev->priv)->lock); return 0;}/* * The devices */#ifdef LINUX_24struct net_device snull_devs[2] = { { init: snull_init, }, /* init, nothing more */ { init: snull_init, }};#else /* pre-2.4 */char snull_names[16];struct net_device snull_devs[2] = { { name: snull_names, init: snull_init, /* init function */ }, { name: snull_names+8, init: snull_init, /* init function */ }};#endif /* LINUX_24 *//* * Finally, the module stuff */int snull_init_module(void){ int result, i, device_present = 0; snull_eth = eth; /* copy the cfg datum in the non-static place */ if (!snull_eth) { /* call them "sn0" and "sn1" */ strcpy(snull_devs[0].name, "sn0"); strcpy(snull_devs[1].name, "sn1"); } else { /* use automatic assignment */#ifdef LINUX_24 strcpy(snull_devs[0].name, "eth%d"); strcpy(snull_devs[1].name, "eth%d");#else snull_devs[0].name[0] = snull_devs[1].name[0] = ' '; #endif } for (i=0; i<2; i++) if ( (result = register_netdev(snull_devs + i)) ) printk("snull: error %i registering device \"%s\"\n", result, snull_devs[i].name); else device_present++;#ifndef SNULL_DEBUG EXPORT_NO_SYMBOLS;#endif return device_present ? 0 : -ENODEV;}void snull_cleanup(void){ int i; for (i=0; i<2; i++) { kfree(snull_devs[i].priv); unregister_netdev(snull_devs + i); } return;}module_init(snull_init_module);module_exit(snull_cleanup);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -