diff options
Diffstat (limited to 'net/batman-adv/soft-interface.c')
-rw-r--r-- | net/batman-adv/soft-interface.c | 288 |
1 files changed, 199 insertions, 89 deletions
diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index 2711e870f557..6f20d339e33a 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <linux/if_ether.h> | 37 | #include <linux/if_ether.h> |
38 | #include "unicast.h" | 38 | #include "unicast.h" |
39 | #include "bridge_loop_avoidance.h" | 39 | #include "bridge_loop_avoidance.h" |
40 | #include "network-coding.h" | ||
40 | 41 | ||
41 | 42 | ||
42 | static int batadv_get_settings(struct net_device *dev, struct ethtool_cmd *cmd); | 43 | static int batadv_get_settings(struct net_device *dev, struct ethtool_cmd *cmd); |
@@ -401,55 +402,6 @@ static void batadv_set_lockdep_class(struct net_device *dev) | |||
401 | } | 402 | } |
402 | 403 | ||
403 | /** | 404 | /** |
404 | * batadv_softif_init - Late stage initialization of soft interface | ||
405 | * @dev: registered network device to modify | ||
406 | * | ||
407 | * Returns error code on failures | ||
408 | */ | ||
409 | static int batadv_softif_init(struct net_device *dev) | ||
410 | { | ||
411 | batadv_set_lockdep_class(dev); | ||
412 | |||
413 | return 0; | ||
414 | } | ||
415 | |||
416 | static const struct net_device_ops batadv_netdev_ops = { | ||
417 | .ndo_init = batadv_softif_init, | ||
418 | .ndo_open = batadv_interface_open, | ||
419 | .ndo_stop = batadv_interface_release, | ||
420 | .ndo_get_stats = batadv_interface_stats, | ||
421 | .ndo_set_mac_address = batadv_interface_set_mac_addr, | ||
422 | .ndo_change_mtu = batadv_interface_change_mtu, | ||
423 | .ndo_start_xmit = batadv_interface_tx, | ||
424 | .ndo_validate_addr = eth_validate_addr | ||
425 | }; | ||
426 | |||
427 | static void batadv_interface_setup(struct net_device *dev) | ||
428 | { | ||
429 | struct batadv_priv *priv = netdev_priv(dev); | ||
430 | |||
431 | ether_setup(dev); | ||
432 | |||
433 | dev->netdev_ops = &batadv_netdev_ops; | ||
434 | dev->destructor = free_netdev; | ||
435 | dev->tx_queue_len = 0; | ||
436 | |||
437 | /* can't call min_mtu, because the needed variables | ||
438 | * have not been initialized yet | ||
439 | */ | ||
440 | dev->mtu = ETH_DATA_LEN; | ||
441 | /* reserve more space in the skbuff for our header */ | ||
442 | dev->hard_header_len = BATADV_HEADER_LEN; | ||
443 | |||
444 | /* generate random address */ | ||
445 | eth_hw_addr_random(dev); | ||
446 | |||
447 | SET_ETHTOOL_OPS(dev, &batadv_ethtool_ops); | ||
448 | |||
449 | memset(priv, 0, sizeof(*priv)); | ||
450 | } | ||
451 | |||
452 | /** | ||
453 | * batadv_softif_destroy_finish - cleans up the remains of a softif | 405 | * batadv_softif_destroy_finish - cleans up the remains of a softif |
454 | * @work: work queue item | 406 | * @work: work queue item |
455 | * | 407 | * |
@@ -465,7 +417,6 @@ static void batadv_softif_destroy_finish(struct work_struct *work) | |||
465 | cleanup_work); | 417 | cleanup_work); |
466 | soft_iface = bat_priv->soft_iface; | 418 | soft_iface = bat_priv->soft_iface; |
467 | 419 | ||
468 | batadv_debugfs_del_meshif(soft_iface); | ||
469 | batadv_sysfs_del_meshif(soft_iface); | 420 | batadv_sysfs_del_meshif(soft_iface); |
470 | 421 | ||
471 | rtnl_lock(); | 422 | rtnl_lock(); |
@@ -473,21 +424,22 @@ static void batadv_softif_destroy_finish(struct work_struct *work) | |||
473 | rtnl_unlock(); | 424 | rtnl_unlock(); |
474 | } | 425 | } |
475 | 426 | ||
476 | struct net_device *batadv_softif_create(const char *name) | 427 | /** |
428 | * batadv_softif_init_late - late stage initialization of soft interface | ||
429 | * @dev: registered network device to modify | ||
430 | * | ||
431 | * Returns error code on failures | ||
432 | */ | ||
433 | static int batadv_softif_init_late(struct net_device *dev) | ||
477 | { | 434 | { |
478 | struct net_device *soft_iface; | ||
479 | struct batadv_priv *bat_priv; | 435 | struct batadv_priv *bat_priv; |
480 | int ret; | 436 | int ret; |
481 | size_t cnt_len = sizeof(uint64_t) * BATADV_CNT_NUM; | 437 | size_t cnt_len = sizeof(uint64_t) * BATADV_CNT_NUM; |
482 | 438 | ||
483 | soft_iface = alloc_netdev(sizeof(*bat_priv), name, | 439 | batadv_set_lockdep_class(dev); |
484 | batadv_interface_setup); | ||
485 | |||
486 | if (!soft_iface) | ||
487 | goto out; | ||
488 | 440 | ||
489 | bat_priv = netdev_priv(soft_iface); | 441 | bat_priv = netdev_priv(dev); |
490 | bat_priv->soft_iface = soft_iface; | 442 | bat_priv->soft_iface = dev; |
491 | INIT_WORK(&bat_priv->cleanup_work, batadv_softif_destroy_finish); | 443 | INIT_WORK(&bat_priv->cleanup_work, batadv_softif_destroy_finish); |
492 | 444 | ||
493 | /* batadv_interface_stats() needs to be available as soon as | 445 | /* batadv_interface_stats() needs to be available as soon as |
@@ -495,14 +447,7 @@ struct net_device *batadv_softif_create(const char *name) | |||
495 | */ | 447 | */ |
496 | bat_priv->bat_counters = __alloc_percpu(cnt_len, __alignof__(uint64_t)); | 448 | bat_priv->bat_counters = __alloc_percpu(cnt_len, __alignof__(uint64_t)); |
497 | if (!bat_priv->bat_counters) | 449 | if (!bat_priv->bat_counters) |
498 | goto free_soft_iface; | 450 | return -ENOMEM; |
499 | |||
500 | ret = register_netdevice(soft_iface); | ||
501 | if (ret < 0) { | ||
502 | pr_err("Unable to register the batman interface '%s': %i\n", | ||
503 | name, ret); | ||
504 | goto free_bat_counters; | ||
505 | } | ||
506 | 451 | ||
507 | atomic_set(&bat_priv->aggregated_ogms, 1); | 452 | atomic_set(&bat_priv->aggregated_ogms, 1); |
508 | atomic_set(&bat_priv->bonding, 0); | 453 | atomic_set(&bat_priv->bonding, 0); |
@@ -540,49 +485,196 @@ struct net_device *batadv_softif_create(const char *name) | |||
540 | bat_priv->primary_if = NULL; | 485 | bat_priv->primary_if = NULL; |
541 | bat_priv->num_ifaces = 0; | 486 | bat_priv->num_ifaces = 0; |
542 | 487 | ||
543 | ret = batadv_algo_select(bat_priv, batadv_routing_algo); | 488 | batadv_nc_init_bat_priv(bat_priv); |
544 | if (ret < 0) | ||
545 | goto unreg_soft_iface; | ||
546 | 489 | ||
547 | ret = batadv_sysfs_add_meshif(soft_iface); | 490 | ret = batadv_algo_select(bat_priv, batadv_routing_algo); |
548 | if (ret < 0) | 491 | if (ret < 0) |
549 | goto unreg_soft_iface; | 492 | goto free_bat_counters; |
550 | 493 | ||
551 | ret = batadv_debugfs_add_meshif(soft_iface); | 494 | ret = batadv_debugfs_add_meshif(dev); |
552 | if (ret < 0) | 495 | if (ret < 0) |
553 | goto unreg_sysfs; | 496 | goto free_bat_counters; |
554 | 497 | ||
555 | ret = batadv_mesh_init(soft_iface); | 498 | ret = batadv_mesh_init(dev); |
556 | if (ret < 0) | 499 | if (ret < 0) |
557 | goto unreg_debugfs; | 500 | goto unreg_debugfs; |
558 | 501 | ||
559 | return soft_iface; | 502 | return 0; |
560 | 503 | ||
561 | unreg_debugfs: | 504 | unreg_debugfs: |
562 | batadv_debugfs_del_meshif(soft_iface); | 505 | batadv_debugfs_del_meshif(dev); |
563 | unreg_sysfs: | ||
564 | batadv_sysfs_del_meshif(soft_iface); | ||
565 | unreg_soft_iface: | ||
566 | free_percpu(bat_priv->bat_counters); | ||
567 | unregister_netdevice(soft_iface); | ||
568 | return NULL; | ||
569 | |||
570 | free_bat_counters: | 506 | free_bat_counters: |
571 | free_percpu(bat_priv->bat_counters); | 507 | free_percpu(bat_priv->bat_counters); |
572 | free_soft_iface: | 508 | |
573 | free_netdev(soft_iface); | 509 | return ret; |
510 | } | ||
511 | |||
512 | /** | ||
513 | * batadv_softif_slave_add - Add a slave interface to a batadv_soft_interface | ||
514 | * @dev: batadv_soft_interface used as master interface | ||
515 | * @slave_dev: net_device which should become the slave interface | ||
516 | * | ||
517 | * Return 0 if successful or error otherwise. | ||
518 | */ | ||
519 | static int batadv_softif_slave_add(struct net_device *dev, | ||
520 | struct net_device *slave_dev) | ||
521 | { | ||
522 | struct batadv_hard_iface *hard_iface; | ||
523 | int ret = -EINVAL; | ||
524 | |||
525 | hard_iface = batadv_hardif_get_by_netdev(slave_dev); | ||
526 | if (!hard_iface || hard_iface->soft_iface != NULL) | ||
527 | goto out; | ||
528 | |||
529 | ret = batadv_hardif_enable_interface(hard_iface, dev->name); | ||
530 | |||
574 | out: | 531 | out: |
575 | return NULL; | 532 | if (hard_iface) |
533 | batadv_hardif_free_ref(hard_iface); | ||
534 | return ret; | ||
576 | } | 535 | } |
577 | 536 | ||
578 | void batadv_softif_destroy(struct net_device *soft_iface) | 537 | /** |
538 | * batadv_softif_slave_del - Delete a slave iface from a batadv_soft_interface | ||
539 | * @dev: batadv_soft_interface used as master interface | ||
540 | * @slave_dev: net_device which should be removed from the master interface | ||
541 | * | ||
542 | * Return 0 if successful or error otherwise. | ||
543 | */ | ||
544 | static int batadv_softif_slave_del(struct net_device *dev, | ||
545 | struct net_device *slave_dev) | ||
546 | { | ||
547 | struct batadv_hard_iface *hard_iface; | ||
548 | int ret = -EINVAL; | ||
549 | |||
550 | hard_iface = batadv_hardif_get_by_netdev(slave_dev); | ||
551 | |||
552 | if (!hard_iface || hard_iface->soft_iface != dev) | ||
553 | goto out; | ||
554 | |||
555 | batadv_hardif_disable_interface(hard_iface, BATADV_IF_CLEANUP_KEEP); | ||
556 | ret = 0; | ||
557 | |||
558 | out: | ||
559 | if (hard_iface) | ||
560 | batadv_hardif_free_ref(hard_iface); | ||
561 | return ret; | ||
562 | } | ||
563 | |||
564 | static const struct net_device_ops batadv_netdev_ops = { | ||
565 | .ndo_init = batadv_softif_init_late, | ||
566 | .ndo_open = batadv_interface_open, | ||
567 | .ndo_stop = batadv_interface_release, | ||
568 | .ndo_get_stats = batadv_interface_stats, | ||
569 | .ndo_set_mac_address = batadv_interface_set_mac_addr, | ||
570 | .ndo_change_mtu = batadv_interface_change_mtu, | ||
571 | .ndo_start_xmit = batadv_interface_tx, | ||
572 | .ndo_validate_addr = eth_validate_addr, | ||
573 | .ndo_add_slave = batadv_softif_slave_add, | ||
574 | .ndo_del_slave = batadv_softif_slave_del, | ||
575 | }; | ||
576 | |||
577 | /** | ||
578 | * batadv_softif_free - Deconstructor of batadv_soft_interface | ||
579 | * @dev: Device to cleanup and remove | ||
580 | */ | ||
581 | static void batadv_softif_free(struct net_device *dev) | ||
582 | { | ||
583 | batadv_debugfs_del_meshif(dev); | ||
584 | batadv_mesh_free(dev); | ||
585 | |||
586 | /* some scheduled RCU callbacks need the bat_priv struct to accomplish | ||
587 | * their tasks. Wait for them all to be finished before freeing the | ||
588 | * netdev and its private data (bat_priv) | ||
589 | */ | ||
590 | rcu_barrier(); | ||
591 | |||
592 | free_netdev(dev); | ||
593 | } | ||
594 | |||
595 | /** | ||
596 | * batadv_softif_init_early - early stage initialization of soft interface | ||
597 | * @dev: registered network device to modify | ||
598 | */ | ||
599 | static void batadv_softif_init_early(struct net_device *dev) | ||
600 | { | ||
601 | struct batadv_priv *priv = netdev_priv(dev); | ||
602 | |||
603 | ether_setup(dev); | ||
604 | |||
605 | dev->netdev_ops = &batadv_netdev_ops; | ||
606 | dev->destructor = batadv_softif_free; | ||
607 | dev->tx_queue_len = 0; | ||
608 | |||
609 | /* can't call min_mtu, because the needed variables | ||
610 | * have not been initialized yet | ||
611 | */ | ||
612 | dev->mtu = ETH_DATA_LEN; | ||
613 | /* reserve more space in the skbuff for our header */ | ||
614 | dev->hard_header_len = BATADV_HEADER_LEN; | ||
615 | |||
616 | /* generate random address */ | ||
617 | eth_hw_addr_random(dev); | ||
618 | |||
619 | SET_ETHTOOL_OPS(dev, &batadv_ethtool_ops); | ||
620 | |||
621 | memset(priv, 0, sizeof(*priv)); | ||
622 | } | ||
623 | |||
624 | struct net_device *batadv_softif_create(const char *name) | ||
625 | { | ||
626 | struct net_device *soft_iface; | ||
627 | int ret; | ||
628 | |||
629 | soft_iface = alloc_netdev(sizeof(struct batadv_priv), name, | ||
630 | batadv_softif_init_early); | ||
631 | if (!soft_iface) | ||
632 | return NULL; | ||
633 | |||
634 | soft_iface->rtnl_link_ops = &batadv_link_ops; | ||
635 | |||
636 | ret = register_netdevice(soft_iface); | ||
637 | if (ret < 0) { | ||
638 | pr_err("Unable to register the batman interface '%s': %i\n", | ||
639 | name, ret); | ||
640 | free_netdev(soft_iface); | ||
641 | return NULL; | ||
642 | } | ||
643 | |||
644 | return soft_iface; | ||
645 | } | ||
646 | |||
647 | /** | ||
648 | * batadv_softif_destroy_sysfs - deletion of batadv_soft_interface via sysfs | ||
649 | * @soft_iface: the to-be-removed batman-adv interface | ||
650 | */ | ||
651 | void batadv_softif_destroy_sysfs(struct net_device *soft_iface) | ||
579 | { | 652 | { |
580 | struct batadv_priv *bat_priv = netdev_priv(soft_iface); | 653 | struct batadv_priv *bat_priv = netdev_priv(soft_iface); |
581 | 654 | ||
582 | batadv_mesh_free(soft_iface); | ||
583 | queue_work(batadv_event_workqueue, &bat_priv->cleanup_work); | 655 | queue_work(batadv_event_workqueue, &bat_priv->cleanup_work); |
584 | } | 656 | } |
585 | 657 | ||
658 | /** | ||
659 | * batadv_softif_destroy_netlink - deletion of batadv_soft_interface via netlink | ||
660 | * @soft_iface: the to-be-removed batman-adv interface | ||
661 | * @head: list pointer | ||
662 | */ | ||
663 | static void batadv_softif_destroy_netlink(struct net_device *soft_iface, | ||
664 | struct list_head *head) | ||
665 | { | ||
666 | struct batadv_hard_iface *hard_iface; | ||
667 | |||
668 | list_for_each_entry(hard_iface, &batadv_hardif_list, list) { | ||
669 | if (hard_iface->soft_iface == soft_iface) | ||
670 | batadv_hardif_disable_interface(hard_iface, | ||
671 | BATADV_IF_CLEANUP_KEEP); | ||
672 | } | ||
673 | |||
674 | batadv_sysfs_del_meshif(soft_iface); | ||
675 | unregister_netdevice_queue(soft_iface, head); | ||
676 | } | ||
677 | |||
586 | int batadv_softif_is_valid(const struct net_device *net_dev) | 678 | int batadv_softif_is_valid(const struct net_device *net_dev) |
587 | { | 679 | { |
588 | if (net_dev->netdev_ops->ndo_start_xmit == batadv_interface_tx) | 680 | if (net_dev->netdev_ops->ndo_start_xmit == batadv_interface_tx) |
@@ -591,6 +683,13 @@ int batadv_softif_is_valid(const struct net_device *net_dev) | |||
591 | return 0; | 683 | return 0; |
592 | } | 684 | } |
593 | 685 | ||
686 | struct rtnl_link_ops batadv_link_ops __read_mostly = { | ||
687 | .kind = "batadv", | ||
688 | .priv_size = sizeof(struct batadv_priv), | ||
689 | .setup = batadv_softif_init_early, | ||
690 | .dellink = batadv_softif_destroy_netlink, | ||
691 | }; | ||
692 | |||
594 | /* ethtool */ | 693 | /* ethtool */ |
595 | static int batadv_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) | 694 | static int batadv_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) |
596 | { | 695 | { |
@@ -662,6 +761,17 @@ static const struct { | |||
662 | { "dat_put_rx" }, | 761 | { "dat_put_rx" }, |
663 | { "dat_cached_reply_tx" }, | 762 | { "dat_cached_reply_tx" }, |
664 | #endif | 763 | #endif |
764 | #ifdef CONFIG_BATMAN_ADV_NC | ||
765 | { "nc_code" }, | ||
766 | { "nc_code_bytes" }, | ||
767 | { "nc_recode" }, | ||
768 | { "nc_recode_bytes" }, | ||
769 | { "nc_buffer" }, | ||
770 | { "nc_decode" }, | ||
771 | { "nc_decode_bytes" }, | ||
772 | { "nc_decode_failed" }, | ||
773 | { "nc_sniffed" }, | ||
774 | #endif | ||
665 | }; | 775 | }; |
666 | 776 | ||
667 | static void batadv_get_strings(struct net_device *dev, uint32_t stringset, | 777 | static void batadv_get_strings(struct net_device *dev, uint32_t stringset, |