1 #include "kvm/uip.h"
2
3 #include <arpa/inet.h>
4
5 #define EMPTY_ADDR "0.0.0.0"
6
uip_dhcp_is_discovery(struct uip_dhcp * dhcp)7 static inline bool uip_dhcp_is_discovery(struct uip_dhcp *dhcp)
8 {
9 return (dhcp->option[2] == UIP_DHCP_DISCOVER &&
10 dhcp->option[1] == UIP_DHCP_TAG_MSG_TYPE_LEN &&
11 dhcp->option[0] == UIP_DHCP_TAG_MSG_TYPE);
12 }
13
uip_dhcp_is_request(struct uip_dhcp * dhcp)14 static inline bool uip_dhcp_is_request(struct uip_dhcp *dhcp)
15 {
16 return (dhcp->option[2] == UIP_DHCP_REQUEST &&
17 dhcp->option[1] == UIP_DHCP_TAG_MSG_TYPE_LEN &&
18 dhcp->option[0] == UIP_DHCP_TAG_MSG_TYPE);
19 }
20
uip_udp_is_dhcp(struct uip_udp * udp)21 bool uip_udp_is_dhcp(struct uip_udp *udp)
22 {
23 struct uip_dhcp *dhcp;
24
25 if (ntohs(udp->sport) != UIP_DHCP_PORT_CLIENT ||
26 ntohs(udp->dport) != UIP_DHCP_PORT_SERVER)
27 return false;
28
29 dhcp = (struct uip_dhcp *)udp;
30
31 if (ntohl(dhcp->magic_cookie) != UIP_DHCP_MAGIC_COOKIE)
32 return false;
33
34 return true;
35 }
36
uip_dhcp_get_dns(struct uip_info * info)37 int uip_dhcp_get_dns(struct uip_info *info)
38 {
39 char key[256], val[256];
40 struct in_addr addr;
41 int ret = -1;
42 int n = 0;
43 FILE *fp;
44 u32 ip;
45
46 fp = fopen("/etc/resolv.conf", "r");
47 if (!fp)
48 return ret;
49
50 while (!feof(fp)) {
51 if (fscanf(fp, "%s %s\n", key, val) != 2)
52 continue;
53 if (strncmp("domain", key, 6) == 0)
54 info->domain_name = strndup(val, UIP_DHCP_MAX_DOMAIN_NAME_LEN);
55 else if (strncmp("nameserver", key, 10) == 0) {
56 if (!inet_aton(val, &addr))
57 continue;
58 ip = ntohl(addr.s_addr);
59 if (n < UIP_DHCP_MAX_DNS_SERVER_NR)
60 info->dns_ip[n++] = ip;
61 ret = 0;
62 }
63 }
64
65 fclose(fp);
66 return ret;
67 }
68
uip_dhcp_fill_option_name_and_server(struct uip_info * info,u8 * opt,int i)69 static int uip_dhcp_fill_option_name_and_server(struct uip_info *info, u8 *opt, int i)
70 {
71 u8 domain_name_len;
72 u32 *addr;
73 int n;
74
75 if (info->domain_name) {
76 domain_name_len = strlen(info->domain_name);
77 opt[i++] = UIP_DHCP_TAG_DOMAIN_NAME;
78 opt[i++] = domain_name_len;
79 memcpy(&opt[i], info->domain_name, domain_name_len);
80 i += domain_name_len;
81 }
82
83 for (n = 0; n < UIP_DHCP_MAX_DNS_SERVER_NR; n++) {
84 if (info->dns_ip[n] == 0)
85 continue;
86 opt[i++] = UIP_DHCP_TAG_DNS_SERVER;
87 opt[i++] = UIP_DHCP_TAG_DNS_SERVER_LEN;
88 addr = (u32 *)&opt[i];
89 *addr = htonl(info->dns_ip[n]);
90 i += UIP_DHCP_TAG_DNS_SERVER_LEN;
91 }
92
93 return i;
94 }
uip_dhcp_fill_option(struct uip_info * info,struct uip_dhcp * dhcp,int reply_msg_type)95 static int uip_dhcp_fill_option(struct uip_info *info, struct uip_dhcp *dhcp, int reply_msg_type)
96 {
97 int i = 0;
98 u32 *addr;
99 u8 *opt;
100
101 opt = dhcp->option;
102
103 opt[i++] = UIP_DHCP_TAG_MSG_TYPE;
104 opt[i++] = UIP_DHCP_TAG_MSG_TYPE_LEN;
105 opt[i++] = reply_msg_type;
106
107 opt[i++] = UIP_DHCP_TAG_SERVER_ID;
108 opt[i++] = UIP_DHCP_TAG_SERVER_ID_LEN;
109 addr = (u32 *)&opt[i];
110 *addr = htonl(info->host_ip);
111 i += UIP_DHCP_TAG_SERVER_ID_LEN;
112
113 opt[i++] = UIP_DHCP_TAG_LEASE_TIME;
114 opt[i++] = UIP_DHCP_TAG_LEASE_TIME_LEN;
115 addr = (u32 *)&opt[i];
116 *addr = htonl(UIP_DHCP_LEASE_TIME);
117 i += UIP_DHCP_TAG_LEASE_TIME_LEN;
118
119 opt[i++] = UIP_DHCP_TAG_SUBMASK;
120 opt[i++] = UIP_DHCP_TAG_SUBMASK_LEN;
121 addr = (u32 *)&opt[i];
122 *addr = htonl(info->guest_netmask);
123 i += UIP_DHCP_TAG_SUBMASK_LEN;
124
125 opt[i++] = UIP_DHCP_TAG_ROUTER;
126 opt[i++] = UIP_DHCP_TAG_ROUTER_LEN;
127 addr = (u32 *)&opt[i];
128 *addr = htonl(info->host_ip);
129 i += UIP_DHCP_TAG_ROUTER_LEN;
130
131 opt[i++] = UIP_DHCP_TAG_ROOT;
132 opt[i++] = strlen(EMPTY_ADDR);
133 addr = (u32 *)&opt[i];
134 strcpy((void *) addr, EMPTY_ADDR);
135 i += strlen(EMPTY_ADDR);
136
137 i = uip_dhcp_fill_option_name_and_server(info, opt, i);
138
139 opt[i++] = UIP_DHCP_TAG_END;
140
141 return 0;
142 }
143
uip_dhcp_make_pkg(struct uip_info * info,struct uip_udp_socket * sk,struct uip_buf * buf,u8 reply_msg_type)144 static int uip_dhcp_make_pkg(struct uip_info *info, struct uip_udp_socket *sk, struct uip_buf *buf, u8 reply_msg_type)
145 {
146 struct uip_dhcp *dhcp;
147
148 dhcp = (struct uip_dhcp *)buf->eth;
149
150 dhcp->msg_type = 2;
151 dhcp->client_ip = 0;
152 dhcp->your_ip = htonl(info->guest_ip);
153 dhcp->server_ip = htonl(info->host_ip);
154 dhcp->agent_ip = 0;
155
156 uip_dhcp_fill_option(info, dhcp, reply_msg_type);
157
158 sk->sip = htonl(info->guest_ip);
159 sk->dip = htonl(info->host_ip);
160 sk->sport = htons(UIP_DHCP_PORT_CLIENT);
161 sk->dport = htons(UIP_DHCP_PORT_SERVER);
162
163 return 0;
164 }
165
uip_tx_do_ipv4_udp_dhcp(struct uip_tx_arg * arg)166 int uip_tx_do_ipv4_udp_dhcp(struct uip_tx_arg *arg)
167 {
168 struct uip_udp_socket sk;
169 struct uip_dhcp *dhcp;
170 struct uip_info *info;
171 struct uip_buf *buf;
172 u8 reply_msg_type;
173
174 dhcp = (struct uip_dhcp *)arg->eth;
175
176 if (uip_dhcp_is_discovery(dhcp))
177 reply_msg_type = UIP_DHCP_OFFER;
178 else if (uip_dhcp_is_request(dhcp))
179 reply_msg_type = UIP_DHCP_ACK;
180 else
181 return -1;
182
183 buf = uip_buf_clone(arg);
184 info = arg->info;
185
186 /*
187 * Cook DHCP pkg
188 */
189 uip_dhcp_make_pkg(info, &sk, buf, reply_msg_type);
190
191 /*
192 * Cook UDP pkg
193 */
194 uip_udp_make_pkg(info, &sk, buf, NULL, UIP_DHCP_MAX_PAYLOAD_LEN);
195
196 /*
197 * Send data received from socket to guest
198 */
199 uip_buf_set_used(info, buf);
200
201 return 0;
202 }
203
uip_dhcp_exit(struct uip_info * info)204 void uip_dhcp_exit(struct uip_info *info)
205 {
206 free(info->domain_name);
207 info->domain_name = NULL;
208 }
209