1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16#include <linux/netdevice.h>
17
18#include "brcmu_wifi.h"
19#include "brcmu_utils.h"
20
21#include "cfg80211.h"
22#include "core.h"
23#include "debug.h"
24#include "tracepoint.h"
25#include "fweh.h"
26#include "fwil.h"
27#include "proto.h"
28
29
30
31
32
33
34
35
36
37
38
39struct brcmf_fweh_queue_item {
40 struct list_head q;
41 enum brcmf_fweh_event_code code;
42 u8 ifidx;
43 u8 ifaddr[ETH_ALEN];
44 struct brcmf_event_msg_be emsg;
45 u32 datalen;
46 u8 data[0];
47};
48
49
50
51
52struct brcmf_fweh_event_name {
53 enum brcmf_fweh_event_code code;
54 const char *name;
55};
56
57#ifdef DEBUG
58#define BRCMF_ENUM_DEF(id, val) \
59 { val, #id },
60
61
62static struct brcmf_fweh_event_name fweh_event_names[] = {
63 BRCMF_FWEH_EVENT_ENUM_DEFLIST
64};
65#undef BRCMF_ENUM_DEF
66
67
68
69
70
71
72const char *brcmf_fweh_event_name(enum brcmf_fweh_event_code code)
73{
74 int i;
75 for (i = 0; i < ARRAY_SIZE(fweh_event_names); i++) {
76 if (fweh_event_names[i].code == code)
77 return fweh_event_names[i].name;
78 }
79 return "unknown";
80}
81#else
82const char *brcmf_fweh_event_name(enum brcmf_fweh_event_code code)
83{
84 return "nodebug";
85}
86#endif
87
88
89
90
91
92
93
94static void brcmf_fweh_queue_event(struct brcmf_fweh_info *fweh,
95 struct brcmf_fweh_queue_item *event)
96{
97 ulong flags;
98
99 spin_lock_irqsave(&fweh->evt_q_lock, flags);
100 list_add_tail(&event->q, &fweh->event_q);
101 spin_unlock_irqrestore(&fweh->evt_q_lock, flags);
102 schedule_work(&fweh->event_work);
103}
104
105static int brcmf_fweh_call_event_handler(struct brcmf_if *ifp,
106 enum brcmf_fweh_event_code code,
107 struct brcmf_event_msg *emsg,
108 void *data)
109{
110 struct brcmf_fweh_info *fweh;
111 int err = -EINVAL;
112
113 if (ifp) {
114 fweh = &ifp->drvr->fweh;
115
116
117 if (fweh->evt_handler[code])
118 err = fweh->evt_handler[code](ifp, emsg, data);
119 else
120 brcmf_err("unhandled event %d ignored\n", code);
121 } else {
122 brcmf_err("no interface object\n");
123 }
124 return err;
125}
126
127
128
129
130
131
132
133
134static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr,
135 struct brcmf_event_msg *emsg,
136 void *data)
137{
138 struct brcmf_if_event *ifevent = data;
139 struct brcmf_if *ifp;
140 bool is_p2pdev;
141 int err = 0;
142
143 brcmf_dbg(EVENT, "action: %u ifidx: %u bsscfgidx: %u flags: %u role: %u\n",
144 ifevent->action, ifevent->ifidx, ifevent->bsscfgidx,
145 ifevent->flags, ifevent->role);
146
147
148
149
150
151
152 is_p2pdev = ((ifevent->flags & BRCMF_E_IF_FLAG_NOIF) &&
153 (ifevent->role == BRCMF_E_IF_ROLE_P2P_CLIENT ||
154 ((ifevent->role == BRCMF_E_IF_ROLE_STA) &&
155 (drvr->fweh.p2pdev_setup_ongoing))));
156 if (!is_p2pdev && (ifevent->flags & BRCMF_E_IF_FLAG_NOIF)) {
157 brcmf_dbg(EVENT, "event can be ignored\n");
158 return;
159 }
160 if (ifevent->ifidx >= BRCMF_MAX_IFS) {
161 brcmf_err("invalid interface index: %u\n", ifevent->ifidx);
162 return;
163 }
164
165 ifp = drvr->iflist[ifevent->bsscfgidx];
166
167 if (ifevent->action == BRCMF_E_IF_ADD) {
168 brcmf_dbg(EVENT, "adding %s (%pM)\n", emsg->ifname,
169 emsg->addr);
170 ifp = brcmf_add_if(drvr, ifevent->bsscfgidx, ifevent->ifidx,
171 is_p2pdev, emsg->ifname, emsg->addr);
172 if (IS_ERR(ifp))
173 return;
174 if (!is_p2pdev)
175 brcmf_proto_add_if(drvr, ifp);
176 if (!drvr->fweh.evt_handler[BRCMF_E_IF])
177 if (brcmf_net_attach(ifp, false) < 0)
178 return;
179 }
180
181 if (ifp && ifevent->action == BRCMF_E_IF_CHANGE)
182 brcmf_proto_reset_if(drvr, ifp);
183
184 err = brcmf_fweh_call_event_handler(ifp, emsg->event_code, emsg, data);
185
186 if (ifp && ifevent->action == BRCMF_E_IF_DEL) {
187 bool armed = brcmf_cfg80211_vif_event_armed(drvr->config);
188
189
190 if (!armed)
191 brcmf_remove_interface(ifp, false);
192 }
193}
194
195
196
197
198
199
200static struct brcmf_fweh_queue_item *
201brcmf_fweh_dequeue_event(struct brcmf_fweh_info *fweh)
202{
203 struct brcmf_fweh_queue_item *event = NULL;
204 ulong flags;
205
206 spin_lock_irqsave(&fweh->evt_q_lock, flags);
207 if (!list_empty(&fweh->event_q)) {
208 event = list_first_entry(&fweh->event_q,
209 struct brcmf_fweh_queue_item, q);
210 list_del(&event->q);
211 }
212 spin_unlock_irqrestore(&fweh->evt_q_lock, flags);
213
214 return event;
215}
216
217
218
219
220
221
222static void brcmf_fweh_event_worker(struct work_struct *work)
223{
224 struct brcmf_pub *drvr;
225 struct brcmf_if *ifp;
226 struct brcmf_fweh_info *fweh;
227 struct brcmf_fweh_queue_item *event;
228 int err = 0;
229 struct brcmf_event_msg_be *emsg_be;
230 struct brcmf_event_msg emsg;
231
232 fweh = container_of(work, struct brcmf_fweh_info, event_work);
233 drvr = container_of(fweh, struct brcmf_pub, fweh);
234
235 while ((event = brcmf_fweh_dequeue_event(fweh))) {
236 brcmf_dbg(EVENT, "event %s (%u) ifidx %u bsscfg %u addr %pM\n",
237 brcmf_fweh_event_name(event->code), event->code,
238 event->emsg.ifidx, event->emsg.bsscfgidx,
239 event->emsg.addr);
240
241
242 emsg_be = &event->emsg;
243 emsg.version = be16_to_cpu(emsg_be->version);
244 emsg.flags = be16_to_cpu(emsg_be->flags);
245 emsg.event_code = event->code;
246 emsg.status = be32_to_cpu(emsg_be->status);
247 emsg.reason = be32_to_cpu(emsg_be->reason);
248 emsg.auth_type = be32_to_cpu(emsg_be->auth_type);
249 emsg.datalen = be32_to_cpu(emsg_be->datalen);
250 memcpy(emsg.addr, emsg_be->addr, ETH_ALEN);
251 memcpy(emsg.ifname, emsg_be->ifname, sizeof(emsg.ifname));
252 emsg.ifidx = emsg_be->ifidx;
253 emsg.bsscfgidx = emsg_be->bsscfgidx;
254
255 brcmf_dbg(EVENT, " version %u flags %u status %u reason %u\n",
256 emsg.version, emsg.flags, emsg.status, emsg.reason);
257 brcmf_dbg_hex_dump(BRCMF_EVENT_ON(), event->data,
258 min_t(u32, emsg.datalen, 64),
259 "event payload, len=%d\n", emsg.datalen);
260 if (emsg.datalen > event->datalen) {
261 brcmf_err("event invalid length header=%d, msg=%d\n",
262 event->datalen, emsg.datalen);
263 goto event_free;
264 }
265
266
267 if (event->code == BRCMF_E_IF) {
268 brcmf_fweh_handle_if_event(drvr, &emsg, event->data);
269 goto event_free;
270 }
271
272 if (event->code == BRCMF_E_TDLS_PEER_EVENT)
273 ifp = drvr->iflist[0];
274 else
275 ifp = drvr->iflist[emsg.bsscfgidx];
276 err = brcmf_fweh_call_event_handler(ifp, event->code, &emsg,
277 event->data);
278 if (err) {
279 brcmf_err("event handler failed (%d)\n",
280 event->code);
281 err = 0;
282 }
283event_free:
284 kfree(event);
285 }
286}
287
288
289
290
291
292
293
294void brcmf_fweh_p2pdev_setup(struct brcmf_if *ifp, bool ongoing)
295{
296 ifp->drvr->fweh.p2pdev_setup_ongoing = ongoing;
297}
298
299
300
301
302
303
304void brcmf_fweh_attach(struct brcmf_pub *drvr)
305{
306 struct brcmf_fweh_info *fweh = &drvr->fweh;
307 INIT_WORK(&fweh->event_work, brcmf_fweh_event_worker);
308 spin_lock_init(&fweh->evt_q_lock);
309 INIT_LIST_HEAD(&fweh->event_q);
310}
311
312
313
314
315
316
317void brcmf_fweh_detach(struct brcmf_pub *drvr)
318{
319 struct brcmf_fweh_info *fweh = &drvr->fweh;
320 struct brcmf_if *ifp = brcmf_get_ifp(drvr, 0);
321 s8 eventmask[BRCMF_EVENTING_MASK_LEN];
322
323 if (ifp) {
324
325 memset(eventmask, 0, BRCMF_EVENTING_MASK_LEN);
326 (void)brcmf_fil_iovar_data_set(ifp, "event_msgs",
327 eventmask,
328 BRCMF_EVENTING_MASK_LEN);
329 }
330
331 cancel_work_sync(&fweh->event_work);
332 WARN_ON(!list_empty(&fweh->event_q));
333 memset(fweh->evt_handler, 0, sizeof(fweh->evt_handler));
334}
335
336
337
338
339
340
341
342
343int brcmf_fweh_register(struct brcmf_pub *drvr, enum brcmf_fweh_event_code code,
344 brcmf_fweh_handler_t handler)
345{
346 if (drvr->fweh.evt_handler[code]) {
347 brcmf_err("event code %d already registered\n", code);
348 return -ENOSPC;
349 }
350 drvr->fweh.evt_handler[code] = handler;
351 brcmf_dbg(TRACE, "event handler registered for %s\n",
352 brcmf_fweh_event_name(code));
353 return 0;
354}
355
356
357
358
359
360
361
362void brcmf_fweh_unregister(struct brcmf_pub *drvr,
363 enum brcmf_fweh_event_code code)
364{
365 brcmf_dbg(TRACE, "event handler cleared for %s\n",
366 brcmf_fweh_event_name(code));
367 drvr->fweh.evt_handler[code] = NULL;
368}
369
370
371
372
373
374
375int brcmf_fweh_activate_events(struct brcmf_if *ifp)
376{
377 int i, err;
378 s8 eventmask[BRCMF_EVENTING_MASK_LEN];
379
380 memset(eventmask, 0, sizeof(eventmask));
381 for (i = 0; i < BRCMF_E_LAST; i++) {
382 if (ifp->drvr->fweh.evt_handler[i]) {
383 brcmf_dbg(EVENT, "enable event %s\n",
384 brcmf_fweh_event_name(i));
385 setbit(eventmask, i);
386 }
387 }
388
389
390 brcmf_dbg(EVENT, "enable event IF\n");
391 setbit(eventmask, BRCMF_E_IF);
392
393 err = brcmf_fil_iovar_data_set(ifp, "event_msgs",
394 eventmask, BRCMF_EVENTING_MASK_LEN);
395 if (err)
396 brcmf_err("Set event_msgs error (%d)\n", err);
397
398 return err;
399}
400
401
402
403
404
405
406
407
408
409
410void brcmf_fweh_process_event(struct brcmf_pub *drvr,
411 struct brcmf_event *event_packet,
412 u32 packet_len)
413{
414 enum brcmf_fweh_event_code code;
415 struct brcmf_fweh_info *fweh = &drvr->fweh;
416 struct brcmf_fweh_queue_item *event;
417 gfp_t alloc_flag = GFP_KERNEL;
418 void *data;
419 u32 datalen;
420
421
422 code = get_unaligned_be32(&event_packet->msg.event_type);
423 datalen = get_unaligned_be32(&event_packet->msg.datalen);
424 data = &event_packet[1];
425
426 if (code >= BRCMF_E_LAST)
427 return;
428
429 if (code != BRCMF_E_IF && !fweh->evt_handler[code])
430 return;
431
432 if (datalen > BRCMF_DCMD_MAXLEN ||
433 datalen + sizeof(*event_packet) > packet_len)
434 return;
435
436 if (in_interrupt())
437 alloc_flag = GFP_ATOMIC;
438
439 event = kzalloc(sizeof(*event) + datalen, alloc_flag);
440 if (!event)
441 return;
442
443 event->code = code;
444 event->ifidx = event_packet->msg.ifidx;
445
446
447 memcpy(&event->emsg, &event_packet->msg, sizeof(event->emsg));
448 memcpy(event->data, data, datalen);
449 event->datalen = datalen;
450 memcpy(event->ifaddr, event_packet->eth.h_dest, ETH_ALEN);
451
452 brcmf_fweh_queue_event(fweh, event);
453}
454