@@ -224,6 +224,12 @@ static int emit_interface_added(struct link *link);
224
224
static int emit_interface_removed (struct link * link );
225
225
static int emit_net_added (struct ctx * ctx , struct net * net );
226
226
static int emit_net_removed (struct ctx * ctx , struct net * net );
227
+ static int add_peer (struct ctx * ctx , const dest_phys * dest , mctp_eid_t eid ,
228
+ uint32_t net , struct peer * * ret_peer );
229
+ static int add_peer_from_addr (struct ctx * ctx ,
230
+ const struct sockaddr_mctp_ext * addr ,
231
+ struct peer * * ret_peer );
232
+ static int remove_peer (struct peer * peer );
227
233
static int query_peer_properties (struct peer * peer );
228
234
static int setup_added_peer (struct peer * peer );
229
235
static void add_peer_route (struct peer * peer );
@@ -624,32 +630,163 @@ static int reply_message(struct ctx *ctx, int sd, const void *resp,
624
630
return 0 ;
625
631
}
626
632
627
- // Handles new Incoming Set Endpoint ID request
633
+ /// Clear interface local addresses and remote cached peers
634
+ static void clear_interface_addrs (struct ctx * ctx , int ifindex )
635
+ {
636
+ mctp_eid_t * addrs ;
637
+ size_t addrs_num ;
638
+ size_t i ;
639
+ int rc ;
640
+
641
+ // Remove all addresses on this interface
642
+ addrs = mctp_nl_addrs_byindex (ctx -> nl , ifindex , & addrs_num );
643
+ if (addrs ) {
644
+ for (i = 0 ; i < addrs_num ; i ++ ) {
645
+ rc = mctp_nl_addr_del (ctx -> nl , addrs [i ], ifindex );
646
+ if (rc < 0 ) {
647
+ errx (rc ,
648
+ "ERR: cannot remove local eid %d ifindex %d" ,
649
+ addrs [i ], ifindex );
650
+ }
651
+ }
652
+ free (addrs );
653
+ }
654
+
655
+ // Remove all peers on this interface
656
+ for (i = 0 ; i < ctx -> num_peers ; i ++ ) {
657
+ struct peer * p = ctx -> peers [i ];
658
+ if (p -> state == REMOTE && p -> phys .ifindex == ifindex ) {
659
+ remove_peer (p );
660
+ }
661
+ }
662
+ }
663
+
664
+ /// Handles new Incoming Set Endpoint ID request
665
+ ///
666
+ /// This currently handles two cases: Top-most bus owner and Endpoint. No bridge
667
+ /// support yet.
668
+ ///
669
+ ///
670
+ /// # References
671
+ ///
672
+ /// The DSP0236 1.3.3 specification describes Set Endpoint ID in the following
673
+ /// sections:
674
+ ///
675
+ /// - 8.18 Endpoint ID assignment and endpoint ID pools
676
+ ///
677
+ /// > A non-bridge device that is connected to multiple different buses
678
+ /// > will have one EID for each bus it is attached to.
679
+ ///
680
+ /// - 9.1.3 EID options for MCTP bridge
681
+ ///
682
+ /// > There are three general options:
683
+ /// > - The bridge uses a single MCTP endpoint
684
+ /// > - The bridge uses an MCTP endpoint for each bus that connects to a bus owner
685
+ /// > - The bridge uses an MCTP endpoint for every bus to which it connects
686
+ ///
687
+ /// - 12.4 Set Endpoint ID
688
+ ///
689
+ /// [the whole section]
690
+ ///
628
691
static int handle_control_set_endpoint_id (struct ctx * ctx , int sd ,
629
692
struct sockaddr_mctp_ext * addr ,
630
693
const uint8_t * buf ,
631
694
const size_t buf_size )
632
695
{
633
696
struct mctp_ctrl_cmd_set_eid * req = NULL ;
634
697
struct mctp_ctrl_resp_set_eid respi = { 0 }, * resp = & respi ;
698
+ struct link * link_data ;
699
+ struct peer * peer ;
635
700
size_t resp_len ;
701
+ int rc ;
636
702
637
703
if (buf_size < sizeof (* req )) {
638
- warnx ("short Set Endpoint ID message" );
704
+ bug_warn ("short Set Endpoint ID message" );
639
705
return - ENOMSG ;
640
706
}
641
707
req = (void * )buf ;
642
708
709
+ link_data = mctp_nl_get_link_userdata (ctx -> nl , addr -> smctp_ifindex );
710
+ if (!link_data ) {
711
+ bug_warn ("unconfigured interface %d" , addr -> smctp_ifindex );
712
+ return - ENOENT ;
713
+ }
714
+
643
715
mctp_ctrl_msg_hdr_init_resp (& respi .ctrl_hdr , req -> ctrl_hdr );
644
716
resp -> completion_code = MCTP_CTRL_CC_SUCCESS ;
645
- resp -> status = 0x01 << 4 ; // Already assigned, TODO
646
- resp -> eid_set = local_addr (ctx , addr -> smctp_ifindex );
647
- resp -> eid_pool_size = 0 ;
648
717
resp_len = sizeof (struct mctp_ctrl_resp_set_eid );
649
718
650
- // TODO: learn busowner route and neigh
719
+ // reject if we are bus owner
720
+ if (link_data -> role == ENDPOINT_ROLE_BUS_OWNER ) {
721
+ warnx ("Rejected set EID %d because we are the bus owner" ,
722
+ req -> eid );
723
+ resp -> completion_code = MCTP_CTRL_CC_ERROR_UNSUPPORTED_CMD ;
724
+ resp_len =
725
+ sizeof (resp -> ctrl_hdr ) + sizeof (resp -> completion_code );
726
+ return reply_message (ctx , sd , resp , resp_len , addr );
727
+ }
728
+
729
+ // error if EID is invalid
730
+ if (req -> eid < 0x08 || req -> eid == 0xFF ) {
731
+ warnx ("Rejected invalid EID %d" , req -> eid );
732
+ resp -> completion_code = MCTP_CTRL_CC_ERROR_INVALID_DATA ;
733
+ resp_len =
734
+ sizeof (resp -> ctrl_hdr ) + sizeof (resp -> completion_code );
735
+ return reply_message (ctx , sd , resp , resp_len , addr );
736
+ }
737
+
738
+ switch (GET_MCTP_SET_EID_OPERATION (req -> operation )) {
739
+ case MCTP_SET_EID_SET :
740
+ // TODO: for bridges, only accept EIDs from originator bus
741
+ //
742
+ // We currently only support endpoints, which require separate EIDs on
743
+ // interfaces (see function comment). For bridges, we might need to support
744
+ // sharing a single EID for multiple interfaces. We will need to:
745
+ // - track the first bus assigned the EID.
746
+ // - policy for propagating EID to other interfaces (see bridge EID options in
747
+ // function comment above)
748
+ case MCTP_SET_EID_FORCE :
749
+
750
+ warnx ("setting EID to %d" , req -> eid );
751
+
752
+ // When we are assigned a new EID, assume our world view of the network
753
+ // reachable from this interface has been stale. Reset everything.
754
+ clear_interface_addrs (ctx , addr -> smctp_ifindex );
755
+
756
+ rc = mctp_nl_addr_add (ctx -> nl , req -> eid , addr -> smctp_ifindex );
757
+ if (rc < 0 ) {
758
+ warnx ("ERR: cannot add local eid %d to ifindex %d" ,
759
+ req -> eid , addr -> smctp_ifindex );
760
+ resp -> completion_code = MCTP_CTRL_CC_ERROR_NOT_READY ;
761
+ }
762
+
763
+ rc = add_peer_from_addr (ctx , addr , & peer );
764
+ if (rc == 0 ) {
765
+ rc = setup_added_peer (peer );
766
+ }
767
+ if (rc < 0 ) {
768
+ warnx ("ERR: cannot add bus owner to object lists" );
769
+ }
651
770
652
- return reply_message (ctx , sd , resp , resp_len , addr );
771
+ SET_MCTP_EID_ASSIGNMENT_STATUS (resp -> status ,
772
+ MCTP_SET_EID_ACCEPTED );
773
+ SET_MCTP_EID_ALLOCATION_STATUS (resp -> status ,
774
+ MCTP_SET_EID_POOL_NONE );
775
+ resp -> eid_set = req -> eid ;
776
+ resp -> eid_pool_size = 0 ;
777
+ warnx ("Accepted set eid %d\n" , req -> eid );
778
+ return reply_message (ctx , sd , resp , resp_len , addr );
779
+
780
+ case MCTP_SET_EID_DISCOVERED :
781
+ case MCTP_SET_EID_RESET :
782
+ // unsupported
783
+ resp -> completion_code = MCTP_CTRL_CC_ERROR_INVALID_DATA ;
784
+ return reply_message (ctx , sd , resp , resp_len , addr );
785
+
786
+ default :
787
+ bug_warn ("unreachable Set EID operation code" );
788
+ return - EINVAL ;
789
+ }
653
790
}
654
791
655
792
static int
@@ -1469,6 +1606,20 @@ static int add_peer(struct ctx *ctx, const dest_phys *dest, mctp_eid_t eid,
1469
1606
return 0 ;
1470
1607
}
1471
1608
1609
+ static int add_peer_from_addr (struct ctx * ctx ,
1610
+ const struct sockaddr_mctp_ext * addr ,
1611
+ struct peer * * ret_peer )
1612
+ {
1613
+ struct dest_phys phys ;
1614
+
1615
+ phys .ifindex = addr -> smctp_ifindex ;
1616
+ memcpy (phys .hwaddr , addr -> smctp_haddr , addr -> smctp_halen );
1617
+ phys .hwaddr_len = addr -> smctp_halen ;
1618
+
1619
+ return add_peer (ctx , & phys , addr -> smctp_base .smctp_addr .s_addr ,
1620
+ addr -> smctp_base .smctp_network , ret_peer );
1621
+ }
1622
+
1472
1623
static int check_peer_struct (const struct peer * peer , const struct net * n )
1473
1624
{
1474
1625
if (n -> net != peer -> net ) {
0 commit comments