@@ -231,6 +231,12 @@ static int emit_interface_added(struct link *link);
231231static int emit_interface_removed (struct link * link );
232232static int emit_net_added (struct ctx * ctx , struct net * net );
233233static int emit_net_removed (struct ctx * ctx , struct net * net );
234+ static int add_peer (struct ctx * ctx , const dest_phys * dest , mctp_eid_t eid ,
235+ uint32_t net , struct peer * * ret_peer );
236+ static int add_peer_from_addr (struct ctx * ctx ,
237+ const struct sockaddr_mctp_ext * addr ,
238+ struct peer * * ret_peer );
239+ static int remove_peer (struct peer * peer );
234240static int query_peer_properties (struct peer * peer );
235241static int setup_added_peer (struct peer * peer );
236242static void add_peer_route (struct peer * peer );
@@ -631,32 +637,163 @@ static int reply_message(struct ctx *ctx, int sd, const void *resp,
631637 return 0 ;
632638}
633639
634- // Handles new Incoming Set Endpoint ID request
640+ /// Clear interface local addresses and remote cached peers
641+ static void clear_interface_addrs (struct ctx * ctx , int ifindex )
642+ {
643+ mctp_eid_t * addrs ;
644+ size_t addrs_num ;
645+ size_t i ;
646+ int rc ;
647+
648+ // Remove all addresses on this interface
649+ addrs = mctp_nl_addrs_byindex (ctx -> nl , ifindex , & addrs_num );
650+ if (addrs ) {
651+ for (i = 0 ; i < addrs_num ; i ++ ) {
652+ rc = mctp_nl_addr_del (ctx -> nl , addrs [i ], ifindex );
653+ if (rc < 0 ) {
654+ errx (rc ,
655+ "ERR: cannot remove local eid %d ifindex %d" ,
656+ addrs [i ], ifindex );
657+ }
658+ }
659+ free (addrs );
660+ }
661+
662+ // Remove all peers on this interface
663+ for (i = 0 ; i < ctx -> num_peers ; i ++ ) {
664+ struct peer * p = ctx -> peers [i ];
665+ if (p -> state == REMOTE && p -> phys .ifindex == ifindex ) {
666+ remove_peer (p );
667+ }
668+ }
669+ }
670+
671+ /// Handles new Incoming Set Endpoint ID request
672+ ///
673+ /// This currently handles two cases: Top-most bus owner and Endpoint. No bridge
674+ /// support yet.
675+ ///
676+ ///
677+ /// # References
678+ ///
679+ /// The DSP0236 1.3.3 specification describes Set Endpoint ID in the following
680+ /// sections:
681+ ///
682+ /// - 8.18 Endpoint ID assignment and endpoint ID pools
683+ ///
684+ /// > A non-bridge device that is connected to multiple different buses
685+ /// > will have one EID for each bus it is attached to.
686+ ///
687+ /// - 9.1.3 EID options for MCTP bridge
688+ ///
689+ /// > There are three general options:
690+ /// > - The bridge uses a single MCTP endpoint
691+ /// > - The bridge uses an MCTP endpoint for each bus that connects to a bus owner
692+ /// > - The bridge uses an MCTP endpoint for every bus to which it connects
693+ ///
694+ /// - 12.4 Set Endpoint ID
695+ ///
696+ /// [the whole section]
697+ ///
635698static int handle_control_set_endpoint_id (struct ctx * ctx , int sd ,
636699 struct sockaddr_mctp_ext * addr ,
637700 const uint8_t * buf ,
638701 const size_t buf_size )
639702{
640703 struct mctp_ctrl_cmd_set_eid * req = NULL ;
641704 struct mctp_ctrl_resp_set_eid respi = { 0 }, * resp = & respi ;
705+ struct link * link_data ;
706+ struct peer * peer ;
642707 size_t resp_len ;
708+ int rc ;
643709
644710 if (buf_size < sizeof (* req )) {
645- warnx ("short Set Endpoint ID message" );
711+ bug_warn ("short Set Endpoint ID message" );
646712 return - ENOMSG ;
647713 }
648714 req = (void * )buf ;
649715
716+ link_data = mctp_nl_get_link_userdata (ctx -> nl , addr -> smctp_ifindex );
717+ if (!link_data ) {
718+ bug_warn ("unconfigured interface %d" , addr -> smctp_ifindex );
719+ return - ENOENT ;
720+ }
721+
650722 mctp_ctrl_msg_hdr_init_resp (& respi .ctrl_hdr , req -> ctrl_hdr );
651723 resp -> completion_code = MCTP_CTRL_CC_SUCCESS ;
652- resp -> status = 0x01 << 4 ; // Already assigned, TODO
653- resp -> eid_set = local_addr (ctx , addr -> smctp_ifindex );
654- resp -> eid_pool_size = 0 ;
655724 resp_len = sizeof (struct mctp_ctrl_resp_set_eid );
656725
657- // TODO: learn busowner route and neigh
726+ // reject if we are bus owner
727+ if (link_data -> role == ENDPOINT_ROLE_BUS_OWNER ) {
728+ warnx ("Rejected set EID %d request from (%s) because we are the bus owner" ,
729+ req -> eid , ext_addr_tostr (addr ));
730+ resp -> completion_code = MCTP_CTRL_CC_ERROR_UNSUPPORTED_CMD ;
731+ resp_len = sizeof (struct mctp_ctrl_resp );
732+ return reply_message (ctx , sd , resp , resp_len , addr );
733+ }
734+
735+ // error if EID is invalid
736+ if (req -> eid < 0x08 || req -> eid == 0xFF ) {
737+ warnx ("Rejected invalid EID %d" , req -> eid );
738+ resp -> completion_code = MCTP_CTRL_CC_ERROR_INVALID_DATA ;
739+ resp_len =
740+ sizeof (resp -> ctrl_hdr ) + sizeof (resp -> completion_code );
741+ return reply_message (ctx , sd , resp , resp_len , addr );
742+ }
743+
744+ switch (GET_MCTP_SET_EID_OPERATION (req -> operation )) {
745+ case MCTP_SET_EID_SET :
746+ // TODO: for bridges, only accept EIDs from originator bus
747+ //
748+ // We currently only support endpoints, which require separate EIDs on
749+ // interfaces (see function comment). For bridges, we might need to support
750+ // sharing a single EID for multiple interfaces. We will need to:
751+ // - track the first bus assigned the EID.
752+ // - policy for propagating EID to other interfaces (see bridge EID options in
753+ // function comment above)
754+
755+ // fallthrough
756+ case MCTP_SET_EID_FORCE :
757+
758+ fprintf (stderr , "setting EID to %d\n" , req -> eid );
759+
760+ // When we are assigned a new EID, assume our world view of the network
761+ // reachable from this interface has been stale. Reset everything.
762+ clear_interface_addrs (ctx , addr -> smctp_ifindex );
763+
764+ rc = mctp_nl_addr_add (ctx -> nl , req -> eid , addr -> smctp_ifindex );
765+ if (rc < 0 ) {
766+ warnx ("ERR: cannot add local eid %d to ifindex %d" ,
767+ req -> eid , addr -> smctp_ifindex );
768+ resp -> completion_code = MCTP_CTRL_CC_ERROR_NOT_READY ;
769+ }
658770
659- return reply_message (ctx , sd , resp , resp_len , addr );
771+ rc = add_peer_from_addr (ctx , addr , & peer );
772+ if (rc == 0 ) {
773+ rc = setup_added_peer (peer );
774+ }
775+ if (rc < 0 ) {
776+ warnx ("ERR: cannot add bus owner to object lists" );
777+ }
778+
779+ resp -> status =
780+ SET_MCTP_EID_ASSIGNMENT_STATUS (MCTP_SET_EID_ACCEPTED ) |
781+ SET_MCTP_EID_ALLOCATION_STATUS (MCTP_SET_EID_POOL_NONE );
782+ resp -> eid_set = req -> eid ;
783+ resp -> eid_pool_size = 0 ;
784+ fprintf (stderr , "Accepted set eid %d\n" , req -> eid );
785+ return reply_message (ctx , sd , resp , resp_len , addr );
786+
787+ case MCTP_SET_EID_DISCOVERED :
788+ case MCTP_SET_EID_RESET :
789+ // unsupported
790+ resp -> completion_code = MCTP_CTRL_CC_ERROR_INVALID_DATA ;
791+ return reply_message (ctx , sd , resp , resp_len , addr );
792+
793+ default :
794+ bug_warn ("unreachable Set EID operation code" );
795+ return - EINVAL ;
796+ }
660797}
661798
662799static int
@@ -1478,6 +1615,20 @@ static int add_peer(struct ctx *ctx, const dest_phys *dest, mctp_eid_t eid,
14781615 return 0 ;
14791616}
14801617
1618+ static int add_peer_from_addr (struct ctx * ctx ,
1619+ const struct sockaddr_mctp_ext * addr ,
1620+ struct peer * * ret_peer )
1621+ {
1622+ struct dest_phys phys ;
1623+
1624+ phys .ifindex = addr -> smctp_ifindex ;
1625+ memcpy (phys .hwaddr , addr -> smctp_haddr , addr -> smctp_halen );
1626+ phys .hwaddr_len = addr -> smctp_halen ;
1627+
1628+ return add_peer (ctx , & phys , addr -> smctp_base .smctp_addr .s_addr ,
1629+ addr -> smctp_base .smctp_network , ret_peer );
1630+ }
1631+
14811632static int check_peer_struct (const struct peer * peer , const struct net * n )
14821633{
14831634 if (n -> net != peer -> net ) {
0 commit comments