Jeff Johnson | 295189b | 2012-06-20 16:38:30 -0700 | [diff] [blame] | 1 | /* |
Kiet Lam | aa8e15a | 2014-02-11 23:30:06 -0800 | [diff] [blame^] | 2 | * Copyright (c) 2012-2013 Qualcomm Atheros, Inc. |
| 3 | * All Rights Reserved. |
| 4 | * Qualcomm Atheros Confidential and Proprietary. |
Gopichand Nakkala | 92f07d8 | 2013-01-08 21:16:34 -0800 | [diff] [blame] | 5 | */ |
Jeff Johnson | 295189b | 2012-06-20 16:38:30 -0700 | [diff] [blame] | 6 | /****************************************************************************** |
| 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 Koyyalamudi | dfd6aa8 | 2012-10-18 20:18:43 -0700 | [diff] [blame] | 18 | static struct hdd_context_s *pHddCtx; |
Jeff Johnson | 295189b | 2012-06-20 16:38:30 -0700 | [diff] [blame] | 19 | |
Madan Mohan Koyyalamudi | dfd6aa8 | 2012-10-18 20:18:43 -0700 | [diff] [blame] | 20 | static int gWiFiChannel; /* WiFi associated channel 1-13, or 0 (none) */ |
| 21 | static int gAmpChannel; /* AMP associated channel 1-13, or 0 (none) */ |
Jeff Johnson | 295189b | 2012-06-20 16:38:30 -0700 | [diff] [blame] | 22 | static int gBtcDriverMode = WLAN_HDD_INFRA_STATION; /* Driver mode in BTC */ |
| 23 | |
| 24 | |
| 25 | // Forward declrarion |
| 26 | static 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 | */ |
| 31 | void 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 Johnson | b0d01c0 | 2013-04-03 15:42:47 -0700 | [diff] [blame] | 174 | kfree_skb(skb); |
Jeff Johnson | 295189b | 2012-06-20 16:38:30 -0700 | [diff] [blame] | 175 | 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 | */ |
| 186 | int 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 | */ |
| 198 | int 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 | } |