1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44:
45:
46: 47: 48: 49:
50:
51: #include <t2ex/socket.h>
52: #include <tk/tkernel.h>
53: #include <tk/errno.h>
54: #include <tk/devmgr.h>
55: #include <device/netdrv.h>
56:
57: #include <strings.h>
58:
59: #include "dhcp.h"
60: #include "route.h"
61: #include "util.h"
62:
63: struct dhcp_state {
64: uint8_t state;
65: const char* ifname;
66: int xid;
67: SYSTIM start_time;
68: size_t option_length;
69: char hwaddr[6];
70: uint32_t yiaddr;
71: uint32_t dhcp_server;
72: uint32_t mask;
73: uint32_t gate;
74: uint32_t bcaddr;
75: uint32_t dns[2];
76: char domain_name[256];
77: };
78:
79: struct dhcp_packet {
80: struct ether_header eth;
81: struct ip ip;
82: struct udphdr udphdr;
83: struct dhcp_message dhcp;
84: } __packed;
85:
86: static int init_receiver(void)
87: {
88: int re;
89: int sd;
90: struct sockaddr_in s;
91:
92: sd = so_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
93: DEBUG_PRINT(("init_receiver: so_socket = %d(%d, %d)\n", sd, MERCD(sd), SERCD(sd)));
94:
95: bzero(&s, sizeof s);
96: s.sin_len = sizeof s;
97: s.sin_family = AF_INET;
98: s.sin_addr.s_addr = htonl(INADDR_ANY);
99: s.sin_port = htons(DHCP_CLIENT_PORT);
100: re = so_bind(sd, (struct sockaddr*)&s, sizeof s);
101: DEBUG_PRINT(("init_receiver: so_bind = %d(%d, %d)\n", re, MERCD(re), SERCD(re)));
102:
103: return sd;
104: }
105:
106: static void init_state(struct dhcp_state* state, const char* ifname)
107: {
108: int re;
109:
110: bzero(state, sizeof *state);
111:
112: state->state = DHCP_DISCOVER;
113:
114: state->ifname = ifname;
115:
116:
117: re = get_hwaddr(ifname, state->hwaddr);
118: DEBUG_PRINT(("init_state: get_hwaddr = %d(%d, %d)\n", re, MERCD(re), SERCD(re)));
119:
120:
121: state->xid = net_random();
122:
123:
124: tk_get_tim(&state->start_time);
125: }
126:
127: static int send_request(struct dhcp_state* state)
128: {
129: struct dhcp_packet p;
130: int i = 0;
131: int j;
132: int re;
133: int fd;
134: unsigned long sum;
135: int udp_len;
136: struct ifreq ifr;
137:
138: bzero(&ifr, sizeof ifr);
139: strncpy(ifr.ifr_name, state->ifname, IFNAMSIZ-1);
140:
141: bzero(&p, sizeof p);
142:
143: for(j = 0; j < 6; j++) {
144: p.eth.ether_dhost[j] = 0xffU;
145: p.eth.ether_shost[j] = state->hwaddr[j];
146: }
147: p.eth.ether_type = htons(0x0800);
148:
149: p.ip.ip_v = IPVERSION;
150: p.ip.ip_hl = sizeof p.ip >> 2;
151: p.ip.ip_id = state->xid;
152: p.ip.ip_ttl = 255;
153: p.ip.ip_p = IPPROTO_UDP;
154: p.ip.ip_dst.s_addr = htonl(INADDR_BROADCAST);
155:
156: p.udphdr.uh_sport = htons(DHCP_CLIENT_PORT);
157: p.udphdr.uh_dport = htons(DHCP_SERVER_PORT);
158:
159: p.dhcp.op = DHCP_BOOTREQUEST;
160: p.dhcp.hwtype = 1;
161: p.dhcp.hwlen = 6;
162: p.dhcp.xid = state->xid;
163: if ( state->state == DHCP_DISCOVER ) {
164: tk_get_tim(&state->start_time);
165: } else {
166: SYSTIM tim;
167: UW time;
168: tk_get_tim(&tim);
169: time = (tim.lo - state->start_time.lo) / 1000;
170: p.dhcp.secs = htons(time > 65535 ? 65535 : time);
171: }
172: p.dhcp.flags = htons(BROADCAST_FLAG);
173: p.dhcp.yiaddr = state->yiaddr;
174: memcpy(p.dhcp.chaddr, state->hwaddr, 6);
175: p.dhcp.cookie = htonl(MAGIC_COOKIE);
176:
177: p.dhcp.options[i] = DHO_MESSAGETYPE;
178: i++;
179: p.dhcp.options[i] = 1;
180: i++;
181: p.dhcp.options[i] = state->state;
182: i++;
183: if ( state->state == DHCP_REQUEST ) {
184: p.dhcp.options[i] = DHO_IPADDRESS;
185: i++;
186: p.dhcp.options[i] = sizeof(uint32_t);
187: i++;
188: memcpy(&p.dhcp.options[i], &state->yiaddr, sizeof(uint32_t));
189: i += sizeof(uint32_t);
190: }
191: p.dhcp.options[i] = DHO_END;
192: i++;
193:
194: state->option_length = i;
195:
196: udp_len = sizeof p.udphdr + offsetof(struct dhcp_message, options) + state->option_length;
197: p.udphdr.uh_ulen = htons(udp_len);
198: sum = p.ip.ip_src.s_addr & 0xffffU;
199: sum += (p.ip.ip_src.s_addr >> 16) & 0xffffU;
200: sum += p.ip.ip_dst.s_addr & 0xffffU;
201: sum += (p.ip.ip_dst.s_addr >> 16) & 0xffffU;
202: sum += htons(IPPROTO_UDP);
203: sum += htons(udp_len);
204: p.udphdr.uh_sum = checksum2((unsigned short*)&p.udphdr, udp_len, sum);
205:
206: p.ip.ip_len = htons(sizeof p.ip + udp_len);
207: p.ip.ip_sum = checksum((unsigned short*)&p.ip, sizeof p.ip);
208:
209: fd = so_bpfopen("/dev/bpf0", O_RDWR);
210: DEBUG_PRINT(("send_request: so_bpfopen = %d(%d, %d)\n", fd, MERCD(fd), SERCD(fd)));
211: re = so_ioctl(fd, BIOCSETIF, &ifr);
212: DEBUG_PRINT(("send_request: so_ioctl = %d(%d, %d)\n", re, MERCD(re), SERCD(re)));
213: re = so_write(fd, &p, sizeof p.eth + sizeof p.ip + udp_len);
214: DEBUG_PRINT(("send_request: so_write = %d(%d, %d)\n", re, MERCD(re), SERCD(re)));
215: so_close(fd);
216:
217: return re;
218: }
219:
220: static int wait_response(int server, long tmo)
221: {
222: fd_set fds;
223: struct timeval tv;
224: int re;
225:
226: FD_ZERO(&fds);
227: FD_SET(server, &fds);
228: tv.tv_sec = tmo;
229: tv.tv_usec = 0;
230:
231: DEBUG_PRINT(("dhclient: pre-select for %d secs\n", tmo));
232: re = so_select(server+1, &fds, NULL, NULL, &tv);
233: DEBUG_PRINT(("dhclient: so_select = %d(%d, %d)\n", re, MERCD(re), SERCD(re)));
234:
235: return re;
236: }
237:
238: static void get_params(struct dhcp_message* offer, struct dhcp_state* state)
239: {
240: int i;
241: for(i = 0; offer->options[i] != DHO_END; i += offer->options[i+1] + 2) {
242: switch(offer->options[i]) {
243: case DHO_PAD:
244: break;
245:
246: case DHO_SUBNETMASK:
247: memcpy(&state->mask, &offer->options[i+2], 4);
248: break;
249:
250: case DHO_ROUTER:
251: memcpy(&state->gate, &offer->options[i+2], 4);
252: break;
253:
254: case DHO_BROADCAST:
255: memcpy(&state->bcaddr, &offer->options[i+2], 4);
256: break;
257:
258: case DHO_SERVERID:
259: memcpy(&state->dhcp_server, &offer->options[i+2], 4);
260: break;
261:
262: case DHO_DNSSERVER:
263: memcpy(&state->dns[0], &offer->options[i+2], offer->options[i+1]);
264: break;
265:
266: case DHO_DNSDOMAIN:
267: strncpy(state->domain_name, &offer->options[i+2], offer->options[i+1]);
268: break;
269: }
270: }
271: }
272:
273: static int get_response(int server, struct dhcp_state* state)
274: {
275: struct dhcp_message offer;
276: struct sockaddr_in ssa;
277: socklen_t ssa_len;
278: int re;
279:
280: bzero(&offer, sizeof offer);
281: bzero(&ssa, sizeof ssa);
282: ssa_len = sizeof ssa;
283:
284: re = so_recvfrom(server, &offer, sizeof offer, 0, (struct sockaddr*)&ssa, &ssa_len);
285: DEBUG_PRINT(("dhclient: so_recvfrom = %d(%d, %d)\n", re, MERCD(re), SERCD(re)));
286: if ( re < 0 ) {
287: return re;
288: }
289: if ( offer.xid != state->xid ) {
290: return 0;
291: }
292: if ( state->state == DHCP_OFFER ) {
293: state->yiaddr = offer.yiaddr;
294: } else {
295: if ( offer.options[2] == DHCP_NAK ) {
296: 297: 298:
299: return INT32_MAX;
300: }
301:
302: get_params(&offer, state);
303: }
304:
305: return re;
306: }
307:
308: static void setup(const struct dhcp_state* state, const char* ifname)
309: {
310: int i;
311: int re;
312: struct sockaddr_in sa;
313: struct in_addr a;
314: int index = so_ifnametoindex(ifname);
315: #ifdef DEBUG
316: char rbuf[18];
317: #endif
318:
319: set_ifaddr(ifname, state->yiaddr, state->mask);
320: a.s_addr = state->yiaddr;
321: DEBUG_PRINT(("%s: IP address = %s\n", ifname, inet_ntop(AF_INET, &a, rbuf, sizeof(rbuf))));
322: route_add(INADDR_ANY, state->gate, INADDR_ANY, index, 0);
323:
324: bzero(&sa, sizeof sa);
325: sa.sin_len = sizeof sa;
326: sa.sin_family = AF_INET;
327: sa.sin_addr.s_addr = INADDR_ANY;
328: sa.sin_port = htons(53);
329: re = so_resctl(SO_RES_DEL_SERVER, &sa, sizeof sa);
330: DEBUG_PRINT(("setup: so_resctl(%s) = %d(%d, %d)\n", "delete", re, MERCD(re), SERCD(re)));
331:
332: for(i = 0; state->dns[i] != 0 && i < 2; i++ ) {
333: bzero(&sa, sizeof sa);
334: sa.sin_len = sizeof sa;
335: sa.sin_family = AF_INET;
336: sa.sin_addr.s_addr = state->dns[i];
337: sa.sin_port = htons(53);
338: re = so_resctl(SO_RES_ADD_SERVER, &sa, sizeof sa);
339: a.s_addr = state->dns[i];
340: DEBUG_PRINT(("setup: so_resctl(%s) = %d(%d, %d)\n", inet_ntop(AF_INET, &a, rbuf, sizeof(rbuf)), re, MERCD(re), SERCD(re)));
341: }
342:
343: so_resctl(SO_RES_ADD_DOMAIN, (void*)state->domain_name, strlen(state->domain_name) + 1);
344: }
345:
346: int dhclient(const char* ifname)
347: {
348: int re;
349: int receiver;
350: struct dhcp_state state;
351:
352: init_state(&state, ifname);
353: receiver = init_receiver();
354:
355: long tmo = DHCP_BASE;
356: while(state.state != 0) {
357: switch(state.state) {
358: case DHCP_DISCOVER:
359: case DHCP_REQUEST:
360: re = send_request(&state);
361: DEBUG_PRINT(("dhclient: [REQUEST:%d] = %d(%d, %d)\n", state.state, re, MERCD(re), SERCD(re)));
362: if ( re < 0 ) {
363: return re;
364: }
365: state.state = (state.state == DHCP_DISCOVER) ? DHCP_OFFER : DHCP_ACK;
366: break;
367:
368: case DHCP_OFFER:
369: case DHCP_ACK:
370: re = wait_response(receiver, tmo);
371: if ( re == 0 ) {
372: DEBUG_PRINT(("dhclient: select timed out\n"));
373:
374: tmo *= 2;
375: tmo += net_random() % 3 - 1;
376: if ( tmo > DHCP_MAX ) {
377: tmo = DHCP_MAX;
378: }
379: state.state = (state.state == DHCP_OFFER) ? DHCP_DISCOVER : DHCP_REQUEST;
380: continue;
381: } else if ( re < 0 ) {
382: return re;
383: }
384:
385: re = get_response(receiver, &state);
386: if ( re == 0 ) {
387:
388: DEBUG_PRINT(("dhclient: unrelated packet\n"));
389: continue;
390: } else if ( re == INT32_MAX ) {
391: state.state = DHCP_DISCOVER;
392: continue;
393: } else if ( re < 0 ) {
394: return re;
395: }
396: tmo = DHCP_BASE;
397: state.state = (state.state == DHCP_OFFER) ? DHCP_REQUEST : 0;
398: break;
399: }
400: }
401:
402: so_close(receiver);
403:
404: setup(&state, ifname);
405:
406: return 0;
407: }