📄 br2684.c
字号:
return; } skb_pull(skb, plen - ETH_HLEN); skb->protocol = eth_type_trans(skb, net_dev);#ifdef CONFIG_ATM_BR2684_IPFILTER if (unlikely(packet_fails_filter(skb->protocol, brvcc, skb))) { brdev->stats.rx_dropped++; dev_kfree_skb(skb); return; }#endif /* CONFIG_ATM_BR2684_IPFILTER */ skb->dev = net_dev; ATM_SKB(skb)->vcc = atmvcc; /* needed ? */ pr_debug("received packet's protocol: %x\n", ntohs(skb->protocol)); skb_debug(skb); if (unlikely(!(net_dev->flags & IFF_UP))) { /* sigh, interface is down */ brdev->stats.rx_dropped++; dev_kfree_skb(skb); return; } brdev->stats.rx_packets++; brdev->stats.rx_bytes += skb->len; memset(ATM_SKB(skb), 0, sizeof(struct atm_skb_data)); netif_rx(skb);}static int br2684_regvcc(struct atm_vcc *atmvcc, void __user *arg){/* assign a vcc to a devNote: we do not have explicit unassign, but look at _push()*/ int err; struct br2684_vcc *brvcc; struct sk_buff *skb; struct sk_buff_head *rq; struct br2684_dev *brdev; struct net_device *net_dev; struct atm_backend_br2684 be; unsigned long flags; if (copy_from_user(&be, arg, sizeof be)) return -EFAULT; brvcc = kzalloc(sizeof(struct br2684_vcc), GFP_KERNEL); if (!brvcc) return -ENOMEM; write_lock_irq(&devs_lock); net_dev = br2684_find_dev(&be.ifspec); if (net_dev == NULL) { printk(KERN_ERR "br2684: tried to attach to non-existant device\n"); err = -ENXIO; goto error; } brdev = BRPRIV(net_dev); if (atmvcc->push == NULL) { err = -EBADFD; goto error; } if (!list_empty(&brdev->brvccs)) { /* Only 1 VCC/dev right now */ err = -EEXIST; goto error; } if (be.fcs_in != BR2684_FCSIN_NO || be.fcs_out != BR2684_FCSOUT_NO || be.fcs_auto || be.has_vpiid || be.send_padding || (be.encaps != BR2684_ENCAPS_VC && be.encaps != BR2684_ENCAPS_LLC) || be.min_size != 0) { err = -EINVAL; goto error; } pr_debug("br2684_regvcc vcc=%p, encaps=%d, brvcc=%p\n", atmvcc, be.encaps, brvcc); if (list_empty(&brdev->brvccs) && !brdev->mac_was_set) { unsigned char *esi = atmvcc->dev->esi; if (esi[0] | esi[1] | esi[2] | esi[3] | esi[4] | esi[5]) memcpy(net_dev->dev_addr, esi, net_dev->addr_len); else net_dev->dev_addr[2] = 1; } list_add(&brvcc->brvccs, &brdev->brvccs); write_unlock_irq(&devs_lock); brvcc->device = net_dev; brvcc->atmvcc = atmvcc; atmvcc->user_back = brvcc; brvcc->encaps = (enum br2684_encaps) be.encaps; brvcc->old_push = atmvcc->push; barrier(); atmvcc->push = br2684_push; rq = &sk_atm(atmvcc)->sk_receive_queue; spin_lock_irqsave(&rq->lock, flags); if (skb_queue_empty(rq)) { skb = NULL; } else { /* NULL terminate the list. */ rq->prev->next = NULL; skb = rq->next; } rq->prev = rq->next = (struct sk_buff *)rq; rq->qlen = 0; spin_unlock_irqrestore(&rq->lock, flags); while (skb) { struct sk_buff *next = skb->next; skb->next = skb->prev = NULL; BRPRIV(skb->dev)->stats.rx_bytes -= skb->len; BRPRIV(skb->dev)->stats.rx_packets--; br2684_push(atmvcc, skb); skb = next; } __module_get(THIS_MODULE); return 0; error: write_unlock_irq(&devs_lock); kfree(brvcc); return err;}static void br2684_setup(struct net_device *netdev){ struct br2684_dev *brdev = BRPRIV(netdev); ether_setup(netdev); brdev->net_dev = netdev; my_eth_mac_addr = netdev->set_mac_address; netdev->set_mac_address = br2684_mac_addr; netdev->hard_start_xmit = br2684_start_xmit; netdev->get_stats = br2684_get_stats; INIT_LIST_HEAD(&brdev->brvccs);}static int br2684_create(void __user *arg){ int err; struct net_device *netdev; struct br2684_dev *brdev; struct atm_newif_br2684 ni; pr_debug("br2684_create\n"); if (copy_from_user(&ni, arg, sizeof ni)) { return -EFAULT; } if (ni.media != BR2684_MEDIA_ETHERNET || ni.mtu != 1500) { return -EINVAL; } netdev = alloc_netdev(sizeof(struct br2684_dev), ni.ifname[0] ? ni.ifname : "nas%d", br2684_setup); if (!netdev) return -ENOMEM; brdev = BRPRIV(netdev); pr_debug("registered netdev %s\n", netdev->name); /* open, stop, do_ioctl ? */ err = register_netdev(netdev); if (err < 0) { printk(KERN_ERR "br2684_create: register_netdev failed\n"); free_netdev(netdev); return err; } write_lock_irq(&devs_lock); brdev->number = list_empty(&br2684_devs) ? 1 : BRPRIV(list_entry_brdev(br2684_devs.prev))->number + 1; list_add_tail(&brdev->br2684_devs, &br2684_devs); write_unlock_irq(&devs_lock); return 0;}/* * This handles ioctls actually performed on our vcc - we must return * -ENOIOCTLCMD for any unrecognized ioctl */static int br2684_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg){ struct atm_vcc *atmvcc = ATM_SD(sock); void __user *argp = (void __user *)arg; int err; switch(cmd) { case ATM_SETBACKEND: case ATM_NEWBACKENDIF: { atm_backend_t b; err = get_user(b, (atm_backend_t __user *) argp); if (err) return -EFAULT; if (b != ATM_BACKEND_BR2684) return -ENOIOCTLCMD; if (!capable(CAP_NET_ADMIN)) return -EPERM; if (cmd == ATM_SETBACKEND) return br2684_regvcc(atmvcc, argp); else return br2684_create(argp); }#ifdef CONFIG_ATM_BR2684_IPFILTER case BR2684_SETFILT: if (atmvcc->push != br2684_push) return -ENOIOCTLCMD; if (!capable(CAP_NET_ADMIN)) return -EPERM; err = br2684_setfilt(atmvcc, argp); return err;#endif /* CONFIG_ATM_BR2684_IPFILTER */ } return -ENOIOCTLCMD;}static struct atm_ioctl br2684_ioctl_ops = { .owner = THIS_MODULE, .ioctl = br2684_ioctl,};#ifdef CONFIG_PROC_FSstatic void *br2684_seq_start(struct seq_file *seq, loff_t *pos){ read_lock(&devs_lock); return seq_list_start(&br2684_devs, *pos);}static void *br2684_seq_next(struct seq_file *seq, void *v, loff_t *pos){ return seq_list_next(v, &br2684_devs, pos);}static void br2684_seq_stop(struct seq_file *seq, void *v){ read_unlock(&devs_lock);}static int br2684_seq_show(struct seq_file *seq, void *v){ const struct br2684_dev *brdev = list_entry(v, struct br2684_dev, br2684_devs); const struct net_device *net_dev = brdev->net_dev; const struct br2684_vcc *brvcc; DECLARE_MAC_BUF(mac); seq_printf(seq, "dev %.16s: num=%d, mac=%s (%s)\n", net_dev->name, brdev->number, print_mac(mac, net_dev->dev_addr), brdev->mac_was_set ? "set" : "auto"); list_for_each_entry(brvcc, &brdev->brvccs, brvccs) { seq_printf(seq, " vcc %d.%d.%d: encaps=%s" ", failed copies %u/%u" "\n", brvcc->atmvcc->dev->number, brvcc->atmvcc->vpi, brvcc->atmvcc->vci, (brvcc->encaps == e_llc) ? "LLC" : "VC" , brvcc->copies_failed , brvcc->copies_needed );#ifdef CONFIG_ATM_BR2684_IPFILTER#define b1(var, byte) ((u8 *) &brvcc->filter.var)[byte]#define bs(var) b1(var, 0), b1(var, 1), b1(var, 2), b1(var, 3) if (brvcc->filter.netmask != 0) seq_printf(seq, " filter=%d.%d.%d.%d/" "%d.%d.%d.%d\n", bs(prefix), bs(netmask));#undef bs#undef b1#endif /* CONFIG_ATM_BR2684_IPFILTER */ } return 0;}static const struct seq_operations br2684_seq_ops = { .start = br2684_seq_start, .next = br2684_seq_next, .stop = br2684_seq_stop, .show = br2684_seq_show,};static int br2684_proc_open(struct inode *inode, struct file *file){ return seq_open(file, &br2684_seq_ops);}static const struct file_operations br2684_proc_ops = { .owner = THIS_MODULE, .open = br2684_proc_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release,};extern struct proc_dir_entry *atm_proc_root; /* from proc.c */#endifstatic int __init br2684_init(void){#ifdef CONFIG_PROC_FS struct proc_dir_entry *p; if ((p = create_proc_entry("br2684", 0, atm_proc_root)) == NULL) return -ENOMEM; p->proc_fops = &br2684_proc_ops;#endif register_atm_ioctl(&br2684_ioctl_ops); return 0;}static void __exit br2684_exit(void){ struct net_device *net_dev; struct br2684_dev *brdev; struct br2684_vcc *brvcc; deregister_atm_ioctl(&br2684_ioctl_ops);#ifdef CONFIG_PROC_FS remove_proc_entry("br2684", atm_proc_root);#endif while (!list_empty(&br2684_devs)) { net_dev = list_entry_brdev(br2684_devs.next); brdev = BRPRIV(net_dev); while (!list_empty(&brdev->brvccs)) { brvcc = list_entry_brvcc(brdev->brvccs.next); br2684_close_vcc(brvcc); } list_del(&brdev->br2684_devs); unregister_netdev(net_dev); free_netdev(net_dev); }}module_init(br2684_init);module_exit(br2684_exit);MODULE_AUTHOR("Marcell GAL");MODULE_DESCRIPTION("RFC2684 bridged protocols over ATM/AAL5");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -