diff options
Diffstat (limited to 'net/atm/br2684.c')
| -rw-r--r-- | net/atm/br2684.c | 150 |
1 files changed, 97 insertions, 53 deletions
diff --git a/net/atm/br2684.c b/net/atm/br2684.c index c9230c398697..ad2b232a2055 100644 --- a/net/atm/br2684.c +++ b/net/atm/br2684.c | |||
| @@ -6,6 +6,8 @@ | |||
| 6 | * Eric Kinzie, 2006-2007, US Naval Research Laboratory | 6 | * Eric Kinzie, 2006-2007, US Naval Research Laboratory |
| 7 | */ | 7 | */ |
| 8 | 8 | ||
| 9 | #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ | ||
| 10 | |||
| 9 | #include <linux/module.h> | 11 | #include <linux/module.h> |
| 10 | #include <linux/init.h> | 12 | #include <linux/init.h> |
| 11 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
| @@ -15,7 +17,8 @@ | |||
| 15 | #include <linux/etherdevice.h> | 17 | #include <linux/etherdevice.h> |
| 16 | #include <linux/rtnetlink.h> | 18 | #include <linux/rtnetlink.h> |
| 17 | #include <linux/ip.h> | 19 | #include <linux/ip.h> |
| 18 | #include <asm/uaccess.h> | 20 | #include <linux/uaccess.h> |
| 21 | #include <linux/slab.h> | ||
| 19 | #include <net/arp.h> | 22 | #include <net/arp.h> |
| 20 | #include <linux/atm.h> | 23 | #include <linux/atm.h> |
| 21 | #include <linux/atmdev.h> | 24 | #include <linux/atmdev.h> |
| @@ -26,20 +29,14 @@ | |||
| 26 | 29 | ||
| 27 | #include "common.h" | 30 | #include "common.h" |
| 28 | 31 | ||
| 29 | #ifdef SKB_DEBUG | ||
| 30 | static void skb_debug(const struct sk_buff *skb) | 32 | static void skb_debug(const struct sk_buff *skb) |
| 31 | { | 33 | { |
| 34 | #ifdef SKB_DEBUG | ||
| 32 | #define NUM2PRINT 50 | 35 | #define NUM2PRINT 50 |
| 33 | char buf[NUM2PRINT * 3 + 1]; /* 3 chars per byte */ | 36 | print_hex_dump(KERN_DEBUG, "br2684: skb: ", DUMP_OFFSET, |
| 34 | int i = 0; | 37 | 16, 1, skb->data, min(NUM2PRINT, skb->len), true); |
| 35 | for (i = 0; i < skb->len && i < NUM2PRINT; i++) { | ||
| 36 | sprintf(buf + i * 3, "%2.2x ", 0xff & skb->data[i]); | ||
| 37 | } | ||
| 38 | printk(KERN_DEBUG "br2684: skb: %s\n", buf); | ||
| 39 | } | ||
| 40 | #else | ||
| 41 | #define skb_debug(skb) do {} while (0) | ||
| 42 | #endif | 38 | #endif |
| 39 | } | ||
| 43 | 40 | ||
| 44 | #define BR2684_ETHERTYPE_LEN 2 | 41 | #define BR2684_ETHERTYPE_LEN 2 |
| 45 | #define BR2684_PAD_LEN 2 | 42 | #define BR2684_PAD_LEN 2 |
| @@ -68,7 +65,7 @@ struct br2684_vcc { | |||
| 68 | struct atm_vcc *atmvcc; | 65 | struct atm_vcc *atmvcc; |
| 69 | struct net_device *device; | 66 | struct net_device *device; |
| 70 | /* keep old push, pop functions for chaining */ | 67 | /* keep old push, pop functions for chaining */ |
| 71 | void (*old_push) (struct atm_vcc * vcc, struct sk_buff * skb); | 68 | void (*old_push)(struct atm_vcc *vcc, struct sk_buff *skb); |
| 72 | void (*old_pop)(struct atm_vcc *vcc, struct sk_buff *skb); | 69 | void (*old_pop)(struct atm_vcc *vcc, struct sk_buff *skb); |
| 73 | enum br2684_encaps encaps; | 70 | enum br2684_encaps encaps; |
| 74 | struct list_head brvccs; | 71 | struct list_head brvccs; |
| @@ -142,13 +139,50 @@ static struct net_device *br2684_find_dev(const struct br2684_if_spec *s) | |||
| 142 | return NULL; | 139 | return NULL; |
| 143 | } | 140 | } |
| 144 | 141 | ||
| 142 | static int atm_dev_event(struct notifier_block *this, unsigned long event, | ||
| 143 | void *arg) | ||
| 144 | { | ||
| 145 | struct atm_dev *atm_dev = arg; | ||
| 146 | struct list_head *lh; | ||
| 147 | struct net_device *net_dev; | ||
| 148 | struct br2684_vcc *brvcc; | ||
| 149 | struct atm_vcc *atm_vcc; | ||
| 150 | unsigned long flags; | ||
| 151 | |||
| 152 | pr_debug("event=%ld dev=%p\n", event, atm_dev); | ||
| 153 | |||
| 154 | read_lock_irqsave(&devs_lock, flags); | ||
| 155 | list_for_each(lh, &br2684_devs) { | ||
| 156 | net_dev = list_entry_brdev(lh); | ||
| 157 | |||
| 158 | list_for_each_entry(brvcc, &BRPRIV(net_dev)->brvccs, brvccs) { | ||
| 159 | atm_vcc = brvcc->atmvcc; | ||
| 160 | if (atm_vcc && brvcc->atmvcc->dev == atm_dev) { | ||
| 161 | |||
| 162 | if (atm_vcc->dev->signal == ATM_PHY_SIG_LOST) | ||
| 163 | netif_carrier_off(net_dev); | ||
| 164 | else | ||
| 165 | netif_carrier_on(net_dev); | ||
| 166 | |||
| 167 | } | ||
| 168 | } | ||
| 169 | } | ||
| 170 | read_unlock_irqrestore(&devs_lock, flags); | ||
| 171 | |||
| 172 | return NOTIFY_DONE; | ||
| 173 | } | ||
| 174 | |||
| 175 | static struct notifier_block atm_dev_notifier = { | ||
| 176 | .notifier_call = atm_dev_event, | ||
| 177 | }; | ||
| 178 | |||
| 145 | /* chained vcc->pop function. Check if we should wake the netif_queue */ | 179 | /* chained vcc->pop function. Check if we should wake the netif_queue */ |
| 146 | static void br2684_pop(struct atm_vcc *vcc, struct sk_buff *skb) | 180 | static void br2684_pop(struct atm_vcc *vcc, struct sk_buff *skb) |
| 147 | { | 181 | { |
| 148 | struct br2684_vcc *brvcc = BR2684_VCC(vcc); | 182 | struct br2684_vcc *brvcc = BR2684_VCC(vcc); |
| 149 | struct net_device *net_dev = skb->dev; | 183 | struct net_device *net_dev = skb->dev; |
| 150 | 184 | ||
| 151 | pr_debug("br2684_pop(vcc %p ; net_dev %p )\n", vcc, net_dev); | 185 | pr_debug("(vcc %p ; net_dev %p )\n", vcc, net_dev); |
| 152 | brvcc->old_pop(vcc, skb); | 186 | brvcc->old_pop(vcc, skb); |
| 153 | 187 | ||
| 154 | if (!net_dev) | 188 | if (!net_dev) |
| @@ -244,7 +278,7 @@ static netdev_tx_t br2684_start_xmit(struct sk_buff *skb, | |||
| 244 | struct br2684_dev *brdev = BRPRIV(dev); | 278 | struct br2684_dev *brdev = BRPRIV(dev); |
| 245 | struct br2684_vcc *brvcc; | 279 | struct br2684_vcc *brvcc; |
| 246 | 280 | ||
| 247 | pr_debug("br2684_start_xmit, skb_dst(skb)=%p\n", skb_dst(skb)); | 281 | pr_debug("skb_dst(skb)=%p\n", skb_dst(skb)); |
| 248 | read_lock(&devs_lock); | 282 | read_lock(&devs_lock); |
| 249 | brvcc = pick_outgoing_vcc(skb, brdev); | 283 | brvcc = pick_outgoing_vcc(skb, brdev); |
| 250 | if (brvcc == NULL) { | 284 | if (brvcc == NULL) { |
| @@ -300,7 +334,8 @@ static int br2684_setfilt(struct atm_vcc *atmvcc, void __user * arg) | |||
| 300 | struct br2684_dev *brdev; | 334 | struct br2684_dev *brdev; |
| 301 | read_lock(&devs_lock); | 335 | read_lock(&devs_lock); |
| 302 | brdev = BRPRIV(br2684_find_dev(&fs.ifspec)); | 336 | brdev = BRPRIV(br2684_find_dev(&fs.ifspec)); |
| 303 | if (brdev == NULL || list_empty(&brdev->brvccs) || brdev->brvccs.next != brdev->brvccs.prev) /* >1 VCC */ | 337 | if (brdev == NULL || list_empty(&brdev->brvccs) || |
| 338 | brdev->brvccs.next != brdev->brvccs.prev) /* >1 VCC */ | ||
| 304 | brvcc = NULL; | 339 | brvcc = NULL; |
| 305 | else | 340 | else |
| 306 | brvcc = list_entry_brvcc(brdev->brvccs.next); | 341 | brvcc = list_entry_brvcc(brdev->brvccs.next); |
| @@ -352,7 +387,7 @@ static void br2684_push(struct atm_vcc *atmvcc, struct sk_buff *skb) | |||
| 352 | struct net_device *net_dev = brvcc->device; | 387 | struct net_device *net_dev = brvcc->device; |
| 353 | struct br2684_dev *brdev = BRPRIV(net_dev); | 388 | struct br2684_dev *brdev = BRPRIV(net_dev); |
| 354 | 389 | ||
| 355 | pr_debug("br2684_push\n"); | 390 | pr_debug("\n"); |
| 356 | 391 | ||
| 357 | if (unlikely(skb == NULL)) { | 392 | if (unlikely(skb == NULL)) { |
| 358 | /* skb==NULL means VCC is being destroyed */ | 393 | /* skb==NULL means VCC is being destroyed */ |
| @@ -376,29 +411,25 @@ static void br2684_push(struct atm_vcc *atmvcc, struct sk_buff *skb) | |||
| 376 | __skb_trim(skb, skb->len - 4); | 411 | __skb_trim(skb, skb->len - 4); |
| 377 | 412 | ||
| 378 | /* accept packets that have "ipv[46]" in the snap header */ | 413 | /* accept packets that have "ipv[46]" in the snap header */ |
| 379 | if ((skb->len >= (sizeof(llc_oui_ipv4))) | 414 | if ((skb->len >= (sizeof(llc_oui_ipv4))) && |
| 380 | && | 415 | (memcmp(skb->data, llc_oui_ipv4, |
| 381 | (memcmp | 416 | sizeof(llc_oui_ipv4) - BR2684_ETHERTYPE_LEN) == 0)) { |
| 382 | (skb->data, llc_oui_ipv4, | 417 | if (memcmp(skb->data + 6, ethertype_ipv6, |
| 383 | sizeof(llc_oui_ipv4) - BR2684_ETHERTYPE_LEN) == 0)) { | 418 | sizeof(ethertype_ipv6)) == 0) |
| 384 | if (memcmp | ||
| 385 | (skb->data + 6, ethertype_ipv6, | ||
| 386 | sizeof(ethertype_ipv6)) == 0) | ||
| 387 | skb->protocol = htons(ETH_P_IPV6); | 419 | skb->protocol = htons(ETH_P_IPV6); |
| 388 | else if (memcmp | 420 | else if (memcmp(skb->data + 6, ethertype_ipv4, |
| 389 | (skb->data + 6, ethertype_ipv4, | 421 | sizeof(ethertype_ipv4)) == 0) |
| 390 | sizeof(ethertype_ipv4)) == 0) | ||
| 391 | skb->protocol = htons(ETH_P_IP); | 422 | skb->protocol = htons(ETH_P_IP); |
| 392 | else | 423 | else |
| 393 | goto error; | 424 | goto error; |
| 394 | skb_pull(skb, sizeof(llc_oui_ipv4)); | 425 | skb_pull(skb, sizeof(llc_oui_ipv4)); |
| 395 | skb_reset_network_header(skb); | 426 | skb_reset_network_header(skb); |
| 396 | skb->pkt_type = PACKET_HOST; | 427 | skb->pkt_type = PACKET_HOST; |
| 397 | /* | 428 | /* |
| 398 | * Let us waste some time for checking the encapsulation. | 429 | * Let us waste some time for checking the encapsulation. |
| 399 | * Note, that only 7 char is checked so frames with a valid FCS | 430 | * Note, that only 7 char is checked so frames with a valid FCS |
| 400 | * are also accepted (but FCS is not checked of course). | 431 | * are also accepted (but FCS is not checked of course). |
| 401 | */ | 432 | */ |
| 402 | } else if ((skb->len >= sizeof(llc_oui_pid_pad)) && | 433 | } else if ((skb->len >= sizeof(llc_oui_pid_pad)) && |
| 403 | (memcmp(skb->data, llc_oui_pid_pad, 7) == 0)) { | 434 | (memcmp(skb->data, llc_oui_pid_pad, 7) == 0)) { |
| 404 | skb_pull(skb, sizeof(llc_oui_pid_pad)); | 435 | skb_pull(skb, sizeof(llc_oui_pid_pad)); |
| @@ -452,7 +483,6 @@ error: | |||
| 452 | net_dev->stats.rx_errors++; | 483 | net_dev->stats.rx_errors++; |
| 453 | free_skb: | 484 | free_skb: |
| 454 | dev_kfree_skb(skb); | 485 | dev_kfree_skb(skb); |
| 455 | return; | ||
| 456 | } | 486 | } |
| 457 | 487 | ||
| 458 | /* | 488 | /* |
| @@ -479,8 +509,7 @@ static int br2684_regvcc(struct atm_vcc *atmvcc, void __user * arg) | |||
| 479 | write_lock_irq(&devs_lock); | 509 | write_lock_irq(&devs_lock); |
| 480 | net_dev = br2684_find_dev(&be.ifspec); | 510 | net_dev = br2684_find_dev(&be.ifspec); |
| 481 | if (net_dev == NULL) { | 511 | if (net_dev == NULL) { |
| 482 | printk(KERN_ERR | 512 | pr_err("tried to attach to non-existant device\n"); |
| 483 | "br2684: tried to attach to non-existant device\n"); | ||
| 484 | err = -ENXIO; | 513 | err = -ENXIO; |
| 485 | goto error; | 514 | goto error; |
| 486 | } | 515 | } |
| @@ -494,17 +523,16 @@ static int br2684_regvcc(struct atm_vcc *atmvcc, void __user * arg) | |||
| 494 | err = -EEXIST; | 523 | err = -EEXIST; |
| 495 | goto error; | 524 | goto error; |
| 496 | } | 525 | } |
| 497 | if (be.fcs_in != BR2684_FCSIN_NO || be.fcs_out != BR2684_FCSOUT_NO || | 526 | if (be.fcs_in != BR2684_FCSIN_NO || |
| 498 | be.fcs_auto || be.has_vpiid || be.send_padding || (be.encaps != | 527 | be.fcs_out != BR2684_FCSOUT_NO || |
| 499 | BR2684_ENCAPS_VC | 528 | be.fcs_auto || be.has_vpiid || be.send_padding || |
| 500 | && be.encaps != | 529 | (be.encaps != BR2684_ENCAPS_VC && |
| 501 | BR2684_ENCAPS_LLC) | 530 | be.encaps != BR2684_ENCAPS_LLC) || |
| 502 | || be.min_size != 0) { | 531 | be.min_size != 0) { |
| 503 | err = -EINVAL; | 532 | err = -EINVAL; |
| 504 | goto error; | 533 | goto error; |
| 505 | } | 534 | } |
| 506 | pr_debug("br2684_regvcc vcc=%p, encaps=%d, brvcc=%p\n", atmvcc, | 535 | pr_debug("vcc=%p, encaps=%d, brvcc=%p\n", atmvcc, be.encaps, brvcc); |
| 507 | be.encaps, brvcc); | ||
| 508 | if (list_empty(&brdev->brvccs) && !brdev->mac_was_set) { | 536 | if (list_empty(&brdev->brvccs) && !brdev->mac_was_set) { |
| 509 | unsigned char *esi = atmvcc->dev->esi; | 537 | unsigned char *esi = atmvcc->dev->esi; |
| 510 | if (esi[0] | esi[1] | esi[2] | esi[3] | esi[4] | esi[5]) | 538 | if (esi[0] | esi[1] | esi[2] | esi[3] | esi[4] | esi[5]) |
| @@ -539,9 +567,17 @@ static int br2684_regvcc(struct atm_vcc *atmvcc, void __user * arg) | |||
| 539 | 567 | ||
| 540 | br2684_push(atmvcc, skb); | 568 | br2684_push(atmvcc, skb); |
| 541 | } | 569 | } |
| 570 | |||
| 571 | /* initialize netdev carrier state */ | ||
| 572 | if (atmvcc->dev->signal == ATM_PHY_SIG_LOST) | ||
| 573 | netif_carrier_off(net_dev); | ||
| 574 | else | ||
| 575 | netif_carrier_on(net_dev); | ||
| 576 | |||
| 542 | __module_get(THIS_MODULE); | 577 | __module_get(THIS_MODULE); |
| 543 | return 0; | 578 | return 0; |
| 544 | error: | 579 | |
| 580 | error: | ||
| 545 | write_unlock_irq(&devs_lock); | 581 | write_unlock_irq(&devs_lock); |
| 546 | kfree(brvcc); | 582 | kfree(brvcc); |
| 547 | return err; | 583 | return err; |
| @@ -587,7 +623,7 @@ static void br2684_setup_routed(struct net_device *netdev) | |||
| 587 | INIT_LIST_HEAD(&brdev->brvccs); | 623 | INIT_LIST_HEAD(&brdev->brvccs); |
| 588 | } | 624 | } |
| 589 | 625 | ||
| 590 | static int br2684_create(void __user * arg) | 626 | static int br2684_create(void __user *arg) |
| 591 | { | 627 | { |
| 592 | int err; | 628 | int err; |
| 593 | struct net_device *netdev; | 629 | struct net_device *netdev; |
| @@ -595,11 +631,10 @@ static int br2684_create(void __user * arg) | |||
| 595 | struct atm_newif_br2684 ni; | 631 | struct atm_newif_br2684 ni; |
| 596 | enum br2684_payload payload; | 632 | enum br2684_payload payload; |
| 597 | 633 | ||
| 598 | pr_debug("br2684_create\n"); | 634 | pr_debug("\n"); |
| 599 | 635 | ||
| 600 | if (copy_from_user(&ni, arg, sizeof ni)) { | 636 | if (copy_from_user(&ni, arg, sizeof ni)) |
| 601 | return -EFAULT; | 637 | return -EFAULT; |
| 602 | } | ||
| 603 | 638 | ||
| 604 | if (ni.media & BR2684_FLAG_ROUTED) | 639 | if (ni.media & BR2684_FLAG_ROUTED) |
| 605 | payload = p_routed; | 640 | payload = p_routed; |
| @@ -607,9 +642,8 @@ static int br2684_create(void __user * arg) | |||
| 607 | payload = p_bridged; | 642 | payload = p_bridged; |
| 608 | ni.media &= 0xffff; /* strip flags */ | 643 | ni.media &= 0xffff; /* strip flags */ |
| 609 | 644 | ||
| 610 | if (ni.media != BR2684_MEDIA_ETHERNET || ni.mtu != 1500) { | 645 | if (ni.media != BR2684_MEDIA_ETHERNET || ni.mtu != 1500) |
| 611 | return -EINVAL; | 646 | return -EINVAL; |
| 612 | } | ||
| 613 | 647 | ||
| 614 | netdev = alloc_netdev(sizeof(struct br2684_dev), | 648 | netdev = alloc_netdev(sizeof(struct br2684_dev), |
| 615 | ni.ifname[0] ? ni.ifname : "nas%d", | 649 | ni.ifname[0] ? ni.ifname : "nas%d", |
| @@ -624,15 +658,21 @@ static int br2684_create(void __user * arg) | |||
| 624 | /* open, stop, do_ioctl ? */ | 658 | /* open, stop, do_ioctl ? */ |
| 625 | err = register_netdev(netdev); | 659 | err = register_netdev(netdev); |
| 626 | if (err < 0) { | 660 | if (err < 0) { |
| 627 | printk(KERN_ERR "br2684_create: register_netdev failed\n"); | 661 | pr_err("register_netdev failed\n"); |
| 628 | free_netdev(netdev); | 662 | free_netdev(netdev); |
| 629 | return err; | 663 | return err; |
| 630 | } | 664 | } |
| 631 | 665 | ||
| 632 | write_lock_irq(&devs_lock); | 666 | write_lock_irq(&devs_lock); |
| 667 | |||
| 633 | brdev->payload = payload; | 668 | brdev->payload = payload; |
| 634 | brdev->number = list_empty(&br2684_devs) ? 1 : | 669 | |
| 635 | BRPRIV(list_entry_brdev(br2684_devs.prev))->number + 1; | 670 | if (list_empty(&br2684_devs)) { |
| 671 | /* 1st br2684 device */ | ||
| 672 | brdev->number = 1; | ||
| 673 | } else | ||
| 674 | brdev->number = BRPRIV(list_entry_brdev(br2684_devs.prev))->number + 1; | ||
| 675 | |||
| 636 | list_add_tail(&brdev->br2684_devs, &br2684_devs); | 676 | list_add_tail(&brdev->br2684_devs, &br2684_devs); |
| 637 | write_unlock_irq(&devs_lock); | 677 | write_unlock_irq(&devs_lock); |
| 638 | return 0; | 678 | return 0; |
| @@ -768,6 +808,7 @@ static int __init br2684_init(void) | |||
| 768 | return -ENOMEM; | 808 | return -ENOMEM; |
| 769 | #endif | 809 | #endif |
| 770 | register_atm_ioctl(&br2684_ioctl_ops); | 810 | register_atm_ioctl(&br2684_ioctl_ops); |
| 811 | register_atmdevice_notifier(&atm_dev_notifier); | ||
| 771 | return 0; | 812 | return 0; |
| 772 | } | 813 | } |
| 773 | 814 | ||
| @@ -782,6 +823,9 @@ static void __exit br2684_exit(void) | |||
| 782 | remove_proc_entry("br2684", atm_proc_root); | 823 | remove_proc_entry("br2684", atm_proc_root); |
| 783 | #endif | 824 | #endif |
| 784 | 825 | ||
| 826 | |||
| 827 | unregister_atmdevice_notifier(&atm_dev_notifier); | ||
| 828 | |||
| 785 | while (!list_empty(&br2684_devs)) { | 829 | while (!list_empty(&br2684_devs)) { |
| 786 | net_dev = list_entry_brdev(br2684_devs.next); | 830 | net_dev = list_entry_brdev(br2684_devs.next); |
| 787 | brdev = BRPRIV(net_dev); | 831 | brdev = BRPRIV(net_dev); |
