1*00c7fec1SAndroid Build Coastguard Worker /*
2*00c7fec1SAndroid Build Coastguard Worker * Copyright 2008, The Android Open Source Project
3*00c7fec1SAndroid Build Coastguard Worker *
4*00c7fec1SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*00c7fec1SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*00c7fec1SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*00c7fec1SAndroid Build Coastguard Worker *
8*00c7fec1SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*00c7fec1SAndroid Build Coastguard Worker *
10*00c7fec1SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*00c7fec1SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*00c7fec1SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*00c7fec1SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*00c7fec1SAndroid Build Coastguard Worker * limitations under the License.
15*00c7fec1SAndroid Build Coastguard Worker */
16*00c7fec1SAndroid Build Coastguard Worker
17*00c7fec1SAndroid Build Coastguard Worker #define LOG_TAG "DHCP"
18*00c7fec1SAndroid Build Coastguard Worker
19*00c7fec1SAndroid Build Coastguard Worker #include <dirent.h>
20*00c7fec1SAndroid Build Coastguard Worker #include <errno.h>
21*00c7fec1SAndroid Build Coastguard Worker #include <poll.h>
22*00c7fec1SAndroid Build Coastguard Worker #include <netinet/in.h>
23*00c7fec1SAndroid Build Coastguard Worker #include <stdarg.h>
24*00c7fec1SAndroid Build Coastguard Worker #include <stdlib.h>
25*00c7fec1SAndroid Build Coastguard Worker #include <stdio.h>
26*00c7fec1SAndroid Build Coastguard Worker #include <string.h>
27*00c7fec1SAndroid Build Coastguard Worker #include <sys/select.h>
28*00c7fec1SAndroid Build Coastguard Worker #include <sys/socket.h>
29*00c7fec1SAndroid Build Coastguard Worker #include <sys/time.h>
30*00c7fec1SAndroid Build Coastguard Worker #include <sys/types.h>
31*00c7fec1SAndroid Build Coastguard Worker #include <time.h>
32*00c7fec1SAndroid Build Coastguard Worker #include <unistd.h>
33*00c7fec1SAndroid Build Coastguard Worker
34*00c7fec1SAndroid Build Coastguard Worker #include <cutils/properties.h>
35*00c7fec1SAndroid Build Coastguard Worker #include <log/log.h>
36*00c7fec1SAndroid Build Coastguard Worker
37*00c7fec1SAndroid Build Coastguard Worker #include <netutils/ifc.h>
38*00c7fec1SAndroid Build Coastguard Worker #include "dhcpmsg.h"
39*00c7fec1SAndroid Build Coastguard Worker #include "packet.h"
40*00c7fec1SAndroid Build Coastguard Worker
41*00c7fec1SAndroid Build Coastguard Worker #define VERBOSE 2
42*00c7fec1SAndroid Build Coastguard Worker
43*00c7fec1SAndroid Build Coastguard Worker static int verbose = 1;
44*00c7fec1SAndroid Build Coastguard Worker static char errmsg[2048];
45*00c7fec1SAndroid Build Coastguard Worker
46*00c7fec1SAndroid Build Coastguard Worker typedef unsigned long long msecs_t;
47*00c7fec1SAndroid Build Coastguard Worker #if VERBOSE
48*00c7fec1SAndroid Build Coastguard Worker void dump_dhcp_msg(dhcp_msg *msg, int len);
49*00c7fec1SAndroid Build Coastguard Worker #endif
50*00c7fec1SAndroid Build Coastguard Worker
get_msecs(void)51*00c7fec1SAndroid Build Coastguard Worker msecs_t get_msecs(void)
52*00c7fec1SAndroid Build Coastguard Worker {
53*00c7fec1SAndroid Build Coastguard Worker struct timespec ts;
54*00c7fec1SAndroid Build Coastguard Worker
55*00c7fec1SAndroid Build Coastguard Worker if (clock_gettime(CLOCK_MONOTONIC, &ts)) {
56*00c7fec1SAndroid Build Coastguard Worker return 0;
57*00c7fec1SAndroid Build Coastguard Worker } else {
58*00c7fec1SAndroid Build Coastguard Worker return (((msecs_t) ts.tv_sec) * ((msecs_t) 1000)) +
59*00c7fec1SAndroid Build Coastguard Worker (((msecs_t) ts.tv_nsec) / ((msecs_t) 1000000));
60*00c7fec1SAndroid Build Coastguard Worker }
61*00c7fec1SAndroid Build Coastguard Worker }
62*00c7fec1SAndroid Build Coastguard Worker
printerr(char * fmt,...)63*00c7fec1SAndroid Build Coastguard Worker void printerr(char *fmt, ...)
64*00c7fec1SAndroid Build Coastguard Worker {
65*00c7fec1SAndroid Build Coastguard Worker va_list ap;
66*00c7fec1SAndroid Build Coastguard Worker
67*00c7fec1SAndroid Build Coastguard Worker va_start(ap, fmt);
68*00c7fec1SAndroid Build Coastguard Worker vsnprintf(errmsg, sizeof(errmsg), fmt, ap);
69*00c7fec1SAndroid Build Coastguard Worker va_end(ap);
70*00c7fec1SAndroid Build Coastguard Worker
71*00c7fec1SAndroid Build Coastguard Worker ALOGD("%s", errmsg);
72*00c7fec1SAndroid Build Coastguard Worker }
73*00c7fec1SAndroid Build Coastguard Worker
dhcp_lasterror()74*00c7fec1SAndroid Build Coastguard Worker const char *dhcp_lasterror()
75*00c7fec1SAndroid Build Coastguard Worker {
76*00c7fec1SAndroid Build Coastguard Worker return errmsg;
77*00c7fec1SAndroid Build Coastguard Worker }
78*00c7fec1SAndroid Build Coastguard Worker
fatal(const char * reason)79*00c7fec1SAndroid Build Coastguard Worker int fatal(const char *reason)
80*00c7fec1SAndroid Build Coastguard Worker {
81*00c7fec1SAndroid Build Coastguard Worker printerr("%s: %s\n", reason, strerror(errno));
82*00c7fec1SAndroid Build Coastguard Worker return -1;
83*00c7fec1SAndroid Build Coastguard Worker // exit(1);
84*00c7fec1SAndroid Build Coastguard Worker }
85*00c7fec1SAndroid Build Coastguard Worker
ipaddr(in_addr_t addr)86*00c7fec1SAndroid Build Coastguard Worker const char *ipaddr(in_addr_t addr)
87*00c7fec1SAndroid Build Coastguard Worker {
88*00c7fec1SAndroid Build Coastguard Worker struct in_addr in_addr;
89*00c7fec1SAndroid Build Coastguard Worker
90*00c7fec1SAndroid Build Coastguard Worker in_addr.s_addr = addr;
91*00c7fec1SAndroid Build Coastguard Worker return inet_ntoa(in_addr);
92*00c7fec1SAndroid Build Coastguard Worker }
93*00c7fec1SAndroid Build Coastguard Worker
94*00c7fec1SAndroid Build Coastguard Worker extern int ipv4NetmaskToPrefixLength(in_addr_t mask);
95*00c7fec1SAndroid Build Coastguard Worker
96*00c7fec1SAndroid Build Coastguard Worker typedef struct dhcp_info dhcp_info;
97*00c7fec1SAndroid Build Coastguard Worker
98*00c7fec1SAndroid Build Coastguard Worker struct dhcp_info {
99*00c7fec1SAndroid Build Coastguard Worker uint32_t type;
100*00c7fec1SAndroid Build Coastguard Worker
101*00c7fec1SAndroid Build Coastguard Worker uint32_t ipaddr;
102*00c7fec1SAndroid Build Coastguard Worker uint32_t gateway;
103*00c7fec1SAndroid Build Coastguard Worker uint32_t prefixLength;
104*00c7fec1SAndroid Build Coastguard Worker
105*00c7fec1SAndroid Build Coastguard Worker uint32_t dns1;
106*00c7fec1SAndroid Build Coastguard Worker uint32_t dns2;
107*00c7fec1SAndroid Build Coastguard Worker
108*00c7fec1SAndroid Build Coastguard Worker uint32_t serveraddr;
109*00c7fec1SAndroid Build Coastguard Worker uint32_t lease;
110*00c7fec1SAndroid Build Coastguard Worker };
111*00c7fec1SAndroid Build Coastguard Worker
112*00c7fec1SAndroid Build Coastguard Worker dhcp_info last_good_info;
113*00c7fec1SAndroid Build Coastguard Worker
get_dhcp_info(uint32_t * ipaddr,uint32_t * gateway,uint32_t * prefixLength,uint32_t * dns1,uint32_t * dns2,uint32_t * server,uint32_t * lease)114*00c7fec1SAndroid Build Coastguard Worker void get_dhcp_info(uint32_t *ipaddr, uint32_t *gateway, uint32_t *prefixLength,
115*00c7fec1SAndroid Build Coastguard Worker uint32_t *dns1, uint32_t *dns2, uint32_t *server,
116*00c7fec1SAndroid Build Coastguard Worker uint32_t *lease)
117*00c7fec1SAndroid Build Coastguard Worker {
118*00c7fec1SAndroid Build Coastguard Worker *ipaddr = last_good_info.ipaddr;
119*00c7fec1SAndroid Build Coastguard Worker *gateway = last_good_info.gateway;
120*00c7fec1SAndroid Build Coastguard Worker *prefixLength = last_good_info.prefixLength;
121*00c7fec1SAndroid Build Coastguard Worker *dns1 = last_good_info.dns1;
122*00c7fec1SAndroid Build Coastguard Worker *dns2 = last_good_info.dns2;
123*00c7fec1SAndroid Build Coastguard Worker *server = last_good_info.serveraddr;
124*00c7fec1SAndroid Build Coastguard Worker *lease = last_good_info.lease;
125*00c7fec1SAndroid Build Coastguard Worker }
126*00c7fec1SAndroid Build Coastguard Worker
dhcp_configure(const char * ifname,dhcp_info * info)127*00c7fec1SAndroid Build Coastguard Worker static int dhcp_configure(const char *ifname, dhcp_info *info)
128*00c7fec1SAndroid Build Coastguard Worker {
129*00c7fec1SAndroid Build Coastguard Worker last_good_info = *info;
130*00c7fec1SAndroid Build Coastguard Worker return ifc_configure(ifname, info->ipaddr, info->prefixLength, info->gateway,
131*00c7fec1SAndroid Build Coastguard Worker info->dns1, info->dns2);
132*00c7fec1SAndroid Build Coastguard Worker }
133*00c7fec1SAndroid Build Coastguard Worker
dhcp_type_to_name(uint32_t type)134*00c7fec1SAndroid Build Coastguard Worker static const char *dhcp_type_to_name(uint32_t type)
135*00c7fec1SAndroid Build Coastguard Worker {
136*00c7fec1SAndroid Build Coastguard Worker switch(type) {
137*00c7fec1SAndroid Build Coastguard Worker case DHCPDISCOVER: return "discover";
138*00c7fec1SAndroid Build Coastguard Worker case DHCPOFFER: return "offer";
139*00c7fec1SAndroid Build Coastguard Worker case DHCPREQUEST: return "request";
140*00c7fec1SAndroid Build Coastguard Worker case DHCPDECLINE: return "decline";
141*00c7fec1SAndroid Build Coastguard Worker case DHCPACK: return "ack";
142*00c7fec1SAndroid Build Coastguard Worker case DHCPNAK: return "nak";
143*00c7fec1SAndroid Build Coastguard Worker case DHCPRELEASE: return "release";
144*00c7fec1SAndroid Build Coastguard Worker case DHCPINFORM: return "inform";
145*00c7fec1SAndroid Build Coastguard Worker default: return "???";
146*00c7fec1SAndroid Build Coastguard Worker }
147*00c7fec1SAndroid Build Coastguard Worker }
148*00c7fec1SAndroid Build Coastguard Worker
dump_dhcp_info(dhcp_info * info)149*00c7fec1SAndroid Build Coastguard Worker void dump_dhcp_info(dhcp_info *info)
150*00c7fec1SAndroid Build Coastguard Worker {
151*00c7fec1SAndroid Build Coastguard Worker char addr[20], gway[20];
152*00c7fec1SAndroid Build Coastguard Worker ALOGD("--- dhcp %s (%d) ---",
153*00c7fec1SAndroid Build Coastguard Worker dhcp_type_to_name(info->type), info->type);
154*00c7fec1SAndroid Build Coastguard Worker strcpy(addr, ipaddr(info->ipaddr));
155*00c7fec1SAndroid Build Coastguard Worker strcpy(gway, ipaddr(info->gateway));
156*00c7fec1SAndroid Build Coastguard Worker ALOGD("ip %s gw %s prefixLength %d", addr, gway, info->prefixLength);
157*00c7fec1SAndroid Build Coastguard Worker if (info->dns1) ALOGD("dns1: %s", ipaddr(info->dns1));
158*00c7fec1SAndroid Build Coastguard Worker if (info->dns2) ALOGD("dns2: %s", ipaddr(info->dns2));
159*00c7fec1SAndroid Build Coastguard Worker ALOGD("server %s, lease %d seconds",
160*00c7fec1SAndroid Build Coastguard Worker ipaddr(info->serveraddr), info->lease);
161*00c7fec1SAndroid Build Coastguard Worker }
162*00c7fec1SAndroid Build Coastguard Worker
163*00c7fec1SAndroid Build Coastguard Worker
decode_dhcp_msg(dhcp_msg * msg,int len,dhcp_info * info)164*00c7fec1SAndroid Build Coastguard Worker int decode_dhcp_msg(dhcp_msg *msg, int len, dhcp_info *info)
165*00c7fec1SAndroid Build Coastguard Worker {
166*00c7fec1SAndroid Build Coastguard Worker uint8_t *x;
167*00c7fec1SAndroid Build Coastguard Worker unsigned int opt;
168*00c7fec1SAndroid Build Coastguard Worker int optlen;
169*00c7fec1SAndroid Build Coastguard Worker
170*00c7fec1SAndroid Build Coastguard Worker memset(info, 0, sizeof(dhcp_info));
171*00c7fec1SAndroid Build Coastguard Worker if (len < (DHCP_MSG_FIXED_SIZE + 4)) return -1;
172*00c7fec1SAndroid Build Coastguard Worker
173*00c7fec1SAndroid Build Coastguard Worker len -= (DHCP_MSG_FIXED_SIZE + 4);
174*00c7fec1SAndroid Build Coastguard Worker
175*00c7fec1SAndroid Build Coastguard Worker if (msg->options[0] != OPT_COOKIE1) return -1;
176*00c7fec1SAndroid Build Coastguard Worker if (msg->options[1] != OPT_COOKIE2) return -1;
177*00c7fec1SAndroid Build Coastguard Worker if (msg->options[2] != OPT_COOKIE3) return -1;
178*00c7fec1SAndroid Build Coastguard Worker if (msg->options[3] != OPT_COOKIE4) return -1;
179*00c7fec1SAndroid Build Coastguard Worker
180*00c7fec1SAndroid Build Coastguard Worker x = msg->options + 4;
181*00c7fec1SAndroid Build Coastguard Worker
182*00c7fec1SAndroid Build Coastguard Worker while (len > 2) {
183*00c7fec1SAndroid Build Coastguard Worker opt = *x++;
184*00c7fec1SAndroid Build Coastguard Worker if (opt == OPT_PAD) {
185*00c7fec1SAndroid Build Coastguard Worker len--;
186*00c7fec1SAndroid Build Coastguard Worker continue;
187*00c7fec1SAndroid Build Coastguard Worker }
188*00c7fec1SAndroid Build Coastguard Worker if (opt == OPT_END) {
189*00c7fec1SAndroid Build Coastguard Worker break;
190*00c7fec1SAndroid Build Coastguard Worker }
191*00c7fec1SAndroid Build Coastguard Worker optlen = *x++;
192*00c7fec1SAndroid Build Coastguard Worker len -= 2;
193*00c7fec1SAndroid Build Coastguard Worker if (optlen > len) {
194*00c7fec1SAndroid Build Coastguard Worker break;
195*00c7fec1SAndroid Build Coastguard Worker }
196*00c7fec1SAndroid Build Coastguard Worker switch(opt) {
197*00c7fec1SAndroid Build Coastguard Worker case OPT_SUBNET_MASK:
198*00c7fec1SAndroid Build Coastguard Worker if (optlen >= 4) {
199*00c7fec1SAndroid Build Coastguard Worker in_addr_t mask;
200*00c7fec1SAndroid Build Coastguard Worker memcpy(&mask, x, 4);
201*00c7fec1SAndroid Build Coastguard Worker info->prefixLength = ipv4NetmaskToPrefixLength(mask);
202*00c7fec1SAndroid Build Coastguard Worker }
203*00c7fec1SAndroid Build Coastguard Worker break;
204*00c7fec1SAndroid Build Coastguard Worker case OPT_GATEWAY:
205*00c7fec1SAndroid Build Coastguard Worker if (optlen >= 4) memcpy(&info->gateway, x, 4);
206*00c7fec1SAndroid Build Coastguard Worker break;
207*00c7fec1SAndroid Build Coastguard Worker case OPT_DNS:
208*00c7fec1SAndroid Build Coastguard Worker if (optlen >= 4) memcpy(&info->dns1, x + 0, 4);
209*00c7fec1SAndroid Build Coastguard Worker if (optlen >= 8) memcpy(&info->dns2, x + 4, 4);
210*00c7fec1SAndroid Build Coastguard Worker break;
211*00c7fec1SAndroid Build Coastguard Worker case OPT_LEASE_TIME:
212*00c7fec1SAndroid Build Coastguard Worker if (optlen >= 4) {
213*00c7fec1SAndroid Build Coastguard Worker memcpy(&info->lease, x, 4);
214*00c7fec1SAndroid Build Coastguard Worker info->lease = ntohl(info->lease);
215*00c7fec1SAndroid Build Coastguard Worker }
216*00c7fec1SAndroid Build Coastguard Worker break;
217*00c7fec1SAndroid Build Coastguard Worker case OPT_SERVER_ID:
218*00c7fec1SAndroid Build Coastguard Worker if (optlen >= 4) memcpy(&info->serveraddr, x, 4);
219*00c7fec1SAndroid Build Coastguard Worker break;
220*00c7fec1SAndroid Build Coastguard Worker case OPT_MESSAGE_TYPE:
221*00c7fec1SAndroid Build Coastguard Worker info->type = *x;
222*00c7fec1SAndroid Build Coastguard Worker break;
223*00c7fec1SAndroid Build Coastguard Worker default:
224*00c7fec1SAndroid Build Coastguard Worker break;
225*00c7fec1SAndroid Build Coastguard Worker }
226*00c7fec1SAndroid Build Coastguard Worker x += optlen;
227*00c7fec1SAndroid Build Coastguard Worker len -= optlen;
228*00c7fec1SAndroid Build Coastguard Worker }
229*00c7fec1SAndroid Build Coastguard Worker
230*00c7fec1SAndroid Build Coastguard Worker info->ipaddr = msg->yiaddr;
231*00c7fec1SAndroid Build Coastguard Worker
232*00c7fec1SAndroid Build Coastguard Worker return 0;
233*00c7fec1SAndroid Build Coastguard Worker }
234*00c7fec1SAndroid Build Coastguard Worker
235*00c7fec1SAndroid Build Coastguard Worker #if VERBOSE
236*00c7fec1SAndroid Build Coastguard Worker
hex2str(char * buf,size_t buf_size,const unsigned char * array,int len)237*00c7fec1SAndroid Build Coastguard Worker static void hex2str(char *buf, size_t buf_size, const unsigned char *array, int len)
238*00c7fec1SAndroid Build Coastguard Worker {
239*00c7fec1SAndroid Build Coastguard Worker int i;
240*00c7fec1SAndroid Build Coastguard Worker char *cp = buf;
241*00c7fec1SAndroid Build Coastguard Worker char *buf_end = buf + buf_size;
242*00c7fec1SAndroid Build Coastguard Worker for (i = 0; i < len; i++) {
243*00c7fec1SAndroid Build Coastguard Worker cp += snprintf(cp, buf_end - cp, " %02x ", array[i]);
244*00c7fec1SAndroid Build Coastguard Worker }
245*00c7fec1SAndroid Build Coastguard Worker }
246*00c7fec1SAndroid Build Coastguard Worker
dump_dhcp_msg(dhcp_msg * msg,int len)247*00c7fec1SAndroid Build Coastguard Worker void dump_dhcp_msg(dhcp_msg *msg, int len)
248*00c7fec1SAndroid Build Coastguard Worker {
249*00c7fec1SAndroid Build Coastguard Worker unsigned char *x;
250*00c7fec1SAndroid Build Coastguard Worker unsigned int n,c;
251*00c7fec1SAndroid Build Coastguard Worker int optsz;
252*00c7fec1SAndroid Build Coastguard Worker const char *name;
253*00c7fec1SAndroid Build Coastguard Worker char buf[2048];
254*00c7fec1SAndroid Build Coastguard Worker
255*00c7fec1SAndroid Build Coastguard Worker ALOGD("===== DHCP message:");
256*00c7fec1SAndroid Build Coastguard Worker if (len < DHCP_MSG_FIXED_SIZE) {
257*00c7fec1SAndroid Build Coastguard Worker ALOGD("Invalid length %d, should be %d", len, DHCP_MSG_FIXED_SIZE);
258*00c7fec1SAndroid Build Coastguard Worker return;
259*00c7fec1SAndroid Build Coastguard Worker }
260*00c7fec1SAndroid Build Coastguard Worker
261*00c7fec1SAndroid Build Coastguard Worker len -= DHCP_MSG_FIXED_SIZE;
262*00c7fec1SAndroid Build Coastguard Worker
263*00c7fec1SAndroid Build Coastguard Worker if (msg->op == OP_BOOTREQUEST)
264*00c7fec1SAndroid Build Coastguard Worker name = "BOOTREQUEST";
265*00c7fec1SAndroid Build Coastguard Worker else if (msg->op == OP_BOOTREPLY)
266*00c7fec1SAndroid Build Coastguard Worker name = "BOOTREPLY";
267*00c7fec1SAndroid Build Coastguard Worker else
268*00c7fec1SAndroid Build Coastguard Worker name = "????";
269*00c7fec1SAndroid Build Coastguard Worker ALOGD("op = %s (%d), htype = %d, hlen = %d, hops = %d",
270*00c7fec1SAndroid Build Coastguard Worker name, msg->op, msg->htype, msg->hlen, msg->hops);
271*00c7fec1SAndroid Build Coastguard Worker ALOGD("xid = 0x%08x secs = %d, flags = 0x%04x optlen = %d",
272*00c7fec1SAndroid Build Coastguard Worker ntohl(msg->xid), ntohs(msg->secs), ntohs(msg->flags), len);
273*00c7fec1SAndroid Build Coastguard Worker ALOGD("ciaddr = %s", ipaddr(msg->ciaddr));
274*00c7fec1SAndroid Build Coastguard Worker ALOGD("yiaddr = %s", ipaddr(msg->yiaddr));
275*00c7fec1SAndroid Build Coastguard Worker ALOGD("siaddr = %s", ipaddr(msg->siaddr));
276*00c7fec1SAndroid Build Coastguard Worker ALOGD("giaddr = %s", ipaddr(msg->giaddr));
277*00c7fec1SAndroid Build Coastguard Worker
278*00c7fec1SAndroid Build Coastguard Worker c = msg->hlen > 16 ? 16 : msg->hlen;
279*00c7fec1SAndroid Build Coastguard Worker hex2str(buf, sizeof(buf), msg->chaddr, c);
280*00c7fec1SAndroid Build Coastguard Worker ALOGD("chaddr = {%s}", buf);
281*00c7fec1SAndroid Build Coastguard Worker
282*00c7fec1SAndroid Build Coastguard Worker for (n = 0; n < 64; n++) {
283*00c7fec1SAndroid Build Coastguard Worker unsigned char x = msg->sname[n];
284*00c7fec1SAndroid Build Coastguard Worker if ((x < ' ') || (x > 127)) {
285*00c7fec1SAndroid Build Coastguard Worker if (x == 0) break;
286*00c7fec1SAndroid Build Coastguard Worker msg->sname[n] = '.';
287*00c7fec1SAndroid Build Coastguard Worker }
288*00c7fec1SAndroid Build Coastguard Worker }
289*00c7fec1SAndroid Build Coastguard Worker msg->sname[63] = 0;
290*00c7fec1SAndroid Build Coastguard Worker
291*00c7fec1SAndroid Build Coastguard Worker for (n = 0; n < 128; n++) {
292*00c7fec1SAndroid Build Coastguard Worker unsigned char x = msg->file[n];
293*00c7fec1SAndroid Build Coastguard Worker if ((x < ' ') || (x > 127)) {
294*00c7fec1SAndroid Build Coastguard Worker if (x == 0) break;
295*00c7fec1SAndroid Build Coastguard Worker msg->file[n] = '.';
296*00c7fec1SAndroid Build Coastguard Worker }
297*00c7fec1SAndroid Build Coastguard Worker }
298*00c7fec1SAndroid Build Coastguard Worker msg->file[127] = 0;
299*00c7fec1SAndroid Build Coastguard Worker
300*00c7fec1SAndroid Build Coastguard Worker ALOGD("sname = '%s'", msg->sname);
301*00c7fec1SAndroid Build Coastguard Worker ALOGD("file = '%s'", msg->file);
302*00c7fec1SAndroid Build Coastguard Worker
303*00c7fec1SAndroid Build Coastguard Worker if (len < 4) return;
304*00c7fec1SAndroid Build Coastguard Worker len -= 4;
305*00c7fec1SAndroid Build Coastguard Worker x = msg->options + 4;
306*00c7fec1SAndroid Build Coastguard Worker
307*00c7fec1SAndroid Build Coastguard Worker while (len > 2) {
308*00c7fec1SAndroid Build Coastguard Worker if (*x == 0) {
309*00c7fec1SAndroid Build Coastguard Worker x++;
310*00c7fec1SAndroid Build Coastguard Worker len--;
311*00c7fec1SAndroid Build Coastguard Worker continue;
312*00c7fec1SAndroid Build Coastguard Worker }
313*00c7fec1SAndroid Build Coastguard Worker if (*x == OPT_END) {
314*00c7fec1SAndroid Build Coastguard Worker break;
315*00c7fec1SAndroid Build Coastguard Worker }
316*00c7fec1SAndroid Build Coastguard Worker len -= 2;
317*00c7fec1SAndroid Build Coastguard Worker optsz = x[1];
318*00c7fec1SAndroid Build Coastguard Worker if (optsz > len) break;
319*00c7fec1SAndroid Build Coastguard Worker if (x[0] == OPT_DOMAIN_NAME || x[0] == OPT_MESSAGE) {
320*00c7fec1SAndroid Build Coastguard Worker if ((unsigned int)optsz < sizeof(buf) - 1) {
321*00c7fec1SAndroid Build Coastguard Worker n = optsz;
322*00c7fec1SAndroid Build Coastguard Worker } else {
323*00c7fec1SAndroid Build Coastguard Worker n = sizeof(buf) - 1;
324*00c7fec1SAndroid Build Coastguard Worker }
325*00c7fec1SAndroid Build Coastguard Worker memcpy(buf, &x[2], n);
326*00c7fec1SAndroid Build Coastguard Worker buf[n] = '\0';
327*00c7fec1SAndroid Build Coastguard Worker } else {
328*00c7fec1SAndroid Build Coastguard Worker hex2str(buf, sizeof(buf), &x[2], optsz);
329*00c7fec1SAndroid Build Coastguard Worker }
330*00c7fec1SAndroid Build Coastguard Worker if (x[0] == OPT_MESSAGE_TYPE)
331*00c7fec1SAndroid Build Coastguard Worker name = dhcp_type_to_name(x[2]);
332*00c7fec1SAndroid Build Coastguard Worker else
333*00c7fec1SAndroid Build Coastguard Worker name = NULL;
334*00c7fec1SAndroid Build Coastguard Worker ALOGD("op %d len %d {%s} %s", x[0], optsz, buf, name == NULL ? "" : name);
335*00c7fec1SAndroid Build Coastguard Worker len -= optsz;
336*00c7fec1SAndroid Build Coastguard Worker x = x + optsz + 2;
337*00c7fec1SAndroid Build Coastguard Worker }
338*00c7fec1SAndroid Build Coastguard Worker }
339*00c7fec1SAndroid Build Coastguard Worker
340*00c7fec1SAndroid Build Coastguard Worker #endif
341*00c7fec1SAndroid Build Coastguard Worker
send_message(int sock,int if_index,dhcp_msg * msg,int size)342*00c7fec1SAndroid Build Coastguard Worker static int send_message(int sock, int if_index, dhcp_msg *msg, int size)
343*00c7fec1SAndroid Build Coastguard Worker {
344*00c7fec1SAndroid Build Coastguard Worker #if VERBOSE > 1
345*00c7fec1SAndroid Build Coastguard Worker dump_dhcp_msg(msg, size);
346*00c7fec1SAndroid Build Coastguard Worker #endif
347*00c7fec1SAndroid Build Coastguard Worker return send_packet(sock, if_index, msg, size, INADDR_ANY, INADDR_BROADCAST,
348*00c7fec1SAndroid Build Coastguard Worker PORT_BOOTP_CLIENT, PORT_BOOTP_SERVER);
349*00c7fec1SAndroid Build Coastguard Worker }
350*00c7fec1SAndroid Build Coastguard Worker
is_valid_reply(dhcp_msg * msg,dhcp_msg * reply,int sz)351*00c7fec1SAndroid Build Coastguard Worker static int is_valid_reply(dhcp_msg *msg, dhcp_msg *reply, int sz)
352*00c7fec1SAndroid Build Coastguard Worker {
353*00c7fec1SAndroid Build Coastguard Worker if (sz < DHCP_MSG_FIXED_SIZE) {
354*00c7fec1SAndroid Build Coastguard Worker if (verbose) ALOGD("Wrong size %d != %d\n", sz, DHCP_MSG_FIXED_SIZE);
355*00c7fec1SAndroid Build Coastguard Worker return 0;
356*00c7fec1SAndroid Build Coastguard Worker }
357*00c7fec1SAndroid Build Coastguard Worker if (reply->op != OP_BOOTREPLY) {
358*00c7fec1SAndroid Build Coastguard Worker if (verbose) ALOGD("Wrong Op %d != %d\n", reply->op, OP_BOOTREPLY);
359*00c7fec1SAndroid Build Coastguard Worker return 0;
360*00c7fec1SAndroid Build Coastguard Worker }
361*00c7fec1SAndroid Build Coastguard Worker if (reply->xid != msg->xid) {
362*00c7fec1SAndroid Build Coastguard Worker if (verbose) ALOGD("Wrong Xid 0x%x != 0x%x\n", ntohl(reply->xid),
363*00c7fec1SAndroid Build Coastguard Worker ntohl(msg->xid));
364*00c7fec1SAndroid Build Coastguard Worker return 0;
365*00c7fec1SAndroid Build Coastguard Worker }
366*00c7fec1SAndroid Build Coastguard Worker if (reply->htype != msg->htype) {
367*00c7fec1SAndroid Build Coastguard Worker if (verbose) ALOGD("Wrong Htype %d != %d\n", reply->htype, msg->htype);
368*00c7fec1SAndroid Build Coastguard Worker return 0;
369*00c7fec1SAndroid Build Coastguard Worker }
370*00c7fec1SAndroid Build Coastguard Worker if (reply->hlen != msg->hlen) {
371*00c7fec1SAndroid Build Coastguard Worker if (verbose) ALOGD("Wrong Hlen %d != %d\n", reply->hlen, msg->hlen);
372*00c7fec1SAndroid Build Coastguard Worker return 0;
373*00c7fec1SAndroid Build Coastguard Worker }
374*00c7fec1SAndroid Build Coastguard Worker if (memcmp(msg->chaddr, reply->chaddr, msg->hlen)) {
375*00c7fec1SAndroid Build Coastguard Worker if (verbose) ALOGD("Wrong chaddr %x != %x\n", *(reply->chaddr),*(msg->chaddr));
376*00c7fec1SAndroid Build Coastguard Worker return 0;
377*00c7fec1SAndroid Build Coastguard Worker }
378*00c7fec1SAndroid Build Coastguard Worker return 1;
379*00c7fec1SAndroid Build Coastguard Worker }
380*00c7fec1SAndroid Build Coastguard Worker
381*00c7fec1SAndroid Build Coastguard Worker #define STATE_SELECTING 1
382*00c7fec1SAndroid Build Coastguard Worker #define STATE_REQUESTING 2
383*00c7fec1SAndroid Build Coastguard Worker
384*00c7fec1SAndroid Build Coastguard Worker #define TIMEOUT_INITIAL 4000
385*00c7fec1SAndroid Build Coastguard Worker #define TIMEOUT_MAX 32000
386*00c7fec1SAndroid Build Coastguard Worker
dhcp_init_ifc(const char * ifname)387*00c7fec1SAndroid Build Coastguard Worker int dhcp_init_ifc(const char *ifname)
388*00c7fec1SAndroid Build Coastguard Worker {
389*00c7fec1SAndroid Build Coastguard Worker dhcp_msg discover_msg;
390*00c7fec1SAndroid Build Coastguard Worker dhcp_msg request_msg;
391*00c7fec1SAndroid Build Coastguard Worker dhcp_msg reply;
392*00c7fec1SAndroid Build Coastguard Worker dhcp_msg *msg;
393*00c7fec1SAndroid Build Coastguard Worker dhcp_info info;
394*00c7fec1SAndroid Build Coastguard Worker int s, r, size;
395*00c7fec1SAndroid Build Coastguard Worker int valid_reply;
396*00c7fec1SAndroid Build Coastguard Worker uint32_t xid;
397*00c7fec1SAndroid Build Coastguard Worker unsigned char hwaddr[6];
398*00c7fec1SAndroid Build Coastguard Worker struct pollfd pfd;
399*00c7fec1SAndroid Build Coastguard Worker unsigned int state;
400*00c7fec1SAndroid Build Coastguard Worker unsigned int timeout;
401*00c7fec1SAndroid Build Coastguard Worker int if_index;
402*00c7fec1SAndroid Build Coastguard Worker
403*00c7fec1SAndroid Build Coastguard Worker xid = (uint32_t) get_msecs();
404*00c7fec1SAndroid Build Coastguard Worker
405*00c7fec1SAndroid Build Coastguard Worker if (ifc_get_hwaddr(ifname, hwaddr)) {
406*00c7fec1SAndroid Build Coastguard Worker return fatal("cannot obtain interface address");
407*00c7fec1SAndroid Build Coastguard Worker }
408*00c7fec1SAndroid Build Coastguard Worker if (ifc_get_ifindex(ifname, &if_index)) {
409*00c7fec1SAndroid Build Coastguard Worker return fatal("cannot obtain interface index");
410*00c7fec1SAndroid Build Coastguard Worker }
411*00c7fec1SAndroid Build Coastguard Worker
412*00c7fec1SAndroid Build Coastguard Worker s = open_raw_socket(ifname, hwaddr, if_index);
413*00c7fec1SAndroid Build Coastguard Worker
414*00c7fec1SAndroid Build Coastguard Worker timeout = TIMEOUT_INITIAL;
415*00c7fec1SAndroid Build Coastguard Worker state = STATE_SELECTING;
416*00c7fec1SAndroid Build Coastguard Worker info.type = 0;
417*00c7fec1SAndroid Build Coastguard Worker goto transmit;
418*00c7fec1SAndroid Build Coastguard Worker
419*00c7fec1SAndroid Build Coastguard Worker for (;;) {
420*00c7fec1SAndroid Build Coastguard Worker pfd.fd = s;
421*00c7fec1SAndroid Build Coastguard Worker pfd.events = POLLIN;
422*00c7fec1SAndroid Build Coastguard Worker pfd.revents = 0;
423*00c7fec1SAndroid Build Coastguard Worker r = poll(&pfd, 1, timeout);
424*00c7fec1SAndroid Build Coastguard Worker
425*00c7fec1SAndroid Build Coastguard Worker if (r == 0) {
426*00c7fec1SAndroid Build Coastguard Worker #if VERBOSE
427*00c7fec1SAndroid Build Coastguard Worker printerr("TIMEOUT\n");
428*00c7fec1SAndroid Build Coastguard Worker #endif
429*00c7fec1SAndroid Build Coastguard Worker if (timeout >= TIMEOUT_MAX) {
430*00c7fec1SAndroid Build Coastguard Worker printerr("timed out\n");
431*00c7fec1SAndroid Build Coastguard Worker if ( info.type == DHCPOFFER ) {
432*00c7fec1SAndroid Build Coastguard Worker printerr("no acknowledgement from DHCP server\nconfiguring %s with offered parameters\n", ifname);
433*00c7fec1SAndroid Build Coastguard Worker return dhcp_configure(ifname, &info);
434*00c7fec1SAndroid Build Coastguard Worker }
435*00c7fec1SAndroid Build Coastguard Worker errno = ETIME;
436*00c7fec1SAndroid Build Coastguard Worker close(s);
437*00c7fec1SAndroid Build Coastguard Worker return -1;
438*00c7fec1SAndroid Build Coastguard Worker }
439*00c7fec1SAndroid Build Coastguard Worker timeout = timeout * 2;
440*00c7fec1SAndroid Build Coastguard Worker
441*00c7fec1SAndroid Build Coastguard Worker transmit:
442*00c7fec1SAndroid Build Coastguard Worker size = 0;
443*00c7fec1SAndroid Build Coastguard Worker msg = NULL;
444*00c7fec1SAndroid Build Coastguard Worker switch(state) {
445*00c7fec1SAndroid Build Coastguard Worker case STATE_SELECTING:
446*00c7fec1SAndroid Build Coastguard Worker msg = &discover_msg;
447*00c7fec1SAndroid Build Coastguard Worker size = init_dhcp_discover_msg(msg, hwaddr, xid);
448*00c7fec1SAndroid Build Coastguard Worker break;
449*00c7fec1SAndroid Build Coastguard Worker case STATE_REQUESTING:
450*00c7fec1SAndroid Build Coastguard Worker msg = &request_msg;
451*00c7fec1SAndroid Build Coastguard Worker size = init_dhcp_request_msg(msg, hwaddr, xid, info.ipaddr, info.serveraddr);
452*00c7fec1SAndroid Build Coastguard Worker break;
453*00c7fec1SAndroid Build Coastguard Worker default:
454*00c7fec1SAndroid Build Coastguard Worker r = 0;
455*00c7fec1SAndroid Build Coastguard Worker }
456*00c7fec1SAndroid Build Coastguard Worker if (size != 0) {
457*00c7fec1SAndroid Build Coastguard Worker r = send_message(s, if_index, msg, size);
458*00c7fec1SAndroid Build Coastguard Worker if (r < 0) {
459*00c7fec1SAndroid Build Coastguard Worker printerr("error sending dhcp msg: %s\n", strerror(errno));
460*00c7fec1SAndroid Build Coastguard Worker }
461*00c7fec1SAndroid Build Coastguard Worker }
462*00c7fec1SAndroid Build Coastguard Worker continue;
463*00c7fec1SAndroid Build Coastguard Worker }
464*00c7fec1SAndroid Build Coastguard Worker
465*00c7fec1SAndroid Build Coastguard Worker if (r < 0) {
466*00c7fec1SAndroid Build Coastguard Worker if ((errno == EAGAIN) || (errno == EINTR)) {
467*00c7fec1SAndroid Build Coastguard Worker continue;
468*00c7fec1SAndroid Build Coastguard Worker }
469*00c7fec1SAndroid Build Coastguard Worker return fatal("poll failed");
470*00c7fec1SAndroid Build Coastguard Worker }
471*00c7fec1SAndroid Build Coastguard Worker
472*00c7fec1SAndroid Build Coastguard Worker errno = 0;
473*00c7fec1SAndroid Build Coastguard Worker r = receive_packet(s, &reply);
474*00c7fec1SAndroid Build Coastguard Worker if (r < 0) {
475*00c7fec1SAndroid Build Coastguard Worker if (errno != 0) {
476*00c7fec1SAndroid Build Coastguard Worker ALOGD("receive_packet failed (%d): %s", r, strerror(errno));
477*00c7fec1SAndroid Build Coastguard Worker if (errno == ENETDOWN || errno == ENXIO) {
478*00c7fec1SAndroid Build Coastguard Worker return -1;
479*00c7fec1SAndroid Build Coastguard Worker }
480*00c7fec1SAndroid Build Coastguard Worker }
481*00c7fec1SAndroid Build Coastguard Worker continue;
482*00c7fec1SAndroid Build Coastguard Worker }
483*00c7fec1SAndroid Build Coastguard Worker
484*00c7fec1SAndroid Build Coastguard Worker #if VERBOSE > 1
485*00c7fec1SAndroid Build Coastguard Worker dump_dhcp_msg(&reply, r);
486*00c7fec1SAndroid Build Coastguard Worker #endif
487*00c7fec1SAndroid Build Coastguard Worker decode_dhcp_msg(&reply, r, &info);
488*00c7fec1SAndroid Build Coastguard Worker
489*00c7fec1SAndroid Build Coastguard Worker if (state == STATE_SELECTING) {
490*00c7fec1SAndroid Build Coastguard Worker valid_reply = is_valid_reply(&discover_msg, &reply, r);
491*00c7fec1SAndroid Build Coastguard Worker } else {
492*00c7fec1SAndroid Build Coastguard Worker valid_reply = is_valid_reply(&request_msg, &reply, r);
493*00c7fec1SAndroid Build Coastguard Worker }
494*00c7fec1SAndroid Build Coastguard Worker if (!valid_reply) {
495*00c7fec1SAndroid Build Coastguard Worker printerr("invalid reply\n");
496*00c7fec1SAndroid Build Coastguard Worker continue;
497*00c7fec1SAndroid Build Coastguard Worker }
498*00c7fec1SAndroid Build Coastguard Worker
499*00c7fec1SAndroid Build Coastguard Worker if (verbose) dump_dhcp_info(&info);
500*00c7fec1SAndroid Build Coastguard Worker
501*00c7fec1SAndroid Build Coastguard Worker switch(state) {
502*00c7fec1SAndroid Build Coastguard Worker case STATE_SELECTING:
503*00c7fec1SAndroid Build Coastguard Worker if (info.type == DHCPOFFER) {
504*00c7fec1SAndroid Build Coastguard Worker state = STATE_REQUESTING;
505*00c7fec1SAndroid Build Coastguard Worker timeout = TIMEOUT_INITIAL;
506*00c7fec1SAndroid Build Coastguard Worker xid++;
507*00c7fec1SAndroid Build Coastguard Worker goto transmit;
508*00c7fec1SAndroid Build Coastguard Worker }
509*00c7fec1SAndroid Build Coastguard Worker break;
510*00c7fec1SAndroid Build Coastguard Worker case STATE_REQUESTING:
511*00c7fec1SAndroid Build Coastguard Worker if (info.type == DHCPACK) {
512*00c7fec1SAndroid Build Coastguard Worker printerr("configuring %s\n", ifname);
513*00c7fec1SAndroid Build Coastguard Worker close(s);
514*00c7fec1SAndroid Build Coastguard Worker return dhcp_configure(ifname, &info);
515*00c7fec1SAndroid Build Coastguard Worker } else if (info.type == DHCPNAK) {
516*00c7fec1SAndroid Build Coastguard Worker printerr("configuration request denied\n");
517*00c7fec1SAndroid Build Coastguard Worker close(s);
518*00c7fec1SAndroid Build Coastguard Worker return -1;
519*00c7fec1SAndroid Build Coastguard Worker } else {
520*00c7fec1SAndroid Build Coastguard Worker printerr("ignoring %s message in state %d\n",
521*00c7fec1SAndroid Build Coastguard Worker dhcp_type_to_name(info.type), state);
522*00c7fec1SAndroid Build Coastguard Worker }
523*00c7fec1SAndroid Build Coastguard Worker break;
524*00c7fec1SAndroid Build Coastguard Worker }
525*00c7fec1SAndroid Build Coastguard Worker }
526*00c7fec1SAndroid Build Coastguard Worker close(s);
527*00c7fec1SAndroid Build Coastguard Worker return 0;
528*00c7fec1SAndroid Build Coastguard Worker }
529*00c7fec1SAndroid Build Coastguard Worker
do_dhcp(char * iname)530*00c7fec1SAndroid Build Coastguard Worker int do_dhcp(char *iname)
531*00c7fec1SAndroid Build Coastguard Worker {
532*00c7fec1SAndroid Build Coastguard Worker if (ifc_set_addr(iname, 0)) {
533*00c7fec1SAndroid Build Coastguard Worker printerr("failed to set ip addr for %s to 0.0.0.0: %s\n", iname, strerror(errno));
534*00c7fec1SAndroid Build Coastguard Worker return -1;
535*00c7fec1SAndroid Build Coastguard Worker }
536*00c7fec1SAndroid Build Coastguard Worker
537*00c7fec1SAndroid Build Coastguard Worker if (ifc_up(iname)) {
538*00c7fec1SAndroid Build Coastguard Worker printerr("failed to bring up interface %s: %s\n", iname, strerror(errno));
539*00c7fec1SAndroid Build Coastguard Worker return -1;
540*00c7fec1SAndroid Build Coastguard Worker }
541*00c7fec1SAndroid Build Coastguard Worker
542*00c7fec1SAndroid Build Coastguard Worker return dhcp_init_ifc(iname);
543*00c7fec1SAndroid Build Coastguard Worker }
544