2019-05-27 06:55:21 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-only
|
2009-06-08 12:18:48 +00:00
|
|
|
/*
|
|
|
|
* IEEE802154.4 socket interface
|
|
|
|
*
|
|
|
|
* Copyright 2007, 2008 Siemens AG
|
|
|
|
*
|
|
|
|
* Written by:
|
|
|
|
* Sergey Lapin <slapin@ossfans.org>
|
|
|
|
* Maxim Gorbachyov <maxim.gorbachev@siemens.com>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/net.h>
|
|
|
|
#include <linux/capability.h>
|
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/if_arp.h>
|
|
|
|
#include <linux/if.h>
|
|
|
|
#include <linux/termios.h> /* For TIOCOUTQ/INQ */
|
|
|
|
#include <linux/list.h>
|
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h
percpu.h is included by sched.h and module.h and thus ends up being
included when building most .c files. percpu.h includes slab.h which
in turn includes gfp.h making everything defined by the two files
universally available and complicating inclusion dependencies.
percpu.h -> slab.h dependency is about to be removed. Prepare for
this change by updating users of gfp and slab facilities include those
headers directly instead of assuming availability. As this conversion
needs to touch large number of source files, the following script is
used as the basis of conversion.
http://userweb.kernel.org/~tj/misc/slabh-sweep.py
The script does the followings.
* Scan files for gfp and slab usages and update includes such that
only the necessary includes are there. ie. if only gfp is used,
gfp.h, if slab is used, slab.h.
* When the script inserts a new include, it looks at the include
blocks and try to put the new include such that its order conforms
to its surrounding. It's put in the include block which contains
core kernel includes, in the same order that the rest are ordered -
alphabetical, Christmas tree, rev-Xmas-tree or at the end if there
doesn't seem to be any matching order.
* If the script can't find a place to put a new include (mostly
because the file doesn't have fitting include block), it prints out
an error message indicating which .h file needs to be added to the
file.
The conversion was done in the following steps.
1. The initial automatic conversion of all .c files updated slightly
over 4000 files, deleting around 700 includes and adding ~480 gfp.h
and ~3000 slab.h inclusions. The script emitted errors for ~400
files.
2. Each error was manually checked. Some didn't need the inclusion,
some needed manual addition while adding it to implementation .h or
embedding .c file was more appropriate for others. This step added
inclusions to around 150 files.
3. The script was run again and the output was compared to the edits
from #2 to make sure no file was left behind.
4. Several build tests were done and a couple of problems were fixed.
e.g. lib/decompress_*.c used malloc/free() wrappers around slab
APIs requiring slab.h to be added manually.
5. The script was run on all .h files but without automatically
editing them as sprinkling gfp.h and slab.h inclusions around .h
files could easily lead to inclusion dependency hell. Most gfp.h
inclusion directives were ignored as stuff from gfp.h was usually
wildly available and often used in preprocessor macros. Each
slab.h inclusion directive was examined and added manually as
necessary.
6. percpu.h was updated not to include slab.h.
7. Build test were done on the following configurations and failures
were fixed. CONFIG_GCOV_KERNEL was turned off for all tests (as my
distributed build env didn't work with gcov compiles) and a few
more options had to be turned off depending on archs to make things
build (like ipr on powerpc/64 which failed due to missing writeq).
* x86 and x86_64 UP and SMP allmodconfig and a custom test config.
* powerpc and powerpc64 SMP allmodconfig
* sparc and sparc64 SMP allmodconfig
* ia64 SMP allmodconfig
* s390 SMP allmodconfig
* alpha SMP allmodconfig
* um on x86_64 SMP allmodconfig
8. percpu.h modifications were reverted so that it could be applied as
a separate patch and serve as bisection point.
Given the fact that I had only a couple of failures from tests on step
6, I'm fairly confident about the coverage of this conversion patch.
If there is a breakage, it's likely to be something in one of the arch
headers which should be easily discoverable easily on most builds of
the specific arch.
Signed-off-by: Tejun Heo <tj@kernel.org>
Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
2010-03-24 08:04:11 +00:00
|
|
|
#include <linux/slab.h>
|
2018-06-07 14:08:02 +00:00
|
|
|
#include <linux/socket.h>
|
2009-06-08 12:18:48 +00:00
|
|
|
#include <net/datalink.h>
|
|
|
|
#include <net/psnap.h>
|
|
|
|
#include <net/sock.h>
|
|
|
|
#include <net/tcp_states.h>
|
|
|
|
#include <net/route.h>
|
|
|
|
|
2009-07-23 12:56:29 +00:00
|
|
|
#include <net/af_ieee802154.h>
|
|
|
|
#include <net/ieee802154_netdev.h>
|
2009-06-08 12:18:48 +00:00
|
|
|
|
2014-07-02 03:31:09 +00:00
|
|
|
/* Utility function for families */
|
2014-12-31 18:39:10 +00:00
|
|
|
static struct net_device*
|
2014-03-14 20:24:01 +00:00
|
|
|
ieee802154_get_dev(struct net *net, const struct ieee802154_addr *addr)
|
2009-06-08 12:18:48 +00:00
|
|
|
{
|
|
|
|
struct net_device *dev = NULL;
|
|
|
|
struct net_device *tmp;
|
2014-03-14 20:23:59 +00:00
|
|
|
__le16 pan_id, short_addr;
|
2014-03-14 20:24:01 +00:00
|
|
|
u8 hwaddr[IEEE802154_ADDR_LEN];
|
2009-06-08 12:18:48 +00:00
|
|
|
|
2014-03-14 20:24:01 +00:00
|
|
|
switch (addr->mode) {
|
2009-06-08 12:18:48 +00:00
|
|
|
case IEEE802154_ADDR_LONG:
|
2014-03-14 20:24:01 +00:00
|
|
|
ieee802154_devaddr_to_raw(hwaddr, addr->extended_addr);
|
2010-12-05 01:23:53 +00:00
|
|
|
rcu_read_lock();
|
2014-03-14 20:24:01 +00:00
|
|
|
dev = dev_getbyhwaddr_rcu(net, ARPHRD_IEEE802154, hwaddr);
|
2021-08-05 11:55:27 +00:00
|
|
|
dev_hold(dev);
|
2010-12-05 01:23:53 +00:00
|
|
|
rcu_read_unlock();
|
2009-06-08 12:18:48 +00:00
|
|
|
break;
|
|
|
|
case IEEE802154_ADDR_SHORT:
|
2014-03-14 20:24:01 +00:00
|
|
|
if (addr->pan_id == cpu_to_le16(IEEE802154_PANID_BROADCAST) ||
|
|
|
|
addr->short_addr == cpu_to_le16(IEEE802154_ADDR_UNDEF) ||
|
2014-03-20 13:57:02 +00:00
|
|
|
addr->short_addr == cpu_to_le16(IEEE802154_ADDR_BROADCAST))
|
2009-06-08 12:18:48 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
rtnl_lock();
|
|
|
|
|
|
|
|
for_each_netdev(net, tmp) {
|
|
|
|
if (tmp->type != ARPHRD_IEEE802154)
|
|
|
|
continue;
|
|
|
|
|
2015-05-22 15:43:54 +00:00
|
|
|
pan_id = tmp->ieee802154_ptr->pan_id;
|
|
|
|
short_addr = tmp->ieee802154_ptr->short_addr;
|
2014-03-14 20:24:01 +00:00
|
|
|
if (pan_id == addr->pan_id &&
|
|
|
|
short_addr == addr->short_addr) {
|
2009-06-08 12:18:48 +00:00
|
|
|
dev = tmp;
|
|
|
|
dev_hold(dev);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
rtnl_unlock();
|
|
|
|
break;
|
|
|
|
default:
|
2014-07-02 03:31:09 +00:00
|
|
|
pr_warn("Unsupported ieee802154 address type: %d\n",
|
|
|
|
addr->mode);
|
2009-06-08 12:18:48 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return dev;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ieee802154_sock_release(struct socket *sock)
|
|
|
|
{
|
|
|
|
struct sock *sk = sock->sk;
|
|
|
|
|
|
|
|
if (sk) {
|
|
|
|
sock->sk = NULL;
|
|
|
|
sk->sk_prot->close(sk, 0);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2014-12-04 10:51:59 +00:00
|
|
|
|
2015-03-02 07:37:48 +00:00
|
|
|
static int ieee802154_sock_sendmsg(struct socket *sock, struct msghdr *msg,
|
|
|
|
size_t len)
|
2009-06-08 12:18:48 +00:00
|
|
|
{
|
|
|
|
struct sock *sk = sock->sk;
|
|
|
|
|
2015-03-02 07:37:48 +00:00
|
|
|
return sk->sk_prot->sendmsg(sk, msg, len);
|
2009-06-08 12:18:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int ieee802154_sock_bind(struct socket *sock, struct sockaddr *uaddr,
|
2014-07-02 03:31:09 +00:00
|
|
|
int addr_len)
|
2009-06-08 12:18:48 +00:00
|
|
|
{
|
|
|
|
struct sock *sk = sock->sk;
|
|
|
|
|
|
|
|
if (sk->sk_prot->bind)
|
|
|
|
return sk->sk_prot->bind(sk, uaddr, addr_len);
|
|
|
|
|
|
|
|
return sock_no_bind(sock, uaddr, addr_len);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ieee802154_sock_connect(struct socket *sock, struct sockaddr *uaddr,
|
2014-07-02 03:31:09 +00:00
|
|
|
int addr_len, int flags)
|
2009-06-08 12:18:48 +00:00
|
|
|
{
|
|
|
|
struct sock *sk = sock->sk;
|
|
|
|
|
2010-03-31 22:58:26 +00:00
|
|
|
if (addr_len < sizeof(uaddr->sa_family))
|
|
|
|
return -EINVAL;
|
|
|
|
|
2009-06-08 12:18:48 +00:00
|
|
|
if (uaddr->sa_family == AF_UNSPEC)
|
|
|
|
return sk->sk_prot->disconnect(sk, flags);
|
|
|
|
|
|
|
|
return sk->sk_prot->connect(sk, uaddr, addr_len);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ieee802154_dev_ioctl(struct sock *sk, struct ifreq __user *arg,
|
2014-07-02 03:31:09 +00:00
|
|
|
unsigned int cmd)
|
2009-06-08 12:18:48 +00:00
|
|
|
{
|
|
|
|
struct ifreq ifr;
|
2009-08-02 10:12:01 +00:00
|
|
|
int ret = -ENOIOCTLCMD;
|
2009-06-08 12:18:48 +00:00
|
|
|
struct net_device *dev;
|
|
|
|
|
net: socket: rework compat_ifreq_ioctl()
compat_ifreq_ioctl() is one of the last users of copy_in_user() and
compat_alloc_user_space(), as it attempts to convert the 'struct ifreq'
arguments from 32-bit to 64-bit format as used by dev_ioctl() and a
couple of socket family specific interpretations.
The current implementation works correctly when calling dev_ioctl(),
inet_ioctl(), ieee802154_sock_ioctl(), atalk_ioctl(), qrtr_ioctl()
and packet_ioctl(). The ioctl handlers for x25, netrom, rose and x25 do
not interpret the arguments and only block the corresponding commands,
so they do not care.
For af_inet6 and af_decnet however, the compat conversion is slightly
incorrect, as it will copy more data than the native handler accesses,
both of them use a structure that is shorter than ifreq.
Replace the copy_in_user() conversion with a pair of accessor functions
to read and write the ifreq data in place with the correct length where
needed, while leaving the other ones to copy the (already compatible)
structures directly.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-07-22 14:29:03 +00:00
|
|
|
if (get_user_ifreq(&ifr, NULL, arg))
|
2009-06-08 12:18:48 +00:00
|
|
|
return -EFAULT;
|
|
|
|
|
|
|
|
ifr.ifr_name[IFNAMSIZ-1] = 0;
|
|
|
|
|
|
|
|
dev_load(sock_net(sk), ifr.ifr_name);
|
|
|
|
dev = dev_get_by_name(sock_net(sk), ifr.ifr_name);
|
2009-08-02 10:12:01 +00:00
|
|
|
|
2010-04-26 18:20:32 +00:00
|
|
|
if (!dev)
|
|
|
|
return -ENODEV;
|
|
|
|
|
2009-08-14 16:00:20 +00:00
|
|
|
if (dev->type == ARPHRD_IEEE802154 && dev->netdev_ops->ndo_do_ioctl)
|
2009-06-08 12:18:48 +00:00
|
|
|
ret = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, cmd);
|
|
|
|
|
net: socket: rework compat_ifreq_ioctl()
compat_ifreq_ioctl() is one of the last users of copy_in_user() and
compat_alloc_user_space(), as it attempts to convert the 'struct ifreq'
arguments from 32-bit to 64-bit format as used by dev_ioctl() and a
couple of socket family specific interpretations.
The current implementation works correctly when calling dev_ioctl(),
inet_ioctl(), ieee802154_sock_ioctl(), atalk_ioctl(), qrtr_ioctl()
and packet_ioctl(). The ioctl handlers for x25, netrom, rose and x25 do
not interpret the arguments and only block the corresponding commands,
so they do not care.
For af_inet6 and af_decnet however, the compat conversion is slightly
incorrect, as it will copy more data than the native handler accesses,
both of them use a structure that is shorter than ifreq.
Replace the copy_in_user() conversion with a pair of accessor functions
to read and write the ifreq data in place with the correct length where
needed, while leaving the other ones to copy the (already compatible)
structures directly.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
2021-07-22 14:29:03 +00:00
|
|
|
if (!ret && put_user_ifreq(&ifr, arg))
|
2009-06-08 12:18:48 +00:00
|
|
|
ret = -EFAULT;
|
|
|
|
dev_put(dev);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ieee802154_sock_ioctl(struct socket *sock, unsigned int cmd,
|
2014-07-02 03:31:09 +00:00
|
|
|
unsigned long arg)
|
2009-06-08 12:18:48 +00:00
|
|
|
{
|
|
|
|
struct sock *sk = sock->sk;
|
|
|
|
|
|
|
|
switch (cmd) {
|
|
|
|
case SIOCGIFADDR:
|
|
|
|
case SIOCSIFADDR:
|
|
|
|
return ieee802154_dev_ioctl(sk, (struct ifreq __user *)arg,
|
|
|
|
cmd);
|
|
|
|
default:
|
|
|
|
if (!sk->sk_prot->ioctl)
|
|
|
|
return -ENOIOCTLCMD;
|
net: ioctl: Use kernel memory on protocol ioctl callbacks
Most of the ioctls to net protocols operates directly on userspace
argument (arg). Usually doing get_user()/put_user() directly in the
ioctl callback. This is not flexible, because it is hard to reuse these
functions without passing userspace buffers.
Change the "struct proto" ioctls to avoid touching userspace memory and
operate on kernel buffers, i.e., all protocol's ioctl callbacks is
adapted to operate on a kernel memory other than on userspace (so, no
more {put,get}_user() and friends being called in the ioctl callback).
This changes the "struct proto" ioctl format in the following way:
int (*ioctl)(struct sock *sk, int cmd,
- unsigned long arg);
+ int *karg);
(Important to say that this patch does not touch the "struct proto_ops"
protocols)
So, the "karg" argument, which is passed to the ioctl callback, is a
pointer allocated to kernel space memory (inside a function wrapper).
This buffer (karg) may contain input argument (copied from userspace in
a prep function) and it might return a value/buffer, which is copied
back to userspace if necessary. There is not one-size-fits-all format
(that is I am using 'may' above), but basically, there are three type of
ioctls:
1) Do not read from userspace, returns a result to userspace
2) Read an input parameter from userspace, and does not return anything
to userspace
3) Read an input from userspace, and return a buffer to userspace.
The default case (1) (where no input parameter is given, and an "int" is
returned to userspace) encompasses more than 90% of the cases, but there
are two other exceptions. Here is a list of exceptions:
* Protocol RAW:
* cmd = SIOCGETVIFCNT:
* input and output = struct sioc_vif_req
* cmd = SIOCGETSGCNT
* input and output = struct sioc_sg_req
* Explanation: for the SIOCGETVIFCNT case, userspace passes the input
argument, which is struct sioc_vif_req. Then the callback populates
the struct, which is copied back to userspace.
* Protocol RAW6:
* cmd = SIOCGETMIFCNT_IN6
* input and output = struct sioc_mif_req6
* cmd = SIOCGETSGCNT_IN6
* input and output = struct sioc_sg_req6
* Protocol PHONET:
* cmd == SIOCPNADDRESOURCE | SIOCPNDELRESOURCE
* input int (4 bytes)
* Nothing is copied back to userspace.
For the exception cases, functions sock_sk_ioctl_inout() will
copy the userspace input, and copy it back to kernel space.
The wrapper that prepare the buffer and put the buffer back to user is
sk_ioctl(), so, instead of calling sk->sk_prot->ioctl(), the callee now
calls sk_ioctl(), which will handle all cases.
Signed-off-by: Breno Leitao <leitao@debian.org>
Reviewed-by: Willem de Bruijn <willemb@google.com>
Reviewed-by: David Ahern <dsahern@kernel.org>
Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Link: https://lore.kernel.org/r/20230609152800.830401-1-leitao@debian.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2023-06-09 15:27:42 +00:00
|
|
|
return sk_ioctl(sk, cmd, (void __user *)arg);
|
2009-06-08 12:18:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-31 18:39:10 +00:00
|
|
|
/* RAW Sockets (802.15.4 created in userspace) */
|
|
|
|
static HLIST_HEAD(raw_head);
|
|
|
|
static DEFINE_RWLOCK(raw_lock);
|
|
|
|
|
2016-02-10 16:50:35 +00:00
|
|
|
static int raw_hash(struct sock *sk)
|
2014-12-31 18:39:10 +00:00
|
|
|
{
|
|
|
|
write_lock_bh(&raw_lock);
|
|
|
|
sk_add_node(sk, &raw_head);
|
|
|
|
write_unlock_bh(&raw_lock);
|
2021-11-15 17:11:50 +00:00
|
|
|
sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
|
2016-02-10 16:50:35 +00:00
|
|
|
|
|
|
|
return 0;
|
2014-12-31 18:39:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void raw_unhash(struct sock *sk)
|
|
|
|
{
|
|
|
|
write_lock_bh(&raw_lock);
|
|
|
|
if (sk_del_node_init(sk))
|
|
|
|
sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
|
|
|
|
write_unlock_bh(&raw_lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void raw_close(struct sock *sk, long timeout)
|
|
|
|
{
|
|
|
|
sk_common_release(sk);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int raw_bind(struct sock *sk, struct sockaddr *_uaddr, int len)
|
|
|
|
{
|
|
|
|
struct ieee802154_addr addr;
|
|
|
|
struct sockaddr_ieee802154 *uaddr = (struct sockaddr_ieee802154 *)_uaddr;
|
|
|
|
int err = 0;
|
|
|
|
struct net_device *dev = NULL;
|
|
|
|
|
2022-09-08 12:19:27 +00:00
|
|
|
err = ieee802154_sockaddr_check_size(uaddr, len);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
2014-12-31 18:39:10 +00:00
|
|
|
|
|
|
|
uaddr = (struct sockaddr_ieee802154 *)_uaddr;
|
|
|
|
if (uaddr->family != AF_IEEE802154)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
lock_sock(sk);
|
|
|
|
|
|
|
|
ieee802154_addr_from_sa(&addr, &uaddr->addr);
|
|
|
|
dev = ieee802154_get_dev(sock_net(sk), &addr);
|
|
|
|
if (!dev) {
|
|
|
|
err = -ENODEV;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
sk->sk_bound_dev_if = dev->ifindex;
|
|
|
|
sk_dst_reset(sk);
|
|
|
|
|
|
|
|
dev_put(dev);
|
|
|
|
out:
|
|
|
|
release_sock(sk);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int raw_connect(struct sock *sk, struct sockaddr *uaddr,
|
|
|
|
int addr_len)
|
|
|
|
{
|
|
|
|
return -ENOTSUPP;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int raw_disconnect(struct sock *sk, int flags)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-03-02 07:37:48 +00:00
|
|
|
static int raw_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
|
2014-12-31 18:39:10 +00:00
|
|
|
{
|
|
|
|
struct net_device *dev;
|
|
|
|
unsigned int mtu;
|
|
|
|
struct sk_buff *skb;
|
|
|
|
int hlen, tlen;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (msg->msg_flags & MSG_OOB) {
|
|
|
|
pr_debug("msg->msg_flags = 0x%x\n", msg->msg_flags);
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
}
|
|
|
|
|
|
|
|
lock_sock(sk);
|
|
|
|
if (!sk->sk_bound_dev_if)
|
|
|
|
dev = dev_getfirstbyhwtype(sock_net(sk), ARPHRD_IEEE802154);
|
|
|
|
else
|
|
|
|
dev = dev_get_by_index(sock_net(sk), sk->sk_bound_dev_if);
|
|
|
|
release_sock(sk);
|
|
|
|
|
|
|
|
if (!dev) {
|
|
|
|
pr_debug("no dev\n");
|
|
|
|
err = -ENXIO;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2015-09-28 10:36:26 +00:00
|
|
|
mtu = IEEE802154_MTU;
|
2014-12-31 18:39:10 +00:00
|
|
|
pr_debug("name = %s, mtu = %u\n", dev->name, mtu);
|
|
|
|
|
|
|
|
if (size > mtu) {
|
2017-02-27 22:30:02 +00:00
|
|
|
pr_debug("size = %zu, mtu = %u\n", size, mtu);
|
2015-05-25 12:38:24 +00:00
|
|
|
err = -EMSGSIZE;
|
2014-12-31 18:39:10 +00:00
|
|
|
goto out_dev;
|
|
|
|
}
|
net/ieee802154: don't warn zero-sized raw_sendmsg()
syzbot is hitting skb_assert_len() warning at __dev_queue_xmit() [1],
for PF_IEEE802154 socket's zero-sized raw_sendmsg() request is hitting
__dev_queue_xmit() with skb->len == 0.
Since PF_IEEE802154 socket's zero-sized raw_sendmsg() request was
able to return 0, don't call __dev_queue_xmit() if packet length is 0.
----------
#include <sys/socket.h>
#include <netinet/in.h>
int main(int argc, char *argv[])
{
struct sockaddr_in addr = { .sin_family = AF_INET, .sin_addr.s_addr = htonl(INADDR_LOOPBACK) };
struct iovec iov = { };
struct msghdr hdr = { .msg_name = &addr, .msg_namelen = sizeof(addr), .msg_iov = &iov, .msg_iovlen = 1 };
sendmsg(socket(PF_IEEE802154, SOCK_RAW, 0), &hdr, 0);
return 0;
}
----------
Note that this might be a sign that commit fd1894224407c484 ("bpf: Don't
redirect packets with invalid pkt_len") should be reverted, for
skb->len == 0 was acceptable for at least PF_IEEE802154 socket.
Link: https://syzkaller.appspot.com/bug?extid=5ea725c25d06fb9114c4 [1]
Reported-by: syzbot <syzbot+5ea725c25d06fb9114c4@syzkaller.appspotmail.com>
Fixes: fd1894224407c484 ("bpf: Don't redirect packets with invalid pkt_len")
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Signed-off-by: Alexander Aring <aahringo@redhat.com>
Link: https://lore.kernel.org/r/20221005014750.3685555-2-aahringo@redhat.com
Signed-off-by: Stefan Schmidt <stefan@datenfreihafen.org>
2022-10-05 01:47:50 +00:00
|
|
|
if (!size) {
|
|
|
|
err = 0;
|
|
|
|
goto out_dev;
|
|
|
|
}
|
2014-12-31 18:39:10 +00:00
|
|
|
|
|
|
|
hlen = LL_RESERVED_SPACE(dev);
|
|
|
|
tlen = dev->needed_tailroom;
|
|
|
|
skb = sock_alloc_send_skb(sk, hlen + tlen + size,
|
|
|
|
msg->msg_flags & MSG_DONTWAIT, &err);
|
|
|
|
if (!skb)
|
|
|
|
goto out_dev;
|
|
|
|
|
|
|
|
skb_reserve(skb, hlen);
|
|
|
|
|
|
|
|
skb_reset_mac_header(skb);
|
|
|
|
skb_reset_network_header(skb);
|
|
|
|
|
|
|
|
err = memcpy_from_msg(skb_put(skb, size), msg, size);
|
|
|
|
if (err < 0)
|
|
|
|
goto out_skb;
|
|
|
|
|
|
|
|
skb->dev = dev;
|
|
|
|
skb->protocol = htons(ETH_P_IEEE802154);
|
|
|
|
|
|
|
|
err = dev_queue_xmit(skb);
|
|
|
|
if (err > 0)
|
|
|
|
err = net_xmit_errno(err);
|
|
|
|
|
net: ieee802154: fix net_device reference release too early
This patch fixes the kernel oops when release net_device reference in
advance. In function raw_sendmsg(i think the dgram_sendmsg has the same
problem), there is a race condition between dev_put and dev_queue_xmit
when the device is gong that maybe lead to dev_queue_ximt to see
an illegal net_device pointer.
My test kernel is 3.13.0-32 and because i am not have a real 802154
device, so i change lowpan_newlink function to this:
/* find and hold real wpan device */
real_dev = dev_get_by_index(src_net, nla_get_u32(tb[IFLA_LINK]));
if (!real_dev)
return -ENODEV;
// if (real_dev->type != ARPHRD_IEEE802154) {
// dev_put(real_dev);
// return -EINVAL;
// }
lowpan_dev_info(dev)->real_dev = real_dev;
lowpan_dev_info(dev)->fragment_tag = 0;
mutex_init(&lowpan_dev_info(dev)->dev_list_mtx);
Also, in order to simulate preempt, i change the raw_sendmsg function
to this:
skb->dev = dev;
skb->sk = sk;
skb->protocol = htons(ETH_P_IEEE802154);
dev_put(dev);
//simulate preempt
schedule_timeout_uninterruptible(30 * HZ);
err = dev_queue_xmit(skb);
if (err > 0)
err = net_xmit_errno(err);
and this is my userspace test code named test_send_data:
int main(int argc, char **argv)
{
char buf[127];
int sockfd;
sockfd = socket(AF_IEEE802154, SOCK_RAW, 0);
if (sockfd < 0) {
printf("create sockfd error: %s\n", strerror(errno));
return -1;
}
send(sockfd, buf, sizeof(buf), 0);
return 0;
}
This is my test case:
root@zhanglin-x-computer:~/develop/802154# uname -a
Linux zhanglin-x-computer 3.13.0-32-generic #57-Ubuntu SMP Tue Jul 15
03:51:08 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
root@zhanglin-x-computer:~/develop/802154# ip link add link eth0 name
lowpan0 type lowpan
root@zhanglin-x-computer:~/develop/802154#
//keep the lowpan0 device down
root@zhanglin-x-computer:~/develop/802154# ./test_send_data &
//wait a while
root@zhanglin-x-computer:~/develop/802154# ip link del link dev lowpan0
//the device is gone
//oops
[381.303307] general protection fault: 0000 [#1]SMP
[381.303407] Modules linked in: af_802154 6lowpan bnep rfcomm
bluetooth nls_iso8859_1 snd_hda_codec_hdmi snd_hda_codec_realtek
rts5139(C) snd_hda_intel
snd_had_codec snd_hwdep snd_pcm snd_page_alloc snd_seq_midi
snd_seq_midi_event snd_rawmidi snd_req intel_rapl snd_seq_device
coretemp i915 kvm_intel
kvm snd_timer snd crct10dif_pclmul crc32_pclmul ghash_clmulni_intel
cypted drm_kms_helper drm i2c_algo_bit soundcore video mac_hid
parport_pc ppdev ip parport hid_generic
usbhid hid ahci r8169 mii libahdi
[381.304286] CPU:1 PID: 2524 Commm: 1 Tainted: G C 0 3.13.0-32-generic
[381.304409] Hardware name: Haier Haier DT Computer/Haier DT Codputer,
BIOS FIBT19H02_X64 06/09/2014
[381.304546] tasks: ffff000096965fc0 ti: ffffB0013779c000 task.ti:
ffffB8013779c000
[381.304659] RIP: 0010:[<ffffffff01621fe1>] [<ffffffff81621fe1>]
__dev_queue_ximt+0x61/0x500
[381.304798] RSP: 0018:ffffB8013779dca0 EFLAGS: 00010202
[381.304880] RAX: 272b031d57565351 RBX: 0000000000000000 RCX: ffff8800968f1a00
[381.304987] RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffff8800968f1a00
[381.305095] RBP: ffff8e013773dce0 R08: 0000000000000266 R09: 0000000000000004
[381.305202] R10: 0000000000000004 R11: 0000000000000005 R12: ffff88013902e000
[381.305310] R13: 000000000000007f R14: 000000000000007f R15: ffff8800968f1a00
[381.305418] FS: 00007fc57f50f740(0000) GS: ffff88013fc80000(0000)
knlGS: 0000000000000000
[381.305540] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b
[381.305627] CR2: 00007fad0841c000 CR3: 00000001368dd000 CR4: 00000000001007e0
[361.905734] Stack:
[381.305768] 00000000002052d0 000000003facb30a ffff88013779dcc0
ffff880137764000
[381.305898] ffff88013779de70 000000000000007f 000000000000007f
ffff88013902e000
[381.306026] ffff88013779dcf0 ffffffff81622490 ffff88013779dd39
ffffffffa03af9f1
[381.306155] Call Trace:
[381.306202] [<ffffffff81622490>] dev_queue_xmit+0x10/0x20
[381.306294] [<ffffffffa03af9f1>] raw_sendmsg+0x1b1/0x270 [af_802154]
[381.306396] [<ffffffffa03af054>] ieee802154_sock_sendmsg+0x14/0x20 [af_802154]
[381.306512] [<ffffffff816079eb>] sock_sendmsg+0x8b/0xc0
[381.306600] [<ffffffff811d52a5>] ? __d_alloc+0x25/0x180
[381.306687] [<ffffffff811a1f56>] ? kmem_cache_alloc_trace+0x1c6/0x1f0
[381.306791] [<ffffffff81607b91>] SYSC_sendto+0x121/0x1c0
[381.306878] [<ffffffff8109ddf4>] ? vtime_account_user+x54/0x60
[381.306975] [<ffffffff81020d45>] ? syscall_trace_enter+0x145/0x250
[381.307073] [<ffffffff816086ae>] SyS_sendto+0xe/0x10
[381.307156] [<ffffffff8172c87f>] tracesys+0xe1/0xe6
[381.307233] Code: c6 a1 a4 ff 41 8b 57 78 49 8b 47 20 85 d2 48 8b 80
78 07 00 00 75 21 49 8b 57 18 48 85 d2 74 18 48 85 c0 74 13 8b 92 ac
01 00 00 <3b> 50 10 73 08 8b 44 90 14 41 89 47 78 41 f6 84 24 d5 00 00
00
[381.307801] RIP [<ffffffff81621fe1>] _dev_queue_xmit+0x61/0x500
[381.307901] RSP <ffff88013779dca0>
[381.347512] Kernel panic - not syncing: Fatal exception in interrupt
[381.347747] drm_kms_helper: panic occurred, switching back to text console
In my opinion, there is always exist a chance that the device is gong
before call dev_queue_xmit.
I think the latest kernel is have the same problem and that
dev_put should be behind of the dev_queue_xmit.
Signed-off-by: Lin Zhang <xiaolou4617@gmail.com>
Acked-by: Stefan Schmidt <stefan@osg.samsung.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
2017-05-23 05:29:39 +00:00
|
|
|
dev_put(dev);
|
|
|
|
|
2014-12-31 18:39:10 +00:00
|
|
|
return err ?: size;
|
|
|
|
|
|
|
|
out_skb:
|
|
|
|
kfree_skb(skb);
|
|
|
|
out_dev:
|
|
|
|
dev_put(dev);
|
|
|
|
out:
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2015-03-02 07:37:48 +00:00
|
|
|
static int raw_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
|
net: remove noblock parameter from recvmsg() entities
The internal recvmsg() functions have two parameters 'flags' and 'noblock'
that were merged inside skb_recv_datagram(). As a follow up patch to commit
f4b41f062c42 ("net: remove noblock parameter from skb_recv_datagram()")
this patch removes the separate 'noblock' parameter for recvmsg().
Analogue to the referenced patch for skb_recv_datagram() the 'flags' and
'noblock' parameters are unnecessarily split up with e.g.
err = sk->sk_prot->recvmsg(sk, msg, size, flags & MSG_DONTWAIT,
flags & ~MSG_DONTWAIT, &addr_len);
or in
err = INDIRECT_CALL_2(sk->sk_prot->recvmsg, tcp_recvmsg, udp_recvmsg,
sk, msg, size, flags & MSG_DONTWAIT,
flags & ~MSG_DONTWAIT, &addr_len);
instead of simply using only flags all the time and check for MSG_DONTWAIT
where needed (to preserve for the formerly separated no(n)block condition).
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Link: https://lore.kernel.org/r/20220411124955.154876-1-socketcan@hartkopp.net
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2022-04-11 12:49:55 +00:00
|
|
|
int flags, int *addr_len)
|
2014-12-31 18:39:10 +00:00
|
|
|
{
|
|
|
|
size_t copied = 0;
|
|
|
|
int err = -EOPNOTSUPP;
|
|
|
|
struct sk_buff *skb;
|
|
|
|
|
2022-04-04 16:30:22 +00:00
|
|
|
skb = skb_recv_datagram(sk, flags, &err);
|
2014-12-31 18:39:10 +00:00
|
|
|
if (!skb)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
copied = skb->len;
|
|
|
|
if (len < copied) {
|
|
|
|
msg->msg_flags |= MSG_TRUNC;
|
|
|
|
copied = len;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = skb_copy_datagram_msg(skb, 0, msg, copied);
|
|
|
|
if (err)
|
|
|
|
goto done;
|
|
|
|
|
2022-04-27 20:02:37 +00:00
|
|
|
sock_recv_cmsgs(msg, sk, skb);
|
2014-12-31 18:39:10 +00:00
|
|
|
|
|
|
|
if (flags & MSG_TRUNC)
|
|
|
|
copied = skb->len;
|
|
|
|
done:
|
|
|
|
skb_free_datagram(sk, skb);
|
|
|
|
out:
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
return copied;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int raw_rcv_skb(struct sock *sk, struct sk_buff *skb)
|
|
|
|
{
|
|
|
|
skb = skb_share_check(skb, GFP_ATOMIC);
|
|
|
|
if (!skb)
|
|
|
|
return NET_RX_DROP;
|
|
|
|
|
|
|
|
if (sock_queue_rcv_skb(sk, skb) < 0) {
|
|
|
|
kfree_skb(skb);
|
|
|
|
return NET_RX_DROP;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NET_RX_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ieee802154_raw_deliver(struct net_device *dev, struct sk_buff *skb)
|
|
|
|
{
|
|
|
|
struct sock *sk;
|
|
|
|
|
|
|
|
read_lock(&raw_lock);
|
|
|
|
sk_for_each(sk, &raw_head) {
|
|
|
|
bh_lock_sock(sk);
|
|
|
|
if (!sk->sk_bound_dev_if ||
|
|
|
|
sk->sk_bound_dev_if == dev->ifindex) {
|
|
|
|
struct sk_buff *clone;
|
|
|
|
|
|
|
|
clone = skb_clone(skb, GFP_ATOMIC);
|
|
|
|
if (clone)
|
|
|
|
raw_rcv_skb(sk, clone);
|
|
|
|
}
|
|
|
|
bh_unlock_sock(sk);
|
|
|
|
}
|
|
|
|
read_unlock(&raw_lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int raw_getsockopt(struct sock *sk, int level, int optname,
|
|
|
|
char __user *optval, int __user *optlen)
|
|
|
|
{
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int raw_setsockopt(struct sock *sk, int level, int optname,
|
2020-07-23 06:09:07 +00:00
|
|
|
sockptr_t optval, unsigned int optlen)
|
2014-12-31 18:39:10 +00:00
|
|
|
{
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct proto ieee802154_raw_prot = {
|
|
|
|
.name = "IEEE-802.15.4-RAW",
|
|
|
|
.owner = THIS_MODULE,
|
|
|
|
.obj_size = sizeof(struct sock),
|
|
|
|
.close = raw_close,
|
|
|
|
.bind = raw_bind,
|
|
|
|
.sendmsg = raw_sendmsg,
|
|
|
|
.recvmsg = raw_recvmsg,
|
|
|
|
.hash = raw_hash,
|
|
|
|
.unhash = raw_unhash,
|
|
|
|
.connect = raw_connect,
|
|
|
|
.disconnect = raw_disconnect,
|
|
|
|
.getsockopt = raw_getsockopt,
|
|
|
|
.setsockopt = raw_setsockopt,
|
|
|
|
};
|
|
|
|
|
2009-06-08 12:18:48 +00:00
|
|
|
static const struct proto_ops ieee802154_raw_ops = {
|
|
|
|
.family = PF_IEEE802154,
|
|
|
|
.owner = THIS_MODULE,
|
|
|
|
.release = ieee802154_sock_release,
|
|
|
|
.bind = ieee802154_sock_bind,
|
|
|
|
.connect = ieee802154_sock_connect,
|
|
|
|
.socketpair = sock_no_socketpair,
|
|
|
|
.accept = sock_no_accept,
|
|
|
|
.getname = sock_no_getname,
|
2018-06-28 16:43:44 +00:00
|
|
|
.poll = datagram_poll,
|
2009-06-08 12:18:48 +00:00
|
|
|
.ioctl = ieee802154_sock_ioctl,
|
2019-04-17 20:51:48 +00:00
|
|
|
.gettstamp = sock_gettstamp,
|
2009-06-08 12:18:48 +00:00
|
|
|
.listen = sock_no_listen,
|
|
|
|
.shutdown = sock_no_shutdown,
|
|
|
|
.setsockopt = sock_common_setsockopt,
|
|
|
|
.getsockopt = sock_common_getsockopt,
|
|
|
|
.sendmsg = ieee802154_sock_sendmsg,
|
|
|
|
.recvmsg = sock_common_recvmsg,
|
|
|
|
.mmap = sock_no_mmap,
|
|
|
|
};
|
|
|
|
|
2014-12-31 18:39:10 +00:00
|
|
|
/* DGRAM Sockets (802.15.4 dataframes) */
|
|
|
|
static HLIST_HEAD(dgram_head);
|
|
|
|
static DEFINE_RWLOCK(dgram_lock);
|
|
|
|
|
|
|
|
struct dgram_sock {
|
|
|
|
struct sock sk;
|
|
|
|
|
|
|
|
struct ieee802154_addr src_addr;
|
|
|
|
struct ieee802154_addr dst_addr;
|
|
|
|
|
|
|
|
unsigned int bound:1;
|
|
|
|
unsigned int connected:1;
|
|
|
|
unsigned int want_ack:1;
|
2018-06-07 14:08:02 +00:00
|
|
|
unsigned int want_lqi:1;
|
2014-12-31 18:39:10 +00:00
|
|
|
unsigned int secen:1;
|
|
|
|
unsigned int secen_override:1;
|
|
|
|
unsigned int seclevel:3;
|
|
|
|
unsigned int seclevel_override:1;
|
|
|
|
};
|
|
|
|
|
|
|
|
static inline struct dgram_sock *dgram_sk(const struct sock *sk)
|
|
|
|
{
|
|
|
|
return container_of(sk, struct dgram_sock, sk);
|
|
|
|
}
|
|
|
|
|
2016-02-10 16:50:35 +00:00
|
|
|
static int dgram_hash(struct sock *sk)
|
2014-12-31 18:39:10 +00:00
|
|
|
{
|
|
|
|
write_lock_bh(&dgram_lock);
|
|
|
|
sk_add_node(sk, &dgram_head);
|
|
|
|
write_unlock_bh(&dgram_lock);
|
2021-11-15 17:11:50 +00:00
|
|
|
sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
|
2016-02-10 16:50:35 +00:00
|
|
|
|
|
|
|
return 0;
|
2014-12-31 18:39:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void dgram_unhash(struct sock *sk)
|
|
|
|
{
|
|
|
|
write_lock_bh(&dgram_lock);
|
|
|
|
if (sk_del_node_init(sk))
|
|
|
|
sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
|
|
|
|
write_unlock_bh(&dgram_lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int dgram_init(struct sock *sk)
|
|
|
|
{
|
|
|
|
struct dgram_sock *ro = dgram_sk(sk);
|
|
|
|
|
|
|
|
ro->want_ack = 1;
|
2018-06-07 14:08:02 +00:00
|
|
|
ro->want_lqi = 0;
|
2014-12-31 18:39:10 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void dgram_close(struct sock *sk, long timeout)
|
|
|
|
{
|
|
|
|
sk_common_release(sk);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int dgram_bind(struct sock *sk, struct sockaddr *uaddr, int len)
|
|
|
|
{
|
|
|
|
struct sockaddr_ieee802154 *addr = (struct sockaddr_ieee802154 *)uaddr;
|
|
|
|
struct ieee802154_addr haddr;
|
|
|
|
struct dgram_sock *ro = dgram_sk(sk);
|
|
|
|
int err = -EINVAL;
|
|
|
|
struct net_device *dev;
|
|
|
|
|
|
|
|
lock_sock(sk);
|
|
|
|
|
|
|
|
ro->bound = 0;
|
|
|
|
|
2022-09-08 12:19:27 +00:00
|
|
|
err = ieee802154_sockaddr_check_size(addr, len);
|
|
|
|
if (err < 0)
|
2014-12-31 18:39:10 +00:00
|
|
|
goto out;
|
|
|
|
|
2022-09-19 16:08:30 +00:00
|
|
|
if (addr->family != AF_IEEE802154) {
|
|
|
|
err = -EINVAL;
|
2014-12-31 18:39:10 +00:00
|
|
|
goto out;
|
2022-09-19 16:08:30 +00:00
|
|
|
}
|
2014-12-31 18:39:10 +00:00
|
|
|
|
|
|
|
ieee802154_addr_from_sa(&haddr, &addr->addr);
|
|
|
|
dev = ieee802154_get_dev(sock_net(sk), &haddr);
|
|
|
|
if (!dev) {
|
|
|
|
err = -ENODEV;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dev->type != ARPHRD_IEEE802154) {
|
|
|
|
err = -ENODEV;
|
|
|
|
goto out_put;
|
|
|
|
}
|
|
|
|
|
|
|
|
ro->src_addr = haddr;
|
|
|
|
|
|
|
|
ro->bound = 1;
|
|
|
|
err = 0;
|
|
|
|
out_put:
|
|
|
|
dev_put(dev);
|
|
|
|
out:
|
|
|
|
release_sock(sk);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
net: ioctl: Use kernel memory on protocol ioctl callbacks
Most of the ioctls to net protocols operates directly on userspace
argument (arg). Usually doing get_user()/put_user() directly in the
ioctl callback. This is not flexible, because it is hard to reuse these
functions without passing userspace buffers.
Change the "struct proto" ioctls to avoid touching userspace memory and
operate on kernel buffers, i.e., all protocol's ioctl callbacks is
adapted to operate on a kernel memory other than on userspace (so, no
more {put,get}_user() and friends being called in the ioctl callback).
This changes the "struct proto" ioctl format in the following way:
int (*ioctl)(struct sock *sk, int cmd,
- unsigned long arg);
+ int *karg);
(Important to say that this patch does not touch the "struct proto_ops"
protocols)
So, the "karg" argument, which is passed to the ioctl callback, is a
pointer allocated to kernel space memory (inside a function wrapper).
This buffer (karg) may contain input argument (copied from userspace in
a prep function) and it might return a value/buffer, which is copied
back to userspace if necessary. There is not one-size-fits-all format
(that is I am using 'may' above), but basically, there are three type of
ioctls:
1) Do not read from userspace, returns a result to userspace
2) Read an input parameter from userspace, and does not return anything
to userspace
3) Read an input from userspace, and return a buffer to userspace.
The default case (1) (where no input parameter is given, and an "int" is
returned to userspace) encompasses more than 90% of the cases, but there
are two other exceptions. Here is a list of exceptions:
* Protocol RAW:
* cmd = SIOCGETVIFCNT:
* input and output = struct sioc_vif_req
* cmd = SIOCGETSGCNT
* input and output = struct sioc_sg_req
* Explanation: for the SIOCGETVIFCNT case, userspace passes the input
argument, which is struct sioc_vif_req. Then the callback populates
the struct, which is copied back to userspace.
* Protocol RAW6:
* cmd = SIOCGETMIFCNT_IN6
* input and output = struct sioc_mif_req6
* cmd = SIOCGETSGCNT_IN6
* input and output = struct sioc_sg_req6
* Protocol PHONET:
* cmd == SIOCPNADDRESOURCE | SIOCPNDELRESOURCE
* input int (4 bytes)
* Nothing is copied back to userspace.
For the exception cases, functions sock_sk_ioctl_inout() will
copy the userspace input, and copy it back to kernel space.
The wrapper that prepare the buffer and put the buffer back to user is
sk_ioctl(), so, instead of calling sk->sk_prot->ioctl(), the callee now
calls sk_ioctl(), which will handle all cases.
Signed-off-by: Breno Leitao <leitao@debian.org>
Reviewed-by: Willem de Bruijn <willemb@google.com>
Reviewed-by: David Ahern <dsahern@kernel.org>
Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Link: https://lore.kernel.org/r/20230609152800.830401-1-leitao@debian.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2023-06-09 15:27:42 +00:00
|
|
|
static int dgram_ioctl(struct sock *sk, int cmd, int *karg)
|
2014-12-31 18:39:10 +00:00
|
|
|
{
|
|
|
|
switch (cmd) {
|
|
|
|
case SIOCOUTQ:
|
|
|
|
{
|
net: ioctl: Use kernel memory on protocol ioctl callbacks
Most of the ioctls to net protocols operates directly on userspace
argument (arg). Usually doing get_user()/put_user() directly in the
ioctl callback. This is not flexible, because it is hard to reuse these
functions without passing userspace buffers.
Change the "struct proto" ioctls to avoid touching userspace memory and
operate on kernel buffers, i.e., all protocol's ioctl callbacks is
adapted to operate on a kernel memory other than on userspace (so, no
more {put,get}_user() and friends being called in the ioctl callback).
This changes the "struct proto" ioctl format in the following way:
int (*ioctl)(struct sock *sk, int cmd,
- unsigned long arg);
+ int *karg);
(Important to say that this patch does not touch the "struct proto_ops"
protocols)
So, the "karg" argument, which is passed to the ioctl callback, is a
pointer allocated to kernel space memory (inside a function wrapper).
This buffer (karg) may contain input argument (copied from userspace in
a prep function) and it might return a value/buffer, which is copied
back to userspace if necessary. There is not one-size-fits-all format
(that is I am using 'may' above), but basically, there are three type of
ioctls:
1) Do not read from userspace, returns a result to userspace
2) Read an input parameter from userspace, and does not return anything
to userspace
3) Read an input from userspace, and return a buffer to userspace.
The default case (1) (where no input parameter is given, and an "int" is
returned to userspace) encompasses more than 90% of the cases, but there
are two other exceptions. Here is a list of exceptions:
* Protocol RAW:
* cmd = SIOCGETVIFCNT:
* input and output = struct sioc_vif_req
* cmd = SIOCGETSGCNT
* input and output = struct sioc_sg_req
* Explanation: for the SIOCGETVIFCNT case, userspace passes the input
argument, which is struct sioc_vif_req. Then the callback populates
the struct, which is copied back to userspace.
* Protocol RAW6:
* cmd = SIOCGETMIFCNT_IN6
* input and output = struct sioc_mif_req6
* cmd = SIOCGETSGCNT_IN6
* input and output = struct sioc_sg_req6
* Protocol PHONET:
* cmd == SIOCPNADDRESOURCE | SIOCPNDELRESOURCE
* input int (4 bytes)
* Nothing is copied back to userspace.
For the exception cases, functions sock_sk_ioctl_inout() will
copy the userspace input, and copy it back to kernel space.
The wrapper that prepare the buffer and put the buffer back to user is
sk_ioctl(), so, instead of calling sk->sk_prot->ioctl(), the callee now
calls sk_ioctl(), which will handle all cases.
Signed-off-by: Breno Leitao <leitao@debian.org>
Reviewed-by: Willem de Bruijn <willemb@google.com>
Reviewed-by: David Ahern <dsahern@kernel.org>
Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Link: https://lore.kernel.org/r/20230609152800.830401-1-leitao@debian.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2023-06-09 15:27:42 +00:00
|
|
|
*karg = sk_wmem_alloc_get(sk);
|
2014-12-31 18:39:10 +00:00
|
|
|
|
net: ioctl: Use kernel memory on protocol ioctl callbacks
Most of the ioctls to net protocols operates directly on userspace
argument (arg). Usually doing get_user()/put_user() directly in the
ioctl callback. This is not flexible, because it is hard to reuse these
functions without passing userspace buffers.
Change the "struct proto" ioctls to avoid touching userspace memory and
operate on kernel buffers, i.e., all protocol's ioctl callbacks is
adapted to operate on a kernel memory other than on userspace (so, no
more {put,get}_user() and friends being called in the ioctl callback).
This changes the "struct proto" ioctl format in the following way:
int (*ioctl)(struct sock *sk, int cmd,
- unsigned long arg);
+ int *karg);
(Important to say that this patch does not touch the "struct proto_ops"
protocols)
So, the "karg" argument, which is passed to the ioctl callback, is a
pointer allocated to kernel space memory (inside a function wrapper).
This buffer (karg) may contain input argument (copied from userspace in
a prep function) and it might return a value/buffer, which is copied
back to userspace if necessary. There is not one-size-fits-all format
(that is I am using 'may' above), but basically, there are three type of
ioctls:
1) Do not read from userspace, returns a result to userspace
2) Read an input parameter from userspace, and does not return anything
to userspace
3) Read an input from userspace, and return a buffer to userspace.
The default case (1) (where no input parameter is given, and an "int" is
returned to userspace) encompasses more than 90% of the cases, but there
are two other exceptions. Here is a list of exceptions:
* Protocol RAW:
* cmd = SIOCGETVIFCNT:
* input and output = struct sioc_vif_req
* cmd = SIOCGETSGCNT
* input and output = struct sioc_sg_req
* Explanation: for the SIOCGETVIFCNT case, userspace passes the input
argument, which is struct sioc_vif_req. Then the callback populates
the struct, which is copied back to userspace.
* Protocol RAW6:
* cmd = SIOCGETMIFCNT_IN6
* input and output = struct sioc_mif_req6
* cmd = SIOCGETSGCNT_IN6
* input and output = struct sioc_sg_req6
* Protocol PHONET:
* cmd == SIOCPNADDRESOURCE | SIOCPNDELRESOURCE
* input int (4 bytes)
* Nothing is copied back to userspace.
For the exception cases, functions sock_sk_ioctl_inout() will
copy the userspace input, and copy it back to kernel space.
The wrapper that prepare the buffer and put the buffer back to user is
sk_ioctl(), so, instead of calling sk->sk_prot->ioctl(), the callee now
calls sk_ioctl(), which will handle all cases.
Signed-off-by: Breno Leitao <leitao@debian.org>
Reviewed-by: Willem de Bruijn <willemb@google.com>
Reviewed-by: David Ahern <dsahern@kernel.org>
Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Link: https://lore.kernel.org/r/20230609152800.830401-1-leitao@debian.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2023-06-09 15:27:42 +00:00
|
|
|
return 0;
|
2014-12-31 18:39:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
case SIOCINQ:
|
|
|
|
{
|
|
|
|
struct sk_buff *skb;
|
|
|
|
|
net: ioctl: Use kernel memory on protocol ioctl callbacks
Most of the ioctls to net protocols operates directly on userspace
argument (arg). Usually doing get_user()/put_user() directly in the
ioctl callback. This is not flexible, because it is hard to reuse these
functions without passing userspace buffers.
Change the "struct proto" ioctls to avoid touching userspace memory and
operate on kernel buffers, i.e., all protocol's ioctl callbacks is
adapted to operate on a kernel memory other than on userspace (so, no
more {put,get}_user() and friends being called in the ioctl callback).
This changes the "struct proto" ioctl format in the following way:
int (*ioctl)(struct sock *sk, int cmd,
- unsigned long arg);
+ int *karg);
(Important to say that this patch does not touch the "struct proto_ops"
protocols)
So, the "karg" argument, which is passed to the ioctl callback, is a
pointer allocated to kernel space memory (inside a function wrapper).
This buffer (karg) may contain input argument (copied from userspace in
a prep function) and it might return a value/buffer, which is copied
back to userspace if necessary. There is not one-size-fits-all format
(that is I am using 'may' above), but basically, there are three type of
ioctls:
1) Do not read from userspace, returns a result to userspace
2) Read an input parameter from userspace, and does not return anything
to userspace
3) Read an input from userspace, and return a buffer to userspace.
The default case (1) (where no input parameter is given, and an "int" is
returned to userspace) encompasses more than 90% of the cases, but there
are two other exceptions. Here is a list of exceptions:
* Protocol RAW:
* cmd = SIOCGETVIFCNT:
* input and output = struct sioc_vif_req
* cmd = SIOCGETSGCNT
* input and output = struct sioc_sg_req
* Explanation: for the SIOCGETVIFCNT case, userspace passes the input
argument, which is struct sioc_vif_req. Then the callback populates
the struct, which is copied back to userspace.
* Protocol RAW6:
* cmd = SIOCGETMIFCNT_IN6
* input and output = struct sioc_mif_req6
* cmd = SIOCGETSGCNT_IN6
* input and output = struct sioc_sg_req6
* Protocol PHONET:
* cmd == SIOCPNADDRESOURCE | SIOCPNDELRESOURCE
* input int (4 bytes)
* Nothing is copied back to userspace.
For the exception cases, functions sock_sk_ioctl_inout() will
copy the userspace input, and copy it back to kernel space.
The wrapper that prepare the buffer and put the buffer back to user is
sk_ioctl(), so, instead of calling sk->sk_prot->ioctl(), the callee now
calls sk_ioctl(), which will handle all cases.
Signed-off-by: Breno Leitao <leitao@debian.org>
Reviewed-by: Willem de Bruijn <willemb@google.com>
Reviewed-by: David Ahern <dsahern@kernel.org>
Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Link: https://lore.kernel.org/r/20230609152800.830401-1-leitao@debian.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2023-06-09 15:27:42 +00:00
|
|
|
*karg = 0;
|
2014-12-31 18:39:10 +00:00
|
|
|
spin_lock_bh(&sk->sk_receive_queue.lock);
|
|
|
|
skb = skb_peek(&sk->sk_receive_queue);
|
2014-12-31 18:39:11 +00:00
|
|
|
if (skb) {
|
2014-12-31 18:39:10 +00:00
|
|
|
/* We will only return the amount
|
|
|
|
* of this packet since that is all
|
|
|
|
* that will be read.
|
|
|
|
*/
|
net: ioctl: Use kernel memory on protocol ioctl callbacks
Most of the ioctls to net protocols operates directly on userspace
argument (arg). Usually doing get_user()/put_user() directly in the
ioctl callback. This is not flexible, because it is hard to reuse these
functions without passing userspace buffers.
Change the "struct proto" ioctls to avoid touching userspace memory and
operate on kernel buffers, i.e., all protocol's ioctl callbacks is
adapted to operate on a kernel memory other than on userspace (so, no
more {put,get}_user() and friends being called in the ioctl callback).
This changes the "struct proto" ioctl format in the following way:
int (*ioctl)(struct sock *sk, int cmd,
- unsigned long arg);
+ int *karg);
(Important to say that this patch does not touch the "struct proto_ops"
protocols)
So, the "karg" argument, which is passed to the ioctl callback, is a
pointer allocated to kernel space memory (inside a function wrapper).
This buffer (karg) may contain input argument (copied from userspace in
a prep function) and it might return a value/buffer, which is copied
back to userspace if necessary. There is not one-size-fits-all format
(that is I am using 'may' above), but basically, there are three type of
ioctls:
1) Do not read from userspace, returns a result to userspace
2) Read an input parameter from userspace, and does not return anything
to userspace
3) Read an input from userspace, and return a buffer to userspace.
The default case (1) (where no input parameter is given, and an "int" is
returned to userspace) encompasses more than 90% of the cases, but there
are two other exceptions. Here is a list of exceptions:
* Protocol RAW:
* cmd = SIOCGETVIFCNT:
* input and output = struct sioc_vif_req
* cmd = SIOCGETSGCNT
* input and output = struct sioc_sg_req
* Explanation: for the SIOCGETVIFCNT case, userspace passes the input
argument, which is struct sioc_vif_req. Then the callback populates
the struct, which is copied back to userspace.
* Protocol RAW6:
* cmd = SIOCGETMIFCNT_IN6
* input and output = struct sioc_mif_req6
* cmd = SIOCGETSGCNT_IN6
* input and output = struct sioc_sg_req6
* Protocol PHONET:
* cmd == SIOCPNADDRESOURCE | SIOCPNDELRESOURCE
* input int (4 bytes)
* Nothing is copied back to userspace.
For the exception cases, functions sock_sk_ioctl_inout() will
copy the userspace input, and copy it back to kernel space.
The wrapper that prepare the buffer and put the buffer back to user is
sk_ioctl(), so, instead of calling sk->sk_prot->ioctl(), the callee now
calls sk_ioctl(), which will handle all cases.
Signed-off-by: Breno Leitao <leitao@debian.org>
Reviewed-by: Willem de Bruijn <willemb@google.com>
Reviewed-by: David Ahern <dsahern@kernel.org>
Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Link: https://lore.kernel.org/r/20230609152800.830401-1-leitao@debian.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2023-06-09 15:27:42 +00:00
|
|
|
*karg = skb->len - ieee802154_hdr_length(skb);
|
2014-12-31 18:39:10 +00:00
|
|
|
}
|
|
|
|
spin_unlock_bh(&sk->sk_receive_queue.lock);
|
net: ioctl: Use kernel memory on protocol ioctl callbacks
Most of the ioctls to net protocols operates directly on userspace
argument (arg). Usually doing get_user()/put_user() directly in the
ioctl callback. This is not flexible, because it is hard to reuse these
functions without passing userspace buffers.
Change the "struct proto" ioctls to avoid touching userspace memory and
operate on kernel buffers, i.e., all protocol's ioctl callbacks is
adapted to operate on a kernel memory other than on userspace (so, no
more {put,get}_user() and friends being called in the ioctl callback).
This changes the "struct proto" ioctl format in the following way:
int (*ioctl)(struct sock *sk, int cmd,
- unsigned long arg);
+ int *karg);
(Important to say that this patch does not touch the "struct proto_ops"
protocols)
So, the "karg" argument, which is passed to the ioctl callback, is a
pointer allocated to kernel space memory (inside a function wrapper).
This buffer (karg) may contain input argument (copied from userspace in
a prep function) and it might return a value/buffer, which is copied
back to userspace if necessary. There is not one-size-fits-all format
(that is I am using 'may' above), but basically, there are three type of
ioctls:
1) Do not read from userspace, returns a result to userspace
2) Read an input parameter from userspace, and does not return anything
to userspace
3) Read an input from userspace, and return a buffer to userspace.
The default case (1) (where no input parameter is given, and an "int" is
returned to userspace) encompasses more than 90% of the cases, but there
are two other exceptions. Here is a list of exceptions:
* Protocol RAW:
* cmd = SIOCGETVIFCNT:
* input and output = struct sioc_vif_req
* cmd = SIOCGETSGCNT
* input and output = struct sioc_sg_req
* Explanation: for the SIOCGETVIFCNT case, userspace passes the input
argument, which is struct sioc_vif_req. Then the callback populates
the struct, which is copied back to userspace.
* Protocol RAW6:
* cmd = SIOCGETMIFCNT_IN6
* input and output = struct sioc_mif_req6
* cmd = SIOCGETSGCNT_IN6
* input and output = struct sioc_sg_req6
* Protocol PHONET:
* cmd == SIOCPNADDRESOURCE | SIOCPNDELRESOURCE
* input int (4 bytes)
* Nothing is copied back to userspace.
For the exception cases, functions sock_sk_ioctl_inout() will
copy the userspace input, and copy it back to kernel space.
The wrapper that prepare the buffer and put the buffer back to user is
sk_ioctl(), so, instead of calling sk->sk_prot->ioctl(), the callee now
calls sk_ioctl(), which will handle all cases.
Signed-off-by: Breno Leitao <leitao@debian.org>
Reviewed-by: Willem de Bruijn <willemb@google.com>
Reviewed-by: David Ahern <dsahern@kernel.org>
Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Link: https://lore.kernel.org/r/20230609152800.830401-1-leitao@debian.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2023-06-09 15:27:42 +00:00
|
|
|
return 0;
|
2014-12-31 18:39:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return -ENOIOCTLCMD;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* FIXME: autobind */
|
|
|
|
static int dgram_connect(struct sock *sk, struct sockaddr *uaddr,
|
|
|
|
int len)
|
|
|
|
{
|
|
|
|
struct sockaddr_ieee802154 *addr = (struct sockaddr_ieee802154 *)uaddr;
|
|
|
|
struct dgram_sock *ro = dgram_sk(sk);
|
|
|
|
int err = 0;
|
|
|
|
|
2022-09-08 12:19:27 +00:00
|
|
|
err = ieee802154_sockaddr_check_size(addr, len);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
2014-12-31 18:39:10 +00:00
|
|
|
|
|
|
|
if (addr->family != AF_IEEE802154)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
lock_sock(sk);
|
|
|
|
|
|
|
|
if (!ro->bound) {
|
|
|
|
err = -ENETUNREACH;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
ieee802154_addr_from_sa(&ro->dst_addr, &addr->addr);
|
|
|
|
ro->connected = 1;
|
|
|
|
|
|
|
|
out:
|
|
|
|
release_sock(sk);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int dgram_disconnect(struct sock *sk, int flags)
|
|
|
|
{
|
|
|
|
struct dgram_sock *ro = dgram_sk(sk);
|
|
|
|
|
|
|
|
lock_sock(sk);
|
|
|
|
ro->connected = 0;
|
|
|
|
release_sock(sk);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-03-02 07:37:48 +00:00
|
|
|
static int dgram_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
|
2014-12-31 18:39:10 +00:00
|
|
|
{
|
|
|
|
struct net_device *dev;
|
|
|
|
unsigned int mtu;
|
|
|
|
struct sk_buff *skb;
|
|
|
|
struct ieee802154_mac_cb *cb;
|
|
|
|
struct dgram_sock *ro = dgram_sk(sk);
|
|
|
|
struct ieee802154_addr dst_addr;
|
2022-09-08 12:19:27 +00:00
|
|
|
DECLARE_SOCKADDR(struct sockaddr_ieee802154*, daddr, msg->msg_name);
|
2014-12-31 18:39:10 +00:00
|
|
|
int hlen, tlen;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (msg->msg_flags & MSG_OOB) {
|
|
|
|
pr_debug("msg->msg_flags = 0x%x\n", msg->msg_flags);
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
}
|
|
|
|
|
2022-09-08 12:19:27 +00:00
|
|
|
if (msg->msg_name) {
|
|
|
|
if (ro->connected)
|
|
|
|
return -EISCONN;
|
|
|
|
if (msg->msg_namelen < IEEE802154_MIN_NAMELEN)
|
|
|
|
return -EINVAL;
|
|
|
|
err = ieee802154_sockaddr_check_size(daddr, msg->msg_namelen);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
ieee802154_addr_from_sa(&dst_addr, &daddr->addr);
|
|
|
|
} else {
|
|
|
|
if (!ro->connected)
|
|
|
|
return -EDESTADDRREQ;
|
|
|
|
dst_addr = ro->dst_addr;
|
|
|
|
}
|
2014-12-31 18:39:10 +00:00
|
|
|
|
|
|
|
if (!ro->bound)
|
|
|
|
dev = dev_getfirstbyhwtype(sock_net(sk), ARPHRD_IEEE802154);
|
|
|
|
else
|
|
|
|
dev = ieee802154_get_dev(sock_net(sk), &ro->src_addr);
|
|
|
|
|
|
|
|
if (!dev) {
|
|
|
|
pr_debug("no dev\n");
|
|
|
|
err = -ENXIO;
|
|
|
|
goto out;
|
|
|
|
}
|
2015-09-28 10:36:26 +00:00
|
|
|
mtu = IEEE802154_MTU;
|
2014-12-31 18:39:10 +00:00
|
|
|
pr_debug("name = %s, mtu = %u\n", dev->name, mtu);
|
|
|
|
|
|
|
|
if (size > mtu) {
|
2017-02-27 22:30:02 +00:00
|
|
|
pr_debug("size = %zu, mtu = %u\n", size, mtu);
|
2014-12-31 18:39:10 +00:00
|
|
|
err = -EMSGSIZE;
|
|
|
|
goto out_dev;
|
|
|
|
}
|
|
|
|
|
|
|
|
hlen = LL_RESERVED_SPACE(dev);
|
|
|
|
tlen = dev->needed_tailroom;
|
|
|
|
skb = sock_alloc_send_skb(sk, hlen + tlen + size,
|
|
|
|
msg->msg_flags & MSG_DONTWAIT,
|
|
|
|
&err);
|
|
|
|
if (!skb)
|
|
|
|
goto out_dev;
|
|
|
|
|
|
|
|
skb_reserve(skb, hlen);
|
|
|
|
|
|
|
|
skb_reset_network_header(skb);
|
|
|
|
|
|
|
|
cb = mac_cb_init(skb);
|
|
|
|
cb->type = IEEE802154_FC_TYPE_DATA;
|
|
|
|
cb->ackreq = ro->want_ack;
|
|
|
|
cb->secen = ro->secen;
|
|
|
|
cb->secen_override = ro->secen_override;
|
|
|
|
cb->seclevel = ro->seclevel;
|
|
|
|
cb->seclevel_override = ro->seclevel_override;
|
|
|
|
|
2015-09-18 09:30:42 +00:00
|
|
|
err = wpan_dev_hard_header(skb, dev, &dst_addr,
|
|
|
|
ro->bound ? &ro->src_addr : NULL, size);
|
2014-12-31 18:39:10 +00:00
|
|
|
if (err < 0)
|
|
|
|
goto out_skb;
|
|
|
|
|
|
|
|
err = memcpy_from_msg(skb_put(skb, size), msg, size);
|
|
|
|
if (err < 0)
|
|
|
|
goto out_skb;
|
|
|
|
|
|
|
|
skb->dev = dev;
|
|
|
|
skb->protocol = htons(ETH_P_IEEE802154);
|
|
|
|
|
|
|
|
err = dev_queue_xmit(skb);
|
|
|
|
if (err > 0)
|
|
|
|
err = net_xmit_errno(err);
|
|
|
|
|
net: ieee802154: fix net_device reference release too early
This patch fixes the kernel oops when release net_device reference in
advance. In function raw_sendmsg(i think the dgram_sendmsg has the same
problem), there is a race condition between dev_put and dev_queue_xmit
when the device is gong that maybe lead to dev_queue_ximt to see
an illegal net_device pointer.
My test kernel is 3.13.0-32 and because i am not have a real 802154
device, so i change lowpan_newlink function to this:
/* find and hold real wpan device */
real_dev = dev_get_by_index(src_net, nla_get_u32(tb[IFLA_LINK]));
if (!real_dev)
return -ENODEV;
// if (real_dev->type != ARPHRD_IEEE802154) {
// dev_put(real_dev);
// return -EINVAL;
// }
lowpan_dev_info(dev)->real_dev = real_dev;
lowpan_dev_info(dev)->fragment_tag = 0;
mutex_init(&lowpan_dev_info(dev)->dev_list_mtx);
Also, in order to simulate preempt, i change the raw_sendmsg function
to this:
skb->dev = dev;
skb->sk = sk;
skb->protocol = htons(ETH_P_IEEE802154);
dev_put(dev);
//simulate preempt
schedule_timeout_uninterruptible(30 * HZ);
err = dev_queue_xmit(skb);
if (err > 0)
err = net_xmit_errno(err);
and this is my userspace test code named test_send_data:
int main(int argc, char **argv)
{
char buf[127];
int sockfd;
sockfd = socket(AF_IEEE802154, SOCK_RAW, 0);
if (sockfd < 0) {
printf("create sockfd error: %s\n", strerror(errno));
return -1;
}
send(sockfd, buf, sizeof(buf), 0);
return 0;
}
This is my test case:
root@zhanglin-x-computer:~/develop/802154# uname -a
Linux zhanglin-x-computer 3.13.0-32-generic #57-Ubuntu SMP Tue Jul 15
03:51:08 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
root@zhanglin-x-computer:~/develop/802154# ip link add link eth0 name
lowpan0 type lowpan
root@zhanglin-x-computer:~/develop/802154#
//keep the lowpan0 device down
root@zhanglin-x-computer:~/develop/802154# ./test_send_data &
//wait a while
root@zhanglin-x-computer:~/develop/802154# ip link del link dev lowpan0
//the device is gone
//oops
[381.303307] general protection fault: 0000 [#1]SMP
[381.303407] Modules linked in: af_802154 6lowpan bnep rfcomm
bluetooth nls_iso8859_1 snd_hda_codec_hdmi snd_hda_codec_realtek
rts5139(C) snd_hda_intel
snd_had_codec snd_hwdep snd_pcm snd_page_alloc snd_seq_midi
snd_seq_midi_event snd_rawmidi snd_req intel_rapl snd_seq_device
coretemp i915 kvm_intel
kvm snd_timer snd crct10dif_pclmul crc32_pclmul ghash_clmulni_intel
cypted drm_kms_helper drm i2c_algo_bit soundcore video mac_hid
parport_pc ppdev ip parport hid_generic
usbhid hid ahci r8169 mii libahdi
[381.304286] CPU:1 PID: 2524 Commm: 1 Tainted: G C 0 3.13.0-32-generic
[381.304409] Hardware name: Haier Haier DT Computer/Haier DT Codputer,
BIOS FIBT19H02_X64 06/09/2014
[381.304546] tasks: ffff000096965fc0 ti: ffffB0013779c000 task.ti:
ffffB8013779c000
[381.304659] RIP: 0010:[<ffffffff01621fe1>] [<ffffffff81621fe1>]
__dev_queue_ximt+0x61/0x500
[381.304798] RSP: 0018:ffffB8013779dca0 EFLAGS: 00010202
[381.304880] RAX: 272b031d57565351 RBX: 0000000000000000 RCX: ffff8800968f1a00
[381.304987] RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffff8800968f1a00
[381.305095] RBP: ffff8e013773dce0 R08: 0000000000000266 R09: 0000000000000004
[381.305202] R10: 0000000000000004 R11: 0000000000000005 R12: ffff88013902e000
[381.305310] R13: 000000000000007f R14: 000000000000007f R15: ffff8800968f1a00
[381.305418] FS: 00007fc57f50f740(0000) GS: ffff88013fc80000(0000)
knlGS: 0000000000000000
[381.305540] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b
[381.305627] CR2: 00007fad0841c000 CR3: 00000001368dd000 CR4: 00000000001007e0
[361.905734] Stack:
[381.305768] 00000000002052d0 000000003facb30a ffff88013779dcc0
ffff880137764000
[381.305898] ffff88013779de70 000000000000007f 000000000000007f
ffff88013902e000
[381.306026] ffff88013779dcf0 ffffffff81622490 ffff88013779dd39
ffffffffa03af9f1
[381.306155] Call Trace:
[381.306202] [<ffffffff81622490>] dev_queue_xmit+0x10/0x20
[381.306294] [<ffffffffa03af9f1>] raw_sendmsg+0x1b1/0x270 [af_802154]
[381.306396] [<ffffffffa03af054>] ieee802154_sock_sendmsg+0x14/0x20 [af_802154]
[381.306512] [<ffffffff816079eb>] sock_sendmsg+0x8b/0xc0
[381.306600] [<ffffffff811d52a5>] ? __d_alloc+0x25/0x180
[381.306687] [<ffffffff811a1f56>] ? kmem_cache_alloc_trace+0x1c6/0x1f0
[381.306791] [<ffffffff81607b91>] SYSC_sendto+0x121/0x1c0
[381.306878] [<ffffffff8109ddf4>] ? vtime_account_user+x54/0x60
[381.306975] [<ffffffff81020d45>] ? syscall_trace_enter+0x145/0x250
[381.307073] [<ffffffff816086ae>] SyS_sendto+0xe/0x10
[381.307156] [<ffffffff8172c87f>] tracesys+0xe1/0xe6
[381.307233] Code: c6 a1 a4 ff 41 8b 57 78 49 8b 47 20 85 d2 48 8b 80
78 07 00 00 75 21 49 8b 57 18 48 85 d2 74 18 48 85 c0 74 13 8b 92 ac
01 00 00 <3b> 50 10 73 08 8b 44 90 14 41 89 47 78 41 f6 84 24 d5 00 00
00
[381.307801] RIP [<ffffffff81621fe1>] _dev_queue_xmit+0x61/0x500
[381.307901] RSP <ffff88013779dca0>
[381.347512] Kernel panic - not syncing: Fatal exception in interrupt
[381.347747] drm_kms_helper: panic occurred, switching back to text console
In my opinion, there is always exist a chance that the device is gong
before call dev_queue_xmit.
I think the latest kernel is have the same problem and that
dev_put should be behind of the dev_queue_xmit.
Signed-off-by: Lin Zhang <xiaolou4617@gmail.com>
Acked-by: Stefan Schmidt <stefan@osg.samsung.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
2017-05-23 05:29:39 +00:00
|
|
|
dev_put(dev);
|
|
|
|
|
2014-12-31 18:39:10 +00:00
|
|
|
return err ?: size;
|
|
|
|
|
|
|
|
out_skb:
|
|
|
|
kfree_skb(skb);
|
|
|
|
out_dev:
|
|
|
|
dev_put(dev);
|
|
|
|
out:
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2015-03-02 07:37:48 +00:00
|
|
|
static int dgram_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
|
net: remove noblock parameter from recvmsg() entities
The internal recvmsg() functions have two parameters 'flags' and 'noblock'
that were merged inside skb_recv_datagram(). As a follow up patch to commit
f4b41f062c42 ("net: remove noblock parameter from skb_recv_datagram()")
this patch removes the separate 'noblock' parameter for recvmsg().
Analogue to the referenced patch for skb_recv_datagram() the 'flags' and
'noblock' parameters are unnecessarily split up with e.g.
err = sk->sk_prot->recvmsg(sk, msg, size, flags & MSG_DONTWAIT,
flags & ~MSG_DONTWAIT, &addr_len);
or in
err = INDIRECT_CALL_2(sk->sk_prot->recvmsg, tcp_recvmsg, udp_recvmsg,
sk, msg, size, flags & MSG_DONTWAIT,
flags & ~MSG_DONTWAIT, &addr_len);
instead of simply using only flags all the time and check for MSG_DONTWAIT
where needed (to preserve for the formerly separated no(n)block condition).
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Link: https://lore.kernel.org/r/20220411124955.154876-1-socketcan@hartkopp.net
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2022-04-11 12:49:55 +00:00
|
|
|
int flags, int *addr_len)
|
2014-12-31 18:39:10 +00:00
|
|
|
{
|
|
|
|
size_t copied = 0;
|
|
|
|
int err = -EOPNOTSUPP;
|
|
|
|
struct sk_buff *skb;
|
2018-06-07 14:08:02 +00:00
|
|
|
struct dgram_sock *ro = dgram_sk(sk);
|
2014-12-31 18:39:10 +00:00
|
|
|
DECLARE_SOCKADDR(struct sockaddr_ieee802154 *, saddr, msg->msg_name);
|
|
|
|
|
2022-04-04 16:30:22 +00:00
|
|
|
skb = skb_recv_datagram(sk, flags, &err);
|
2014-12-31 18:39:10 +00:00
|
|
|
if (!skb)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
copied = skb->len;
|
|
|
|
if (len < copied) {
|
|
|
|
msg->msg_flags |= MSG_TRUNC;
|
|
|
|
copied = len;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* FIXME: skip headers if necessary ?! */
|
|
|
|
err = skb_copy_datagram_msg(skb, 0, msg, copied);
|
|
|
|
if (err)
|
|
|
|
goto done;
|
|
|
|
|
2022-04-27 20:02:37 +00:00
|
|
|
sock_recv_cmsgs(msg, sk, skb);
|
2014-12-31 18:39:10 +00:00
|
|
|
|
|
|
|
if (saddr) {
|
ieee802154: Fix sockaddr_ieee802154 implicit padding information leak.
The AF_IEEE802154 sockaddr looks like this:
struct sockaddr_ieee802154 {
sa_family_t family; /* AF_IEEE802154 */
struct ieee802154_addr_sa addr;
};
struct ieee802154_addr_sa {
int addr_type;
u16 pan_id;
union {
u8 hwaddr[IEEE802154_ADDR_LEN];
u16 short_addr;
};
};
On most architectures there will be implicit structure padding here,
in two different places:
* In struct sockaddr_ieee802154, two bytes of padding between 'family'
(unsigned short) and 'addr', so that 'addr' starts on a four byte
boundary.
* In struct ieee802154_addr_sa, two bytes at the end of the structure,
to make the structure 16 bytes.
When calling recvmsg(2) on a PF_IEEE802154 SOCK_DGRAM socket, the
ieee802154 stack constructs a struct sockaddr_ieee802154 on the
kernel stack without clearing these padding fields, and, depending
on the addr_type, between four and ten bytes of uncleared kernel
stack will be copied to userspace.
We can't just insert two 'u16 __pad's in the right places and zero
those before copying an address to userspace, as not all architectures
insert this implicit padding -- from a quick test it seems that avr32,
cris and m68k don't insert this padding, while every other architecture
that I have cross compilers for does insert this padding.
The easiest way to plug the leak is to just memset the whole struct
sockaddr_ieee802154 before filling in the fields we want to fill in,
and that's what this patch does.
Cc: stable@vger.kernel.org
Signed-off-by: Lennert Buytenhek <buytenh@wantstofly.org>
Acked-by: Alexander Aring <alex.aring@gmail.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
2015-06-03 07:50:19 +00:00
|
|
|
/* Clear the implicit padding in struct sockaddr_ieee802154
|
|
|
|
* (16 bits between 'family' and 'addr') and in struct
|
|
|
|
* ieee802154_addr_sa (16 bits at the end of the structure).
|
|
|
|
*/
|
|
|
|
memset(saddr, 0, sizeof(*saddr));
|
|
|
|
|
2014-12-31 18:39:10 +00:00
|
|
|
saddr->family = AF_IEEE802154;
|
|
|
|
ieee802154_addr_to_sa(&saddr->addr, &mac_cb(skb)->source);
|
|
|
|
*addr_len = sizeof(*saddr);
|
|
|
|
}
|
|
|
|
|
2018-06-07 14:08:02 +00:00
|
|
|
if (ro->want_lqi) {
|
|
|
|
err = put_cmsg(msg, SOL_IEEE802154, WPAN_WANTLQI,
|
|
|
|
sizeof(uint8_t), &(mac_cb(skb)->lqi));
|
|
|
|
if (err)
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2014-12-31 18:39:10 +00:00
|
|
|
if (flags & MSG_TRUNC)
|
|
|
|
copied = skb->len;
|
|
|
|
done:
|
|
|
|
skb_free_datagram(sk, skb);
|
|
|
|
out:
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
return copied;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int dgram_rcv_skb(struct sock *sk, struct sk_buff *skb)
|
|
|
|
{
|
|
|
|
skb = skb_share_check(skb, GFP_ATOMIC);
|
|
|
|
if (!skb)
|
|
|
|
return NET_RX_DROP;
|
|
|
|
|
|
|
|
if (sock_queue_rcv_skb(sk, skb) < 0) {
|
|
|
|
kfree_skb(skb);
|
|
|
|
return NET_RX_DROP;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NET_RX_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool
|
|
|
|
ieee802154_match_sock(__le64 hw_addr, __le16 pan_id, __le16 short_addr,
|
|
|
|
struct dgram_sock *ro)
|
|
|
|
{
|
|
|
|
if (!ro->bound)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (ro->src_addr.mode == IEEE802154_ADDR_LONG &&
|
|
|
|
hw_addr == ro->src_addr.extended_addr)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (ro->src_addr.mode == IEEE802154_ADDR_SHORT &&
|
|
|
|
pan_id == ro->src_addr.pan_id &&
|
|
|
|
short_addr == ro->src_addr.short_addr)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ieee802154_dgram_deliver(struct net_device *dev, struct sk_buff *skb)
|
|
|
|
{
|
|
|
|
struct sock *sk, *prev = NULL;
|
|
|
|
int ret = NET_RX_SUCCESS;
|
|
|
|
__le16 pan_id, short_addr;
|
|
|
|
__le64 hw_addr;
|
|
|
|
|
|
|
|
/* Data frame processing */
|
|
|
|
BUG_ON(dev->type != ARPHRD_IEEE802154);
|
|
|
|
|
2015-05-22 15:43:54 +00:00
|
|
|
pan_id = dev->ieee802154_ptr->pan_id;
|
|
|
|
short_addr = dev->ieee802154_ptr->short_addr;
|
|
|
|
hw_addr = dev->ieee802154_ptr->extended_addr;
|
2014-12-31 18:39:10 +00:00
|
|
|
|
|
|
|
read_lock(&dgram_lock);
|
|
|
|
sk_for_each(sk, &dgram_head) {
|
|
|
|
if (ieee802154_match_sock(hw_addr, pan_id, short_addr,
|
|
|
|
dgram_sk(sk))) {
|
|
|
|
if (prev) {
|
|
|
|
struct sk_buff *clone;
|
|
|
|
|
|
|
|
clone = skb_clone(skb, GFP_ATOMIC);
|
|
|
|
if (clone)
|
|
|
|
dgram_rcv_skb(prev, clone);
|
|
|
|
}
|
|
|
|
|
|
|
|
prev = sk;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (prev) {
|
|
|
|
dgram_rcv_skb(prev, skb);
|
|
|
|
} else {
|
|
|
|
kfree_skb(skb);
|
|
|
|
ret = NET_RX_DROP;
|
|
|
|
}
|
|
|
|
read_unlock(&dgram_lock);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int dgram_getsockopt(struct sock *sk, int level, int optname,
|
|
|
|
char __user *optval, int __user *optlen)
|
|
|
|
{
|
|
|
|
struct dgram_sock *ro = dgram_sk(sk);
|
|
|
|
|
|
|
|
int val, len;
|
|
|
|
|
|
|
|
if (level != SOL_IEEE802154)
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
if (get_user(len, optlen))
|
|
|
|
return -EFAULT;
|
|
|
|
|
|
|
|
len = min_t(unsigned int, len, sizeof(int));
|
|
|
|
|
|
|
|
switch (optname) {
|
|
|
|
case WPAN_WANTACK:
|
|
|
|
val = ro->want_ack;
|
|
|
|
break;
|
2018-06-07 14:08:02 +00:00
|
|
|
case WPAN_WANTLQI:
|
|
|
|
val = ro->want_lqi;
|
|
|
|
break;
|
2014-12-31 18:39:10 +00:00
|
|
|
case WPAN_SECURITY:
|
|
|
|
if (!ro->secen_override)
|
|
|
|
val = WPAN_SECURITY_DEFAULT;
|
|
|
|
else if (ro->secen)
|
|
|
|
val = WPAN_SECURITY_ON;
|
|
|
|
else
|
|
|
|
val = WPAN_SECURITY_OFF;
|
|
|
|
break;
|
|
|
|
case WPAN_SECURITY_LEVEL:
|
|
|
|
if (!ro->seclevel_override)
|
|
|
|
val = WPAN_SECURITY_LEVEL_DEFAULT;
|
|
|
|
else
|
|
|
|
val = ro->seclevel;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return -ENOPROTOOPT;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (put_user(len, optlen))
|
|
|
|
return -EFAULT;
|
|
|
|
if (copy_to_user(optval, &val, len))
|
|
|
|
return -EFAULT;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int dgram_setsockopt(struct sock *sk, int level, int optname,
|
2020-07-23 06:09:07 +00:00
|
|
|
sockptr_t optval, unsigned int optlen)
|
2014-12-31 18:39:10 +00:00
|
|
|
{
|
|
|
|
struct dgram_sock *ro = dgram_sk(sk);
|
|
|
|
struct net *net = sock_net(sk);
|
|
|
|
int val;
|
|
|
|
int err = 0;
|
|
|
|
|
|
|
|
if (optlen < sizeof(int))
|
|
|
|
return -EINVAL;
|
|
|
|
|
2020-07-23 06:09:07 +00:00
|
|
|
if (copy_from_sockptr(&val, optval, sizeof(int)))
|
2014-12-31 18:39:10 +00:00
|
|
|
return -EFAULT;
|
|
|
|
|
|
|
|
lock_sock(sk);
|
|
|
|
|
|
|
|
switch (optname) {
|
|
|
|
case WPAN_WANTACK:
|
|
|
|
ro->want_ack = !!val;
|
|
|
|
break;
|
2018-06-07 14:08:02 +00:00
|
|
|
case WPAN_WANTLQI:
|
|
|
|
ro->want_lqi = !!val;
|
|
|
|
break;
|
2014-12-31 18:39:10 +00:00
|
|
|
case WPAN_SECURITY:
|
|
|
|
if (!ns_capable(net->user_ns, CAP_NET_ADMIN) &&
|
|
|
|
!ns_capable(net->user_ns, CAP_NET_RAW)) {
|
|
|
|
err = -EPERM;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (val) {
|
|
|
|
case WPAN_SECURITY_DEFAULT:
|
|
|
|
ro->secen_override = 0;
|
|
|
|
break;
|
|
|
|
case WPAN_SECURITY_ON:
|
|
|
|
ro->secen_override = 1;
|
|
|
|
ro->secen = 1;
|
|
|
|
break;
|
|
|
|
case WPAN_SECURITY_OFF:
|
|
|
|
ro->secen_override = 1;
|
|
|
|
ro->secen = 0;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
err = -EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case WPAN_SECURITY_LEVEL:
|
|
|
|
if (!ns_capable(net->user_ns, CAP_NET_ADMIN) &&
|
|
|
|
!ns_capable(net->user_ns, CAP_NET_RAW)) {
|
|
|
|
err = -EPERM;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (val < WPAN_SECURITY_LEVEL_DEFAULT ||
|
|
|
|
val > IEEE802154_SCF_SECLEVEL_ENC_MIC128) {
|
|
|
|
err = -EINVAL;
|
|
|
|
} else if (val == WPAN_SECURITY_LEVEL_DEFAULT) {
|
|
|
|
ro->seclevel_override = 0;
|
|
|
|
} else {
|
|
|
|
ro->seclevel_override = 1;
|
|
|
|
ro->seclevel = val;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
err = -ENOPROTOOPT;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
release_sock(sk);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct proto ieee802154_dgram_prot = {
|
|
|
|
.name = "IEEE-802.15.4-MAC",
|
|
|
|
.owner = THIS_MODULE,
|
|
|
|
.obj_size = sizeof(struct dgram_sock),
|
|
|
|
.init = dgram_init,
|
|
|
|
.close = dgram_close,
|
|
|
|
.bind = dgram_bind,
|
|
|
|
.sendmsg = dgram_sendmsg,
|
|
|
|
.recvmsg = dgram_recvmsg,
|
|
|
|
.hash = dgram_hash,
|
|
|
|
.unhash = dgram_unhash,
|
|
|
|
.connect = dgram_connect,
|
|
|
|
.disconnect = dgram_disconnect,
|
|
|
|
.ioctl = dgram_ioctl,
|
|
|
|
.getsockopt = dgram_getsockopt,
|
|
|
|
.setsockopt = dgram_setsockopt,
|
|
|
|
};
|
|
|
|
|
2009-06-08 12:18:48 +00:00
|
|
|
static const struct proto_ops ieee802154_dgram_ops = {
|
|
|
|
.family = PF_IEEE802154,
|
|
|
|
.owner = THIS_MODULE,
|
|
|
|
.release = ieee802154_sock_release,
|
|
|
|
.bind = ieee802154_sock_bind,
|
|
|
|
.connect = ieee802154_sock_connect,
|
|
|
|
.socketpair = sock_no_socketpair,
|
|
|
|
.accept = sock_no_accept,
|
|
|
|
.getname = sock_no_getname,
|
2018-06-28 16:43:44 +00:00
|
|
|
.poll = datagram_poll,
|
2009-06-08 12:18:48 +00:00
|
|
|
.ioctl = ieee802154_sock_ioctl,
|
2019-04-17 20:51:48 +00:00
|
|
|
.gettstamp = sock_gettstamp,
|
2009-06-08 12:18:48 +00:00
|
|
|
.listen = sock_no_listen,
|
|
|
|
.shutdown = sock_no_shutdown,
|
|
|
|
.setsockopt = sock_common_setsockopt,
|
|
|
|
.getsockopt = sock_common_getsockopt,
|
|
|
|
.sendmsg = ieee802154_sock_sendmsg,
|
|
|
|
.recvmsg = sock_common_recvmsg,
|
|
|
|
.mmap = sock_no_mmap,
|
|
|
|
};
|
|
|
|
|
2021-08-05 07:54:14 +00:00
|
|
|
static void ieee802154_sock_destruct(struct sock *sk)
|
|
|
|
{
|
|
|
|
skb_queue_purge(&sk->sk_receive_queue);
|
|
|
|
}
|
|
|
|
|
2014-07-02 03:31:09 +00:00
|
|
|
/* Create a socket. Initialise the socket, blank the addresses
|
2009-06-08 12:18:48 +00:00
|
|
|
* set the state.
|
|
|
|
*/
|
|
|
|
static int ieee802154_create(struct net *net, struct socket *sock,
|
2009-11-06 06:18:14 +00:00
|
|
|
int protocol, int kern)
|
2009-06-08 12:18:48 +00:00
|
|
|
{
|
|
|
|
struct sock *sk;
|
|
|
|
int rc;
|
|
|
|
struct proto *proto;
|
|
|
|
const struct proto_ops *ops;
|
|
|
|
|
2009-11-25 23:14:13 +00:00
|
|
|
if (!net_eq(net, &init_net))
|
2009-06-08 12:18:48 +00:00
|
|
|
return -EAFNOSUPPORT;
|
|
|
|
|
|
|
|
switch (sock->type) {
|
|
|
|
case SOCK_RAW:
|
2019-09-20 07:35:48 +00:00
|
|
|
rc = -EPERM;
|
|
|
|
if (!capable(CAP_NET_RAW))
|
|
|
|
goto out;
|
2009-06-08 12:18:48 +00:00
|
|
|
proto = &ieee802154_raw_prot;
|
|
|
|
ops = &ieee802154_raw_ops;
|
|
|
|
break;
|
|
|
|
case SOCK_DGRAM:
|
|
|
|
proto = &ieee802154_dgram_prot;
|
|
|
|
ops = &ieee802154_dgram_ops;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
rc = -ESOCKTNOSUPPORT;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = -ENOMEM;
|
2015-05-09 02:09:13 +00:00
|
|
|
sk = sk_alloc(net, PF_IEEE802154, GFP_KERNEL, proto, kern);
|
2009-06-08 12:18:48 +00:00
|
|
|
if (!sk)
|
|
|
|
goto out;
|
|
|
|
rc = 0;
|
|
|
|
|
|
|
|
sock->ops = ops;
|
|
|
|
|
|
|
|
sock_init_data(sock, sk);
|
2021-08-05 07:54:14 +00:00
|
|
|
sk->sk_destruct = ieee802154_sock_destruct;
|
2009-06-08 12:18:48 +00:00
|
|
|
sk->sk_family = PF_IEEE802154;
|
|
|
|
|
|
|
|
/* Checksums on by default */
|
|
|
|
sock_set_flag(sk, SOCK_ZAPPED);
|
|
|
|
|
2016-02-10 16:50:35 +00:00
|
|
|
if (sk->sk_prot->hash) {
|
|
|
|
rc = sk->sk_prot->hash(sk);
|
|
|
|
if (rc) {
|
|
|
|
sk_common_release(sk);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
2009-06-08 12:18:48 +00:00
|
|
|
|
|
|
|
if (sk->sk_prot->init) {
|
|
|
|
rc = sk->sk_prot->init(sk);
|
|
|
|
if (rc)
|
|
|
|
sk_common_release(sk);
|
|
|
|
}
|
|
|
|
out:
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2009-10-05 05:58:39 +00:00
|
|
|
static const struct net_proto_family ieee802154_family_ops = {
|
2009-06-08 12:18:48 +00:00
|
|
|
.family = PF_IEEE802154,
|
|
|
|
.create = ieee802154_create,
|
|
|
|
.owner = THIS_MODULE,
|
|
|
|
};
|
|
|
|
|
|
|
|
static int ieee802154_rcv(struct sk_buff *skb, struct net_device *dev,
|
2014-07-02 03:31:09 +00:00
|
|
|
struct packet_type *pt, struct net_device *orig_dev)
|
2009-06-08 12:18:48 +00:00
|
|
|
{
|
|
|
|
if (!netif_running(dev))
|
2011-06-29 12:51:37 +00:00
|
|
|
goto drop;
|
2009-06-08 12:18:48 +00:00
|
|
|
pr_debug("got frame, type %d, dev %p\n", dev->type, dev);
|
2009-06-18 04:16:46 +00:00
|
|
|
#ifdef DEBUG
|
2014-07-02 03:31:09 +00:00
|
|
|
print_hex_dump_bytes("ieee802154_rcv ",
|
|
|
|
DUMP_PREFIX_NONE, skb->data, skb->len);
|
2009-06-18 04:16:46 +00:00
|
|
|
#endif
|
2009-06-08 12:18:48 +00:00
|
|
|
|
|
|
|
if (!net_eq(dev_net(dev), &init_net))
|
|
|
|
goto drop;
|
|
|
|
|
|
|
|
ieee802154_raw_deliver(dev, skb);
|
|
|
|
|
|
|
|
if (dev->type != ARPHRD_IEEE802154)
|
|
|
|
goto drop;
|
|
|
|
|
|
|
|
if (skb->pkt_type != PACKET_OTHERHOST)
|
|
|
|
return ieee802154_dgram_deliver(dev, skb);
|
|
|
|
|
|
|
|
drop:
|
|
|
|
kfree_skb(skb);
|
|
|
|
return NET_RX_DROP;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct packet_type ieee802154_packet_type = {
|
2014-03-12 17:04:18 +00:00
|
|
|
.type = htons(ETH_P_IEEE802154),
|
2009-06-08 12:18:48 +00:00
|
|
|
.func = ieee802154_rcv,
|
|
|
|
};
|
|
|
|
|
|
|
|
static int __init af_ieee802154_init(void)
|
|
|
|
{
|
2019-08-13 14:28:18 +00:00
|
|
|
int rc;
|
2009-06-08 12:18:48 +00:00
|
|
|
|
|
|
|
rc = proto_register(&ieee802154_raw_prot, 1);
|
|
|
|
if (rc)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
rc = proto_register(&ieee802154_dgram_prot, 1);
|
|
|
|
if (rc)
|
|
|
|
goto err_dgram;
|
|
|
|
|
|
|
|
/* Tell SOCKET that we are alive */
|
|
|
|
rc = sock_register(&ieee802154_family_ops);
|
|
|
|
if (rc)
|
|
|
|
goto err_sock;
|
|
|
|
dev_add_pack(&ieee802154_packet_type);
|
|
|
|
|
|
|
|
rc = 0;
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
err_sock:
|
|
|
|
proto_unregister(&ieee802154_dgram_prot);
|
|
|
|
err_dgram:
|
|
|
|
proto_unregister(&ieee802154_raw_prot);
|
|
|
|
out:
|
|
|
|
return rc;
|
|
|
|
}
|
2014-12-04 10:51:59 +00:00
|
|
|
|
2009-06-08 12:18:48 +00:00
|
|
|
static void __exit af_ieee802154_remove(void)
|
|
|
|
{
|
|
|
|
dev_remove_pack(&ieee802154_packet_type);
|
|
|
|
sock_unregister(PF_IEEE802154);
|
|
|
|
proto_unregister(&ieee802154_dgram_prot);
|
|
|
|
proto_unregister(&ieee802154_raw_prot);
|
|
|
|
}
|
|
|
|
|
|
|
|
module_init(af_ieee802154_init);
|
|
|
|
module_exit(af_ieee802154_remove);
|
|
|
|
|
|
|
|
MODULE_LICENSE("GPL");
|
|
|
|
MODULE_ALIAS_NETPROTO(PF_IEEE802154);
|