@@ -224,6 +224,12 @@ static int emit_interface_added(struct link *link);
224224static int emit_interface_removed (struct link * link );
225225static int emit_net_added (struct ctx * ctx , struct net * net );
226226static 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 );
227233static int query_peer_properties (struct peer * peer );
228234static int setup_added_peer (struct peer * peer );
229235static void add_peer_route (struct peer * peer );
@@ -624,32 +630,163 @@ static int reply_message(struct ctx *ctx, int sd, const void *resp,
624630 return 0 ;
625631}
626632
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+ ///
628691static int handle_control_set_endpoint_id (struct ctx * ctx , int sd ,
629692 struct sockaddr_mctp_ext * addr ,
630693 const uint8_t * buf ,
631694 const size_t buf_size )
632695{
633696 struct mctp_ctrl_cmd_set_eid * req = NULL ;
634697 struct mctp_ctrl_resp_set_eid respi = { 0 }, * resp = & respi ;
698+ struct link * link_data ;
699+ struct peer * peer ;
635700 size_t resp_len ;
701+ int rc ;
636702
637703 if (buf_size < sizeof (* req )) {
638- warnx ("short Set Endpoint ID message" );
704+ bug_warn ("short Set Endpoint ID message" );
639705 return - ENOMSG ;
640706 }
641707 req = (void * )buf ;
642708
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+
643715 mctp_ctrl_msg_hdr_init_resp (& respi .ctrl_hdr , req -> ctrl_hdr );
644716 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 ;
648717 resp_len = sizeof (struct mctp_ctrl_resp_set_eid );
649718
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+ }
651770
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+ }
653790}
654791
655792static int
@@ -1469,6 +1606,20 @@ static int add_peer(struct ctx *ctx, const dest_phys *dest, mctp_eid_t eid,
14691606 return 0 ;
14701607}
14711608
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+
14721623static int check_peer_struct (const struct peer * peer , const struct net * n )
14731624{
14741625 if (n -> net != peer -> net ) {
0 commit comments