⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 insane.c

📁 Linux 虚拟网络接口 实例 In the Linux (or Unix) world, most network interfaces, such as eth0 and ppp0, are a
💻 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 + -