Skip to content

mctpd: Handle discovery messages #16

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
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
70 changes: 70 additions & 0 deletions src/mctp-netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -1056,6 +1056,76 @@ static int linkmap_add_entry(mctp_nl *nl, struct ifinfomsg *info,
return 0;
}

/* Common parts of RTM_NEWADDR and RTM_DELADDR */
struct mctp_addralter_msg {
struct nlmsghdr nh;
struct ifaddrmsg ifmsg;
struct rtattr rta;
uint8_t data[4];
};
static int fill_addralter_args(struct mctp_nl *nl,
struct mctp_addralter_msg *msg,
struct rtattr **prta, size_t *prta_len,
mctp_eid_t eid, const char *linkstr)
{
int ifindex;

ifindex = mctp_nl_ifindex_byname(nl, linkstr);
if (!ifindex) {
warnx("invalid device %s", linkstr);
return -1;
}

memset(msg, 0x0, sizeof(*msg));

msg->nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;

msg->ifmsg.ifa_index = ifindex;
msg->ifmsg.ifa_family = AF_MCTP;

msg->rta.rta_type = IFA_LOCAL;
msg->rta.rta_len = RTA_LENGTH(sizeof(eid));
memcpy(RTA_DATA(&msg->rta), &eid, sizeof(eid));

msg->nh.nlmsg_len =
NLMSG_LENGTH(sizeof(msg->ifmsg)) + RTA_SPACE(sizeof(eid));

if (prta)
*prta = &msg->rta;
if (prta_len)
*prta_len = msg->rta.rta_len;

return 0;
}

int mctp_nl_addr_add(struct mctp_nl *nl, mctp_eid_t eid, const char *linkstr)
{
struct mctp_addralter_msg msg;
int rc;

rc = fill_addralter_args(nl, &msg, NULL, NULL, eid, linkstr);
if (rc)
return -1;

msg.nh.nlmsg_type = RTM_NEWADDR;

return mctp_nl_send(nl, &msg.nh);
}

int mctp_nl_addr_del(struct mctp_nl *nl, mctp_eid_t eid, const char *linkstr)
{
struct mctp_addralter_msg msg;
int rc;

rc = fill_addralter_args(nl, &msg, NULL, NULL, eid, linkstr);
if (rc)
return -1;

msg.nh.nlmsg_type = RTM_DELADDR;

return mctp_nl_send(nl, &msg.nh);
}

