Exemple #1
0
int lxc_netdev_delete_by_index(int ifindex)
{
	struct nl_handler nlh;
	struct nlmsg *nlmsg = NULL, *answer = NULL;
	struct link_req *link_req;
	int err;

	err = netlink_open(&nlh, NETLINK_ROUTE);
	if (err)
		return err;

	err = -ENOMEM;
	nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
	if (!nlmsg)
		goto out;

	answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
	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;

	err = netlink_transaction(&nlh, nlmsg, answer);
out:
	netlink_close(&nlh);
	nlmsg_free(answer);
	nlmsg_free(nlmsg);
	return err;
}
Exemple #2
0
static int
ip_addr_add(int family, int ifindex,
		       void *addr, void *bcast, void *acast, int prefix) {
	struct nl_handler nlh;
	struct nlmsg *nlmsg = NULL, *answer = NULL;
	struct ip_req *ip_req;
	int addrlen;
	int err;

	addrlen = family == AF_INET ? sizeof(struct in_addr) :
		sizeof(struct in6_addr);

	err = netlink_open(&nlh, NETLINK_ROUTE);
	if (err)
		return err;

	err = -ENOMEM;
	nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
	if (!nlmsg)
		goto out;

	answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
	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 =
		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;

	err = -EINVAL;
	if (nla_put_buffer(nlmsg, IFA_LOCAL, addr, addrlen))
		goto out;

	if (nla_put_buffer(nlmsg, IFA_ADDRESS, addr, addrlen))
		goto out;

	if (nla_put_buffer(nlmsg, IFA_BROADCAST, bcast, addrlen))
		goto out;

	/* TODO : multicast, anycast with ipv6 */
	err = -EPROTONOSUPPORT;
	if (family == AF_INET6 &&
	    (memcmp(bcast, &in6addr_any, sizeof(in6addr_any)) ||
	     memcmp(acast, &in6addr_any, sizeof(in6addr_any))))
		goto out;

	err = netlink_transaction(&nlh, nlmsg, answer);
out:
	netlink_close(&nlh);
	nlmsg_free(answer);
	nlmsg_free(nlmsg);
	return err;
}
Exemple #3
0
extern int genetlink_open(struct genl_handler *handler, const char *family)
{
	int ret;
	handler->family = genetlink_resolve_family(family);
	if (handler->family < 0)
		return handler->family;

	ret = netlink_open(&handler->nlh, NETLINK_GENERIC);

	return ret;
}
Exemple #4
0
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;
	int addrlen;
	int err;

	addrlen = family == AF_INET ? sizeof(struct in_addr) :
		sizeof(struct in6_addr);

	err = netlink_open(&nlh, NETLINK_ROUTE);
	if (err)
		return err;

	err = -ENOMEM;
	nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
	if (!nlmsg)
		goto out;

	answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
	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 =
		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;
	/* "default" destination */
	rt_req->rt.rtm_dst_len = 0;

	err = -EINVAL;
	if (nla_put_buffer(nlmsg, RTA_GATEWAY, gw, addrlen))
		goto out;

	/* Adding the interface index enables the use of link-local
	 * addresses for the gateway */
	if (nla_put_u32(nlmsg, RTA_OIF, ifindex))
		goto out;

	err = netlink_transaction(&nlh, nlmsg, answer);
