openwrt之dhcp客户端是如何设置端口ip地址的

dhcp协议就不在这里多介绍了,主要想说下dhcp客户端设置端口ip地址的流程。

客户端执行的命令是:(关于dhcp客户端如何被执行的可以参考上一篇文章)

root@BDCOM:~# ps -w | grep udh
 1761 root      1484 S    udhcpc -p /var/run/udhcpc-eth0.2.pid -s /lib/netifd/dhcp.script -f -t 0 -i eth0.2 -V 3830d84fd8bc77bf -C

 

udhcpc源码在busybox-1.23.0\networking\udhcp内

从udhcpc_main函数开始一直找到下面的函数

在REQUESTING状态接收到DHCPACK

udhcp_run_script(&packet, state == REQUESTING ? "bound" : "renew");
static void udhcp_run_script(struct dhcp_packet *packet, const char *name)
{
	char **envp, **curr;
	char *argv[3];

	envp = fill_envp(packet);//把需要设置的参数传入环境变量中
	/* call script */
	log1("Executing %s %s", client_config.script, name);
	argv[0] = (char*) client_config.script;
	argv[1] = (char*) name;
	argv[2] = NULL;
	spawn_and_wait(argv);

	for (curr = envp; *curr; curr++) {
		log2(" %s", *curr);
		bb_unsetenv_and_free(*curr);
	}
	free(envp);
}


在这里执行dhcp.script脚本,参数为bound或是renew

在脚本处调用的是setup_interface

case "$1" in
	deconfig)
		deconfig_interface
	;;
	renew|bound)
		setup_interface
	;;
esac


 

