xref: /aosp_15_r20/external/toybox/toys/pending/dhcp.c (revision cf5a6c84e2b8763fc1a7db14496fd4742913b199)
1*cf5a6c84SAndroid Build Coastguard Worker /* dhcp.c - DHCP client for dynamic network configuration.
2*cf5a6c84SAndroid Build Coastguard Worker  *
3*cf5a6c84SAndroid Build Coastguard Worker  * Copyright 2012 Madhur Verma <[email protected]>
4*cf5a6c84SAndroid Build Coastguard Worker  * Copyright 2013 Kyungwan Han <[email protected]>
5*cf5a6c84SAndroid Build Coastguard Worker  *
6*cf5a6c84SAndroid Build Coastguard Worker  * See RFC 2132, and 3442 (option 121)
7*cf5a6c84SAndroid Build Coastguard Worker 
8*cf5a6c84SAndroid Build Coastguard Worker USE_DHCP(NEWTOY(dhcp, "V:H:F:x*r:O*A#<0=20T#<0=3t#<0=3s:p:i:SBRCaovqnbf", TOYFLAG_SBIN|TOYFLAG_ROOTONLY))
9*cf5a6c84SAndroid Build Coastguard Worker 
10*cf5a6c84SAndroid Build Coastguard Worker config DHCP
11*cf5a6c84SAndroid Build Coastguard Worker   bool "dhcp"
12*cf5a6c84SAndroid Build Coastguard Worker   default n
13*cf5a6c84SAndroid Build Coastguard Worker   help
14*cf5a6c84SAndroid Build Coastguard Worker    usage: dhcp [-fbnqvoCRB] [-i IFACE] [-r IP] [-s PROG] [-p PIDFILE]
15*cf5a6c84SAndroid Build Coastguard Worker                [-H HOSTNAME] [-V VENDOR] [-x OPT:VAL] [-O OPT]
16*cf5a6c84SAndroid Build Coastguard Worker 
17*cf5a6c84SAndroid Build Coastguard Worker         Configure network dynamically using DHCP.
18*cf5a6c84SAndroid Build Coastguard Worker 
19*cf5a6c84SAndroid Build Coastguard Worker       -i Interface to use (default eth0)
20*cf5a6c84SAndroid Build Coastguard Worker       -p Create pidfile
21*cf5a6c84SAndroid Build Coastguard Worker       -s Run PROG at DHCP events (default /usr/share/dhcp/default.script)
22*cf5a6c84SAndroid Build Coastguard Worker       -B Request broadcast replies
23*cf5a6c84SAndroid Build Coastguard Worker       -t Send up to N discover packets
24*cf5a6c84SAndroid Build Coastguard Worker       -T Pause between packets (default 3 seconds)
25*cf5a6c84SAndroid Build Coastguard Worker       -A Wait N seconds after failure (default 20)
26*cf5a6c84SAndroid Build Coastguard Worker       -f Run in foreground
27*cf5a6c84SAndroid Build Coastguard Worker       -b Background if lease is not obtained
28*cf5a6c84SAndroid Build Coastguard Worker       -n Exit if lease is not obtained
29*cf5a6c84SAndroid Build Coastguard Worker       -q Exit after obtaining lease
30*cf5a6c84SAndroid Build Coastguard Worker       -R Release IP on exit
31*cf5a6c84SAndroid Build Coastguard Worker       -S Log to syslog too
32*cf5a6c84SAndroid Build Coastguard Worker       -a Use arping to validate offered address
33*cf5a6c84SAndroid Build Coastguard Worker       -O Request option OPT from server (cumulative)
34*cf5a6c84SAndroid Build Coastguard Worker       -o Don't request any options (unless -O is given)
35*cf5a6c84SAndroid Build Coastguard Worker       -r Request this IP address
36*cf5a6c84SAndroid Build Coastguard Worker       -x OPT:VAL  Include option OPT in sent packets (cumulative)
37*cf5a6c84SAndroid Build Coastguard Worker       -F Ask server to update DNS mapping for NAME
38*cf5a6c84SAndroid Build Coastguard Worker       -H Send NAME as client hostname (default none)
39*cf5a6c84SAndroid Build Coastguard Worker       -V VENDOR Vendor identifier (default 'toybox VERSION')
40*cf5a6c84SAndroid Build Coastguard Worker       -C Don't send MAC as client identifier
41*cf5a6c84SAndroid Build Coastguard Worker       -v Verbose
42*cf5a6c84SAndroid Build Coastguard Worker 
43*cf5a6c84SAndroid Build Coastguard Worker       Signals:
44*cf5a6c84SAndroid Build Coastguard Worker       USR1  Renew current lease
45*cf5a6c84SAndroid Build Coastguard Worker       USR2  Release current lease
46*cf5a6c84SAndroid Build Coastguard Worker 
47*cf5a6c84SAndroid Build Coastguard Worker */
48*cf5a6c84SAndroid Build Coastguard Worker 
49*cf5a6c84SAndroid Build Coastguard Worker #define FOR_dhcp
50*cf5a6c84SAndroid Build Coastguard Worker #include "toys.h"
51*cf5a6c84SAndroid Build Coastguard Worker 
52*cf5a6c84SAndroid Build Coastguard Worker // TODO: headers not in posix:
53*cf5a6c84SAndroid Build Coastguard Worker #include <netinet/ip.h>
54*cf5a6c84SAndroid Build Coastguard Worker #include <netinet/udp.h>
55*cf5a6c84SAndroid Build Coastguard Worker #include <netpacket/packet.h>
56*cf5a6c84SAndroid Build Coastguard Worker 
57*cf5a6c84SAndroid Build Coastguard Worker #include <linux/filter.h> //FIXME: linux specific. fix for other OS ports
58*cf5a6c84SAndroid Build Coastguard Worker #include <linux/if_ether.h>
59*cf5a6c84SAndroid Build Coastguard Worker 
60*cf5a6c84SAndroid Build Coastguard Worker GLOBALS(
61*cf5a6c84SAndroid Build Coastguard Worker     char *iface;
62*cf5a6c84SAndroid Build Coastguard Worker     char *pidfile;
63*cf5a6c84SAndroid Build Coastguard Worker     char *script;
64*cf5a6c84SAndroid Build Coastguard Worker     long retries;
65*cf5a6c84SAndroid Build Coastguard Worker     long timeout;
66*cf5a6c84SAndroid Build Coastguard Worker     long tryagain;
67*cf5a6c84SAndroid Build Coastguard Worker     struct arg_list *req_opt;
68*cf5a6c84SAndroid Build Coastguard Worker     char *req_ip;
69*cf5a6c84SAndroid Build Coastguard Worker     struct arg_list *pkt_opt;
70*cf5a6c84SAndroid Build Coastguard Worker     char *fdn_name;
71*cf5a6c84SAndroid Build Coastguard Worker     char *hostname;
72*cf5a6c84SAndroid Build Coastguard Worker     char *vendor_cls;
73*cf5a6c84SAndroid Build Coastguard Worker )
74*cf5a6c84SAndroid Build Coastguard Worker 
75*cf5a6c84SAndroid Build Coastguard Worker #define STATE_INIT            0
76*cf5a6c84SAndroid Build Coastguard Worker #define STATE_REQUESTING      1
77*cf5a6c84SAndroid Build Coastguard Worker #define STATE_BOUND           2
78*cf5a6c84SAndroid Build Coastguard Worker #define STATE_RENEWING        3
79*cf5a6c84SAndroid Build Coastguard Worker #define STATE_REBINDING       4
80*cf5a6c84SAndroid Build Coastguard Worker #define STATE_RENEW_REQUESTED 5
81*cf5a6c84SAndroid Build Coastguard Worker #define STATE_RELEASED        6
82*cf5a6c84SAndroid Build Coastguard Worker 
83*cf5a6c84SAndroid Build Coastguard Worker #define BOOTP_BROADCAST   0x8000
84*cf5a6c84SAndroid Build Coastguard Worker #define DHCP_MAGIC        0x63825363
85*cf5a6c84SAndroid Build Coastguard Worker 
86*cf5a6c84SAndroid Build Coastguard Worker #define DHCP_REQUEST          1
87*cf5a6c84SAndroid Build Coastguard Worker #define DHCP_REPLY            2
88*cf5a6c84SAndroid Build Coastguard Worker #define DHCP_HTYPE_ETHERNET   1
89*cf5a6c84SAndroid Build Coastguard Worker 
90*cf5a6c84SAndroid Build Coastguard Worker #define DHCPC_SERVER_PORT     67
91*cf5a6c84SAndroid Build Coastguard Worker #define DHCPC_CLIENT_PORT     68
92*cf5a6c84SAndroid Build Coastguard Worker 
93*cf5a6c84SAndroid Build Coastguard Worker #define DHCPDISCOVER      1
94*cf5a6c84SAndroid Build Coastguard Worker #define DHCPOFFER         2
95*cf5a6c84SAndroid Build Coastguard Worker #define DHCPREQUEST       3
96*cf5a6c84SAndroid Build Coastguard Worker #define DHCPACK           5
97*cf5a6c84SAndroid Build Coastguard Worker #define DHCPNAK           6
98*cf5a6c84SAndroid Build Coastguard Worker #define DHCPRELEASE       7
99*cf5a6c84SAndroid Build Coastguard Worker 
100*cf5a6c84SAndroid Build Coastguard Worker #define DHCP_OPTION_PADDING     0x00
101*cf5a6c84SAndroid Build Coastguard Worker #define DHCP_OPTION_SUBNET_MASK 0x01
102*cf5a6c84SAndroid Build Coastguard Worker #define DHCP_OPTION_ROUTER      0x03
103*cf5a6c84SAndroid Build Coastguard Worker #define DHCP_OPTION_DNS_SERVER  0x06
104*cf5a6c84SAndroid Build Coastguard Worker #define DHCP_OPTION_HOST_NAME   0x0c
105*cf5a6c84SAndroid Build Coastguard Worker #define DHCP_OPTION_BROADCAST   0x1c
106*cf5a6c84SAndroid Build Coastguard Worker #define DHCP_OPTION_REQ_IPADDR  0x32
107*cf5a6c84SAndroid Build Coastguard Worker #define DHCP_OPTION_LEASE_TIME  0x33
108*cf5a6c84SAndroid Build Coastguard Worker #define DHCP_OPTION_OVERLOAD    0x34
109*cf5a6c84SAndroid Build Coastguard Worker #define DHCP_OPTION_MSG_TYPE    0x35
110*cf5a6c84SAndroid Build Coastguard Worker #define DHCP_OPTION_SERVER_ID   0x36
111*cf5a6c84SAndroid Build Coastguard Worker #define DHCP_OPTION_REQ_LIST    0x37
112*cf5a6c84SAndroid Build Coastguard Worker #define DHCP_OPTION_MAX_SIZE    0x39
113*cf5a6c84SAndroid Build Coastguard Worker #define DHCP_OPTION_CLIENTID    0x3D
114*cf5a6c84SAndroid Build Coastguard Worker #define DHCP_OPTION_VENDOR      0x3C
115*cf5a6c84SAndroid Build Coastguard Worker #define DHCP_OPTION_FQDN        0x51
116*cf5a6c84SAndroid Build Coastguard Worker #define DHCP_OPTION_END         0xFF
117*cf5a6c84SAndroid Build Coastguard Worker 
118*cf5a6c84SAndroid Build Coastguard Worker #define DHCP_NUM8           (1<<8)
119*cf5a6c84SAndroid Build Coastguard Worker #define DHCP_NUM16          (1<<9)
120*cf5a6c84SAndroid Build Coastguard Worker #define DHCP_NUM32          DHCP_NUM16 | DHCP_NUM8
121*cf5a6c84SAndroid Build Coastguard Worker #define DHCP_STRING         (1<<10)
122*cf5a6c84SAndroid Build Coastguard Worker #define DHCP_STRLST         (1<<11)
123*cf5a6c84SAndroid Build Coastguard Worker #define DHCP_IP             (1<<12)
124*cf5a6c84SAndroid Build Coastguard Worker #define DHCP_IPLIST         (1<<13)
125*cf5a6c84SAndroid Build Coastguard Worker #define DHCP_IPPLST         (1<<14)
126*cf5a6c84SAndroid Build Coastguard Worker #define DHCP_STCRTS         (1<<15)
127*cf5a6c84SAndroid Build Coastguard Worker 
128*cf5a6c84SAndroid Build Coastguard Worker #define LOG_SILENT          0x0
129*cf5a6c84SAndroid Build Coastguard Worker #define LOG_CONSOLE         0x1
130*cf5a6c84SAndroid Build Coastguard Worker #define LOG_SYSTEM          0x2
131*cf5a6c84SAndroid Build Coastguard Worker 
132*cf5a6c84SAndroid Build Coastguard Worker #define MODE_OFF        0
133*cf5a6c84SAndroid Build Coastguard Worker #define MODE_RAW        1
134*cf5a6c84SAndroid Build Coastguard Worker #define MODE_APP        2
135*cf5a6c84SAndroid Build Coastguard Worker 
136*cf5a6c84SAndroid Build Coastguard Worker static void (*dbg)(char *format, ...);
dummy(char * format,...)137*cf5a6c84SAndroid Build Coastguard Worker static void dummy(char *format, ...){
138*cf5a6c84SAndroid Build Coastguard Worker   return;
139*cf5a6c84SAndroid Build Coastguard Worker }
140*cf5a6c84SAndroid Build Coastguard Worker 
141*cf5a6c84SAndroid Build Coastguard Worker typedef struct dhcpc_result_s {
142*cf5a6c84SAndroid Build Coastguard Worker   struct in_addr serverid;
143*cf5a6c84SAndroid Build Coastguard Worker   struct in_addr ipaddr;
144*cf5a6c84SAndroid Build Coastguard Worker   struct in_addr netmask;
145*cf5a6c84SAndroid Build Coastguard Worker   struct in_addr dnsaddr;
146*cf5a6c84SAndroid Build Coastguard Worker   struct in_addr default_router;
147*cf5a6c84SAndroid Build Coastguard Worker   uint32_t lease_time;
148*cf5a6c84SAndroid Build Coastguard Worker } dhcpc_result_t;
149*cf5a6c84SAndroid Build Coastguard Worker 
150*cf5a6c84SAndroid Build Coastguard Worker typedef struct __attribute__((packed)) dhcp_msg_s {
151*cf5a6c84SAndroid Build Coastguard Worker   uint8_t op;
152*cf5a6c84SAndroid Build Coastguard Worker   uint8_t htype;
153*cf5a6c84SAndroid Build Coastguard Worker   uint8_t hlen;
154*cf5a6c84SAndroid Build Coastguard Worker   uint8_t hops;
155*cf5a6c84SAndroid Build Coastguard Worker   uint32_t xid;
156*cf5a6c84SAndroid Build Coastguard Worker   uint16_t secs;
157*cf5a6c84SAndroid Build Coastguard Worker   uint16_t flags;
158*cf5a6c84SAndroid Build Coastguard Worker   uint32_t ciaddr;
159*cf5a6c84SAndroid Build Coastguard Worker   uint32_t yiaddr;
160*cf5a6c84SAndroid Build Coastguard Worker   uint32_t nsiaddr;
161*cf5a6c84SAndroid Build Coastguard Worker   uint32_t ngiaddr;
162*cf5a6c84SAndroid Build Coastguard Worker   uint8_t chaddr[16];
163*cf5a6c84SAndroid Build Coastguard Worker   uint8_t sname[64];
164*cf5a6c84SAndroid Build Coastguard Worker   uint8_t file[128];
165*cf5a6c84SAndroid Build Coastguard Worker   uint32_t cookie;
166*cf5a6c84SAndroid Build Coastguard Worker   uint8_t options[308];
167*cf5a6c84SAndroid Build Coastguard Worker } dhcp_msg_t;
168*cf5a6c84SAndroid Build Coastguard Worker 
169*cf5a6c84SAndroid Build Coastguard Worker typedef struct __attribute__((packed)) dhcp_raw_s {
170*cf5a6c84SAndroid Build Coastguard Worker   struct iphdr iph;
171*cf5a6c84SAndroid Build Coastguard Worker   struct udphdr udph;
172*cf5a6c84SAndroid Build Coastguard Worker   dhcp_msg_t dhcp;
173*cf5a6c84SAndroid Build Coastguard Worker } dhcp_raw_t;
174*cf5a6c84SAndroid Build Coastguard Worker 
175*cf5a6c84SAndroid Build Coastguard Worker typedef struct dhcpc_state_s {
176*cf5a6c84SAndroid Build Coastguard Worker   uint8_t macaddr[6];
177*cf5a6c84SAndroid Build Coastguard Worker    char *iface;
178*cf5a6c84SAndroid Build Coastguard Worker   int ifindex;
179*cf5a6c84SAndroid Build Coastguard Worker   int sockfd;
180*cf5a6c84SAndroid Build Coastguard Worker   int status;
181*cf5a6c84SAndroid Build Coastguard Worker   int mode;
182*cf5a6c84SAndroid Build Coastguard Worker   uint32_t mask;
183*cf5a6c84SAndroid Build Coastguard Worker   struct in_addr ipaddr;
184*cf5a6c84SAndroid Build Coastguard Worker   struct in_addr serverid;
185*cf5a6c84SAndroid Build Coastguard Worker   dhcp_msg_t pdhcp;
186*cf5a6c84SAndroid Build Coastguard Worker } dhcpc_state_t;
187*cf5a6c84SAndroid Build Coastguard Worker 
188*cf5a6c84SAndroid Build Coastguard Worker typedef struct option_val_s {
189*cf5a6c84SAndroid Build Coastguard Worker   char *key;
190*cf5a6c84SAndroid Build Coastguard Worker   uint16_t code;
191*cf5a6c84SAndroid Build Coastguard Worker   void *val;
192*cf5a6c84SAndroid Build Coastguard Worker   size_t len;
193*cf5a6c84SAndroid Build Coastguard Worker } option_val_t;
194*cf5a6c84SAndroid Build Coastguard Worker 
195*cf5a6c84SAndroid Build Coastguard Worker struct fd_pair { int rd; int wr; };
196*cf5a6c84SAndroid Build Coastguard Worker static uint32_t xid;
197*cf5a6c84SAndroid Build Coastguard Worker static dhcpc_state_t *state;
198*cf5a6c84SAndroid Build Coastguard Worker static struct fd_pair sigfd;
199*cf5a6c84SAndroid Build Coastguard Worker uint8_t bmacaddr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
200*cf5a6c84SAndroid Build Coastguard Worker  int set = 1;
201*cf5a6c84SAndroid Build Coastguard Worker uint8_t infomode = LOG_CONSOLE;
202*cf5a6c84SAndroid Build Coastguard Worker uint8_t raw_opt[29];
203*cf5a6c84SAndroid Build Coastguard Worker int raw_optcount = 0;
204*cf5a6c84SAndroid Build Coastguard Worker struct arg_list *x_opt;
205*cf5a6c84SAndroid Build Coastguard Worker in_addr_t server = 0;
206*cf5a6c84SAndroid Build Coastguard Worker 
207*cf5a6c84SAndroid Build Coastguard Worker static option_val_t *msgopt_list = NULL;
208*cf5a6c84SAndroid Build Coastguard Worker static option_val_t options_list[] = {
209*cf5a6c84SAndroid Build Coastguard Worker     {"lease"          , DHCP_NUM32  | 0x33, NULL, 0},
210*cf5a6c84SAndroid Build Coastguard Worker     {"subnet"         , DHCP_IP     | 0x01, NULL, 0},
211*cf5a6c84SAndroid Build Coastguard Worker     {"broadcast"      , DHCP_IP     | 0x1c, NULL, 0},
212*cf5a6c84SAndroid Build Coastguard Worker     {"router"         , DHCP_IP     | 0x03, NULL, 0},
213*cf5a6c84SAndroid Build Coastguard Worker     {"ipttl"          , DHCP_NUM8   | 0x17, NULL, 0},
214*cf5a6c84SAndroid Build Coastguard Worker     {"mtu"            , DHCP_NUM16  | 0x1a, NULL, 0},
215*cf5a6c84SAndroid Build Coastguard Worker     {"hostname"       , DHCP_STRING | 0x0c, NULL, 0},
216*cf5a6c84SAndroid Build Coastguard Worker     {"domain"         , DHCP_STRING | 0x0f, NULL, 0},
217*cf5a6c84SAndroid Build Coastguard Worker     {"search"         , DHCP_STRLST | 0x77, NULL, 0},
218*cf5a6c84SAndroid Build Coastguard Worker     {"nisdomain"      , DHCP_STRING | 0x28, NULL, 0},
219*cf5a6c84SAndroid Build Coastguard Worker     {"timezone"       , DHCP_NUM32  | 0x02, NULL, 0},
220*cf5a6c84SAndroid Build Coastguard Worker     {"tftp"           , DHCP_STRING | 0x42, NULL, 0},
221*cf5a6c84SAndroid Build Coastguard Worker     {"bootfile"       , DHCP_STRING | 0x43, NULL, 0},
222*cf5a6c84SAndroid Build Coastguard Worker     {"bootsize"       , DHCP_NUM16  | 0x0d, NULL, 0},
223*cf5a6c84SAndroid Build Coastguard Worker     {"rootpath"       , DHCP_STRING | 0x11, NULL, 0},
224*cf5a6c84SAndroid Build Coastguard Worker     {"wpad"           , DHCP_STRING | 0xfc, NULL, 0},
225*cf5a6c84SAndroid Build Coastguard Worker     {"serverid"       , DHCP_IP     | 0x36, NULL, 0},
226*cf5a6c84SAndroid Build Coastguard Worker     {"message"        , DHCP_STRING | 0x38, NULL, 0},
227*cf5a6c84SAndroid Build Coastguard Worker     {"vlanid"         , DHCP_NUM32  | 0x84, NULL, 0},
228*cf5a6c84SAndroid Build Coastguard Worker     {"vlanpriority"   , DHCP_NUM32  | 0x85, NULL, 0},
229*cf5a6c84SAndroid Build Coastguard Worker     {"dns"            , DHCP_IPLIST | 0x06, NULL, 0},
230*cf5a6c84SAndroid Build Coastguard Worker     {"wins"           , DHCP_IPLIST | 0x2c, NULL, 0},
231*cf5a6c84SAndroid Build Coastguard Worker     {"nissrv"         , DHCP_IPLIST | 0x29, NULL, 0},
232*cf5a6c84SAndroid Build Coastguard Worker     {"ntpsrv"         , DHCP_IPLIST | 0x2a, NULL, 0},
233*cf5a6c84SAndroid Build Coastguard Worker     {"lprsrv"         , DHCP_IPLIST | 0x09, NULL, 0},
234*cf5a6c84SAndroid Build Coastguard Worker     {"swapsrv"        , DHCP_IP     | 0x10, NULL, 0},
235*cf5a6c84SAndroid Build Coastguard Worker     {"routes"         , DHCP_STCRTS | 0x21, NULL, 0},
236*cf5a6c84SAndroid Build Coastguard Worker     {"staticroutes"   , DHCP_STCRTS | 0x79, NULL, 0},
237*cf5a6c84SAndroid Build Coastguard Worker     {"msstaticroutes" , DHCP_STCRTS | 0xf9, NULL, 0},
238*cf5a6c84SAndroid Build Coastguard Worker };
239*cf5a6c84SAndroid Build Coastguard Worker 
240*cf5a6c84SAndroid Build Coastguard Worker static  struct sock_filter filter_instr[] = {
241*cf5a6c84SAndroid Build Coastguard Worker     BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 9),
242*cf5a6c84SAndroid Build Coastguard Worker     BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, IPPROTO_UDP, 0, 6),
243*cf5a6c84SAndroid Build Coastguard Worker     BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 6),
244*cf5a6c84SAndroid Build Coastguard Worker     BPF_JUMP(BPF_JMP|BPF_JSET|BPF_K, 0x1fff, 4, 0),
245*cf5a6c84SAndroid Build Coastguard Worker     BPF_STMT(BPF_LDX|BPF_B|BPF_MSH, 0), BPF_STMT(BPF_LD|BPF_H|BPF_IND, 2),
246*cf5a6c84SAndroid Build Coastguard Worker     BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 68, 0, 1),
247*cf5a6c84SAndroid Build Coastguard Worker     BPF_STMT(BPF_RET|BPF_K, 0xffffffff), BPF_STMT(BPF_RET|BPF_K, 0),
248*cf5a6c84SAndroid Build Coastguard Worker };
249*cf5a6c84SAndroid Build Coastguard Worker 
250*cf5a6c84SAndroid Build Coastguard Worker static  struct sock_fprog filter_prog = {
251*cf5a6c84SAndroid Build Coastguard Worker     .len = ARRAY_LEN(filter_instr),
252*cf5a6c84SAndroid Build Coastguard Worker     .filter = (struct sock_filter *) filter_instr,
253*cf5a6c84SAndroid Build Coastguard Worker };
254*cf5a6c84SAndroid Build Coastguard Worker 
255*cf5a6c84SAndroid Build Coastguard Worker // calculate options size.
dhcp_opt_size(uint8_t * optionptr)256*cf5a6c84SAndroid Build Coastguard Worker static int dhcp_opt_size(uint8_t *optionptr)
257*cf5a6c84SAndroid Build Coastguard Worker {
258*cf5a6c84SAndroid Build Coastguard Worker   int i = 0;
259*cf5a6c84SAndroid Build Coastguard Worker   for(;optionptr[i] != 0xff; i++) if(optionptr[i] != 0x00) i += optionptr[i + 1] + 2 -1;
260*cf5a6c84SAndroid Build Coastguard Worker   return i;
261*cf5a6c84SAndroid Build Coastguard Worker }
262*cf5a6c84SAndroid Build Coastguard Worker 
263*cf5a6c84SAndroid Build Coastguard Worker // calculates checksum for dhcp messages.
dhcp_checksum(void * addr,int count)264*cf5a6c84SAndroid Build Coastguard Worker static uint16_t dhcp_checksum(void *addr, int count)
265*cf5a6c84SAndroid Build Coastguard Worker {
266*cf5a6c84SAndroid Build Coastguard Worker   int32_t sum = 0;
267*cf5a6c84SAndroid Build Coastguard Worker   uint16_t tmp = 0, *source = (uint16_t *)addr;
268*cf5a6c84SAndroid Build Coastguard Worker 
269*cf5a6c84SAndroid Build Coastguard Worker   while (count > 1)  {
270*cf5a6c84SAndroid Build Coastguard Worker     sum += *source++;
271*cf5a6c84SAndroid Build Coastguard Worker     count -= 2;
272*cf5a6c84SAndroid Build Coastguard Worker   }
273*cf5a6c84SAndroid Build Coastguard Worker   if (count > 0) {
274*cf5a6c84SAndroid Build Coastguard Worker     *(uint8_t*)&tmp = *(uint8_t*)source;
275*cf5a6c84SAndroid Build Coastguard Worker     sum += tmp;
276*cf5a6c84SAndroid Build Coastguard Worker   }
277*cf5a6c84SAndroid Build Coastguard Worker   while (sum >> 16) sum = (sum & 0xffff) + (sum >> 16);
278*cf5a6c84SAndroid Build Coastguard Worker   return ~sum;
279*cf5a6c84SAndroid Build Coastguard Worker }
280*cf5a6c84SAndroid Build Coastguard Worker 
281*cf5a6c84SAndroid Build Coastguard Worker // gets information of INTERFACE and updates IFINDEX, MAC and IP
get_interface(char * interface,int * ifindex,uint32_t * oip,uint8_t * mac)282*cf5a6c84SAndroid Build Coastguard Worker static int get_interface( char *interface, int *ifindex, uint32_t *oip, uint8_t *mac)
283*cf5a6c84SAndroid Build Coastguard Worker {
284*cf5a6c84SAndroid Build Coastguard Worker   struct ifreq req;
285*cf5a6c84SAndroid Build Coastguard Worker   struct sockaddr_in *ip;
286*cf5a6c84SAndroid Build Coastguard Worker   int fd = xsocket(AF_INET, SOCK_RAW, IPPROTO_RAW);
287*cf5a6c84SAndroid Build Coastguard Worker 
288*cf5a6c84SAndroid Build Coastguard Worker   req.ifr_addr.sa_family = AF_INET;
289*cf5a6c84SAndroid Build Coastguard Worker   xstrncpy(req.ifr_name, interface, IFNAMSIZ);
290*cf5a6c84SAndroid Build Coastguard Worker   req.ifr_name[IFNAMSIZ-1] = '\0';
291*cf5a6c84SAndroid Build Coastguard Worker 
292*cf5a6c84SAndroid Build Coastguard Worker   xioctl(fd, SIOCGIFFLAGS, &req);
293*cf5a6c84SAndroid Build Coastguard Worker   if (!(req.ifr_flags & IFF_UP)) return -1;
294*cf5a6c84SAndroid Build Coastguard Worker 
295*cf5a6c84SAndroid Build Coastguard Worker   if (oip) {
296*cf5a6c84SAndroid Build Coastguard Worker     xioctl(fd, SIOCGIFADDR, &req);
297*cf5a6c84SAndroid Build Coastguard Worker     ip = (struct sockaddr_in*) &req.ifr_addr;
298*cf5a6c84SAndroid Build Coastguard Worker     dbg("IP %s\n", inet_ntoa(ip->sin_addr));
299*cf5a6c84SAndroid Build Coastguard Worker     *oip = ntohl(ip->sin_addr.s_addr);
300*cf5a6c84SAndroid Build Coastguard Worker   }
301*cf5a6c84SAndroid Build Coastguard Worker   if (ifindex) {
302*cf5a6c84SAndroid Build Coastguard Worker     xioctl(fd, SIOCGIFINDEX, &req);
303*cf5a6c84SAndroid Build Coastguard Worker     dbg("Adapter index %d\n", req.ifr_ifindex);
304*cf5a6c84SAndroid Build Coastguard Worker     *ifindex = req.ifr_ifindex;
305*cf5a6c84SAndroid Build Coastguard Worker   }
306*cf5a6c84SAndroid Build Coastguard Worker   if (mac) {
307*cf5a6c84SAndroid Build Coastguard Worker     xioctl(fd, SIOCGIFHWADDR, &req);
308*cf5a6c84SAndroid Build Coastguard Worker     memcpy(mac, req.ifr_hwaddr.sa_data, 6);
309*cf5a6c84SAndroid Build Coastguard Worker     dbg("MAC %02x:%02x:%02x:%02x:%02x:%02x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
310*cf5a6c84SAndroid Build Coastguard Worker   }
311*cf5a6c84SAndroid Build Coastguard Worker   close(fd);
312*cf5a6c84SAndroid Build Coastguard Worker   return 0;
313*cf5a6c84SAndroid Build Coastguard Worker }
314*cf5a6c84SAndroid Build Coastguard Worker 
315*cf5a6c84SAndroid Build Coastguard Worker /*
316*cf5a6c84SAndroid Build Coastguard Worker  *logs messeges to syslog or console
317*cf5a6c84SAndroid Build Coastguard Worker  *opening the log is still left with applet.
318*cf5a6c84SAndroid Build Coastguard Worker  *FIXME: move to more relevent lib. probably libc.c
319*cf5a6c84SAndroid Build Coastguard Worker  */
infomsg(uint8_t infomode,char * s,...)320*cf5a6c84SAndroid Build Coastguard Worker static void infomsg(uint8_t infomode,  char *s, ...)
321*cf5a6c84SAndroid Build Coastguard Worker {
322*cf5a6c84SAndroid Build Coastguard Worker   int used;
323*cf5a6c84SAndroid Build Coastguard Worker   char *msg;
324*cf5a6c84SAndroid Build Coastguard Worker   va_list p, t;
325*cf5a6c84SAndroid Build Coastguard Worker 
326*cf5a6c84SAndroid Build Coastguard Worker   if (infomode == LOG_SILENT) return;
327*cf5a6c84SAndroid Build Coastguard Worker   va_start(p, s);
328*cf5a6c84SAndroid Build Coastguard Worker   va_copy(t, p);
329*cf5a6c84SAndroid Build Coastguard Worker   used = vsnprintf(NULL, 0, s, t);
330*cf5a6c84SAndroid Build Coastguard Worker   used++;
331*cf5a6c84SAndroid Build Coastguard Worker   va_end(t);
332*cf5a6c84SAndroid Build Coastguard Worker 
333*cf5a6c84SAndroid Build Coastguard Worker   msg = xmalloc(used);
334*cf5a6c84SAndroid Build Coastguard Worker   vsnprintf(msg, used, s, p);
335*cf5a6c84SAndroid Build Coastguard Worker   va_end(p);
336*cf5a6c84SAndroid Build Coastguard Worker 
337*cf5a6c84SAndroid Build Coastguard Worker   if (infomode & LOG_SYSTEM) syslog(LOG_INFO, "%s", msg);
338*cf5a6c84SAndroid Build Coastguard Worker   if (infomode & LOG_CONSOLE) printf("%s\n", msg);
339*cf5a6c84SAndroid Build Coastguard Worker   free(msg);
340*cf5a6c84SAndroid Build Coastguard Worker }
341*cf5a6c84SAndroid Build Coastguard Worker 
342*cf5a6c84SAndroid Build Coastguard Worker /*
343*cf5a6c84SAndroid Build Coastguard Worker  * Writes self PID in file PATH
344*cf5a6c84SAndroid Build Coastguard Worker  * FIXME: libc implementation only writes in /var/run
345*cf5a6c84SAndroid Build Coastguard Worker  * this is more generic as some implemenation may provide
346*cf5a6c84SAndroid Build Coastguard Worker  * arguments to write in specific file. as dhcpd does.
347*cf5a6c84SAndroid Build Coastguard Worker  */
write_pid(char * path)348*cf5a6c84SAndroid Build Coastguard Worker static void write_pid(char *path)
349*cf5a6c84SAndroid Build Coastguard Worker {
350*cf5a6c84SAndroid Build Coastguard Worker   int pidfile = open(path, O_CREAT | O_WRONLY | O_TRUNC, 0666);
351*cf5a6c84SAndroid Build Coastguard Worker   if (pidfile > 0) {
352*cf5a6c84SAndroid Build Coastguard Worker     char pidbuf[12];
353*cf5a6c84SAndroid Build Coastguard Worker 
354*cf5a6c84SAndroid Build Coastguard Worker     sprintf(pidbuf, "%u", (unsigned)getpid());
355*cf5a6c84SAndroid Build Coastguard Worker     write(pidfile, pidbuf, strlen(pidbuf));
356*cf5a6c84SAndroid Build Coastguard Worker     close(pidfile);
357*cf5a6c84SAndroid Build Coastguard Worker   }
358*cf5a6c84SAndroid Build Coastguard Worker }
359*cf5a6c84SAndroid Build Coastguard Worker 
360*cf5a6c84SAndroid Build Coastguard Worker // String STR to UINT32 conversion strored in VAR
strtou32(char * str)361*cf5a6c84SAndroid Build Coastguard Worker static long strtou32( char *str)
362*cf5a6c84SAndroid Build Coastguard Worker {
363*cf5a6c84SAndroid Build Coastguard Worker   char *endptr = NULL;
364*cf5a6c84SAndroid Build Coastguard Worker   int base = 10;
365*cf5a6c84SAndroid Build Coastguard Worker   errno=0;
366*cf5a6c84SAndroid Build Coastguard Worker   if (str[0]=='0' && (str[1]=='x' || str[1]=='X')) {
367*cf5a6c84SAndroid Build Coastguard Worker     base = 16;
368*cf5a6c84SAndroid Build Coastguard Worker     str+=2;
369*cf5a6c84SAndroid Build Coastguard Worker   }
370*cf5a6c84SAndroid Build Coastguard Worker   long ret_val = strtol(str, &endptr, base);
371*cf5a6c84SAndroid Build Coastguard Worker   if (errno) return -1;
372*cf5a6c84SAndroid Build Coastguard Worker   else if (endptr && (*endptr!='\0'||endptr == str)) return -1;
373*cf5a6c84SAndroid Build Coastguard Worker   return ret_val;
374*cf5a6c84SAndroid Build Coastguard Worker }
375*cf5a6c84SAndroid Build Coastguard Worker 
376*cf5a6c84SAndroid Build Coastguard Worker // IP String STR to binary data.
striptovar(char * str,void * var)377*cf5a6c84SAndroid Build Coastguard Worker static int striptovar( char *str, void *var)
378*cf5a6c84SAndroid Build Coastguard Worker {
379*cf5a6c84SAndroid Build Coastguard Worker   in_addr_t addr;
380*cf5a6c84SAndroid Build Coastguard Worker   if(!str) error_exit("NULL address string.");
381*cf5a6c84SAndroid Build Coastguard Worker   addr = inet_addr(str);
382*cf5a6c84SAndroid Build Coastguard Worker   if(addr == -1) error_exit("Wrong address %s.",str );
383*cf5a6c84SAndroid Build Coastguard Worker   *((uint32_t*)(var)) = (uint32_t)addr;
384*cf5a6c84SAndroid Build Coastguard Worker   return 0;
385*cf5a6c84SAndroid Build Coastguard Worker }
386*cf5a6c84SAndroid Build Coastguard Worker 
387*cf5a6c84SAndroid Build Coastguard Worker // String to dhcp option conversion
strtoopt(char * str,uint8_t optonly)388*cf5a6c84SAndroid Build Coastguard Worker static int strtoopt( char *str, uint8_t optonly)
389*cf5a6c84SAndroid Build Coastguard Worker {
390*cf5a6c84SAndroid Build Coastguard Worker   char *option, *valstr, *grp, *tp;
391*cf5a6c84SAndroid Build Coastguard Worker   long optcode = 0, convtmp;
392*cf5a6c84SAndroid Build Coastguard Worker   uint16_t flag = 0;
393*cf5a6c84SAndroid Build Coastguard Worker   uint32_t mask, nip, router;
394*cf5a6c84SAndroid Build Coastguard Worker   int count, size = ARRAY_LEN(options_list);
395*cf5a6c84SAndroid Build Coastguard Worker 
396*cf5a6c84SAndroid Build Coastguard Worker   if (!*str) return 0;
397*cf5a6c84SAndroid Build Coastguard Worker   option = strtok((char*)str, ":");
398*cf5a6c84SAndroid Build Coastguard Worker   if (!option) return -1;
399*cf5a6c84SAndroid Build Coastguard Worker 
400*cf5a6c84SAndroid Build Coastguard Worker   dbg("-x option : %s ", option);
401*cf5a6c84SAndroid Build Coastguard Worker   optcode = strtou32(option);
402*cf5a6c84SAndroid Build Coastguard Worker 
403*cf5a6c84SAndroid Build Coastguard Worker   if (optcode > 0 && optcode < 256) {         // raw option
404*cf5a6c84SAndroid Build Coastguard Worker     for (count = 0; count < size; count++) {
405*cf5a6c84SAndroid Build Coastguard Worker       if ((options_list[count].code & 0X00FF) == optcode) {
406*cf5a6c84SAndroid Build Coastguard Worker         flag = (options_list[count].code & 0XFF00);
407*cf5a6c84SAndroid Build Coastguard Worker         break;
408*cf5a6c84SAndroid Build Coastguard Worker       }
409*cf5a6c84SAndroid Build Coastguard Worker     }
410*cf5a6c84SAndroid Build Coastguard Worker     if (count == size) error_exit("Obsolete OR Unknown Option : %s", option);
411*cf5a6c84SAndroid Build Coastguard Worker   } else {    // string option
412*cf5a6c84SAndroid Build Coastguard Worker     for (count = 0; count < size; count++) {
413*cf5a6c84SAndroid Build Coastguard Worker       if (!strcmp(options_list[count].key, option)) {
414*cf5a6c84SAndroid Build Coastguard Worker         flag = (options_list[count].code & 0XFF00);
415*cf5a6c84SAndroid Build Coastguard Worker         optcode = (options_list[count].code & 0X00FF);
416*cf5a6c84SAndroid Build Coastguard Worker         break;
417*cf5a6c84SAndroid Build Coastguard Worker       }
418*cf5a6c84SAndroid Build Coastguard Worker     }
419*cf5a6c84SAndroid Build Coastguard Worker     if (count == size) error_exit("Obsolete OR Unknown Option : %s", option);
420*cf5a6c84SAndroid Build Coastguard Worker   }
421*cf5a6c84SAndroid Build Coastguard Worker   if (!flag || !optcode) return -1;
422*cf5a6c84SAndroid Build Coastguard Worker   if (optonly) return optcode;
423*cf5a6c84SAndroid Build Coastguard Worker 
424*cf5a6c84SAndroid Build Coastguard Worker   valstr = strtok(NULL, "\n");
425*cf5a6c84SAndroid Build Coastguard Worker   if (!valstr) error_exit("option %s has no value defined.\n", option);
426*cf5a6c84SAndroid Build Coastguard Worker   dbg(" value : %-20s \n ", valstr);
427*cf5a6c84SAndroid Build Coastguard Worker   switch (flag) {
428*cf5a6c84SAndroid Build Coastguard Worker   case DHCP_NUM32:
429*cf5a6c84SAndroid Build Coastguard Worker     options_list[count].len = sizeof(uint32_t);
430*cf5a6c84SAndroid Build Coastguard Worker     options_list[count].val = xmalloc(sizeof(uint32_t));
431*cf5a6c84SAndroid Build Coastguard Worker     convtmp = strtou32(valstr);
432*cf5a6c84SAndroid Build Coastguard Worker     if (convtmp < 0) error_exit("Invalid/wrong formatted number %s", valstr);
433*cf5a6c84SAndroid Build Coastguard Worker     convtmp = htonl(convtmp);
434*cf5a6c84SAndroid Build Coastguard Worker     memcpy(options_list[count].val, &convtmp, sizeof(uint32_t));
435*cf5a6c84SAndroid Build Coastguard Worker     break;
436*cf5a6c84SAndroid Build Coastguard Worker   case DHCP_NUM16:
437*cf5a6c84SAndroid Build Coastguard Worker     options_list[count].len = sizeof(uint16_t);
438*cf5a6c84SAndroid Build Coastguard Worker     options_list[count].val = xmalloc(sizeof(uint16_t));
439*cf5a6c84SAndroid Build Coastguard Worker     convtmp = strtou32(valstr);
440*cf5a6c84SAndroid Build Coastguard Worker     if (convtmp < 0) error_exit("Invalid/malformed number %s", valstr);
441*cf5a6c84SAndroid Build Coastguard Worker     convtmp = htons(convtmp);
442*cf5a6c84SAndroid Build Coastguard Worker     memcpy(options_list[count].val, &convtmp, sizeof(uint16_t));
443*cf5a6c84SAndroid Build Coastguard Worker     break;
444*cf5a6c84SAndroid Build Coastguard Worker   case DHCP_NUM8:
445*cf5a6c84SAndroid Build Coastguard Worker     options_list[count].len = sizeof(uint8_t);
446*cf5a6c84SAndroid Build Coastguard Worker     options_list[count].val = xmalloc(sizeof(uint8_t));
447*cf5a6c84SAndroid Build Coastguard Worker     convtmp = strtou32(valstr);
448*cf5a6c84SAndroid Build Coastguard Worker     if (convtmp < 0) error_exit("Invalid/malformed number %s", valstr);
449*cf5a6c84SAndroid Build Coastguard Worker     memcpy(options_list[count].val, &convtmp, sizeof(uint8_t));
450*cf5a6c84SAndroid Build Coastguard Worker     break;
451*cf5a6c84SAndroid Build Coastguard Worker   case DHCP_IP:
452*cf5a6c84SAndroid Build Coastguard Worker     options_list[count].len = sizeof(uint32_t);
453*cf5a6c84SAndroid Build Coastguard Worker     options_list[count].val = xmalloc(sizeof(uint32_t));
454*cf5a6c84SAndroid Build Coastguard Worker     striptovar(valstr, options_list[count].val);
455*cf5a6c84SAndroid Build Coastguard Worker     break;
456*cf5a6c84SAndroid Build Coastguard Worker   case DHCP_STRING:
457*cf5a6c84SAndroid Build Coastguard Worker     options_list[count].len = strlen(valstr);
458*cf5a6c84SAndroid Build Coastguard Worker     options_list[count].val = strdup(valstr);
459*cf5a6c84SAndroid Build Coastguard Worker     break;
460*cf5a6c84SAndroid Build Coastguard Worker   case DHCP_IPLIST:
461*cf5a6c84SAndroid Build Coastguard Worker     while(valstr){
462*cf5a6c84SAndroid Build Coastguard Worker       options_list[count].val = xrealloc(options_list[count].val, options_list[count].len + sizeof(uint32_t));
463*cf5a6c84SAndroid Build Coastguard Worker       striptovar(valstr, ((uint8_t*)options_list[count].val)+options_list[count].len);
464*cf5a6c84SAndroid Build Coastguard Worker       options_list[count].len += sizeof(uint32_t);
465*cf5a6c84SAndroid Build Coastguard Worker       valstr = strtok(NULL," \t");
466*cf5a6c84SAndroid Build Coastguard Worker     }
467*cf5a6c84SAndroid Build Coastguard Worker     break;
468*cf5a6c84SAndroid Build Coastguard Worker   case DHCP_STRLST:
469*cf5a6c84SAndroid Build Coastguard Worker   case DHCP_IPPLST:
470*cf5a6c84SAndroid Build Coastguard Worker     break;
471*cf5a6c84SAndroid Build Coastguard Worker   case DHCP_STCRTS:
472*cf5a6c84SAndroid Build Coastguard Worker     /* Option binary format:
473*cf5a6c84SAndroid Build Coastguard Worker      * mask [one byte, 0..32]
474*cf5a6c84SAndroid Build Coastguard Worker      * ip [0..4 bytes depending on mask]
475*cf5a6c84SAndroid Build Coastguard Worker      * router [4 bytes]
476*cf5a6c84SAndroid Build Coastguard Worker      * may be repeated
477*cf5a6c84SAndroid Build Coastguard Worker      * staticroutes 10.0.0.0/8 10.127.0.1, 10.11.12.0/24 10.11.12.1
478*cf5a6c84SAndroid Build Coastguard Worker      */
479*cf5a6c84SAndroid Build Coastguard Worker     grp = strtok(valstr, ",");;
480*cf5a6c84SAndroid Build Coastguard Worker     while(grp){
481*cf5a6c84SAndroid Build Coastguard Worker       while(*grp == ' ' || *grp == '\t') grp++;
482*cf5a6c84SAndroid Build Coastguard Worker       tp = strchr(grp, '/');
483*cf5a6c84SAndroid Build Coastguard Worker       if (!tp) error_exit("malformed static route option");
484*cf5a6c84SAndroid Build Coastguard Worker       *tp = '\0';
485*cf5a6c84SAndroid Build Coastguard Worker       mask = strtol(++tp, &tp, 10);
486*cf5a6c84SAndroid Build Coastguard Worker       if (striptovar(grp, (uint8_t*)&nip) < 0) error_exit("malformed static route option");
487*cf5a6c84SAndroid Build Coastguard Worker       while(*tp == ' ' || *tp == '\t' || *tp == '-') tp++;
488*cf5a6c84SAndroid Build Coastguard Worker       if (striptovar(tp, (uint8_t*)&router) < 0) error_exit("malformed static route option");
489*cf5a6c84SAndroid Build Coastguard Worker       options_list[count].val = xrealloc(options_list[count].val, options_list[count].len + 1 + mask/8 + 4);
490*cf5a6c84SAndroid Build Coastguard Worker       memcpy(((uint8_t*)options_list[count].val)+options_list[count].len, &mask, 1);
491*cf5a6c84SAndroid Build Coastguard Worker       options_list[count].len += 1;
492*cf5a6c84SAndroid Build Coastguard Worker       memcpy(((uint8_t*)options_list[count].val)+options_list[count].len, &nip, mask/8);
493*cf5a6c84SAndroid Build Coastguard Worker       options_list[count].len += mask/8;
494*cf5a6c84SAndroid Build Coastguard Worker       memcpy(((uint8_t*)options_list[count].val)+options_list[count].len, &router, 4);
495*cf5a6c84SAndroid Build Coastguard Worker       options_list[count].len += 4;
496*cf5a6c84SAndroid Build Coastguard Worker       tp = NULL;
497*cf5a6c84SAndroid Build Coastguard Worker       grp = strtok(NULL, ",");
498*cf5a6c84SAndroid Build Coastguard Worker     }
499*cf5a6c84SAndroid Build Coastguard Worker     break;
500*cf5a6c84SAndroid Build Coastguard Worker   }
501*cf5a6c84SAndroid Build Coastguard Worker   return 0;
502*cf5a6c84SAndroid Build Coastguard Worker }
503*cf5a6c84SAndroid Build Coastguard Worker 
504*cf5a6c84SAndroid Build Coastguard Worker // Creates environment pointers from RES to use in script
fill_envp(dhcpc_result_t * res)505*cf5a6c84SAndroid Build Coastguard Worker static int fill_envp(dhcpc_result_t *res)
506*cf5a6c84SAndroid Build Coastguard Worker {
507*cf5a6c84SAndroid Build Coastguard Worker   struct in_addr temp;
508*cf5a6c84SAndroid Build Coastguard Worker   int size = ARRAY_LEN(options_list), count, ret = -1;
509*cf5a6c84SAndroid Build Coastguard Worker 
510*cf5a6c84SAndroid Build Coastguard Worker   ret = setenv("interface", state->iface, 1);
511*cf5a6c84SAndroid Build Coastguard Worker   if (!res) return ret;
512*cf5a6c84SAndroid Build Coastguard Worker   if (res->ipaddr.s_addr) {
513*cf5a6c84SAndroid Build Coastguard Worker       temp.s_addr = htonl(res->ipaddr.s_addr);
514*cf5a6c84SAndroid Build Coastguard Worker       ret = setenv("ip", inet_ntoa(temp), 1);
515*cf5a6c84SAndroid Build Coastguard Worker       if (ret) return ret;
516*cf5a6c84SAndroid Build Coastguard Worker   }
517*cf5a6c84SAndroid Build Coastguard Worker   if (msgopt_list) {
518*cf5a6c84SAndroid Build Coastguard Worker     for (count = 0; count < size; count++) {
519*cf5a6c84SAndroid Build Coastguard Worker         if ((msgopt_list[count].len == 0) || (msgopt_list[count].val == NULL)) continue;
520*cf5a6c84SAndroid Build Coastguard Worker         ret = setenv(msgopt_list[count].key, (char*)msgopt_list[count].val, 1);
521*cf5a6c84SAndroid Build Coastguard Worker         if (ret) return ret;
522*cf5a6c84SAndroid Build Coastguard Worker       }
523*cf5a6c84SAndroid Build Coastguard Worker   }
524*cf5a6c84SAndroid Build Coastguard Worker   return ret;
525*cf5a6c84SAndroid Build Coastguard Worker }
526*cf5a6c84SAndroid Build Coastguard Worker 
527*cf5a6c84SAndroid Build Coastguard Worker // Executes Script NAME.
run_script(dhcpc_result_t * res,char * name)528*cf5a6c84SAndroid Build Coastguard Worker static void run_script(dhcpc_result_t *res,  char *name)
529*cf5a6c84SAndroid Build Coastguard Worker {
530*cf5a6c84SAndroid Build Coastguard Worker   volatile int error = 0;
531*cf5a6c84SAndroid Build Coastguard Worker   pid_t pid;
532*cf5a6c84SAndroid Build Coastguard Worker   char *argv[3];
533*cf5a6c84SAndroid Build Coastguard Worker   struct stat sts;
534*cf5a6c84SAndroid Build Coastguard Worker   char *script = (toys.optflags & FLAG_s) ? TT.script
535*cf5a6c84SAndroid Build Coastguard Worker     : "/usr/share/dhcp/default.script";
536*cf5a6c84SAndroid Build Coastguard Worker 
537*cf5a6c84SAndroid Build Coastguard Worker   if (stat(script, &sts) == -1 && errno == ENOENT) return;
538*cf5a6c84SAndroid Build Coastguard Worker   if (fill_envp(res)) {
539*cf5a6c84SAndroid Build Coastguard Worker     dbg("Failed to create environment variables.");
540*cf5a6c84SAndroid Build Coastguard Worker     return;
541*cf5a6c84SAndroid Build Coastguard Worker   }
542*cf5a6c84SAndroid Build Coastguard Worker   dbg("Executing %s %s\n", script, name);
543*cf5a6c84SAndroid Build Coastguard Worker   argv[0] = (char*) script;
544*cf5a6c84SAndroid Build Coastguard Worker   argv[1] = (char*) name;
545*cf5a6c84SAndroid Build Coastguard Worker   argv[2] = NULL;
546*cf5a6c84SAndroid Build Coastguard Worker   fflush(NULL);
547*cf5a6c84SAndroid Build Coastguard Worker 
548*cf5a6c84SAndroid Build Coastguard Worker   pid = vfork();
549*cf5a6c84SAndroid Build Coastguard Worker   if (pid < 0) {
550*cf5a6c84SAndroid Build Coastguard Worker     dbg("Fork failed.\n");
551*cf5a6c84SAndroid Build Coastguard Worker     return;
552*cf5a6c84SAndroid Build Coastguard Worker   }
553*cf5a6c84SAndroid Build Coastguard Worker   if (!pid) {
554*cf5a6c84SAndroid Build Coastguard Worker     execvp(argv[0], argv);
555*cf5a6c84SAndroid Build Coastguard Worker     error = errno;
556*cf5a6c84SAndroid Build Coastguard Worker     _exit(111);
557*cf5a6c84SAndroid Build Coastguard Worker   }
558*cf5a6c84SAndroid Build Coastguard Worker   if (error) {
559*cf5a6c84SAndroid Build Coastguard Worker     waitpid(pid, NULL,0);
560*cf5a6c84SAndroid Build Coastguard Worker     errno = error;
561*cf5a6c84SAndroid Build Coastguard Worker     perror_msg("script exec failed");
562*cf5a6c84SAndroid Build Coastguard Worker   }
563*cf5a6c84SAndroid Build Coastguard Worker   dbg("script complete.\n");
564*cf5a6c84SAndroid Build Coastguard Worker }
565*cf5a6c84SAndroid Build Coastguard Worker 
566*cf5a6c84SAndroid Build Coastguard Worker // returns a randome ID
getxid(void)567*cf5a6c84SAndroid Build Coastguard Worker static uint32_t getxid(void)
568*cf5a6c84SAndroid Build Coastguard Worker {
569*cf5a6c84SAndroid Build Coastguard Worker   uint32_t randnum;
570*cf5a6c84SAndroid Build Coastguard Worker   int fd = xopenro("/dev/urandom");
571*cf5a6c84SAndroid Build Coastguard Worker 
572*cf5a6c84SAndroid Build Coastguard Worker // TODO xreadfile
573*cf5a6c84SAndroid Build Coastguard Worker   xreadall(fd, &randnum, sizeof(randnum));
574*cf5a6c84SAndroid Build Coastguard Worker   xclose(fd);
575*cf5a6c84SAndroid Build Coastguard Worker   return randnum;
576*cf5a6c84SAndroid Build Coastguard Worker }
577*cf5a6c84SAndroid Build Coastguard Worker 
578*cf5a6c84SAndroid Build Coastguard Worker // opens socket in raw mode.
mode_raw(void)579*cf5a6c84SAndroid Build Coastguard Worker static int mode_raw(void)
580*cf5a6c84SAndroid Build Coastguard Worker {
581*cf5a6c84SAndroid Build Coastguard Worker   state->mode = MODE_OFF;
582*cf5a6c84SAndroid Build Coastguard Worker   struct sockaddr_ll sock;
583*cf5a6c84SAndroid Build Coastguard Worker 
584*cf5a6c84SAndroid Build Coastguard Worker   if (state->sockfd > 0) close(state->sockfd);
585*cf5a6c84SAndroid Build Coastguard Worker   dbg("Opening raw socket on ifindex %d\n", state->ifindex);
586*cf5a6c84SAndroid Build Coastguard Worker 
587*cf5a6c84SAndroid Build Coastguard Worker   state->sockfd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP));
588*cf5a6c84SAndroid Build Coastguard Worker   if (state->sockfd < 0) {
589*cf5a6c84SAndroid Build Coastguard Worker     dbg("MODE RAW : socket fail ERROR : %d\n", state->sockfd);
590*cf5a6c84SAndroid Build Coastguard Worker     return -1;
591*cf5a6c84SAndroid Build Coastguard Worker   }
592*cf5a6c84SAndroid Build Coastguard Worker   dbg("Got raw socket fd %d\n", state->sockfd);
593*cf5a6c84SAndroid Build Coastguard Worker   memset(&sock, 0, sizeof(sock));
594*cf5a6c84SAndroid Build Coastguard Worker   sock.sll_family = AF_PACKET;
595*cf5a6c84SAndroid Build Coastguard Worker   sock.sll_protocol = htons(ETH_P_IP);
596*cf5a6c84SAndroid Build Coastguard Worker   sock.sll_ifindex = state->ifindex;
597*cf5a6c84SAndroid Build Coastguard Worker 
598*cf5a6c84SAndroid Build Coastguard Worker   if (bind(state->sockfd, (struct sockaddr *) &sock, sizeof(sock))) {
599*cf5a6c84SAndroid Build Coastguard Worker     dbg("MODE RAW : bind fail.\n");
600*cf5a6c84SAndroid Build Coastguard Worker     close(state->sockfd);
601*cf5a6c84SAndroid Build Coastguard Worker     return -1;
602*cf5a6c84SAndroid Build Coastguard Worker   }
603*cf5a6c84SAndroid Build Coastguard Worker   state->mode = MODE_RAW;
604*cf5a6c84SAndroid Build Coastguard Worker   if (setsockopt(state->sockfd, SOL_SOCKET, SO_ATTACH_FILTER, &filter_prog, sizeof(filter_prog)) < 0)
605*cf5a6c84SAndroid Build Coastguard Worker     dbg("MODE RAW : filter attach fail.\n");
606*cf5a6c84SAndroid Build Coastguard Worker 
607*cf5a6c84SAndroid Build Coastguard Worker   dbg("MODE RAW : success\n");
608*cf5a6c84SAndroid Build Coastguard Worker   return 0;
609*cf5a6c84SAndroid Build Coastguard Worker }
610*cf5a6c84SAndroid Build Coastguard Worker 
611*cf5a6c84SAndroid Build Coastguard Worker // opens UDP socket
mode_app(void)612*cf5a6c84SAndroid Build Coastguard Worker static int mode_app(void)
613*cf5a6c84SAndroid Build Coastguard Worker {
614*cf5a6c84SAndroid Build Coastguard Worker   struct sockaddr_in addr;
615*cf5a6c84SAndroid Build Coastguard Worker   struct ifreq ifr;
616*cf5a6c84SAndroid Build Coastguard Worker 
617*cf5a6c84SAndroid Build Coastguard Worker   state->mode = MODE_OFF;
618*cf5a6c84SAndroid Build Coastguard Worker   if (state->sockfd > 0) close(state->sockfd);
619*cf5a6c84SAndroid Build Coastguard Worker 
620*cf5a6c84SAndroid Build Coastguard Worker   dbg("Opening listen socket on *:%d %s\n", DHCPC_CLIENT_PORT, state->iface);
621*cf5a6c84SAndroid Build Coastguard Worker   state->sockfd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
622*cf5a6c84SAndroid Build Coastguard Worker   if (state->sockfd < 0) {
623*cf5a6c84SAndroid Build Coastguard Worker     dbg("MODE APP : socket fail ERROR: %d\n", state->sockfd);
624*cf5a6c84SAndroid Build Coastguard Worker     return -1;
625*cf5a6c84SAndroid Build Coastguard Worker   }
626*cf5a6c84SAndroid Build Coastguard Worker   setsockopt(state->sockfd, SOL_SOCKET, SO_REUSEADDR, &set, sizeof(set));
627*cf5a6c84SAndroid Build Coastguard Worker   if (setsockopt(state->sockfd, SOL_SOCKET, SO_BROADCAST, &set, sizeof(set)) == -1) {
628*cf5a6c84SAndroid Build Coastguard Worker     dbg("MODE APP : brodcast failed.\n");
629*cf5a6c84SAndroid Build Coastguard Worker     close(state->sockfd);
630*cf5a6c84SAndroid Build Coastguard Worker     return -1;
631*cf5a6c84SAndroid Build Coastguard Worker   }
632*cf5a6c84SAndroid Build Coastguard Worker   xstrncpy(ifr.ifr_name, state->iface, IFNAMSIZ);
633*cf5a6c84SAndroid Build Coastguard Worker   ifr.ifr_name[IFNAMSIZ -1] = '\0';
634*cf5a6c84SAndroid Build Coastguard Worker   setsockopt(state->sockfd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr));
635*cf5a6c84SAndroid Build Coastguard Worker 
636*cf5a6c84SAndroid Build Coastguard Worker   memset(&addr, 0, sizeof(addr));
637*cf5a6c84SAndroid Build Coastguard Worker   addr.sin_family = AF_INET;
638*cf5a6c84SAndroid Build Coastguard Worker   addr.sin_port = htons(DHCPC_CLIENT_PORT);
639*cf5a6c84SAndroid Build Coastguard Worker   addr.sin_addr.s_addr = INADDR_ANY ;
640*cf5a6c84SAndroid Build Coastguard Worker 
641*cf5a6c84SAndroid Build Coastguard Worker   if (bind(state->sockfd, (struct sockaddr *) &addr, sizeof(addr))) {
642*cf5a6c84SAndroid Build Coastguard Worker     close(state->sockfd);
643*cf5a6c84SAndroid Build Coastguard Worker     dbg("MODE APP : bind failed.\n");
644*cf5a6c84SAndroid Build Coastguard Worker     return -1;
645*cf5a6c84SAndroid Build Coastguard Worker   }
646*cf5a6c84SAndroid Build Coastguard Worker   state->mode = MODE_APP;
647*cf5a6c84SAndroid Build Coastguard Worker   dbg("MODE APP : success\n");
648*cf5a6c84SAndroid Build Coastguard Worker   return 0;
649*cf5a6c84SAndroid Build Coastguard Worker }
650*cf5a6c84SAndroid Build Coastguard Worker 
read_raw(void)651*cf5a6c84SAndroid Build Coastguard Worker static int read_raw(void)
652*cf5a6c84SAndroid Build Coastguard Worker {
653*cf5a6c84SAndroid Build Coastguard Worker   dhcp_raw_t packet;
654*cf5a6c84SAndroid Build Coastguard Worker   int bytes = 0;
655*cf5a6c84SAndroid Build Coastguard Worker 
656*cf5a6c84SAndroid Build Coastguard Worker   memset(&packet, 0, sizeof(packet));
657*cf5a6c84SAndroid Build Coastguard Worker   if ((bytes = read(state->sockfd, &packet, sizeof(packet))) < 0) {
658*cf5a6c84SAndroid Build Coastguard Worker     dbg("\tPacket read error, ignoring\n");
659*cf5a6c84SAndroid Build Coastguard Worker     return bytes;
660*cf5a6c84SAndroid Build Coastguard Worker   }
661*cf5a6c84SAndroid Build Coastguard Worker   if (bytes < (int) (sizeof(packet.iph) + sizeof(packet.udph))) {
662*cf5a6c84SAndroid Build Coastguard Worker     dbg("\tPacket is too short, ignoring\n");
663*cf5a6c84SAndroid Build Coastguard Worker     return -2;
664*cf5a6c84SAndroid Build Coastguard Worker   }
665*cf5a6c84SAndroid Build Coastguard Worker   if (bytes < ntohs(packet.iph.tot_len)) {
666*cf5a6c84SAndroid Build Coastguard Worker     dbg("\tOversized packet, ignoring\n");
667*cf5a6c84SAndroid Build Coastguard Worker     return -2;
668*cf5a6c84SAndroid Build Coastguard Worker   }
669*cf5a6c84SAndroid Build Coastguard Worker   // ignore any extra garbage bytes
670*cf5a6c84SAndroid Build Coastguard Worker   bytes = ntohs(packet.iph.tot_len);
671*cf5a6c84SAndroid Build Coastguard Worker   // make sure its the right packet for us, and that it passes sanity checks
672*cf5a6c84SAndroid Build Coastguard Worker   if (packet.iph.protocol != IPPROTO_UDP || packet.iph.version != IPVERSION
673*cf5a6c84SAndroid Build Coastguard Worker    || packet.iph.ihl != (sizeof(packet.iph) >> 2)
674*cf5a6c84SAndroid Build Coastguard Worker    || packet.udph.dest != htons(DHCPC_CLIENT_PORT)
675*cf5a6c84SAndroid Build Coastguard Worker    || ntohs(packet.udph.len) != (uint16_t)(bytes - sizeof(packet.iph))) {
676*cf5a6c84SAndroid Build Coastguard Worker     dbg("\tUnrelated/bogus packet, ignoring\n");
677*cf5a6c84SAndroid Build Coastguard Worker     return -2;
678*cf5a6c84SAndroid Build Coastguard Worker   }
679*cf5a6c84SAndroid Build Coastguard Worker   // Verify IP checksum.
680*cf5a6c84SAndroid Build Coastguard Worker   if (dhcp_checksum(&packet.iph, sizeof(packet.iph)) != 0) {
681*cf5a6c84SAndroid Build Coastguard Worker     dbg("\tBad IP header checksum, ignoring\n");
682*cf5a6c84SAndroid Build Coastguard Worker     return -2;
683*cf5a6c84SAndroid Build Coastguard Worker   }
684*cf5a6c84SAndroid Build Coastguard Worker   // Verify UDP checksum. From RFC 768, the UDP checksum is done over the IPv4
685*cf5a6c84SAndroid Build Coastguard Worker   // pseudo header, the UDP header and the UDP data. The IPv4 pseudo header
686*cf5a6c84SAndroid Build Coastguard Worker   // includes saddr, daddr, protocol, and UDP length. The IP header has to be
687*cf5a6c84SAndroid Build Coastguard Worker   // modified for this.
688*cf5a6c84SAndroid Build Coastguard Worker   memset(&packet.iph, 0, ((size_t) &((struct iphdr *)0)->protocol));
689*cf5a6c84SAndroid Build Coastguard Worker   packet.iph.check = 0;
690*cf5a6c84SAndroid Build Coastguard Worker   packet.iph.tot_len = packet.udph.len;
691*cf5a6c84SAndroid Build Coastguard Worker   if (packet.udph.check != 0 && dhcp_checksum(&packet, bytes) != 0) {
692*cf5a6c84SAndroid Build Coastguard Worker     dbg("\tPacket with bad UDP checksum received, ignoring\n");
693*cf5a6c84SAndroid Build Coastguard Worker     return -2;
694*cf5a6c84SAndroid Build Coastguard Worker   }
695*cf5a6c84SAndroid Build Coastguard Worker   memcpy(&state->pdhcp, &packet.dhcp, bytes - (sizeof(packet.iph) + sizeof(packet.udph)));
696*cf5a6c84SAndroid Build Coastguard Worker   if (state->pdhcp.cookie != htonl(DHCP_MAGIC)) {
697*cf5a6c84SAndroid Build Coastguard Worker     dbg("\tPacket with bad magic, ignoring\n");
698*cf5a6c84SAndroid Build Coastguard Worker     return -2;
699*cf5a6c84SAndroid Build Coastguard Worker   }
700*cf5a6c84SAndroid Build Coastguard Worker   return bytes - sizeof(packet.iph) - sizeof(packet.udph);
701*cf5a6c84SAndroid Build Coastguard Worker }
702*cf5a6c84SAndroid Build Coastguard Worker 
read_app(void)703*cf5a6c84SAndroid Build Coastguard Worker static int read_app(void)
704*cf5a6c84SAndroid Build Coastguard Worker {
705*cf5a6c84SAndroid Build Coastguard Worker   int ret;
706*cf5a6c84SAndroid Build Coastguard Worker 
707*cf5a6c84SAndroid Build Coastguard Worker   memset(&state->pdhcp, 0, sizeof(dhcp_msg_t));
708*cf5a6c84SAndroid Build Coastguard Worker   if ((ret = read(state->sockfd, &state->pdhcp, sizeof(dhcp_msg_t))) < 0) {
709*cf5a6c84SAndroid Build Coastguard Worker     dbg("Packet read error, ignoring\n");
710*cf5a6c84SAndroid Build Coastguard Worker     return ret; /* returns -1 */
711*cf5a6c84SAndroid Build Coastguard Worker   }
712*cf5a6c84SAndroid Build Coastguard Worker   if (state->pdhcp.cookie != htonl(DHCP_MAGIC)) {
713*cf5a6c84SAndroid Build Coastguard Worker     dbg("Packet with bad magic, ignoring\n");
714*cf5a6c84SAndroid Build Coastguard Worker     return -2;
715*cf5a6c84SAndroid Build Coastguard Worker   }
716*cf5a6c84SAndroid Build Coastguard Worker   return ret;
717*cf5a6c84SAndroid Build Coastguard Worker }
718*cf5a6c84SAndroid Build Coastguard Worker 
719*cf5a6c84SAndroid Build Coastguard Worker // Sends data through raw socket.
send_raw(void)720*cf5a6c84SAndroid Build Coastguard Worker static int send_raw(void)
721*cf5a6c84SAndroid Build Coastguard Worker {
722*cf5a6c84SAndroid Build Coastguard Worker   struct sockaddr_ll dest_sll;
723*cf5a6c84SAndroid Build Coastguard Worker   dhcp_raw_t packet;
724*cf5a6c84SAndroid Build Coastguard Worker   unsigned padding;
725*cf5a6c84SAndroid Build Coastguard Worker   int fd, result = -1;
726*cf5a6c84SAndroid Build Coastguard Worker 
727*cf5a6c84SAndroid Build Coastguard Worker   memset(&packet, 0, sizeof(dhcp_raw_t));
728*cf5a6c84SAndroid Build Coastguard Worker   memcpy(&packet.dhcp, &state->pdhcp, sizeof(dhcp_msg_t));
729*cf5a6c84SAndroid Build Coastguard Worker 
730*cf5a6c84SAndroid Build Coastguard Worker   if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) {
731*cf5a6c84SAndroid Build Coastguard Worker     dbg("SEND RAW: socket failed\n");
732*cf5a6c84SAndroid Build Coastguard Worker     return result;
733*cf5a6c84SAndroid Build Coastguard Worker   }
734*cf5a6c84SAndroid Build Coastguard Worker   memset(&dest_sll, 0, sizeof(dest_sll));
735*cf5a6c84SAndroid Build Coastguard Worker   dest_sll.sll_family = AF_PACKET;
736*cf5a6c84SAndroid Build Coastguard Worker   dest_sll.sll_protocol = htons(ETH_P_IP);
737*cf5a6c84SAndroid Build Coastguard Worker   dest_sll.sll_ifindex = state->ifindex;
738*cf5a6c84SAndroid Build Coastguard Worker   dest_sll.sll_halen = 6;
739*cf5a6c84SAndroid Build Coastguard Worker   memcpy(dest_sll.sll_addr, bmacaddr , 6);
740*cf5a6c84SAndroid Build Coastguard Worker 
741*cf5a6c84SAndroid Build Coastguard Worker   if (bind(fd, (struct sockaddr *) &dest_sll, sizeof(dest_sll)) < 0) {
742*cf5a6c84SAndroid Build Coastguard Worker     dbg("SEND RAW: bind failed\n");
743*cf5a6c84SAndroid Build Coastguard Worker     close(fd);
744*cf5a6c84SAndroid Build Coastguard Worker     return result;
745*cf5a6c84SAndroid Build Coastguard Worker   }
746*cf5a6c84SAndroid Build Coastguard Worker   padding = 308 - 1 - dhcp_opt_size(state->pdhcp.options);
747*cf5a6c84SAndroid Build Coastguard Worker   packet.iph.protocol = IPPROTO_UDP;
748*cf5a6c84SAndroid Build Coastguard Worker   packet.iph.saddr = INADDR_ANY;
749*cf5a6c84SAndroid Build Coastguard Worker   packet.iph.daddr = INADDR_BROADCAST;
750*cf5a6c84SAndroid Build Coastguard Worker   packet.udph.source = htons(DHCPC_CLIENT_PORT);
751*cf5a6c84SAndroid Build Coastguard Worker   packet.udph.dest = htons(DHCPC_SERVER_PORT);
752*cf5a6c84SAndroid Build Coastguard Worker   packet.udph.len = htons(sizeof(dhcp_raw_t) - sizeof(struct iphdr) - padding);
753*cf5a6c84SAndroid Build Coastguard Worker   packet.iph.tot_len = packet.udph.len;
754*cf5a6c84SAndroid Build Coastguard Worker   packet.udph.check = dhcp_checksum(&packet, sizeof(dhcp_raw_t) - padding);
755*cf5a6c84SAndroid Build Coastguard Worker   packet.iph.tot_len = htons(sizeof(dhcp_raw_t) - padding);
756*cf5a6c84SAndroid Build Coastguard Worker   packet.iph.ihl = sizeof(packet.iph) >> 2;
757*cf5a6c84SAndroid Build Coastguard Worker   packet.iph.version = IPVERSION;
758*cf5a6c84SAndroid Build Coastguard Worker   packet.iph.ttl = IPDEFTTL;
759*cf5a6c84SAndroid Build Coastguard Worker   packet.iph.check = dhcp_checksum(&packet.iph, sizeof(packet.iph));
760*cf5a6c84SAndroid Build Coastguard Worker 
761*cf5a6c84SAndroid Build Coastguard Worker   result = sendto(fd, &packet, sizeof(dhcp_raw_t) - padding, 0,
762*cf5a6c84SAndroid Build Coastguard Worker       (struct sockaddr *) &dest_sll, sizeof(dest_sll));
763*cf5a6c84SAndroid Build Coastguard Worker 
764*cf5a6c84SAndroid Build Coastguard Worker   close(fd);
765*cf5a6c84SAndroid Build Coastguard Worker   if (result < 0) dbg("SEND RAW: PACKET send error\n");
766*cf5a6c84SAndroid Build Coastguard Worker   return result;
767*cf5a6c84SAndroid Build Coastguard Worker }
768*cf5a6c84SAndroid Build Coastguard Worker 
769*cf5a6c84SAndroid Build Coastguard Worker // Sends data through UDP socket.
send_app(void)770*cf5a6c84SAndroid Build Coastguard Worker static int send_app(void)
771*cf5a6c84SAndroid Build Coastguard Worker {
772*cf5a6c84SAndroid Build Coastguard Worker   struct sockaddr_in cli;
773*cf5a6c84SAndroid Build Coastguard Worker   int fd, ret = -1;
774*cf5a6c84SAndroid Build Coastguard Worker 
775*cf5a6c84SAndroid Build Coastguard Worker   if ((fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
776*cf5a6c84SAndroid Build Coastguard Worker     dbg("SEND APP: sock failed.\n");
777*cf5a6c84SAndroid Build Coastguard Worker     return ret;
778*cf5a6c84SAndroid Build Coastguard Worker   }
779*cf5a6c84SAndroid Build Coastguard Worker   setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &set, sizeof(set));
780*cf5a6c84SAndroid Build Coastguard Worker 
781*cf5a6c84SAndroid Build Coastguard Worker   memset(&cli, 0, sizeof(cli));
782*cf5a6c84SAndroid Build Coastguard Worker   cli.sin_family = AF_INET;
783*cf5a6c84SAndroid Build Coastguard Worker   cli.sin_port = htons(DHCPC_CLIENT_PORT);
784*cf5a6c84SAndroid Build Coastguard Worker   cli.sin_addr.s_addr = state->pdhcp.ciaddr;
785*cf5a6c84SAndroid Build Coastguard Worker   if (bind(fd, (struct sockaddr *)&cli, sizeof(cli)) == -1) {
786*cf5a6c84SAndroid Build Coastguard Worker     dbg("SEND APP: bind failed.\n");
787*cf5a6c84SAndroid Build Coastguard Worker     goto error_fd;
788*cf5a6c84SAndroid Build Coastguard Worker   }
789*cf5a6c84SAndroid Build Coastguard Worker   memset(&cli, 0, sizeof(cli));
790*cf5a6c84SAndroid Build Coastguard Worker   cli.sin_family = AF_INET;
791*cf5a6c84SAndroid Build Coastguard Worker   cli.sin_port = htons(DHCPC_SERVER_PORT);
792*cf5a6c84SAndroid Build Coastguard Worker   cli.sin_addr.s_addr = state->serverid.s_addr;
793*cf5a6c84SAndroid Build Coastguard Worker   if (connect(fd, (struct sockaddr *)&cli, sizeof(cli)) == -1) {
794*cf5a6c84SAndroid Build Coastguard Worker     dbg("SEND APP: connect failed.\n");
795*cf5a6c84SAndroid Build Coastguard Worker     goto error_fd;
796*cf5a6c84SAndroid Build Coastguard Worker   }
797*cf5a6c84SAndroid Build Coastguard Worker   int padding = 308 - 1 - dhcp_opt_size(state->pdhcp.options);
798*cf5a6c84SAndroid Build Coastguard Worker   if((ret = write(fd, &state->pdhcp, sizeof(dhcp_msg_t) - padding)) < 0) {
799*cf5a6c84SAndroid Build Coastguard Worker     dbg("SEND APP: write failed error %d\n", ret);
800*cf5a6c84SAndroid Build Coastguard Worker     goto error_fd;
801*cf5a6c84SAndroid Build Coastguard Worker   }
802*cf5a6c84SAndroid Build Coastguard Worker   dbg("SEND APP: write success wrote %d\n", ret);
803*cf5a6c84SAndroid Build Coastguard Worker error_fd:
804*cf5a6c84SAndroid Build Coastguard Worker   close(fd);
805*cf5a6c84SAndroid Build Coastguard Worker   return ret;
806*cf5a6c84SAndroid Build Coastguard Worker }
807*cf5a6c84SAndroid Build Coastguard Worker 
808*cf5a6c84SAndroid Build Coastguard Worker // Generic signal handler real handling is done in main funcrion.
signal_handler(int sig)809*cf5a6c84SAndroid Build Coastguard Worker static void signal_handler(int sig)
810*cf5a6c84SAndroid Build Coastguard Worker {
811*cf5a6c84SAndroid Build Coastguard Worker   unsigned char ch = sig;
812*cf5a6c84SAndroid Build Coastguard Worker   if (write(sigfd.wr, &ch, 1) != 1) dbg("can't send signal\n");
813*cf5a6c84SAndroid Build Coastguard Worker }
814*cf5a6c84SAndroid Build Coastguard Worker 
815*cf5a6c84SAndroid Build Coastguard Worker // signal setup for SIGUSR1 SIGUSR2 SIGTERM
setup_signal()816*cf5a6c84SAndroid Build Coastguard Worker static int setup_signal()
817*cf5a6c84SAndroid Build Coastguard Worker {
818*cf5a6c84SAndroid Build Coastguard Worker   if (pipe((int *)&sigfd) < 0) {
819*cf5a6c84SAndroid Build Coastguard Worker     dbg("signal pipe failed\n");
820*cf5a6c84SAndroid Build Coastguard Worker     return -1;
821*cf5a6c84SAndroid Build Coastguard Worker   }
822*cf5a6c84SAndroid Build Coastguard Worker   fcntl(sigfd.wr , F_SETFD, FD_CLOEXEC);
823*cf5a6c84SAndroid Build Coastguard Worker   fcntl(sigfd.rd , F_SETFD, FD_CLOEXEC);
824*cf5a6c84SAndroid Build Coastguard Worker   int flags = fcntl(sigfd.wr, F_GETFL);
825*cf5a6c84SAndroid Build Coastguard Worker   fcntl(sigfd.wr, F_SETFL, flags | O_NONBLOCK);
826*cf5a6c84SAndroid Build Coastguard Worker   signal(SIGUSR1, signal_handler);
827*cf5a6c84SAndroid Build Coastguard Worker   signal(SIGUSR2, signal_handler);
828*cf5a6c84SAndroid Build Coastguard Worker   signal(SIGTERM, signal_handler);
829*cf5a6c84SAndroid Build Coastguard Worker 
830*cf5a6c84SAndroid Build Coastguard Worker   return 0;
831*cf5a6c84SAndroid Build Coastguard Worker }
832*cf5a6c84SAndroid Build Coastguard Worker 
833*cf5a6c84SAndroid Build Coastguard Worker // adds client id to dhcp packet
dhcpc_addclientid(uint8_t * optptr)834*cf5a6c84SAndroid Build Coastguard Worker static uint8_t *dhcpc_addclientid(uint8_t *optptr)
835*cf5a6c84SAndroid Build Coastguard Worker {
836*cf5a6c84SAndroid Build Coastguard Worker   *optptr++ = DHCP_OPTION_CLIENTID;
837*cf5a6c84SAndroid Build Coastguard Worker   *optptr++ = 7;
838*cf5a6c84SAndroid Build Coastguard Worker   *optptr++ = 1;
839*cf5a6c84SAndroid Build Coastguard Worker   memcpy(optptr, &state->macaddr, 6);
840*cf5a6c84SAndroid Build Coastguard Worker   return optptr + 6;
841*cf5a6c84SAndroid Build Coastguard Worker }
842*cf5a6c84SAndroid Build Coastguard Worker 
843*cf5a6c84SAndroid Build Coastguard Worker // adds messege type to dhcp packet
dhcpc_addmsgtype(uint8_t * optptr,uint8_t type)844*cf5a6c84SAndroid Build Coastguard Worker static uint8_t *dhcpc_addmsgtype(uint8_t *optptr, uint8_t type)
845*cf5a6c84SAndroid Build Coastguard Worker {
846*cf5a6c84SAndroid Build Coastguard Worker   *optptr++ = DHCP_OPTION_MSG_TYPE;
847*cf5a6c84SAndroid Build Coastguard Worker   *optptr++ = 1;
848*cf5a6c84SAndroid Build Coastguard Worker   *optptr++ = type;
849*cf5a6c84SAndroid Build Coastguard Worker   return optptr;
850*cf5a6c84SAndroid Build Coastguard Worker }
851*cf5a6c84SAndroid Build Coastguard Worker 
852*cf5a6c84SAndroid Build Coastguard Worker // adds max size to dhcp packet
dhcpc_addmaxsize(uint8_t * optptr,uint16_t size)853*cf5a6c84SAndroid Build Coastguard Worker static uint8_t *dhcpc_addmaxsize(uint8_t *optptr, uint16_t size)
854*cf5a6c84SAndroid Build Coastguard Worker {
855*cf5a6c84SAndroid Build Coastguard Worker   *optptr++ = DHCP_OPTION_MAX_SIZE;
856*cf5a6c84SAndroid Build Coastguard Worker   *optptr++ = 2;
857*cf5a6c84SAndroid Build Coastguard Worker   memcpy(optptr, &size, 2);
858*cf5a6c84SAndroid Build Coastguard Worker   return optptr + 2;
859*cf5a6c84SAndroid Build Coastguard Worker }
860*cf5a6c84SAndroid Build Coastguard Worker 
dhcpc_addstropt(uint8_t * optptr,uint8_t opcode,char * str,int len)861*cf5a6c84SAndroid Build Coastguard Worker static uint8_t *dhcpc_addstropt(uint8_t *optptr, uint8_t opcode, char* str, int len)
862*cf5a6c84SAndroid Build Coastguard Worker {
863*cf5a6c84SAndroid Build Coastguard Worker   *optptr++ = opcode;
864*cf5a6c84SAndroid Build Coastguard Worker   *optptr++ = len;
865*cf5a6c84SAndroid Build Coastguard Worker   memcpy(optptr, str, len);
866*cf5a6c84SAndroid Build Coastguard Worker   return optptr + len;
867*cf5a6c84SAndroid Build Coastguard Worker }
868*cf5a6c84SAndroid Build Coastguard Worker 
869*cf5a6c84SAndroid Build Coastguard Worker // adds server id to dhcp packet.
dhcpc_addserverid(struct in_addr * serverid,uint8_t * optptr)870*cf5a6c84SAndroid Build Coastguard Worker static uint8_t *dhcpc_addserverid(struct in_addr *serverid, uint8_t *optptr)
871*cf5a6c84SAndroid Build Coastguard Worker {
872*cf5a6c84SAndroid Build Coastguard Worker   *optptr++ = DHCP_OPTION_SERVER_ID;
873*cf5a6c84SAndroid Build Coastguard Worker   *optptr++ = 4;
874*cf5a6c84SAndroid Build Coastguard Worker   memcpy(optptr, &serverid->s_addr, 4);
875*cf5a6c84SAndroid Build Coastguard Worker   return optptr + 4;
876*cf5a6c84SAndroid Build Coastguard Worker }
877*cf5a6c84SAndroid Build Coastguard Worker 
878*cf5a6c84SAndroid Build Coastguard Worker // adds requested ip address to dhcp packet.
dhcpc_addreqipaddr(struct in_addr * ipaddr,uint8_t * optptr)879*cf5a6c84SAndroid Build Coastguard Worker static uint8_t *dhcpc_addreqipaddr(struct in_addr *ipaddr, uint8_t *optptr)
880*cf5a6c84SAndroid Build Coastguard Worker {
881*cf5a6c84SAndroid Build Coastguard Worker   *optptr++ = DHCP_OPTION_REQ_IPADDR;
882*cf5a6c84SAndroid Build Coastguard Worker   *optptr++ = 4;
883*cf5a6c84SAndroid Build Coastguard Worker   memcpy(optptr, &ipaddr->s_addr, 4);
884*cf5a6c84SAndroid Build Coastguard Worker   return optptr + 4;
885*cf5a6c84SAndroid Build Coastguard Worker }
886*cf5a6c84SAndroid Build Coastguard Worker 
887*cf5a6c84SAndroid Build Coastguard Worker // adds hostname to dhcp packet.
dhcpc_addfdnname(uint8_t * optptr,char * hname)888*cf5a6c84SAndroid Build Coastguard Worker static uint8_t *dhcpc_addfdnname(uint8_t *optptr, char *hname)
889*cf5a6c84SAndroid Build Coastguard Worker {
890*cf5a6c84SAndroid Build Coastguard Worker   int size = strlen(hname);
891*cf5a6c84SAndroid Build Coastguard Worker 
892*cf5a6c84SAndroid Build Coastguard Worker   *optptr++ = DHCP_OPTION_FQDN;
893*cf5a6c84SAndroid Build Coastguard Worker   *optptr++ = size + 3;
894*cf5a6c84SAndroid Build Coastguard Worker   *optptr++ = 0x1;  //flags
895*cf5a6c84SAndroid Build Coastguard Worker   optptr += 2;      // two blank bytes
896*cf5a6c84SAndroid Build Coastguard Worker   strcpy((char*)optptr, hname); // name
897*cf5a6c84SAndroid Build Coastguard Worker 
898*cf5a6c84SAndroid Build Coastguard Worker   return optptr + size;
899*cf5a6c84SAndroid Build Coastguard Worker }
900*cf5a6c84SAndroid Build Coastguard Worker 
901*cf5a6c84SAndroid Build Coastguard Worker // adds request options using -o,-O flag to dhcp packet
dhcpc_addreqoptions(uint8_t * optptr)902*cf5a6c84SAndroid Build Coastguard Worker static uint8_t *dhcpc_addreqoptions(uint8_t *optptr)
903*cf5a6c84SAndroid Build Coastguard Worker {
904*cf5a6c84SAndroid Build Coastguard Worker   uint8_t *len;
905*cf5a6c84SAndroid Build Coastguard Worker 
906*cf5a6c84SAndroid Build Coastguard Worker   *optptr++ = DHCP_OPTION_REQ_LIST;
907*cf5a6c84SAndroid Build Coastguard Worker   len = optptr;
908*cf5a6c84SAndroid Build Coastguard Worker   *len = 0;
909*cf5a6c84SAndroid Build Coastguard Worker   optptr++;
910*cf5a6c84SAndroid Build Coastguard Worker 
911*cf5a6c84SAndroid Build Coastguard Worker   if (!(toys.optflags & FLAG_o)) {
912*cf5a6c84SAndroid Build Coastguard Worker     *len = 4;
913*cf5a6c84SAndroid Build Coastguard Worker     *optptr++ = DHCP_OPTION_SUBNET_MASK;
914*cf5a6c84SAndroid Build Coastguard Worker     *optptr++ = DHCP_OPTION_ROUTER;
915*cf5a6c84SAndroid Build Coastguard Worker     *optptr++ = DHCP_OPTION_DNS_SERVER;
916*cf5a6c84SAndroid Build Coastguard Worker     *optptr++ = DHCP_OPTION_BROADCAST;
917*cf5a6c84SAndroid Build Coastguard Worker   }
918*cf5a6c84SAndroid Build Coastguard Worker   if (toys.optflags & FLAG_O) {
919*cf5a6c84SAndroid Build Coastguard Worker     memcpy(optptr++, raw_opt, raw_optcount);
920*cf5a6c84SAndroid Build Coastguard Worker     *len += raw_optcount;
921*cf5a6c84SAndroid Build Coastguard Worker   }
922*cf5a6c84SAndroid Build Coastguard Worker   return optptr;
923*cf5a6c84SAndroid Build Coastguard Worker }
924*cf5a6c84SAndroid Build Coastguard Worker 
dhcpc_addend(uint8_t * optptr)925*cf5a6c84SAndroid Build Coastguard Worker static uint8_t *dhcpc_addend(uint8_t *optptr)
926*cf5a6c84SAndroid Build Coastguard Worker {
927*cf5a6c84SAndroid Build Coastguard Worker   *optptr++ = DHCP_OPTION_END;
928*cf5a6c84SAndroid Build Coastguard Worker   return optptr;
929*cf5a6c84SAndroid Build Coastguard Worker }
930*cf5a6c84SAndroid Build Coastguard Worker 
931*cf5a6c84SAndroid Build Coastguard Worker // Sets values of -x options in dhcp discover and request packet.
set_xopt(uint8_t * optptr)932*cf5a6c84SAndroid Build Coastguard Worker static uint8_t* set_xopt(uint8_t *optptr)
933*cf5a6c84SAndroid Build Coastguard Worker {
934*cf5a6c84SAndroid Build Coastguard Worker   int count;
935*cf5a6c84SAndroid Build Coastguard Worker   int size = ARRAY_LEN(options_list);
936*cf5a6c84SAndroid Build Coastguard Worker   for (count = 0; count < size; count++) {
937*cf5a6c84SAndroid Build Coastguard Worker     if ((options_list[count].len == 0) || (options_list[count].val == NULL)) continue;
938*cf5a6c84SAndroid Build Coastguard Worker     *optptr++ = (uint8_t) (options_list[count].code & 0x00FF);
939*cf5a6c84SAndroid Build Coastguard Worker     *optptr++ = (uint8_t) options_list[count].len;
940*cf5a6c84SAndroid Build Coastguard Worker     memcpy(optptr, options_list[count].val, options_list[count].len);
941*cf5a6c84SAndroid Build Coastguard Worker     optptr += options_list[count].len;
942*cf5a6c84SAndroid Build Coastguard Worker   }
943*cf5a6c84SAndroid Build Coastguard Worker   return optptr;
944*cf5a6c84SAndroid Build Coastguard Worker }
945*cf5a6c84SAndroid Build Coastguard Worker 
get_option_serverid(uint8_t * opt,dhcpc_result_t * presult)946*cf5a6c84SAndroid Build Coastguard Worker static uint32_t get_option_serverid (uint8_t *opt, dhcpc_result_t *presult)
947*cf5a6c84SAndroid Build Coastguard Worker {
948*cf5a6c84SAndroid Build Coastguard Worker   uint32_t var = 0;
949*cf5a6c84SAndroid Build Coastguard Worker   while (*opt != DHCP_OPTION_SERVER_ID) {
950*cf5a6c84SAndroid Build Coastguard Worker     if (*opt == DHCP_OPTION_END) return var;
951*cf5a6c84SAndroid Build Coastguard Worker     opt += opt[1] + 2;
952*cf5a6c84SAndroid Build Coastguard Worker   }
953*cf5a6c84SAndroid Build Coastguard Worker   memcpy(&var, opt+2, sizeof(uint32_t));
954*cf5a6c84SAndroid Build Coastguard Worker   state->serverid.s_addr = var;
955*cf5a6c84SAndroid Build Coastguard Worker   presult->serverid.s_addr = state->serverid.s_addr;
956*cf5a6c84SAndroid Build Coastguard Worker   presult->serverid.s_addr = ntohl(presult->serverid.s_addr);
957*cf5a6c84SAndroid Build Coastguard Worker   return var;
958*cf5a6c84SAndroid Build Coastguard Worker }
959*cf5a6c84SAndroid Build Coastguard Worker 
get_option_msgtype(uint8_t * opt)960*cf5a6c84SAndroid Build Coastguard Worker static uint8_t get_option_msgtype(uint8_t *opt)
961*cf5a6c84SAndroid Build Coastguard Worker {
962*cf5a6c84SAndroid Build Coastguard Worker   uint32_t var = 0;
963*cf5a6c84SAndroid Build Coastguard Worker   while (*opt != DHCP_OPTION_MSG_TYPE) {
964*cf5a6c84SAndroid Build Coastguard Worker     if (*opt == DHCP_OPTION_END) return var;
965*cf5a6c84SAndroid Build Coastguard Worker     opt += opt[1] + 2;
966*cf5a6c84SAndroid Build Coastguard Worker   }
967*cf5a6c84SAndroid Build Coastguard Worker   memcpy(&var, opt+2, sizeof(uint8_t));
968*cf5a6c84SAndroid Build Coastguard Worker   return var;
969*cf5a6c84SAndroid Build Coastguard Worker }
970*cf5a6c84SAndroid Build Coastguard Worker 
get_option_lease(uint8_t * opt,dhcpc_result_t * presult)971*cf5a6c84SAndroid Build Coastguard Worker static uint8_t get_option_lease(uint8_t *opt, dhcpc_result_t *presult)
972*cf5a6c84SAndroid Build Coastguard Worker {
973*cf5a6c84SAndroid Build Coastguard Worker   uint32_t var = 0;
974*cf5a6c84SAndroid Build Coastguard Worker   while (*opt != DHCP_OPTION_LEASE_TIME) {
975*cf5a6c84SAndroid Build Coastguard Worker     if (*opt == DHCP_OPTION_END) return var;
976*cf5a6c84SAndroid Build Coastguard Worker     opt += opt[1] + 2;
977*cf5a6c84SAndroid Build Coastguard Worker   }
978*cf5a6c84SAndroid Build Coastguard Worker   memcpy(&var, opt+2, sizeof(uint32_t));
979*cf5a6c84SAndroid Build Coastguard Worker   var = htonl(var);
980*cf5a6c84SAndroid Build Coastguard Worker   presult->lease_time = var;
981*cf5a6c84SAndroid Build Coastguard Worker   return var;
982*cf5a6c84SAndroid Build Coastguard Worker }
983*cf5a6c84SAndroid Build Coastguard Worker 
984*cf5a6c84SAndroid Build Coastguard Worker 
985*cf5a6c84SAndroid Build Coastguard Worker // sends dhcp msg of MSGTYPE
dhcpc_sendmsg(int msgtype)986*cf5a6c84SAndroid Build Coastguard Worker static int dhcpc_sendmsg(int msgtype)
987*cf5a6c84SAndroid Build Coastguard Worker {
988*cf5a6c84SAndroid Build Coastguard Worker   uint8_t *pend;
989*cf5a6c84SAndroid Build Coastguard Worker   struct in_addr rqsd;
990*cf5a6c84SAndroid Build Coastguard Worker   char *vendor;
991*cf5a6c84SAndroid Build Coastguard Worker 
992*cf5a6c84SAndroid Build Coastguard Worker   // Create the common message header settings
993*cf5a6c84SAndroid Build Coastguard Worker   memset(&state->pdhcp, 0, sizeof(dhcp_msg_t));
994*cf5a6c84SAndroid Build Coastguard Worker   state->pdhcp.op = DHCP_REQUEST;
995*cf5a6c84SAndroid Build Coastguard Worker   state->pdhcp.htype = DHCP_HTYPE_ETHERNET;
996*cf5a6c84SAndroid Build Coastguard Worker   state->pdhcp.hlen = 6;
997*cf5a6c84SAndroid Build Coastguard Worker   state->pdhcp.xid = xid;
998*cf5a6c84SAndroid Build Coastguard Worker   memcpy(state->pdhcp.chaddr, state->macaddr, 6);
999*cf5a6c84SAndroid Build Coastguard Worker   memset(&state->pdhcp.chaddr[6], 0, 10);
1000*cf5a6c84SAndroid Build Coastguard Worker   state->pdhcp.cookie = htonl(DHCP_MAGIC);;
1001*cf5a6c84SAndroid Build Coastguard Worker 
1002*cf5a6c84SAndroid Build Coastguard Worker   // Add the common header options
1003*cf5a6c84SAndroid Build Coastguard Worker   pend = state->pdhcp.options;
1004*cf5a6c84SAndroid Build Coastguard Worker   pend = dhcpc_addmsgtype(pend, msgtype);
1005*cf5a6c84SAndroid Build Coastguard Worker 
1006*cf5a6c84SAndroid Build Coastguard Worker   if (!(toys.optflags & FLAG_C)) pend = dhcpc_addclientid(pend);
1007*cf5a6c84SAndroid Build Coastguard Worker   // Handle the message specific settings
1008*cf5a6c84SAndroid Build Coastguard Worker   switch (msgtype) {
1009*cf5a6c84SAndroid Build Coastguard Worker   case DHCPDISCOVER: // Broadcast DISCOVER message to all servers
1010*cf5a6c84SAndroid Build Coastguard Worker     state->pdhcp.flags = htons(BOOTP_BROADCAST); //  Broadcast bit.
1011*cf5a6c84SAndroid Build Coastguard Worker     if (toys.optflags & FLAG_r) {
1012*cf5a6c84SAndroid Build Coastguard Worker       inet_aton(TT.req_ip, &rqsd);
1013*cf5a6c84SAndroid Build Coastguard Worker       pend = dhcpc_addreqipaddr(&rqsd, pend);
1014*cf5a6c84SAndroid Build Coastguard Worker     }
1015*cf5a6c84SAndroid Build Coastguard Worker     pend = dhcpc_addmaxsize(pend, htons(sizeof(dhcp_raw_t)));
1016*cf5a6c84SAndroid Build Coastguard Worker     vendor = (toys.optflags & FLAG_V) ? TT.vendor_cls : "toybox\0";
1017*cf5a6c84SAndroid Build Coastguard Worker     pend = dhcpc_addstropt(pend, DHCP_OPTION_VENDOR, vendor, strlen(vendor));
1018*cf5a6c84SAndroid Build Coastguard Worker     if (toys.optflags & FLAG_H) pend = dhcpc_addstropt(pend, DHCP_OPTION_HOST_NAME, TT.hostname, strlen(TT.hostname));
1019*cf5a6c84SAndroid Build Coastguard Worker     if (toys.optflags & FLAG_F) pend = dhcpc_addfdnname(pend, TT.fdn_name);
1020*cf5a6c84SAndroid Build Coastguard Worker     if (!(toys.optflags & FLAG_o) || (toys.optflags & FLAG_O))
1021*cf5a6c84SAndroid Build Coastguard Worker       pend = dhcpc_addreqoptions(pend);
1022*cf5a6c84SAndroid Build Coastguard Worker     if (toys.optflags & FLAG_x) pend = set_xopt(pend);
1023*cf5a6c84SAndroid Build Coastguard Worker     break;
1024*cf5a6c84SAndroid Build Coastguard Worker   case DHCPREQUEST: // Send REQUEST message to the server that sent the *first* OFFER
1025*cf5a6c84SAndroid Build Coastguard Worker     state->pdhcp.flags = htons(BOOTP_BROADCAST); //  Broadcast bit.
1026*cf5a6c84SAndroid Build Coastguard Worker     if (state->status == STATE_RENEWING) memcpy(&state->pdhcp.ciaddr, &state->ipaddr.s_addr, 4);
1027*cf5a6c84SAndroid Build Coastguard Worker     pend = dhcpc_addmaxsize(pend, htons(sizeof(dhcp_raw_t)));
1028*cf5a6c84SAndroid Build Coastguard Worker     rqsd.s_addr = htonl(server);
1029*cf5a6c84SAndroid Build Coastguard Worker     pend = dhcpc_addserverid(&rqsd, pend);
1030*cf5a6c84SAndroid Build Coastguard Worker     pend = dhcpc_addreqipaddr(&state->ipaddr, pend);
1031*cf5a6c84SAndroid Build Coastguard Worker     vendor = (toys.optflags & FLAG_V) ? TT.vendor_cls : "toybox\0";
1032*cf5a6c84SAndroid Build Coastguard Worker     pend = dhcpc_addstropt(pend, DHCP_OPTION_VENDOR, vendor, strlen(vendor));
1033*cf5a6c84SAndroid Build Coastguard Worker     if (toys.optflags & FLAG_H) pend = dhcpc_addstropt(pend, DHCP_OPTION_HOST_NAME, TT.hostname, strlen(TT.hostname));
1034*cf5a6c84SAndroid Build Coastguard Worker     if (toys.optflags & FLAG_F) pend = dhcpc_addfdnname(pend, TT.fdn_name);
1035*cf5a6c84SAndroid Build Coastguard Worker     if (!(toys.optflags & FLAG_o) || (toys.optflags & FLAG_O))
1036*cf5a6c84SAndroid Build Coastguard Worker       pend = dhcpc_addreqoptions(pend);
1037*cf5a6c84SAndroid Build Coastguard Worker     if (toys.optflags & FLAG_x) pend = set_xopt(pend);
1038*cf5a6c84SAndroid Build Coastguard Worker     break;
1039*cf5a6c84SAndroid Build Coastguard Worker   case DHCPRELEASE: // Send RELEASE message to the server.
1040*cf5a6c84SAndroid Build Coastguard Worker     memcpy(&state->pdhcp.ciaddr, &state->ipaddr.s_addr, 4);
1041*cf5a6c84SAndroid Build Coastguard Worker     rqsd.s_addr = htonl(server);
1042*cf5a6c84SAndroid Build Coastguard Worker     pend = dhcpc_addserverid(&rqsd, pend);
1043*cf5a6c84SAndroid Build Coastguard Worker     break;
1044*cf5a6c84SAndroid Build Coastguard Worker   default:
1045*cf5a6c84SAndroid Build Coastguard Worker     return -1;
1046*cf5a6c84SAndroid Build Coastguard Worker   }
1047*cf5a6c84SAndroid Build Coastguard Worker   pend = dhcpc_addend(pend);
1048*cf5a6c84SAndroid Build Coastguard Worker 
1049*cf5a6c84SAndroid Build Coastguard Worker   if (state->mode == MODE_APP) return send_app();
1050*cf5a6c84SAndroid Build Coastguard Worker   return send_raw();
1051*cf5a6c84SAndroid Build Coastguard Worker }
1052*cf5a6c84SAndroid Build Coastguard Worker 
1053*cf5a6c84SAndroid Build Coastguard Worker /*
1054*cf5a6c84SAndroid Build Coastguard Worker  * parses options from received dhcp packet at OPTPTR and
1055*cf5a6c84SAndroid Build Coastguard Worker  * stores result in PRESULT or MSGOPT_LIST
1056*cf5a6c84SAndroid Build Coastguard Worker  */
dhcpc_parseoptions(dhcpc_result_t * presult,uint8_t * optptr)1057*cf5a6c84SAndroid Build Coastguard Worker static uint8_t dhcpc_parseoptions(dhcpc_result_t *presult, uint8_t *optptr)
1058*cf5a6c84SAndroid Build Coastguard Worker {
1059*cf5a6c84SAndroid Build Coastguard Worker   uint8_t type = 0, *options, overloaded = 0;;
1060*cf5a6c84SAndroid Build Coastguard Worker   uint16_t flag = 0;
1061*cf5a6c84SAndroid Build Coastguard Worker   char *dest, *pfx;
1062*cf5a6c84SAndroid Build Coastguard Worker   int count, optlen, size = ARRAY_LEN(options_list);
1063*cf5a6c84SAndroid Build Coastguard Worker 
1064*cf5a6c84SAndroid Build Coastguard Worker   if (toys.optflags & FLAG_x) {
1065*cf5a6c84SAndroid Build Coastguard Worker     if(msgopt_list){
1066*cf5a6c84SAndroid Build Coastguard Worker       for (count = 0; count < size; count++){
1067*cf5a6c84SAndroid Build Coastguard Worker         if(msgopt_list[count].val) free(msgopt_list[count].val);
1068*cf5a6c84SAndroid Build Coastguard Worker         msgopt_list[count].val = NULL;
1069*cf5a6c84SAndroid Build Coastguard Worker         msgopt_list[count].len = 0;
1070*cf5a6c84SAndroid Build Coastguard Worker       }
1071*cf5a6c84SAndroid Build Coastguard Worker     } else {
1072*cf5a6c84SAndroid Build Coastguard Worker      msgopt_list = xmalloc(sizeof(options_list));
1073*cf5a6c84SAndroid Build Coastguard Worker      memcpy(msgopt_list, options_list, sizeof(options_list));
1074*cf5a6c84SAndroid Build Coastguard Worker      for (count = 0; count < size; count++) {
1075*cf5a6c84SAndroid Build Coastguard Worker          msgopt_list[count].len = 0;
1076*cf5a6c84SAndroid Build Coastguard Worker          msgopt_list[count].val = NULL;
1077*cf5a6c84SAndroid Build Coastguard Worker      }
1078*cf5a6c84SAndroid Build Coastguard Worker     }
1079*cf5a6c84SAndroid Build Coastguard Worker   } else {
1080*cf5a6c84SAndroid Build Coastguard Worker     msgopt_list = options_list;
1081*cf5a6c84SAndroid Build Coastguard Worker     for (count = 0; count < size; count++) {
1082*cf5a6c84SAndroid Build Coastguard Worker       msgopt_list[count].len = 0;
1083*cf5a6c84SAndroid Build Coastguard Worker       if(msgopt_list[count].val) free(msgopt_list[count].val);
1084*cf5a6c84SAndroid Build Coastguard Worker       msgopt_list[count].val = NULL;
1085*cf5a6c84SAndroid Build Coastguard Worker     }
1086*cf5a6c84SAndroid Build Coastguard Worker   }
1087*cf5a6c84SAndroid Build Coastguard Worker 
1088*cf5a6c84SAndroid Build Coastguard Worker   while (*optptr != DHCP_OPTION_END) {
1089*cf5a6c84SAndroid Build Coastguard Worker     if (*optptr == DHCP_OPTION_PADDING) {
1090*cf5a6c84SAndroid Build Coastguard Worker       optptr++;
1091*cf5a6c84SAndroid Build Coastguard Worker       continue;
1092*cf5a6c84SAndroid Build Coastguard Worker     }
1093*cf5a6c84SAndroid Build Coastguard Worker     if (*optptr == DHCP_OPTION_OVERLOAD) {
1094*cf5a6c84SAndroid Build Coastguard Worker       overloaded = optptr[2];
1095*cf5a6c84SAndroid Build Coastguard Worker       optptr += optptr[1] + 2;
1096*cf5a6c84SAndroid Build Coastguard Worker       continue;
1097*cf5a6c84SAndroid Build Coastguard Worker     }
1098*cf5a6c84SAndroid Build Coastguard Worker     for (count = 0, flag = 0; count < size; count++) {
1099*cf5a6c84SAndroid Build Coastguard Worker       if ((msgopt_list[count].code & 0X00FF) == *optptr) {
1100*cf5a6c84SAndroid Build Coastguard Worker         flag = (msgopt_list[count].code & 0XFF00);
1101*cf5a6c84SAndroid Build Coastguard Worker         break;
1102*cf5a6c84SAndroid Build Coastguard Worker       }
1103*cf5a6c84SAndroid Build Coastguard Worker     }
1104*cf5a6c84SAndroid Build Coastguard Worker     msgopt_list[count].val = 0;
1105*cf5a6c84SAndroid Build Coastguard Worker     msgopt_list[count].len = 0;
1106*cf5a6c84SAndroid Build Coastguard Worker     switch (flag) {
1107*cf5a6c84SAndroid Build Coastguard Worker     case DHCP_NUM32:
1108*cf5a6c84SAndroid Build Coastguard Worker       msgopt_list[count].val = xmprintf("%llu", peek_be(optptr+2, 4));
1109*cf5a6c84SAndroid Build Coastguard Worker       break;
1110*cf5a6c84SAndroid Build Coastguard Worker     case DHCP_NUM16:
1111*cf5a6c84SAndroid Build Coastguard Worker       msgopt_list[count].val = xmprintf("%llu", peek_be(optptr+2, 2));
1112*cf5a6c84SAndroid Build Coastguard Worker       break;
1113*cf5a6c84SAndroid Build Coastguard Worker     case DHCP_NUM8:
1114*cf5a6c84SAndroid Build Coastguard Worker       msgopt_list[count].val = xmprintf("%llu", peek_be(optptr+2, 1));
1115*cf5a6c84SAndroid Build Coastguard Worker       break;
1116*cf5a6c84SAndroid Build Coastguard Worker     case DHCP_IP:
1117*cf5a6c84SAndroid Build Coastguard Worker       msgopt_list[count].val = xstrdup(inet_ntoa((struct in_addr){peek(optptr+2, 4)}));
1118*cf5a6c84SAndroid Build Coastguard Worker       break;
1119*cf5a6c84SAndroid Build Coastguard Worker     case DHCP_STRING:
1120*cf5a6c84SAndroid Build Coastguard Worker       msgopt_list[count].val = xmprintf("%.*s", optptr[1], optptr+2);
1121*cf5a6c84SAndroid Build Coastguard Worker       break;
1122*cf5a6c84SAndroid Build Coastguard Worker     case DHCP_IPLIST:
1123*cf5a6c84SAndroid Build Coastguard Worker       options = &optptr[2];
1124*cf5a6c84SAndroid Build Coastguard Worker       optlen = optptr[1];
1125*cf5a6c84SAndroid Build Coastguard Worker       dest = toybuf;
1126*cf5a6c84SAndroid Build Coastguard Worker       while (optlen) {
1127*cf5a6c84SAndroid Build Coastguard Worker         dest += sprintf(dest, "%s ", inet_ntoa((struct in_addr){peek(options, 4)}));
1128*cf5a6c84SAndroid Build Coastguard Worker         options += 4;
1129*cf5a6c84SAndroid Build Coastguard Worker         optlen -= 4;
1130*cf5a6c84SAndroid Build Coastguard Worker       }
1131*cf5a6c84SAndroid Build Coastguard Worker       *(dest - 1) = '\0';
1132*cf5a6c84SAndroid Build Coastguard Worker       msgopt_list[count].val = strdup(toybuf);
1133*cf5a6c84SAndroid Build Coastguard Worker       break;
1134*cf5a6c84SAndroid Build Coastguard Worker     case DHCP_STRLST: //FIXME: do smthing.
1135*cf5a6c84SAndroid Build Coastguard Worker     case DHCP_IPPLST:
1136*cf5a6c84SAndroid Build Coastguard Worker       break;
1137*cf5a6c84SAndroid Build Coastguard Worker     case DHCP_STCRTS:
1138*cf5a6c84SAndroid Build Coastguard Worker       pfx = "";
1139*cf5a6c84SAndroid Build Coastguard Worker       dest = toybuf;
1140*cf5a6c84SAndroid Build Coastguard Worker       options = &optptr[2];
1141*cf5a6c84SAndroid Build Coastguard Worker       optlen = optptr[1];
1142*cf5a6c84SAndroid Build Coastguard Worker 
1143*cf5a6c84SAndroid Build Coastguard Worker       while (optlen >= 1 + 4) {
1144*cf5a6c84SAndroid Build Coastguard Worker         uint32_t nip = 0;
1145*cf5a6c84SAndroid Build Coastguard Worker         int bytes;
1146*cf5a6c84SAndroid Build Coastguard Worker         uint8_t *p_tmp;
1147*cf5a6c84SAndroid Build Coastguard Worker         unsigned mask = *options;
1148*cf5a6c84SAndroid Build Coastguard Worker 
1149*cf5a6c84SAndroid Build Coastguard Worker         if (mask > 32) break;
1150*cf5a6c84SAndroid Build Coastguard Worker         optlen--;
1151*cf5a6c84SAndroid Build Coastguard Worker         p_tmp = (void*) &nip;
1152*cf5a6c84SAndroid Build Coastguard Worker         bytes = (mask + 7) / 8;
1153*cf5a6c84SAndroid Build Coastguard Worker         while (--bytes >= 0) {
1154*cf5a6c84SAndroid Build Coastguard Worker           *p_tmp++ = *options++;
1155*cf5a6c84SAndroid Build Coastguard Worker           optlen--;
1156*cf5a6c84SAndroid Build Coastguard Worker         }
1157*cf5a6c84SAndroid Build Coastguard Worker         if (optlen < 4) break;
1158*cf5a6c84SAndroid Build Coastguard Worker         dest += sprintf(dest, "%s%u.%u.%u.%u", pfx, ((uint8_t*) &nip)[0],
1159*cf5a6c84SAndroid Build Coastguard Worker             ((uint8_t*) &nip)[1], ((uint8_t*) &nip)[2], ((uint8_t*) &nip)[3]);
1160*cf5a6c84SAndroid Build Coastguard Worker         pfx = " ";
1161*cf5a6c84SAndroid Build Coastguard Worker         dest += sprintf(dest, "/%u ", mask);
1162*cf5a6c84SAndroid Build Coastguard Worker         dest += sprintf(dest, "%u.%u.%u.%u", options[0], options[1], options[2], options[3]);
1163*cf5a6c84SAndroid Build Coastguard Worker         options += 4;
1164*cf5a6c84SAndroid Build Coastguard Worker         optlen -= 4;
1165*cf5a6c84SAndroid Build Coastguard Worker       }
1166*cf5a6c84SAndroid Build Coastguard Worker       msgopt_list[count].val = strdup(toybuf);
1167*cf5a6c84SAndroid Build Coastguard Worker       break;
1168*cf5a6c84SAndroid Build Coastguard Worker     default: break;
1169*cf5a6c84SAndroid Build Coastguard Worker     }
1170*cf5a6c84SAndroid Build Coastguard Worker     if (msgopt_list[count].val)
1171*cf5a6c84SAndroid Build Coastguard Worker       msgopt_list[count].len = strlen(msgopt_list[count].val);
1172*cf5a6c84SAndroid Build Coastguard Worker 
1173*cf5a6c84SAndroid Build Coastguard Worker     optptr += optptr[1] + 2;
1174*cf5a6c84SAndroid Build Coastguard Worker   }
1175*cf5a6c84SAndroid Build Coastguard Worker   if ((overloaded == 1) || (overloaded == 3)) dhcpc_parseoptions(presult, optptr);
1176*cf5a6c84SAndroid Build Coastguard Worker   if ((overloaded == 2) || (overloaded == 3)) dhcpc_parseoptions(presult, optptr);
1177*cf5a6c84SAndroid Build Coastguard Worker   return type;
1178*cf5a6c84SAndroid Build Coastguard Worker }
1179*cf5a6c84SAndroid Build Coastguard Worker 
1180*cf5a6c84SAndroid Build Coastguard Worker // parses recvd messege to check that it was for us.
dhcpc_parsemsg(dhcpc_result_t * presult)1181*cf5a6c84SAndroid Build Coastguard Worker static uint8_t dhcpc_parsemsg(dhcpc_result_t *presult)
1182*cf5a6c84SAndroid Build Coastguard Worker {
1183*cf5a6c84SAndroid Build Coastguard Worker   if (state->pdhcp.op == DHCP_REPLY
1184*cf5a6c84SAndroid Build Coastguard Worker       && !memcmp(state->pdhcp.chaddr, state->macaddr, 6)
1185*cf5a6c84SAndroid Build Coastguard Worker       && !memcmp(&state->pdhcp.xid, &xid, sizeof(xid))) {
1186*cf5a6c84SAndroid Build Coastguard Worker     memcpy(&presult->ipaddr.s_addr, &state->pdhcp.yiaddr, 4);
1187*cf5a6c84SAndroid Build Coastguard Worker     presult->ipaddr.s_addr = ntohl(presult->ipaddr.s_addr);
1188*cf5a6c84SAndroid Build Coastguard Worker     return get_option_msgtype(state->pdhcp.options);
1189*cf5a6c84SAndroid Build Coastguard Worker   }
1190*cf5a6c84SAndroid Build Coastguard Worker   return 0;
1191*cf5a6c84SAndroid Build Coastguard Worker }
1192*cf5a6c84SAndroid Build Coastguard Worker 
1193*cf5a6c84SAndroid Build Coastguard Worker // Sends a IP renew request.
renew(void)1194*cf5a6c84SAndroid Build Coastguard Worker static void renew(void)
1195*cf5a6c84SAndroid Build Coastguard Worker {
1196*cf5a6c84SAndroid Build Coastguard Worker   infomsg(infomode, "Performing a DHCP renew");
1197*cf5a6c84SAndroid Build Coastguard Worker   switch (state->status) {
1198*cf5a6c84SAndroid Build Coastguard Worker   case STATE_INIT:
1199*cf5a6c84SAndroid Build Coastguard Worker     break;
1200*cf5a6c84SAndroid Build Coastguard Worker   case STATE_BOUND:
1201*cf5a6c84SAndroid Build Coastguard Worker     mode_raw();
1202*cf5a6c84SAndroid Build Coastguard Worker   case STATE_RENEWING:    // FALLTHROUGH
1203*cf5a6c84SAndroid Build Coastguard Worker   case STATE_REBINDING:   // FALLTHROUGH
1204*cf5a6c84SAndroid Build Coastguard Worker     state->status = STATE_RENEW_REQUESTED;
1205*cf5a6c84SAndroid Build Coastguard Worker     break;
1206*cf5a6c84SAndroid Build Coastguard Worker   case STATE_RENEW_REQUESTED:
1207*cf5a6c84SAndroid Build Coastguard Worker     run_script(NULL, "deconfig");
1208*cf5a6c84SAndroid Build Coastguard Worker   case STATE_REQUESTING:           // FALLTHROUGH
1209*cf5a6c84SAndroid Build Coastguard Worker   case STATE_RELEASED:             // FALLTHROUGH
1210*cf5a6c84SAndroid Build Coastguard Worker     mode_raw();
1211*cf5a6c84SAndroid Build Coastguard Worker     state->status = STATE_INIT;
1212*cf5a6c84SAndroid Build Coastguard Worker     break;
1213*cf5a6c84SAndroid Build Coastguard Worker   default: break;
1214*cf5a6c84SAndroid Build Coastguard Worker   }
1215*cf5a6c84SAndroid Build Coastguard Worker }
1216*cf5a6c84SAndroid Build Coastguard Worker 
1217*cf5a6c84SAndroid Build Coastguard Worker // Sends a IP release request.
release(void)1218*cf5a6c84SAndroid Build Coastguard Worker static void release(void)
1219*cf5a6c84SAndroid Build Coastguard Worker {
1220*cf5a6c84SAndroid Build Coastguard Worker   char buffer[sizeof("255.255.255.255\0")];
1221*cf5a6c84SAndroid Build Coastguard Worker   struct in_addr temp_addr;
1222*cf5a6c84SAndroid Build Coastguard Worker 
1223*cf5a6c84SAndroid Build Coastguard Worker   mode_app();
1224*cf5a6c84SAndroid Build Coastguard Worker   // send release packet
1225*cf5a6c84SAndroid Build Coastguard Worker   if (state->status == STATE_BOUND || state->status == STATE_RENEWING || state->status == STATE_REBINDING) {
1226*cf5a6c84SAndroid Build Coastguard Worker     temp_addr.s_addr = htonl(server);
1227*cf5a6c84SAndroid Build Coastguard Worker     xstrncpy(buffer, inet_ntoa(temp_addr), sizeof(buffer));
1228*cf5a6c84SAndroid Build Coastguard Worker     temp_addr.s_addr = state->ipaddr.s_addr;
1229*cf5a6c84SAndroid Build Coastguard Worker     infomsg( infomode, "Unicasting a release of %s to %s", inet_ntoa(temp_addr), buffer);
1230*cf5a6c84SAndroid Build Coastguard Worker     dhcpc_sendmsg(DHCPRELEASE);
1231*cf5a6c84SAndroid Build Coastguard Worker     run_script(NULL, "deconfig");
1232*cf5a6c84SAndroid Build Coastguard Worker   }
1233*cf5a6c84SAndroid Build Coastguard Worker   infomsg(infomode, "Entering released state");
1234*cf5a6c84SAndroid Build Coastguard Worker   close(state->sockfd);
1235*cf5a6c84SAndroid Build Coastguard Worker   state->sockfd = -1;
1236*cf5a6c84SAndroid Build Coastguard Worker   state->mode = MODE_OFF;
1237*cf5a6c84SAndroid Build Coastguard Worker   state->status = STATE_RELEASED;
1238*cf5a6c84SAndroid Build Coastguard Worker }
1239*cf5a6c84SAndroid Build Coastguard Worker 
free_option_stores(void)1240*cf5a6c84SAndroid Build Coastguard Worker static void free_option_stores(void)
1241*cf5a6c84SAndroid Build Coastguard Worker {
1242*cf5a6c84SAndroid Build Coastguard Worker   int count, size = ARRAY_LEN(options_list);
1243*cf5a6c84SAndroid Build Coastguard Worker   for (count = 0; count < size; count++)
1244*cf5a6c84SAndroid Build Coastguard Worker     if (options_list[count].val) free(options_list[count].val);
1245*cf5a6c84SAndroid Build Coastguard Worker   if (toys.optflags & FLAG_x) {
1246*cf5a6c84SAndroid Build Coastguard Worker     for (count = 0; count < size; count++)
1247*cf5a6c84SAndroid Build Coastguard Worker         if (msgopt_list[count].val) free(msgopt_list[count].val);
1248*cf5a6c84SAndroid Build Coastguard Worker     free(msgopt_list);
1249*cf5a6c84SAndroid Build Coastguard Worker   }
1250*cf5a6c84SAndroid Build Coastguard Worker }
1251*cf5a6c84SAndroid Build Coastguard Worker 
dhcp_main(void)1252*cf5a6c84SAndroid Build Coastguard Worker void dhcp_main(void)
1253*cf5a6c84SAndroid Build Coastguard Worker {
1254*cf5a6c84SAndroid Build Coastguard Worker   struct timeval tv;
1255*cf5a6c84SAndroid Build Coastguard Worker   int retval, bufflen = 0;
1256*cf5a6c84SAndroid Build Coastguard Worker   dhcpc_result_t result;
1257*cf5a6c84SAndroid Build Coastguard Worker   uint8_t packets = 0, retries = 0;
1258*cf5a6c84SAndroid Build Coastguard Worker   uint32_t timeout = 0, waited = 0;
1259*cf5a6c84SAndroid Build Coastguard Worker   fd_set rfds;
1260*cf5a6c84SAndroid Build Coastguard Worker 
1261*cf5a6c84SAndroid Build Coastguard Worker   xid = 0;
1262*cf5a6c84SAndroid Build Coastguard Worker   setlinebuf(stdout);
1263*cf5a6c84SAndroid Build Coastguard Worker   dbg = dummy;
1264*cf5a6c84SAndroid Build Coastguard Worker   if (toys.optflags & FLAG_v) dbg = xprintf;
1265*cf5a6c84SAndroid Build Coastguard Worker   if (toys.optflags & FLAG_p) write_pid(TT.pidfile);
1266*cf5a6c84SAndroid Build Coastguard Worker   retries = TT.retries;
1267*cf5a6c84SAndroid Build Coastguard Worker   if (toys.optflags & FLAG_S) {
1268*cf5a6c84SAndroid Build Coastguard Worker       openlog("UDHCPC :", LOG_PID, LOG_DAEMON);
1269*cf5a6c84SAndroid Build Coastguard Worker       infomode |= LOG_SYSTEM;
1270*cf5a6c84SAndroid Build Coastguard Worker   }
1271*cf5a6c84SAndroid Build Coastguard Worker   infomsg(infomode, "dhcp started");
1272*cf5a6c84SAndroid Build Coastguard Worker   if (toys.optflags & FLAG_O) {
1273*cf5a6c84SAndroid Build Coastguard Worker     while (TT.req_opt) {
1274*cf5a6c84SAndroid Build Coastguard Worker       raw_opt[raw_optcount] = (uint8_t) strtoopt(TT.req_opt->arg, 1);
1275*cf5a6c84SAndroid Build Coastguard Worker       raw_optcount++;
1276*cf5a6c84SAndroid Build Coastguard Worker       TT.req_opt = TT.req_opt->next;
1277*cf5a6c84SAndroid Build Coastguard Worker     }
1278*cf5a6c84SAndroid Build Coastguard Worker   }
1279*cf5a6c84SAndroid Build Coastguard Worker   if (toys.optflags & FLAG_x) {
1280*cf5a6c84SAndroid Build Coastguard Worker     while (TT.pkt_opt) {
1281*cf5a6c84SAndroid Build Coastguard Worker       (void) strtoopt(TT.pkt_opt->arg, 0);
1282*cf5a6c84SAndroid Build Coastguard Worker       TT.pkt_opt = TT.pkt_opt->next;
1283*cf5a6c84SAndroid Build Coastguard Worker     }
1284*cf5a6c84SAndroid Build Coastguard Worker   }
1285*cf5a6c84SAndroid Build Coastguard Worker   memset(&result, 0, sizeof(dhcpc_result_t));
1286*cf5a6c84SAndroid Build Coastguard Worker   state = (dhcpc_state_t*) xmalloc(sizeof(dhcpc_state_t));
1287*cf5a6c84SAndroid Build Coastguard Worker   memset(state, 0, sizeof(dhcpc_state_t));
1288*cf5a6c84SAndroid Build Coastguard Worker   state->iface = (toys.optflags & FLAG_i) ? TT.iface : "eth0";
1289*cf5a6c84SAndroid Build Coastguard Worker 
1290*cf5a6c84SAndroid Build Coastguard Worker   if (get_interface(state->iface, &state->ifindex, NULL, state->macaddr))
1291*cf5a6c84SAndroid Build Coastguard Worker     perror_exit("Failed to get interface %s", state->iface);
1292*cf5a6c84SAndroid Build Coastguard Worker 
1293*cf5a6c84SAndroid Build Coastguard Worker   run_script(NULL, "deconfig");
1294*cf5a6c84SAndroid Build Coastguard Worker   setup_signal();
1295*cf5a6c84SAndroid Build Coastguard Worker   state->status = STATE_INIT;
1296*cf5a6c84SAndroid Build Coastguard Worker   mode_raw();
1297*cf5a6c84SAndroid Build Coastguard Worker   fcntl(state->sockfd, F_SETFD, FD_CLOEXEC);
1298*cf5a6c84SAndroid Build Coastguard Worker 
1299*cf5a6c84SAndroid Build Coastguard Worker   for (;;) {
1300*cf5a6c84SAndroid Build Coastguard Worker     FD_ZERO(&rfds);
1301*cf5a6c84SAndroid Build Coastguard Worker     if (state->sockfd >= 0) FD_SET(state->sockfd, &rfds);
1302*cf5a6c84SAndroid Build Coastguard Worker     FD_SET(sigfd.rd, &rfds);
1303*cf5a6c84SAndroid Build Coastguard Worker     tv.tv_sec = timeout - waited;
1304*cf5a6c84SAndroid Build Coastguard Worker     tv.tv_usec = 0;
1305*cf5a6c84SAndroid Build Coastguard Worker     retval = 0;
1306*cf5a6c84SAndroid Build Coastguard Worker 
1307*cf5a6c84SAndroid Build Coastguard Worker     int maxfd = (sigfd.rd > state->sockfd)? sigfd.rd : state->sockfd;
1308*cf5a6c84SAndroid Build Coastguard Worker     dbg("select wait ....\n");
1309*cf5a6c84SAndroid Build Coastguard Worker     uint32_t timestmp = time(NULL);
1310*cf5a6c84SAndroid Build Coastguard Worker     if((retval = select(maxfd + 1, &rfds, NULL, NULL, &tv)) < 0) {
1311*cf5a6c84SAndroid Build Coastguard Worker       if (errno == EINTR) {
1312*cf5a6c84SAndroid Build Coastguard Worker         waited += (unsigned) time(NULL) - timestmp;
1313*cf5a6c84SAndroid Build Coastguard Worker         continue;
1314*cf5a6c84SAndroid Build Coastguard Worker       }
1315*cf5a6c84SAndroid Build Coastguard Worker       perror_exit("Error in select");
1316*cf5a6c84SAndroid Build Coastguard Worker     }
1317*cf5a6c84SAndroid Build Coastguard Worker     if (!retval) { // Timed out
1318*cf5a6c84SAndroid Build Coastguard Worker       if (get_interface(state->iface, &state->ifindex, NULL, state->macaddr))
1319*cf5a6c84SAndroid Build Coastguard Worker         error_exit("Interface lost %s\n", state->iface);
1320*cf5a6c84SAndroid Build Coastguard Worker 
1321*cf5a6c84SAndroid Build Coastguard Worker       switch (state->status) {
1322*cf5a6c84SAndroid Build Coastguard Worker       case STATE_INIT:
1323*cf5a6c84SAndroid Build Coastguard Worker         if (packets < retries) {
1324*cf5a6c84SAndroid Build Coastguard Worker           if (!packets) xid = getxid();
1325*cf5a6c84SAndroid Build Coastguard Worker           run_script(NULL, "deconfig");
1326*cf5a6c84SAndroid Build Coastguard Worker           infomsg(infomode, "Sending discover...");
1327*cf5a6c84SAndroid Build Coastguard Worker           dhcpc_sendmsg(DHCPDISCOVER);
1328*cf5a6c84SAndroid Build Coastguard Worker           server = 0;
1329*cf5a6c84SAndroid Build Coastguard Worker           timeout = TT.timeout;
1330*cf5a6c84SAndroid Build Coastguard Worker           waited = 0;
1331*cf5a6c84SAndroid Build Coastguard Worker           packets++;
1332*cf5a6c84SAndroid Build Coastguard Worker           continue;
1333*cf5a6c84SAndroid Build Coastguard Worker         }
1334*cf5a6c84SAndroid Build Coastguard Worker lease_fail:
1335*cf5a6c84SAndroid Build Coastguard Worker         run_script(NULL,"leasefail");
1336*cf5a6c84SAndroid Build Coastguard Worker         if (toys.optflags & FLAG_n) {
1337*cf5a6c84SAndroid Build Coastguard Worker           infomsg(infomode, "Lease failed. Exiting");
1338*cf5a6c84SAndroid Build Coastguard Worker           goto ret_with_sockfd;
1339*cf5a6c84SAndroid Build Coastguard Worker         }
1340*cf5a6c84SAndroid Build Coastguard Worker         if (toys.optflags & FLAG_b) {
1341*cf5a6c84SAndroid Build Coastguard Worker           infomsg(infomode, "Lease failed. Going Daemon mode");
1342*cf5a6c84SAndroid Build Coastguard Worker           daemon(0, 0);
1343*cf5a6c84SAndroid Build Coastguard Worker           if (toys.optflags & FLAG_p) write_pid(TT.pidfile);
1344*cf5a6c84SAndroid Build Coastguard Worker           toys.optflags &= ~FLAG_b;
1345*cf5a6c84SAndroid Build Coastguard Worker           toys.optflags |= FLAG_f;
1346*cf5a6c84SAndroid Build Coastguard Worker         }
1347*cf5a6c84SAndroid Build Coastguard Worker         timeout = TT.tryagain;
1348*cf5a6c84SAndroid Build Coastguard Worker         waited = 0;
1349*cf5a6c84SAndroid Build Coastguard Worker         packets = 0;
1350*cf5a6c84SAndroid Build Coastguard Worker         continue;
1351*cf5a6c84SAndroid Build Coastguard Worker       case STATE_REQUESTING:
1352*cf5a6c84SAndroid Build Coastguard Worker         if (packets < retries) {
1353*cf5a6c84SAndroid Build Coastguard Worker           memcpy(&state->ipaddr.s_addr,&state->pdhcp.yiaddr, 4);
1354*cf5a6c84SAndroid Build Coastguard Worker           dhcpc_sendmsg(DHCPREQUEST);
1355*cf5a6c84SAndroid Build Coastguard Worker           infomsg(infomode, "Sending select for %d.%d.%d.%d...",
1356*cf5a6c84SAndroid Build Coastguard Worker               (result.ipaddr.s_addr >> 24) & 0xff, (result.ipaddr.s_addr >> 16) & 0xff, (result.ipaddr.s_addr >> 8) & 0xff, (result.ipaddr.s_addr) & 0xff);
1357*cf5a6c84SAndroid Build Coastguard Worker           timeout = TT.timeout;
1358*cf5a6c84SAndroid Build Coastguard Worker           waited = 0;
1359*cf5a6c84SAndroid Build Coastguard Worker           packets++;
1360*cf5a6c84SAndroid Build Coastguard Worker           continue;
1361*cf5a6c84SAndroid Build Coastguard Worker         }
1362*cf5a6c84SAndroid Build Coastguard Worker         mode_raw();
1363*cf5a6c84SAndroid Build Coastguard Worker         state->status = STATE_INIT;
1364*cf5a6c84SAndroid Build Coastguard Worker         goto lease_fail;
1365*cf5a6c84SAndroid Build Coastguard Worker       case STATE_BOUND:
1366*cf5a6c84SAndroid Build Coastguard Worker         state->status = STATE_RENEWING;
1367*cf5a6c84SAndroid Build Coastguard Worker         dbg("Entering renew state\n");
1368*cf5a6c84SAndroid Build Coastguard Worker         // FALLTHROUGH
1369*cf5a6c84SAndroid Build Coastguard Worker       case STATE_RENEW_REQUESTED:   // FALLTHROUGH
1370*cf5a6c84SAndroid Build Coastguard Worker       case STATE_RENEWING:
1371*cf5a6c84SAndroid Build Coastguard Worker renew_requested:
1372*cf5a6c84SAndroid Build Coastguard Worker         if (timeout > 60) {
1373*cf5a6c84SAndroid Build Coastguard Worker           dhcpc_sendmsg(DHCPREQUEST);
1374*cf5a6c84SAndroid Build Coastguard Worker           timeout >>= 1;
1375*cf5a6c84SAndroid Build Coastguard Worker           waited = 0;
1376*cf5a6c84SAndroid Build Coastguard Worker           continue;
1377*cf5a6c84SAndroid Build Coastguard Worker         }
1378*cf5a6c84SAndroid Build Coastguard Worker         dbg("Entering rebinding state\n");
1379*cf5a6c84SAndroid Build Coastguard Worker         state->status = STATE_REBINDING;
1380*cf5a6c84SAndroid Build Coastguard Worker         // FALLTHROUGH
1381*cf5a6c84SAndroid Build Coastguard Worker       case STATE_REBINDING:
1382*cf5a6c84SAndroid Build Coastguard Worker         mode_raw();
1383*cf5a6c84SAndroid Build Coastguard Worker         if (timeout > 0) {
1384*cf5a6c84SAndroid Build Coastguard Worker           dhcpc_sendmsg(DHCPREQUEST);
1385*cf5a6c84SAndroid Build Coastguard Worker           timeout >>= 1;
1386*cf5a6c84SAndroid Build Coastguard Worker           waited = 0;
1387*cf5a6c84SAndroid Build Coastguard Worker           continue;
1388*cf5a6c84SAndroid Build Coastguard Worker         }
1389*cf5a6c84SAndroid Build Coastguard Worker         infomsg(infomode, "Lease lost, entering INIT state");
1390*cf5a6c84SAndroid Build Coastguard Worker         run_script(NULL, "deconfig");
1391*cf5a6c84SAndroid Build Coastguard Worker         state->status = STATE_INIT;
1392*cf5a6c84SAndroid Build Coastguard Worker         timeout = 0;
1393*cf5a6c84SAndroid Build Coastguard Worker         waited = 0;
1394*cf5a6c84SAndroid Build Coastguard Worker         packets = 0;
1395*cf5a6c84SAndroid Build Coastguard Worker         continue;
1396*cf5a6c84SAndroid Build Coastguard Worker       default: break;
1397*cf5a6c84SAndroid Build Coastguard Worker       }
1398*cf5a6c84SAndroid Build Coastguard Worker       timeout = INT_MAX;
1399*cf5a6c84SAndroid Build Coastguard Worker       waited = 0;
1400*cf5a6c84SAndroid Build Coastguard Worker       continue;
1401*cf5a6c84SAndroid Build Coastguard Worker     }
1402*cf5a6c84SAndroid Build Coastguard Worker     if (FD_ISSET(sigfd.rd, &rfds)) { // Some Activity on RDFDs : is signal
1403*cf5a6c84SAndroid Build Coastguard Worker       unsigned char sig;
1404*cf5a6c84SAndroid Build Coastguard Worker       if (read(sigfd.rd, &sig, 1) != 1) {
1405*cf5a6c84SAndroid Build Coastguard Worker         dbg("signal read failed.\n");
1406*cf5a6c84SAndroid Build Coastguard Worker         continue;
1407*cf5a6c84SAndroid Build Coastguard Worker       }
1408*cf5a6c84SAndroid Build Coastguard Worker       switch (sig) {
1409*cf5a6c84SAndroid Build Coastguard Worker       case SIGUSR1:
1410*cf5a6c84SAndroid Build Coastguard Worker         infomsg(infomode, "Received SIGUSR1");
1411*cf5a6c84SAndroid Build Coastguard Worker         renew();
1412*cf5a6c84SAndroid Build Coastguard Worker         packets = 0;
1413*cf5a6c84SAndroid Build Coastguard Worker         waited = 0;
1414*cf5a6c84SAndroid Build Coastguard Worker         if (state->status == STATE_RENEW_REQUESTED) goto renew_requested;
1415*cf5a6c84SAndroid Build Coastguard Worker         if (state->status == STATE_INIT) timeout = 0;
1416*cf5a6c84SAndroid Build Coastguard Worker         continue;
1417*cf5a6c84SAndroid Build Coastguard Worker       case SIGUSR2:
1418*cf5a6c84SAndroid Build Coastguard Worker         infomsg(infomode, "Received SIGUSR2");
1419*cf5a6c84SAndroid Build Coastguard Worker         release();
1420*cf5a6c84SAndroid Build Coastguard Worker         timeout = INT_MAX;
1421*cf5a6c84SAndroid Build Coastguard Worker         waited = 0;
1422*cf5a6c84SAndroid Build Coastguard Worker         packets = 0;
1423*cf5a6c84SAndroid Build Coastguard Worker         continue;
1424*cf5a6c84SAndroid Build Coastguard Worker       case SIGTERM:
1425*cf5a6c84SAndroid Build Coastguard Worker         infomsg(infomode, "Received SIGTERM");
1426*cf5a6c84SAndroid Build Coastguard Worker         if (toys.optflags & FLAG_R) release();
1427*cf5a6c84SAndroid Build Coastguard Worker         goto ret_with_sockfd;
1428*cf5a6c84SAndroid Build Coastguard Worker       default: break;
1429*cf5a6c84SAndroid Build Coastguard Worker       }
1430*cf5a6c84SAndroid Build Coastguard Worker     }
1431*cf5a6c84SAndroid Build Coastguard Worker     if (FD_ISSET(state->sockfd, &rfds)) { // Some Activity on RDFDs : is socket
1432*cf5a6c84SAndroid Build Coastguard Worker       dbg("main sock read\n");
1433*cf5a6c84SAndroid Build Coastguard Worker       uint8_t msgType;
1434*cf5a6c84SAndroid Build Coastguard Worker       if (state->mode == MODE_RAW) bufflen = read_raw();
1435*cf5a6c84SAndroid Build Coastguard Worker       if (state->mode == MODE_APP) bufflen = read_app();
1436*cf5a6c84SAndroid Build Coastguard Worker       if (bufflen < 0) {
1437*cf5a6c84SAndroid Build Coastguard Worker         if (state->mode == MODE_RAW) mode_raw();
1438*cf5a6c84SAndroid Build Coastguard Worker         if (state->mode == MODE_APP) mode_app();
1439*cf5a6c84SAndroid Build Coastguard Worker         continue;
1440*cf5a6c84SAndroid Build Coastguard Worker       }
1441*cf5a6c84SAndroid Build Coastguard Worker       waited += time(NULL) - timestmp;
1442*cf5a6c84SAndroid Build Coastguard Worker       memset(&result, 0, sizeof(dhcpc_result_t));
1443*cf5a6c84SAndroid Build Coastguard Worker       msgType = dhcpc_parsemsg(&result);
1444*cf5a6c84SAndroid Build Coastguard Worker       if (msgType != DHCPNAK && result.ipaddr.s_addr == 0 ) continue;       // no ip for me ignore
1445*cf5a6c84SAndroid Build Coastguard Worker       if (!msgType || !get_option_serverid(state->pdhcp.options, &result)) continue; //no server id ignore
1446*cf5a6c84SAndroid Build Coastguard Worker       if (msgType == DHCPOFFER && server == 0) server = result.serverid.s_addr; // select the server
1447*cf5a6c84SAndroid Build Coastguard Worker       if (result.serverid.s_addr != server) continue; // not from the server we requested ignore
1448*cf5a6c84SAndroid Build Coastguard Worker       dhcpc_parseoptions(&result, state->pdhcp.options);
1449*cf5a6c84SAndroid Build Coastguard Worker       get_option_lease(state->pdhcp.options, &result);
1450*cf5a6c84SAndroid Build Coastguard Worker 
1451*cf5a6c84SAndroid Build Coastguard Worker       switch (state->status) {
1452*cf5a6c84SAndroid Build Coastguard Worker       case STATE_INIT:
1453*cf5a6c84SAndroid Build Coastguard Worker         if (msgType == DHCPOFFER) {
1454*cf5a6c84SAndroid Build Coastguard Worker           state->status = STATE_REQUESTING;
1455*cf5a6c84SAndroid Build Coastguard Worker           mode_raw();
1456*cf5a6c84SAndroid Build Coastguard Worker           timeout = 0;
1457*cf5a6c84SAndroid Build Coastguard Worker           waited = 0;
1458*cf5a6c84SAndroid Build Coastguard Worker           packets = 0;
1459*cf5a6c84SAndroid Build Coastguard Worker         }
1460*cf5a6c84SAndroid Build Coastguard Worker         continue;
1461*cf5a6c84SAndroid Build Coastguard Worker       case STATE_REQUESTING:         // FALLTHROUGH
1462*cf5a6c84SAndroid Build Coastguard Worker       case STATE_RENEWING:           // FALLTHROUGH
1463*cf5a6c84SAndroid Build Coastguard Worker       case STATE_RENEW_REQUESTED:    // FALLTHROUGH
1464*cf5a6c84SAndroid Build Coastguard Worker       case STATE_REBINDING:
1465*cf5a6c84SAndroid Build Coastguard Worker         if (msgType == DHCPACK) {
1466*cf5a6c84SAndroid Build Coastguard Worker           timeout = result.lease_time / 2;
1467*cf5a6c84SAndroid Build Coastguard Worker           run_script(&result, state->status == STATE_REQUESTING ? "bound" : "renew");
1468*cf5a6c84SAndroid Build Coastguard Worker           state->status = STATE_BOUND;
1469*cf5a6c84SAndroid Build Coastguard Worker           infomsg(infomode, "Lease of %d.%d.%d.%d obtained, lease time %d from server %d.%d.%d.%d",
1470*cf5a6c84SAndroid Build Coastguard Worker               (result.ipaddr.s_addr >> 24) & 0xff, (result.ipaddr.s_addr >> 16) & 0xff, (result.ipaddr.s_addr >> 8) & 0xff, (result.ipaddr.s_addr) & 0xff,
1471*cf5a6c84SAndroid Build Coastguard Worker               result.lease_time,
1472*cf5a6c84SAndroid Build Coastguard Worker               (result.serverid.s_addr >> 24) & 0xff, (result.serverid.s_addr >> 16) & 0xff, (result.serverid.s_addr >> 8) & 0xff, (result.serverid.s_addr) & 0xff);
1473*cf5a6c84SAndroid Build Coastguard Worker           if (toys.optflags & FLAG_q) {
1474*cf5a6c84SAndroid Build Coastguard Worker             if (toys.optflags & FLAG_R) release();
1475*cf5a6c84SAndroid Build Coastguard Worker             goto ret_with_sockfd;
1476*cf5a6c84SAndroid Build Coastguard Worker           }
1477*cf5a6c84SAndroid Build Coastguard Worker           toys.optflags &= ~FLAG_n;
1478*cf5a6c84SAndroid Build Coastguard Worker           if (!(toys.optflags & FLAG_f)) {
1479*cf5a6c84SAndroid Build Coastguard Worker             daemon(0, 0);
1480*cf5a6c84SAndroid Build Coastguard Worker             toys.optflags |= FLAG_f;
1481*cf5a6c84SAndroid Build Coastguard Worker             if (toys.optflags & FLAG_p) write_pid(TT.pidfile);
1482*cf5a6c84SAndroid Build Coastguard Worker           }
1483*cf5a6c84SAndroid Build Coastguard Worker           waited = 0;
1484*cf5a6c84SAndroid Build Coastguard Worker           continue;
1485*cf5a6c84SAndroid Build Coastguard Worker         } else if (msgType == DHCPNAK) {
1486*cf5a6c84SAndroid Build Coastguard Worker           dbg("NACK received.\n");
1487*cf5a6c84SAndroid Build Coastguard Worker           run_script(&result, "nak");
1488*cf5a6c84SAndroid Build Coastguard Worker           if (state->status != STATE_REQUESTING) run_script(NULL, "deconfig");
1489*cf5a6c84SAndroid Build Coastguard Worker           mode_raw();
1490*cf5a6c84SAndroid Build Coastguard Worker           sleep(3);
1491*cf5a6c84SAndroid Build Coastguard Worker           state->status = STATE_INIT;
1492*cf5a6c84SAndroid Build Coastguard Worker           state->ipaddr.s_addr = 0;
1493*cf5a6c84SAndroid Build Coastguard Worker           server = 0;
1494*cf5a6c84SAndroid Build Coastguard Worker           timeout = 0;
1495*cf5a6c84SAndroid Build Coastguard Worker           packets = 0;
1496*cf5a6c84SAndroid Build Coastguard Worker           waited = 0;
1497*cf5a6c84SAndroid Build Coastguard Worker         }
1498*cf5a6c84SAndroid Build Coastguard Worker         continue;
1499*cf5a6c84SAndroid Build Coastguard Worker       default: break;
1500*cf5a6c84SAndroid Build Coastguard Worker       }
1501*cf5a6c84SAndroid Build Coastguard Worker     }
1502*cf5a6c84SAndroid Build Coastguard Worker   }
1503*cf5a6c84SAndroid Build Coastguard Worker ret_with_sockfd:
1504*cf5a6c84SAndroid Build Coastguard Worker   if (CFG_TOYBOX_FREE) {
1505*cf5a6c84SAndroid Build Coastguard Worker     free_option_stores();
1506*cf5a6c84SAndroid Build Coastguard Worker     if (state->sockfd > 0) close(state->sockfd);
1507*cf5a6c84SAndroid Build Coastguard Worker     free(state);
1508*cf5a6c84SAndroid Build Coastguard Worker   }
1509*cf5a6c84SAndroid Build Coastguard Worker }
1510