0001
0002
0003
0004
0005 #include <linux/netdevice.h>
0006
0007 #include "brcmu_wifi.h"
0008 #include "brcmu_utils.h"
0009
0010 #include "cfg80211.h"
0011 #include "core.h"
0012 #include "debug.h"
0013 #include "tracepoint.h"
0014 #include "fweh.h"
0015 #include "fwil.h"
0016 #include "proto.h"
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029 struct brcmf_fweh_queue_item {
0030 struct list_head q;
0031 enum brcmf_fweh_event_code code;
0032 u8 ifidx;
0033 u8 ifaddr[ETH_ALEN];
0034 struct brcmf_event_msg_be emsg;
0035 u32 datalen;
0036 u8 data[];
0037 };
0038
0039
0040
0041
0042 struct brcmf_fweh_event_name {
0043 enum brcmf_fweh_event_code code;
0044 const char *name;
0045 };
0046
0047 #ifdef DEBUG
0048 #define BRCMF_ENUM_DEF(id, val) \
0049 { val, #id },
0050
0051
0052 static struct brcmf_fweh_event_name fweh_event_names[] = {
0053 BRCMF_FWEH_EVENT_ENUM_DEFLIST
0054 };
0055 #undef BRCMF_ENUM_DEF
0056
0057
0058
0059
0060
0061
0062 const char *brcmf_fweh_event_name(enum brcmf_fweh_event_code code)
0063 {
0064 int i;
0065 for (i = 0; i < ARRAY_SIZE(fweh_event_names); i++) {
0066 if (fweh_event_names[i].code == code)
0067 return fweh_event_names[i].name;
0068 }
0069 return "unknown";
0070 }
0071 #else
0072 const char *brcmf_fweh_event_name(enum brcmf_fweh_event_code code)
0073 {
0074 return "nodebug";
0075 }
0076 #endif
0077
0078
0079
0080
0081
0082
0083
0084 static void brcmf_fweh_queue_event(struct brcmf_fweh_info *fweh,
0085 struct brcmf_fweh_queue_item *event)
0086 {
0087 ulong flags;
0088
0089 spin_lock_irqsave(&fweh->evt_q_lock, flags);
0090 list_add_tail(&event->q, &fweh->event_q);
0091 spin_unlock_irqrestore(&fweh->evt_q_lock, flags);
0092 schedule_work(&fweh->event_work);
0093 }
0094
0095 static int brcmf_fweh_call_event_handler(struct brcmf_pub *drvr,
0096 struct brcmf_if *ifp,
0097 enum brcmf_fweh_event_code code,
0098 struct brcmf_event_msg *emsg,
0099 void *data)
0100 {
0101 struct brcmf_fweh_info *fweh;
0102 int err = -EINVAL;
0103
0104 if (ifp) {
0105 fweh = &ifp->drvr->fweh;
0106
0107
0108 if (fweh->evt_handler[code])
0109 err = fweh->evt_handler[code](ifp, emsg, data);
0110 else
0111 bphy_err(drvr, "unhandled event %d ignored\n", code);
0112 } else {
0113 bphy_err(drvr, "no interface object\n");
0114 }
0115 return err;
0116 }
0117
0118
0119
0120
0121
0122
0123
0124
0125 static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr,
0126 struct brcmf_event_msg *emsg,
0127 void *data)
0128 {
0129 struct brcmf_if_event *ifevent = data;
0130 struct brcmf_if *ifp;
0131 bool is_p2pdev;
0132
0133 brcmf_dbg(EVENT, "action: %u ifidx: %u bsscfgidx: %u flags: %u role: %u\n",
0134 ifevent->action, ifevent->ifidx, ifevent->bsscfgidx,
0135 ifevent->flags, ifevent->role);
0136
0137
0138
0139
0140
0141
0142 is_p2pdev = ((ifevent->flags & BRCMF_E_IF_FLAG_NOIF) &&
0143 (ifevent->role == BRCMF_E_IF_ROLE_P2P_CLIENT ||
0144 ((ifevent->role == BRCMF_E_IF_ROLE_STA) &&
0145 (drvr->fweh.p2pdev_setup_ongoing))));
0146 if (!is_p2pdev && (ifevent->flags & BRCMF_E_IF_FLAG_NOIF)) {
0147 brcmf_dbg(EVENT, "event can be ignored\n");
0148 return;
0149 }
0150 if (ifevent->ifidx >= BRCMF_MAX_IFS) {
0151 bphy_err(drvr, "invalid interface index: %u\n", ifevent->ifidx);
0152 return;
0153 }
0154
0155 ifp = drvr->iflist[ifevent->bsscfgidx];
0156
0157 if (ifevent->action == BRCMF_E_IF_ADD) {
0158 brcmf_dbg(EVENT, "adding %s (%pM)\n", emsg->ifname,
0159 emsg->addr);
0160 ifp = brcmf_add_if(drvr, ifevent->bsscfgidx, ifevent->ifidx,
0161 is_p2pdev, emsg->ifname, emsg->addr);
0162 if (IS_ERR(ifp))
0163 return;
0164 if (!is_p2pdev)
0165 brcmf_proto_add_if(drvr, ifp);
0166 if (!drvr->fweh.evt_handler[BRCMF_E_IF])
0167 if (brcmf_net_attach(ifp, false) < 0)
0168 return;
0169 }
0170
0171 if (ifp && ifevent->action == BRCMF_E_IF_CHANGE)
0172 brcmf_proto_reset_if(drvr, ifp);
0173
0174 brcmf_fweh_call_event_handler(drvr, ifp, emsg->event_code, emsg,
0175 data);
0176
0177 if (ifp && ifevent->action == BRCMF_E_IF_DEL) {
0178 bool armed = brcmf_cfg80211_vif_event_armed(drvr->config);
0179
0180
0181 if (!armed)
0182 brcmf_remove_interface(ifp, false);
0183 }
0184 }
0185
0186
0187
0188
0189
0190
0191 static struct brcmf_fweh_queue_item *
0192 brcmf_fweh_dequeue_event(struct brcmf_fweh_info *fweh)
0193 {
0194 struct brcmf_fweh_queue_item *event = NULL;
0195 ulong flags;
0196
0197 spin_lock_irqsave(&fweh->evt_q_lock, flags);
0198 if (!list_empty(&fweh->event_q)) {
0199 event = list_first_entry(&fweh->event_q,
0200 struct brcmf_fweh_queue_item, q);
0201 list_del(&event->q);
0202 }
0203 spin_unlock_irqrestore(&fweh->evt_q_lock, flags);
0204
0205 return event;
0206 }
0207
0208
0209
0210
0211
0212
0213 static void brcmf_fweh_event_worker(struct work_struct *work)
0214 {
0215 struct brcmf_pub *drvr;
0216 struct brcmf_if *ifp;
0217 struct brcmf_fweh_info *fweh;
0218 struct brcmf_fweh_queue_item *event;
0219 int err = 0;
0220 struct brcmf_event_msg_be *emsg_be;
0221 struct brcmf_event_msg emsg;
0222
0223 fweh = container_of(work, struct brcmf_fweh_info, event_work);
0224 drvr = container_of(fweh, struct brcmf_pub, fweh);
0225
0226 while ((event = brcmf_fweh_dequeue_event(fweh))) {
0227 brcmf_dbg(EVENT, "event %s (%u) ifidx %u bsscfg %u addr %pM\n",
0228 brcmf_fweh_event_name(event->code), event->code,
0229 event->emsg.ifidx, event->emsg.bsscfgidx,
0230 event->emsg.addr);
0231
0232
0233 emsg_be = &event->emsg;
0234 emsg.version = be16_to_cpu(emsg_be->version);
0235 emsg.flags = be16_to_cpu(emsg_be->flags);
0236 emsg.event_code = event->code;
0237 emsg.status = be32_to_cpu(emsg_be->status);
0238 emsg.reason = be32_to_cpu(emsg_be->reason);
0239 emsg.auth_type = be32_to_cpu(emsg_be->auth_type);
0240 emsg.datalen = be32_to_cpu(emsg_be->datalen);
0241 memcpy(emsg.addr, emsg_be->addr, ETH_ALEN);
0242 memcpy(emsg.ifname, emsg_be->ifname, sizeof(emsg.ifname));
0243 emsg.ifidx = emsg_be->ifidx;
0244 emsg.bsscfgidx = emsg_be->bsscfgidx;
0245
0246 brcmf_dbg(EVENT, " version %u flags %u status %u reason %u\n",
0247 emsg.version, emsg.flags, emsg.status, emsg.reason);
0248 brcmf_dbg_hex_dump(BRCMF_EVENT_ON(), event->data,
0249 min_t(u32, emsg.datalen, 64),
0250 "event payload, len=%d\n", emsg.datalen);
0251
0252
0253 if (event->code == BRCMF_E_IF) {
0254 brcmf_fweh_handle_if_event(drvr, &emsg, event->data);
0255 goto event_free;
0256 }
0257
0258 if (event->code == BRCMF_E_TDLS_PEER_EVENT)
0259 ifp = drvr->iflist[0];
0260 else
0261 ifp = drvr->iflist[emsg.bsscfgidx];
0262 err = brcmf_fweh_call_event_handler(drvr, ifp, event->code,
0263 &emsg, event->data);
0264 if (err) {
0265 bphy_err(drvr, "event handler failed (%d)\n",
0266 event->code);
0267 err = 0;
0268 }
0269 event_free:
0270 kfree(event);
0271 }
0272 }
0273
0274
0275
0276
0277
0278
0279
0280 void brcmf_fweh_p2pdev_setup(struct brcmf_if *ifp, bool ongoing)
0281 {
0282 ifp->drvr->fweh.p2pdev_setup_ongoing = ongoing;
0283 }
0284
0285
0286
0287
0288
0289
0290 void brcmf_fweh_attach(struct brcmf_pub *drvr)
0291 {
0292 struct brcmf_fweh_info *fweh = &drvr->fweh;
0293 INIT_WORK(&fweh->event_work, brcmf_fweh_event_worker);
0294 spin_lock_init(&fweh->evt_q_lock);
0295 INIT_LIST_HEAD(&fweh->event_q);
0296 }
0297
0298
0299
0300
0301
0302
0303 void brcmf_fweh_detach(struct brcmf_pub *drvr)
0304 {
0305 struct brcmf_fweh_info *fweh = &drvr->fweh;
0306
0307
0308 if (fweh->event_work.func) {
0309 cancel_work_sync(&fweh->event_work);
0310 WARN_ON(!list_empty(&fweh->event_q));
0311 memset(fweh->evt_handler, 0, sizeof(fweh->evt_handler));
0312 }
0313 }
0314
0315
0316
0317
0318
0319
0320
0321
0322 int brcmf_fweh_register(struct brcmf_pub *drvr, enum brcmf_fweh_event_code code,
0323 brcmf_fweh_handler_t handler)
0324 {
0325 if (drvr->fweh.evt_handler[code]) {
0326 bphy_err(drvr, "event code %d already registered\n", code);
0327 return -ENOSPC;
0328 }
0329 drvr->fweh.evt_handler[code] = handler;
0330 brcmf_dbg(TRACE, "event handler registered for %s\n",
0331 brcmf_fweh_event_name(code));
0332 return 0;
0333 }
0334
0335
0336
0337
0338
0339
0340
0341 void brcmf_fweh_unregister(struct brcmf_pub *drvr,
0342 enum brcmf_fweh_event_code code)
0343 {
0344 brcmf_dbg(TRACE, "event handler cleared for %s\n",
0345 brcmf_fweh_event_name(code));
0346 drvr->fweh.evt_handler[code] = NULL;
0347 }
0348
0349
0350
0351
0352
0353
0354 int brcmf_fweh_activate_events(struct brcmf_if *ifp)
0355 {
0356 struct brcmf_pub *drvr = ifp->drvr;
0357 int i, err;
0358 s8 eventmask[BRCMF_EVENTING_MASK_LEN];
0359
0360 memset(eventmask, 0, sizeof(eventmask));
0361 for (i = 0; i < BRCMF_E_LAST; i++) {
0362 if (ifp->drvr->fweh.evt_handler[i]) {
0363 brcmf_dbg(EVENT, "enable event %s\n",
0364 brcmf_fweh_event_name(i));
0365 setbit(eventmask, i);
0366 }
0367 }
0368
0369
0370 brcmf_dbg(EVENT, "enable event IF\n");
0371 setbit(eventmask, BRCMF_E_IF);
0372
0373 err = brcmf_fil_iovar_data_set(ifp, "event_msgs",
0374 eventmask, BRCMF_EVENTING_MASK_LEN);
0375 if (err)
0376 bphy_err(drvr, "Set event_msgs error (%d)\n", err);
0377
0378 return err;
0379 }
0380
0381
0382
0383
0384
0385
0386
0387
0388
0389
0390
0391
0392 void brcmf_fweh_process_event(struct brcmf_pub *drvr,
0393 struct brcmf_event *event_packet,
0394 u32 packet_len, gfp_t gfp)
0395 {
0396 enum brcmf_fweh_event_code code;
0397 struct brcmf_fweh_info *fweh = &drvr->fweh;
0398 struct brcmf_fweh_queue_item *event;
0399 void *data;
0400 u32 datalen;
0401
0402
0403 code = get_unaligned_be32(&event_packet->msg.event_type);
0404 datalen = get_unaligned_be32(&event_packet->msg.datalen);
0405 data = &event_packet[1];
0406
0407 if (code >= BRCMF_E_LAST)
0408 return;
0409
0410 if (code != BRCMF_E_IF && !fweh->evt_handler[code])
0411 return;
0412
0413 if (datalen > BRCMF_DCMD_MAXLEN ||
0414 datalen + sizeof(*event_packet) > packet_len)
0415 return;
0416
0417 event = kzalloc(sizeof(*event) + datalen, gfp);
0418 if (!event)
0419 return;
0420
0421 event->code = code;
0422 event->ifidx = event_packet->msg.ifidx;
0423
0424
0425 memcpy(&event->emsg, &event_packet->msg, sizeof(event->emsg));
0426 memcpy(event->data, data, datalen);
0427 event->datalen = datalen;
0428 memcpy(event->ifaddr, event_packet->eth.h_dest, ETH_ALEN);
0429
0430 brcmf_fweh_queue_event(fweh, event);
0431 }