-struct rtnl_handle {
- int fd;
- struct sockaddr_nl local;
- struct sockaddr_nl peer;
- __u32 seq;
- __u32 dump;
-};
-
-static int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data)
-{
- int len = RTA_LENGTH(4);
- struct rtattr *rta;
- if (NLMSG_ALIGN(n->nlmsg_len) + len > (unsigned int)maxlen) {
- DBG("Error! max allowed bound %d exceeded", maxlen);
- return -1;
- }
- rta = NLMSG_TAIL(n);
- rta->rta_type = type;
- rta->rta_len = len;
- memcpy(RTA_DATA(rta), &data, 4);
- n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
-
- return 0;
-}
-
-static int addattr_l(struct nlmsghdr *n, int maxlen, int type,
- const void *data, int alen)
-{
- int len = RTA_LENGTH(alen);
- struct rtattr *rta;
-
- if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) >
- (unsigned int)maxlen) {
- DBG("addattr_l message exceeded bound of %d", maxlen);
- return -1;
- }
- rta = NLMSG_TAIL(n);
- rta->rta_type = type;
- rta->rta_len = len;
- memcpy(RTA_DATA(rta), data, alen);
- n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
-
- return 0;
-}
-
-static void rtnl_close(struct rtnl_handle *rth)
-{
- if (rth->fd >= 0) {
- close(rth->fd);
- rth->fd = -1;
- }
-}
-
-static int rtnl_open(struct rtnl_handle *rth)
-{
- socklen_t addr_len;
- int sndbuf = 1024;
-
- memset(rth, 0, sizeof(*rth));
-
- rth->fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
- if (rth->fd < 0) {
- connman_error("Can not open netlink socket: %s",
- strerror(errno));
- return -1;
- }
-
- if (setsockopt(rth->fd, SOL_SOCKET, SO_SNDBUF, &sndbuf,
- sizeof(sndbuf)) < 0) {
- connman_error("SO_SNDBUF: %s", strerror(errno));
- return -1;
- }
-
- memset(&rth->local, 0, sizeof(rth->local));
- rth->local.nl_family = AF_NETLINK;
- rth->local.nl_groups = 0;
-
- if (bind(rth->fd, (struct sockaddr *)&rth->local,
- sizeof(rth->local)) < 0) {
- connman_error("Can not bind netlink socket: %s",
- strerror(errno));
- return -1;
- }
- addr_len = sizeof(rth->local);
- if (getsockname(rth->fd, (struct sockaddr *)&rth->local,
- &addr_len) < 0) {
- connman_error("Can not getsockname: %s", strerror(errno));
- return -1;
- }
- if (addr_len != sizeof(rth->local)) {
- connman_error("Wrong address length %d", addr_len);
- return -1;
- }
- if (rth->local.nl_family != AF_NETLINK) {
- connman_error("Wrong address family %d", rth->local.nl_family);
- return -1;
- }
- rth->seq = time(NULL);
-
- return 0;
-}
-
-static int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n)
-{
- struct sockaddr_nl nladdr;
- struct iovec iov = {
- .iov_base = (void *)n,
- .iov_len = n->nlmsg_len
- };
- struct msghdr msg = {
- .msg_name = &nladdr,
- .msg_namelen = sizeof(nladdr),
- .msg_iov = &iov,
- .msg_iovlen = 1,
- };
- unsigned seq;
- int err;
-
- memset(&nladdr, 0, sizeof(nladdr));
- nladdr.nl_family = AF_NETLINK;
-
- n->nlmsg_seq = seq = ++rtnl->seq;
- n->nlmsg_flags |= NLM_F_ACK;
-
- err = sendmsg(rtnl->fd, &msg, 0);
- if (err < 0) {
- connman_error("Can not talk to rtnetlink");
- return err;
- }
-
- return 0;
-}
-