@@ -717,6 +717,15 @@ static int qeth_l2_dev2br_an_set(struct qeth_card *card, bool enable)
717
717
return rc ;
718
718
}
719
719
720
+ struct qeth_l2_br2dev_event_work {
721
+ struct work_struct work ;
722
+ struct net_device * br_dev ;
723
+ struct net_device * lsync_dev ;
724
+ struct net_device * dst_dev ;
725
+ unsigned long event ;
726
+ unsigned char addr [ETH_ALEN ];
727
+ };
728
+
720
729
static const struct net_device_ops qeth_l2_netdev_ops ;
721
730
722
731
static bool qeth_l2_must_learn (struct net_device * netdev ,
@@ -732,6 +741,116 @@ static bool qeth_l2_must_learn(struct net_device *netdev,
732
741
netdev -> netdev_ops == & qeth_l2_netdev_ops );
733
742
}
734
743
744
+ /**
745
+ * qeth_l2_br2dev_worker() - update local MACs
746
+ * @work: bridge to device FDB update
747
+ *
748
+ * Update local MACs of a learning_sync bridgeport so it can receive
749
+ * messages for a destination port.
750
+ * In case of an isolated learning_sync port, also update its isolated
751
+ * siblings.
752
+ */
753
+ static void qeth_l2_br2dev_worker (struct work_struct * work )
754
+ {
755
+ struct qeth_l2_br2dev_event_work * br2dev_event_work =
756
+ container_of (work , struct qeth_l2_br2dev_event_work , work );
757
+ struct net_device * lsyncdev = br2dev_event_work -> lsync_dev ;
758
+ struct net_device * dstdev = br2dev_event_work -> dst_dev ;
759
+ struct net_device * brdev = br2dev_event_work -> br_dev ;
760
+ unsigned long event = br2dev_event_work -> event ;
761
+ unsigned char * addr = br2dev_event_work -> addr ;
762
+ struct qeth_card * card = lsyncdev -> ml_priv ;
763
+ struct net_device * lowerdev ;
764
+ struct list_head * iter ;
765
+ int err = 0 ;
766
+
767
+ kfree (br2dev_event_work );
768
+ QETH_CARD_TEXT_ (card , 4 , "b2dw%04x" , event );
769
+ QETH_CARD_TEXT_ (card , 4 , "ma%012lx" , ether_addr_to_u64 (addr ));
770
+
771
+ rcu_read_lock ();
772
+ /* Verify preconditions are still valid: */
773
+ if (!netif_is_bridge_port (lsyncdev ) ||
774
+ brdev != netdev_master_upper_dev_get_rcu (lsyncdev ))
775
+ goto unlock ;
776
+ if (!qeth_l2_must_learn (lsyncdev , dstdev ))
777
+ goto unlock ;
778
+
779
+ if (br_port_flag_is_set (lsyncdev , BR_ISOLATED )) {
780
+ /* Update lsyncdev and its isolated sibling(s): */
781
+ iter = & brdev -> adj_list .lower ;
782
+ lowerdev = netdev_next_lower_dev_rcu (brdev , & iter );
783
+ while (lowerdev ) {
784
+ if (br_port_flag_is_set (lowerdev , BR_ISOLATED )) {
785
+ switch (event ) {
786
+ case SWITCHDEV_FDB_ADD_TO_DEVICE :
787
+ err = dev_uc_add (lowerdev , addr );
788
+ break ;
789
+ case SWITCHDEV_FDB_DEL_TO_DEVICE :
790
+ err = dev_uc_del (lowerdev , addr );
791
+ break ;
792
+ default :
793
+ break ;
794
+ }
795
+ if (err ) {
796
+ QETH_CARD_TEXT (card , 2 , "b2derris" );
797
+ QETH_CARD_TEXT_ (card , 2 ,
798
+ "err%02x%03d" , event ,
799
+ lowerdev -> ifindex );
800
+ }
801
+ }
802
+ lowerdev = netdev_next_lower_dev_rcu (brdev , & iter );
803
+ }
804
+ } else {
805
+ switch (event ) {
806
+ case SWITCHDEV_FDB_ADD_TO_DEVICE :
807
+ err = dev_uc_add (lsyncdev , addr );
808
+ break ;
809
+ case SWITCHDEV_FDB_DEL_TO_DEVICE :
810
+ err = dev_uc_del (lsyncdev , addr );
811
+ break ;
812
+ default :
813
+ break ;
814
+ }
815
+ if (err )
816
+ QETH_CARD_TEXT_ (card , 2 , "b2derr%02x" , event );
817
+ }
818
+
819
+ unlock :
820
+ rcu_read_unlock ();
821
+ dev_put (brdev );
822
+ dev_put (lsyncdev );
823
+ dev_put (dstdev );
824
+ }
825
+
826
+ static int qeth_l2_br2dev_queue_work (struct net_device * brdev ,
827
+ struct net_device * lsyncdev ,
828
+ struct net_device * dstdev ,
829
+ unsigned long event ,
830
+ const unsigned char * addr )
831
+ {
832
+ struct qeth_l2_br2dev_event_work * worker_data ;
833
+ struct qeth_card * card ;
834
+
835
+ worker_data = kzalloc (sizeof (* worker_data ), GFP_ATOMIC );
836
+ if (!worker_data )
837
+ return - ENOMEM ;
838
+ INIT_WORK (& worker_data -> work , qeth_l2_br2dev_worker );
839
+ worker_data -> br_dev = brdev ;
840
+ worker_data -> lsync_dev = lsyncdev ;
841
+ worker_data -> dst_dev = dstdev ;
842
+ worker_data -> event = event ;
843
+ ether_addr_copy (worker_data -> addr , addr );
844
+
845
+ card = lsyncdev -> ml_priv ;
846
+ /* Take a reference on the sw port devices and the bridge */
847
+ dev_hold (brdev );
848
+ dev_hold (lsyncdev );
849
+ dev_hold (dstdev );
850
+ queue_work (card -> event_wq , & worker_data -> work );
851
+ return 0 ;
852
+ }
853
+
735
854
/* Called under rtnl_lock */
736
855
static int qeth_l2_switchdev_event (struct notifier_block * unused ,
737
856
unsigned long event , void * ptr )
@@ -741,6 +860,7 @@ static int qeth_l2_switchdev_event(struct notifier_block *unused,
741
860
struct switchdev_notifier_info * info = ptr ;
742
861
struct list_head * iter ;
743
862
struct qeth_card * card ;
863
+ int rc ;
744
864
745
865
if (!(event == SWITCHDEV_FDB_ADD_TO_DEVICE ||
746
866
event == SWITCHDEV_FDB_DEL_TO_DEVICE ))
@@ -759,10 +879,13 @@ static int qeth_l2_switchdev_event(struct notifier_block *unused,
759
879
if (qeth_l2_must_learn (lowerdev , dstdev )) {
760
880
card = lowerdev -> ml_priv ;
761
881
QETH_CARD_TEXT_ (card , 4 , "b2dqw%03x" , event );
762
- /* tbd: rc = qeth_l2_br2dev_queue_work(brdev, lowerdev,
763
- * dstdev, event,
764
- * fdb_info->addr);
765
- */
882
+ rc = qeth_l2_br2dev_queue_work (brdev , lowerdev ,
883
+ dstdev , event ,
884
+ fdb_info -> addr );
885
+ if (rc ) {
886
+ QETH_CARD_TEXT (card , 2 , "b2dqwerr" );
887
+ return NOTIFY_BAD ;
888
+ }
766
889
}
767
890
lowerdev = netdev_next_lower_dev_rcu (brdev , & iter );
768
891
}
0 commit comments