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