/* Utility function to send a netlink message to an application
 * in user space
 */
static int wlan_send_sock_msg_to_app(tAniHdr *wmsg, int radio,
				int src_mod, int pid)
{
	int err = -1;
	int payload_len;
	int tot_msg_len;
	tAniNlHdr *wnl = NULL;
	struct sk_buff *skb;
	struct nlmsghdr *nlh;
	int wmsg_length = wmsg->length;
	static int nlmsg_seq;

	if (radio < 0 || radio > ANI_MAX_RADIOS) {
		LOGGING_TRACE(VOS_TRACE_LEVEL_ERROR,
				"%s: invalid radio id [%d]",
				__func__, radio);
		return -EINVAL;
	}

	payload_len = wmsg_length + sizeof(wnl->radio);
	tot_msg_len = NLMSG_SPACE(payload_len);
	skb = dev_alloc_skb(tot_msg_len);
	if (skb == NULL) {
		LOGGING_TRACE(VOS_TRACE_LEVEL_ERROR,
				"%s: dev_alloc_skb() failed for msg size[%d]",
				__func__, tot_msg_len);
		return -ENOMEM;
	}
	nlh = nlmsg_put(skb, pid, nlmsg_seq++, src_mod, payload_len,
		NLM_F_REQUEST);
	if (NULL == nlh) {
		LOGGING_TRACE(VOS_TRACE_LEVEL_ERROR,
				"%s: nlmsg_put() failed for msg size[%d]",
				__func__, tot_msg_len);
		kfree_skb(skb);
		return -ENOMEM;
	}

	wnl = (tAniNlHdr *) nlh;
	wnl->radio = radio;
	memcpy(&wnl->wmsg, wmsg, wmsg_length);
	err = nl_srv_ucast(skb, pid, MSG_DONTWAIT);
	if (err) {
		LOGGING_TRACE(VOS_TRACE_LEVEL_INFO,
				"%s: Failed sending Msg Type [0x%X] to pid[%d]\n",
				__func__, wmsg->type, pid);
	}

	return err;
}
static int send_filled_buffers_to_user(void)
{
	int ret = -1;
	struct log_msg *plog_msg;
	int payload_len;
	int tot_msg_len;
	tAniNlHdr *wnl;
	struct sk_buff *skb = NULL;
	struct nlmsghdr *nlh;
	static int nlmsg_seq;
	unsigned long flags;
	static int rate_limit;

	while (!list_empty(&gwlan_logging.filled_list)
		&& !gwlan_logging.exit) {

		skb = dev_alloc_skb(MAX_LOGMSG_LENGTH);
		if (skb == NULL) {
			if (!rate_limit) {
				pr_err("%s: dev_alloc_skb() failed for msg size[%d] drop count = %u\n",
					__func__, MAX_LOGMSG_LENGTH,
					gwlan_logging.drop_count);
			}
			rate_limit = 1;
			ret = -ENOMEM;
			break;
		}
		rate_limit = 0;

		spin_lock_irqsave(&gwlan_logging.spin_lock, flags);

		plog_msg = (struct log_msg *)
			(gwlan_logging.filled_list.next);
		list_del_init(gwlan_logging.filled_list.next);
		spin_unlock_irqrestore(&gwlan_logging.spin_lock, flags);
		/* 4 extra bytes for the radio idx */
		payload_len = plog_msg->filled_length +
			sizeof(wnl->radio) + sizeof(tAniHdr);

		tot_msg_len = NLMSG_SPACE(payload_len);
		nlh = nlmsg_put(skb, gapp_pid, nlmsg_seq++,
				ANI_NL_MSG_LOG, payload_len,
				NLM_F_REQUEST);
		if (NULL == nlh) {
			spin_lock_irqsave(&gwlan_logging.spin_lock, flags);
			list_add_tail(&plog_msg->node,
				&gwlan_logging.free_list);
			spin_unlock_irqrestore(&gwlan_logging.spin_lock,
							flags);
			pr_err("%s: drop_count = %u\n", __func__,
				++gwlan_logging.drop_count);
			pr_err("%s: nlmsg_put() failed for msg size[%d]\n",
				__func__, tot_msg_len);
			dev_kfree_skb(skb);
			skb = NULL;
			ret = -EINVAL;
			continue;
		}

		wnl = (tAniNlHdr *) nlh;
		wnl->radio = plog_msg->radio;
		vos_mem_copy(&wnl->wmsg, plog_msg->logbuf,
				plog_msg->filled_length +
				sizeof(tAniHdr));

		spin_lock_irqsave(&gwlan_logging.spin_lock, flags);
		list_add_tail(&plog_msg->node,
				&gwlan_logging.free_list);
		spin_unlock_irqrestore(&gwlan_logging.spin_lock, flags);

		ret = nl_srv_ucast(skb, gapp_pid, 0);
		if (ret < 0) {
			pr_err("%s: Send Failed %d drop_count = %u\n",
				__func__, ret, ++gwlan_logging.drop_count);
			skb = NULL;
			gapp_pid = INVALID_PID;
			clear_default_logtoapp_log_level();
			wlan_logging_srv_nl_ready_indication();
		} else {
			skb = NULL;
			ret = 0;
		}
	}

	return ret;
}
Beispiel #3
0
/*
 * Send a netlink message to the user space. 
 * Destination pid as zero implies broadcast
 */
