1*1c60b9acSAndroid Build Coastguard Worker /*
2*1c60b9acSAndroid Build Coastguard Worker * libwebsockets - small server side websockets and web server implementation
3*1c60b9acSAndroid Build Coastguard Worker *
4*1c60b9acSAndroid Build Coastguard Worker * Copyright (C) 2010 - 2021 Andy Green <[email protected]>
5*1c60b9acSAndroid Build Coastguard Worker *
6*1c60b9acSAndroid Build Coastguard Worker * Permission is hereby granted, free of charge, to any person obtaining a copy
7*1c60b9acSAndroid Build Coastguard Worker * of this software and associated documentation files (the "Software"), to
8*1c60b9acSAndroid Build Coastguard Worker * deal in the Software without restriction, including without limitation the
9*1c60b9acSAndroid Build Coastguard Worker * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10*1c60b9acSAndroid Build Coastguard Worker * sell copies of the Software, and to permit persons to whom the Software is
11*1c60b9acSAndroid Build Coastguard Worker * furnished to do so, subject to the following conditions:
12*1c60b9acSAndroid Build Coastguard Worker *
13*1c60b9acSAndroid Build Coastguard Worker * The above copyright notice and this permission notice shall be included in
14*1c60b9acSAndroid Build Coastguard Worker * all copies or substantial portions of the Software.
15*1c60b9acSAndroid Build Coastguard Worker *
16*1c60b9acSAndroid Build Coastguard Worker * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17*1c60b9acSAndroid Build Coastguard Worker * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18*1c60b9acSAndroid Build Coastguard Worker * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19*1c60b9acSAndroid Build Coastguard Worker * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20*1c60b9acSAndroid Build Coastguard Worker * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21*1c60b9acSAndroid Build Coastguard Worker * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22*1c60b9acSAndroid Build Coastguard Worker * IN THE SOFTWARE.
23*1c60b9acSAndroid Build Coastguard Worker *
24*1c60b9acSAndroid Build Coastguard Worker * The protocol part of dhcp4 client
25*1c60b9acSAndroid Build Coastguard Worker */
26*1c60b9acSAndroid Build Coastguard Worker
27*1c60b9acSAndroid Build Coastguard Worker #include "private-lib-core.h"
28*1c60b9acSAndroid Build Coastguard Worker #include "private-lib-system-dhcpclient.h"
29*1c60b9acSAndroid Build Coastguard Worker
30*1c60b9acSAndroid Build Coastguard Worker #define LDHC_OP_BOOTREQUEST 1
31*1c60b9acSAndroid Build Coastguard Worker #define LDHC_OP_BOOTREPLY 2
32*1c60b9acSAndroid Build Coastguard Worker
33*1c60b9acSAndroid Build Coastguard Worker /*
34*1c60b9acSAndroid Build Coastguard Worker * IPv4... max total 576
35*1c60b9acSAndroid Build Coastguard Worker *
36*1c60b9acSAndroid Build Coastguard Worker * 0 1 2 3
37*1c60b9acSAndroid Build Coastguard Worker * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
38*1c60b9acSAndroid Build Coastguard Worker * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
39*1c60b9acSAndroid Build Coastguard Worker * | op (1) | htype (1) | hlen (1) | hops (1) |
40*1c60b9acSAndroid Build Coastguard Worker * +---------------+---------------+---------------+---------------+
41*1c60b9acSAndroid Build Coastguard Worker * | +04 xid (4) |
42*1c60b9acSAndroid Build Coastguard Worker * +-------------------------------+-------------------------------+
43*1c60b9acSAndroid Build Coastguard Worker * | +08 secs (2) | +0a flags (2) |
44*1c60b9acSAndroid Build Coastguard Worker * +-------------------------------+-------------------------------+
45*1c60b9acSAndroid Build Coastguard Worker * | +0C ciaddr (4) client IP |
46*1c60b9acSAndroid Build Coastguard Worker * +---------------------------------------------------------------+
47*1c60b9acSAndroid Build Coastguard Worker * | +10 yiaddr (4) your IP |
48*1c60b9acSAndroid Build Coastguard Worker * +---------------------------------------------------------------+
49*1c60b9acSAndroid Build Coastguard Worker * | +14 siaddr (4) server IP |
50*1c60b9acSAndroid Build Coastguard Worker * +---------------------------------------------------------------+
51*1c60b9acSAndroid Build Coastguard Worker * | +18 giaddr (4) gateway IP |
52*1c60b9acSAndroid Build Coastguard Worker * +---------------------------------------------------------------+
53*1c60b9acSAndroid Build Coastguard Worker * | |
54*1c60b9acSAndroid Build Coastguard Worker * | +1C chaddr (16) client HWADDR |
55*1c60b9acSAndroid Build Coastguard Worker * +---------------------------------------------------------------+
56*1c60b9acSAndroid Build Coastguard Worker * | |
57*1c60b9acSAndroid Build Coastguard Worker * | +2C sname (64) |
58*1c60b9acSAndroid Build Coastguard Worker * +---------------------------------------------------------------+
59*1c60b9acSAndroid Build Coastguard Worker * | |
60*1c60b9acSAndroid Build Coastguard Worker * | +6C file (128) |
61*1c60b9acSAndroid Build Coastguard Worker * +---------------------------------------------------------------+
62*1c60b9acSAndroid Build Coastguard Worker * | |
63*1c60b9acSAndroid Build Coastguard Worker * | +EC options (variable) |
64*1c60b9acSAndroid Build Coastguard Worker * +---------------------------------------------------------------+
65*1c60b9acSAndroid Build Coastguard Worker */
66*1c60b9acSAndroid Build Coastguard Worker
67*1c60b9acSAndroid Build Coastguard Worker static const uint8_t rawdisc4[] = {
68*1c60b9acSAndroid Build Coastguard Worker 0x45, 0x00, 0, 0, 0, 0, 0x40, 0, 0x2e, IPPROTO_UDP,
69*1c60b9acSAndroid Build Coastguard Worker 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff,
70*1c60b9acSAndroid Build Coastguard Worker 0, 68, 0, 67, 0, 0, 0, 0
71*1c60b9acSAndroid Build Coastguard Worker };
72*1c60b9acSAndroid Build Coastguard Worker
73*1c60b9acSAndroid Build Coastguard Worker static const uint32_t botable2[] = { 1500, 1750, 5000 /* in case dog slow */ };
74*1c60b9acSAndroid Build Coastguard Worker static const lws_retry_bo_t bo2 = {
75*1c60b9acSAndroid Build Coastguard Worker botable2, LWS_ARRAY_SIZE(botable2), LWS_RETRY_CONCEAL_ALWAYS, 0, 0, 20 };
76*1c60b9acSAndroid Build Coastguard Worker
77*1c60b9acSAndroid Build Coastguard Worker static int
lws_dhcpc4_prep(uint8_t * start,unsigned int bufsiz,lws_dhcpc_req_t * r,int op)78*1c60b9acSAndroid Build Coastguard Worker lws_dhcpc4_prep(uint8_t *start, unsigned int bufsiz, lws_dhcpc_req_t *r, int op)
79*1c60b9acSAndroid Build Coastguard Worker {
80*1c60b9acSAndroid Build Coastguard Worker uint8_t *p = start;
81*1c60b9acSAndroid Build Coastguard Worker
82*1c60b9acSAndroid Build Coastguard Worker memset(start, 0, bufsiz);
83*1c60b9acSAndroid Build Coastguard Worker
84*1c60b9acSAndroid Build Coastguard Worker *p++ = 1;
85*1c60b9acSAndroid Build Coastguard Worker *p++ = 1;
86*1c60b9acSAndroid Build Coastguard Worker *p++ = 6; /* sizeof ethernet MAC */
87*1c60b9acSAndroid Build Coastguard Worker
88*1c60b9acSAndroid Build Coastguard Worker memcpy(p + 1, r->xid, 4);
89*1c60b9acSAndroid Build Coastguard Worker
90*1c60b9acSAndroid Build Coastguard Worker // p[7] = 0x80; /* broadcast flag */
91*1c60b9acSAndroid Build Coastguard Worker
92*1c60b9acSAndroid Build Coastguard Worker p += 0x1c - 3;
93*1c60b9acSAndroid Build Coastguard Worker
94*1c60b9acSAndroid Build Coastguard Worker if (lws_plat_ifname_to_hwaddr(r->wsi_raw->desc.sockfd,
95*1c60b9acSAndroid Build Coastguard Worker (const char *)&r[1], r->is.mac, 6) < 0)
96*1c60b9acSAndroid Build Coastguard Worker return -1;
97*1c60b9acSAndroid Build Coastguard Worker
98*1c60b9acSAndroid Build Coastguard Worker memcpy(p, r->is.mac, 6);
99*1c60b9acSAndroid Build Coastguard Worker
100*1c60b9acSAndroid Build Coastguard Worker p += 16 + 64 + 128;
101*1c60b9acSAndroid Build Coastguard Worker
102*1c60b9acSAndroid Build Coastguard Worker *p++ = 0x63; /* RFC2132 Magic Cookie indicates start of options */
103*1c60b9acSAndroid Build Coastguard Worker *p++ = 0x82;
104*1c60b9acSAndroid Build Coastguard Worker *p++ = 0x53;
105*1c60b9acSAndroid Build Coastguard Worker *p++ = 0x63;
106*1c60b9acSAndroid Build Coastguard Worker
107*1c60b9acSAndroid Build Coastguard Worker *p++ = LWSDHC4POPT_MESSAGE_TYPE;
108*1c60b9acSAndroid Build Coastguard Worker *p++ = 1; /* length */
109*1c60b9acSAndroid Build Coastguard Worker *p++ = (uint8_t)op;
110*1c60b9acSAndroid Build Coastguard Worker
111*1c60b9acSAndroid Build Coastguard Worker switch (op) {
112*1c60b9acSAndroid Build Coastguard Worker case LWSDHC4PDISCOVER:
113*1c60b9acSAndroid Build Coastguard Worker *p++ = LWSDHC4POPT_PARAM_REQ_LIST;
114*1c60b9acSAndroid Build Coastguard Worker *p++ = 4; /* length */
115*1c60b9acSAndroid Build Coastguard Worker *p++ = LWSDHC4POPT_SUBNET_MASK;
116*1c60b9acSAndroid Build Coastguard Worker *p++ = LWSDHC4POPT_ROUTER;
117*1c60b9acSAndroid Build Coastguard Worker *p++ = LWSDHC4POPT_DNSERVER;
118*1c60b9acSAndroid Build Coastguard Worker *p++ = LWSDHC4POPT_DOMAIN_NAME;
119*1c60b9acSAndroid Build Coastguard Worker break;
120*1c60b9acSAndroid Build Coastguard Worker
121*1c60b9acSAndroid Build Coastguard Worker case LWSDHC4PREQUEST:
122*1c60b9acSAndroid Build Coastguard Worker if (r->is.sa46[LWSDH_SA46_IP].sa4.sin_family != AF_INET)
123*1c60b9acSAndroid Build Coastguard Worker break;
124*1c60b9acSAndroid Build Coastguard Worker *p++ = LWSDHC4POPT_REQUESTED_ADS;
125*1c60b9acSAndroid Build Coastguard Worker *p++ = 4; /* length */
126*1c60b9acSAndroid Build Coastguard Worker lws_ser_wu32be(p, r->is.sa46[LWSDH_SA46_IP].sa4.sin_addr.s_addr);
127*1c60b9acSAndroid Build Coastguard Worker p += 4;
128*1c60b9acSAndroid Build Coastguard Worker *p++ = LWSDHC4POPT_SERVER_ID;
129*1c60b9acSAndroid Build Coastguard Worker *p++ = 4; /* length */
130*1c60b9acSAndroid Build Coastguard Worker lws_ser_wu32be(p, r->is.sa46[LWSDH_SA46_DHCP_SERVER].sa4.sin_addr.s_addr);
131*1c60b9acSAndroid Build Coastguard Worker p += 4;
132*1c60b9acSAndroid Build Coastguard Worker break;
133*1c60b9acSAndroid Build Coastguard Worker }
134*1c60b9acSAndroid Build Coastguard Worker
135*1c60b9acSAndroid Build Coastguard Worker *p++ = LWSDHC4POPT_END_OPTIONS;
136*1c60b9acSAndroid Build Coastguard Worker
137*1c60b9acSAndroid Build Coastguard Worker return lws_ptr_diff(p, start);
138*1c60b9acSAndroid Build Coastguard Worker }
139*1c60b9acSAndroid Build Coastguard Worker
140*1c60b9acSAndroid Build Coastguard Worker static int
callback_dhcpc4(struct lws * wsi,enum lws_callback_reasons reason,void * user,void * in,size_t len)141*1c60b9acSAndroid Build Coastguard Worker callback_dhcpc4(struct lws *wsi, enum lws_callback_reasons reason, void *user,
142*1c60b9acSAndroid Build Coastguard Worker void *in, size_t len)
143*1c60b9acSAndroid Build Coastguard Worker {
144*1c60b9acSAndroid Build Coastguard Worker lws_dhcpc_req_t *r = (lws_dhcpc_req_t *)user;
145*1c60b9acSAndroid Build Coastguard Worker uint8_t pkt[LWS_PRE + 576], *p = pkt + LWS_PRE;
146*1c60b9acSAndroid Build Coastguard Worker int n, m;
147*1c60b9acSAndroid Build Coastguard Worker
148*1c60b9acSAndroid Build Coastguard Worker switch (reason) {
149*1c60b9acSAndroid Build Coastguard Worker
150*1c60b9acSAndroid Build Coastguard Worker case LWS_CALLBACK_RAW_ADOPT:
151*1c60b9acSAndroid Build Coastguard Worker lwsl_debug("%s: LWS_CALLBACK_RAW_ADOPT\n", __func__);
152*1c60b9acSAndroid Build Coastguard Worker lws_callback_on_writable(wsi);
153*1c60b9acSAndroid Build Coastguard Worker break;
154*1c60b9acSAndroid Build Coastguard Worker
155*1c60b9acSAndroid Build Coastguard Worker case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
156*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: udp conn failed\n", __func__);
157*1c60b9acSAndroid Build Coastguard Worker
158*1c60b9acSAndroid Build Coastguard Worker /* fallthru */
159*1c60b9acSAndroid Build Coastguard Worker case LWS_CALLBACK_RAW_CLOSE:
160*1c60b9acSAndroid Build Coastguard Worker lwsl_debug("%s: LWS_CALLBACK_RAW_CLOSE\n", __func__);
161*1c60b9acSAndroid Build Coastguard Worker if (!r)
162*1c60b9acSAndroid Build Coastguard Worker break;
163*1c60b9acSAndroid Build Coastguard Worker r->wsi_raw = NULL;
164*1c60b9acSAndroid Build Coastguard Worker lws_sul_cancel(&r->sul_write);
165*1c60b9acSAndroid Build Coastguard Worker if (r->state != LDHC_BOUND) {
166*1c60b9acSAndroid Build Coastguard Worker r->state = LDHC_INIT;
167*1c60b9acSAndroid Build Coastguard Worker lws_retry_sul_schedule(r->context, 0, &r->sul_conn,
168*1c60b9acSAndroid Build Coastguard Worker &bo2, lws_dhcpc4_retry_conn,
169*1c60b9acSAndroid Build Coastguard Worker &r->retry_count_conn);
170*1c60b9acSAndroid Build Coastguard Worker }
171*1c60b9acSAndroid Build Coastguard Worker break;
172*1c60b9acSAndroid Build Coastguard Worker
173*1c60b9acSAndroid Build Coastguard Worker case LWS_CALLBACK_RAW_RX:
174*1c60b9acSAndroid Build Coastguard Worker
175*1c60b9acSAndroid Build Coastguard Worker if (lws_dhcpc4_parse(r, in, len))
176*1c60b9acSAndroid Build Coastguard Worker break;
177*1c60b9acSAndroid Build Coastguard Worker
178*1c60b9acSAndroid Build Coastguard Worker /*
179*1c60b9acSAndroid Build Coastguard Worker * that's it... commit to the configuration
180*1c60b9acSAndroid Build Coastguard Worker */
181*1c60b9acSAndroid Build Coastguard Worker
182*1c60b9acSAndroid Build Coastguard Worker /* set up our network interface as offered */
183*1c60b9acSAndroid Build Coastguard Worker
184*1c60b9acSAndroid Build Coastguard Worker if (lws_plat_ifconfig(r->wsi_raw->desc.sockfd, &r->is))
185*1c60b9acSAndroid Build Coastguard Worker /*
186*1c60b9acSAndroid Build Coastguard Worker * Problem setting the IP... maybe something
187*1c60b9acSAndroid Build Coastguard Worker * transient like racing with NetworkManager?
188*1c60b9acSAndroid Build Coastguard Worker * Since the sul retries are still around it
189*1c60b9acSAndroid Build Coastguard Worker * will retry
190*1c60b9acSAndroid Build Coastguard Worker */
191*1c60b9acSAndroid Build Coastguard Worker return -1;
192*1c60b9acSAndroid Build Coastguard Worker
193*1c60b9acSAndroid Build Coastguard Worker /* clear timeouts related to the broadcast socket */
194*1c60b9acSAndroid Build Coastguard Worker
195*1c60b9acSAndroid Build Coastguard Worker lws_sul_cancel(&r->sul_write);
196*1c60b9acSAndroid Build Coastguard Worker lws_sul_cancel(&r->sul_conn);
197*1c60b9acSAndroid Build Coastguard Worker
198*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("%s: DHCP configured %s\n", __func__,
199*1c60b9acSAndroid Build Coastguard Worker (const char *)&r[1]);
200*1c60b9acSAndroid Build Coastguard Worker r->state = LDHC_BOUND;
201*1c60b9acSAndroid Build Coastguard Worker
202*1c60b9acSAndroid Build Coastguard Worker lws_state_transition_steps(&wsi->a.context->mgr_system,
203*1c60b9acSAndroid Build Coastguard Worker LWS_SYSTATE_OPERATIONAL);
204*1c60b9acSAndroid Build Coastguard Worker
205*1c60b9acSAndroid Build Coastguard Worker r->cb(r->opaque, &r->is);
206*1c60b9acSAndroid Build Coastguard Worker
207*1c60b9acSAndroid Build Coastguard Worker r->wsi_raw = NULL;
208*1c60b9acSAndroid Build Coastguard Worker
209*1c60b9acSAndroid Build Coastguard Worker return -1; /* close the broadcast wsi */
210*1c60b9acSAndroid Build Coastguard Worker
211*1c60b9acSAndroid Build Coastguard Worker case LWS_CALLBACK_RAW_WRITEABLE:
212*1c60b9acSAndroid Build Coastguard Worker
213*1c60b9acSAndroid Build Coastguard Worker if (!r)
214*1c60b9acSAndroid Build Coastguard Worker break;
215*1c60b9acSAndroid Build Coastguard Worker
216*1c60b9acSAndroid Build Coastguard Worker /*
217*1c60b9acSAndroid Build Coastguard Worker * UDP is not reliable, it can be locally dropped, or dropped
218*1c60b9acSAndroid Build Coastguard Worker * by any intermediary or the remote peer. So even though we
219*1c60b9acSAndroid Build Coastguard Worker * will do the write in a moment, we schedule another request
220*1c60b9acSAndroid Build Coastguard Worker * for rewrite according to the wsi retry policy.
221*1c60b9acSAndroid Build Coastguard Worker *
222*1c60b9acSAndroid Build Coastguard Worker * If the result came before, we'll cancel it in the close flow.
223*1c60b9acSAndroid Build Coastguard Worker *
224*1c60b9acSAndroid Build Coastguard Worker * If we have already reached the end of our concealed retries
225*1c60b9acSAndroid Build Coastguard Worker * in the policy, just close without another write.
226*1c60b9acSAndroid Build Coastguard Worker */
227*1c60b9acSAndroid Build Coastguard Worker if (lws_dll2_is_detached(&r->sul_write.list) &&
228*1c60b9acSAndroid Build Coastguard Worker lws_retry_sul_schedule_retry_wsi(wsi, &r->sul_write,
229*1c60b9acSAndroid Build Coastguard Worker lws_dhcpc_retry_write,
230*1c60b9acSAndroid Build Coastguard Worker &r->retry_count_write)) {
231*1c60b9acSAndroid Build Coastguard Worker /* we have reached the end of our concealed retries */
232*1c60b9acSAndroid Build Coastguard Worker lwsl_warn("%s: concealed retries done, failing\n",
233*1c60b9acSAndroid Build Coastguard Worker __func__);
234*1c60b9acSAndroid Build Coastguard Worker goto retry_conn;
235*1c60b9acSAndroid Build Coastguard Worker }
236*1c60b9acSAndroid Build Coastguard Worker
237*1c60b9acSAndroid Build Coastguard Worker switch (r->state) {
238*1c60b9acSAndroid Build Coastguard Worker case LDHC_INIT:
239*1c60b9acSAndroid Build Coastguard Worker n = LWSDHC4PDISCOVER;
240*1c60b9acSAndroid Build Coastguard Worker goto bcast;
241*1c60b9acSAndroid Build Coastguard Worker
242*1c60b9acSAndroid Build Coastguard Worker case LDHC_REQUESTING:
243*1c60b9acSAndroid Build Coastguard Worker n = LWSDHC4PREQUEST;
244*1c60b9acSAndroid Build Coastguard Worker
245*1c60b9acSAndroid Build Coastguard Worker /* fallthru */
246*1c60b9acSAndroid Build Coastguard Worker bcast:
247*1c60b9acSAndroid Build Coastguard Worker n = lws_dhcpc4_prep(p + 28, (unsigned int)
248*1c60b9acSAndroid Build Coastguard Worker (sizeof(pkt) - LWS_PRE - 28), r, n);
249*1c60b9acSAndroid Build Coastguard Worker if (n < 0) {
250*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: failed to prep\n", __func__);
251*1c60b9acSAndroid Build Coastguard Worker break;
252*1c60b9acSAndroid Build Coastguard Worker }
253*1c60b9acSAndroid Build Coastguard Worker
254*1c60b9acSAndroid Build Coastguard Worker m = lws_plat_rawudp_broadcast(p, rawdisc4,
255*1c60b9acSAndroid Build Coastguard Worker LWS_ARRAY_SIZE(rawdisc4),
256*1c60b9acSAndroid Build Coastguard Worker (size_t)(n + 28),
257*1c60b9acSAndroid Build Coastguard Worker r->wsi_raw->desc.sockfd,
258*1c60b9acSAndroid Build Coastguard Worker (const char *)&r[1]);
259*1c60b9acSAndroid Build Coastguard Worker if (m < 0)
260*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: Failed to write dhcp client req: "
261*1c60b9acSAndroid Build Coastguard Worker "%d %d, errno %d\n", __func__,
262*1c60b9acSAndroid Build Coastguard Worker n, m, LWS_ERRNO);
263*1c60b9acSAndroid Build Coastguard Worker break;
264*1c60b9acSAndroid Build Coastguard Worker default:
265*1c60b9acSAndroid Build Coastguard Worker break;
266*1c60b9acSAndroid Build Coastguard Worker }
267*1c60b9acSAndroid Build Coastguard Worker
268*1c60b9acSAndroid Build Coastguard Worker return 0;
269*1c60b9acSAndroid Build Coastguard Worker
270*1c60b9acSAndroid Build Coastguard Worker retry_conn:
271*1c60b9acSAndroid Build Coastguard Worker lws_retry_sul_schedule(wsi->a.context, 0, &r->sul_conn, &bo2,
272*1c60b9acSAndroid Build Coastguard Worker lws_dhcpc4_retry_conn,
273*1c60b9acSAndroid Build Coastguard Worker &r->retry_count_conn);
274*1c60b9acSAndroid Build Coastguard Worker
275*1c60b9acSAndroid Build Coastguard Worker return -1;
276*1c60b9acSAndroid Build Coastguard Worker
277*1c60b9acSAndroid Build Coastguard Worker default:
278*1c60b9acSAndroid Build Coastguard Worker break;
279*1c60b9acSAndroid Build Coastguard Worker }
280*1c60b9acSAndroid Build Coastguard Worker
281*1c60b9acSAndroid Build Coastguard Worker return 0;
282*1c60b9acSAndroid Build Coastguard Worker }
283*1c60b9acSAndroid Build Coastguard Worker
284*1c60b9acSAndroid Build Coastguard Worker struct lws_protocols lws_system_protocol_dhcpc4 =
285*1c60b9acSAndroid Build Coastguard Worker { "lws-dhcp4client", callback_dhcpc4, 0, 128, 0, NULL, 0 };
286*1c60b9acSAndroid Build Coastguard Worker
287*1c60b9acSAndroid Build Coastguard Worker void
lws_dhcpc4_retry_conn(struct lws_sorted_usec_list * sul)288*1c60b9acSAndroid Build Coastguard Worker lws_dhcpc4_retry_conn(struct lws_sorted_usec_list *sul)
289*1c60b9acSAndroid Build Coastguard Worker {
290*1c60b9acSAndroid Build Coastguard Worker lws_dhcpc_req_t *r = lws_container_of(sul, lws_dhcpc_req_t, sul_conn);
291*1c60b9acSAndroid Build Coastguard Worker
292*1c60b9acSAndroid Build Coastguard Worker if (r->wsi_raw || !lws_dll2_is_detached(&r->sul_conn.list))
293*1c60b9acSAndroid Build Coastguard Worker return;
294*1c60b9acSAndroid Build Coastguard Worker
295*1c60b9acSAndroid Build Coastguard Worker /* create the UDP socket aimed at the server */
296*1c60b9acSAndroid Build Coastguard Worker
297*1c60b9acSAndroid Build Coastguard Worker r->retry_count_write = 0;
298*1c60b9acSAndroid Build Coastguard Worker r->wsi_raw = lws_create_adopt_udp(r->context->vhost_system, "0.0.0.0",
299*1c60b9acSAndroid Build Coastguard Worker 68, LWS_CAUDP_PF_PACKET |
300*1c60b9acSAndroid Build Coastguard Worker LWS_CAUDP_BROADCAST,
301*1c60b9acSAndroid Build Coastguard Worker "lws-dhcp4client", (const char *)&r[1],
302*1c60b9acSAndroid Build Coastguard Worker NULL, NULL, &bo2, "dhcpc");
303*1c60b9acSAndroid Build Coastguard Worker lwsl_debug("%s: created wsi_raw: %s\n", __func__, lws_wsi_tag(r->wsi_raw));
304*1c60b9acSAndroid Build Coastguard Worker if (!r->wsi_raw) {
305*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: unable to create udp skt\n", __func__);
306*1c60b9acSAndroid Build Coastguard Worker
307*1c60b9acSAndroid Build Coastguard Worker lws_retry_sul_schedule(r->context, 0, &r->sul_conn, &bo2,
308*1c60b9acSAndroid Build Coastguard Worker lws_dhcpc4_retry_conn,
309*1c60b9acSAndroid Build Coastguard Worker &r->retry_count_conn);
310*1c60b9acSAndroid Build Coastguard Worker
311*1c60b9acSAndroid Build Coastguard Worker return;
312*1c60b9acSAndroid Build Coastguard Worker }
313*1c60b9acSAndroid Build Coastguard Worker
314*1c60b9acSAndroid Build Coastguard Worker /* force the network if up */
315*1c60b9acSAndroid Build Coastguard Worker lws_plat_if_up((const char *)&r[1], r->wsi_raw->desc.sockfd, 0);
316*1c60b9acSAndroid Build Coastguard Worker lws_plat_if_up((const char *)&r[1], r->wsi_raw->desc.sockfd, 1);
317*1c60b9acSAndroid Build Coastguard Worker
318*1c60b9acSAndroid Build Coastguard Worker r->wsi_raw->user_space = r;
319*1c60b9acSAndroid Build Coastguard Worker r->wsi_raw->user_space_externally_allocated = 1;
320*1c60b9acSAndroid Build Coastguard Worker
321*1c60b9acSAndroid Build Coastguard Worker lws_get_random(r->wsi_raw->a.context, r->xid, 4);
322*1c60b9acSAndroid Build Coastguard Worker }
323*1c60b9acSAndroid Build Coastguard Worker
324*1c60b9acSAndroid Build Coastguard Worker static void
lws_sa46_set_ipv4(lws_dhcpc_req_t * r,unsigned int which,uint8_t * p)325*1c60b9acSAndroid Build Coastguard Worker lws_sa46_set_ipv4(lws_dhcpc_req_t *r, unsigned int which, uint8_t *p)
326*1c60b9acSAndroid Build Coastguard Worker {
327*1c60b9acSAndroid Build Coastguard Worker r->is.sa46[which].sa4.sin_family = AF_INET;
328*1c60b9acSAndroid Build Coastguard Worker r->is.sa46[which].sa4.sin_addr.s_addr = ntohl(lws_ser_ru32be(p));
329*1c60b9acSAndroid Build Coastguard Worker }
330*1c60b9acSAndroid Build Coastguard Worker
331*1c60b9acSAndroid Build Coastguard Worker int
lws_dhcpc4_parse(lws_dhcpc_req_t * r,void * in,size_t len)332*1c60b9acSAndroid Build Coastguard Worker lws_dhcpc4_parse(lws_dhcpc_req_t *r, void *in, size_t len)
333*1c60b9acSAndroid Build Coastguard Worker {
334*1c60b9acSAndroid Build Coastguard Worker uint8_t pkt[LWS_PRE + 576], *p = pkt + LWS_PRE, *end;
335*1c60b9acSAndroid Build Coastguard Worker int n, m;
336*1c60b9acSAndroid Build Coastguard Worker
337*1c60b9acSAndroid Build Coastguard Worker switch (r->state) {
338*1c60b9acSAndroid Build Coastguard Worker case LDHC_INIT: /* expect DHCPOFFER */
339*1c60b9acSAndroid Build Coastguard Worker case LDHC_REQUESTING: /* expect DHCPACK */
340*1c60b9acSAndroid Build Coastguard Worker /*
341*1c60b9acSAndroid Build Coastguard Worker * We should check carefully if we like what we were
342*1c60b9acSAndroid Build Coastguard Worker * sent... anything can spam us with crafted replies
343*1c60b9acSAndroid Build Coastguard Worker */
344*1c60b9acSAndroid Build Coastguard Worker if (len < 0x100)
345*1c60b9acSAndroid Build Coastguard Worker break;
346*1c60b9acSAndroid Build Coastguard Worker
347*1c60b9acSAndroid Build Coastguard Worker p = (uint8_t *)in + 28; /* skip to UDP payload */
348*1c60b9acSAndroid Build Coastguard Worker if (p[0] != 2 || p[1] != 1 || p[2] != 6)
349*1c60b9acSAndroid Build Coastguard Worker break;
350*1c60b9acSAndroid Build Coastguard Worker
351*1c60b9acSAndroid Build Coastguard Worker if (memcmp(&p[4], r->xid, 4)) /* must be our xid */
352*1c60b9acSAndroid Build Coastguard Worker break;
353*1c60b9acSAndroid Build Coastguard Worker
354*1c60b9acSAndroid Build Coastguard Worker if (memcmp(&p[0x1c], r->is.mac, 6)) /* our netif mac? */
355*1c60b9acSAndroid Build Coastguard Worker break;
356*1c60b9acSAndroid Build Coastguard Worker
357*1c60b9acSAndroid Build Coastguard Worker /* the DHCP magic cookie must be in place */
358*1c60b9acSAndroid Build Coastguard Worker if (lws_ser_ru32be(&p[0xec]) != 0x63825363)
359*1c60b9acSAndroid Build Coastguard Worker break;
360*1c60b9acSAndroid Build Coastguard Worker
361*1c60b9acSAndroid Build Coastguard Worker /* "your" client IP address */
362*1c60b9acSAndroid Build Coastguard Worker lws_sa46_set_ipv4(r, LWSDH_SA46_IP, p + 0x10);
363*1c60b9acSAndroid Build Coastguard Worker /* IP of next server used in bootstrap */
364*1c60b9acSAndroid Build Coastguard Worker lws_sa46_set_ipv4(r, LWSDH_SA46_DHCP_SERVER, p + 0x14);
365*1c60b9acSAndroid Build Coastguard Worker
366*1c60b9acSAndroid Build Coastguard Worker /* it looks legit so far... look at the options */
367*1c60b9acSAndroid Build Coastguard Worker
368*1c60b9acSAndroid Build Coastguard Worker end = (uint8_t *)in + len;
369*1c60b9acSAndroid Build Coastguard Worker p += 0xec + 4;
370*1c60b9acSAndroid Build Coastguard Worker while (p < end) {
371*1c60b9acSAndroid Build Coastguard Worker uint8_t c = *p++;
372*1c60b9acSAndroid Build Coastguard Worker uint8_t l = 0;
373*1c60b9acSAndroid Build Coastguard Worker
374*1c60b9acSAndroid Build Coastguard Worker if (c && c != 0xff) {
375*1c60b9acSAndroid Build Coastguard Worker /* pad 0 and EOT 0xff have no length */
376*1c60b9acSAndroid Build Coastguard Worker l = *p++;
377*1c60b9acSAndroid Build Coastguard Worker if (!l) {
378*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: zero length\n",
379*1c60b9acSAndroid Build Coastguard Worker __func__);
380*1c60b9acSAndroid Build Coastguard Worker goto broken;
381*1c60b9acSAndroid Build Coastguard Worker }
382*1c60b9acSAndroid Build Coastguard Worker if (p + l > end) {
383*1c60b9acSAndroid Build Coastguard Worker /* ...nice try... */
384*1c60b9acSAndroid Build Coastguard Worker lwsl_err("%s: bad len\n",
385*1c60b9acSAndroid Build Coastguard Worker __func__);
386*1c60b9acSAndroid Build Coastguard Worker goto broken;
387*1c60b9acSAndroid Build Coastguard Worker }
388*1c60b9acSAndroid Build Coastguard Worker }
389*1c60b9acSAndroid Build Coastguard Worker
390*1c60b9acSAndroid Build Coastguard Worker if (c == 0xff) /* end of options */
391*1c60b9acSAndroid Build Coastguard Worker break;
392*1c60b9acSAndroid Build Coastguard Worker
393*1c60b9acSAndroid Build Coastguard Worker m = 0;
394*1c60b9acSAndroid Build Coastguard Worker switch (c) {
395*1c60b9acSAndroid Build Coastguard Worker case LWSDHC4POPT_SUBNET_MASK:
396*1c60b9acSAndroid Build Coastguard Worker n = LWSDH_IPV4_SUBNET_MASK;
397*1c60b9acSAndroid Build Coastguard Worker goto get_ipv4;
398*1c60b9acSAndroid Build Coastguard Worker
399*1c60b9acSAndroid Build Coastguard Worker case LWSDHC4POPT_ROUTER:
400*1c60b9acSAndroid Build Coastguard Worker lws_sa46_set_ipv4(r, LWSDH_SA46_IPV4_ROUTER, p);
401*1c60b9acSAndroid Build Coastguard Worker break;
402*1c60b9acSAndroid Build Coastguard Worker
403*1c60b9acSAndroid Build Coastguard Worker case LWSDHC4POPT_TIME_SERVER:
404*1c60b9acSAndroid Build Coastguard Worker lws_sa46_set_ipv4(r, LWSDH_SA46_NTP_SERVER, p);
405*1c60b9acSAndroid Build Coastguard Worker break;
406*1c60b9acSAndroid Build Coastguard Worker
407*1c60b9acSAndroid Build Coastguard Worker case LWSDHC4POPT_BROADCAST_ADS:
408*1c60b9acSAndroid Build Coastguard Worker n = LWSDH_IPV4_BROADCAST;
409*1c60b9acSAndroid Build Coastguard Worker goto get_ipv4;
410*1c60b9acSAndroid Build Coastguard Worker
411*1c60b9acSAndroid Build Coastguard Worker case LWSDHC4POPT_LEASE_TIME:
412*1c60b9acSAndroid Build Coastguard Worker n = LWSDH_LEASE_SECS;
413*1c60b9acSAndroid Build Coastguard Worker goto get_ipv4;
414*1c60b9acSAndroid Build Coastguard Worker
415*1c60b9acSAndroid Build Coastguard Worker case LWSDHC4POPT_RENEWAL_TIME: /* AKA T1 */
416*1c60b9acSAndroid Build Coastguard Worker n = LWSDH_RENEWAL_SECS;
417*1c60b9acSAndroid Build Coastguard Worker goto get_ipv4;
418*1c60b9acSAndroid Build Coastguard Worker
419*1c60b9acSAndroid Build Coastguard Worker case LWSDHC4POPT_REBINDING_TIME: /* AKA T2 */
420*1c60b9acSAndroid Build Coastguard Worker n = LWSDH_REBINDING_SECS;
421*1c60b9acSAndroid Build Coastguard Worker goto get_ipv4;
422*1c60b9acSAndroid Build Coastguard Worker
423*1c60b9acSAndroid Build Coastguard Worker case LWSDHC4POPT_DNSERVER:
424*1c60b9acSAndroid Build Coastguard Worker if (l & 3)
425*1c60b9acSAndroid Build Coastguard Worker break;
426*1c60b9acSAndroid Build Coastguard Worker m = LWSDH_SA46_DNS_SRV_1;
427*1c60b9acSAndroid Build Coastguard Worker while (l && m - LWSDH_SA46_DNS_SRV_1 < 4) {
428*1c60b9acSAndroid Build Coastguard Worker lws_sa46_set_ipv4(r, (unsigned int)m++, p);
429*1c60b9acSAndroid Build Coastguard Worker l = (uint8_t)(l - 4);
430*1c60b9acSAndroid Build Coastguard Worker p += 4;
431*1c60b9acSAndroid Build Coastguard Worker }
432*1c60b9acSAndroid Build Coastguard Worker break;
433*1c60b9acSAndroid Build Coastguard Worker
434*1c60b9acSAndroid Build Coastguard Worker case LWSDHC4POPT_DOMAIN_NAME:
435*1c60b9acSAndroid Build Coastguard Worker m = l;
436*1c60b9acSAndroid Build Coastguard Worker if (m > (int)sizeof(r->is.domain) - 1)
437*1c60b9acSAndroid Build Coastguard Worker m = sizeof(r->is.domain) - 1;
438*1c60b9acSAndroid Build Coastguard Worker lws_strnncpy(r->is.domain, (const char *)p,
439*1c60b9acSAndroid Build Coastguard Worker (unsigned int)m, sizeof(r->is.domain));
440*1c60b9acSAndroid Build Coastguard Worker break;
441*1c60b9acSAndroid Build Coastguard Worker
442*1c60b9acSAndroid Build Coastguard Worker case LWSDHC4POPT_MESSAGE_TYPE:
443*1c60b9acSAndroid Build Coastguard Worker /*
444*1c60b9acSAndroid Build Coastguard Worker * Confirm this is the right message
445*1c60b9acSAndroid Build Coastguard Worker * for the state of the negotiation
446*1c60b9acSAndroid Build Coastguard Worker */
447*1c60b9acSAndroid Build Coastguard Worker if (r->state == LDHC_INIT && *p != LWSDHC4POFFER)
448*1c60b9acSAndroid Build Coastguard Worker goto broken;
449*1c60b9acSAndroid Build Coastguard Worker if (r->state == LDHC_REQUESTING &&
450*1c60b9acSAndroid Build Coastguard Worker *p != LWSDHC4PACK)
451*1c60b9acSAndroid Build Coastguard Worker goto broken;
452*1c60b9acSAndroid Build Coastguard Worker break;
453*1c60b9acSAndroid Build Coastguard Worker
454*1c60b9acSAndroid Build Coastguard Worker default:
455*1c60b9acSAndroid Build Coastguard Worker break;
456*1c60b9acSAndroid Build Coastguard Worker }
457*1c60b9acSAndroid Build Coastguard Worker
458*1c60b9acSAndroid Build Coastguard Worker p += l;
459*1c60b9acSAndroid Build Coastguard Worker continue;
460*1c60b9acSAndroid Build Coastguard Worker get_ipv4:
461*1c60b9acSAndroid Build Coastguard Worker if (l >= 4)
462*1c60b9acSAndroid Build Coastguard Worker r->is.nums[n] = ntohl(lws_ser_ru32be(p));
463*1c60b9acSAndroid Build Coastguard Worker p += l;
464*1c60b9acSAndroid Build Coastguard Worker continue;
465*1c60b9acSAndroid Build Coastguard Worker broken:
466*1c60b9acSAndroid Build Coastguard Worker memset(r->is.sa46, 0, sizeof(r->is.sa46));
467*1c60b9acSAndroid Build Coastguard Worker break;
468*1c60b9acSAndroid Build Coastguard Worker }
469*1c60b9acSAndroid Build Coastguard Worker
470*1c60b9acSAndroid Build Coastguard Worker #if defined(_DEBUG)
471*1c60b9acSAndroid Build Coastguard Worker /* dump what we have parsed out */
472*1c60b9acSAndroid Build Coastguard Worker
473*1c60b9acSAndroid Build Coastguard Worker for (n = 0; n < (int)_LWSDH_NUMS_COUNT; n++) {
474*1c60b9acSAndroid Build Coastguard Worker m = (int)ntohl(r->is.nums[n]);
475*1c60b9acSAndroid Build Coastguard Worker lwsl_info("%s: %d: 0x%x\n", __func__, n, m);
476*1c60b9acSAndroid Build Coastguard Worker }
477*1c60b9acSAndroid Build Coastguard Worker
478*1c60b9acSAndroid Build Coastguard Worker for (n = 0; n < (int)_LWSDH_SA46_COUNT; n++) {
479*1c60b9acSAndroid Build Coastguard Worker lws_sa46_write_numeric_address(&r->is.sa46[n],
480*1c60b9acSAndroid Build Coastguard Worker (char *)pkt, 48);
481*1c60b9acSAndroid Build Coastguard Worker lwsl_info("%s: %d: %s\n", __func__, n, pkt);
482*1c60b9acSAndroid Build Coastguard Worker }
483*1c60b9acSAndroid Build Coastguard Worker #endif
484*1c60b9acSAndroid Build Coastguard Worker
485*1c60b9acSAndroid Build Coastguard Worker /*
486*1c60b9acSAndroid Build Coastguard Worker * Having seen everything in there... do we really feel
487*1c60b9acSAndroid Build Coastguard Worker * we could use it? Everything critical is there?
488*1c60b9acSAndroid Build Coastguard Worker */
489*1c60b9acSAndroid Build Coastguard Worker
490*1c60b9acSAndroid Build Coastguard Worker if (!r->is.sa46[LWSDH_SA46_IP].sa4.sin_family ||
491*1c60b9acSAndroid Build Coastguard Worker !r->is.sa46[LWSDH_SA46_DHCP_SERVER].sa4.sin_family ||
492*1c60b9acSAndroid Build Coastguard Worker !r->is.sa46[LWSDH_SA46_IPV4_ROUTER].sa4.sin_family ||
493*1c60b9acSAndroid Build Coastguard Worker !r->is.nums[LWSDH_IPV4_SUBNET_MASK] ||
494*1c60b9acSAndroid Build Coastguard Worker !r->is.nums[LWSDH_LEASE_SECS] ||
495*1c60b9acSAndroid Build Coastguard Worker !r->is.sa46[LWSDH_SA46_DNS_SRV_1].sa4.sin_family) {
496*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("%s: rejecting on incomplete\n", __func__);
497*1c60b9acSAndroid Build Coastguard Worker memset(r->is.sa46, 0, sizeof(r->is.sa46));
498*1c60b9acSAndroid Build Coastguard Worker break;
499*1c60b9acSAndroid Build Coastguard Worker }
500*1c60b9acSAndroid Build Coastguard Worker
501*1c60b9acSAndroid Build Coastguard Worker /*
502*1c60b9acSAndroid Build Coastguard Worker * Network layout has to be internally consistent...
503*1c60b9acSAndroid Build Coastguard Worker * DHCP server has to be reachable by broadcast and
504*1c60b9acSAndroid Build Coastguard Worker * default route has to be on same subnet
505*1c60b9acSAndroid Build Coastguard Worker */
506*1c60b9acSAndroid Build Coastguard Worker
507*1c60b9acSAndroid Build Coastguard Worker if ((r->is.sa46[LWSDH_SA46_IP].sa4.sin_addr.s_addr &
508*1c60b9acSAndroid Build Coastguard Worker r->is.nums[LWSDH_IPV4_SUBNET_MASK]) !=
509*1c60b9acSAndroid Build Coastguard Worker (r->is.sa46[LWSDH_SA46_DHCP_SERVER].sa4.sin_addr.s_addr &
510*1c60b9acSAndroid Build Coastguard Worker r->is.nums[LWSDH_IPV4_SUBNET_MASK])) {
511*1c60b9acSAndroid Build Coastguard Worker lwsl_notice("%s: rejecting on srv %x reachable on mask %x\n",
512*1c60b9acSAndroid Build Coastguard Worker __func__, r->is.sa46[LWSDH_SA46_IP].sa4.sin_addr.s_addr,
513*1c60b9acSAndroid Build Coastguard Worker r->is.nums[LWSDH_IPV4_SUBNET_MASK]);
514*1c60b9acSAndroid Build Coastguard Worker break;
515*1c60b9acSAndroid Build Coastguard Worker }
516*1c60b9acSAndroid Build Coastguard Worker
517*1c60b9acSAndroid Build Coastguard Worker if (r->state == LDHC_INIT) {
518*1c60b9acSAndroid Build Coastguard Worker lwsl_info("%s: moving to REQ\n", __func__);
519*1c60b9acSAndroid Build Coastguard Worker r->state = LDHC_REQUESTING;
520*1c60b9acSAndroid Build Coastguard Worker lws_callback_on_writable(r->wsi_raw);
521*1c60b9acSAndroid Build Coastguard Worker //break;
522*1c60b9acSAndroid Build Coastguard Worker }
523*1c60b9acSAndroid Build Coastguard Worker
524*1c60b9acSAndroid Build Coastguard Worker return 0;
525*1c60b9acSAndroid Build Coastguard Worker
526*1c60b9acSAndroid Build Coastguard Worker default:
527*1c60b9acSAndroid Build Coastguard Worker break;
528*1c60b9acSAndroid Build Coastguard Worker }
529*1c60b9acSAndroid Build Coastguard Worker
530*1c60b9acSAndroid Build Coastguard Worker return 1;
531*1c60b9acSAndroid Build Coastguard Worker }
532*1c60b9acSAndroid Build Coastguard Worker
533