out:
	netlink_close(&nlh);
	nlmsg_free(answer);
	nlmsg_free(nlmsg);
	return err;
}
Exemple #5
0
int lxc_device_rename(const char *oldname, const char *newname)
{
	struct nl_handler nlh;
	struct nlmsg *nlmsg = NULL, *answer = NULL;
	struct link_req *link_req;
	int index, len, err = -1;

	if (netlink_open(&nlh, NETLINK_ROUTE))
		return -1;

	len = strlen(oldname);
	if (len == 1 || len > IFNAMSIZ)
		goto out;

	len = strlen(newname);
	if (len == 1 || len > IFNAMSIZ)
		goto out;

	nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
	if (!nlmsg)
		goto out;

	answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
	if (!answer)
		goto out;

	index = if_nametoindex(oldname);
	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_ACK|NLM_F_REQUEST;
	nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK;

	if (nla_put_string(nlmsg, IFLA_IFNAME, newname))
		goto out;

	if (netlink_transaction(&nlh, nlmsg, answer))
		goto out;

	err = 0;
out:
	netlink_close(&nlh);
	nlmsg_free(answer);
	nlmsg_free(nlmsg);
	return err;
}
Exemple #6
0
static int netdev_set_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;

	err = netlink_open(&nlh, NETLINK_ROUTE);
	if (err)
		return err;

	err = -EINVAL;
	len = strlen(name);
	if (len == 1 || len >= IFNAMSIZ)
		goto out;

	err = -ENOMEM;
	nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
	if (!nlmsg)
		goto out;

	answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
	if (!answer)
		goto out;

	err = -EINVAL;
	index = if_nametoindex(name);
	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;

	err = netlink_transaction(&nlh, nlmsg, answer);
out:
	netlink_close(&nlh);
	nlmsg_free(nlmsg);
	nlmsg_free(answer);
	return err;
}
Exemple #7
0
int lxc_netdev_move_by_index(int ifindex, pid_t pid, const char* ifname)
{
	struct nl_handler nlh;
	struct nlmsg *nlmsg = NULL;
	struct ifinfomsg *ifi;
	int err;

	err = netlink_open(&nlh, NETLINK_ROUTE);
	if (err)
		return err;

	err = -ENOMEM;
	nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
	if (!nlmsg)
		goto out;

	nlmsg->nlmsghdr->nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
	nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK;

	ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg));
	if (!ifi)
		goto out;
	ifi->ifi_family = AF_UNSPEC;
	ifi->ifi_index = ifindex;

	if (nla_put_u32(nlmsg, IFLA_NET_NS_PID, pid))
		goto out;

	if (ifname != NULL) {
		if (nla_put_string(nlmsg, IFLA_IFNAME, ifname))
			goto out;
	}

	err = netlink_transaction(&nlh, nlmsg, nlmsg);
