Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions src/mctpd.c
Original file line number Diff line number Diff line change
Expand Up @@ -1330,6 +1330,61 @@ handle_control_endpoint_discovery(struct ctx *ctx, int sd,
return reply_message_phys(ctx, sd, resp, sizeof(*resp), addr);
}

/* Handles an incoming Discovery Notify (DSP0236 command 0x0D): a device
* telling us, as bus owner, that it wants (re)discovery. The message
* carries no payload beyond the header - all we learn is the sender's
* physical address. Acks the message and relays it as a D-Bus signal on
* the sender's interface object; deciding what to do about it is left to
* whatever is listening for that signal, since only the bus-owner policy
* layer knows how to reconcile or debounce it.
*/
static int handle_control_discovery_notify(struct ctx *ctx, int sd,
const struct sockaddr_mctp_ext *addr,
const uint8_t *buf,
const size_t buf_size)
{
struct mctp_ctrl_cmd_discovery_notify *req = NULL;
struct mctp_ctrl_resp_discovery_notify respi = { 0 }, *resp = &respi;
const char *ifname;
char *path = NULL;
int rc;

if (buf_size < sizeof(*req)) {
warnx("short Discovery Notify message");
return -ENOMSG;
}
req = (void *)buf;

/* Acknowledge immediately using physical addressing, since the
* sender may not have a valid EID yet. */
mctp_ctrl_msg_hdr_init_resp(&respi.ctrl_hdr, req->ctrl_hdr);
resp->completion_code = MCTP_CTRL_CC_SUCCESS;
rc = reply_message_phys(ctx, sd, resp, sizeof(respi), addr);
if (rc < 0)
warnx("Failed replying to Discovery Notify from %s: %s",
ext_addr_tostr(addr), strerror(-rc));

ifname = mctp_nl_if_byindex(ctx->nl, addr->smctp_ifindex);
if (!ifname) {
warnx("No interface found for Discovery Notify from %s",
ext_addr_tostr(addr));
return 0;
}

rc = asprintf(&path, "%s/%s", MCTP_DBUS_PATH_LINKS, ifname);
if (rc < 0)
return 0;

rc = sd_bus_emit_signal(ctx->bus, path, CC_MCTP_DBUS_IFACE_BUSOWNER,
"DiscoveryNotify", NULL);
if (rc < 0)
warnx("Failed to emit DiscoveryNotify signal for %s: %s",
ifname, strerror(-rc));
free(path);

return 0;
}

static int handle_control_unsupported(struct ctx *ctx, int sd,
const struct sockaddr_mctp_ext *addr,
const uint8_t *buf, const size_t buf_size)
Expand Down Expand Up @@ -1424,6 +1479,10 @@ static int cb_listen_control_msg(sd_event_source *s, int sd, uint32_t revents,
rc = handle_control_endpoint_discovery(ctx, sd, &addr, buf,
buf_size);
break;
case MCTP_CTRL_CMD_DISCOVERY_NOTIFY:
rc = handle_control_discovery_notify(ctx, sd, &addr, buf,
buf_size);
break;
default:
if (ctx->verbose) {
warnx("Ignoring unsupported command code 0x%02x",
Expand Down Expand Up @@ -4330,6 +4389,8 @@ static const sd_bus_vtable bus_link_owner_vtable[] = {
SD_BUS_PARAM(found),
method_learn_endpoint,
0),

SD_BUS_SIGNAL("DiscoveryNotify", "", 0),
SD_BUS_VTABLE_END,

};
Expand Down
42 changes: 42 additions & 0 deletions tests/test_mctpd.py
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,48 @@ async def test_get_endpoint_id(dbus, mctpd, routed_ep):
assert rsp[3] == mctpd.system.addresses[0].eid


async def test_discovery_notify(dbus, mctpd, routed_ep):
"""mctpd acks Discovery Notify and relays it as a DiscoveryNotify
signal on the sending interface's BusOwner1 object
"""
ep = routed_ep
iface = mctpd.system.interfaces[0]

mctp = await mctpd_mctp_iface_obj(dbus, iface)

notified = trio.Semaphore(initial_value=0)

def discovery_notify():
notified.release()

await mctp.on_discovery_notify(discovery_notify)

cmd = MCTPControlCommand(True, 0, 0x0D)
rsp = await ep.send_control(mctpd.network.mctp_socket, cmd)

# command code
assert rsp[1] == 0x0D
# completion code indicates success
assert rsp[2] == 0x00

with trio.move_on_after(2) as expected:
await notified.acquire()
assert not expected.cancelled_caught


async def test_discovery_notify_no_eid(mctpd):
"""Discovery Notify is acked using physical addressing, even from a
peer with no assigned EID yet
"""
peer = mctpd.network.endpoints[0]

cmd = MCTPControlCommand(True, 0, 0x0D)
rsp = await peer.send_control(mctpd.network.mctp_socket, cmd)

assert rsp[1] == 0x0D
assert rsp[2] == 0x00


async def test_response_iid(mctpd):
"""Test that instance ID is populated correctly on control protocol
responses
Expand Down
Loading