1/*
2 * libwebsockets - small server side websockets and web server implementation
3 *
4 * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to
8 * deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 * IN THE SOFTWARE.
23 */
24
25#include <private-lib-core.h>
26
27static const lws_struct_map_t lsm_wifi_creds[] = {
28	LSM_CARRAY	(lws_wifi_creds_t, ssid,		"ssid"),
29	LSM_CARRAY	(lws_wifi_creds_t, passphrase,		"passphrase"),
30	LSM_UNSIGNED	(lws_wifi_creds_t, alg,			"alg"),
31	LSM_STRING_PTR	(lws_wifi_creds_t, bssid,		"bssid"),
32};
33
34static const lws_struct_map_t lsm_netdev_credentials[] = {
35	LSM_LIST	(lws_netdevs_t, owner_creds, lws_wifi_creds_t, list,
36			 NULL, lsm_wifi_creds,			"credentials"),
37};
38
39static const lws_struct_map_t lsm_netdev_schema[] = {
40        LSM_SCHEMA      (lws_netdevs_t, NULL, lsm_netdev_credentials,
41                                              "lws-netdev-creds"),
42};
43
44
45//LSM_CHILD_PTR	(lws_netdev_instance_wifi_t, ap_cred, lws_wifi_creds_t,
46//		 NULL, lsm_wifi_creds,			"ap_cred"),
47//LSM_STRING_PTR	(lws_netdev_instance_wifi_t, ap_ip,	"ap_ip"),
48
49int
50lws_netdev_credentials_settings_set(lws_netdevs_t *nds)
51{
52	lws_struct_serialize_t *js;
53	size_t w = 0, max = 2048;
54	int n, r = 1;
55	uint8_t *buf;
56
57	buf = lws_malloc(max, __func__); /* length should be computed */
58
59	js = lws_struct_json_serialize_create(lsm_netdev_schema,
60			LWS_ARRAY_SIZE(lsm_netdev_schema), 0, nds);
61	if (!js)
62		goto bail;
63
64	n = lws_struct_json_serialize(js, buf, max, &w);
65	lws_struct_json_serialize_destroy(&js);
66	if (n != LSJS_RESULT_FINISH)
67		goto bail;
68
69	lwsl_notice("%s: setting %s\n", __func__, buf);
70
71	if (!lws_settings_plat_set(nds->si, "netdev.creds", buf, w))
72		r = 0;
73
74bail:
75	if (r)
76		lwsl_err("%s: failed\n", __func__);
77	lws_free(buf);
78
79	return r;
80}
81
82int
83lws_netdev_credentials_settings_get(lws_netdevs_t *nds)
84{
85	struct lejp_ctx ctx;
86	lws_struct_args_t a;
87	size_t l = 0;
88	uint8_t *buf;
89	int m;
90
91	memset(&a, 0, sizeof(a));
92
93	if (lws_settings_plat_get(nds->si, "netdev.creds", NULL, &l)) {
94		lwsl_notice("%s: not in settings\n", __func__);
95		return 1;
96	}
97
98	buf = lws_malloc(l, __func__);
99	if (!buf)
100		return 1;
101
102	if (lws_settings_plat_get(nds->si, "netdev.creds", buf, &l)) {
103		lwsl_err("%s: unexpected settings get fail\n", __func__);
104		goto bail;
105	}
106
107	a.map_st[0] = lsm_netdev_schema;
108	a.map_entries_st[0] = LWS_ARRAY_SIZE(lsm_netdev_schema);
109	a.ac_block_size = 512;
110
111	lws_struct_json_init_parse(&ctx, NULL, &a);
112	m = lejp_parse(&ctx, (uint8_t *)buf, l);
113	lws_free(buf);
114	if (m < 0 || !a.dest) {
115		lwsl_notice("%s: JSON decode failed '%s'\n",
116			    __func__, lejp_error_to_string(m));
117		goto bail1;
118	}
119
120	/*
121	 * Forcibly set the state of the nds creds owner to the synthesized
122	 * one in the ac, and keep the ac for as long as we keep the creds out
123	 */
124	nds->owner_creds = ((lws_netdevs_t *)a.dest)->owner_creds;
125	nds->ac_creds = a.ac;
126
127	return 0;
128
129bail:
130	lws_free(buf);
131bail1:
132	lwsac_free(&a.ac);
133
134	return 1;
135}
136
137lws_wifi_creds_t *
138lws_netdev_credentials_find(lws_netdevs_t *netdevs, const char *ssid,
139			    const uint8_t *bssid)
140{
141	lws_start_foreach_dll(struct lws_dll2 *, p, lws_dll2_get_head(
142	                                               &netdevs->owner_creds)) {
143		lws_wifi_creds_t *w = lws_container_of(p, lws_wifi_creds_t, list);
144
145		if (!strcmp(ssid, (const char *)&w[1]) &&
146		    !memcmp(bssid, w->bssid, 6))
147			return w;
148
149	} lws_end_foreach_dll(p);
150
151	return NULL;
152}
153
154lws_netdev_instance_t *
155lws_netdev_find(lws_netdevs_t *netdevs, const char *ifname)
156{
157	lws_start_foreach_dll(struct lws_dll2 *, p, lws_dll2_get_head(
158	                                               &netdevs->owner)) {
159		lws_netdev_instance_t *ni = lws_container_of(p,
160						lws_netdev_instance_t, list);
161
162		if (!strcmp(ifname, ni->name))
163			return ni;
164
165	} lws_end_foreach_dll(p);
166
167	return NULL;
168}
169
170/*
171 * Context forwards NETWORK related smd here, in lws thread context
172 */
173
174int
175lws_netdev_smd_cb(void *opaque, lws_smd_class_t _class, lws_usec_t timestamp,
176		  void *buf, size_t len)
177{
178	struct lws_context *ctx = (struct lws_context *)opaque;
179	const char *iface;
180	char setname[16];
181	size_t al = 0;
182
183	/* deal with anything from whole-network perspective */
184
185	/* pass through netdev-specific messages to correct platform handler */
186
187	iface = lws_json_simple_find(buf, len, "\"if\":", &al);
188	if (!iface)
189		return 0;
190
191	lws_start_foreach_dll(struct lws_dll2 *, p, lws_dll2_get_head(
192	                                                 &ctx->netdevs.owner)) {
193		lws_netdev_instance_t *ni = lws_container_of(
194						p, lws_netdev_instance_t, list);
195
196		if (!strncmp(ni->name, iface, al)) {
197
198			/*
199			 * IP assignment on our netif?  We can deal with marking
200			 * the last successful association generically...
201			 */
202
203			if (ni->type == LWSNDTYP_WIFI &&
204			    !lws_json_simple_strcmp(buf, len, "\"type\":",
205							"ipacq")) {
206				const char *ev = lws_json_simple_find(buf, len,
207							"\"ipv4\":", &al);
208				lws_netdev_instance_wifi_t *wnd =
209					       (lws_netdev_instance_wifi_t *)ni;
210
211				if (!ev)
212					return 0;
213
214				lws_snprintf(setname, sizeof(setname),
215						"netdev.last.%s", iface);
216
217				lws_settings_plat_printf(ctx->netdevs.si,
218					setname, "{\"ssid\":\"%s\",\"bssid\":"
219					"\"%02X%02X%02X%02X%02X%02X\"}",
220					wnd->current_attempt_ssid,
221					wnd->current_attempt_bssid[0],
222					wnd->current_attempt_bssid[1],
223					wnd->current_attempt_bssid[2],
224					wnd->current_attempt_bssid[3],
225					wnd->current_attempt_bssid[4],
226					wnd->current_attempt_bssid[5]);
227			}
228
229			/*
230			 * Pass it through to related netdev instance for
231			 * private actions
232			 */
233
234			return ni->ops->event(ni, timestamp, buf, len);
235		}
236
237	} lws_end_foreach_dll(p);
238
239	return 0;
240}
241
242/*
243 * This is the generic part of the netdev instance initialization that's always
244 * the same, regardless of the netdev type
245 */
246
247void
248lws_netdev_instance_create(lws_netdev_instance_t *ni, struct lws_context *ctx,
249			   const lws_netdev_ops_t *ops, const char *name,
250			   void *platinfo)
251{
252	ni->ops		= ops;
253	ni->name	= name;
254	ni->platinfo	= platinfo;
255
256	/* add us to the list of active netdevs */
257
258	lws_dll2_add_tail(&ni->list, &ctx->netdevs.owner);
259}
260
261void
262lws_netdev_instance_remove_destroy(struct lws_netdev_instance *ni)
263{
264	lws_dll2_remove(&ni->list);
265	lws_free(ni);
266}
267
268lws_netdevs_t *
269lws_netdevs_from_ctx(struct lws_context *ctx)
270{
271	return &ctx->netdevs;
272}
273