out:
	netlink_close(&nlh);
	nlmsg_free(nlmsg);
	return err;
}
Exemple #8
0
int lxc_netdev_move(char *ifname, pid_t pid)
{
	struct nl_handler nlh;
	struct nlmsg *nlmsg = NULL;
	struct link_req *link_req;
	int err, index;

	index = if_nametoindex(ifname);
	if (!ifname)
		return -EINVAL;

	err = netlink_open(&nlh, NETLINK_ROUTE);
	if (err)
		return err;

	err = -ENOMEM;
	nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
	if (!nlmsg)
		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;

	if (nla_put_u32(nlmsg, IFLA_NET_NS_PID, pid))
		goto out;

	err = netlink_transaction(&nlh, nlmsg, nlmsg);
out:
	netlink_close(&nlh);
	nlmsg_free(nlmsg);
	return err;
}
Exemple #9
0
Fichier : rtnl.c Projet : d4s/lxc
extern int rtnetlink_open(struct rtnl_handler *handler)
{
	return netlink_open(&handler->nlh, NETLINK_ROUTE);
}
Exemple #10
0
static int genetlink_resolve_family(const char *family)
{
	struct nl_handler handler;
	struct nlattr *attr;
	struct genlmsg *request, *reply;
	struct genlmsghdr *genlmsghdr;

	int len, ret;

	request = genlmsg_alloc(GENLMSG_GOOD_SIZE);
	if (!request)
		return -ENOMEM;
		
	reply = genlmsg_alloc(GENLMSG_GOOD_SIZE);
	if (!reply) {
		genlmsg_free(request);
		return -ENOMEM;
	}

	request->nlmsghdr.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
	request->nlmsghdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
        request->nlmsghdr.nlmsg_type = GENL_ID_CTRL;

	genlmsghdr = NLMSG_DATA(&request->nlmsghdr);
        genlmsghdr->cmd = CTRL_CMD_GETFAMILY;

	ret = netlink_open(&handler, NETLINK_GENERIC);
	if (ret)
		goto out;

	ret = nla_put_string((struct nlmsg *)&request->nlmsghdr,
			     CTRL_ATTR_FAMILY_NAME, family);
	if (ret)
		goto out_close;

	ret = netlink_transaction(&handler, (struct nlmsg *)&request->nlmsghdr,
				  (struct nlmsg *)&reply->nlmsghdr);
	if (ret < 0)
		goto out_close;

	genlmsghdr = NLMSG_DATA(&reply->nlmsghdr);
	len = reply->nlmsghdr.nlmsg_len;

	ret = -ENOMSG;
	if (reply->nlmsghdr.nlmsg_type !=  GENL_ID_CTRL)
		goto out_close;

	if (genlmsghdr->cmd != CTRL_CMD_NEWFAMILY)
		goto out_close;

	ret = -EMSGSIZE;
	len -= NLMSG_LENGTH(GENL_HDRLEN);
	if (len < 0)
		goto out_close;
	
	attr = (struct nlattr *)GENLMSG_DATA(reply);
	attr = (struct nlattr *)((char *)attr + NLA_ALIGN(attr->nla_len));
	
	ret = -ENOMSG;
	if (attr->nla_type != CTRL_ATTR_FAMILY_ID)
		goto out_close;

	ret =  *(__u16 *) NLA_DATA(attr);
out_close:
	netlink_close(&handler);
out:
	genlmsg_free(request);
	genlmsg_free(reply);
	return ret;
}
Exemple #11
0
int scim_port_wake(scim_root_t _root)
{
	int index;
	int netlink;
	int result = -1;
	char name[IFNAMSIZ];
	scim_lane_t lane;
	scim_port_data_t port;

	if((netlink = netlink_open()) < 0) {
		fprintf(stderr, "%s: netlink_open: %m\n", __func__);
		return -1;
	}

	if(scim_port_list(port) < 0) {
		goto done;
	}

	for(scim_port_list_t list = port->list; **list; list++) {
		scim_port_item_t info = *list;

		snprintf(name, sizeof(name), "%s",  info[_PORT_NAME]);

		if(strcmp(name, "lo") && strncmp(name + 3, "bone", 4) && strncmp(name + 3, "port", 4)) {
			continue;
		}

		if(!sscanf(info[_PORT_INDEX], "%d", &index)) {
			errno = EINVAL;
			fprintf(stderr, "%s: port->info[_PORT_INDEX]: %m\n", __func__);
			goto done;
		}

		if(name[2] && !strncmp(name + 3, "port", 4)) {
			if(isdigit(name[7])) {
				name[7] = '\0';

				if(netlink_link_rename(netlink, name, index) < 0) {
					fprintf(stderr, "%s: netlink_link_rename %s to %s: %m\n", __func__, info[_PORT_NAME], name);
					goto done;
				}
			}

			for(lane = __lane; *lane->name && strncmp(lane->name, name, 3); lane++);

			if(*lane->name && lane->base) {
				uint32_t mask = ((uint32_t)0xffffffffU << lane->size) >> lane->size;

				uint32_t address = htonl(lane->base|(_root->task->cell->code + 1));

				uint32_t broadcast = htonl(lane->base|mask);

				if(netlink_address_four_create(netlink, index, address, broadcast, lane->size, 0) < 0) {
					if(errno != EEXIST) {
						fprintf(stderr, "%s: netlink_address_four_create: %s, %08x: %m\n", __func__, name, address);
						goto done;
					}
				}
			}
		}

		netlink_link_change(netlink, index, IFF_UP, IFF_UP);
	}
Exemple #12
0
int scim_port_make(scim_task_t _task)
{
	int index;
	int netlink;
	int result = -1;
	char name[IFNAMSIZ];
	unsigned char mac[6] = {};
	scim_port_data_t port;
	scim_port_data_t link;

	scim_port_wipe(link);
	scim_port_head(link);

	if((netlink = netlink_open()) < 0) {
		return -1;
	}

	if(scim_port_list(port) < 0) {
		return -1;
	}

	mac[0] = 0x02;
	mac[5] = _task->cell->code + 1;

	for(scim_lane_t* lane = *_task->cell->lanes; *lane; lane++) {
		snprintf(name, sizeof(name), "%sbone", (*lane)->name);

		if(scim_port_pick(port, _PORT_NAME, name) < 0) {
			goto done;
		}
	
		sscanf(port->info[_PORT_INDEX], "%d", &index);

		if(_task->form == __form_cell) {
			snprintf(name, sizeof(name), "%sport%d", (*lane)->name, _task->cell->code);
		}
		else {
			snprintf(name, sizeof(name), "%sport", (*lane)->name);
		}

		if((netlink_macvlan_create(netlink, name, mac, index, MACVLAN_MODE_BRIDGE)) < 0 && errno != EEXIST) {
			fprintf(stderr, "%s: netlink_macvlan_create: %m\n", __func__);
			goto done;
		}
	
		if(scim_port_read(link, name) < 0) {
			goto done;
		}

		sscanf(link->info[_PORT_INDEX], "%d", &index);

		if(_task->form == __form_cell) {
			if(netlink_link_move(netlink, index, _task->stat->pawn) < 0) {
				fprintf(stderr, "%s: netlink_link_move: %s to %d: %m\n", __func__, name, _task->stat->pawn);
			}
		}
	}

	result = 0;
	done:
	close(netlink);
	return result;
}
Exemple #13
0
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 rtattr *nest1, *nest2, *nest3;
	int len, err;

	err = netlink_open(&nlh, NETLINK_ROUTE);
	if (err)
		return err;

	err = -EINVAL;
	len = strlen(name1);
	if (len == 1 || len >= IFNAMSIZ)
		goto out;

	len = strlen(name2);
	if (len == 1 || len >= IFNAMSIZ)
		goto out;

	err = -ENOMEM;
	nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
	if (!nlmsg)
		goto out;

	answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
	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 =
		NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL|NLM_F_ACK;
	nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK;

	err = -EINVAL;
	nest1 = nla_begin_nested(nlmsg, IFLA_LINKINFO);
	if (!nest1)
		goto out;

	if (nla_put_string(nlmsg, IFLA_INFO_KIND, "veth"))
		goto out;

	nest2 = nla_begin_nested(nlmsg, IFLA_INFO_DATA);
	if (!nest2)
		goto out;

	nest3 = nla_begin_nested(nlmsg, VETH_INFO_PEER);
	if (!nest3)
		goto out;

	nlmsg->nlmsghdr.nlmsg_len += sizeof(struct ifinfomsg);

	if (nla_put_string(nlmsg, IFLA_IFNAME, name2))
		goto out;

	nla_end_nested(nlmsg, nest3);

	nla_end_nested(nlmsg, nest2);

	nla_end_nested(nlmsg, nest1);

	if (nla_put_string(nlmsg, IFLA_IFNAME, name1))
		goto out;

	err = netlink_transaction(&nlh, nlmsg, answer);
out:
	netlink_close(&nlh);
	nlmsg_free(answer);
	nlmsg_free(nlmsg);
	return err;
}
Exemple #14
0
static int netlink_receive(struct netlink_fd *fd, struct nlmsghdr *reply)
{
	struct sockaddr_nl nladdr;
	struct iovec iov;
	struct msghdr msg = {
		.msg_name = &nladdr,
		.msg_namelen = sizeof(nladdr),
		.msg_iov = &iov,
		.msg_iovlen = 1,
	};
	int got_reply = FALSE, len;
	char buf[16*1024];

	iov.iov_base = buf;
	while (!got_reply) {
		int status;
		struct nlmsghdr *h;

		iov.iov_len = sizeof(buf);
		status = recvmsg(fd->fd, &msg, MSG_DONTWAIT);
		if (status < 0) {
			if (errno == EINTR)
				continue;
			if (errno == EAGAIN)
				return reply == NULL;
			fprintf(stderr, "Netlink overrun\n");
			continue;
		}

		if (status == 0) {
			fprintf(stderr, "Netlink returned EOF\n");
			return FALSE;
		}

		h = (struct nlmsghdr *) buf;
		while (NLMSG_OK(h, status)) {
			if (reply != NULL &&
			    h->nlmsg_seq == reply->nlmsg_seq) {
				len = h->nlmsg_len;
				if (len > reply->nlmsg_len) {
					fprintf(stderr, "Netlink message "
						"truncated\n");
					len = reply->nlmsg_len;
				}
				memcpy(reply, h, len);
				got_reply = TRUE;
			} else if (h->nlmsg_type != NLMSG_DONE) {
				fprintf(stderr,
					"Unknown NLmsg: 0x%08x, len %d\n",
					h->nlmsg_type, h->nlmsg_len);
			}
			h = NLMSG_NEXT(h, status);
		}
	}

	return TRUE;
}

