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

📄 br2684.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*Experimental ethernet netdevice using ATM AAL5 as underlying carrier(RFC1483 obsoleted by RFC2684) for Linux 2.4Author: Marcell GAL, 2000, XDSL Ltd, Hungary*/#include <linux/module.h>#include <linux/init.h>#include <linux/kernel.h>#include <linux/list.h>#include <linux/netdevice.h>#include <linux/skbuff.h>#include <linux/etherdevice.h>#include <linux/rtnetlink.h>#include <linux/ip.h>#include <asm/uaccess.h>#include <net/arp.h>#include <linux/atm.h>#include <linux/atmdev.h>#include <linux/capability.h>#include <linux/seq_file.h>#include <linux/atmbr2684.h>#include "common.h"#ifdef SKB_DEBUGstatic void skb_debug(const struct sk_buff *skb){#define NUM2PRINT 50	char buf[NUM2PRINT * 3 + 1];	/* 3 chars per byte */	int i = 0;	for (i = 0; i < skb->len && i < NUM2PRINT; i++) {		sprintf(buf + i * 3, "%2.2x ", 0xff & skb->data[i]);	}	printk(KERN_DEBUG "br2684: skb: %s\n", buf);}#else#define skb_debug(skb)	do {} while (0)#endifstatic unsigned char llc_oui_pid_pad[] =    { 0xAA, 0xAA, 0x03, 0x00, 0x80, 0xC2, 0x00, 0x07, 0x00, 0x00 };#define PADLEN	(2)enum br2684_encaps {	e_vc  = BR2684_ENCAPS_VC,	e_llc = BR2684_ENCAPS_LLC,};struct br2684_vcc {	struct atm_vcc  *atmvcc;	struct net_device *device;	/* keep old push,pop functions for chaining */	void (*old_push)(struct atm_vcc *vcc,struct sk_buff *skb);	/* void (*old_pop)(struct atm_vcc *vcc,struct sk_buff *skb); */	enum br2684_encaps encaps;	struct list_head brvccs;#ifdef CONFIG_ATM_BR2684_IPFILTER	struct br2684_filter filter;#endif /* CONFIG_ATM_BR2684_IPFILTER */	unsigned copies_needed, copies_failed;};struct br2684_dev {	struct net_device *net_dev;	struct list_head br2684_devs;	int number;	struct list_head brvccs; /* one device <=> one vcc (before xmas) */	struct net_device_stats stats;	int mac_was_set;};/* * This lock should be held for writing any time the list of devices or * their attached vcc's could be altered.  It should be held for reading * any time these are being queried.  Note that we sometimes need to * do read-locking under interrupt context, so write locking must block * the current CPU's interrupts */static DEFINE_RWLOCK(devs_lock);static LIST_HEAD(br2684_devs);static inline struct br2684_dev *BRPRIV(const struct net_device *net_dev){	return (struct br2684_dev *) net_dev->priv;}static inline struct net_device *list_entry_brdev(const struct list_head *le){	return list_entry(le, struct br2684_dev, br2684_devs)->net_dev;}static inline struct br2684_vcc *BR2684_VCC(const struct atm_vcc *atmvcc){	return (struct br2684_vcc *) (atmvcc->user_back);}static inline struct br2684_vcc *list_entry_brvcc(const struct list_head *le){	return list_entry(le, struct br2684_vcc, brvccs);}/* Caller should hold read_lock(&devs_lock) */static struct net_device *br2684_find_dev(const struct br2684_if_spec *s){	struct list_head *lh;	struct net_device *net_dev;	switch (s->method) {	case BR2684_FIND_BYNUM:		list_for_each(lh, &br2684_devs) {			net_dev = list_entry_brdev(lh);			if (BRPRIV(net_dev)->number == s->spec.devnum)				return net_dev;		}		break;	case BR2684_FIND_BYIFNAME:		list_for_each(lh, &br2684_devs) {			net_dev = list_entry_brdev(lh);			if (!strncmp(net_dev->name, s->spec.ifname, IFNAMSIZ))				return net_dev;		}		break;	}	return NULL;}/* * Send a packet out a particular vcc.  Not to useful right now, but paves * the way for multiple vcc's per itf.  Returns true if we can send, * otherwise false */static int br2684_xmit_vcc(struct sk_buff *skb, struct br2684_dev *brdev,	struct br2684_vcc *brvcc){	struct atm_vcc *atmvcc;	int minheadroom = (brvcc->encaps == e_llc) ? 10 : 2;	if (skb_headroom(skb) < minheadroom) {		struct sk_buff *skb2 = skb_realloc_headroom(skb, minheadroom);		brvcc->copies_needed++;		dev_kfree_skb(skb);		if (skb2 == NULL) {			brvcc->copies_failed++;			return 0;		}		skb = skb2;	}	skb_push(skb, minheadroom);	if (brvcc->encaps == e_llc)		skb_copy_to_linear_data(skb, llc_oui_pid_pad, 10);	else		memset(skb->data, 0, 2);	skb_debug(skb);	ATM_SKB(skb)->vcc = atmvcc = brvcc->atmvcc;	pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n", skb, atmvcc, atmvcc->dev);	if (!atm_may_send(atmvcc, skb->truesize)) {		/* we free this here for now, because we cannot know in a higher			layer whether the skb point it supplied wasn't freed yet.			now, it always is.		*/		dev_kfree_skb(skb);		return 0;		}	atomic_add(skb->truesize, &sk_atm(atmvcc)->sk_wmem_alloc);	ATM_SKB(skb)->atm_options = atmvcc->atm_options;	brdev->stats.tx_packets++;	brdev->stats.tx_bytes += skb->len;	atmvcc->send(atmvcc, skb);	return 1;}static inline struct br2684_vcc *pick_outgoing_vcc(struct sk_buff *skb,	struct br2684_dev *brdev){	return list_empty(&brdev->brvccs) ? NULL :	    list_entry_brvcc(brdev->brvccs.next); /* 1 vcc/dev right now */}static int br2684_start_xmit(struct sk_buff *skb, struct net_device *dev){	struct br2684_dev *brdev = BRPRIV(dev);	struct br2684_vcc *brvcc;	pr_debug("br2684_start_xmit, skb->dst=%p\n", skb->dst);	read_lock(&devs_lock);	brvcc = pick_outgoing_vcc(skb, brdev);	if (brvcc == NULL) {		pr_debug("no vcc attached to dev %s\n", dev->name);		brdev->stats.tx_errors++;		brdev->stats.tx_carrier_errors++;		/* netif_stop_queue(dev); */		dev_kfree_skb(skb);		read_unlock(&devs_lock);		return 0;	}	if (!br2684_xmit_vcc(skb, brdev, brvcc)) {		/*		 * We should probably use netif_*_queue() here, but that		 * involves added complication.  We need to walk before		 * we can run		 */		/* don't free here! this pointer might be no longer valid!		dev_kfree_skb(skb);		*/		brdev->stats.tx_errors++;		brdev->stats.tx_fifo_errors++;	}	read_unlock(&devs_lock);	return 0;}static struct net_device_stats *br2684_get_stats(struct net_device *dev){	pr_debug("br2684_get_stats\n");	return &BRPRIV(dev)->stats;}/* * We remember when the MAC gets set, so we don't override it later with * the ESI of the ATM card of the first VC */static int (*my_eth_mac_addr)(struct net_device *, void *);static int br2684_mac_addr(struct net_device *dev, void *p){	int err = my_eth_mac_addr(dev, p);	if (!err)		BRPRIV(dev)->mac_was_set = 1;	return err;}#ifdef CONFIG_ATM_BR2684_IPFILTER/* this IOCTL is experimental. */static int br2684_setfilt(struct atm_vcc *atmvcc, void __user *arg){	struct br2684_vcc *brvcc;	struct br2684_filter_set fs;	if (copy_from_user(&fs, arg, sizeof fs))		return -EFAULT;	if (fs.ifspec.method != BR2684_FIND_BYNOTHING) {		/*		 * This is really a per-vcc thing, but we can also search		 * by device		 */		struct br2684_dev *brdev;		read_lock(&devs_lock);		brdev = BRPRIV(br2684_find_dev(&fs.ifspec));		if (brdev == NULL || list_empty(&brdev->brvccs) ||		    brdev->brvccs.next != brdev->brvccs.prev)  /* >1 VCC */			brvcc = NULL;		else			brvcc = list_entry_brvcc(brdev->brvccs.next);		read_unlock(&devs_lock);		if (brvcc == NULL)			return -ESRCH;	} else		brvcc = BR2684_VCC(atmvcc);	memcpy(&brvcc->filter, &fs.filter, sizeof(brvcc->filter));	return 0;}/* Returns 1 if packet should be dropped */static inline intpacket_fails_filter(__be16 type, struct br2684_vcc *brvcc, struct sk_buff *skb){	if (brvcc->filter.netmask == 0)		return 0;			/* no filter in place */	if (type == htons(ETH_P_IP) &&	    (((struct iphdr *) (skb->data))->daddr & brvcc->filter.	     netmask) == brvcc->filter.prefix)		return 0;	if (type == htons(ETH_P_ARP))		return 0;	/* TODO: we should probably filter ARPs too.. don't want to have	 *   them returning values that don't make sense, or is that ok?	 */	return 1;		/* drop */}#endif /* CONFIG_ATM_BR2684_IPFILTER */static void br2684_close_vcc(struct br2684_vcc *brvcc){	pr_debug("removing VCC %p from dev %p\n", brvcc, brvcc->device);	write_lock_irq(&devs_lock);	list_del(&brvcc->brvccs);	write_unlock_irq(&devs_lock);	brvcc->atmvcc->user_back = NULL;	/* what about vcc->recvq ??? */	brvcc->old_push(brvcc->atmvcc, NULL);	/* pass on the bad news */	kfree(brvcc);	module_put(THIS_MODULE);}/* when AAL5 PDU comes in: */static void br2684_push(struct atm_vcc *atmvcc, struct sk_buff *skb){	struct br2684_vcc *brvcc = BR2684_VCC(atmvcc);	struct net_device *net_dev = brvcc->device;	struct br2684_dev *brdev = BRPRIV(net_dev);	int plen = sizeof(llc_oui_pid_pad) + ETH_HLEN;	pr_debug("br2684_push\n");	if (unlikely(skb == NULL)) {		/* skb==NULL means VCC is being destroyed */		br2684_close_vcc(brvcc);		if (list_empty(&brdev->brvccs)) {			read_lock(&devs_lock);			list_del(&brdev->br2684_devs);			read_unlock(&devs_lock);			unregister_netdev(net_dev);			free_netdev(net_dev);		}		return;	}	skb_debug(skb);	atm_return(atmvcc, skb->truesize);	pr_debug("skb from brdev %p\n", brdev);	if (brvcc->encaps == e_llc) {		/* let us waste some time for checking the encapsulation.		   Note, that only 7 char is checked so frames with a valid FCS		   are also accepted (but FCS is not checked of course) */		if (memcmp(skb->data, llc_oui_pid_pad, 7)) {			brdev->stats.rx_errors++;			dev_kfree_skb(skb);			return;		}		/* Strip FCS if present */		if (skb->len > 7 && skb->data[7] == 0x01)			__skb_trim(skb, skb->len - 4);	} else {		plen = PADLEN + ETH_HLEN;	/* pad, dstmac,srcmac, ethtype */		/* first 2 chars should be 0 */		if (*((u16 *) (skb->data)) != 0) {			brdev->stats.rx_errors++;			dev_kfree_skb(skb);			return;		}	}	if (skb->len < plen) {		brdev->stats.rx_errors++;		dev_kfree_skb(skb);	/* dev_ not needed? */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -