Skip to content

Commit af129e9

Browse files
committed
mctpd: prevent add-then-remove during SetupEndpoint reassignment
Currently, if an endpoint needs reassigning due to a bridge conflict, SetupEndpoint may publish an endpoint, then remove it. This is because we're calling get_endpoint_peer() for the Get Endpoint ID function (which adds the peer), but later check for bridge compatibility. Prevent this by open-codin the parts we need from get_endpoint_peer, and only performing the add once we have a valid peer. This requires a bit of re-work that is particular to bridge allocation in the SetupEndpoint case. Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
1 parent 307298d commit af129e9

File tree

1 file changed

+71
-31
lines changed

1 file changed

+71
-31
lines changed

src/mctpd.c

Lines changed: 71 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2360,10 +2360,14 @@ static int method_setup_endpoint(sd_bus_message *call, void *data,
23602360
sd_bus_error *berr)
23612361
{
23622362
dest_phys desti = { 0 }, *dest = &desti;
2363+
uint8_t ep_type, medium_spec;
23632364
const char *peer_path = NULL;
23642365
struct link *link = data;
23652366
struct ctx *ctx = link->ctx;
23662367
struct peer *peer = NULL;
2368+
bool new = true;
2369+
mctp_eid_t eid;
2370+
uint32_t net;
23672371
int rc;
23682372

23692373
dest->ifindex = link->ifindex;
@@ -2380,53 +2384,89 @@ static int method_setup_endpoint(sd_bus_message *call, void *data,
23802384
return sd_bus_error_setf(berr, SD_BUS_ERROR_INVALID_ARGS,
23812385
"Bad physaddr");
23822386

2387+
net = mctp_nl_net_byindex(ctx->nl, dest->ifindex);
2388+
if (!net) {
2389+
rc = -EINVAL;
2390+
goto err;
2391+
}
2392+
23832393
/* Get Endpoint ID */
2384-
rc = get_endpoint_peer(ctx, berr, dest, &peer, NULL);
2385-
if (rc >= 0 && peer) {
2386-
uint8_t ep_type = GET_MCTP_GET_EID_EP_TYPE(peer->endpoint_type);
2387-
if (ep_type == MCTP_GET_EID_EP_TYPE_BRIDGE) {
2388-
fprintf(stderr,
2389-
"SetupEndpoint, eid %d: Get EID "
2390-
"response indicated a bridge with existing "
2391-
"EID, reassigning\n",
2392-
peer->eid);
2393-
remove_peer(peer);
2394-
peer = NULL;
2394+
rc = query_get_endpoint_id(ctx, dest, &eid, &ep_type, &medium_spec);
2395+
if (rc)
2396+
goto err;
2397+
2398+
/* does it exist already? */
2399+
peer = find_peer_by_phys(ctx, dest);
2400+
2401+
/* we have a few cases:
2402+
*
2403+
* - no peer, no eid
2404+
* --> set up both
2405+
* - no peer, eid, not a bridge:
2406+
* --> create a peer with the given EID
2407+
* - no peer, eid, bridge:
2408+
* --> reassign, including bridge
2409+
* - peer, eid (but not matching)
2410+
* --> change EID if possible, or reassign
2411+
* - peer, no eid:
2412+
* --> remove peer, reassign
2413+
*/
2414+
2415+
bool is_bridge = GET_MCTP_GET_EID_EP_TYPE(ep_type) ==
2416+
MCTP_GET_EID_EP_TYPE_BRIDGE;
2417+
2418+
printf("%s: peer %p, eid %d, is_bridge %d ep type %x\n", __func__, peer,
2419+
eid, is_bridge, ep_type);
2420+
2421+
if (peer) {
2422+
/* TODO: we could check the bridge allocation through the
2423+
* Get Allocation Information op of Allocate Endpoint IDs,
2424+
* and be slightly more accurate with persisting the EID...
2425+
*/
2426+
if (eid && peer->eid == eid && is_bridge == !!peer->pool_size) {
2427+
/* all matching: no action required */
2428+
new = false;
2429+
goto out;
2430+
}
2431+
/* we have some difference in EID / bridge config, remove and
2432+
* reassign */
2433+
remove_peer(peer);
2434+
peer = NULL;
2435+
}
2436+
2437+
/* simple allocation: try to use existing EID */
2438+
if (eid && !is_bridge) {
2439+
rc = add_peer(ctx, dest, eid, net, &peer, false);
2440+
if (rc == -EEXIST) {
2441+
/* proposed EID already present on a different peer,
2442+
* fall back to assigning */
2443+
} else if (rc < 0) {
2444+
goto err;
23952445
} else {
2396-
if (ctx->verbose)
2397-
fprintf(stderr,
2398-
"%s returning from get_endpoint_peer %s\n",
2399-
__func__, peer_tostr(peer));
2400-
peer_path = path_from_peer(peer);
2401-
if (!peer_path)
2446+
peer->endpoint_type = ep_type;
2447+
peer->medium_spec = medium_spec;
2448+
rc = setup_added_peer(peer);
2449+
if (rc)
24022450
goto err;
2403-
return sd_bus_reply_method_return(call, "yisb",
2404-
peer->eid, peer->net,
2405-
peer_path, 0);
2451+
goto out;
24062452
}
2407-
} else if (rc == -EEXIST) {
2408-
// EEXISTS is OK, we will assign a new eid instead.
2409-
} else if (rc < 0) {
2410-
// Unhandled error, fail.
2411-
goto err;
24122453
}
24132454

2414-
/* Set Endpoint ID */
24152455
rc = endpoint_assign_eid(ctx, berr, dest, &peer, 0, true);
24162456
if (rc < 0)
24172457
goto err;
24182458

24192459
if (peer->pool_size)
24202460
endpoint_allocate_eids(peer);
24212461

2462+
out:
24222463
peer_path = path_from_peer(peer);
2423-
if (!peer_path)
2464+
if (!peer_path) {
2465+
rc = -EPROTO;
24242466
goto err;
2425-
if (ctx->verbose)
2426-
fprintf(stderr, "%s returning from endpoint_assign_eid %s\n",
2427-
__func__, peer_tostr(peer));
2467+
}
24282468
return sd_bus_reply_method_return(call, "yisb", peer->eid, peer->net,
2429-
peer_path, 1);
2469+
peer_path, new);
24302470

24312471
err:
24322472
set_berr(ctx, rc, berr);

0 commit comments

Comments
 (0)