📄 insane.c
字号:
/* * insane.c -- source for the "insane" module, a sample virtual interface * * Copyright (c) 2000 Alessandro Rubini (rubini@linux.it) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. */#ifndef __KERNEL__# define __KERNEL__#endif/* The Makefile takes care of adding -DMODULE */#include <linux/module.h>#include <linux/kernel.h> /* printk() */#include <linux/malloc.h> /* kmalloc() */#include <linux/errno.h> /* error codes */#include <linux/netdevice.h> /* basic data structures */#include <linux/init.h> /* __init */#include <linux/if_arp.h> /* ARPHRD_ETHER */#include <net/arp.h> /* neighbor stuff */#include <asm/uaccess.h> /* memcpy and such */#include "insane.h"#if LINUX_VERSION_CODE < 0x020300 /* 2.2 compatibility */# define net_device device# define __dev_get_by_name dev_get#endifstatic struct net_device insane_dev; /* forward decl *//* -------------------------------------------------------------------------- * definition of the "private" data structure used by this interface */struct insane_private { struct net_device_stats priv_stats; struct net_device *priv_device; /* interface used to xmit data */ int priv_mode; /* how to drop packets */ int priv_arg1; /* arguments to the dropping mode */ int priv_arg2;};/* -------------------------------------------------------------------------- * open and close */int insane_open(struct net_device *dev){ /* mark the device as operational */ dev->start = 1; dev->tbusy = 0; MOD_INC_USE_COUNT; return 0;}int insane_close(struct net_device *dev){ dev->start = 0; dev->tbusy = 1; MOD_DEC_USE_COUNT; return 0;}/* -------------------------------------------------------------------------- * get_stats: return a pointer to the device statistics */struct net_device_stats *insane_get_stats(struct net_device *dev){ return &((struct insane_private *)dev->priv)->priv_stats;}/* -------------------------------------------------------------------------- * header stuff: fall back on the slave interface to deal with this stuff */int insane_hard_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, void *daddr, void *saddr, unsigned len){ struct insane_private *priv = dev->priv; int retval; skb->dev = priv->priv_device; retval = skb->dev->hard_header(skb, skb->dev, type, daddr, saddr, len); skb->dev = dev; return retval;}static int insane_rebuild_header(struct sk_buff *skb){ struct insane_private *priv = insane_dev.priv; int retval; skb->dev = priv->priv_device; retval = skb->dev->rebuild_header(skb); skb->dev = &insane_dev; return retval;}/* -------------------------------------------------------------------------- * neighbors: this comes form shaper.c (Alan Cox) and is needed for ARP to work */int insane_neigh_setup(struct neighbour *n){ if (n->nud_state == NUD_NONE) { n->ops = &arp_broken_ops; n->output = n->ops->output; } return 0;}int insane_neigh_setup_dev(struct net_device *dev, struct neigh_parms *p){ if (p->tbl->family == AF_INET) { p->neigh_setup = insane_neigh_setup; p->ucast_probes = 0; p->mcast_probes = 0; } return 0;}/* -------------------------------------------------------------------------- * xmit: actual delivery (or not) of the data packets */int insane_xmit(struct sk_buff *skb, struct net_device *dev){ struct insane_private *priv = dev->priv; int accept; /* accept this packet or drop it */ static unsigned long randval; if (!priv->priv_device) { /* cannot send to anyone, just return */ priv->priv_stats.tx_errors++; priv->priv_stats.tx_dropped++; return 0; } switch (priv->priv_mode) { case INSANE_PERCENT: if (!randval) randval = jiffies; /* a typical seed */ /* hash the value, according to the TYPE_0 rule of glibc */ randval = ((randval * 1103515245) + 12345) & 0x7fffffff; accept = (randval % 100) < priv->priv_arg1; break; case INSANE_TIME: randval = jiffies % (priv->priv_arg1 + priv->priv_arg2); accept = randval < priv->priv_arg1; break; case INSANE_PASS: default: /* unknown mode: default to pass */ accept = 1; } if (!accept) { priv->priv_stats.tx_errors++; priv->priv_stats.tx_dropped++; return 0; } /* else, pass it to the real interface */ priv->priv_stats.tx_packets++; priv->priv_stats.tx_bytes += skb->len;#if 0 return priv->priv_device->hard_start_xmit(skb, priv->priv_device);#else skb->dev = priv->priv_device; skb->priority = 1; dev_queue_xmit (skb); return 0;#endif}/* -------------------------------------------------------------------------- * ioctl: let user programs configure this interface */int insane_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd){ int err; struct net_device *slave; struct insane_private *priv = dev->priv; /* hold a local (kernel-space) copy of the configuration data */ struct insane_userinfo info; /* and a pointer into user space as well */ struct insane_userinfo *uptr = (struct insane_userinfo *)ifr->ifr_data; /* only authorized users can control the interface */ if (cmd == SIOCINSANESETINFO && !capable(CAP_NET_ADMIN)) return -EPERM; /* process the command */ switch(cmd) { case SIOCINSANEGETINFO: /* return configuration to user space */ /* interface name */ memset(info.name, 0, INSANE_NAMELEN); if (priv->priv_device) strncpy(info.name, priv->priv_device->name, INSANE_NAMELEN-1); /* parameters */ info.mode = priv->priv_mode; info.arg1 = priv->priv_arg1; info.arg2 = priv->priv_arg2; /* return the data structure to user space */ err = copy_to_user(uptr, &info, sizeof(info)); if (err) return err; break; case SIOCINSANESETINFO: /* retrieve the data structure from user space */ err = copy_from_user(&info, uptr, sizeof(info)); if (err) return err; printk("name: %s, arg %i %i\n", info.name, info.arg1, info.arg2); /* interface name */ slave = __dev_get_by_name(info.name); if (!slave) return -ENODEV; if (slave->type != ARPHRD_ETHER && slave->type != ARPHRD_LOOPBACK) return -EINVAL; /* The interface is good, get hold of it */ priv->priv_device = slave; if (slave->hard_header) dev->hard_header = insane_hard_header; else dev->hard_header = NULL; if (slave->rebuild_header) dev->rebuild_header = insane_rebuild_header; else dev->rebuild_header = NULL; /* also, and clone its IP, MAC and other information */ memcpy(dev->dev_addr, slave->dev_addr, sizeof(slave->dev_addr)); memcpy(dev->broadcast, slave->broadcast, sizeof(slave->broadcast)); /* accept the parameters (no checks here) */ priv->priv_mode = info.mode; priv->priv_arg1 = info.arg1; priv->priv_arg2 = info.arg2; break; default: return -EOPNOTSUPP; } return 0;}/* -------------------------------------------------------------------------- * The initialization function: it is used to assign fields in the structure *//* * The __init attribute has no effect (by now) in modules; it is nonetheless * good practice to declare initialization functions as such, when working * in Linux kernel space. */int __init insane_init(struct net_device *dev){ /* * fill the fields of the device structure that are used */ /* priv is used to host the statistics, and packet dropping policy */ dev->priv = kmalloc(sizeof(struct insane_private), GFP_USER); if (!dev->priv) return -ENOMEM; memset(dev->priv, 0, sizeof(struct insane_private)); ether_setup(dev); /* assign some of the fields as "generic ethernet" */ /* dev->flags |= IFF_NOARP; */ /* these are the device methods */ dev->open = insane_open; dev->stop = insane_close; dev->do_ioctl = insane_ioctl; dev->get_stats = insane_get_stats; /* the hardware transmission method */ dev->hard_start_xmit = insane_xmit; /* and finally this one, needed for ARP to work */ dev->neigh_setup = insane_neigh_setup_dev; return 0;}/* -------------------------------------------------------------------------- * declaration of the interface data structure */static struct net_device insane_dev = { name: "insane", init: insane_init,};/* * this way of defining fields is gcc-specific. "name" is the first * field, and "init" the 12th. Most drivers use something like * struct net_device mydev = {"name", 0,0,0,0, 0,0,0,0,0, NULL, my_init}; *//* -------------------------------------------------------------------------- * module entry points */#ifdef MODULE /* It is defined, by Makefile, but you can try without it */int init_module(void){ int err; if ( (err = register_netdev(&insane_dev)) ) { printk(KERN_WARNING "insane: can't register, error %i\n", err); return -EIO; } return 0;}void cleanup_module(void){ kfree(insane_dev.priv); unregister_netdev(&insane_dev);}#endif /* module */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -