2 function handler for linux netlink socket!
8 #include <sys/socket.h>
9 #include <linux/netlink.h>
10 #include <linux/rtnetlink.h>
11 #include "wsc_common.h"
12 #include "wsc_netlink.h"
15 int we_version_compiled = WIRELESS_EXT;
16 static int netlink_sock = -1;
18 static void wscEventHandler(char *data, int len)
20 struct iw_event iwe_buf, *iwe = &iwe_buf;
21 char *pos, *end, *custom;
27 while (pos + IW_EV_LCP_LEN <= end)
29 /* Event data may be unaligned, so make a local, aligned copy
30 * before processing. */
31 memcpy(&iwe_buf, pos, IW_EV_LCP_LEN);
32 //DBGPRINTF(RT_DBG_INFO, "Wireless event: cmd=0x%x len=%d, we_version_compiled=%d!\n", iwe->cmd, iwe->len, we_version_compiled);
33 if (iwe->len <= IW_EV_LCP_LEN)
36 custom = pos + IW_EV_POINT_LEN;
37 if(iwe->cmd == IWEVCUSTOM)
39 if (we_version_compiled > 18)
41 /* WE-19 removed the pointer from struct iw_point */
42 char *dpos = (char *) &iwe_buf.u.data.length;
43 int dlen = dpos - (char *) &iwe_buf;
44 memcpy(dpos, pos + IW_EV_LCP_LEN, sizeof(struct iw_event) - dlen);
48 memcpy(&iwe_buf, pos, sizeof(struct iw_event));
51 if (custom + iwe->u.data.length > end){
52 DBGPRINTF(RT_DBG_INFO, "custom(0x%x) + iwe->u.data.length(0x%x) > end(0x%x)!\n", custom, iwe->u.data.length, end);
56 buf = malloc(iwe->u.data.length + 1);
60 memcpy(buf, custom, iwe->u.data.length);
61 buf[iwe->u.data.length] = '\0';
63 //DBGPRINTF(RT_DBG_INFO, "iwe->u.data.flags=0x%x!\n", iwe->u.data.flags);
64 switch(iwe->u.data.flags)
66 case RT_ASSOC_EVENT_FLAG:
67 case RT_DISASSOC_EVENT_FLAG:
68 case RT_REQIE_EVENT_FLAG:
69 case RT_RESPIE_EVENT_FLAG:
70 case RT_ASSOCINFO_EVENT_FLAG:
71 case RT_PMKIDCAND_FLAG:
74 if(strncmp(custom, "RAWSCMSG", 8) == 0)
76 DBGPRINTF(RT_DBG_INFO, "Recevive a RAWSCMSG segment\n");
77 WscRTMPMsgHandler(custom, iwe->u.data.length);
89 static void wscNLEventRTMNewlinkHandle(struct nlmsghdr *nlmsgHdr, int len)
91 struct ifinfomsg *ifi;
92 int attrlen, nlmsg_len, rta_len;
95 DBGPRINTF(RT_DBG_INFO, "%s", __FUNCTION__);
97 if (len < sizeof(struct ifinfomsg))
100 ifi = NLMSG_DATA(nlmsgHdr);
101 //wsc_hexdump("ifi: ", (char *)ifi, sizeof(struct ifinfomsg));
103 nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
105 attrlen = nlmsgHdr->nlmsg_len - nlmsg_len;
106 // DBGPRINTF("attrlen=%d\n",attrlen);
110 attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
111 //wsc_hexdump("rtattr: ", (char *)attr,sizeof(struct rtattr));
112 rta_len = RTA_ALIGN(sizeof(struct rtattr));
113 //wsc_hexdump("rtattr: ", (char *)attr, rta_len);
114 while (RTA_OK(attr, attrlen))
116 if (attr->rta_type == IFLA_WIRELESS)
118 wscEventHandler(((char *) attr) + rta_len, attr->rta_len - rta_len);
120 attr = RTA_NEXT(attr, attrlen);
121 //wsc_hexdump("rta_type: ", (char *)attr,sizeof(struct rtattr));
125 void wscNLSockRecv(int sock)
129 struct sockaddr_nl from;
131 struct nlmsghdr *nlmsgHdr;
133 fromlen = sizeof(from);
134 left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT, (struct sockaddr *)&from, &fromlen);
138 if (errno != EINTR && errno != EAGAIN)
139 perror("recvfrom(netlink)");
143 nlmsgHdr = (struct nlmsghdr *)buf;
144 //wsc_hexdump("nlmsgHdr: ", (char *)nlmsgHdr, nlmsgHdr->nlmsg_len);
146 while (left >= sizeof(*nlmsgHdr))
150 len = nlmsgHdr->nlmsg_len;
151 plen = len - sizeof(*nlmsgHdr);
152 if (len > left || plen < 0)
154 DBGPRINTF(RT_DBG_INFO, "Malformed netlink message: len=%d left=%d plen=%d", len, left, plen);
158 switch (nlmsgHdr->nlmsg_type)
161 wscNLEventRTMNewlinkHandle(nlmsgHdr, plen);
165 len = NLMSG_ALIGN(len);
167 nlmsgHdr = (struct nlmsghdr *) ((char *) nlmsgHdr + len);
172 DBGPRINTF(RT_DBG_INFO, "%d extra bytes in the end of netlink message", left);
177 /******************************************************************************
181 * Function that receives netlink socket msg from the kernel
182 * during the lifetime of the device, and send to appropriate
183 * msg queue and trigger the callback handler.
190 *****************************************************************************/
191 void *wscDevNLHandle(void *args)
197 DBGPRINTF(RT_DBG_INFO, "Pthread(%s)Now waiting for the netlink socket incoming message!\n", __FUNCTION__);
199 flags = fcntl(netlink_sock, F_GETFL, 0);
202 fcntl(netlink_sock, F_SETFL, flags | O_NONBLOCK);
207 FD_SET(netlink_sock, &rfds);
209 retVal = select(netlink_sock + 1, &rfds, NULL, NULL, NULL);
211 /* Don¡¦t rely on the value of Wsc now! */
215 DBGPRINTF(RT_DBG_INFO, "(%s):netlink socket data is available now.\n", __FUNCTION__);
216 if(FD_ISSET(netlink_sock, &rfds)){
217 wscNLSockRecv(netlink_sock);
223 if(netlink_sock >= 0)
230 /******************************************************************************
234 * The Kernel space 2 user space msg subsystem entry point.
235 * In Linux system, we use netlink socket to receive the specific type msg
236 * send from wireless driver.
237 * This function mainly create a posix thread and recvive msg then dispatch
238 * to coressponding handler.
246 *****************************************************************************/
247 int wscK2UModuleInit(void)
250 struct sockaddr_nl local;
251 pthread_t wscNLHandle_thread;
253 //Create netlink socket
254 sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
257 perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)");
258 return WSC_SYS_ERROR;
261 memset(&local, 0, sizeof(local));
262 local.nl_family = AF_NETLINK;
263 local.nl_groups = RTMGRP_LINK;
265 if (bind(sock, (struct sockaddr *)&local, sizeof(local)) < 0)
267 perror("bind(netlink)");
269 return WSC_SYS_ERROR;
273 start a netlink socket receiver handle thread
275 DBGPRINTF(RT_DBG_INFO, "sock=%d!(0x%p)\n", sock, &sock);
277 retVal = pthread_create(&wscNLHandle_thread, NULL, wscDevNLHandle, NULL);
279 pthread_detach(wscNLHandle_thread);
281 return WSC_SYS_SUCCESS;