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