1 /* 2 * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for 6 * any purpose with or without fee is hereby granted, provided that the 7 * above copyright notice and this permission notice appear in all 8 * copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /****************************************************************************** 21 * wlan_ptt_sock_svc.c 22 * 23 ******************************************************************************/ 24 #ifdef PTT_SOCK_SVC_ENABLE 25 #include <wlan_nlink_srv.h> 26 #include <qdf_types.h> 27 #include <qdf_status.h> 28 #include <qdf_trace.h> 29 #include <wlan_nlink_common.h> 30 #include <wlan_ptt_sock_svc.h> 31 #include <qdf_types.h> 32 #include <qdf_trace.h> 33 34 #ifdef CNSS_GENL 35 #ifdef CONFIG_CNSS_OUT_OF_TREE 36 #include "cnss_nl.h" 37 #else 38 #include <net/cnss_nl.h> 39 #endif 40 #include <wlan_cfg80211.h> 41 #endif 42 43 #define PTT_SOCK_DEBUG 44 #ifdef PTT_SOCK_DEBUG 45 #define PTT_TRACE(level, args ...) QDF_TRACE(QDF_MODULE_ID_QDF, level, ## args) 46 #else 47 #define PTT_TRACE(level, args ...) 48 #endif 49 50 #ifdef PTT_SOCK_DEBUG_VERBOSE 51 /* Utility function to perform a hex dump */ ptt_sock_dump_buf(const unsigned char * pbuf,int cnt)52 static void ptt_sock_dump_buf(const unsigned char *pbuf, int cnt) 53 { 54 int i; 55 56 for (i = 0; i < cnt; i++) { 57 if ((i % 16) == 0) 58 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO, 59 "\n%pK:", pbuf); 60 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO, " %02X", 61 *pbuf); 62 pbuf++; 63 } 64 QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO, "\n"); 65 } 66 #endif 67 68 /** 69 * nl_srv_ucast_ptt() - Wrapper function to send ucast msgs to PTT 70 * @skb: sk buffer pointer 71 * @dst_pid: Destination PID 72 * @flag: flags 73 * 74 * Sends the ucast message to PTT with generic nl socket if CNSS_GENL 75 * is enabled. Else, use the legacy netlink socket to send. 76 * 77 * Return: zero on success, error code otherwise 78 */ nl_srv_ucast_ptt(struct sk_buff * skb,int dst_pid,int flag)79 static int nl_srv_ucast_ptt(struct sk_buff *skb, int dst_pid, int flag) 80 { 81 #ifdef CNSS_GENL 82 return nl_srv_ucast(skb, dst_pid, flag, ANI_NL_MSG_PUMAC, 83 CLD80211_MCGRP_DIAG_EVENTS); 84 #else 85 return nl_srv_ucast(skb, dst_pid, flag); 86 #endif 87 } 88 89 /** 90 * nl_srv_bcast_ptt() - Wrapper function to send bcast msgs to DIAG mcast group 91 * @skb: sk buffer pointer 92 * 93 * Sends the bcast message to DIAG multicast group with generic nl socket 94 * if CNSS_GENL is enabled. Else, use the legacy netlink socket to send. 95 * 96 * Return: zero on success, error code otherwise 97 */ nl_srv_bcast_ptt(struct sk_buff * skb)98 static int nl_srv_bcast_ptt(struct sk_buff *skb) 99 { 100 #ifdef CNSS_GENL 101 return nl_srv_bcast(skb, CLD80211_MCGRP_DIAG_EVENTS, ANI_NL_MSG_PUMAC); 102 #else 103 return nl_srv_bcast(skb); 104 #endif 105 } 106 107 /** 108 * ptt_sock_send_msg_to_app() - Send nl message to user space 109 * wmsg: Message header 110 * radio: Unit number of the radio 111 * src_mod: Message type 112 * pid: Process ID to which message will be unicast. Message 113 * will be broadcast when PID is INVALID_PID 114 * 115 * Utility function to send a netlink message to an application in user space 116 * 117 * Return: 0 on success and negative value on failure 118 */ ptt_sock_send_msg_to_app(tAniHdr * wmsg,int radio,int src_mod,int pid)119 int ptt_sock_send_msg_to_app(tAniHdr *wmsg, int radio, int src_mod, int pid) 120 { 121 int err = -1; 122 int payload_len; 123 int tot_msg_len; 124 tAniNlHdr *wnl; 125 struct sk_buff *skb; 126 struct nlmsghdr *nlh; 127 int wmsg_length = be16_to_cpu(wmsg->length); 128 static int nlmsg_seq; 129 130 if (radio < 0 || radio > ANI_MAX_RADIOS) { 131 PTT_TRACE(QDF_TRACE_LEVEL_ERROR, "%s: invalid radio id [%d]\n", 132 __func__, radio); 133 return -EINVAL; 134 } 135 payload_len = wmsg_length + sizeof(wnl->radio) + sizeof(*wmsg); 136 tot_msg_len = NLMSG_SPACE(payload_len); 137 skb = dev_alloc_skb(tot_msg_len); 138 if (!skb) { 139 PTT_TRACE(QDF_TRACE_LEVEL_ERROR, 140 "%s: dev_alloc_skb() failed for msg size[%d]\n", 141 __func__, tot_msg_len); 142 return -ENOMEM; 143 } 144 nlh = 145 nlmsg_put(skb, pid, nlmsg_seq++, src_mod, payload_len, 146 NLM_F_REQUEST); 147 if (!nlh) { 148 PTT_TRACE(QDF_TRACE_LEVEL_ERROR, 149 "%s: nlmsg_put() failed for msg size[%d]\n", __func__, 150 tot_msg_len); 151 kfree_skb(skb); 152 return -ENOMEM; 153 } 154 wnl = (tAniNlHdr *) nlh; 155 wnl->radio = radio; 156 157 /* Offset of data buffer from nlmsg_hdr + sizeof(int) radio */ 158 memcpy(nlmsg_data(nlh) + sizeof(wnl->radio), wmsg, wmsg_length); 159 #ifdef PTT_SOCK_DEBUG_VERBOSE 160 ptt_sock_dump_buf((const unsigned char *)skb->data, skb->len); 161 #endif 162 163 if (pid != INVALID_PID) 164 err = nl_srv_ucast_ptt(skb, pid, MSG_DONTWAIT); 165 else 166 err = nl_srv_bcast_ptt(skb); 167 168 if ((err < 0) && (err != -ESRCH)) 169 PTT_TRACE(QDF_TRACE_LEVEL_INFO, 170 "%s:Failed sending Msg Type [0x%X] to pid[%d]\n", 171 __func__, be16_to_cpu(wmsg->type), pid); 172 return err; 173 } 174 175 #ifdef CNSS_GENL 176 /** 177 * ptt_cmd_handler() - Handler function for PTT commands 178 * @data: Data to be parsed 179 * @data_len: Length of the data received 180 * @ctx: Registered context reference 181 * @pid: Process id of the user space application 182 * 183 * This function handles the command from PTT user space application 184 * 185 * Return: None 186 */ ptt_cmd_handler(const void * data,int data_len,void * ctx,int pid)187 static void ptt_cmd_handler(const void *data, int data_len, void *ctx, int pid) 188 { 189 uint16_t length; 190 struct sptt_app_reg_req *payload; 191 struct nlattr *tb[CLD80211_ATTR_MAX + 1]; 192 193 /* 194 * audit note: it is ok to pass a NULL policy here since a 195 * length check on the data is added later already 196 */ 197 if (wlan_cfg80211_nla_parse(tb, CLD80211_ATTR_MAX, 198 data, data_len, NULL)) { 199 PTT_TRACE(QDF_TRACE_LEVEL_ERROR, "Invalid ATTR"); 200 return; 201 } 202 203 if (!tb[CLD80211_ATTR_DATA]) { 204 PTT_TRACE(QDF_TRACE_LEVEL_ERROR, "attr ATTR_DATA failed"); 205 return; 206 } 207 208 if (nla_len(tb[CLD80211_ATTR_DATA]) < sizeof(struct sptt_app_reg_req)) { 209 PTT_TRACE(QDF_TRACE_LEVEL_ERROR, "%s:attr length check fails\n", 210 __func__); 211 return; 212 } 213 214 payload = (struct sptt_app_reg_req *)(nla_data(tb[CLD80211_ATTR_DATA])); 215 length = be16_to_cpu(payload->wmsg.length); 216 if ((USHRT_MAX - length) < (sizeof(payload->radio) + sizeof(tAniHdr))) { 217 PTT_TRACE(QDF_TRACE_LEVEL_ERROR, 218 "u16 overflow length %d %zu %zu", 219 length, 220 sizeof(payload->radio), 221 sizeof(tAniHdr)); 222 return; 223 } 224 225 if (nla_len(tb[CLD80211_ATTR_DATA]) < (length + 226 sizeof(payload->radio) + 227 sizeof(tAniHdr))) { 228 PTT_TRACE(QDF_TRACE_LEVEL_ERROR, "ATTR_DATA len check failed"); 229 return; 230 } 231 232 switch (payload->wmsg.type) { 233 case ANI_MSG_APP_REG_REQ: 234 ptt_sock_send_msg_to_app(&payload->wmsg, payload->radio, 235 ANI_NL_MSG_PUMAC, pid); 236 break; 237 default: 238 PTT_TRACE(QDF_TRACE_LEVEL_ERROR, "Unknown msg type %d", 239 payload->wmsg.type); 240 break; 241 } 242 } 243 ptt_sock_activate_svc(void)244 void ptt_sock_activate_svc(void) 245 { 246 register_cld_cmd_cb(ANI_NL_MSG_PUMAC, ptt_cmd_handler, NULL); 247 register_cld_cmd_cb(ANI_NL_MSG_PTT, ptt_cmd_handler, NULL); 248 } 249 ptt_sock_deactivate_svc(void)250 void ptt_sock_deactivate_svc(void) 251 { 252 deregister_cld_cmd_cb(ANI_NL_MSG_PTT); 253 deregister_cld_cmd_cb(ANI_NL_MSG_PUMAC); 254 } 255 #endif 256 #endif /* PTT_SOCK_SVC_ENABLE */ 257