Message ID | 20160804130932.4429-4-aar@pengutronix.de (mailing list archive) |
---|---|
State | Not Applicable |
Headers | show |
Hi, On 08/04/2016 03:09 PM, Alexander Aring wrote: > This patch adds a mechanism to get the device address length via > netlink. This is necessary for device type 6LoWPAN which can have > different device address lengths. > --- > device-linux.c | 16 +++++++++++++-- > netlink.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > netlink.h | 1 + > 3 files changed, 79 insertions(+), 2 deletions(-) > > diff --git a/device-linux.c b/device-linux.c > index 7301927..1ccb207 100644 > --- a/device-linux.c > +++ b/device-linux.c > @@ -17,6 +17,7 @@ > #include "radvd.h" > #include "defaults.h" > #include "pathnames.h" > +#include "netlink.h" > > #ifndef IPV6_ADDR_LINKLOCAL > #define IPV6_ADDR_LINKLOCAL 0x0020U > @@ -84,8 +85,19 @@ int update_device_info(int sock, struct Interface *iface) > break; > #endif /* ARPHDR_ARCNET */ > case ARPHRD_6LOWPAN: > - iface->sllao.if_hwaddr_len = 64; > - iface->sllao.if_prefix_len = 64; > +#ifdef HAVE_NETLINK > + /* hwaddr length differs on some L2 type lets detect them */ > + iface->sllao.if_hwaddr_len = netlink_get_device_addr_len(iface); > + if (iface->sllao.if_hwaddr_len != -1) { > + iface->sllao.if_hwaddr_len *= 8; > + iface->sllao.if_prefix_len = 64; > + } else { > + iface->sllao.if_prefix_len = -1; > + } > +#else > + iface->sllao.if_hwaddr_len = -1; > + iface->sllao.if_prefix_len = -1; > +#endif > break; > default: > iface->sllao.if_hwaddr_len = -1; > diff --git a/netlink.c b/netlink.c > index 80d2254..d07a0b8 100644 > --- a/netlink.c > +++ b/netlink.c > @@ -32,6 +32,70 @@ > #define SOL_NETLINK 270 > #endif > > +struct iplink_req { > + struct nlmsghdr n; > + struct ifinfomsg i; > + char buf[1024]; > +}; > + > +int netlink_get_device_addr_len(struct Interface *iface) > +{ > + struct iplink_req req = {}; > + struct iovec iov = { &req, sizeof(req) }; > + struct sockaddr_nl sa = {}; > + struct msghdr msg = { (void *)&sa, sizeof(sa), &iov, 1, NULL, 0, 0 }; > + int sock, len, addr_len = -1; > + unsigned short type; > + char answer[32768]; > + struct rtattr *tb; > + > + /* nl_pid (for linux kernel) and nl_groups (unicast) should be zero */ > + sa.nl_family = AF_NETLINK; > + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); > + req.n.nlmsg_flags = NLM_F_REQUEST; > + req.n.nlmsg_type = RTM_GETLINK; > + req.i.ifi_index = iface->props.if_index; > + > + sock = netlink_socket(); > + if (sock == -1) > + return -1; > + > + len = sendmsg(sock, &msg, 0); > + if (len == -1) { > + flog(LOG_ERR, "netlink: sendmsg for addr_len failed: %s", strerror(errno)); > + close(sock); need to be removed. > + goto out; > + } > + > + iov.iov_base = answer; > + iov.iov_len = sizeof(answer); > + len = recvmsg(sock, &msg, 0); > + if (len == -1) { > + flog(LOG_ERR, "netlink: recvmsg for addr_len failed: %s", strerror(errno)); > + close(sock); same here. > + goto out; > + } > + > + if (len < NLMSG_LENGTH(sizeof(struct ifinfomsg))) > + goto out; > + len -= NLMSG_LENGTH(sizeof(struct ifinfomsg)); > + > + tb = (struct rtattr *)(answer + NLMSG_LENGTH(sizeof(struct ifinfomsg))); > + while (RTA_OK(tb, len)) { > + type = tb->rta_type & ~NLA_F_NESTED; > + if (type == IFLA_ADDRESS) { > + addr_len = RTA_PAYLOAD(tb); > + break; > + } > + tb = RTA_NEXT(tb, len); > + } > + > +out: > + close(sock); will be done here. I will fix that before sending the pull-request if everything else is fine enough. :-) - Alex -- To unsubscribe from this list: send the line "unsubscribe linux-wpan" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/device-linux.c b/device-linux.c index 7301927..1ccb207 100644 --- a/device-linux.c +++ b/device-linux.c @@ -17,6 +17,7 @@ #include "radvd.h" #include "defaults.h" #include "pathnames.h" +#include "netlink.h" #ifndef IPV6_ADDR_LINKLOCAL #define IPV6_ADDR_LINKLOCAL 0x0020U @@ -84,8 +85,19 @@ int update_device_info(int sock, struct Interface *iface) break; #endif /* ARPHDR_ARCNET */ case ARPHRD_6LOWPAN: - iface->sllao.if_hwaddr_len = 64; - iface->sllao.if_prefix_len = 64; +#ifdef HAVE_NETLINK + /* hwaddr length differs on some L2 type lets detect them */ + iface->sllao.if_hwaddr_len = netlink_get_device_addr_len(iface); + if (iface->sllao.if_hwaddr_len != -1) { + iface->sllao.if_hwaddr_len *= 8; + iface->sllao.if_prefix_len = 64; + } else { + iface->sllao.if_prefix_len = -1; + } +#else + iface->sllao.if_hwaddr_len = -1; + iface->sllao.if_prefix_len = -1; +#endif break; default: iface->sllao.if_hwaddr_len = -1; diff --git a/netlink.c b/netlink.c index 80d2254..d07a0b8 100644 --- a/netlink.c +++ b/netlink.c @@ -32,6 +32,70 @@ #define SOL_NETLINK 270 #endif +struct iplink_req { + struct nlmsghdr n; + struct ifinfomsg i; + char buf[1024]; +}; + +int netlink_get_device_addr_len(struct Interface *iface) +{ + struct iplink_req req = {}; + struct iovec iov = { &req, sizeof(req) }; + struct sockaddr_nl sa = {}; + struct msghdr msg = { (void *)&sa, sizeof(sa), &iov, 1, NULL, 0, 0 }; + int sock, len, addr_len = -1; + unsigned short type; + char answer[32768]; + struct rtattr *tb; + + /* nl_pid (for linux kernel) and nl_groups (unicast) should be zero */ + sa.nl_family = AF_NETLINK; + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); + req.n.nlmsg_flags = NLM_F_REQUEST; + req.n.nlmsg_type = RTM_GETLINK; + req.i.ifi_index = iface->props.if_index; + + sock = netlink_socket(); + if (sock == -1) + return -1; + + len = sendmsg(sock, &msg, 0); + if (len == -1) { + flog(LOG_ERR, "netlink: sendmsg for addr_len failed: %s", strerror(errno)); + close(sock); + goto out; + } + + iov.iov_base = answer; + iov.iov_len = sizeof(answer); + len = recvmsg(sock, &msg, 0); + if (len == -1) { + flog(LOG_ERR, "netlink: recvmsg for addr_len failed: %s", strerror(errno)); + close(sock); + goto out; + } + + if (len < NLMSG_LENGTH(sizeof(struct ifinfomsg))) + goto out; + len -= NLMSG_LENGTH(sizeof(struct ifinfomsg)); + + tb = (struct rtattr *)(answer + NLMSG_LENGTH(sizeof(struct ifinfomsg))); + while (RTA_OK(tb, len)) { + type = tb->rta_type & ~NLA_F_NESTED; + if (type == IFLA_ADDRESS) { + addr_len = RTA_PAYLOAD(tb); + break; + } + tb = RTA_NEXT(tb, len); + } + +out: + close(sock); + + return addr_len; +} + void process_netlink_msg(int sock, struct Interface * ifaces) { char buf[4096]; diff --git a/netlink.h b/netlink.h index e2b706e..c693a10 100644 --- a/netlink.h +++ b/netlink.h @@ -17,5 +17,6 @@ #include "radvd.h" +int netlink_get_device_addr_len(struct Interface *iface); void process_netlink_msg(int sock, struct Interface * ifaces); int netlink_socket(void);