📄 br2684.c
字号:
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); DPRINTK("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? */ return; }#ifdef FASTER_VERSION /* FIXME: tcpdump shows that pointer to mac header is 2 bytes earlier, than should be. What else should I set? */ skb_pull(skb, plen); skb->mac.raw = ((char *) (skb->data)) - ETH_HLEN; skb->pkt_type = PACKET_HOST;#ifdef CONFIG_BR2684_FAST_TRANS skb->protocol = ((u16 *) skb->data)[-1];#else /* some protocols might require this: */ skb->protocol = br_type_trans(skb, net_dev);#endif /* CONFIG_BR2684_FAST_TRANS */#else skb_pull(skb, plen - ETH_HLEN); skb->protocol = eth_type_trans(skb, net_dev);#endif /* FASTER_VERSION */#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 ? */ DPRINTK("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_head copy; struct sk_buff *skb; struct br2684_dev *brdev; struct net_device *net_dev; struct atm_backend_br2684 be; if (copy_from_user(&be, arg, sizeof be)) return -EFAULT; brvcc = kmalloc(sizeof(struct br2684_vcc), GFP_KERNEL); if (!brvcc) return -ENOMEM; memset(brvcc, 0, sizeof(struct br2684_vcc)); 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; } DPRINTK("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; skb_queue_head_init(©); skb_migrate(&atmvcc->sk->sk_receive_queue, ©); while ((skb = skb_dequeue(©)) != NULL) { BRPRIV(skb->dev)->stats.rx_bytes -= skb->len; BRPRIV(skb->dev)->stats.rx_packets--; br2684_push(atmvcc, skb); } __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;#ifdef FASTER_VERSION my_eth_header = netdev->hard_header; netdev->hard_header = br2684_header; my_eth_header_cache = netdev->hard_header_cache; netdev->hard_header_cache = br2684_header_cache; netdev->hard_header_len = sizeof(llc_oui_pid_pad) + ETH_HLEN; /* 10 + 14 */#endif 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; DPRINTK("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); DPRINTK("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){ loff_t offs = 0; struct br2684_dev *brd; read_lock(&devs_lock); list_for_each_entry(brd, &br2684_devs, br2684_devs) { if (offs == *pos) return brd; ++offs; } return NULL;}static void *br2684_seq_next(struct seq_file *seq, void *v, loff_t *pos){ struct br2684_dev *brd = v; ++*pos; brd = list_entry(brd->br2684_devs.next, struct br2684_dev, br2684_devs); return (&brd->br2684_devs != &br2684_devs) ? brd : NULL;}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 = v; const struct net_device *net_dev = brdev->net_dev; const struct br2684_vcc *brvcc; seq_printf(seq, "dev %.16s: num=%d, mac=%02X:%02X:" "%02X:%02X:%02X:%02X (%s)\n", net_dev->name, brdev->number, net_dev->dev_addr[0], net_dev->dev_addr[1], net_dev->dev_addr[2], net_dev->dev_addr[3], net_dev->dev_addr[4], net_dev->dev_addr[5], brdev->mac_was_set ? "set" : "auto"); list_for_each_entry(brvcc, &brdev->brvccs, brvccs) { seq_printf(seq, " vcc %d.%d.%d: encaps=%s"#ifndef FASTER_VERSION ", failed copies %u/%u"#endif /* FASTER_VERSION */ "\n", brvcc->atmvcc->dev->number, brvcc->atmvcc->vpi, brvcc->atmvcc->vci, (brvcc->encaps == e_llc) ? "LLC" : "VC"#ifndef FASTER_VERSION , brvcc->copies_failed , brvcc->copies_needed#endif /* FASTER_VERSION */ );#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 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 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 + -