@@ -717,6 +717,15 @@ static int qeth_l2_dev2br_an_set(struct qeth_card *card, bool enable)
717717 return rc ;
718718}
719719
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+
720729static const struct net_device_ops qeth_l2_netdev_ops ;
721730
722731static bool qeth_l2_must_learn (struct net_device * netdev ,
@@ -732,6 +741,116 @@ static bool qeth_l2_must_learn(struct net_device *netdev,
732741 netdev -> netdev_ops == & qeth_l2_netdev_ops );
733742}
734743
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+
735854/* Called under rtnl_lock */
736855static int qeth_l2_switchdev_event (struct notifier_block * unused ,
737856 unsigned long event , void * ptr )
@@ -741,6 +860,7 @@ static int qeth_l2_switchdev_event(struct notifier_block *unused,
741860 struct switchdev_notifier_info * info = ptr ;
742861 struct list_head * iter ;
743862 struct qeth_card * card ;
863+ int rc ;
744864
745865 if (!(event == SWITCHDEV_FDB_ADD_TO_DEVICE ||
746866 event == SWITCHDEV_FDB_DEL_TO_DEVICE ))
@@ -759,10 +879,13 @@ static int qeth_l2_switchdev_event(struct notifier_block *unused,
759879 if (qeth_l2_must_learn (lowerdev , dstdev )) {
760880 card = lowerdev -> ml_priv ;
761881 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+ }
766889 }
767890 lowerdev = netdev_next_lower_dev_rcu (brdev , & iter );
768891 }
0 commit comments