blob: 54a654aa62b397e2080990f87aab2dd158e999b6 [file] [log] [blame]
Jeff Johnson295189b2012-06-20 16:38:30 -07001/*
Jeff Johnson32d95a32012-09-10 13:15:23 -07002 * Copyright (c) 2012, The Linux Foundation. All rights reserved.
Jeff Johnson295189b2012-06-20 16:38:30 -07003 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/******************************************************************************
23 * wlan_btc_svc.c
24 *
25 ******************************************************************************/
26#include <wlan_nlink_srv.h>
27#include <wlan_btc_svc.h>
28#include <halTypes.h>
29#include <vos_status.h>
30#include <btcApi.h>
31#include <wlan_hdd_includes.h>
32#include <vos_trace.h>
33// Global variables
34static struct hdd_context_s *pHddCtx = NULL;
35
36static int gWiFiChannel = 0; /* WiFi associated channel 1-13, or 0 (none) */
37static int gAmpChannel = 0; /* AMP associated channel 1-13, or 0 (none) */
38static int gBtcDriverMode = WLAN_HDD_INFRA_STATION; /* Driver mode in BTC */
39
40
41// Forward declrarion
42static int btc_msg_callback (struct sk_buff * skb);
43/*
44 * Send a netlink message to the user space.
45 * Destination pid as zero implies broadcast
46 */
47void send_btc_nlink_msg (int type, int dest_pid)
48{
49 struct sk_buff *skb;
50 struct nlmsghdr *nlh;
51 tAniMsgHdr *aniHdr;
52 tWlanAssocData *assocData;
53 skb = alloc_skb(NLMSG_SPACE(WLAN_NL_MAX_PAYLOAD), GFP_KERNEL);
54 if(skb == NULL) {
55 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
56 "BTC: alloc_skb failed\n");
57 return;
58 }
59 nlh = (struct nlmsghdr *)skb->data;
60 nlh->nlmsg_pid = 0; /* from kernel */
61 nlh->nlmsg_flags = 0;
62 nlh->nlmsg_seq = 0;
63 nlh->nlmsg_type = WLAN_NL_MSG_BTC;
64 aniHdr = NLMSG_DATA(nlh);
65 aniHdr->type = type;
66
67 /* Set BTC driver mode correctly based on received events type */
68 if(type == WLAN_BTC_SOFTAP_BSS_START)
69 {
70 /* Event is SoftAP BSS Start set BTC driver mode to SoftAP */
71 gBtcDriverMode = WLAN_HDD_SOFTAP;
72 }
73 if(type == WLAN_STA_ASSOC_DONE_IND)
74 {
75 /* Event is STA Assoc done set BTC driver mode to INFRA STA*/
76 gBtcDriverMode = WLAN_HDD_INFRA_STATION;
77 }
78
79 switch( type )
80 {
81 case WLAN_STA_DISASSOC_DONE_IND:
82 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_LOW,
83 "WiFi unassociated; gAmpChannel %d gWiFiChannel %d", gAmpChannel, gWiFiChannel);
84
85 /* If AMP is using a channel (non-zero), no message sent.
86 Or, if WiFi wasn't using a channel before, no message sent.
87 Logic presumes same channel has to be used for WiFi and AMP if both are active.
88 In any case, track the WiFi channel in use (none) */
89 if((gAmpChannel != 0) || (gWiFiChannel == 0))
90 {
91 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_LOW,
92 "No msg for AFH will be sent");
93 gWiFiChannel = 0;
94 kfree_skb(skb);
95 return;
96 }
97 gWiFiChannel = 0;
98
99 /* No Break: Fall into next cases */
100
101 case WLAN_MODULE_UP_IND:
102 case WLAN_MODULE_DOWN_IND:
103 aniHdr->length = 0;
104 nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr)));
105 skb_put(skb, NLMSG_SPACE(sizeof(tAniMsgHdr)));
106 break;
107 case WLAN_BTC_SOFTAP_BSS_START:
108 case WLAN_BTC_QUERY_STATE_RSP:
109 case WLAN_STA_ASSOC_DONE_IND:
110 aniHdr->length = sizeof(tWlanAssocData);
111 nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + sizeof(tWlanAssocData)));
112 assocData = ( tWlanAssocData *)((char*)aniHdr + sizeof(tAniMsgHdr));
113
114 assocData->channel = hdd_get_operating_channel( pHddCtx, gBtcDriverMode );
115
116 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_LOW,
117 "New WiFi channel %d gAmpChannel %d gWiFiChannel %d",
118 assocData->channel, gAmpChannel, gWiFiChannel);
119
120 /* If WiFi has finished associating */
121 if(type == WLAN_STA_ASSOC_DONE_IND)
122 {
123 /* If AMP is using a channel (non-zero), no message sent.
124 Or, if the WiFi channel did not change, no message sent.
125 Logic presumes same channel has to be used for WiFi and AMP if both are active.
126 In any case, track the WiFi channel in use (1-13 or none, in assocData->channel) */
127 if((gAmpChannel != 0) || (assocData->channel == gWiFiChannel))
128 {
129 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_LOW,
130 "No msg for AFH will be sent");
131 gWiFiChannel = assocData->channel;
132 kfree_skb(skb);
133 return;
134 }
135 }
136 if(type == WLAN_BTC_SOFTAP_BSS_START)
137 {
138 /*Replace WLAN_BTC_SOFTAP_BSS_START by WLAN_STA_ASSOC_DONE_IND*/
139 aniHdr->type = WLAN_STA_ASSOC_DONE_IND;
140 }
141 gWiFiChannel = assocData->channel;
142 skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr)+ sizeof(tWlanAssocData))));
143 break;
144
145 case WLAN_AMP_ASSOC_DONE_IND:
146
147 /* This is an overloaded type. It means that AMP is connected (dest_pid is channel 1-13),
148 or it means AMP is now disconnected (dest_pid is 0) */
149
150 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_LOW,
151 "New AMP channel %d gAmpChannel %d gWiFiChannel %d", dest_pid, gAmpChannel, gWiFiChannel);
152 /* If WiFi is using a channel (non-zero), no message sent.
153 Or, if the AMP channel did not change, no message sent.
154 Logic presumes same channel has to be used for WiFi and AMP if both are active.
155 In any case, track the AMP channel in use (1-13 or none, in dest_pid) */
156 if((gWiFiChannel != 0) || (dest_pid == gAmpChannel))
157 {
158 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_LOW,
159 "No msg for AFH will be sent");
160 gAmpChannel = dest_pid;
161 kfree_skb(skb);
162 return;
163 }
164
165 gAmpChannel = dest_pid;
166
167 /* Fix overloaded parameters and finish message formatting */
168 if(dest_pid != 0)
169 {
170 aniHdr->type = WLAN_STA_ASSOC_DONE_IND;
171 aniHdr->length = sizeof(tWlanAssocData);
172 nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + sizeof(tWlanAssocData)));
173 assocData = ( tWlanAssocData *)((char*)aniHdr + sizeof(tAniMsgHdr));
174 assocData->channel = dest_pid;
175 skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr)+ sizeof(tWlanAssocData))));
176 }
177 else
178 {
179 aniHdr->type = WLAN_STA_DISASSOC_DONE_IND;
180 aniHdr->length = 0;
181 nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr)));
182 skb_put(skb, NLMSG_SPACE(sizeof(tAniMsgHdr)));
183 }
184 dest_pid = 0;
185 break;
186
187 default:
188 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
189 "BTC: Attempt to send unknown nlink message %d\n", type);
190 return;
191 }
192 if(dest_pid == 0)
193 (void)nl_srv_bcast(skb);
194 else
195 (void)nl_srv_ucast(skb, dest_pid);
196}
197/*
198 * Activate BTC handler. This will register a handler to receive
199 * netlink messages addressed to WLAN_NL_MSG_BTC from user space
200 */
201int btc_activate_service(void *pAdapter)
202{
203 pHddCtx = (struct hdd_context_s*)pAdapter;
204
205 //Register the msg handler for msgs addressed to ANI_NL_MSG_BTC
206 nl_srv_register(WLAN_NL_MSG_BTC, btc_msg_callback);
207 return 0;
208}
209/*
210 * Callback function invoked by Netlink service for all netlink
211 * messages (from user space) addressed to WLAN_NL_MSG_BTC
212 */
213int btc_msg_callback (struct sk_buff * skb)
214{
215 struct nlmsghdr *nlh;
216 tAniMsgHdr *msg_hdr;
217 tSmeBtEvent *btEvent = NULL;
218 nlh = (struct nlmsghdr *)skb->data;
219 msg_hdr = NLMSG_DATA(nlh);
220
221 /* Continue with parsing payload. */
222 switch(msg_hdr->type)
223 {
224 case WLAN_BTC_QUERY_STATE_REQ:
225 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
226 "BTC: Received probe from BTC Service\n");
227 send_btc_nlink_msg(WLAN_BTC_QUERY_STATE_RSP, nlh->nlmsg_pid);
228 break;
229 case WLAN_BTC_BT_EVENT_IND:
230 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
231 "BTC: Received Bluetooth event indication\n");
232 if(msg_hdr->length != sizeof(tSmeBtEvent)) {
233 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
234 "BTC: Size mismatch in BT event data\n");
235 break;
236 }
237 btEvent = (tSmeBtEvent*)((char*)msg_hdr + sizeof(tAniMsgHdr));
238 (void)sme_BtcSignalBtEvent(pHddCtx->hHal, btEvent);
239 break;
240 default:
241 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
242 "BTC: Received Invalid Msg type [%d]\n", msg_hdr->type);
243 break;
244 }
245 return 0;
246}