diff --git a/CHANGELOG.md b/CHANGELOG.md index 20a20a0..a1dfa60 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). 5. mctpd: New test infrastructure for control procotol messaging to mctpd 6. mctpd: Add a configuration file facility, defaulting to /etc/mctpd.conf. 7. mctpd: Add mctp/interfaces/ D-Bus object +8. mctpd: Send Discovery Notify on Endpoint role set ### Changed diff --git a/src/mctp-netlink.c b/src/mctp-netlink.c index dfbe042..031b407 100644 --- a/src/mctp-netlink.c +++ b/src/mctp-netlink.c @@ -23,6 +23,8 @@ struct linkmap_entry { int ifindex; char ifname[IFNAMSIZ+1]; + uint8_t ifaddr[MAX_ADDR_LEN]; + size_t ifaddr_len; int net; bool up; @@ -53,8 +55,9 @@ static int fill_local_addrs(mctp_nl *nl); static int fill_linkmap(mctp_nl *nl); static void sort_linkmap(mctp_nl *nl); static int linkmap_add_entry(mctp_nl *nl, struct ifinfomsg *info, - const char *ifname, size_t ifname_len, int net, - bool up); + const char *ifname, size_t ifname_len, + uint8_t *ifaddr, size_t ifaddr_len, int net, + bool up); static struct linkmap_entry *entry_byindex(const mctp_nl *nl, int index); @@ -679,8 +682,9 @@ static int parse_getlink_dump(mctp_nl *nl, struct nlmsghdr *nlh, uint32_t len) for (; NLMSG_OK(nlh, len); nlh = NLMSG_NEXT(nlh, len)) { struct rtattr *rta, *rt_nest, *rt_mctp; + uint8_t *ifaddr; char *ifname; - size_t ifname_len, rlen, nlen, mlen; + size_t ifname_len, ifaddr_len, rlen, nlen, mlen; uint32_t net; bool up; @@ -722,8 +726,13 @@ static int parse_getlink_dump(mctp_nl *nl, struct nlmsghdr *nlh, uint32_t len) continue; } ifname_len = strnlen(ifname, ifname_len); + + ifaddr = mctp_get_rtnlmsg_attr(IFLA_ADDRESS, rta, rlen, + &ifaddr_len); + up = info->ifi_flags & IFF_UP; - linkmap_add_entry(nl, info, ifname, ifname_len, net, up); + linkmap_add_entry(nl, info, ifname, ifname_len, ifaddr, + ifaddr_len, net, up); } // Not done. return 1; @@ -927,6 +936,16 @@ const char* mctp_nl_if_byindex(const mctp_nl *nl, int index) return NULL; } +uint8_t *mctp_nl_ifaddr_byindex(const mctp_nl *nl, int index, size_t *ret_len) +{ + struct linkmap_entry *entry = entry_byindex(nl, index); + if (entry) { + *ret_len = entry->ifaddr_len; + return entry->ifaddr; + } + return NULL; +} + int mctp_nl_net_byindex(const mctp_nl *nl, int index) { struct linkmap_entry *entry = entry_byindex(nl, index); @@ -1054,8 +1073,9 @@ int *mctp_nl_if_list(const mctp_nl *nl, size_t *ret_num_ifs) } static int linkmap_add_entry(mctp_nl *nl, struct ifinfomsg *info, - const char *ifname, size_t ifname_len, int net, - bool up) + const char *ifname, size_t ifname_len, + uint8_t *ifaddr, size_t ifaddr_len, int net, + bool up) { struct linkmap_entry *entry; size_t newsz; @@ -1067,6 +1087,12 @@ static int linkmap_add_entry(mctp_nl *nl, struct ifinfomsg *info, return -1; } + if (ifaddr_len > MAX_ADDR_LEN) { + warnx("linkmap, too long ifaddr (%zu bytes long, expected max %d bytes)", + ifaddr_len, MAX_ADDR_LEN); + return -1; + } + if (net <= 0) { warnx("Bad network ID %d for %*s", net, (int)ifname_len, ifname); return -1; @@ -1088,6 +1114,8 @@ static int linkmap_add_entry(mctp_nl *nl, struct ifinfomsg *info, entry = &nl->linkmap[idx]; memset(entry, 0, sizeof(*entry)); snprintf(entry->ifname, IFNAMSIZ, "%*s", (int)ifname_len, ifname); + memcpy(entry->ifaddr, ifaddr, ifaddr_len); + entry->ifaddr_len = ifaddr_len; entry->ifindex = info->ifi_index; entry->net = net; entry->up = up; diff --git a/src/mctp-netlink.h b/src/mctp-netlink.h index 52847c9..10f7e0e 100644 --- a/src/mctp-netlink.h +++ b/src/mctp-netlink.h @@ -62,6 +62,7 @@ int mctp_nl_recv_all(mctp_nl *nl, int sd, /* Lookup MCTP interfaces */ int mctp_nl_ifindex_byname(const mctp_nl *nl, const char *ifname); const char* mctp_nl_if_byindex(const mctp_nl *nl, int index); +uint8_t *mctp_nl_ifaddr_byindex(const mctp_nl *nl, int index, size_t *ret_len); int mctp_nl_net_byindex(const mctp_nl *nl, int index); bool mctp_nl_up_byindex(const mctp_nl *nl, int index); /* Caller to free */ diff --git a/src/mctpd.c b/src/mctpd.c index b16e456..f9848ec 100644 --- a/src/mctpd.c +++ b/src/mctpd.c @@ -2895,6 +2895,48 @@ static int bus_link_get_prop(sd_bus *bus, return rc; } +static int notify_discovery(ctx *ctx, int ifindex) +{ + int rc = 0; + dest_phys desti = { 0 }, *dest = &desti; + struct mctp_ctrl_cmd_discovery_notify req = { 0 }; + struct mctp_ctrl_resp_discovery_notify *resp; + uint8_t *buf; + size_t buf_size; + struct sockaddr_mctp_ext resp_addr; + + dest->ifindex = ifindex; + mctp_nl_ifaddr_byindex(ctx->nl, dest->ifindex, &dest->hwaddr_len); + memset(dest->hwaddr, 0, sizeof dest->hwaddr); + + req.ctrl_hdr.command_code = MCTP_CTRL_CMD_DISCOVERY_NOTIFY; + req.ctrl_hdr.rq_dgram_inst = RQDI_REQ; + + rc = endpoint_query_phys(ctx, dest, MCTP_CTRL_HDR_MSG_TYPE, &req, + sizeof(req), &buf, &buf_size, &resp_addr); + if (rc < 0) + goto free_buf; + + if (buf_size != sizeof(*resp)) { + warnx("%s: wrong reply length %zu bytes. dest %s", __func__, + buf_size, dest_phys_tostr(dest)); + rc = -ENOMSG; + goto free_buf; + } + resp = (void *)buf; + + if (resp->completion_code != 0) { + // TODO: make this a debug message? + warnx("Failure completion code 0x%02x from %s", + resp->completion_code, dest_phys_tostr(dest)); + rc = -ECONNREFUSED; + goto free_buf; + } +free_buf: + free(buf); + return rc; +} + static int bus_link_set_prop(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *value, void *userdata, sd_bus_error *berr) @@ -2906,6 +2948,7 @@ static int bus_link_set_prop(sd_bus *bus, link_userdata *lmUserData; int rc; struct role role; + int ifindex; if (!is_interfaces_path(path)) { sd_bus_error_setf(berr, SD_BUS_ERROR_INVALID_ARGS, @@ -2921,11 +2964,13 @@ static int bus_link_set_prop(sd_bus *bus, goto out; } - lmUserData = mctp_nl_get_link_userdata_byname(ctx->nl, link_name); - if (!lmUserData) { + ifindex = mctp_nl_ifindex_byname(ctx->nl, link_name); + if (!ifindex) { rc = -ENOENT; goto out; } + lmUserData = mctp_nl_get_link_userdata(ctx->nl, ifindex); + assert(lmUserData); if (strcmp(property, "Role") != 0) { printf("Unknown property '%s' for %s iface %s\n", property, path, interface); @@ -2956,6 +3001,16 @@ static int bus_link_set_prop(sd_bus *bus, } lmUserData->role = role.role; + // Announce on the bus we are endpoint, print warning and ignore error if failed + if (lmUserData->role == ENDPOINT_ROLE_ENDPOINT) { + rc = notify_discovery(ctx, ifindex); + if (rc) { + warnx("Warning: discovery notify on interface '%s' failed: %s", link_name, + strerror(-rc)); + rc = 0; + } + } + out: set_berr(ctx, rc, berr); return rc;