10c4bfcacSAsias He #include "kvm/uip.h"
20c4bfcacSAsias He
3bdcc9e40SAsias He #include <arpa/inet.h>
4bdcc9e40SAsias He
5575a9e3fSSasha Levin #define EMPTY_ADDR "0.0.0.0"
6575a9e3fSSasha Levin
uip_dhcp_is_discovery(struct uip_dhcp * dhcp)78f5f2f95SAsias He static inline bool uip_dhcp_is_discovery(struct uip_dhcp *dhcp)
88f5f2f95SAsias He {
98f5f2f95SAsias He return (dhcp->option[2] == UIP_DHCP_DISCOVER &&
108f5f2f95SAsias He dhcp->option[1] == UIP_DHCP_TAG_MSG_TYPE_LEN &&
118f5f2f95SAsias He dhcp->option[0] == UIP_DHCP_TAG_MSG_TYPE);
128f5f2f95SAsias He }
138f5f2f95SAsias He
uip_dhcp_is_request(struct uip_dhcp * dhcp)148f5f2f95SAsias He static inline bool uip_dhcp_is_request(struct uip_dhcp *dhcp)
158f5f2f95SAsias He {
168f5f2f95SAsias He return (dhcp->option[2] == UIP_DHCP_REQUEST &&
178f5f2f95SAsias He dhcp->option[1] == UIP_DHCP_TAG_MSG_TYPE_LEN &&
188f5f2f95SAsias He dhcp->option[0] == UIP_DHCP_TAG_MSG_TYPE);
198f5f2f95SAsias He }
208f5f2f95SAsias He
uip_udp_is_dhcp(struct uip_udp * udp)210c4bfcacSAsias He bool uip_udp_is_dhcp(struct uip_udp *udp)
220c4bfcacSAsias He {
230c4bfcacSAsias He struct uip_dhcp *dhcp;
240c4bfcacSAsias He
250c4bfcacSAsias He if (ntohs(udp->sport) != UIP_DHCP_PORT_CLIENT ||
260c4bfcacSAsias He ntohs(udp->dport) != UIP_DHCP_PORT_SERVER)
270c4bfcacSAsias He return false;
280c4bfcacSAsias He
290c4bfcacSAsias He dhcp = (struct uip_dhcp *)udp;
300c4bfcacSAsias He
310c4bfcacSAsias He if (ntohl(dhcp->magic_cookie) != UIP_DHCP_MAGIC_COOKIE)
320c4bfcacSAsias He return false;
330c4bfcacSAsias He
340c4bfcacSAsias He return true;
350c4bfcacSAsias He }
36bdcc9e40SAsias He
uip_dhcp_get_dns(struct uip_info * info)37bdcc9e40SAsias He int uip_dhcp_get_dns(struct uip_info *info)
38bdcc9e40SAsias He {
39bdcc9e40SAsias He char key[256], val[256];
40bdcc9e40SAsias He struct in_addr addr;
41bdcc9e40SAsias He int ret = -1;
42bdcc9e40SAsias He int n = 0;
43bdcc9e40SAsias He FILE *fp;
44bdcc9e40SAsias He u32 ip;
45bdcc9e40SAsias He
46bdcc9e40SAsias He fp = fopen("/etc/resolv.conf", "r");
47bdcc9e40SAsias He if (!fp)
48a7b946b9SMichael Ellerman return ret;
49bdcc9e40SAsias He
50bdcc9e40SAsias He while (!feof(fp)) {
51bdcc9e40SAsias He if (fscanf(fp, "%s %s\n", key, val) != 2)
52bdcc9e40SAsias He continue;
53bdcc9e40SAsias He if (strncmp("domain", key, 6) == 0)
54bdcc9e40SAsias He info->domain_name = strndup(val, UIP_DHCP_MAX_DOMAIN_NAME_LEN);
55bdcc9e40SAsias He else if (strncmp("nameserver", key, 10) == 0) {
56bdcc9e40SAsias He if (!inet_aton(val, &addr))
57bdcc9e40SAsias He continue;
58bdcc9e40SAsias He ip = ntohl(addr.s_addr);
59bdcc9e40SAsias He if (n < UIP_DHCP_MAX_DNS_SERVER_NR)
60bdcc9e40SAsias He info->dns_ip[n++] = ip;
61bdcc9e40SAsias He ret = 0;
62bdcc9e40SAsias He }
63bdcc9e40SAsias He }
64bdcc9e40SAsias He
65bdcc9e40SAsias He fclose(fp);
66bdcc9e40SAsias He return ret;
67bdcc9e40SAsias He }
6832a44aafSAsias He
uip_dhcp_fill_option_name_and_server(struct uip_info * info,u8 * opt,int i)6932a44aafSAsias He static int uip_dhcp_fill_option_name_and_server(struct uip_info *info, u8 *opt, int i)
7032a44aafSAsias He {
7132a44aafSAsias He u8 domain_name_len;
7232a44aafSAsias He u32 *addr;
7332a44aafSAsias He int n;
7432a44aafSAsias He
7532a44aafSAsias He if (info->domain_name) {
7632a44aafSAsias He domain_name_len = strlen(info->domain_name);
7732a44aafSAsias He opt[i++] = UIP_DHCP_TAG_DOMAIN_NAME;
7832a44aafSAsias He opt[i++] = domain_name_len;
7932a44aafSAsias He memcpy(&opt[i], info->domain_name, domain_name_len);
8032a44aafSAsias He i += domain_name_len;
8132a44aafSAsias He }
8232a44aafSAsias He
8332a44aafSAsias He for (n = 0; n < UIP_DHCP_MAX_DNS_SERVER_NR; n++) {
8432a44aafSAsias He if (info->dns_ip[n] == 0)
8532a44aafSAsias He continue;
8632a44aafSAsias He opt[i++] = UIP_DHCP_TAG_DNS_SERVER;
8732a44aafSAsias He opt[i++] = UIP_DHCP_TAG_DNS_SERVER_LEN;
8832a44aafSAsias He addr = (u32 *)&opt[i];
8932a44aafSAsias He *addr = htonl(info->dns_ip[n]);
9032a44aafSAsias He i += UIP_DHCP_TAG_DNS_SERVER_LEN;
9132a44aafSAsias He }
9232a44aafSAsias He
9332a44aafSAsias He return i;
9432a44aafSAsias He }
uip_dhcp_fill_option(struct uip_info * info,struct uip_dhcp * dhcp,int reply_msg_type)95ab8d80a6SAsias He static int uip_dhcp_fill_option(struct uip_info *info, struct uip_dhcp *dhcp, int reply_msg_type)
96ab8d80a6SAsias He {
97ab8d80a6SAsias He int i = 0;
98ab8d80a6SAsias He u32 *addr;
99ab8d80a6SAsias He u8 *opt;
100ab8d80a6SAsias He
101ab8d80a6SAsias He opt = dhcp->option;
102ab8d80a6SAsias He
103ab8d80a6SAsias He opt[i++] = UIP_DHCP_TAG_MSG_TYPE;
104ab8d80a6SAsias He opt[i++] = UIP_DHCP_TAG_MSG_TYPE_LEN;
105ab8d80a6SAsias He opt[i++] = reply_msg_type;
106ab8d80a6SAsias He
107ab8d80a6SAsias He opt[i++] = UIP_DHCP_TAG_SERVER_ID;
108ab8d80a6SAsias He opt[i++] = UIP_DHCP_TAG_SERVER_ID_LEN;
109ab8d80a6SAsias He addr = (u32 *)&opt[i];
110ab8d80a6SAsias He *addr = htonl(info->host_ip);
111ab8d80a6SAsias He i += UIP_DHCP_TAG_SERVER_ID_LEN;
112ab8d80a6SAsias He
113ab8d80a6SAsias He opt[i++] = UIP_DHCP_TAG_LEASE_TIME;
114ab8d80a6SAsias He opt[i++] = UIP_DHCP_TAG_LEASE_TIME_LEN;
115ab8d80a6SAsias He addr = (u32 *)&opt[i];
116ab8d80a6SAsias He *addr = htonl(UIP_DHCP_LEASE_TIME);
117ab8d80a6SAsias He i += UIP_DHCP_TAG_LEASE_TIME_LEN;
118ab8d80a6SAsias He
119ab8d80a6SAsias He opt[i++] = UIP_DHCP_TAG_SUBMASK;
120ab8d80a6SAsias He opt[i++] = UIP_DHCP_TAG_SUBMASK_LEN;
121ab8d80a6SAsias He addr = (u32 *)&opt[i];
122ab8d80a6SAsias He *addr = htonl(info->guest_netmask);
123ab8d80a6SAsias He i += UIP_DHCP_TAG_SUBMASK_LEN;
124ab8d80a6SAsias He
125ab8d80a6SAsias He opt[i++] = UIP_DHCP_TAG_ROUTER;
126ab8d80a6SAsias He opt[i++] = UIP_DHCP_TAG_ROUTER_LEN;
127ab8d80a6SAsias He addr = (u32 *)&opt[i];
128ab8d80a6SAsias He *addr = htonl(info->host_ip);
129ab8d80a6SAsias He i += UIP_DHCP_TAG_ROUTER_LEN;
130ab8d80a6SAsias He
131575a9e3fSSasha Levin opt[i++] = UIP_DHCP_TAG_ROOT;
132575a9e3fSSasha Levin opt[i++] = strlen(EMPTY_ADDR);
133575a9e3fSSasha Levin addr = (u32 *)&opt[i];
134*0796825eSAndre Przywara strcpy((void *) addr, EMPTY_ADDR);
135575a9e3fSSasha Levin i += strlen(EMPTY_ADDR);
136575a9e3fSSasha Levin
137ab8d80a6SAsias He i = uip_dhcp_fill_option_name_and_server(info, opt, i);
138ab8d80a6SAsias He
139ab8d80a6SAsias He opt[i++] = UIP_DHCP_TAG_END;
140ab8d80a6SAsias He
141ab8d80a6SAsias He return 0;
142ab8d80a6SAsias He }
143155c7f33SAsias He
uip_dhcp_make_pkg(struct uip_info * info,struct uip_udp_socket * sk,struct uip_buf * buf,u8 reply_msg_type)144155c7f33SAsias He static int uip_dhcp_make_pkg(struct uip_info *info, struct uip_udp_socket *sk, struct uip_buf *buf, u8 reply_msg_type)
145155c7f33SAsias He {
146155c7f33SAsias He struct uip_dhcp *dhcp;
147155c7f33SAsias He
148155c7f33SAsias He dhcp = (struct uip_dhcp *)buf->eth;
149155c7f33SAsias He
150155c7f33SAsias He dhcp->msg_type = 2;
151155c7f33SAsias He dhcp->client_ip = 0;
152155c7f33SAsias He dhcp->your_ip = htonl(info->guest_ip);
153155c7f33SAsias He dhcp->server_ip = htonl(info->host_ip);
154155c7f33SAsias He dhcp->agent_ip = 0;
155155c7f33SAsias He
156155c7f33SAsias He uip_dhcp_fill_option(info, dhcp, reply_msg_type);
157155c7f33SAsias He
158155c7f33SAsias He sk->sip = htonl(info->guest_ip);
159155c7f33SAsias He sk->dip = htonl(info->host_ip);
160155c7f33SAsias He sk->sport = htons(UIP_DHCP_PORT_CLIENT);
161155c7f33SAsias He sk->dport = htons(UIP_DHCP_PORT_SERVER);
162155c7f33SAsias He
163155c7f33SAsias He return 0;
164155c7f33SAsias He }
165bcd315dbSAsias He
uip_tx_do_ipv4_udp_dhcp(struct uip_tx_arg * arg)166bcd315dbSAsias He int uip_tx_do_ipv4_udp_dhcp(struct uip_tx_arg *arg)
167bcd315dbSAsias He {
168bcd315dbSAsias He struct uip_udp_socket sk;
169bcd315dbSAsias He struct uip_dhcp *dhcp;
170bcd315dbSAsias He struct uip_info *info;
171bcd315dbSAsias He struct uip_buf *buf;
172bcd315dbSAsias He u8 reply_msg_type;
173bcd315dbSAsias He
174bcd315dbSAsias He dhcp = (struct uip_dhcp *)arg->eth;
175bcd315dbSAsias He
176bcd315dbSAsias He if (uip_dhcp_is_discovery(dhcp))
177bcd315dbSAsias He reply_msg_type = UIP_DHCP_OFFER;
178bcd315dbSAsias He else if (uip_dhcp_is_request(dhcp))
179bcd315dbSAsias He reply_msg_type = UIP_DHCP_ACK;
180bcd315dbSAsias He else
181bcd315dbSAsias He return -1;
182bcd315dbSAsias He
183bcd315dbSAsias He buf = uip_buf_clone(arg);
184bcd315dbSAsias He info = arg->info;
185bcd315dbSAsias He
186bcd315dbSAsias He /*
187bcd315dbSAsias He * Cook DHCP pkg
188bcd315dbSAsias He */
189bcd315dbSAsias He uip_dhcp_make_pkg(info, &sk, buf, reply_msg_type);
190bcd315dbSAsias He
191bcd315dbSAsias He /*
192bcd315dbSAsias He * Cook UDP pkg
193bcd315dbSAsias He */
194bcd315dbSAsias He uip_udp_make_pkg(info, &sk, buf, NULL, UIP_DHCP_MAX_PAYLOAD_LEN);
195bcd315dbSAsias He
196bcd315dbSAsias He /*
197bcd315dbSAsias He * Send data received from socket to guest
198bcd315dbSAsias He */
199bcd315dbSAsias He uip_buf_set_used(info, buf);
200bcd315dbSAsias He
201bcd315dbSAsias He return 0;
202bcd315dbSAsias He }
203d87b503fSJean-Philippe Brucker
uip_dhcp_exit(struct uip_info * info)204d87b503fSJean-Philippe Brucker void uip_dhcp_exit(struct uip_info *info)
205d87b503fSJean-Philippe Brucker {
206d87b503fSJean-Philippe Brucker free(info->domain_name);
207d87b503fSJean-Philippe Brucker info->domain_name = NULL;
208d87b503fSJean-Philippe Brucker }
209