setup_interface () {
	proto_init_update "*" 1
	proto_add_ipv4_address "$ip" "${subnet:-255.255.255.0}"
	# TODO: apply $broadcast
	logger -t udhcpc "AP IP:\"$ip\" Mask:\"$subnet\""
	for i in $router; do
		proto_add_ipv4_route 0.0.0.0 0 "$i"
	done

	# CIDR STATIC ROUTES (rfc3442)
	[ -n "$staticroutes" ] && set_classless_routes $staticroutes
	[ -n "$msstaticroutes" ] && set_classless_routes $msstaticroutes

	for dns in $dns; do
		proto_add_dns_server "$dns"
	done
	for domain in $domain; do
		proto_add_dns_search "$domain"
	done

	proto_add_data
	[ -n "$ZONE" ] && json_add_string zone "$ZONE"
	proto_close_data

	proto_send_update "$INTERFACE"
...


 

proto_init_update() {
	local ifname="$1"
	local up="$2"
	local external="$3"

	PROTO_KEEP=0
	PROTO_INIT=1
	PROTO_TUNNEL_OPEN=
	PROTO_IPADDR=
	PROTO_IP6ADDR=
	PROTO_ROUTE=
	PROTO_ROUTE6=
	PROTO_PREFIX6=
	PROTO_DNS=
	PROTO_DNS_SEARCH=
	json_init
	json_add_int action 0
	[ -n "$ifname" -a "*" != "$ifname" ] && json_add_string "ifname" "$ifname"
	json_add_boolean "link-up" "$up"
	[ -n "$3" ] && json_add_boolean "address-external" "$external"
}


 

proto_send_update() {
	local interface="$1"

	proto_close_nested
	json_add_boolean keep "$PROTO_KEEP"
	_proto_push_array "ipaddr" "$PROTO_IPADDR" _proto_push_ipv4_addr
	_proto_push_array "ip6addr" "$PROTO_IP6ADDR" _proto_push_ipv6_addr
	_proto_push_array "routes" "$PROTO_ROUTE" _proto_push_route
	_proto_push_array "routes6" "$PROTO_ROUTE6" _proto_push_route
	_proto_push_array "ip6prefix" "$PROTO_PREFIX6" _proto_push_string
	_proto_push_array "dns" "$PROTO_DNS" _proto_push_string
	_proto_push_array "dns_search" "$PROTO_DNS_SEARCH" _proto_push_string
	_proto_notify "$interface"
}


_proto_notify() {
	local interface="$1"
	local options="$2"
	json_add_string "interface" "$interface"
	ubus $options call network.interface notify_proto "$(json_dump)"
}


调用ubus命令,找到netifd模块的ubus.c文件

static struct ubus_method iface_object_methods[] = {
	{ .name = "lds", .handler = netifd_handle_down },
	{ .name = "up", .handler = netifd_handle_up },
	{ .name = "down", .handler = netifd_handle_down },
	{ .name = "status", .handler = netifd_handle_status },
	{ .name = "prepare", .handler = netifd_handle_iface_prepare },
	{ .name = "dump", .handler = netifd_handle_dump },
	UBUS_METHOD("add_device", netifd_iface_handle_device, dev_link_policy ),
	UBUS_METHOD("remove_device", netifd_iface_handle_device, dev_link_policy ),
	{ .name = "notify_proto", .handler = netifd_iface_notify_proto },
	{ .name = "remove", .handler = netifd_iface_remove },
	{ .name = "set_data", .handler = netifd_handle_set_data },
};


 

static int
netifd_iface_notify_proto(struct ubus_context *ctx, struct ubus_object *obj,
			  struct ubus_request_data *req, const char *method,
			  struct blob_attr *msg)
{
	struct interface *iface;

	iface = container_of(obj, struct interface, ubus);

	if (!iface->proto || !iface->proto->notify)
		return UBUS_STATUS_NOT_SUPPORTED;

	return iface->proto->notify(iface->proto, msg);//proto_shell_notify
}


 

static int
proto_shell_notify(struct interface_proto_state *proto, struct blob_attr *attr)
{
	struct proto_shell_state *state;
	struct blob_attr *tb[__NOTIFY_LAST];

	state = container_of(proto, struct proto_shell_state, proto);

	blobmsg_parse(notify_attr, __NOTIFY_LAST, tb, blob_data(attr), blob_len(attr));
	if (!tb[NOTIFY_ACTION])
		return UBUS_STATUS_INVALID_ARGUMENT;

	switch(blobmsg_get_u32(tb[NOTIFY_ACTION])) {
	case 0://json_add_int action 0设置
		return proto_shell_update_link(state, attr, tb);
	case 1:
		return proto_shell_run_command(state, tb);
	case 2:
		return proto_shell_kill_command(state, tb);
	case 3:
		return proto_shell_notify_error(state, tb);
	case 4:
		return proto_shell_block_restart(state, tb);
	case 5:
		return proto_shell_set_available(state, tb);
	case 6:
		return proto_shell_add_host_dependency(state, tb);
	case 7:
		return proto_shell_setup_failed(state);
	default:
		return UBUS_STATUS_INVALID_ARGUMENT;
	}
}


 

static int
proto_shell_update_link(struct proto_shell_state *state, struct blob_attr *data, struct blob_attr **tb)
{
	struct interface *iface = state->proto.iface;
	struct blob_attr *cur;
	struct device *dev;
	const char *devname;
	int dev_create = 1;
	bool addr_ext = false;
	bool keep = false;
	bool up;

	if (state->sm == S_TEARDOWN || state->sm == S_SETUP_ABORT)
		return UBUS_STATUS_PERMISSION_DENIED;

	if (!tb[NOTIFY_LINK_UP])
		return UBUS_STATUS_INVALID_ARGUMENT;

	up = blobmsg_get_bool(tb[NOTIFY_LINK_UP]);
	if (!up) {
		state->proto.proto_event(&state->proto, IFPEV_LINK_LOST);
		return 0;
	}

	if ((cur = tb[NOTIFY_KEEP]) != NULL)
		keep = blobmsg_get_bool(cur);

	if ((cur = tb[NOTIFY_ADDR_EXT]) != NULL) {
		addr_ext = blobmsg_get_bool(cur);
		if (addr_ext)
			dev_create = 2;
	}

	if (iface->state != IFS_UP || !iface->l3_dev.dev)
		keep = false;

	if (!keep) {
		dev = iface->main_dev.dev;
		if (tb[NOTIFY_IFNAME]) {
			keep = false;
			devname = blobmsg_data(tb[NOTIFY_IFNAME]);
			if (tb[NOTIFY_TUNNEL])
				dev = proto_shell_create_tunnel(devname, tb[NOTIFY_TUNNEL]);
			else
				dev = device_get(devname, dev_create);
		}

		if (!dev)
			return UBUS_STATUS_INVALID_ARGUMENT;

		interface_set_l3_dev(iface, dev);
		if (device_claim(&iface->l3_dev) < 0)
			return UBUS_STATUS_UNKNOWN_ERROR;

		device_set_present(dev, true);

		interface_update_start(iface);
	}

	proto_apply_ip_settings(iface, data, addr_ext);

	if ((cur = tb[NOTIFY_ROUTES]) != NULL)
		proto_shell_parse_route_list(state->proto.iface, cur, false);

	if ((cur = tb[NOTIFY_ROUTES6]) != NULL)
		proto_shell_parse_route_list(state->proto.iface, cur, true);

	if ((cur = tb[NOTIFY_DNS]))
		interface_add_dns_server_list(&iface->proto_ip, cur);

	if ((cur = tb[NOTIFY_DNS_SEARCH]))
		interface_add_dns_search_list(&iface->proto_ip, cur);

	if ((cur = tb[NOTIFY_DATA]))
		proto_shell_parse_data(state->proto.iface, cur);

	interface_update_complete(state->proto.iface);

	if (!keep)
		state->proto.proto_event(&state->proto, IFPEV_UP);
	state->sm = S_IDLE;

	return 0;
}


 

int
proto_apply_ip_settings(struct interface *iface, struct blob_attr *attr, bool ext)
{
	struct blob_attr *tb[__OPT_MAX];
	struct blob_attr *cur;
	int n_v4 = 0, n_v6 = 0;

	blobmsg_parse(proto_ip_attributes, __OPT_MAX, tb, blob_data(attr), blob_len(attr));

	if ((cur = tb[OPT_IPADDR]))
		n_v4 = parse_address_list(iface, cur, false, ext);

	if ((cur = tb[OPT_IP6ADDR]))
		n_v6 = parse_address_list(iface, cur, true, ext);

	if ((cur = tb[OPT_IP6PREFIX]))
		if (parse_prefix_list(iface, cur) < 0)
			goto out;

	if (n_v4 < 0 || n_v6 < 0)
		goto out;

	if ((cur = tb[OPT_GATEWAY])) {
		if (n_v4 && !parse_gateway_option(iface, cur, false))
			goto out;
	}

	if ((cur = tb[OPT_IP6GW])) {
		if (n_v6 && !parse_gateway_option(iface, cur, true))
			goto out;
	}

	return 0;

out:
	return -1;
}


 

static int
parse_address_list(struct interface *iface, struct blob_attr *attr, bool v6,
		   bool ext)
{
	struct device_addr *addr;
	struct blob_attr *cur;
	int n_addr = 0;
	int rem;

	blobmsg_for_each_attr(cur, attr, rem) {
		addr = parse_address_item(cur, v6, ext);
		if (!addr)
			return -1;

		n_addr++;
		vlist_add(&iface->proto_ip.addr, &addr->node, &addr->flags);
	}

	return n_addr;
}


来看下netifd的interface.h结构

struct interface {
	struct vlist_node node;
	struct list_head hotplug_list;
	enum interface_event hotplug_ev;

	const char *name;
	const char *ifname;

	bool available;
	bool autostart;
	bool config_autostart;
	bool device_config;
	bool enabled;
	bool link_state;
	bool force_link;
	bool dynamic;

	time_t start_time;
	enum interface_state state;
	enum interface_config_state config_state;
	enum interface_update_flags updated;

	struct list_head users;

	const char *parent_ifname;
	struct interface_user parent_iface;

	/* main interface that the interface is bound to */
	struct device_user main_dev;
	struct device_user ext_dev;

	/* interface that layer 3 communication will go through */
	struct device_user l3_dev;

	struct blob_attr *config;

	/* primary protocol state */
	const struct proto_handler *proto_handler;
	struct interface_proto_state *proto;

	struct interface_ip_settings proto_ip;
	struct interface_ip_settings config_ip;
	struct vlist_tree host_routes;

	int metric;
	unsigned int ip4table;
	unsigned int ip6table;

	/* IPv6 assignment parameters */
	uint8_t assignment_length;
	int32_t assignment_hint;
	struct list_head assignment_classes;

	/* errors/warnings while trying to bring up the interface */
	struct list_head errors;

	/* extra data provided by protocol handlers or modules */
	struct avl_tree data;

	struct uloop_timeout remove_timer;
	struct ubus_object ubus;
};


端口的初始化

static void
__interface_ip_init(struct interface_ip_settings *ip, struct interface *iface)
{
	ip->iface = iface;
	ip->enabled = true;
	vlist_simple_init(&ip->dns_search, struct dns_search_domain, node);
	vlist_simple_init(&ip->dns_servers, struct dns_server, node);
	vlist_init(&ip->route, route_cmp, interface_update_proto_route);
	vlist_init(&ip->addr, addr_cmp, interface_update_proto_addr);
	vlist_init(&ip->prefix, prefix_cmp, interface_update_prefix);
}

void
interface_ip_init(struct interface *iface)
{
	__interface_ip_init(&iface->proto_ip, iface);
	__interface_ip_init(&iface->config_ip, iface);
	vlist_init(&iface->host_routes, route_cmp, interface_update_host_route);
}


当每次增删减地址时都会执行回调函数interface_update_proto_addr

static void
interface_update_proto_addr(struct vlist_tree *tree,
			    struct vlist_node *node_new,
			    struct vlist_node *node_old)
{
	struct interface_ip_settings *ip;
	struct interface *iface;
	struct device *dev;
	struct device_addr *a_new = NULL, *a_old = NULL;
	bool replace = false;
	bool keep = false;
	bool v6 = false;

	ip = container_of(tree, struct interface_ip_settings, addr);
	iface = ip->iface;
	dev = iface->l3_dev.dev;

	if (!node_new || !node_old)
		iface->updated |= IUF_ADDRESS;

	if (node_new) {
		a_new = container_of(node_new, struct device_addr, node);

		if ((a_new->flags & DEVADDR_FAMILY) == DEVADDR_INET4 &&
		    !a_new->broadcast) {

			uint32_t mask = ~0;
			uint32_t *a = (uint32_t *) &a_new->addr;

			mask >>= a_new->mask;
			a_new->broadcast = *a | htonl(mask);
		}
	}

	if (node_old)
		a_old = container_of(node_old, struct device_addr, node);

	if (a_new && a_old) {
		keep = true;

		if (a_old->flags != a_new->flags || a_old->failed)
			keep = false;

		if (a_old->valid_until != a_new->valid_until ||
				a_old->preferred_until != a_new->preferred_until)
			replace = true;

		if ((a_new->flags & DEVADDR_FAMILY) == DEVADDR_INET4 &&
		    a_new->broadcast != a_old->broadcast)
			keep = false;
	}

	if (node_old) {
		if (!(a_old->flags & DEVADDR_EXTERNAL) && a_old->enabled && !keep) {
			interface_handle_subnet_route(iface, a_old, false);

			if ((a_old->flags & DEVADDR_FAMILY) == DEVADDR_INET6)
				v6 = true;

			unsigned int table = (v6) ? iface->ip6table : iface->ip4table;

			//This is needed for source routing to work correctly. If a device
			//has two connections to a network using the same subnet, adding
			//only the network-rule will cause packets to be routed through the
			//first matching network (source IP matches both masks).
			if (table) {
				set_ip_source_policy(false, v6, IPRULE_PRIORITY_ADDR, &a_old->addr,
						(v6) ? 128 : 32, table, NULL, NULL);
				set_ip_source_policy(false, v6, IPRULE_PRIORITY_NW, &a_old->addr,
						a_old->mask, table, NULL, NULL);
			}

			system_del_address(dev, a_old);
		}
		free(a_old->pclass);
		free(a_old);
	}

	if (node_new) {
		a_new->enabled = true;
		if (!(a_new->flags & DEVADDR_EXTERNAL) && (!keep || replace)) {
			if (system_add_address(dev, a_new))
				a_new->failed = true;

			if (!keep) {
				if ((a_new->flags & DEVADDR_FAMILY) == DEVADDR_INET6)
					v6 = true;

				unsigned int table = (v6) ? iface->ip6table : iface->ip4table;

				if (table) {
					set_ip_source_policy(true, v6, IPRULE_PRIORITY_ADDR, &a_new->addr,
							(v6) ? 128 : 32, table, NULL, NULL);
					set_ip_source_policy(true, v6, IPRULE_PRIORITY_NW, &a_new->addr,
							a_new->mask, table, NULL, NULL);
				}
			}

			if ((a_new->flags & DEVADDR_OFFLINK) || iface->metric)
				interface_handle_subnet_route(iface, a_new, true);
		}
	}
}


 

int system_add_address(struct device *dev, struct device_addr *addr)
{
	return system_addr(dev, addr, RTM_NEWADDR);
}


 

static int system_addr(struct device *dev, struct device_addr *addr, int cmd)
{
	bool v4 = ((addr->flags & DEVADDR_FAMILY) == DEVADDR_INET4);
	int alen = v4 ? 4 : 16;
	unsigned int flags = 0;
	struct ifaddrmsg ifa = {
		.ifa_family = (alen == 4) ? AF_INET : AF_INET6,
		.ifa_prefixlen = addr->mask,
		.ifa_index = dev->ifindex,
	};

	struct nl_msg *msg;
	if (cmd == RTM_NEWADDR)
		flags |= NLM_F_CREATE | NLM_F_REPLACE;

	msg = nlmsg_alloc_simple(cmd, flags);
	if (!msg)
		return -1;

	nlmsg_append(msg, &ifa, sizeof(ifa), 0);
	nla_put(msg, IFA_LOCAL, alen, &addr->addr);
	if (v4) {
		if (addr->broadcast)
			nla_put_u32(msg, IFA_BROADCAST, addr->broadcast);
		if (addr->point_to_point)
			nla_put_u32(msg, IFA_ADDRESS, addr->point_to_point);
	} else {
		time_t now = system_get_rtime();
		struct ifa_cacheinfo cinfo = {0xffffffffU, 0xffffffffU, 0, 0};

		if (addr->preferred_until) {
			int64_t preferred = addr->preferred_until - now;
			if (preferred < 0)
				preferred = 0;
			else if (preferred > UINT32_MAX)
				preferred = UINT32_MAX;

			cinfo.ifa_prefered = preferred;
		}

		if (addr->valid_until) {
			int64_t valid = addr->valid_until - now;
			if (valid <= 0)
				return -1;
			else if (valid > UINT32_MAX)
				valid = UINT32_MAX;

			cinfo.ifa_valid = valid;
		}

		nla_put(msg, IFA_CACHEINFO, sizeof(cinfo), &cinfo);
	}

	return system_rtnl_call(msg);
}


通知内核完成ip设置

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值