void send_btc_nlink_msg (int type, int dest_pid)
{
   struct sk_buff *skb;
   struct nlmsghdr *nlh;
   tAniMsgHdr *aniHdr;
   tWlanAssocData *assocData;
   skb = alloc_skb(NLMSG_SPACE(WLAN_NL_MAX_PAYLOAD), GFP_KERNEL);
   if(skb == NULL) {
      VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
         "BTC: alloc_skb failed\n");
      return;
   }   
   nlh = (struct nlmsghdr *)skb->data;
   nlh->nlmsg_pid = 0;  /* from kernel */
   nlh->nlmsg_flags = 0;
   nlh->nlmsg_seq = 0;
   nlh->nlmsg_type = WLAN_NL_MSG_BTC;
   aniHdr = NLMSG_DATA(nlh);
   aniHdr->type = type;

  /* Set BTC driver mode correctly based on received events type */
  if(type == WLAN_BTC_SOFTAP_BSS_START)
  {
     /* Event is SoftAP BSS Start set BTC driver mode to SoftAP */
     gBtcDriverMode = WLAN_HDD_SOFTAP;
  }
  if(type == WLAN_STA_ASSOC_DONE_IND)
  {
     /* Event is STA Assoc done set BTC driver mode to INFRA STA*/
     gBtcDriverMode = WLAN_HDD_INFRA_STATION;
  }

   switch( type )
   {
      case WLAN_STA_DISASSOC_DONE_IND:
         VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_LOW,
                    "WiFi unassociated; gAmpChannel %d gWiFiChannel %d", gAmpChannel, gWiFiChannel);

         /* If AMP is using a channel (non-zero), no message sent.
            Or, if WiFi wasn't using a channel before, no message sent.
            Logic presumes same channel has to be used for WiFi and AMP if both are active.
            In any case, track the WiFi channel in use (none) */
         if((gAmpChannel != 0) || (gWiFiChannel == 0))
         {
           VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_LOW,
                      "No msg for AFH will be sent");
            gWiFiChannel = 0;
            kfree_skb(skb);
            return;
         }
         gWiFiChannel = 0;

         /* No Break: Fall into next cases */

      case WLAN_MODULE_UP_IND:
      case WLAN_MODULE_DOWN_IND:
         aniHdr->length = 0; 
         nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr)));
         skb_put(skb, NLMSG_SPACE(sizeof(tAniMsgHdr)));
         break;
      case WLAN_BTC_SOFTAP_BSS_START:
      case WLAN_BTC_QUERY_STATE_RSP:
      case WLAN_STA_ASSOC_DONE_IND:
         aniHdr->length = sizeof(tWlanAssocData);
         nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + sizeof(tWlanAssocData)));
         assocData = ( tWlanAssocData *)((char*)aniHdr + sizeof(tAniMsgHdr));
         
         assocData->channel = hdd_get_operating_channel( pHddCtx, gBtcDriverMode );

         VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_LOW,
                    "New WiFi channel %d gAmpChannel %d gWiFiChannel %d",
                    assocData->channel, gAmpChannel, gWiFiChannel);

         /* If WiFi has finished associating */
         if(type == WLAN_STA_ASSOC_DONE_IND)
         {
           /* If AMP is using a channel (non-zero), no message sent.
              Or, if the WiFi channel did not change, no message sent.
              Logic presumes same channel has to be used for WiFi and AMP if both are active.
              In any case, track the WiFi channel in use (1-13 or none, in assocData->channel) */
           if((gAmpChannel != 0) || (assocData->channel == gWiFiChannel))
           {
             VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_LOW,
                        "No msg for AFH will be sent");
             gWiFiChannel = assocData->channel;
             kfree_skb(skb);
             return;
           }
         }
         if(type == WLAN_BTC_SOFTAP_BSS_START)
         {
             /*Replace WLAN_BTC_SOFTAP_BSS_START by WLAN_STA_ASSOC_DONE_IND*/
             aniHdr->type = WLAN_STA_ASSOC_DONE_IND;
         }
         gWiFiChannel = assocData->channel;
         skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr)+ sizeof(tWlanAssocData))));
         break;

      case WLAN_AMP_ASSOC_DONE_IND:

         /* This is an overloaded type. It means that AMP is connected (dest_pid is channel 1-13),
            or it means AMP is now disconnected (dest_pid is 0) */

         VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_LOW,
                    "New AMP channel %d gAmpChannel %d gWiFiChannel %d", dest_pid, gAmpChannel, gWiFiChannel);
         /* If WiFi is using a channel (non-zero), no message sent.
            Or, if the AMP channel did not change, no message sent.
            Logic presumes same channel has to be used for WiFi and AMP if both are active.
            In any case, track the AMP channel in use (1-13 or none, in dest_pid) */
         if((gWiFiChannel != 0) || (dest_pid == gAmpChannel))
         {
           VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_LOW,
                      "No msg for AFH will be sent");
            gAmpChannel = dest_pid;
            kfree_skb(skb);
            return;
         }

         gAmpChannel = dest_pid;

         /* Fix overloaded parameters and finish message formatting */
         if(dest_pid != 0)
         {
           aniHdr->type = WLAN_STA_ASSOC_DONE_IND;
           aniHdr->length = sizeof(tWlanAssocData);
           nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + sizeof(tWlanAssocData)));
           assocData = ( tWlanAssocData *)((char*)aniHdr + sizeof(tAniMsgHdr));
           assocData->channel = dest_pid;
           skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr)+ sizeof(tWlanAssocData))));
         }
         else
         {
           aniHdr->type = WLAN_STA_DISASSOC_DONE_IND;
           aniHdr->length = 0;
           nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr)));
           skb_put(skb, NLMSG_SPACE(sizeof(tAniMsgHdr)));
         }
         dest_pid = 0;
         break;

      default:
         VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, 
            "BTC: Attempt to send unknown nlink message %d\n", type);
         kfree_skb(skb);
         return;
   }
   if(dest_pid == 0)
      (void)nl_srv_bcast(skb);
   else
      (void)nl_srv_ucast(skb, dest_pid);
}