blob: 73987d5cbc66ad2603d65da7783d3f8f5175ddbf [file] [log] [blame]
Jeff Johnson295189b2012-06-20 16:38:30 -07001/*
Kiet Lamaa8e15a2014-02-11 23:30:06 -08002 * Copyright (c) 2012-2013 Qualcomm Atheros, Inc.
3 * All Rights Reserved.
4 * Qualcomm Atheros Confidential and Proprietary.
Gopichand Nakkala92f07d82013-01-08 21:16:34 -08005 */
Jeff Johnson295189b2012-06-20 16:38:30 -07006/******************************************************************************
7 * wlan_btc_svc.c
8 *
9 ******************************************************************************/
10#include <wlan_nlink_srv.h>
11#include <wlan_btc_svc.h>
12#include <halTypes.h>
13#include <vos_status.h>
14#include <btcApi.h>
15#include <wlan_hdd_includes.h>
16#include <vos_trace.h>
17// Global variables
Madan Mohan Koyyalamudidfd6aa82012-10-18 20:18:43 -070018static struct hdd_context_s *pHddCtx;
Jeff Johnson295189b2012-06-20 16:38:30 -070019
Madan Mohan Koyyalamudidfd6aa82012-10-18 20:18:43 -070020static int gWiFiChannel; /* WiFi associated channel 1-13, or 0 (none) */
21static int gAmpChannel; /* AMP associated channel 1-13, or 0 (none) */
Jeff Johnson295189b2012-06-20 16:38:30 -070022static int gBtcDriverMode = WLAN_HDD_INFRA_STATION; /* Driver mode in BTC */
23
24
25// Forward declrarion
26static int btc_msg_callback (struct sk_buff * skb);
27/*
28 * Send a netlink message to the user space.
29 * Destination pid as zero implies broadcast
30 */
31void send_btc_nlink_msg (int type, int dest_pid)
32{
33 struct sk_buff *skb;
34 struct nlmsghdr *nlh;
35 tAniMsgHdr *aniHdr;
36 tWlanAssocData *assocData;
37 skb = alloc_skb(NLMSG_SPACE(WLAN_NL_MAX_PAYLOAD), GFP_KERNEL);
38 if(skb == NULL) {
39 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
40 "BTC: alloc_skb failed\n");
41 return;
42 }
43 nlh = (struct nlmsghdr *)skb->data;
44 nlh->nlmsg_pid = 0; /* from kernel */
45 nlh->nlmsg_flags = 0;
46 nlh->nlmsg_seq = 0;
47 nlh->nlmsg_type = WLAN_NL_MSG_BTC;
48 aniHdr = NLMSG_DATA(nlh);
49 aniHdr->type = type;
50
51 /* Set BTC driver mode correctly based on received events type */
52 if(type == WLAN_BTC_SOFTAP_BSS_START)
53 {
54 /* Event is SoftAP BSS Start set BTC driver mode to SoftAP */
55 gBtcDriverMode = WLAN_HDD_SOFTAP;
56 }
57 if(type == WLAN_STA_ASSOC_DONE_IND)
58 {
59 /* Event is STA Assoc done set BTC driver mode to INFRA STA*/
60 gBtcDriverMode = WLAN_HDD_INFRA_STATION;
61 }
62
63 switch( type )
64 {
65 case WLAN_STA_DISASSOC_DONE_IND:
66 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_LOW,
67 "WiFi unassociated; gAmpChannel %d gWiFiChannel %d", gAmpChannel, gWiFiChannel);
68
69 /* If AMP is using a channel (non-zero), no message sent.
70 Or, if WiFi wasn't using a channel before, no message sent.
71 Logic presumes same channel has to be used for WiFi and AMP if both are active.
72 In any case, track the WiFi channel in use (none) */
73 if((gAmpChannel != 0) || (gWiFiChannel == 0))
74 {
75 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_LOW,
76 "No msg for AFH will be sent");
77 gWiFiChannel = 0;
78 kfree_skb(skb);
79 return;
80 }
81 gWiFiChannel = 0;
82
83 /* No Break: Fall into next cases */
84
85 case WLAN_MODULE_UP_IND:
86 case WLAN_MODULE_DOWN_IND:
87 aniHdr->length = 0;
88 nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr)));
89 skb_put(skb, NLMSG_SPACE(sizeof(tAniMsgHdr)));
90 break;
91 case WLAN_BTC_SOFTAP_BSS_START:
92 case WLAN_BTC_QUERY_STATE_RSP:
93 case WLAN_STA_ASSOC_DONE_IND:
94 aniHdr->length = sizeof(tWlanAssocData);
95 nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + sizeof(tWlanAssocData)));
96 assocData = ( tWlanAssocData *)((char*)aniHdr + sizeof(tAniMsgHdr));
97
98 assocData->channel = hdd_get_operating_channel( pHddCtx, gBtcDriverMode );
99
100 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_LOW,
101 "New WiFi channel %d gAmpChannel %d gWiFiChannel %d",
102 assocData->channel, gAmpChannel, gWiFiChannel);
103
104 /* If WiFi has finished associating */
105 if(type == WLAN_STA_ASSOC_DONE_IND)
106 {
107 /* If AMP is using a channel (non-zero), no message sent.
108 Or, if the WiFi channel did not change, no message sent.
109 Logic presumes same channel has to be used for WiFi and AMP if both are active.
110 In any case, track the WiFi channel in use (1-13 or none, in assocData->channel) */
111 if((gAmpChannel != 0) || (assocData->channel == gWiFiChannel))
112 {
113 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_LOW,
114 "No msg for AFH will be sent");
115 gWiFiChannel = assocData->channel;
116 kfree_skb(skb);
117 return;
118 }
119 }
120 if(type == WLAN_BTC_SOFTAP_BSS_START)
121 {
122 /*Replace WLAN_BTC_SOFTAP_BSS_START by WLAN_STA_ASSOC_DONE_IND*/
123 aniHdr->type = WLAN_STA_ASSOC_DONE_IND;
124 }
125 gWiFiChannel = assocData->channel;
126 skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr)+ sizeof(tWlanAssocData))));
127 break;
128
129 case WLAN_AMP_ASSOC_DONE_IND:
130
131 /* This is an overloaded type. It means that AMP is connected (dest_pid is channel 1-13),
132 or it means AMP is now disconnected (dest_pid is 0) */
133
134 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_LOW,
135 "New AMP channel %d gAmpChannel %d gWiFiChannel %d", dest_pid, gAmpChannel, gWiFiChannel);
136 /* If WiFi is using a channel (non-zero), no message sent.
137 Or, if the AMP channel did not change, no message sent.
138 Logic presumes same channel has to be used for WiFi and AMP if both are active.
139 In any case, track the AMP channel in use (1-13 or none, in dest_pid) */
140 if((gWiFiChannel != 0) || (dest_pid == gAmpChannel))
141 {
142 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_LOW,
143 "No msg for AFH will be sent");
144 gAmpChannel = dest_pid;
145 kfree_skb(skb);
146 return;
147 }
148
149 gAmpChannel = dest_pid;
150
151 /* Fix overloaded parameters and finish message formatting */
152 if(dest_pid != 0)
153 {
154 aniHdr->type = WLAN_STA_ASSOC_DONE_IND;
155 aniHdr->length = sizeof(tWlanAssocData);
156 nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + sizeof(tWlanAssocData)));
157 assocData = ( tWlanAssocData *)((char*)aniHdr + sizeof(tAniMsgHdr));
158 assocData->channel = dest_pid;
159 skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr)+ sizeof(tWlanAssocData))));
160 }
161 else
162 {
163 aniHdr->type = WLAN_STA_DISASSOC_DONE_IND;
164 aniHdr->length = 0;
165 nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr)));
166 skb_put(skb, NLMSG_SPACE(sizeof(tAniMsgHdr)));
167 }
168 dest_pid = 0;
169 break;
170
171 default:
172 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
173 "BTC: Attempt to send unknown nlink message %d\n", type);
Jeff Johnsonb0d01c02013-04-03 15:42:47 -0700174 kfree_skb(skb);
Jeff Johnson295189b2012-06-20 16:38:30 -0700175 return;
176 }
177 if(dest_pid == 0)
178 (void)nl_srv_bcast(skb);
179 else
180 (void)nl_srv_ucast(skb, dest_pid);
181}
182/*
183 * Activate BTC handler. This will register a handler to receive
184 * netlink messages addressed to WLAN_NL_MSG_BTC from user space
185 */
186int btc_activate_service(void *pAdapter)
187{
188 pHddCtx = (struct hdd_context_s*)pAdapter;
189
190 //Register the msg handler for msgs addressed to ANI_NL_MSG_BTC
191 nl_srv_register(WLAN_NL_MSG_BTC, btc_msg_callback);
192 return 0;
193}
194/*
195 * Callback function invoked by Netlink service for all netlink
196 * messages (from user space) addressed to WLAN_NL_MSG_BTC
197 */
198int btc_msg_callback (struct sk_buff * skb)
199{
200 struct nlmsghdr *nlh;
201 tAniMsgHdr *msg_hdr;
202 tSmeBtEvent *btEvent = NULL;
203 nlh = (struct nlmsghdr *)skb->data;
204 msg_hdr = NLMSG_DATA(nlh);
205
206 /* Continue with parsing payload. */
207 switch(msg_hdr->type)
208 {
209 case WLAN_BTC_QUERY_STATE_REQ:
210 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
211 "BTC: Received probe from BTC Service\n");
212 send_btc_nlink_msg(WLAN_BTC_QUERY_STATE_RSP, nlh->nlmsg_pid);
213 break;
214 case WLAN_BTC_BT_EVENT_IND:
215 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
216 "BTC: Received Bluetooth event indication\n");
217 if(msg_hdr->length != sizeof(tSmeBtEvent)) {
218 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
219 "BTC: Size mismatch in BT event data\n");
220 break;
221 }
222 btEvent = (tSmeBtEvent*)((char*)msg_hdr + sizeof(tAniMsgHdr));
223 (void)sme_BtcSignalBtEvent(pHddCtx->hHal, btEvent);
224 break;
225 default:
226 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
227 "BTC: Received Invalid Msg type [%d]\n", msg_hdr->type);
228 break;
229 }
230 return 0;
231}