18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Linux WiMAX 48c2ecf20Sopenharmony_ci * Generic messaging interface between userspace and driver/device 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (C) 2007-2008 Intel Corporation <linux-wimax@intel.com> 78c2ecf20Sopenharmony_ci * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * This implements a direct communication channel between user space and 108c2ecf20Sopenharmony_ci * the driver/device, by which free form messages can be sent back and 118c2ecf20Sopenharmony_ci * forth. 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * This is intended for device-specific features, vendor quirks, etc. 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * See include/net/wimax.h 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * GENERIC NETLINK ENCODING AND CAPACITY 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * A destination "pipe name" is added to each message; it is up to the 208c2ecf20Sopenharmony_ci * drivers to assign or use those names (if using them at all). 218c2ecf20Sopenharmony_ci * 228c2ecf20Sopenharmony_ci * Messages are encoded as a binary netlink attribute using nla_put() 238c2ecf20Sopenharmony_ci * using type NLA_UNSPEC (as some versions of libnl still in 248c2ecf20Sopenharmony_ci * deployment don't yet understand NLA_BINARY). 258c2ecf20Sopenharmony_ci * 268c2ecf20Sopenharmony_ci * The maximum capacity of this transport is PAGESIZE per message (so 278c2ecf20Sopenharmony_ci * the actual payload will be bit smaller depending on the 288c2ecf20Sopenharmony_ci * netlink/generic netlink attributes and headers). 298c2ecf20Sopenharmony_ci * 308c2ecf20Sopenharmony_ci * RECEPTION OF MESSAGES 318c2ecf20Sopenharmony_ci * 328c2ecf20Sopenharmony_ci * When a message is received from user space, it is passed verbatim 338c2ecf20Sopenharmony_ci * to the driver calling wimax_dev->op_msg_from_user(). The return 348c2ecf20Sopenharmony_ci * value from this function is passed back to user space as an ack 358c2ecf20Sopenharmony_ci * over the generic netlink protocol. 368c2ecf20Sopenharmony_ci * 378c2ecf20Sopenharmony_ci * The stack doesn't do any processing or interpretation of these 388c2ecf20Sopenharmony_ci * messages. 398c2ecf20Sopenharmony_ci * 408c2ecf20Sopenharmony_ci * SENDING MESSAGES 418c2ecf20Sopenharmony_ci * 428c2ecf20Sopenharmony_ci * Messages can be sent with wimax_msg(). 438c2ecf20Sopenharmony_ci * 448c2ecf20Sopenharmony_ci * If the message delivery needs to happen on a different context to 458c2ecf20Sopenharmony_ci * that of its creation, wimax_msg_alloc() can be used to get a 468c2ecf20Sopenharmony_ci * pointer to the message that can be delivered later on with 478c2ecf20Sopenharmony_ci * wimax_msg_send(). 488c2ecf20Sopenharmony_ci * 498c2ecf20Sopenharmony_ci * ROADMAP 508c2ecf20Sopenharmony_ci * 518c2ecf20Sopenharmony_ci * wimax_gnl_doit_msg_from_user() Process a message from user space 528c2ecf20Sopenharmony_ci * wimax_dev_get_by_genl_info() 538c2ecf20Sopenharmony_ci * wimax_dev->op_msg_from_user() Delivery of message to the driver 548c2ecf20Sopenharmony_ci * 558c2ecf20Sopenharmony_ci * wimax_msg() Send a message to user space 568c2ecf20Sopenharmony_ci * wimax_msg_alloc() 578c2ecf20Sopenharmony_ci * wimax_msg_send() 588c2ecf20Sopenharmony_ci */ 598c2ecf20Sopenharmony_ci#include <linux/device.h> 608c2ecf20Sopenharmony_ci#include <linux/slab.h> 618c2ecf20Sopenharmony_ci#include <net/genetlink.h> 628c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 638c2ecf20Sopenharmony_ci#include <linux/wimax.h> 648c2ecf20Sopenharmony_ci#include <linux/security.h> 658c2ecf20Sopenharmony_ci#include <linux/export.h> 668c2ecf20Sopenharmony_ci#include "wimax-internal.h" 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci#define D_SUBMODULE op_msg 708c2ecf20Sopenharmony_ci#include "debug-levels.h" 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci/** 748c2ecf20Sopenharmony_ci * wimax_msg_alloc - Create a new skb for sending a message to userspace 758c2ecf20Sopenharmony_ci * 768c2ecf20Sopenharmony_ci * @wimax_dev: WiMAX device descriptor 778c2ecf20Sopenharmony_ci * @pipe_name: "named pipe" the message will be sent to 788c2ecf20Sopenharmony_ci * @msg: pointer to the message data to send 798c2ecf20Sopenharmony_ci * @size: size of the message to send (in bytes), including the header. 808c2ecf20Sopenharmony_ci * @gfp_flags: flags for memory allocation. 818c2ecf20Sopenharmony_ci * 828c2ecf20Sopenharmony_ci * Returns: %0 if ok, negative errno code on error 838c2ecf20Sopenharmony_ci * 848c2ecf20Sopenharmony_ci * Description: 858c2ecf20Sopenharmony_ci * 868c2ecf20Sopenharmony_ci * Allocates an skb that will contain the message to send to user 878c2ecf20Sopenharmony_ci * space over the messaging pipe and initializes it, copying the 888c2ecf20Sopenharmony_ci * payload. 898c2ecf20Sopenharmony_ci * 908c2ecf20Sopenharmony_ci * Once this call is done, you can deliver it with 918c2ecf20Sopenharmony_ci * wimax_msg_send(). 928c2ecf20Sopenharmony_ci * 938c2ecf20Sopenharmony_ci * IMPORTANT: 948c2ecf20Sopenharmony_ci * 958c2ecf20Sopenharmony_ci * Don't use skb_push()/skb_pull()/skb_reserve() on the skb, as 968c2ecf20Sopenharmony_ci * wimax_msg_send() depends on skb->data being placed at the 978c2ecf20Sopenharmony_ci * beginning of the user message. 988c2ecf20Sopenharmony_ci * 998c2ecf20Sopenharmony_ci * Unlike other WiMAX stack calls, this call can be used way early, 1008c2ecf20Sopenharmony_ci * even before wimax_dev_add() is called, as long as the 1018c2ecf20Sopenharmony_ci * wimax_dev->net_dev pointer is set to point to a proper 1028c2ecf20Sopenharmony_ci * net_dev. This is so that drivers can use it early in case they need 1038c2ecf20Sopenharmony_ci * to send stuff around or communicate with user space. 1048c2ecf20Sopenharmony_ci */ 1058c2ecf20Sopenharmony_cistruct sk_buff *wimax_msg_alloc(struct wimax_dev *wimax_dev, 1068c2ecf20Sopenharmony_ci const char *pipe_name, 1078c2ecf20Sopenharmony_ci const void *msg, size_t size, 1088c2ecf20Sopenharmony_ci gfp_t gfp_flags) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci int result; 1118c2ecf20Sopenharmony_ci struct device *dev = wimax_dev_to_dev(wimax_dev); 1128c2ecf20Sopenharmony_ci size_t msg_size; 1138c2ecf20Sopenharmony_ci void *genl_msg; 1148c2ecf20Sopenharmony_ci struct sk_buff *skb; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci msg_size = nla_total_size(size) 1178c2ecf20Sopenharmony_ci + nla_total_size(sizeof(u32)) 1188c2ecf20Sopenharmony_ci + (pipe_name ? nla_total_size(strlen(pipe_name)) : 0); 1198c2ecf20Sopenharmony_ci result = -ENOMEM; 1208c2ecf20Sopenharmony_ci skb = genlmsg_new(msg_size, gfp_flags); 1218c2ecf20Sopenharmony_ci if (skb == NULL) 1228c2ecf20Sopenharmony_ci goto error_new; 1238c2ecf20Sopenharmony_ci genl_msg = genlmsg_put(skb, 0, 0, &wimax_gnl_family, 1248c2ecf20Sopenharmony_ci 0, WIMAX_GNL_OP_MSG_TO_USER); 1258c2ecf20Sopenharmony_ci if (genl_msg == NULL) { 1268c2ecf20Sopenharmony_ci dev_err(dev, "no memory to create generic netlink message\n"); 1278c2ecf20Sopenharmony_ci goto error_genlmsg_put; 1288c2ecf20Sopenharmony_ci } 1298c2ecf20Sopenharmony_ci result = nla_put_u32(skb, WIMAX_GNL_MSG_IFIDX, 1308c2ecf20Sopenharmony_ci wimax_dev->net_dev->ifindex); 1318c2ecf20Sopenharmony_ci if (result < 0) { 1328c2ecf20Sopenharmony_ci dev_err(dev, "no memory to add ifindex attribute\n"); 1338c2ecf20Sopenharmony_ci goto error_nla_put; 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci if (pipe_name) { 1368c2ecf20Sopenharmony_ci result = nla_put_string(skb, WIMAX_GNL_MSG_PIPE_NAME, 1378c2ecf20Sopenharmony_ci pipe_name); 1388c2ecf20Sopenharmony_ci if (result < 0) { 1398c2ecf20Sopenharmony_ci dev_err(dev, "no memory to add pipe_name attribute\n"); 1408c2ecf20Sopenharmony_ci goto error_nla_put; 1418c2ecf20Sopenharmony_ci } 1428c2ecf20Sopenharmony_ci } 1438c2ecf20Sopenharmony_ci result = nla_put(skb, WIMAX_GNL_MSG_DATA, size, msg); 1448c2ecf20Sopenharmony_ci if (result < 0) { 1458c2ecf20Sopenharmony_ci dev_err(dev, "no memory to add payload (msg %p size %zu) in " 1468c2ecf20Sopenharmony_ci "attribute: %d\n", msg, size, result); 1478c2ecf20Sopenharmony_ci goto error_nla_put; 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci genlmsg_end(skb, genl_msg); 1508c2ecf20Sopenharmony_ci return skb; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_cierror_nla_put: 1538c2ecf20Sopenharmony_cierror_genlmsg_put: 1548c2ecf20Sopenharmony_cierror_new: 1558c2ecf20Sopenharmony_ci nlmsg_free(skb); 1568c2ecf20Sopenharmony_ci return ERR_PTR(result); 1578c2ecf20Sopenharmony_ci} 1588c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(wimax_msg_alloc); 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci/** 1628c2ecf20Sopenharmony_ci * wimax_msg_data_len - Return a pointer and size of a message's payload 1638c2ecf20Sopenharmony_ci * 1648c2ecf20Sopenharmony_ci * @msg: Pointer to a message created with wimax_msg_alloc() 1658c2ecf20Sopenharmony_ci * @size: Pointer to where to store the message's size 1668c2ecf20Sopenharmony_ci * 1678c2ecf20Sopenharmony_ci * Returns the pointer to the message data. 1688c2ecf20Sopenharmony_ci */ 1698c2ecf20Sopenharmony_ciconst void *wimax_msg_data_len(struct sk_buff *msg, size_t *size) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci struct nlmsghdr *nlh = (void *) msg->head; 1728c2ecf20Sopenharmony_ci struct nlattr *nla; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci nla = nlmsg_find_attr(nlh, sizeof(struct genlmsghdr), 1758c2ecf20Sopenharmony_ci WIMAX_GNL_MSG_DATA); 1768c2ecf20Sopenharmony_ci if (nla == NULL) { 1778c2ecf20Sopenharmony_ci pr_err("Cannot find attribute WIMAX_GNL_MSG_DATA\n"); 1788c2ecf20Sopenharmony_ci return NULL; 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci *size = nla_len(nla); 1818c2ecf20Sopenharmony_ci return nla_data(nla); 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(wimax_msg_data_len); 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci/** 1878c2ecf20Sopenharmony_ci * wimax_msg_data - Return a pointer to a message's payload 1888c2ecf20Sopenharmony_ci * 1898c2ecf20Sopenharmony_ci * @msg: Pointer to a message created with wimax_msg_alloc() 1908c2ecf20Sopenharmony_ci */ 1918c2ecf20Sopenharmony_ciconst void *wimax_msg_data(struct sk_buff *msg) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci struct nlmsghdr *nlh = (void *) msg->head; 1948c2ecf20Sopenharmony_ci struct nlattr *nla; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci nla = nlmsg_find_attr(nlh, sizeof(struct genlmsghdr), 1978c2ecf20Sopenharmony_ci WIMAX_GNL_MSG_DATA); 1988c2ecf20Sopenharmony_ci if (nla == NULL) { 1998c2ecf20Sopenharmony_ci pr_err("Cannot find attribute WIMAX_GNL_MSG_DATA\n"); 2008c2ecf20Sopenharmony_ci return NULL; 2018c2ecf20Sopenharmony_ci } 2028c2ecf20Sopenharmony_ci return nla_data(nla); 2038c2ecf20Sopenharmony_ci} 2048c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(wimax_msg_data); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci/** 2088c2ecf20Sopenharmony_ci * wimax_msg_len - Return a message's payload length 2098c2ecf20Sopenharmony_ci * 2108c2ecf20Sopenharmony_ci * @msg: Pointer to a message created with wimax_msg_alloc() 2118c2ecf20Sopenharmony_ci */ 2128c2ecf20Sopenharmony_cissize_t wimax_msg_len(struct sk_buff *msg) 2138c2ecf20Sopenharmony_ci{ 2148c2ecf20Sopenharmony_ci struct nlmsghdr *nlh = (void *) msg->head; 2158c2ecf20Sopenharmony_ci struct nlattr *nla; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci nla = nlmsg_find_attr(nlh, sizeof(struct genlmsghdr), 2188c2ecf20Sopenharmony_ci WIMAX_GNL_MSG_DATA); 2198c2ecf20Sopenharmony_ci if (nla == NULL) { 2208c2ecf20Sopenharmony_ci pr_err("Cannot find attribute WIMAX_GNL_MSG_DATA\n"); 2218c2ecf20Sopenharmony_ci return -EINVAL; 2228c2ecf20Sopenharmony_ci } 2238c2ecf20Sopenharmony_ci return nla_len(nla); 2248c2ecf20Sopenharmony_ci} 2258c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(wimax_msg_len); 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci/** 2298c2ecf20Sopenharmony_ci * wimax_msg_send - Send a pre-allocated message to user space 2308c2ecf20Sopenharmony_ci * 2318c2ecf20Sopenharmony_ci * @wimax_dev: WiMAX device descriptor 2328c2ecf20Sopenharmony_ci * 2338c2ecf20Sopenharmony_ci * @skb: &struct sk_buff returned by wimax_msg_alloc(). Note the 2348c2ecf20Sopenharmony_ci * ownership of @skb is transferred to this function. 2358c2ecf20Sopenharmony_ci * 2368c2ecf20Sopenharmony_ci * Returns: 0 if ok, < 0 errno code on error 2378c2ecf20Sopenharmony_ci * 2388c2ecf20Sopenharmony_ci * Description: 2398c2ecf20Sopenharmony_ci * 2408c2ecf20Sopenharmony_ci * Sends a free-form message that was preallocated with 2418c2ecf20Sopenharmony_ci * wimax_msg_alloc() and filled up. 2428c2ecf20Sopenharmony_ci * 2438c2ecf20Sopenharmony_ci * Assumes that once you pass an skb to this function for sending, it 2448c2ecf20Sopenharmony_ci * owns it and will release it when done (on success). 2458c2ecf20Sopenharmony_ci * 2468c2ecf20Sopenharmony_ci * IMPORTANT: 2478c2ecf20Sopenharmony_ci * 2488c2ecf20Sopenharmony_ci * Don't use skb_push()/skb_pull()/skb_reserve() on the skb, as 2498c2ecf20Sopenharmony_ci * wimax_msg_send() depends on skb->data being placed at the 2508c2ecf20Sopenharmony_ci * beginning of the user message. 2518c2ecf20Sopenharmony_ci * 2528c2ecf20Sopenharmony_ci * Unlike other WiMAX stack calls, this call can be used way early, 2538c2ecf20Sopenharmony_ci * even before wimax_dev_add() is called, as long as the 2548c2ecf20Sopenharmony_ci * wimax_dev->net_dev pointer is set to point to a proper 2558c2ecf20Sopenharmony_ci * net_dev. This is so that drivers can use it early in case they need 2568c2ecf20Sopenharmony_ci * to send stuff around or communicate with user space. 2578c2ecf20Sopenharmony_ci */ 2588c2ecf20Sopenharmony_ciint wimax_msg_send(struct wimax_dev *wimax_dev, struct sk_buff *skb) 2598c2ecf20Sopenharmony_ci{ 2608c2ecf20Sopenharmony_ci struct device *dev = wimax_dev_to_dev(wimax_dev); 2618c2ecf20Sopenharmony_ci void *msg = skb->data; 2628c2ecf20Sopenharmony_ci size_t size = skb->len; 2638c2ecf20Sopenharmony_ci might_sleep(); 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci d_printf(1, dev, "CTX: wimax msg, %zu bytes\n", size); 2668c2ecf20Sopenharmony_ci d_dump(2, dev, msg, size); 2678c2ecf20Sopenharmony_ci genlmsg_multicast(&wimax_gnl_family, skb, 0, 0, GFP_KERNEL); 2688c2ecf20Sopenharmony_ci d_printf(1, dev, "CTX: genl multicast done\n"); 2698c2ecf20Sopenharmony_ci return 0; 2708c2ecf20Sopenharmony_ci} 2718c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(wimax_msg_send); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci/** 2758c2ecf20Sopenharmony_ci * wimax_msg - Send a message to user space 2768c2ecf20Sopenharmony_ci * 2778c2ecf20Sopenharmony_ci * @wimax_dev: WiMAX device descriptor (properly referenced) 2788c2ecf20Sopenharmony_ci * @pipe_name: "named pipe" the message will be sent to 2798c2ecf20Sopenharmony_ci * @buf: pointer to the message to send. 2808c2ecf20Sopenharmony_ci * @size: size of the buffer pointed to by @buf (in bytes). 2818c2ecf20Sopenharmony_ci * @gfp_flags: flags for memory allocation. 2828c2ecf20Sopenharmony_ci * 2838c2ecf20Sopenharmony_ci * Returns: %0 if ok, negative errno code on error. 2848c2ecf20Sopenharmony_ci * 2858c2ecf20Sopenharmony_ci * Description: 2868c2ecf20Sopenharmony_ci * 2878c2ecf20Sopenharmony_ci * Sends a free-form message to user space on the device @wimax_dev. 2888c2ecf20Sopenharmony_ci * 2898c2ecf20Sopenharmony_ci * NOTES: 2908c2ecf20Sopenharmony_ci * 2918c2ecf20Sopenharmony_ci * Once the @skb is given to this function, who will own it and will 2928c2ecf20Sopenharmony_ci * release it when done (unless it returns error). 2938c2ecf20Sopenharmony_ci */ 2948c2ecf20Sopenharmony_ciint wimax_msg(struct wimax_dev *wimax_dev, const char *pipe_name, 2958c2ecf20Sopenharmony_ci const void *buf, size_t size, gfp_t gfp_flags) 2968c2ecf20Sopenharmony_ci{ 2978c2ecf20Sopenharmony_ci int result = -ENOMEM; 2988c2ecf20Sopenharmony_ci struct sk_buff *skb; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci skb = wimax_msg_alloc(wimax_dev, pipe_name, buf, size, gfp_flags); 3018c2ecf20Sopenharmony_ci if (IS_ERR(skb)) 3028c2ecf20Sopenharmony_ci result = PTR_ERR(skb); 3038c2ecf20Sopenharmony_ci else 3048c2ecf20Sopenharmony_ci result = wimax_msg_send(wimax_dev, skb); 3058c2ecf20Sopenharmony_ci return result; 3068c2ecf20Sopenharmony_ci} 3078c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(wimax_msg); 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci/* 3108c2ecf20Sopenharmony_ci * Relays a message from user space to the driver 3118c2ecf20Sopenharmony_ci * 3128c2ecf20Sopenharmony_ci * The skb is passed to the driver-specific function with the netlink 3138c2ecf20Sopenharmony_ci * and generic netlink headers already stripped. 3148c2ecf20Sopenharmony_ci * 3158c2ecf20Sopenharmony_ci * This call will block while handling/relaying the message. 3168c2ecf20Sopenharmony_ci */ 3178c2ecf20Sopenharmony_ciint wimax_gnl_doit_msg_from_user(struct sk_buff *skb, struct genl_info *info) 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci int result, ifindex; 3208c2ecf20Sopenharmony_ci struct wimax_dev *wimax_dev; 3218c2ecf20Sopenharmony_ci struct device *dev; 3228c2ecf20Sopenharmony_ci struct nlmsghdr *nlh = info->nlhdr; 3238c2ecf20Sopenharmony_ci char *pipe_name; 3248c2ecf20Sopenharmony_ci void *msg_buf; 3258c2ecf20Sopenharmony_ci size_t msg_len; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci might_sleep(); 3288c2ecf20Sopenharmony_ci d_fnstart(3, NULL, "(skb %p info %p)\n", skb, info); 3298c2ecf20Sopenharmony_ci result = -ENODEV; 3308c2ecf20Sopenharmony_ci if (info->attrs[WIMAX_GNL_MSG_IFIDX] == NULL) { 3318c2ecf20Sopenharmony_ci pr_err("WIMAX_GNL_MSG_FROM_USER: can't find IFIDX attribute\n"); 3328c2ecf20Sopenharmony_ci goto error_no_wimax_dev; 3338c2ecf20Sopenharmony_ci } 3348c2ecf20Sopenharmony_ci ifindex = nla_get_u32(info->attrs[WIMAX_GNL_MSG_IFIDX]); 3358c2ecf20Sopenharmony_ci wimax_dev = wimax_dev_get_by_genl_info(info, ifindex); 3368c2ecf20Sopenharmony_ci if (wimax_dev == NULL) 3378c2ecf20Sopenharmony_ci goto error_no_wimax_dev; 3388c2ecf20Sopenharmony_ci dev = wimax_dev_to_dev(wimax_dev); 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci /* Unpack arguments */ 3418c2ecf20Sopenharmony_ci result = -EINVAL; 3428c2ecf20Sopenharmony_ci if (info->attrs[WIMAX_GNL_MSG_DATA] == NULL) { 3438c2ecf20Sopenharmony_ci dev_err(dev, "WIMAX_GNL_MSG_FROM_USER: can't find MSG_DATA " 3448c2ecf20Sopenharmony_ci "attribute\n"); 3458c2ecf20Sopenharmony_ci goto error_no_data; 3468c2ecf20Sopenharmony_ci } 3478c2ecf20Sopenharmony_ci msg_buf = nla_data(info->attrs[WIMAX_GNL_MSG_DATA]); 3488c2ecf20Sopenharmony_ci msg_len = nla_len(info->attrs[WIMAX_GNL_MSG_DATA]); 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci if (info->attrs[WIMAX_GNL_MSG_PIPE_NAME] == NULL) 3518c2ecf20Sopenharmony_ci pipe_name = NULL; 3528c2ecf20Sopenharmony_ci else { 3538c2ecf20Sopenharmony_ci struct nlattr *attr = info->attrs[WIMAX_GNL_MSG_PIPE_NAME]; 3548c2ecf20Sopenharmony_ci size_t attr_len = nla_len(attr); 3558c2ecf20Sopenharmony_ci /* libnl-1.1 does not yet support NLA_NUL_STRING */ 3568c2ecf20Sopenharmony_ci result = -ENOMEM; 3578c2ecf20Sopenharmony_ci pipe_name = kstrndup(nla_data(attr), attr_len + 1, GFP_KERNEL); 3588c2ecf20Sopenharmony_ci if (pipe_name == NULL) 3598c2ecf20Sopenharmony_ci goto error_alloc; 3608c2ecf20Sopenharmony_ci pipe_name[attr_len] = 0; 3618c2ecf20Sopenharmony_ci } 3628c2ecf20Sopenharmony_ci mutex_lock(&wimax_dev->mutex); 3638c2ecf20Sopenharmony_ci result = wimax_dev_is_ready(wimax_dev); 3648c2ecf20Sopenharmony_ci if (result == -ENOMEDIUM) 3658c2ecf20Sopenharmony_ci result = 0; 3668c2ecf20Sopenharmony_ci if (result < 0) 3678c2ecf20Sopenharmony_ci goto error_not_ready; 3688c2ecf20Sopenharmony_ci result = -ENOSYS; 3698c2ecf20Sopenharmony_ci if (wimax_dev->op_msg_from_user == NULL) 3708c2ecf20Sopenharmony_ci goto error_noop; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci d_printf(1, dev, 3738c2ecf20Sopenharmony_ci "CRX: nlmsghdr len %u type %u flags 0x%04x seq 0x%x pid %u\n", 3748c2ecf20Sopenharmony_ci nlh->nlmsg_len, nlh->nlmsg_type, nlh->nlmsg_flags, 3758c2ecf20Sopenharmony_ci nlh->nlmsg_seq, nlh->nlmsg_pid); 3768c2ecf20Sopenharmony_ci d_printf(1, dev, "CRX: wimax message %zu bytes\n", msg_len); 3778c2ecf20Sopenharmony_ci d_dump(2, dev, msg_buf, msg_len); 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci result = wimax_dev->op_msg_from_user(wimax_dev, pipe_name, 3808c2ecf20Sopenharmony_ci msg_buf, msg_len, info); 3818c2ecf20Sopenharmony_cierror_noop: 3828c2ecf20Sopenharmony_cierror_not_ready: 3838c2ecf20Sopenharmony_ci mutex_unlock(&wimax_dev->mutex); 3848c2ecf20Sopenharmony_cierror_alloc: 3858c2ecf20Sopenharmony_ci kfree(pipe_name); 3868c2ecf20Sopenharmony_cierror_no_data: 3878c2ecf20Sopenharmony_ci dev_put(wimax_dev->net_dev); 3888c2ecf20Sopenharmony_cierror_no_wimax_dev: 3898c2ecf20Sopenharmony_ci d_fnend(3, NULL, "(skb %p info %p) = %d\n", skb, info, result); 3908c2ecf20Sopenharmony_ci return result; 3918c2ecf20Sopenharmony_ci} 392