Jeff Johnson | 295189b | 2012-06-20 16:38:30 -0700 | [diff] [blame] | 1 | /* |
Jeff Johnson | 32d95a3 | 2012-09-10 13:15:23 -0700 | [diff] [blame^] | 2 | * Copyright (c) 2012, The Linux Foundation. All rights reserved. |
Jeff Johnson | 295189b | 2012-06-20 16:38:30 -0700 | [diff] [blame] | 3 | * |
| 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 |
| 34 | static struct hdd_context_s *pHddCtx = NULL; |
| 35 | |
| 36 | static int gWiFiChannel = 0; /* WiFi associated channel 1-13, or 0 (none) */ |
| 37 | static int gAmpChannel = 0; /* AMP associated channel 1-13, or 0 (none) */ |
| 38 | static int gBtcDriverMode = WLAN_HDD_INFRA_STATION; /* Driver mode in BTC */ |
| 39 | |
| 40 | |
| 41 | // Forward declrarion |
| 42 | static 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 | */ |
| 47 | void 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 | */ |
| 201 | int 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 | */ |
| 213 | int 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 | } |