diff --git a/src/lxc/network.c b/src/lxc/network.c index 136e4e06da..cb2a8c0fd7 100644 --- a/src/lxc/network.c +++ b/src/lxc/network.c @@ -88,26 +88,12 @@ # define IFLA_MACVLAN_MODE 1 #endif -struct link_req { - struct nlmsg nlmsg; - struct ifinfomsg ifinfomsg; -}; - -struct ip_req { - struct nlmsg nlmsg; - struct ifaddrmsg ifa; -}; - -struct rt_req { - struct nlmsg nlmsg; - struct rtmsg rt; -}; int lxc_netdev_move_by_index(int ifindex, pid_t pid, const char* ifname) { struct nl_handler nlh; struct nlmsg *nlmsg = NULL; - struct link_req *link_req; + struct ifinfomsg *ifi; int err; err = netlink_open(&nlh, NETLINK_ROUTE); @@ -119,12 +105,12 @@ int lxc_netdev_move_by_index(int ifindex, pid_t pid, const char* ifname) if (!nlmsg) goto out; - link_req = (struct link_req *)nlmsg; - link_req->ifinfomsg.ifi_family = AF_UNSPEC; - link_req->ifinfomsg.ifi_index = ifindex; - nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); - nlmsg->nlmsghdr.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK; - nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK; + nlmsg->nlmsghdr->nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK; + nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK; + + ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg)); + ifi->ifi_family = AF_UNSPEC; + ifi->ifi_index = ifindex; if (nla_put_u32(nlmsg, IFLA_NET_NS_PID, pid)) goto out; @@ -269,7 +255,7 @@ int lxc_netdev_delete_by_index(int ifindex) { struct nl_handler nlh; struct nlmsg *nlmsg = NULL, *answer = NULL; - struct link_req *link_req; + struct ifinfomsg *ifi; int err; err = netlink_open(&nlh, NETLINK_ROUTE); @@ -285,12 +271,12 @@ int lxc_netdev_delete_by_index(int ifindex) if (!answer) goto out; - link_req = (struct link_req *)nlmsg; - link_req->ifinfomsg.ifi_family = AF_UNSPEC; - link_req->ifinfomsg.ifi_index = ifindex; - nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); - nlmsg->nlmsghdr.nlmsg_flags = NLM_F_ACK|NLM_F_REQUEST; - nlmsg->nlmsghdr.nlmsg_type = RTM_DELLINK; + nlmsg->nlmsghdr->nlmsg_flags = NLM_F_ACK|NLM_F_REQUEST; + nlmsg->nlmsghdr->nlmsg_type = RTM_DELLINK; + + ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg)); + ifi->ifi_family = AF_UNSPEC; + ifi->ifi_index = ifindex; err = netlink_transaction(&nlh, nlmsg, answer); out: @@ -315,7 +301,7 @@ int lxc_netdev_rename_by_index(int ifindex, const char *newname) { struct nl_handler nlh; struct nlmsg *nlmsg = NULL, *answer = NULL; - struct link_req *link_req; + struct ifinfomsg *ifi; int len, err; err = netlink_open(&nlh, NETLINK_ROUTE); @@ -335,12 +321,12 @@ int lxc_netdev_rename_by_index(int ifindex, const char *newname) if (!answer) goto out; - link_req = (struct link_req *)nlmsg; - link_req->ifinfomsg.ifi_family = AF_UNSPEC; - link_req->ifinfomsg.ifi_index = ifindex; - nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); - nlmsg->nlmsghdr.nlmsg_flags = NLM_F_ACK|NLM_F_REQUEST; - nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK; + nlmsg->nlmsghdr->nlmsg_flags = NLM_F_ACK|NLM_F_REQUEST; + nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK; + + ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg)); + ifi->ifi_family = AF_UNSPEC; + ifi->ifi_index = ifindex; if (nla_put_string(nlmsg, IFLA_IFNAME, newname)) goto out; @@ -372,7 +358,7 @@ int netdev_set_flag(const char *name, int flag) { struct nl_handler nlh; struct nlmsg *nlmsg = NULL, *answer = NULL; - struct link_req *link_req; + struct ifinfomsg *ifi; int index, len, err; err = netlink_open(&nlh, NETLINK_ROUTE); @@ -398,14 +384,14 @@ int netdev_set_flag(const char *name, int flag) if (!index) goto out; - link_req = (struct link_req *)nlmsg; - link_req->ifinfomsg.ifi_family = AF_UNSPEC; - link_req->ifinfomsg.ifi_index = index; - link_req->ifinfomsg.ifi_change |= IFF_UP; - link_req->ifinfomsg.ifi_flags |= flag; - nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); - nlmsg->nlmsghdr.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK; - nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK; + nlmsg->nlmsghdr->nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK; + nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK; + + ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg)); + ifi->ifi_family = AF_UNSPEC; + ifi->ifi_index = index; + ifi->ifi_change |= IFF_UP; + ifi->ifi_flags |= flag; err = netlink_transaction(&nlh, nlmsg, answer); out: @@ -419,9 +405,8 @@ int netdev_get_flag(const char* name, int *flag) { struct nl_handler nlh; struct nlmsg *nlmsg = NULL, *answer = NULL; - struct link_req *link_req; - int index, len, err; struct ifinfomsg *ifi; + int index, len, err; if (!name) return -EINVAL; @@ -449,12 +434,14 @@ int netdev_get_flag(const char* name, int *flag) if (!index) goto out; - link_req = (struct link_req *)nlmsg; - link_req->ifinfomsg.ifi_family = AF_UNSPEC; - link_req->ifinfomsg.ifi_index = index; - nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); - nlmsg->nlmsghdr.nlmsg_flags = NLM_F_REQUEST; - nlmsg->nlmsghdr.nlmsg_type = RTM_GETLINK; + nlmsg->nlmsghdr->nlmsg_flags = NLM_F_REQUEST; + nlmsg->nlmsghdr->nlmsg_type = RTM_GETLINK; + + ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg)); + ifi->ifi_family = AF_UNSPEC; + ifi->ifi_index = index; + + nlmsg_reserve(answer, sizeof(struct ifinfomsg)); err = netlink_transaction(&nlh, nlmsg, answer); if (err) @@ -499,7 +486,7 @@ int netdev_get_mtu(int ifindex) { struct nl_handler nlh; struct nlmsg *nlmsg = NULL, *answer = NULL; - struct ip_req *ip_req; + struct ifinfomsg *ifi; struct nlmsghdr *msg; int err, res; int recv_len = 0, answer_len; @@ -521,14 +508,14 @@ int netdev_get_mtu(int ifindex) /* Save the answer buffer length, since it will be overwritten * on the first receive (and we might need to receive more than * once. */ - answer_len = answer->nlmsghdr.nlmsg_len; + nlmsg_reserve(answer, NLMSG_GOOD_SIZE); + answer_len = answer->nlmsghdr->nlmsg_len; + + nlmsg->nlmsghdr->nlmsg_flags = NLM_F_REQUEST|NLM_F_DUMP; + nlmsg->nlmsghdr->nlmsg_type = RTM_GETLINK; - ip_req = (struct ip_req *)nlmsg; - ip_req->nlmsg.nlmsghdr.nlmsg_len = - NLMSG_LENGTH(sizeof(struct ifaddrmsg)); - ip_req->nlmsg.nlmsghdr.nlmsg_flags = NLM_F_REQUEST|NLM_F_DUMP; - ip_req->nlmsg.nlmsghdr.nlmsg_type = RTM_GETLINK; - ip_req->ifa.ifa_family = AF_UNSPEC; + ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg)); + ifi->ifi_family = AF_UNSPEC; /* Send the request for addresses, which returns all addresses * on all interfaces. */ @@ -539,7 +526,7 @@ int netdev_get_mtu(int ifindex) do { /* Restore the answer buffer length, it might have been * overwritten by a previous receive. */ - answer->nlmsghdr.nlmsg_len = answer_len; + answer->nlmsghdr->nlmsg_len = answer_len; /* Get the (next) batch of reply messages */ err = netlink_rcv(&nlh, answer); @@ -550,7 +537,7 @@ int netdev_get_mtu(int ifindex) err = 0; /* Satisfy the typing for the netlink macros */ - msg = &answer->nlmsghdr; + msg = answer->nlmsghdr; while (NLMSG_OK(msg, recv_len)) { @@ -567,7 +554,7 @@ int netdev_get_mtu(int ifindex) break; } - struct ifinfomsg *ifi = NLMSG_DATA(msg); + ifi = NLMSG_DATA(msg); if (ifi->ifi_index == ifindex) { struct rtattr *rta = IFLA_RTA(ifi); int attr_len = msg->nlmsg_len - NLMSG_LENGTH(sizeof(*ifi)); @@ -609,7 +596,7 @@ int lxc_netdev_set_mtu(const char *name, int mtu) { struct nl_handler nlh; struct nlmsg *nlmsg = NULL, *answer = NULL; - struct link_req *link_req; + struct ifinfomsg *ifi; int index, len, err; err = netlink_open(&nlh, NETLINK_ROUTE); @@ -635,12 +622,12 @@ int lxc_netdev_set_mtu(const char *name, int mtu) if (!index) goto out; - link_req = (struct link_req *)nlmsg; - link_req->ifinfomsg.ifi_family = AF_UNSPEC; - link_req->ifinfomsg.ifi_index = index; - nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); - nlmsg->nlmsghdr.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK; - nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK; + nlmsg->nlmsghdr->nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK; + nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK; + + ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg)); + ifi->ifi_family = AF_UNSPEC; + ifi->ifi_index = index; if (nla_put_u32(nlmsg, IFLA_MTU, mtu)) goto out; @@ -667,7 +654,7 @@ int lxc_veth_create(const char *name1, const char *name2) { struct nl_handler nlh; struct nlmsg *nlmsg = NULL, *answer = NULL; - struct link_req *link_req; + struct ifinfomsg *ifi; struct rtattr *nest1, *nest2, *nest3; int len, err; @@ -693,12 +680,12 @@ int lxc_veth_create(const char *name1, const char *name2) if (!answer) goto out; - link_req = (struct link_req *)nlmsg; - link_req->ifinfomsg.ifi_family = AF_UNSPEC; - nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); - nlmsg->nlmsghdr.nlmsg_flags = + nlmsg->nlmsghdr->nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL|NLM_F_ACK; - nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK; + nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK; + + ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg)); + ifi->ifi_family = AF_UNSPEC; err = -EINVAL; nest1 = nla_begin_nested(nlmsg, IFLA_LINKINFO); @@ -716,7 +703,7 @@ int lxc_veth_create(const char *name1, const char *name2) if (!nest3) goto out; - nlmsg->nlmsghdr.nlmsg_len += sizeof(struct ifinfomsg); + nlmsg->nlmsghdr->nlmsg_len += sizeof(struct ifinfomsg); if (nla_put_string(nlmsg, IFLA_IFNAME, name2)) goto out; @@ -743,7 +730,7 @@ int lxc_vlan_create(const char *master, const char *name, unsigned short vlanid) { struct nl_handler nlh; struct nlmsg *nlmsg = NULL, *answer = NULL; - struct link_req *link_req; + struct ifinfomsg *ifi; struct rtattr *nest, *nest2; int lindex, len, err; @@ -774,12 +761,12 @@ int lxc_vlan_create(const char *master, const char *name, unsigned short vlanid) if (!lindex) goto err1; - link_req = (struct link_req *)nlmsg; - link_req->ifinfomsg.ifi_family = AF_UNSPEC; - nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); - nlmsg->nlmsghdr.nlmsg_flags = + nlmsg->nlmsghdr->nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL|NLM_F_ACK; - nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK; + nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK; + + ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg)); + ifi->ifi_family = AF_UNSPEC; nest = nla_begin_nested(nlmsg, IFLA_LINKINFO); if (!nest) @@ -819,7 +806,7 @@ int lxc_macvlan_create(const char *master, const char *name, int mode) { struct nl_handler nlh; struct nlmsg *nlmsg = NULL, *answer = NULL; - struct link_req *link_req; + struct ifinfomsg *ifi; struct rtattr *nest, *nest2; int index, len, err; @@ -850,12 +837,12 @@ int lxc_macvlan_create(const char *master, const char *name, int mode) if (!index) goto out; - link_req = (struct link_req *)nlmsg; - link_req->ifinfomsg.ifi_family = AF_UNSPEC; - nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); - nlmsg->nlmsghdr.nlmsg_flags = + nlmsg->nlmsghdr->nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL|NLM_F_ACK; - nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK; + nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK; + + ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg)); + ifi->ifi_family = AF_UNSPEC; nest = nla_begin_nested(nlmsg, IFLA_LINKINFO); if (!nest) @@ -1011,7 +998,7 @@ static int ip_addr_add(int family, int ifindex, { struct nl_handler nlh; struct nlmsg *nlmsg = NULL, *answer = NULL; - struct ip_req *ip_req; + struct ifaddrmsg *ifa; int addrlen; int err; @@ -1031,16 +1018,15 @@ static int ip_addr_add(int family, int ifindex, if (!answer) goto out; - ip_req = (struct ip_req *)nlmsg; - ip_req->nlmsg.nlmsghdr.nlmsg_len = - NLMSG_LENGTH(sizeof(struct ifaddrmsg)); - ip_req->nlmsg.nlmsghdr.nlmsg_flags = + nlmsg->nlmsghdr->nlmsg_flags = NLM_F_ACK|NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL; - ip_req->nlmsg.nlmsghdr.nlmsg_type = RTM_NEWADDR; - ip_req->ifa.ifa_prefixlen = prefix; - ip_req->ifa.ifa_index = ifindex; - ip_req->ifa.ifa_family = family; - ip_req->ifa.ifa_scope = 0; + nlmsg->nlmsghdr->nlmsg_type = RTM_NEWADDR; + + ifa = nlmsg_reserve(nlmsg, sizeof(struct ifaddrmsg)); + ifa->ifa_prefixlen = prefix; + ifa->ifa_index = ifindex; + ifa->ifa_family = family; + ifa->ifa_scope = 0; err = -EINVAL; if (nla_put_buffer(nlmsg, IFA_LOCAL, addr, addrlen)) @@ -1085,12 +1071,13 @@ int lxc_ipv4_addr_add(int ifindex, struct in_addr *addr, * address and stores that pointer in *res (so res should be an * in_addr** or in6_addr**). */ -static int ifa_get_local_ip(int family, struct ip_req *ip_info, void** res) { - struct rtattr *rta = IFA_RTA(&ip_info->ifa); - int attr_len = IFA_PAYLOAD(&ip_info->nlmsg.nlmsghdr); +static int ifa_get_local_ip(int family, struct nlmsghdr *msg, void** res) { + struct ifaddrmsg *ifa = NLMSG_DATA(msg); + struct rtattr *rta = IFA_RTA(ifa); + int attr_len = NLMSG_PAYLOAD(msg, sizeof(struct ifaddrmsg)); int addrlen; - if (ip_info->ifa.ifa_family != family) + if (ifa->ifa_family != family) return 0; addrlen = family == AF_INET ? sizeof(struct in_addr) : @@ -1129,7 +1116,7 @@ static int ip_addr_get(int family, int ifindex, void **res) { struct nl_handler nlh; struct nlmsg *nlmsg = NULL, *answer = NULL; - struct ip_req *ip_req, *ip_info; + struct ifaddrmsg *ifa; struct nlmsghdr *msg; int err; int recv_len = 0, answer_len; @@ -1151,14 +1138,14 @@ static int ip_addr_get(int family, int ifindex, void **res) /* Save the answer buffer length, since it will be overwritten * on the first receive (and we might need to receive more than * once. */ - answer_len = answer->nlmsghdr.nlmsg_len; + nlmsg_reserve(answer, NLMSG_GOOD_SIZE); + answer_len = answer->nlmsghdr->nlmsg_len; + + nlmsg->nlmsghdr->nlmsg_flags = NLM_F_REQUEST|NLM_F_ROOT; + nlmsg->nlmsghdr->nlmsg_type = RTM_GETADDR; - ip_req = (struct ip_req *)nlmsg; - ip_req->nlmsg.nlmsghdr.nlmsg_len = - NLMSG_LENGTH(sizeof(struct ifaddrmsg)); - ip_req->nlmsg.nlmsghdr.nlmsg_flags = NLM_F_REQUEST|NLM_F_ROOT; - ip_req->nlmsg.nlmsghdr.nlmsg_type = RTM_GETADDR; - ip_req->ifa.ifa_family = family; + ifa = nlmsg_reserve(nlmsg, sizeof(struct ifaddrmsg)); + ifa->ifa_family = family; /* Send the request for addresses, which returns all addresses * on all interfaces. */ @@ -1169,7 +1156,7 @@ static int ip_addr_get(int family, int ifindex, void **res) do { /* Restore the answer buffer length, it might have been * overwritten by a previous receive. */ - answer->nlmsghdr.nlmsg_len = answer_len; + answer->nlmsghdr->nlmsg_len = answer_len; /* Get the (next) batch of reply messages */ err = netlink_rcv(&nlh, answer); @@ -1180,7 +1167,7 @@ static int ip_addr_get(int family, int ifindex, void **res) err = 0; /* Satisfy the typing for the netlink macros */ - msg = &answer->nlmsghdr; + msg = answer->nlmsghdr; while (NLMSG_OK(msg, recv_len)) { /* Stop reading if we see an error message */ @@ -1201,9 +1188,9 @@ static int ip_addr_get(int family, int ifindex, void **res) goto out; } - ip_info = (struct ip_req *)msg; - if (ip_info->ifa.ifa_index == ifindex) { - if (ifa_get_local_ip(family, ip_info, res) < 0) { + ifa = (struct ifaddrmsg *)NLMSG_DATA(msg); + if (ifa->ifa_index == ifindex) { + if (ifa_get_local_ip(family, msg, res) < 0) { err = -1; goto out; } @@ -1247,7 +1234,7 @@ static int ip_gateway_add(int family, int ifindex, void *gw) { struct nl_handler nlh; struct nlmsg *nlmsg = NULL, *answer = NULL; - struct rt_req *rt_req; + struct rtmsg *rt; int addrlen; int err; @@ -1267,19 +1254,18 @@ static int ip_gateway_add(int family, int ifindex, void *gw) if (!answer) goto out; - rt_req = (struct rt_req *)nlmsg; - rt_req->nlmsg.nlmsghdr.nlmsg_len = - NLMSG_LENGTH(sizeof(struct rtmsg)); - rt_req->nlmsg.nlmsghdr.nlmsg_flags = + nlmsg->nlmsghdr->nlmsg_flags = NLM_F_ACK|NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL; - rt_req->nlmsg.nlmsghdr.nlmsg_type = RTM_NEWROUTE; - rt_req->rt.rtm_family = family; - rt_req->rt.rtm_table = RT_TABLE_MAIN; - rt_req->rt.rtm_scope = RT_SCOPE_UNIVERSE; - rt_req->rt.rtm_protocol = RTPROT_BOOT; - rt_req->rt.rtm_type = RTN_UNICAST; + nlmsg->nlmsghdr->nlmsg_type = RTM_NEWROUTE; + + rt = nlmsg_reserve(nlmsg, sizeof(struct rtmsg)); + rt->rtm_family = family; + rt->rtm_table = RT_TABLE_MAIN; + rt->rtm_scope = RT_SCOPE_UNIVERSE; + rt->rtm_protocol = RTPROT_BOOT; + rt->rtm_type = RTN_UNICAST; /* "default" destination */ - rt_req->rt.rtm_dst_len = 0; + rt->rtm_dst_len = 0; err = -EINVAL; if (nla_put_buffer(nlmsg, RTA_GATEWAY, gw, addrlen)) @@ -1312,7 +1298,7 @@ static int ip_route_dest_add(int family, int ifindex, void *dest) { struct nl_handler nlh; struct nlmsg *nlmsg = NULL, *answer = NULL; - struct rt_req *rt_req; + struct rtmsg *rt; int addrlen; int err; @@ -1332,18 +1318,17 @@ static int ip_route_dest_add(int family, int ifindex, void *dest) if (!answer) goto out; - rt_req = (struct rt_req *)nlmsg; - rt_req->nlmsg.nlmsghdr.nlmsg_len = - NLMSG_LENGTH(sizeof(struct rtmsg)); - rt_req->nlmsg.nlmsghdr.nlmsg_flags = + nlmsg->nlmsghdr->nlmsg_flags = NLM_F_ACK|NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL; - rt_req->nlmsg.nlmsghdr.nlmsg_type = RTM_NEWROUTE; - rt_req->rt.rtm_family = family; - rt_req->rt.rtm_table = RT_TABLE_MAIN; - rt_req->rt.rtm_scope = RT_SCOPE_LINK; - rt_req->rt.rtm_protocol = RTPROT_BOOT; - rt_req->rt.rtm_type = RTN_UNICAST; - rt_req->rt.rtm_dst_len = addrlen*8; + nlmsg->nlmsghdr->nlmsg_type = RTM_NEWROUTE; + + rt = nlmsg_reserve(nlmsg, sizeof(struct rtmsg)); + rt->rtm_family = family; + rt->rtm_table = RT_TABLE_MAIN; + rt->rtm_scope = RT_SCOPE_LINK; + rt->rtm_protocol = RTPROT_BOOT; + rt->rtm_type = RTN_UNICAST; + rt->rtm_dst_len = addrlen*8; err = -EINVAL; if (nla_put_buffer(nlmsg, RTA_DST, dest, addrlen)) diff --git a/src/lxc/nl.c b/src/lxc/nl.c index 132a907f77..40e616d678 100644 --- a/src/lxc/nl.c +++ b/src/lxc/nl.c @@ -37,7 +37,7 @@ extern size_t nlmsg_len(const struct nlmsg *nlmsg) { - return nlmsg->nlmsghdr.nlmsg_len - NLMSG_HDRLEN; + return nlmsg->nlmsghdr->nlmsg_len - NLMSG_HDRLEN; } extern void *nlmsg_data(struct nlmsg *nlmsg) @@ -53,13 +53,16 @@ static int nla_put(struct nlmsg *nlmsg, int attr, { struct rtattr *rta; size_t rtalen = RTA_LENGTH(len); + size_t tlen = NLMSG_ALIGN(nlmsg->nlmsghdr->nlmsg_len) + RTA_ALIGN(rtalen); - rta = NLMSG_TAIL(&nlmsg->nlmsghdr); - rta->rta_type = attr; - rta->rta_len = rtalen; - memcpy(RTA_DATA(rta), data, len); - nlmsg->nlmsghdr.nlmsg_len = - NLMSG_ALIGN(nlmsg->nlmsghdr.nlmsg_len) + RTA_ALIGN(rtalen); + if (tlen > nlmsg->cap) + return -ENOMEM; + + rta = NLMSG_TAIL(nlmsg->nlmsghdr); + rta->rta_type = attr; + rta->rta_len = rtalen; + memcpy(RTA_DATA(rta), data, len); + nlmsg->nlmsghdr->nlmsg_len = tlen; return 0; } @@ -91,7 +94,7 @@ extern int nla_put_attr(struct nlmsg *nlmsg, int attr) struct rtattr *nla_begin_nested(struct nlmsg *nlmsg, int attr) { - struct rtattr *rtattr = NLMSG_TAIL(&nlmsg->nlmsghdr); + struct rtattr *rtattr = NLMSG_TAIL(nlmsg->nlmsghdr); if (nla_put_attr(nlmsg, attr)) return NULL; @@ -101,7 +104,7 @@ struct rtattr *nla_begin_nested(struct nlmsg *nlmsg, int attr) void nla_end_nested(struct nlmsg *nlmsg, struct rtattr *attr) { - attr->rta_len = (void *)NLMSG_TAIL(&nlmsg->nlmsghdr) - (void *)attr; + attr->rta_len = (void *)NLMSG_TAIL(nlmsg->nlmsghdr) - (void *)attr; } extern struct nlmsg *nlmsg_alloc(size_t size) @@ -109,18 +112,48 @@ extern struct nlmsg *nlmsg_alloc(size_t size) struct nlmsg *nlmsg; size_t len = NLMSG_HDRLEN + NLMSG_ALIGN(size); - nlmsg = (struct nlmsg *)malloc(len); + nlmsg = (struct nlmsg *)malloc(sizeof(struct nlmsg)); if (!nlmsg) return NULL; - memset(nlmsg, 0, len); - nlmsg->nlmsghdr.nlmsg_len = NLMSG_HDRLEN; + nlmsg->nlmsghdr = (struct nlmsghdr *)malloc(len); + if (!nlmsg->nlmsghdr) + goto errout; + + memset(nlmsg->nlmsghdr, 0, len); + nlmsg->cap = len; + nlmsg->nlmsghdr->nlmsg_len = NLMSG_HDRLEN; return nlmsg; +errout: + free(nlmsg); + return NULL; +} + +extern void *nlmsg_reserve(struct nlmsg *nlmsg, size_t len) +{ + void *buf; + size_t nlmsg_len = nlmsg->nlmsghdr->nlmsg_len; + size_t tlen = NLMSG_ALIGN(len); + + if (nlmsg_len + tlen > nlmsg->cap) + return NULL; + + buf = nlmsg->nlmsghdr + nlmsg_len; + nlmsg->nlmsghdr->nlmsg_len += tlen; + + if (tlen > len) + memset(buf + len, 0, tlen - len); + + return buf; } extern void nlmsg_free(struct nlmsg *nlmsg) { + if (!nlmsg) + return; + + free(nlmsg->nlmsghdr); free(nlmsg); } @@ -130,7 +163,7 @@ extern int netlink_rcv(struct nl_handler *handler, struct nlmsg *answer) struct sockaddr_nl nladdr; struct iovec iov = { .iov_base = answer, - .iov_len = answer->nlmsghdr.nlmsg_len, + .iov_len = answer->nlmsghdr->nlmsg_len, }; struct msghdr msg = { @@ -157,7 +190,7 @@ extern int netlink_rcv(struct nl_handler *handler, struct nlmsg *answer) return 0; if (msg.msg_flags & MSG_TRUNC && - ret == answer->nlmsghdr.nlmsg_len) + ret == answer->nlmsghdr->nlmsg_len) return -EMSGSIZE; return ret; @@ -168,7 +201,7 @@ extern int netlink_send(struct nl_handler *handler, struct nlmsg *nlmsg) struct sockaddr_nl nladdr; struct iovec iov = { .iov_base = (void*)nlmsg, - .iov_len = nlmsg->nlmsghdr.nlmsg_len, + .iov_len = nlmsg->nlmsghdr->nlmsg_len, }; struct msghdr msg = { .msg_name = &nladdr, @@ -206,7 +239,7 @@ extern int netlink_transaction(struct nl_handler *handler, if (ret < 0) return ret; - if (answer->nlmsghdr.nlmsg_type == NLMSG_ERROR) { + if (answer->nlmsghdr->nlmsg_type == NLMSG_ERROR) { struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(answer); return err->error; } diff --git a/src/lxc/nl.h b/src/lxc/nl.h index 8e737fc8b3..534b1b6775 100644 --- a/src/lxc/nl.h +++ b/src/lxc/nl.h @@ -53,14 +53,16 @@ struct nl_handler { }; /* - * struct nlmsg : the netlink message structure, it consists just - * on a definition for a nlmsghdr. This message is to be used to + * struct nlmsg : the netlink message structure. This message is to be used to * be allocated with netlink_alloc. - * @nlmsghdr : a pointer to a netlink message header, this field - * _must_ be always the first field of this structure + * + * @nlmsghdr: a pointer to a netlink message header + * @cap: capacity of the netlink message, this is the initially allocated size + * and later operations (e.g. reserve and put) can not exceed this limit. */ struct nlmsg { - struct nlmsghdr nlmsghdr; + struct nlmsghdr *nlmsghdr; + ssize_t cap; }; /* @@ -219,6 +221,16 @@ void nla_end_nested(struct nlmsg *nlmsg, struct rtattr *attr); */ struct nlmsg *nlmsg_alloc(size_t size); +/* + * Reserve room for additional data at the tail of a netlink message + * + * @nlmsg: the netlink message + * @len: length of additional data to reserve room for + * + * Returns a pointer to newly reserved room or NULL + */ +void *nlmsg_reserve(struct nlmsg *nlmsg, size_t len); + /* * nlmsg_free : free a previously allocate message *