/* Common parts of RTM_NEWROUTE and RTM_DELROUTE */
struct mctp_rtalter_msg {
struct nlmsghdr nh;
Expand Down
4 changes: 4 additions & 0 deletions src/mctp-netlink.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ int *mctp_nl_net_list(const mctp_nl *nl, size_t *ret_num_nets);
/* Returns an allocated list of ifindex, caller to free */
int *mctp_nl_if_list(const mctp_nl *nl, size_t *ret_num_if);

/* MCTP addr helper */
int mctp_nl_addr_add(struct mctp_nl *nl, uint8_t eid, const char *ifname);
int mctp_nl_addr_del(struct mctp_nl *nl, uint8_t eid, const char *ifname);

/* MCTP route helper */
int mctp_nl_route_add(struct mctp_nl *nl, uint8_t eid, const char* ifname,
uint32_t mtu);
Expand Down
176 changes: 172 additions & 4 deletions src/mctpd.c
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@ struct ctx {

// Whether we are running as the bus owner
bool bus_owner;
// Flag for endpoint discovery process;
bool discovered;

// An allocated array of peers, changes address (reallocated) during runtime
peer *peers;
Expand All @@ -149,6 +151,8 @@ static int emit_endpoint_added(const peer *peer);
static int emit_endpoint_removed(const peer *peer);
static int emit_net_added(ctx *ctx, int net);
static int emit_net_removed(ctx *ctx, int net);
static int add_peer(ctx *ctx, const dest_phys *dest, mctp_eid_t eid, int net,
peer **ret_peer);
static int query_peer_properties(peer *peer);
static int setup_added_peer(peer *peer);
static void add_peer_route(peer *peer);
Expand Down Expand Up @@ -482,6 +486,56 @@ static int reply_message(ctx *ctx, int sd, const void *resp, size_t resp_len,
return 0;
}

/* Replies to a physical address */
static int reply_message_phys(ctx *ctx, int sd, const void *resp,
size_t resp_len,
const struct sockaddr_mctp_ext *addr)
{
ssize_t len;
struct sockaddr_mctp_ext reply_addr = *addr;

reply_addr.smctp_base.smctp_tag &= ~MCTP_TAG_OWNER;

len = sendto(sd, resp, resp_len, 0, (struct sockaddr *)&reply_addr,
sizeof(reply_addr));

if (len < 0) {
return -errno;
}

if ((size_t)len != resp_len) {
warnx("BUG: short sendto %zd, expected %zu", len, resp_len);
return -EPROTO;
}

return 0;
}

static int discover_peer_from_ext_addr(ctx *ctx, struct sockaddr_mctp_ext *addr)
{
struct peer *peer;
struct dest_phys phys;
mctp_eid_t eid;
int net;
int rc;

phys.ifindex = addr->smctp_ifindex;
memcpy(phys.hwaddr, addr->smctp_haddr, addr->smctp_halen);
phys.hwaddr_len = addr->smctp_halen;
eid = addr->smctp_base.smctp_addr.s_addr;
net = addr->smctp_base.smctp_network;

rc = add_peer(ctx, &phys, eid, net, &peer);
if (rc < 0)
return rc;

rc = setup_added_peer(peer);
if (rc < 0)
return rc;

return 0;
}

// Handles new Incoming Set Endpoint ID request
static int handle_control_set_endpoint_id(ctx *ctx,
int sd, struct sockaddr_mctp_ext *addr,
Expand All @@ -490,6 +544,8 @@ static int handle_control_set_endpoint_id(ctx *ctx,
struct mctp_ctrl_cmd_set_eid *req = NULL;
struct mctp_ctrl_resp_set_eid respi = {0}, *resp = &respi;
size_t resp_len;
mctp_eid_t eid_set;
int rc;

if (buf_size < sizeof(*req)) {
warnx("short Set Endpoint ID message");
Expand All @@ -500,12 +556,47 @@ static int handle_control_set_endpoint_id(ctx *ctx,
resp->ctrl_hdr.command_code = req->ctrl_hdr.command_code;
resp->ctrl_hdr.rq_dgram_inst = RQDI_RESP;
resp->completion_code = 0;
resp->status = 0x01 << 4; // Already assigned, TODO
resp->eid_set = local_addr(ctx, addr->smctp_ifindex);
resp->eid_pool_size = 0;
resp_len = sizeof(struct mctp_ctrl_resp_set_eid);

// TODO: learn busowner route and neigh
eid_set = local_addr(ctx, addr->smctp_ifindex);
if (!eid_set) {
const char *linkstr =
mctp_nl_if_byindex(ctx->nl, addr->smctp_ifindex);

rc = mctp_nl_addr_add(ctx->nl, req->eid, linkstr);
if (rc < 0) {
warnx("ERR: cannot add local eid %d to ifindex %d",
req->eid, addr->smctp_ifindex);
return rc;
}

rc = discover_peer_from_ext_addr(ctx, addr);
if (rc < 0) {
warnx("ERR: cannot discover bus owner");
mctp_nl_addr_del(ctx->nl, req->eid, linkstr);
return rc;
}

resp->status = 0x00; // Assignment accepted
resp->eid_set = req->eid;
resp->eid_pool_size = 0;
if (ctx->verbose)
fprintf(stderr, "Accepted set eid %d\n", req->eid);

} else {
resp->status = 0x01 << 4; // Already assigned
resp->eid_set = eid_set;
resp->eid_pool_size = 0;

if (ctx->verbose && req->eid != eid_set)
fprintf(stderr,
"Rejected set eid %d, already assigned with eid %d\n",
req->eid, eid_set);
}

if (ctx->verbose && !ctx->discovered)
fprintf(stderr, "Setting discovered flag to true\n");
ctx->discovered = true;

return reply_message(ctx, sd, resp, resp_len, addr);
}
Expand Down Expand Up @@ -663,6 +754,75 @@ static int handle_control_resolve_endpoint_id(ctx *ctx,
return reply_message(ctx, sd, resp, resp_len, addr);
}

static int handle_control_prepare_endpoint_discovery(ctx *ctx,
int sd, const struct sockaddr_mctp_ext *addr,
const uint8_t *buf, const size_t buf_size)
{
struct mctp_ctrl_msg_hdr *req = (void*)buf;
struct mctp_ctrl_resp_prepare_discovery respi = {0}, *resp = &respi;
int rc;
mctp_eid_t *addrs;
size_t addrs_num;

if (buf_size < sizeof(*req)) {
warnx("short Prepare for Endpoint Discovery message");
return -ENOMSG;
}

resp->ctrl_hdr.command_code = req->command_code;
resp->ctrl_hdr.rq_dgram_inst = RQDI_RESP;

if (ctx->verbose && ctx->discovered)
fprintf(stderr, "Clearing discovered flag\n");
ctx->discovered = false;


// clear local EIDs
addrs = mctp_nl_addrs_byindex(ctx->nl, addr->smctp_ifindex, &addrs_num);
if (!addrs) {
warnx("BUG: cannot get local EIDs at ifindex %d",
addr->smctp_ifindex);
return -ENOENT;
}
for (size_t i = 0; i < addrs_num; i++) {
rc = mctp_nl_addr_del(ctx->nl, addrs[i],
mctp_nl_if_byindex(ctx->nl,
addr->smctp_ifindex));
if (rc < 0) {
errx(rc, "ERR: cannot remove local eid %d ifindex %d",
addrs[i], addr->smctp_ifindex);
}
}
free(addrs);

// we need to send to physical location, no entry in routing table yet
return reply_message_phys(ctx, sd, resp, sizeof(*resp), addr);
}

static int
handle_control_endpoint_discovery(ctx *ctx, int sd,
const struct sockaddr_mctp_ext *addr,
const uint8_t *buf, const size_t buf_size)
{
struct mctp_ctrl_msg_hdr *req = (void *)buf;
struct mctp_ctrl_resp_endpoint_discovery respi = { 0 }, *resp = &respi;

if (buf_size < sizeof(*req)) {
warnx("short Endpoint Discovery message");
return -ENOMSG;
}

if (ctx->discovered) {
return 0;
}

resp->ctrl_hdr.command_code = req->command_code;
resp->ctrl_hdr.rq_dgram_inst = RQDI_RESP;

// we need to send to physical location, no entry in routing table yet
return reply_message_phys(ctx, sd, resp, sizeof(*resp), addr);
}

static int handle_control_unsupported(ctx *ctx,
int sd, const struct sockaddr_mctp_ext *addr,
const uint8_t *buf, const size_t buf_size)
Expand Down Expand Up @@ -743,6 +903,14 @@ static int cb_listen_control_msg(sd_event_source *s, int sd, uint32_t revents,
rc = handle_control_resolve_endpoint_id(ctx,
sd, &addr, buf, buf_size);
break;
case MCTP_CTRL_CMD_PREPARE_ENDPOINT_DISCOVERY:
rc = handle_control_prepare_endpoint_discovery(ctx,
sd, &addr, buf, buf_size);
break;
case MCTP_CTRL_CMD_ENDPOINT_DISCOVERY:
rc = handle_control_endpoint_discovery(ctx, sd, &addr,
buf, buf_size);
break;
default:
if (ctx->verbose) {
warnx("Ignoring unsupported command code 0x%02x",
Expand Down