xref: /kvmtool/net/uip/dhcp.c (revision bcd315db17b1d9d7a9117844cee248ff5cba8f1b)
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 }
94ab8d80a6SAsias He static int uip_dhcp_fill_option(struct uip_info *info, struct uip_dhcp *dhcp, int reply_msg_type)
95ab8d80a6SAsias He {
96ab8d80a6SAsias He 	int i = 0;
97ab8d80a6SAsias He 	u32 *addr;
98ab8d80a6SAsias He 	u8 *opt;
99ab8d80a6SAsias He 
100ab8d80a6SAsias He 	opt		= dhcp->option;
101ab8d80a6SAsias He 
102ab8d80a6SAsias He 	opt[i++]	= UIP_DHCP_TAG_MSG_TYPE;
103ab8d80a6SAsias He 	opt[i++]	= UIP_DHCP_TAG_MSG_TYPE_LEN;
104ab8d80a6SAsias He 	opt[i++]	= reply_msg_type;
105ab8d80a6SAsias He 
106ab8d80a6SAsias He 	opt[i++]	= UIP_DHCP_TAG_SERVER_ID;
107ab8d80a6SAsias He 	opt[i++]	= UIP_DHCP_TAG_SERVER_ID_LEN;
108ab8d80a6SAsias He 	addr		= (u32 *)&opt[i];
109ab8d80a6SAsias He 	*addr		= htonl(info->host_ip);
110ab8d80a6SAsias He 	i		+= UIP_DHCP_TAG_SERVER_ID_LEN;
111ab8d80a6SAsias He 
112ab8d80a6SAsias He 	opt[i++]	= UIP_DHCP_TAG_LEASE_TIME;
113ab8d80a6SAsias He 	opt[i++]	= UIP_DHCP_TAG_LEASE_TIME_LEN;
114ab8d80a6SAsias He 	addr		= (u32 *)&opt[i];
115ab8d80a6SAsias He 	*addr		= htonl(UIP_DHCP_LEASE_TIME);
116ab8d80a6SAsias He 	i		+= UIP_DHCP_TAG_LEASE_TIME_LEN;
117ab8d80a6SAsias He 
118ab8d80a6SAsias He 	opt[i++]	= UIP_DHCP_TAG_SUBMASK;
119ab8d80a6SAsias He 	opt[i++]	= UIP_DHCP_TAG_SUBMASK_LEN;
120ab8d80a6SAsias He 	addr		= (u32 *)&opt[i];
121ab8d80a6SAsias He 	*addr		= htonl(info->guest_netmask);
122ab8d80a6SAsias He 	i		+= UIP_DHCP_TAG_SUBMASK_LEN;
123ab8d80a6SAsias He 
124ab8d80a6SAsias He 	opt[i++]	= UIP_DHCP_TAG_ROUTER;
125ab8d80a6SAsias He 	opt[i++]	= UIP_DHCP_TAG_ROUTER_LEN;
126ab8d80a6SAsias He 	addr		= (u32 *)&opt[i];
127ab8d80a6SAsias He 	*addr		= htonl(info->host_ip);
128ab8d80a6SAsias He 	i		+= UIP_DHCP_TAG_ROUTER_LEN;
129ab8d80a6SAsias He 
130ab8d80a6SAsias He 	i 		= uip_dhcp_fill_option_name_and_server(info, opt, i);
131ab8d80a6SAsias He 
132ab8d80a6SAsias He 	opt[i++]	= UIP_DHCP_TAG_END;
133ab8d80a6SAsias He 
134ab8d80a6SAsias He 	return 0;
135ab8d80a6SAsias He }
136155c7f33SAsias He 
137155c7f33SAsias He static int uip_dhcp_make_pkg(struct uip_info *info, struct uip_udp_socket *sk, struct uip_buf *buf, u8 reply_msg_type)
138155c7f33SAsias He {
139155c7f33SAsias He 	struct uip_dhcp *dhcp;
140155c7f33SAsias He 
141155c7f33SAsias He 	dhcp		= (struct uip_dhcp *)buf->eth;
142155c7f33SAsias He 
143155c7f33SAsias He 	dhcp->msg_type	= 2;
144155c7f33SAsias He 	dhcp->client_ip	= 0;
145155c7f33SAsias He 	dhcp->your_ip	= htonl(info->guest_ip);
146155c7f33SAsias He 	dhcp->server_ip	= htonl(info->host_ip);
147155c7f33SAsias He 	dhcp->agent_ip	= 0;
148155c7f33SAsias He 
149155c7f33SAsias He 	uip_dhcp_fill_option(info, dhcp, reply_msg_type);
150155c7f33SAsias He 
151155c7f33SAsias He 	sk->sip		= htonl(info->guest_ip);
152155c7f33SAsias He 	sk->dip		= htonl(info->host_ip);
153155c7f33SAsias He 	sk->sport	= htons(UIP_DHCP_PORT_CLIENT);
154155c7f33SAsias He 	sk->dport	= htons(UIP_DHCP_PORT_SERVER);
155155c7f33SAsias He 
156155c7f33SAsias He 	return 0;
157155c7f33SAsias He }
158*bcd315dbSAsias He 
159*bcd315dbSAsias He int uip_tx_do_ipv4_udp_dhcp(struct uip_tx_arg *arg)
160*bcd315dbSAsias He {
161*bcd315dbSAsias He 	struct uip_udp_socket sk;
162*bcd315dbSAsias He 	struct uip_dhcp *dhcp;
163*bcd315dbSAsias He 	struct uip_info *info;
164*bcd315dbSAsias He 	struct uip_buf *buf;
165*bcd315dbSAsias He 	u8 reply_msg_type;
166*bcd315dbSAsias He 
167*bcd315dbSAsias He 	dhcp = (struct uip_dhcp *)arg->eth;
168*bcd315dbSAsias He 
169*bcd315dbSAsias He 	if (uip_dhcp_is_discovery(dhcp))
170*bcd315dbSAsias He 		reply_msg_type = UIP_DHCP_OFFER;
171*bcd315dbSAsias He 	else if (uip_dhcp_is_request(dhcp))
172*bcd315dbSAsias He 		reply_msg_type = UIP_DHCP_ACK;
173*bcd315dbSAsias He 	else
174*bcd315dbSAsias He 		return -1;
175*bcd315dbSAsias He 
176*bcd315dbSAsias He 	buf = uip_buf_clone(arg);
177*bcd315dbSAsias He 	info = arg->info;
178*bcd315dbSAsias He 
179*bcd315dbSAsias He 	/*
180*bcd315dbSAsias He 	 * Cook DHCP pkg
181*bcd315dbSAsias He 	 */
182*bcd315dbSAsias He 	uip_dhcp_make_pkg(info, &sk, buf, reply_msg_type);
183*bcd315dbSAsias He 
184*bcd315dbSAsias He 	/*
185*bcd315dbSAsias He 	 * Cook UDP pkg
186*bcd315dbSAsias He 	 */
187*bcd315dbSAsias He 	uip_udp_make_pkg(info, &sk, buf, NULL, UIP_DHCP_MAX_PAYLOAD_LEN);
188*bcd315dbSAsias He 
189*bcd315dbSAsias He 	/*
190*bcd315dbSAsias He 	 * Send data received from socket to guest
191*bcd315dbSAsias He 	 */
192*bcd315dbSAsias He 	uip_buf_set_used(info, buf);
193*bcd315dbSAsias He 
194*bcd315dbSAsias He 	return 0;
195*bcd315dbSAsias He }
196