static int netlink_send(struct netlink_fd *fd, struct nlmsghdr *req)
{
	struct sockaddr_nl nladdr;
	struct iovec iov = {
		.iov_base = (void*) req,
		.iov_len = req->nlmsg_len
	};
	struct msghdr msg = {
		.msg_name = &nladdr,
		.msg_namelen = sizeof(nladdr),
		.msg_iov = &iov,
		.msg_iovlen = 1,
	};
	int status;

	memset(&nladdr, 0, sizeof(nladdr));
	nladdr.nl_family = AF_NETLINK;

	req->nlmsg_seq = ++fd->seq;

	status = sendmsg(fd->fd, &msg, 0);
	if (status < 0) {
		fprintf(stderr, "Cannot talk to rtnetlink\n");
		return FALSE;
	}
	return TRUE;
}

static int netlink_talk(struct nlmsghdr *req, size_t replysize,
			struct nlmsghdr *reply)
{
	struct netlink_fd fd;
	int ret = FALSE;

	if (!netlink_open(&fd))
		return FALSE;

	if (reply == NULL)
		req->nlmsg_flags |= NLM_F_ACK;

	if (!netlink_send(&fd, req))
		goto out;

	if (reply != NULL) {
		reply->nlmsg_len = replysize;
		ret = netlink_receive(&fd, reply);
	} else {
		ret = TRUE;
	}
out:
	netlink_close(&fd);
	return ret;
}

