xref: /kvmtool/net/uip/dhcp.c (revision ab8d80a6151426c229ae31c1de2999d2ca7c367e)
10c4bfcacSAsias He #include "kvm/uip.h"
20c4bfcacSAsias He 
3bdcc9e40SAsias He #include <arpa/inet.h>
4bdcc9e40SAsias He 
58f5f2f95SAsias He static inline bool uip_dhcp_is_discovery(struct uip_dhcp *dhcp)
68f5f2f95SAsias He {
78f5f2f95SAsias He 	return (dhcp->option[2] == UIP_DHCP_DISCOVER &&
88f5f2f95SAsias He 		dhcp->option[1] == UIP_DHCP_TAG_MSG_TYPE_LEN &&
98f5f2f95SAsias He 		dhcp->option[0] == UIP_DHCP_TAG_MSG_TYPE);
108f5f2f95SAsias He }
118f5f2f95SAsias He 
128f5f2f95SAsias He static inline bool uip_dhcp_is_request(struct uip_dhcp *dhcp)
138f5f2f95SAsias He {
148f5f2f95SAsias He 	return (dhcp->option[2] == UIP_DHCP_REQUEST &&
158f5f2f95SAsias He 		dhcp->option[1] == UIP_DHCP_TAG_MSG_TYPE_LEN &&
168f5f2f95SAsias He 		dhcp->option[0] == UIP_DHCP_TAG_MSG_TYPE);
178f5f2f95SAsias He }
188f5f2f95SAsias He 
190c4bfcacSAsias He bool uip_udp_is_dhcp(struct uip_udp *udp)
200c4bfcacSAsias He {
210c4bfcacSAsias He 	struct uip_dhcp *dhcp;
220c4bfcacSAsias He 
230c4bfcacSAsias He 	if (ntohs(udp->sport) != UIP_DHCP_PORT_CLIENT ||
240c4bfcacSAsias He 	    ntohs(udp->dport) != UIP_DHCP_PORT_SERVER)
250c4bfcacSAsias He 		return false;
260c4bfcacSAsias He 
270c4bfcacSAsias He 	dhcp = (struct uip_dhcp *)udp;
280c4bfcacSAsias He 
290c4bfcacSAsias He 	if (ntohl(dhcp->magic_cookie) != UIP_DHCP_MAGIC_COOKIE)
300c4bfcacSAsias He 		return false;
310c4bfcacSAsias He 
320c4bfcacSAsias He 	return true;
330c4bfcacSAsias He }
34bdcc9e40SAsias He 
35bdcc9e40SAsias He int uip_dhcp_get_dns(struct uip_info *info)
36bdcc9e40SAsias He {
37bdcc9e40SAsias He 	char key[256], val[256];
38bdcc9e40SAsias He 	struct in_addr addr;
39bdcc9e40SAsias He 	int ret = -1;
40bdcc9e40SAsias He 	int n = 0;
41bdcc9e40SAsias He 	FILE *fp;
42bdcc9e40SAsias He 	u32 ip;
43bdcc9e40SAsias He 
44bdcc9e40SAsias He 	fp = fopen("/etc/resolv.conf", "r");
45bdcc9e40SAsias He 	if (!fp)
46bdcc9e40SAsias He 		goto out;
47bdcc9e40SAsias He 
48bdcc9e40SAsias He 	while (!feof(fp)) {
49bdcc9e40SAsias He 		if (fscanf(fp, "%s %s\n", key, val) != 2)
50bdcc9e40SAsias He 			continue;
51bdcc9e40SAsias He 		if (strncmp("domain", key, 6) == 0)
52bdcc9e40SAsias He 			info->domain_name = strndup(val, UIP_DHCP_MAX_DOMAIN_NAME_LEN);
53bdcc9e40SAsias He 		else if (strncmp("nameserver", key, 10) == 0) {
54bdcc9e40SAsias He 			if (!inet_aton(val, &addr))
55bdcc9e40SAsias He 				continue;
56bdcc9e40SAsias He 			ip = ntohl(addr.s_addr);
57bdcc9e40SAsias He 			if (n < UIP_DHCP_MAX_DNS_SERVER_NR)
58bdcc9e40SAsias He 				info->dns_ip[n++] = ip;
59bdcc9e40SAsias He 			ret = 0;
60bdcc9e40SAsias He 		}
61bdcc9e40SAsias He 	}
62bdcc9e40SAsias He 
63bdcc9e40SAsias He out:
64bdcc9e40SAsias He 	fclose(fp);
65bdcc9e40SAsias He 	return ret;
66bdcc9e40SAsias He }
6732a44aafSAsias He 
6832a44aafSAsias He static int uip_dhcp_fill_option_name_and_server(struct uip_info *info, u8 *opt, int i)
6932a44aafSAsias He {
7032a44aafSAsias He 	u8 domain_name_len;
7132a44aafSAsias He 	u32 *addr;
7232a44aafSAsias He 	int n;
7332a44aafSAsias He 
7432a44aafSAsias He 	if (info->domain_name) {
7532a44aafSAsias He 		domain_name_len	= strlen(info->domain_name);
7632a44aafSAsias He 		opt[i++]	= UIP_DHCP_TAG_DOMAIN_NAME;
7732a44aafSAsias He 		opt[i++]	= domain_name_len;
7832a44aafSAsias He 		memcpy(&opt[i], info->domain_name, domain_name_len);
7932a44aafSAsias He 		i		+= domain_name_len;
8032a44aafSAsias He 	}
8132a44aafSAsias He 
8232a44aafSAsias He 	for (n = 0; n < UIP_DHCP_MAX_DNS_SERVER_NR; n++) {
8332a44aafSAsias He 		if (info->dns_ip[n] == 0)
8432a44aafSAsias He 			continue;
8532a44aafSAsias He 		opt[i++]	= UIP_DHCP_TAG_DNS_SERVER;
8632a44aafSAsias He 		opt[i++]	= UIP_DHCP_TAG_DNS_SERVER_LEN;
8732a44aafSAsias He 		addr		= (u32 *)&opt[i];
8832a44aafSAsias He 		*addr		= htonl(info->dns_ip[n]);
8932a44aafSAsias He 		i		+= UIP_DHCP_TAG_DNS_SERVER_LEN;
9032a44aafSAsias He 	}
9132a44aafSAsias He 
9232a44aafSAsias He 	return i;
9332a44aafSAsias He }
94*ab8d80a6SAsias He static int uip_dhcp_fill_option(struct uip_info *info, struct uip_dhcp *dhcp, int reply_msg_type)
95*ab8d80a6SAsias He {
96*ab8d80a6SAsias He 	int i = 0;
97*ab8d80a6SAsias He 	u32 *addr;
98*ab8d80a6SAsias He 	u8 *opt;
99*ab8d80a6SAsias He 
100*ab8d80a6SAsias He 	opt		= dhcp->option;
101*ab8d80a6SAsias He 
102*ab8d80a6SAsias He 	opt[i++]	= UIP_DHCP_TAG_MSG_TYPE;
103*ab8d80a6SAsias He 	opt[i++]	= UIP_DHCP_TAG_MSG_TYPE_LEN;
104*ab8d80a6SAsias He 	opt[i++]	= reply_msg_type;
105*ab8d80a6SAsias He 
106*ab8d80a6SAsias He 	opt[i++]	= UIP_DHCP_TAG_SERVER_ID;
107*ab8d80a6SAsias He 	opt[i++]	= UIP_DHCP_TAG_SERVER_ID_LEN;
108*ab8d80a6SAsias He 	addr		= (u32 *)&opt[i];
109*ab8d80a6SAsias He 	*addr		= htonl(info->host_ip);
110*ab8d80a6SAsias He 	i		+= UIP_DHCP_TAG_SERVER_ID_LEN;
111*ab8d80a6SAsias He 
112*ab8d80a6SAsias He 	opt[i++]	= UIP_DHCP_TAG_LEASE_TIME;
113*ab8d80a6SAsias He 	opt[i++]	= UIP_DHCP_TAG_LEASE_TIME_LEN;
114*ab8d80a6SAsias He 	addr		= (u32 *)&opt[i];
115*ab8d80a6SAsias He 	*addr		= htonl(UIP_DHCP_LEASE_TIME);
116*ab8d80a6SAsias He 	i		+= UIP_DHCP_TAG_LEASE_TIME_LEN;
117*ab8d80a6SAsias He 
118*ab8d80a6SAsias He 	opt[i++]	= UIP_DHCP_TAG_SUBMASK;
119*ab8d80a6SAsias He 	opt[i++]	= UIP_DHCP_TAG_SUBMASK_LEN;
120*ab8d80a6SAsias He 	addr		= (u32 *)&opt[i];
121*ab8d80a6SAsias He 	*addr		= htonl(info->guest_netmask);
122*ab8d80a6SAsias He 	i		+= UIP_DHCP_TAG_SUBMASK_LEN;
123*ab8d80a6SAsias He 
124*ab8d80a6SAsias He 	opt[i++]	= UIP_DHCP_TAG_ROUTER;
125*ab8d80a6SAsias He 	opt[i++]	= UIP_DHCP_TAG_ROUTER_LEN;
126*ab8d80a6SAsias He 	addr		= (u32 *)&opt[i];
127*ab8d80a6SAsias He 	*addr		= htonl(info->host_ip);
128*ab8d80a6SAsias He 	i		+= UIP_DHCP_TAG_ROUTER_LEN;
129*ab8d80a6SAsias He 
130*ab8d80a6SAsias He 	i 		= uip_dhcp_fill_option_name_and_server(info, opt, i);
131*ab8d80a6SAsias He 
132*ab8d80a6SAsias He 	opt[i++]	= UIP_DHCP_TAG_END;
133*ab8d80a6SAsias He 
134*ab8d80a6SAsias He 	return 0;
135*ab8d80a6SAsias He }
136