13e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez/* 23e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * Linux WiMAX 33e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * Generic messaging interface between userspace and driver/device 43e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * 53e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * 63e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * Copyright (C) 2007-2008 Intel Corporation <linux-wimax@intel.com> 73e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> 83e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * 93e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * This program is free software; you can redistribute it and/or 103e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * modify it under the terms of the GNU General Public License version 113e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * 2 as published by the Free Software Foundation. 123e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * 133e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * This program is distributed in the hope that it will be useful, 143e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * but WITHOUT ANY WARRANTY; without even the implied warranty of 153e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 163e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * GNU General Public License for more details. 173e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * 183e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * You should have received a copy of the GNU General Public License 193e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * along with this program; if not, write to the Free Software 203e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 213e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * 02110-1301, USA. 223e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * 233e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * 243e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * This implements a direct communication channel between user space and 253e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * the driver/device, by which free form messages can be sent back and 263e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * forth. 273e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * 283e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * This is intended for device-specific features, vendor quirks, etc. 293e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * 303e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * See include/net/wimax.h 313e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * 323e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * GENERIC NETLINK ENCODING AND CAPACITY 333e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * 343e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * A destination "pipe name" is added to each message; it is up to the 353e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * drivers to assign or use those names (if using them at all). 363e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * 373e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * Messages are encoded as a binary netlink attribute using nla_put() 383e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * using type NLA_UNSPEC (as some versions of libnl still in 393e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * deployment don't yet understand NLA_BINARY). 403e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * 413e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * The maximum capacity of this transport is PAGESIZE per message (so 423e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * the actual payload will be bit smaller depending on the 433e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * netlink/generic netlink attributes and headers). 443e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * 453e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * RECEPTION OF MESSAGES 463e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * 473e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * When a message is received from user space, it is passed verbatim 483e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * to the driver calling wimax_dev->op_msg_from_user(). The return 493e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * value from this function is passed back to user space as an ack 503e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * over the generic netlink protocol. 513e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * 523e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * The stack doesn't do any processing or interpretation of these 533e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * messages. 543e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * 553e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * SENDING MESSAGES 563e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * 573e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * Messages can be sent with wimax_msg(). 583e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * 593e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * If the message delivery needs to happen on a different context to 603e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * that of its creation, wimax_msg_alloc() can be used to get a 613e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * pointer to the message that can be delivered later on with 623e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * wimax_msg_send(). 633e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * 643e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * ROADMAP 653e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * 663e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * wimax_gnl_doit_msg_from_user() Process a message from user space 673e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * wimax_dev_get_by_genl_info() 683e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * wimax_dev->op_msg_from_user() Delivery of message to the driver 693e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * 703e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * wimax_msg() Send a message to user space 713e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * wimax_msg_alloc() 723e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * wimax_msg_send() 733e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez */ 743e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez#include <linux/device.h> 755a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 763e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez#include <net/genetlink.h> 773e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez#include <linux/netdevice.h> 783e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez#include <linux/wimax.h> 793e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez#include <linux/security.h> 80bc3b2d7fb9b014d75ebb79ba371a763dbab5e8cfPaul Gortmaker#include <linux/export.h> 813e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez#include "wimax-internal.h" 823e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez 833e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez 843e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez#define D_SUBMODULE op_msg 853e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez#include "debug-levels.h" 863e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez 873e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez 883e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez/** 893e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * wimax_msg_alloc - Create a new skb for sending a message to userspace 903e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * 913e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * @wimax_dev: WiMAX device descriptor 923e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * @pipe_name: "named pipe" the message will be sent to 933e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * @msg: pointer to the message data to send 943e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * @size: size of the message to send (in bytes), including the header. 953e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * @gfp_flags: flags for memory allocation. 963e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * 973e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * Returns: %0 if ok, negative errno code on error 983e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * 993e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * Description: 1003e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * 1013e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * Allocates an skb that will contain the message to send to user 1023e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * space over the messaging pipe and initializes it, copying the 1033e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * payload. 1043e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * 1053e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * Once this call is done, you can deliver it with 1063e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * wimax_msg_send(). 1073e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * 1083e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * IMPORTANT: 1093e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * 1103e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * Don't use skb_push()/skb_pull()/skb_reserve() on the skb, as 1113e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * wimax_msg_send() depends on skb->data being placed at the 1123e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * beginning of the user message. 11352a8d9630890f2289354d03e8751bf0eba2b3376Inaky Perez-Gonzalez * 11452a8d9630890f2289354d03e8751bf0eba2b3376Inaky Perez-Gonzalez * Unlike other WiMAX stack calls, this call can be used way early, 11552a8d9630890f2289354d03e8751bf0eba2b3376Inaky Perez-Gonzalez * even before wimax_dev_add() is called, as long as the 11652a8d9630890f2289354d03e8751bf0eba2b3376Inaky Perez-Gonzalez * wimax_dev->net_dev pointer is set to point to a proper 11752a8d9630890f2289354d03e8751bf0eba2b3376Inaky Perez-Gonzalez * net_dev. This is so that drivers can use it early in case they need 11852a8d9630890f2289354d03e8751bf0eba2b3376Inaky Perez-Gonzalez * to send stuff around or communicate with user space. 1193e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez */ 1203e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalezstruct sk_buff *wimax_msg_alloc(struct wimax_dev *wimax_dev, 1213e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez const char *pipe_name, 1223e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez const void *msg, size_t size, 1233e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez gfp_t gfp_flags) 1243e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez{ 1253e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez int result; 12652a8d9630890f2289354d03e8751bf0eba2b3376Inaky Perez-Gonzalez struct device *dev = wimax_dev_to_dev(wimax_dev); 1273e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez size_t msg_size; 1283e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez void *genl_msg; 1293e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez struct sk_buff *skb; 1303e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez 1313e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez msg_size = nla_total_size(size) 1323e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez + nla_total_size(sizeof(u32)) 1333e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez + (pipe_name ? nla_total_size(strlen(pipe_name)) : 0); 1343e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez result = -ENOMEM; 1353e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez skb = genlmsg_new(msg_size, gfp_flags); 1363e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez if (skb == NULL) 1373e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez goto error_new; 1383e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez genl_msg = genlmsg_put(skb, 0, 0, &wimax_gnl_family, 1393e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez 0, WIMAX_GNL_OP_MSG_TO_USER); 1403e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez if (genl_msg == NULL) { 1413e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez dev_err(dev, "no memory to create generic netlink message\n"); 1423e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez goto error_genlmsg_put; 1433e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez } 1443e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez result = nla_put_u32(skb, WIMAX_GNL_MSG_IFIDX, 1453e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez wimax_dev->net_dev->ifindex); 1463e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez if (result < 0) { 1473e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez dev_err(dev, "no memory to add ifindex attribute\n"); 1483e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez goto error_nla_put; 1493e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez } 1503e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez if (pipe_name) { 1513e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez result = nla_put_string(skb, WIMAX_GNL_MSG_PIPE_NAME, 1523e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez pipe_name); 1533e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez if (result < 0) { 1543e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez dev_err(dev, "no memory to add pipe_name attribute\n"); 1553e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez goto error_nla_put; 1563e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez } 1573e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez } 1583e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez result = nla_put(skb, WIMAX_GNL_MSG_DATA, size, msg); 1593e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez if (result < 0) { 160d1a2627a29667fe7c4a9d06e1579a2d65bd39bbaInaky Perez-Gonzalez dev_err(dev, "no memory to add payload (msg %p size %zu) in " 161d1a2627a29667fe7c4a9d06e1579a2d65bd39bbaInaky Perez-Gonzalez "attribute: %d\n", msg, size, result); 1623e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez goto error_nla_put; 1633e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez } 1643e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez genlmsg_end(skb, genl_msg); 1653e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez return skb; 1663e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez 1673e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalezerror_nla_put: 1683e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalezerror_genlmsg_put: 1693e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalezerror_new: 1703e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez nlmsg_free(skb); 1713e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez return ERR_PTR(result); 1723e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez} 1733e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-GonzalezEXPORT_SYMBOL_GPL(wimax_msg_alloc); 1743e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez 1753e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez 1763e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez/** 1773e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * wimax_msg_data_len - Return a pointer and size of a message's payload 1783e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * 1793e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * @msg: Pointer to a message created with wimax_msg_alloc() 1803e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * @size: Pointer to where to store the message's size 1813e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * 1823e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * Returns the pointer to the message data. 1833e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez */ 1843e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalezconst void *wimax_msg_data_len(struct sk_buff *msg, size_t *size) 1853e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez{ 1863e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez struct nlmsghdr *nlh = (void *) msg->head; 1873e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez struct nlattr *nla; 1883e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez 1893e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez nla = nlmsg_find_attr(nlh, sizeof(struct genlmsghdr), 1903e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez WIMAX_GNL_MSG_DATA); 1913e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez if (nla == NULL) { 19228b7deae75642c51f097391765fd39ff0dd6ce95Fabian Frederick pr_err("Cannot find attribute WIMAX_GNL_MSG_DATA\n"); 1933e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez return NULL; 1943e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez } 1953e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez *size = nla_len(nla); 1963e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez return nla_data(nla); 1973e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez} 1983e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-GonzalezEXPORT_SYMBOL_GPL(wimax_msg_data_len); 1993e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez 2003e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez 2013e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez/** 2023e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * wimax_msg_data - Return a pointer to a message's payload 2033e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * 2043e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * @msg: Pointer to a message created with wimax_msg_alloc() 2053e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez */ 2063e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalezconst void *wimax_msg_data(struct sk_buff *msg) 2073e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez{ 2083e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez struct nlmsghdr *nlh = (void *) msg->head; 2093e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez struct nlattr *nla; 2103e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez 2113e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez nla = nlmsg_find_attr(nlh, sizeof(struct genlmsghdr), 2123e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez WIMAX_GNL_MSG_DATA); 2133e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez if (nla == NULL) { 21428b7deae75642c51f097391765fd39ff0dd6ce95Fabian Frederick pr_err("Cannot find attribute WIMAX_GNL_MSG_DATA\n"); 2153e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez return NULL; 2163e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez } 2173e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez return nla_data(nla); 2183e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez} 2193e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-GonzalezEXPORT_SYMBOL_GPL(wimax_msg_data); 2203e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez 2213e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez 2223e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez/** 2233e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * wimax_msg_len - Return a message's payload length 2243e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * 2253e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * @msg: Pointer to a message created with wimax_msg_alloc() 2263e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez */ 2273e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalezssize_t wimax_msg_len(struct sk_buff *msg) 2283e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez{ 2293e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez struct nlmsghdr *nlh = (void *) msg->head; 2303e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez struct nlattr *nla; 2313e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez 2323e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez nla = nlmsg_find_attr(nlh, sizeof(struct genlmsghdr), 2333e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez WIMAX_GNL_MSG_DATA); 2343e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez if (nla == NULL) { 23528b7deae75642c51f097391765fd39ff0dd6ce95Fabian Frederick pr_err("Cannot find attribute WIMAX_GNL_MSG_DATA\n"); 2363e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez return -EINVAL; 2373e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez } 2383e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez return nla_len(nla); 2393e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez} 2403e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-GonzalezEXPORT_SYMBOL_GPL(wimax_msg_len); 2413e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez 2423e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez 2433e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez/** 2443e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * wimax_msg_send - Send a pre-allocated message to user space 2453e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * 2463e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * @wimax_dev: WiMAX device descriptor 2473e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * 2483e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * @skb: &struct sk_buff returned by wimax_msg_alloc(). Note the 2493e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * ownership of @skb is transferred to this function. 2503e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * 2513e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * Returns: 0 if ok, < 0 errno code on error 2523e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * 2533e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * Description: 2543e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * 2553e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * Sends a free-form message that was preallocated with 2563e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * wimax_msg_alloc() and filled up. 2573e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * 2583e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * Assumes that once you pass an skb to this function for sending, it 2593e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * owns it and will release it when done (on success). 2603e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * 2613e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * IMPORTANT: 2623e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * 2633e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * Don't use skb_push()/skb_pull()/skb_reserve() on the skb, as 2643e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * wimax_msg_send() depends on skb->data being placed at the 2653e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * beginning of the user message. 26652a8d9630890f2289354d03e8751bf0eba2b3376Inaky Perez-Gonzalez * 26752a8d9630890f2289354d03e8751bf0eba2b3376Inaky Perez-Gonzalez * Unlike other WiMAX stack calls, this call can be used way early, 26852a8d9630890f2289354d03e8751bf0eba2b3376Inaky Perez-Gonzalez * even before wimax_dev_add() is called, as long as the 26952a8d9630890f2289354d03e8751bf0eba2b3376Inaky Perez-Gonzalez * wimax_dev->net_dev pointer is set to point to a proper 27052a8d9630890f2289354d03e8751bf0eba2b3376Inaky Perez-Gonzalez * net_dev. This is so that drivers can use it early in case they need 27152a8d9630890f2289354d03e8751bf0eba2b3376Inaky Perez-Gonzalez * to send stuff around or communicate with user space. 2723e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez */ 2733e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalezint wimax_msg_send(struct wimax_dev *wimax_dev, struct sk_buff *skb) 2743e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez{ 27552a8d9630890f2289354d03e8751bf0eba2b3376Inaky Perez-Gonzalez struct device *dev = wimax_dev_to_dev(wimax_dev); 2763e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez void *msg = skb->data; 2773e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez size_t size = skb->len; 2783e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez might_sleep(); 2793e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez 2803e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez d_printf(1, dev, "CTX: wimax msg, %zu bytes\n", size); 2813e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez d_dump(2, dev, msg, size); 2822a94fe48f32ccf7321450a2cc07f2b724a444e5bJohannes Berg genlmsg_multicast(&wimax_gnl_family, skb, 0, 0, GFP_KERNEL); 283ff491a7334acfd74e515c896632e37e401f52676Pablo Neira Ayuso d_printf(1, dev, "CTX: genl multicast done\n"); 284ff491a7334acfd74e515c896632e37e401f52676Pablo Neira Ayuso return 0; 2853e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez} 2863e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-GonzalezEXPORT_SYMBOL_GPL(wimax_msg_send); 2873e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez 2883e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez 2893e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez/** 2903e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * wimax_msg - Send a message to user space 2913e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * 2923e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * @wimax_dev: WiMAX device descriptor (properly referenced) 2933e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * @pipe_name: "named pipe" the message will be sent to 2943e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * @buf: pointer to the message to send. 2953e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * @size: size of the buffer pointed to by @buf (in bytes). 2963e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * @gfp_flags: flags for memory allocation. 2973e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * 2983e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * Returns: %0 if ok, negative errno code on error. 2993e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * 3003e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * Description: 3013e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * 3023e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * Sends a free-form message to user space on the device @wimax_dev. 3033e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * 3043e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * NOTES: 3053e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * 3063e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * Once the @skb is given to this function, who will own it and will 3073e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * release it when done (unless it returns error). 3083e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez */ 3093e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalezint wimax_msg(struct wimax_dev *wimax_dev, const char *pipe_name, 3103e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez const void *buf, size_t size, gfp_t gfp_flags) 3113e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez{ 3123e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez int result = -ENOMEM; 3133e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez struct sk_buff *skb; 3143e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez 3153e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez skb = wimax_msg_alloc(wimax_dev, pipe_name, buf, size, gfp_flags); 316d1a2627a29667fe7c4a9d06e1579a2d65bd39bbaInaky Perez-Gonzalez if (IS_ERR(skb)) 317d1a2627a29667fe7c4a9d06e1579a2d65bd39bbaInaky Perez-Gonzalez result = PTR_ERR(skb); 318d1a2627a29667fe7c4a9d06e1579a2d65bd39bbaInaky Perez-Gonzalez else 319d1a2627a29667fe7c4a9d06e1579a2d65bd39bbaInaky Perez-Gonzalez result = wimax_msg_send(wimax_dev, skb); 3203e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez return result; 3213e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez} 3223e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-GonzalezEXPORT_SYMBOL_GPL(wimax_msg); 3233e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez 3243e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez/* 3253e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * Relays a message from user space to the driver 3263e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * 3273e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * The skb is passed to the driver-specific function with the netlink 3283e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * and generic netlink headers already stripped. 3293e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * 3303e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez * This call will block while handling/relaying the message. 3313e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez */ 3323e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalezint wimax_gnl_doit_msg_from_user(struct sk_buff *skb, struct genl_info *info) 3333e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez{ 3343e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez int result, ifindex; 3353e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez struct wimax_dev *wimax_dev; 3363e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez struct device *dev; 3373e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez struct nlmsghdr *nlh = info->nlhdr; 3383e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez char *pipe_name; 3393e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez void *msg_buf; 3403e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez size_t msg_len; 3413e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez 3423e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez might_sleep(); 3433e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez d_fnstart(3, NULL, "(skb %p info %p)\n", skb, info); 3443e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez result = -ENODEV; 3453e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez if (info->attrs[WIMAX_GNL_MSG_IFIDX] == NULL) { 34628b7deae75642c51f097391765fd39ff0dd6ce95Fabian Frederick pr_err("WIMAX_GNL_MSG_FROM_USER: can't find IFIDX attribute\n"); 3473e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez goto error_no_wimax_dev; 3483e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez } 3493e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez ifindex = nla_get_u32(info->attrs[WIMAX_GNL_MSG_IFIDX]); 3503e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez wimax_dev = wimax_dev_get_by_genl_info(info, ifindex); 3513e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez if (wimax_dev == NULL) 3523e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez goto error_no_wimax_dev; 3533e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez dev = wimax_dev_to_dev(wimax_dev); 3543e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez 3553e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez /* Unpack arguments */ 3563e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez result = -EINVAL; 3573e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez if (info->attrs[WIMAX_GNL_MSG_DATA] == NULL) { 3583e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez dev_err(dev, "WIMAX_GNL_MSG_FROM_USER: can't find MSG_DATA " 3593e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez "attribute\n"); 3603e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez goto error_no_data; 3613e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez } 3623e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez msg_buf = nla_data(info->attrs[WIMAX_GNL_MSG_DATA]); 3633e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez msg_len = nla_len(info->attrs[WIMAX_GNL_MSG_DATA]); 3643e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez 3653e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez if (info->attrs[WIMAX_GNL_MSG_PIPE_NAME] == NULL) 3663e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez pipe_name = NULL; 3673e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez else { 3683e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez struct nlattr *attr = info->attrs[WIMAX_GNL_MSG_PIPE_NAME]; 3693e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez size_t attr_len = nla_len(attr); 3703e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez /* libnl-1.1 does not yet support NLA_NUL_STRING */ 3713e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez result = -ENOMEM; 3723e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez pipe_name = kstrndup(nla_data(attr), attr_len + 1, GFP_KERNEL); 3733e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez if (pipe_name == NULL) 3743e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez goto error_alloc; 3753e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez pipe_name[attr_len] = 0; 3763e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez } 3773e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez mutex_lock(&wimax_dev->mutex); 3783e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez result = wimax_dev_is_ready(wimax_dev); 379de9315fa3a35ebe587cc1a1c88655d095846785eInaky Perez-Gonzalez if (result == -ENOMEDIUM) 380de9315fa3a35ebe587cc1a1c88655d095846785eInaky Perez-Gonzalez result = 0; 3813e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez if (result < 0) 3823e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez goto error_not_ready; 3833e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez result = -ENOSYS; 3843e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez if (wimax_dev->op_msg_from_user == NULL) 3853e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez goto error_noop; 3863e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez 3873e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez d_printf(1, dev, 3883e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez "CRX: nlmsghdr len %u type %u flags 0x%04x seq 0x%x pid %u\n", 3893e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez nlh->nlmsg_len, nlh->nlmsg_type, nlh->nlmsg_flags, 3903e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez nlh->nlmsg_seq, nlh->nlmsg_pid); 3913e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez d_printf(1, dev, "CRX: wimax message %zu bytes\n", msg_len); 3923e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez d_dump(2, dev, msg_buf, msg_len); 3933e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez 3943e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez result = wimax_dev->op_msg_from_user(wimax_dev, pipe_name, 3953e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez msg_buf, msg_len, info); 3963e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalezerror_noop: 3973e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalezerror_not_ready: 3983e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez mutex_unlock(&wimax_dev->mutex); 3993e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalezerror_alloc: 4003e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez kfree(pipe_name); 4013e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalezerror_no_data: 4023e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez dev_put(wimax_dev->net_dev); 4033e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalezerror_no_wimax_dev: 4043e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez d_fnend(3, NULL, "(skb %p info %p) = %d\n", skb, info, result); 4053e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez return result; 4063e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez} 4073e65646bb12be03b14dff53907391095a52d5f49Inaky Perez-Gonzalez 408