int netlink_route_get(struct sockaddr *dst, u_int16_t *mtu, char *ifname)
{
	struct {
		struct nlmsghdr 	n;
		union {
			struct rtmsg		r;
			struct ifinfomsg	i;
		};
		char   			buf[1024];
	} req;
	struct rtmsg *r = NLMSG_DATA(&req.n);
	struct rtattr *rta[RTA_MAX+1];
	struct rtattr *rtax[RTAX_MAX+1];
	struct rtattr *ifla[IFLA_MAX+1];
	int index;

	memset(&req, 0, sizeof(req));
	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
	req.n.nlmsg_flags = NLM_F_REQUEST;
	req.n.nlmsg_type = RTM_GETROUTE;
	req.r.rtm_family = dst->sa_family;

	netlink_add_rtaddr_l(&req.n, sizeof(req), RTA_DST, dst);
	req.r.rtm_dst_len = 32;

	if (!netlink_talk(&req.n, sizeof(req), &req.n))
		return FALSE;

	netlink_parse_rtattr(rta, RTA_MAX, RTM_RTA(r),
			     RTM_PAYLOAD(&req.n));

	if (mtu != NULL) {
		if (rta[RTA_METRICS] == NULL)
			return FALSE;

		netlink_parse_rtattr(rtax, RTAX_MAX,
				     RTA_DATA(rta[RTA_METRICS]),
				     RTA_PAYLOAD(rta[RTA_METRICS]));
		if (rtax[RTAX_MTU] == NULL)
			return FALSE;

		*mtu = *(int*) RTA_DATA(rtax[RTAX_MTU]);
	}

	if (ifname != NULL) {
		if (rta[RTA_OIF] == NULL)
			return FALSE;

		index = *(int*) RTA_DATA(rta[RTA_OIF]);

		memset(&req, 0, sizeof(req));
		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 = index;
		if (!netlink_talk(&req.n, sizeof(req), &req.n))
			return FALSE;

		netlink_parse_rtattr(ifla, IFLA_MAX, IFLA_RTA(r),
				     IFLA_PAYLOAD(&req.n));
		if (ifla[IFLA_IFNAME] == NULL)
			return FALSE;

		memcpy(ifname, RTA_DATA(ifla[IFLA_IFNAME]),
		       RTA_PAYLOAD(ifla[IFLA_IFNAME]));
	}

	return TRUE;
}
int ifplugd_main(int argc UNUSED_PARAM, char **argv)
{
    int iface_status;
    int delay_time;
    const char *iface_status_str;
    struct pollfd netlink_pollfd[1];
    unsigned opts;
#if ENABLE_FEATURE_PIDFILE
    char *pidfile_name;
    pid_t pid_from_pidfile;
#endif

    INIT_G();

    opt_complementary = "t+:u+:d+";
    opts = getopt32(argv, OPTION_STR,
                    &G.iface, &G.script_name, &G.poll_time, &G.delay_up,
                    &G.delay_down, &G.api_mode, &G.extra_arg);
    G.poll_time *= 1000;

    applet_name = xasprintf("ifplugd(%s)", G.iface);

#if ENABLE_FEATURE_PIDFILE
    pidfile_name = xasprintf(_PATH_VARRUN"ifplugd.%s.pid", G.iface);
    pid_from_pidfile = read_pid(pidfile_name);

    if (opts & FLAG_KILL) {
        if (pid_from_pidfile > 0)
            kill(pid_from_pidfile, SIGQUIT);
        return EXIT_SUCCESS;
    }

    if (pid_from_pidfile > 0 && kill(pid_from_pidfile, 0) == 0)
        bb_error_msg_and_die("daemon already running");
#endif

    switch (G.api_mode[0]) {
    case API_AUTO:
        G.detect_link_func = detect_link_auto;
        break;
    case API_ETHTOOL:
        G.detect_link_func = detect_link_ethtool;
        break;
    case API_MII:
        G.detect_link_func = detect_link_mii;
        break;
    case API_PRIVATE:
        G.detect_link_func = detect_link_priv;
        break;
    case API_WLAN:
        G.detect_link_func = detect_link_wlan;
        break;
    case API_IFF:
        G.detect_link_func = detect_link_iff;
        break;
    default:
        bb_error_msg_and_die("unknown API mode '%s'", G.api_mode);
    }

    if (!(opts & FLAG_NO_DAEMON))
        bb_daemonize_or_rexec(DAEMON_CHDIR_ROOT, argv);

    xmove_fd(xsocket(AF_INET, SOCK_DGRAM, 0), ioctl_fd);
    if (opts & FLAG_MONITOR) {
        xmove_fd(netlink_open(), netlink_fd);
    }

    write_pidfile(pidfile_name);

    /* this can't be moved before socket creation */
    if (!(opts & FLAG_NO_SYSLOG)) {
        openlog(applet_name, 0, LOG_DAEMON);
        logmode |= LOGMODE_SYSLOG;
    }

    bb_signals(0
               | (1 << SIGINT )
               | (1 << SIGTERM)
               | (1 << SIGQUIT)
               | (1 << SIGHUP ) /* why we ignore it? */
               /* | (1 << SIGCHLD) - run_script does not use it anymore */
               , record_signo);

    bb_error_msg("started: %s", bb_banner);

    if (opts & FLAG_MONITOR) {
        struct ifreq ifrequest;
        set_ifreq_to_ifname(&ifrequest);
        G.iface_exists = (network_ioctl(SIOCGIFINDEX, &ifrequest, NULL) == 0);
    }

    if (G.iface_exists)
        maybe_up_new_iface();

    iface_status = detect_link();
    if (iface_status == IFSTATUS_ERR)
        goto exiting;
    iface_status_str = strstatus(iface_status);

    if (opts & FLAG_MONITOR) {
        bb_error_msg("interface %s",
                     G.iface_exists ? "exists"
                     : "doesn't exist, waiting");
    }
    /* else we assume it always exists, but don't mislead user
     * by potentially lying that it really exists */

    if (G.iface_exists) {
        bb_error_msg("link is %s", iface_status_str);
    }

    if ((!(opts & FLAG_NO_STARTUP)
            && iface_status == IFSTATUS_UP
        )
            || (opts & FLAG_INITIAL_DOWN)
       ) {
        if (run_script(iface_status_str) != 0)
            goto exiting;
    }

    /* Main loop */
    netlink_pollfd[0].fd = netlink_fd;
    netlink_pollfd[0].events = POLLIN;
    delay_time = 0;
    while (1) {
        int iface_status_old;
        int iface_exists_old;

        switch (bb_got_signal) {
        case SIGINT:
        case SIGTERM:
            bb_got_signal = 0;
            goto cleanup;
        case SIGQUIT:
            bb_got_signal = 0;
            goto exiting;
        default:
            bb_got_signal = 0;
            break;
        }

        if (poll(netlink_pollfd,
                 (opts & FLAG_MONITOR) ? 1 : 0,
                 G.poll_time
                ) < 0
           ) {
            if (errno == EINTR)
                continue;
            bb_perror_msg("poll");
            goto exiting;
        }

        iface_status_old = iface_status;
        iface_exists_old = G.iface_exists;

        if ((opts & FLAG_MONITOR)
                && (netlink_pollfd[0].revents & POLLIN)
           ) {
            G.iface_exists = check_existence_through_netlink();
            if (G.iface_exists < 0) /* error */
                goto exiting;
            if (iface_exists_old != G.iface_exists) {
                bb_error_msg("interface %sappeared",
                             G.iface_exists ? "" : "dis");
                if (G.iface_exists)
                    maybe_up_new_iface();
            }
        }

        /* note: if !G.iface_exists, returns DOWN */
        iface_status = detect_link();
        if (iface_status == IFSTATUS_ERR) {
            if (!(opts & FLAG_MONITOR))
                goto exiting;
            iface_status = IFSTATUS_DOWN;
        }
        iface_status_str = strstatus(iface_status);

        if (iface_status_old != iface_status) {
            bb_error_msg("link is %s", iface_status_str);

            if (delay_time) {
                /* link restored its old status before
                 * we run script. don't run the script: */
                delay_time = 0;
            } else {
                delay_time = monotonic_sec();
                if (iface_status == IFSTATUS_UP)
                    delay_time += G.delay_up;
                if (iface_status == IFSTATUS_DOWN)
                    delay_time += G.delay_down;
                if (delay_time == 0)
                    delay_time++;
            }
        }

        if (delay_time && (int)(monotonic_sec() - delay_time) >= 0) {
            delay_time = 0;
            if (run_script(iface_status_str) != 0)
                goto exiting;
        }
    } /* while (1) */

cleanup:
    if (!(opts & FLAG_NO_SHUTDOWN)
            && (iface_status == IFSTATUS_UP
                || (iface_status == IFSTATUS_DOWN && delay_time)
               )
       ) {
        setenv(IFPLUGD_ENV_PREVIOUS, strstatus(iface_status), 1);
        setenv(IFPLUGD_ENV_CURRENT, strstatus(-1), 1);
        run_script("down\0up"); /* reusing string */
    }

exiting:
    remove_pidfile(pidfile_name);
    bb_error_msg_and_die("exiting");
}