• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #ifdef WL_EXT_GENL
2 #include <bcmendian.h>
3 #include <wl_android.h>
4 #include <dhd_config.h>
5 #include <net/genetlink.h>
6 
7 #define AGENL_ERROR(name, arg1, args...)                                       \
8     do {                                                                       \
9         if (android_msg_level & ANDROID_ERROR_LEVEL) {                         \
10             printk(KERN_ERR DHD_LOG_PREFIX "[%s] AGENL-ERROR) %s : " arg1,     \
11                    name, __func__, ##args);                                    \
12         }                                                                      \
13     } while (0)
14 #define AGENL_TRACE(name, arg1, args...)                                       \
15     do {                                                                       \
16         if (android_msg_level & ANDROID_TRACE_LEVEL) {                         \
17             printk(KERN_INFO DHD_LOG_PREFIX "[%s] AGENL-TRACE) %s : " arg1,    \
18                    name, __func__, ##args);                                    \
19         }                                                                      \
20     } while (0)
21 #define AGENL_INFO(name, arg1, args...)                                        \
22     do {                                                                       \
23         if (android_msg_level & ANDROID_INFO_LEVEL) {                          \
24             printk(KERN_INFO DHD_LOG_PREFIX "[%s] AGENL-INFO) %s : " arg1,     \
25                    name, __func__, ##args);                                    \
26         }                                                                      \
27     } while (0)
28 
29 #define htod32(i) i
30 #define htod16(i) i
31 #define dtoh32(i) i
32 #define dtoh16(i) i
33 
34 #ifdef SENDPROB
35 #define MGMT_PROBE_REQ 0x40
36 #define MGMT_PROBE_RES 0x50
37 #endif
38 
39 enum {
40     __GENL_CUSTOM_ATTR_INVALID,
41     GENL_CUSTOM_ATTR_MSG, /* message */
42     __GENL_CUSTOM_ATTR_MAX,
43 };
44 
45 enum {
46     __GENLL_CUSTOM_COMMAND_INVALID,
47     GENL_CUSTOM_COMMAND_BIND, /* bind */
48     GENL_CUSTOM_COMMAND_SEND, /* user -> kernel */
49     GENL_CUSTOM_COMMAND_RECV, /* kernel -> user */
50     __GENL_CUSTOM_COMMAND_MAX,
51 };
52 
53 #if defined(ALIBABA_ZEROCONFIG)
54 #define GENL_FAMILY_NAME "WIFI_NL_CUSTOM"
55 #define PROBE_RSP_DST_MAC_OFFSET 4
56 #define PROBE_RSP_VNDR_ID_OFFSET 55
57 #else
58 #define GENL_FAMILY_NAME "WLAN_NL_CUSTOM"
59 #define PROBE_RSP_DST_MAC_OFFSET 4
60 #define PROBE_RSP_VNDR_ID_OFFSET DOT11_MGMT_HDR_LEN
61 #endif
62 #define PROBE_RSP_VNDR_LEN_OFFSET (PROBE_RSP_VNDR_ID_OFFSET + 1)
63 #define PROBE_RSP_VNDR_OUI_OFFSET (PROBE_RSP_VNDR_ID_OFFSET + 2)
64 #define MAX_CUSTOM_PKT_LENGTH 2048
65 #define GENL_CUSTOM_ATTR_MAX (__GENL_CUSTOM_ATTR_MAX - 1)
66 #define GENLMSG_UNICAST_RETRY_LIMIT 5
67 
68 typedef struct genl_params {
69     struct net_device *dev;
70     bool bind;
71     int pm;
72     int bind_pid;
73     int send_retry_cnt;
74 } genl_params_t;
75 
76 struct genl_params *g_zconf = NULL;
77 
78 static int wl_ext_genl_bind(struct sk_buff *skb, struct genl_info *info);
79 static int wl_ext_genl_recv(struct sk_buff *skb, struct genl_info *info);
80 static int wl_ext_genl_send(struct genl_params *zconf, struct net_device *dev,
81                             char *buf, int buf_len);
82 
83 static struct nla_policy wl_ext_genl_policy[GENL_CUSTOM_ATTR_MAX + 1] = {
84     [GENL_CUSTOM_ATTR_MSG] = {.type = NLA_NUL_STRING},
85 };
86 
87 static struct genl_ops wl_ext_genl_ops[] = {
88     {
89         .cmd = GENL_CUSTOM_COMMAND_BIND,
90         .flags = 0,
91         .policy = wl_ext_genl_policy,
92         .doit = wl_ext_genl_bind,
93         .dumpit = NULL,
94     },
95     {
96         .cmd = GENL_CUSTOM_COMMAND_SEND,
97         .flags = 0,
98         .policy = wl_ext_genl_policy,
99         .doit = wl_ext_genl_recv,
100         .dumpit = NULL,
101     },
102 };
103 
104 static struct genl_family wl_ext_genl_family = {
105     .id = GENL_ID_GENERATE,
106     .hdrsize = 0,
107     .name = GENL_FAMILY_NAME,
108     .version = 1,
109     .maxattr = GENL_CUSTOM_ATTR_MAX,
110 };
111 
112 #ifdef SENDPROB
wl_ext_add_del_ie_hex(struct net_device * dev,uint pktflag,char * ie_data,int ie_len,const char * add_del_cmd)113 static int wl_ext_add_del_ie_hex(struct net_device *dev, uint pktflag,
114                                  char *ie_data, int ie_len,
115                                  const char *add_del_cmd)
116 {
117     vndr_ie_setbuf_t *vndr_ie = NULL;
118     char iovar_buf[WLC_IOCTL_SMLEN] = "\0";
119     int tot_len = 0, iecount;
120     int err = -1;
121 
122     if (!ie_len) {
123         AGENL_ERROR(dev->name, "wrong ie_len %d\n", ie_len);
124         goto exit;
125     }
126 
127     tot_len = (int)(sizeof(vndr_ie_setbuf_t) + (ie_len));
128     vndr_ie = (vndr_ie_setbuf_t *)kzalloc(tot_len, GFP_KERNEL);
129     if (!vndr_ie) {
130         AGENL_ERROR(dev->name, "IE memory alloc failed\n");
131         err = -ENOMEM;
132         goto exit;
133     }
134 
135     /* Copy the vndr_ie SET command ("add"/"del") to the buffer */
136     strncpy(vndr_ie->cmd, add_del_cmd, VNDR_IE_CMD_LEN - 1);
137     vndr_ie->cmd[VNDR_IE_CMD_LEN - 1] = '\0';
138 
139     /* Set the IE count - the buffer contains only 1 IE */
140     iecount = htod32(1);
141     memcpy((void *)&vndr_ie->vndr_ie_buffer.iecount, &iecount, sizeof(s32));
142 
143     /* Set packet flag to indicate that BEACON's will contain this IE */
144     pktflag = htod32(pktflag);
145     memcpy((void *)&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].pktflag, &pktflag,
146            sizeof(u32));
147 
148     /* Set the IE ID */
149     vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.id =
150         (uchar)DOT11_MNG_VS_ID;
151 
152     /* Set the IE LEN */
153     vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.len = ie_len;
154 
155     /* Set the IE OUI and DATA */
156     memcpy((char *)vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui,
157            ie_data, ie_len);
158 
159     err = wldev_iovar_setbuf(dev, "vndr_ie", vndr_ie, tot_len, iovar_buf,
160                              sizeof(iovar_buf), NULL);
161     if (err != 0) {
162         AGENL_ERROR(dev->name, "vndr_ie, ret=%d\n", err);
163     }
164 
165 exit:
166     if (vndr_ie) {
167         kfree(vndr_ie);
168     }
169     return err;
170 }
171 
wl_ext_send_probersp(struct net_device * dev,char * buf,int buf_len)172 static int wl_ext_send_probersp(struct net_device *dev, char *buf, int buf_len)
173 {
174     char addr[ETHER_ADDR_LEN], *pVndrOUI;
175     char iovar_buf[WLC_IOCTL_SMLEN] = "\0";
176     int err = -1, ie_len;
177 
178     if (buf == NULL || buf_len <= 0) {
179         AGENL_ERROR(dev->name, "buf is NULL or buf_len <= 0\n");
180         return -1;
181     }
182 
183     AGENL_TRACE(dev->name, "Enter\n");
184 
185     memcpy(addr, (buf + PROBE_RSP_DST_MAC_OFFSET), ETHER_ADDR_LEN);
186     pVndrOUI = (buf + PROBE_RSP_VNDR_OUI_OFFSET);
187     ie_len = *(buf + PROBE_RSP_VNDR_LEN_OFFSET);
188 
189     if (ie_len > (buf_len - PROBE_RSP_VNDR_OUI_OFFSET)) {
190         AGENL_ERROR(dev->name, "wrong vendor ie len %d\n", ie_len);
191         return -1;
192     }
193 
194     err = wl_ext_add_del_ie_hex(dev, VNDR_IE_PRBRSP_FLAG, pVndrOUI, ie_len,
195                                 "add");
196     if (err) {
197         goto exit;
198     }
199 
200     err = wldev_iovar_setbuf(dev, "send_probresp", addr, ETHER_ADDR_LEN,
201                              iovar_buf, sizeof(iovar_buf), NULL);
202     if (err != 0) {
203         AGENL_ERROR(dev->name, "vndr_ie, ret=%d\n", err);
204     }
205 
206     OSL_SLEEP(0x64);
207     wl_ext_add_del_ie_hex(dev, VNDR_IE_PRBRSP_FLAG, pVndrOUI, ie_len, "del");
208 
209 exit:
210     return err;
211 }
212 
wl_ext_set_probreq(struct net_device * dev,bool set)213 static int wl_ext_set_probreq(struct net_device *dev, bool set)
214 {
215     int bytes_written = 0;
216     char recv_probreq[32];
217 
218     AGENL_TRACE(dev->name, "Enter\n");
219 
220     if (set) {
221         sprintf(recv_probreq, "wl recv_probreq 1");
222         wl_android_ext_priv_cmd(dev, recv_probreq, 0, &bytes_written);
223     } else {
224         sprintf(recv_probreq, "wl recv_probreq 0");
225         wl_android_ext_priv_cmd(dev, recv_probreq, 0, &bytes_written);
226     }
227 
228     return 0;
229 }
230 
wl_ext_probreq_event(struct net_device * dev,void * argu,const wl_event_msg_t * e,void * data)231 void wl_ext_probreq_event(struct net_device *dev, void *argu,
232                           const wl_event_msg_t *e, void *data)
233 {
234     struct genl_params *zconf = (struct genl_params *)argu;
235     int i, ret = 0, num_ie = 0, totlen;
236     uint32 event_len = 0;
237     char *buf, *pbuf;
238     uint rem_len, buflen = MAX_CUSTOM_PKT_LENGTH;
239     uint32 event_id[] = {DOT11_MNG_VS_ID};
240     uint32 datalen = ntoh32(e->datalen);
241     bcm_tlv_t *ie;
242 
243     AGENL_TRACE(dev->name, "Enter\n");
244 
245     rem_len = buflen;
246     buf = kzalloc(MAX_CUSTOM_PKT_LENGTH, GFP_KERNEL);
247     if (unlikely(!buf)) {
248         AGENL_ERROR(dev->name, "Could not allocate buf\n");
249         return;
250     }
251 
252     // copy mgmt header
253     pbuf = buf;
254     memcpy(pbuf, data, DOT11_MGMT_HDR_LEN);
255     rem_len -= (DOT11_MGMT_HDR_LEN + 1);
256     datalen -= DOT11_MGMT_HDR_LEN;
257     data += DOT11_MGMT_HDR_LEN;
258 
259     // copy IEs
260     pbuf = buf + DOT11_MGMT_HDR_LEN;
261 #if 1 // non-sort by id
262     ie = (bcm_tlv_t *)data;
263     totlen = datalen;
264     while (ie && totlen >= TLV_HDR_LEN) {
265         int ie_id = -1;
266         int ie_len = ie->len + TLV_HDR_LEN;
267         for (i = 0; i < sizeof(event_id) / sizeof(event_id[0]); i++) {
268             if (ie->id == event_id[i]) {
269                 ie_id = ie->id;
270                 break;
271             }
272         }
273         if ((ie->id == ie_id) && (totlen >= ie_len) && (rem_len >= ie_len)) {
274             memcpy(pbuf, ie, ie_len);
275             pbuf += ie_len;
276             rem_len -= ie_len;
277             num_ie++;
278         }
279         ie = (bcm_tlv_t *)((uint8 *)ie + ie_len);
280         totlen -= ie_len;
281     }
282 #else // sort by id
283     for (i = 0; i < sizeof(event_id) / sizeof(event_id[0]); i++) {
284         void *pdata = data;
285         int data_len = datalen;
286         while (rem_len > 0) {
287             ie = bcm_parse_tlvs(pdata, data_len, event_id[i]);
288             if (!ie) {
289                 break;
290             }
291             if (rem_len < (ie->len + TLV_HDR_LEN)) {
292                 ANDROID_TRACE(("%s: buffer is not enough\n", __FUNCTION__));
293                 break;
294             }
295             memcpy(pbuf, ie, min(ie->len + TLV_HDR_LEN, rem_len));
296             pbuf += (ie->len + TLV_HDR_LEN);
297             rem_len -= (ie->len + TLV_HDR_LEN);
298             data_len -= (((void *)ie - pdata) + (ie->len + TLV_HDR_LEN));
299             pdata = (char *)ie + (ie->len + TLV_HDR_LEN);
300             num_ie++;
301         }
302     }
303 #endif
304     if (num_ie) {
305         event_len = buflen - rem_len;
306         AGENL_INFO(dev->name, "num_ie=%d\n", num_ie);
307         if (android_msg_level & ANDROID_INFO_LEVEL) {
308             prhex("buf", buf, event_len);
309         }
310         ret = wl_ext_genl_send(zconf, dev, buf, event_len);
311     }
312 
313     if (buf) {
314         kfree(buf);
315     }
316     return;
317 }
318 #endif
319 
wl_ext_genl_recv(struct sk_buff * skb,struct genl_info * info)320 static int wl_ext_genl_recv(struct sk_buff *skb, struct genl_info *info)
321 {
322     struct genl_params *zconf = g_zconf;
323     struct net_device *dev;
324     struct nlattr *na;
325     char *pData = NULL;
326     int DataLen = 0;
327 
328     if (info == NULL) {
329         AGENL_ERROR(dev->name, "genl_info is NULL\n");
330         return -1;
331     }
332 
333     if (zconf == NULL) {
334         AGENL_ERROR("wlan", "g_zconf is NULL\n");
335         return -1;
336     }
337     dev = zconf->dev;
338 
339 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)
340     AGENL_TRACE(dev->name, "Enter snd_portid=%d\n", info->snd_portid);
341 #else
342     AGENL_TRACE(dev->name, "Enter\n");
343 #endif
344     na = info->attrs[GENL_CUSTOM_ATTR_MSG];
345 
346     if (na) {
347         pData = (char *)nla_data(na);
348         DataLen = nla_len(na);
349         AGENL_INFO(dev->name, "nla_len(na) : %d\n", DataLen);
350         if (android_msg_level & ANDROID_INFO_LEVEL) {
351             prhex("nla_data(na)", pData, DataLen);
352         }
353     }
354 
355 #ifdef SENDPROB
356     if (*pData == MGMT_PROBE_RES) {
357         wl_ext_send_probersp(dev, pData, DataLen);
358     } else if (*pData == MGMT_PROBE_REQ) {
359         AGENL_ERROR(dev->name, "probe req\n");
360     } else {
361         AGENL_ERROR(dev->name, "Unexpected pkt %d\n", *pData);
362         if (android_msg_level & ANDROID_INFO_LEVEL) {
363             prhex("nla_data(na)", pData, DataLen);
364         }
365     }
366 #endif
367 
368     return 0;
369 }
370 
wl_ext_genl_send(struct genl_params * zconf,struct net_device * dev,char * buf,int buf_len)371 static int wl_ext_genl_send(struct genl_params *zconf, struct net_device *dev,
372                             char *buf, int buf_len)
373 {
374     struct sk_buff *skb = NULL;
375     char *msg_head = NULL;
376     int ret = -1;
377     int bytes_written = 0;
378     char recv_probreq[32];
379 
380     if (zconf->bind_pid == -1) {
381         AGENL_ERROR(dev->name, "There is no binded process\n");
382         return -1;
383     }
384 
385     if (buf == NULL || buf_len <= 0) {
386         AGENL_ERROR(dev->name, "buf is NULL or buf_len : %d\n", buf_len);
387         return -1;
388     }
389 
390     skb = genlmsg_new(MAX_CUSTOM_PKT_LENGTH, GFP_KERNEL);
391     if (skb) {
392         msg_head = genlmsg_put(skb, 0, 0, &wl_ext_genl_family, 0,
393                                GENL_CUSTOM_COMMAND_RECV);
394         if (msg_head == NULL) {
395             nlmsg_free(skb);
396             AGENL_ERROR(dev->name, "genlmsg_put fail\n");
397             return -1;
398         }
399 
400         ret = nla_put(skb, GENL_CUSTOM_ATTR_MSG, buf_len, buf);
401         if (ret != 0) {
402             nlmsg_free(skb);
403             AGENL_ERROR(dev->name, "nla_put fail : %d\n", ret);
404             return ret;
405         }
406 
407         genlmsg_end(skb, msg_head);
408 
409         /* sending message */
410         AGENL_TRACE(dev->name, "send to process %d\n", zconf->bind_pid);
411         ret = genlmsg_unicast(&init_net, skb, zconf->bind_pid);
412         if (ret != 0) {
413             AGENL_ERROR(dev->name, "genlmsg_unicast fail : %d\n", ret);
414             zconf->send_retry_cnt++;
415             if (zconf->send_retry_cnt >= GENLMSG_UNICAST_RETRY_LIMIT) {
416                 AGENL_ERROR(dev->name,
417                             "Exceeding retry cnt %d, Unbind pid : %d\n",
418                             zconf->send_retry_cnt, zconf->bind_pid);
419                 zconf->bind_pid = -1;
420                 sprintf(recv_probreq, "wl recv_probreq 0");
421                 wl_android_ext_priv_cmd(dev, recv_probreq, 0, &bytes_written);
422             }
423             return ret;
424         }
425     } else {
426         AGENL_ERROR(dev->name, "genlmsg_new fail\n");
427         return -1;
428     }
429 
430     zconf->send_retry_cnt = 0;
431 
432     return 0;
433 }
434 
wl_ext_genl_bind(struct sk_buff * skb,struct genl_info * info)435 static int wl_ext_genl_bind(struct sk_buff *skb, struct genl_info *info)
436 {
437     struct genl_params *zconf = g_zconf;
438     struct net_device *dev;
439     struct dhd_pub *dhd;
440     struct nlattr *na;
441     bool bind;
442     char *pData = NULL;
443     int DataLen = 0;
444 
445     if (info == NULL) {
446         AGENL_ERROR("wlan", "genl_info is NULL\n");
447         return -1;
448     }
449 
450     if (zconf == NULL) {
451         AGENL_ERROR("wlan", "zconf is NULL\n");
452         return -1;
453     }
454     dev = zconf->dev;
455     dhd = dhd_get_pub(dev);
456 
457     AGENL_TRACE(dev->name, "Enter\n");
458 
459     na = info->attrs[GENL_CUSTOM_ATTR_MSG];
460     if (na) {
461         pData = (char *)nla_data(na);
462         DataLen = nla_len(na);
463         AGENL_INFO(dev->name, "nla_len(na) : %d\n", DataLen);
464         if (android_msg_level & ANDROID_INFO_LEVEL) {
465             prhex("nla_data(na)", pData, DataLen);
466         }
467     }
468 
469     if (strcmp(pData, "BIND") == 0) {
470         bind = TRUE;
471     } else if (strcmp(pData, "UNBIND") == 0) {
472         bind = FALSE;
473     } else {
474         AGENL_ERROR(dev->name, "Unknown cmd %s\n", pData);
475         return -1;
476     }
477 
478     if (bind == zconf->bind) {
479         AGENL_TRACE(dev->name, "Already %s\n", bind ? "BIND" : "UNBIND");
480         return 0;
481     }
482 
483     if (bind) {
484 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)
485         zconf->bind_pid = info->snd_portid;
486 #endif
487         AGENL_TRACE(dev->name, "BIND pid = %d\n", zconf->bind_pid);
488 #ifdef SENDPROB
489         wl_ext_set_probreq(dev, TRUE);
490 #endif
491         zconf->bind = TRUE;
492         zconf->pm = dhd->conf->pm;
493         dhd->conf->pm = PM_OFF;
494     } else {
495 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)
496         AGENL_TRACE(dev->name, "UNBIND snd_portid = %d\n", info->snd_portid);
497 #else
498         AGENL_TRACE(dev->name, "UNBIND pid = %d\n", zconf->bind_pid);
499 #endif
500         zconf->bind_pid = -1;
501 #ifdef SENDPROB
502         wl_ext_set_probreq(dev, FALSE);
503 #endif
504         dhd->conf->pm = zconf->pm;
505         zconf->bind = FALSE;
506     }
507 
508     return 0;
509 }
510 
wl_ext_genl_init(struct net_device * net)511 int wl_ext_genl_init(struct net_device *net)
512 {
513     struct dhd_pub *dhd = dhd_get_pub(net);
514     struct genl_params *zconf = dhd->zconf;
515     int ret = 0;
516 
517     AGENL_TRACE(net->name, "Enter falimy name: \"%s\"\n",
518                 wl_ext_genl_family.name);
519 
520     zconf = kzalloc(sizeof(struct genl_params), GFP_KERNEL);
521     if (unlikely(!zconf)) {
522         AGENL_ERROR(net->name, "Could not allocate zconf\n");
523         return -ENOMEM;
524     }
525     dhd->zconf = (void *)zconf;
526 
527 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
528     ret = genl_register_family(&wl_ext_genl_family);
529     // fix me: how to attach wl_ext_genl_ops
530     ret = -1;
531 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
532     ret = genl_register_family_with_ops(&wl_ext_genl_family, wl_ext_genl_ops);
533 #else
534     ret = genl_register_family_with_ops(&wl_ext_genl_family, wl_ext_genl_ops,
535                                         ARRAY_SIZE(wl_ext_genl_ops));
536 #endif
537     if (ret != 0) {
538         AGENL_ERROR(net->name, "GE_NELINK family registration fail\n");
539         goto err;
540     }
541     zconf->bind_pid = -1;
542 #ifdef SENDPROB
543     ret = wl_ext_event_register(net, dhd, WLC_E_PROBREQ_MSG,
544                                 wl_ext_probreq_event, zconf, PRIO_EVENT_IAPSTA);
545     if (ret) {
546         goto err;
547     }
548 #endif
549     zconf->dev = net;
550     g_zconf = zconf;
551 
552     return ret;
553 err:
554     if (zconf) {
555         kfree(zconf);
556     }
557     return ret;
558 }
559 
wl_ext_genl_deinit(struct net_device * net)560 void wl_ext_genl_deinit(struct net_device *net)
561 {
562     struct dhd_pub *dhd = dhd_get_pub(net);
563     struct genl_params *zconf = dhd->zconf;
564 
565     AGENL_TRACE(net->name, "Enter\n");
566 
567 #ifdef SENDPROB
568     wl_ext_event_deregister(net, dhd, WLC_E_PROBREQ_MSG, wl_ext_probreq_event);
569 #endif
570 
571     genl_unregister_family(&wl_ext_genl_family);
572     if (zconf != NULL) {
573         kfree(dhd->zconf);
574         dhd->zconf = NULL;
575     }
576     g_zconf = NULL;
577 }
578 #endif
579