162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) 262306a36Sopenharmony_ci/* raw.c - Raw sockets for protocol family CAN 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (c) 2002-2007 Volkswagen Group Electronic Research 562306a36Sopenharmony_ci * All rights reserved. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 862306a36Sopenharmony_ci * modification, are permitted provided that the following conditions 962306a36Sopenharmony_ci * are met: 1062306a36Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright 1162306a36Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 1262306a36Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright 1362306a36Sopenharmony_ci * notice, this list of conditions and the following disclaimer in the 1462306a36Sopenharmony_ci * documentation and/or other materials provided with the distribution. 1562306a36Sopenharmony_ci * 3. Neither the name of Volkswagen nor the names of its contributors 1662306a36Sopenharmony_ci * may be used to endorse or promote products derived from this software 1762306a36Sopenharmony_ci * without specific prior written permission. 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * Alternatively, provided that this notice is retained in full, this 2062306a36Sopenharmony_ci * software may be distributed under the terms of the GNU General 2162306a36Sopenharmony_ci * Public License ("GPL") version 2, in which case the provisions of the 2262306a36Sopenharmony_ci * GPL apply INSTEAD OF those given above. 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci * The provided data structures and external interfaces from this code 2562306a36Sopenharmony_ci * are not restricted to be used by modules with a GPL compatible license. 2662306a36Sopenharmony_ci * 2762306a36Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2862306a36Sopenharmony_ci * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2962306a36Sopenharmony_ci * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 3062306a36Sopenharmony_ci * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 3162306a36Sopenharmony_ci * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 3262306a36Sopenharmony_ci * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 3362306a36Sopenharmony_ci * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3462306a36Sopenharmony_ci * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3562306a36Sopenharmony_ci * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3662306a36Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 3762306a36Sopenharmony_ci * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 3862306a36Sopenharmony_ci * DAMAGE. 3962306a36Sopenharmony_ci * 4062306a36Sopenharmony_ci */ 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci#include <linux/module.h> 4362306a36Sopenharmony_ci#include <linux/init.h> 4462306a36Sopenharmony_ci#include <linux/uio.h> 4562306a36Sopenharmony_ci#include <linux/net.h> 4662306a36Sopenharmony_ci#include <linux/slab.h> 4762306a36Sopenharmony_ci#include <linux/netdevice.h> 4862306a36Sopenharmony_ci#include <linux/socket.h> 4962306a36Sopenharmony_ci#include <linux/if_arp.h> 5062306a36Sopenharmony_ci#include <linux/skbuff.h> 5162306a36Sopenharmony_ci#include <linux/can.h> 5262306a36Sopenharmony_ci#include <linux/can/core.h> 5362306a36Sopenharmony_ci#include <linux/can/dev.h> /* for can_is_canxl_dev_mtu() */ 5462306a36Sopenharmony_ci#include <linux/can/skb.h> 5562306a36Sopenharmony_ci#include <linux/can/raw.h> 5662306a36Sopenharmony_ci#include <net/sock.h> 5762306a36Sopenharmony_ci#include <net/net_namespace.h> 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ciMODULE_DESCRIPTION("PF_CAN raw protocol"); 6062306a36Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 6162306a36Sopenharmony_ciMODULE_AUTHOR("Urs Thuermann <urs.thuermann@volkswagen.de>"); 6262306a36Sopenharmony_ciMODULE_ALIAS("can-proto-1"); 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci#define RAW_MIN_NAMELEN CAN_REQUIRED_SIZE(struct sockaddr_can, can_ifindex) 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci#define MASK_ALL 0 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci/* A raw socket has a list of can_filters attached to it, each receiving 6962306a36Sopenharmony_ci * the CAN frames matching that filter. If the filter list is empty, 7062306a36Sopenharmony_ci * no CAN frames will be received by the socket. The default after 7162306a36Sopenharmony_ci * opening the socket, is to have one filter which receives all frames. 7262306a36Sopenharmony_ci * The filter list is allocated dynamically with the exception of the 7362306a36Sopenharmony_ci * list containing only one item. This common case is optimized by 7462306a36Sopenharmony_ci * storing the single filter in dfilter, to avoid using dynamic memory. 7562306a36Sopenharmony_ci */ 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistruct uniqframe { 7862306a36Sopenharmony_ci int skbcnt; 7962306a36Sopenharmony_ci const struct sk_buff *skb; 8062306a36Sopenharmony_ci unsigned int join_rx_count; 8162306a36Sopenharmony_ci}; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cistruct raw_sock { 8462306a36Sopenharmony_ci struct sock sk; 8562306a36Sopenharmony_ci int bound; 8662306a36Sopenharmony_ci int ifindex; 8762306a36Sopenharmony_ci struct net_device *dev; 8862306a36Sopenharmony_ci netdevice_tracker dev_tracker; 8962306a36Sopenharmony_ci struct list_head notifier; 9062306a36Sopenharmony_ci int loopback; 9162306a36Sopenharmony_ci int recv_own_msgs; 9262306a36Sopenharmony_ci int fd_frames; 9362306a36Sopenharmony_ci int xl_frames; 9462306a36Sopenharmony_ci int join_filters; 9562306a36Sopenharmony_ci int count; /* number of active filters */ 9662306a36Sopenharmony_ci struct can_filter dfilter; /* default/single filter */ 9762306a36Sopenharmony_ci struct can_filter *filter; /* pointer to filter(s) */ 9862306a36Sopenharmony_ci can_err_mask_t err_mask; 9962306a36Sopenharmony_ci struct uniqframe __percpu *uniq; 10062306a36Sopenharmony_ci}; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cistatic LIST_HEAD(raw_notifier_list); 10362306a36Sopenharmony_cistatic DEFINE_SPINLOCK(raw_notifier_lock); 10462306a36Sopenharmony_cistatic struct raw_sock *raw_busy_notifier; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci/* Return pointer to store the extra msg flags for raw_recvmsg(). 10762306a36Sopenharmony_ci * We use the space of one unsigned int beyond the 'struct sockaddr_can' 10862306a36Sopenharmony_ci * in skb->cb. 10962306a36Sopenharmony_ci */ 11062306a36Sopenharmony_cistatic inline unsigned int *raw_flags(struct sk_buff *skb) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci sock_skb_cb_check_size(sizeof(struct sockaddr_can) + 11362306a36Sopenharmony_ci sizeof(unsigned int)); 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci /* return pointer after struct sockaddr_can */ 11662306a36Sopenharmony_ci return (unsigned int *)(&((struct sockaddr_can *)skb->cb)[1]); 11762306a36Sopenharmony_ci} 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cistatic inline struct raw_sock *raw_sk(const struct sock *sk) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci return (struct raw_sock *)sk; 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic void raw_rcv(struct sk_buff *oskb, void *data) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci struct sock *sk = (struct sock *)data; 12762306a36Sopenharmony_ci struct raw_sock *ro = raw_sk(sk); 12862306a36Sopenharmony_ci struct sockaddr_can *addr; 12962306a36Sopenharmony_ci struct sk_buff *skb; 13062306a36Sopenharmony_ci unsigned int *pflags; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci /* check the received tx sock reference */ 13362306a36Sopenharmony_ci if (!ro->recv_own_msgs && oskb->sk == sk) 13462306a36Sopenharmony_ci return; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci /* make sure to not pass oversized frames to the socket */ 13762306a36Sopenharmony_ci if ((!ro->fd_frames && can_is_canfd_skb(oskb)) || 13862306a36Sopenharmony_ci (!ro->xl_frames && can_is_canxl_skb(oskb))) 13962306a36Sopenharmony_ci return; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci /* eliminate multiple filter matches for the same skb */ 14262306a36Sopenharmony_ci if (this_cpu_ptr(ro->uniq)->skb == oskb && 14362306a36Sopenharmony_ci this_cpu_ptr(ro->uniq)->skbcnt == can_skb_prv(oskb)->skbcnt) { 14462306a36Sopenharmony_ci if (!ro->join_filters) 14562306a36Sopenharmony_ci return; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci this_cpu_inc(ro->uniq->join_rx_count); 14862306a36Sopenharmony_ci /* drop frame until all enabled filters matched */ 14962306a36Sopenharmony_ci if (this_cpu_ptr(ro->uniq)->join_rx_count < ro->count) 15062306a36Sopenharmony_ci return; 15162306a36Sopenharmony_ci } else { 15262306a36Sopenharmony_ci this_cpu_ptr(ro->uniq)->skb = oskb; 15362306a36Sopenharmony_ci this_cpu_ptr(ro->uniq)->skbcnt = can_skb_prv(oskb)->skbcnt; 15462306a36Sopenharmony_ci this_cpu_ptr(ro->uniq)->join_rx_count = 1; 15562306a36Sopenharmony_ci /* drop first frame to check all enabled filters? */ 15662306a36Sopenharmony_ci if (ro->join_filters && ro->count > 1) 15762306a36Sopenharmony_ci return; 15862306a36Sopenharmony_ci } 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci /* clone the given skb to be able to enqueue it into the rcv queue */ 16162306a36Sopenharmony_ci skb = skb_clone(oskb, GFP_ATOMIC); 16262306a36Sopenharmony_ci if (!skb) 16362306a36Sopenharmony_ci return; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci /* Put the datagram to the queue so that raw_recvmsg() can get 16662306a36Sopenharmony_ci * it from there. We need to pass the interface index to 16762306a36Sopenharmony_ci * raw_recvmsg(). We pass a whole struct sockaddr_can in 16862306a36Sopenharmony_ci * skb->cb containing the interface index. 16962306a36Sopenharmony_ci */ 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci sock_skb_cb_check_size(sizeof(struct sockaddr_can)); 17262306a36Sopenharmony_ci addr = (struct sockaddr_can *)skb->cb; 17362306a36Sopenharmony_ci memset(addr, 0, sizeof(*addr)); 17462306a36Sopenharmony_ci addr->can_family = AF_CAN; 17562306a36Sopenharmony_ci addr->can_ifindex = skb->dev->ifindex; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci /* add CAN specific message flags for raw_recvmsg() */ 17862306a36Sopenharmony_ci pflags = raw_flags(skb); 17962306a36Sopenharmony_ci *pflags = 0; 18062306a36Sopenharmony_ci if (oskb->sk) 18162306a36Sopenharmony_ci *pflags |= MSG_DONTROUTE; 18262306a36Sopenharmony_ci if (oskb->sk == sk) 18362306a36Sopenharmony_ci *pflags |= MSG_CONFIRM; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci if (sock_queue_rcv_skb(sk, skb) < 0) 18662306a36Sopenharmony_ci kfree_skb(skb); 18762306a36Sopenharmony_ci} 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_cistatic int raw_enable_filters(struct net *net, struct net_device *dev, 19062306a36Sopenharmony_ci struct sock *sk, struct can_filter *filter, 19162306a36Sopenharmony_ci int count) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci int err = 0; 19462306a36Sopenharmony_ci int i; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci for (i = 0; i < count; i++) { 19762306a36Sopenharmony_ci err = can_rx_register(net, dev, filter[i].can_id, 19862306a36Sopenharmony_ci filter[i].can_mask, 19962306a36Sopenharmony_ci raw_rcv, sk, "raw", sk); 20062306a36Sopenharmony_ci if (err) { 20162306a36Sopenharmony_ci /* clean up successfully registered filters */ 20262306a36Sopenharmony_ci while (--i >= 0) 20362306a36Sopenharmony_ci can_rx_unregister(net, dev, filter[i].can_id, 20462306a36Sopenharmony_ci filter[i].can_mask, 20562306a36Sopenharmony_ci raw_rcv, sk); 20662306a36Sopenharmony_ci break; 20762306a36Sopenharmony_ci } 20862306a36Sopenharmony_ci } 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci return err; 21162306a36Sopenharmony_ci} 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_cistatic int raw_enable_errfilter(struct net *net, struct net_device *dev, 21462306a36Sopenharmony_ci struct sock *sk, can_err_mask_t err_mask) 21562306a36Sopenharmony_ci{ 21662306a36Sopenharmony_ci int err = 0; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci if (err_mask) 21962306a36Sopenharmony_ci err = can_rx_register(net, dev, 0, err_mask | CAN_ERR_FLAG, 22062306a36Sopenharmony_ci raw_rcv, sk, "raw", sk); 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci return err; 22362306a36Sopenharmony_ci} 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_cistatic void raw_disable_filters(struct net *net, struct net_device *dev, 22662306a36Sopenharmony_ci struct sock *sk, struct can_filter *filter, 22762306a36Sopenharmony_ci int count) 22862306a36Sopenharmony_ci{ 22962306a36Sopenharmony_ci int i; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci for (i = 0; i < count; i++) 23262306a36Sopenharmony_ci can_rx_unregister(net, dev, filter[i].can_id, 23362306a36Sopenharmony_ci filter[i].can_mask, raw_rcv, sk); 23462306a36Sopenharmony_ci} 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_cistatic inline void raw_disable_errfilter(struct net *net, 23762306a36Sopenharmony_ci struct net_device *dev, 23862306a36Sopenharmony_ci struct sock *sk, 23962306a36Sopenharmony_ci can_err_mask_t err_mask) 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci{ 24262306a36Sopenharmony_ci if (err_mask) 24362306a36Sopenharmony_ci can_rx_unregister(net, dev, 0, err_mask | CAN_ERR_FLAG, 24462306a36Sopenharmony_ci raw_rcv, sk); 24562306a36Sopenharmony_ci} 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_cistatic inline void raw_disable_allfilters(struct net *net, 24862306a36Sopenharmony_ci struct net_device *dev, 24962306a36Sopenharmony_ci struct sock *sk) 25062306a36Sopenharmony_ci{ 25162306a36Sopenharmony_ci struct raw_sock *ro = raw_sk(sk); 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci raw_disable_filters(net, dev, sk, ro->filter, ro->count); 25462306a36Sopenharmony_ci raw_disable_errfilter(net, dev, sk, ro->err_mask); 25562306a36Sopenharmony_ci} 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_cistatic int raw_enable_allfilters(struct net *net, struct net_device *dev, 25862306a36Sopenharmony_ci struct sock *sk) 25962306a36Sopenharmony_ci{ 26062306a36Sopenharmony_ci struct raw_sock *ro = raw_sk(sk); 26162306a36Sopenharmony_ci int err; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci err = raw_enable_filters(net, dev, sk, ro->filter, ro->count); 26462306a36Sopenharmony_ci if (!err) { 26562306a36Sopenharmony_ci err = raw_enable_errfilter(net, dev, sk, ro->err_mask); 26662306a36Sopenharmony_ci if (err) 26762306a36Sopenharmony_ci raw_disable_filters(net, dev, sk, ro->filter, 26862306a36Sopenharmony_ci ro->count); 26962306a36Sopenharmony_ci } 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci return err; 27262306a36Sopenharmony_ci} 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_cistatic void raw_notify(struct raw_sock *ro, unsigned long msg, 27562306a36Sopenharmony_ci struct net_device *dev) 27662306a36Sopenharmony_ci{ 27762306a36Sopenharmony_ci struct sock *sk = &ro->sk; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci if (!net_eq(dev_net(dev), sock_net(sk))) 28062306a36Sopenharmony_ci return; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci if (ro->dev != dev) 28362306a36Sopenharmony_ci return; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci switch (msg) { 28662306a36Sopenharmony_ci case NETDEV_UNREGISTER: 28762306a36Sopenharmony_ci lock_sock(sk); 28862306a36Sopenharmony_ci /* remove current filters & unregister */ 28962306a36Sopenharmony_ci if (ro->bound) { 29062306a36Sopenharmony_ci raw_disable_allfilters(dev_net(dev), dev, sk); 29162306a36Sopenharmony_ci netdev_put(dev, &ro->dev_tracker); 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci if (ro->count > 1) 29562306a36Sopenharmony_ci kfree(ro->filter); 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci ro->ifindex = 0; 29862306a36Sopenharmony_ci ro->bound = 0; 29962306a36Sopenharmony_ci ro->dev = NULL; 30062306a36Sopenharmony_ci ro->count = 0; 30162306a36Sopenharmony_ci release_sock(sk); 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci sk->sk_err = ENODEV; 30462306a36Sopenharmony_ci if (!sock_flag(sk, SOCK_DEAD)) 30562306a36Sopenharmony_ci sk_error_report(sk); 30662306a36Sopenharmony_ci break; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci case NETDEV_DOWN: 30962306a36Sopenharmony_ci sk->sk_err = ENETDOWN; 31062306a36Sopenharmony_ci if (!sock_flag(sk, SOCK_DEAD)) 31162306a36Sopenharmony_ci sk_error_report(sk); 31262306a36Sopenharmony_ci break; 31362306a36Sopenharmony_ci } 31462306a36Sopenharmony_ci} 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_cistatic int raw_notifier(struct notifier_block *nb, unsigned long msg, 31762306a36Sopenharmony_ci void *ptr) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci struct net_device *dev = netdev_notifier_info_to_dev(ptr); 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci if (dev->type != ARPHRD_CAN) 32262306a36Sopenharmony_ci return NOTIFY_DONE; 32362306a36Sopenharmony_ci if (msg != NETDEV_UNREGISTER && msg != NETDEV_DOWN) 32462306a36Sopenharmony_ci return NOTIFY_DONE; 32562306a36Sopenharmony_ci if (unlikely(raw_busy_notifier)) /* Check for reentrant bug. */ 32662306a36Sopenharmony_ci return NOTIFY_DONE; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci spin_lock(&raw_notifier_lock); 32962306a36Sopenharmony_ci list_for_each_entry(raw_busy_notifier, &raw_notifier_list, notifier) { 33062306a36Sopenharmony_ci spin_unlock(&raw_notifier_lock); 33162306a36Sopenharmony_ci raw_notify(raw_busy_notifier, msg, dev); 33262306a36Sopenharmony_ci spin_lock(&raw_notifier_lock); 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_ci raw_busy_notifier = NULL; 33562306a36Sopenharmony_ci spin_unlock(&raw_notifier_lock); 33662306a36Sopenharmony_ci return NOTIFY_DONE; 33762306a36Sopenharmony_ci} 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_cistatic int raw_init(struct sock *sk) 34062306a36Sopenharmony_ci{ 34162306a36Sopenharmony_ci struct raw_sock *ro = raw_sk(sk); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci ro->bound = 0; 34462306a36Sopenharmony_ci ro->ifindex = 0; 34562306a36Sopenharmony_ci ro->dev = NULL; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci /* set default filter to single entry dfilter */ 34862306a36Sopenharmony_ci ro->dfilter.can_id = 0; 34962306a36Sopenharmony_ci ro->dfilter.can_mask = MASK_ALL; 35062306a36Sopenharmony_ci ro->filter = &ro->dfilter; 35162306a36Sopenharmony_ci ro->count = 1; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci /* set default loopback behaviour */ 35462306a36Sopenharmony_ci ro->loopback = 1; 35562306a36Sopenharmony_ci ro->recv_own_msgs = 0; 35662306a36Sopenharmony_ci ro->fd_frames = 0; 35762306a36Sopenharmony_ci ro->xl_frames = 0; 35862306a36Sopenharmony_ci ro->join_filters = 0; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci /* alloc_percpu provides zero'ed memory */ 36162306a36Sopenharmony_ci ro->uniq = alloc_percpu(struct uniqframe); 36262306a36Sopenharmony_ci if (unlikely(!ro->uniq)) 36362306a36Sopenharmony_ci return -ENOMEM; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci /* set notifier */ 36662306a36Sopenharmony_ci spin_lock(&raw_notifier_lock); 36762306a36Sopenharmony_ci list_add_tail(&ro->notifier, &raw_notifier_list); 36862306a36Sopenharmony_ci spin_unlock(&raw_notifier_lock); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci return 0; 37162306a36Sopenharmony_ci} 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_cistatic int raw_release(struct socket *sock) 37462306a36Sopenharmony_ci{ 37562306a36Sopenharmony_ci struct sock *sk = sock->sk; 37662306a36Sopenharmony_ci struct raw_sock *ro; 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci if (!sk) 37962306a36Sopenharmony_ci return 0; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci ro = raw_sk(sk); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci spin_lock(&raw_notifier_lock); 38462306a36Sopenharmony_ci while (raw_busy_notifier == ro) { 38562306a36Sopenharmony_ci spin_unlock(&raw_notifier_lock); 38662306a36Sopenharmony_ci schedule_timeout_uninterruptible(1); 38762306a36Sopenharmony_ci spin_lock(&raw_notifier_lock); 38862306a36Sopenharmony_ci } 38962306a36Sopenharmony_ci list_del(&ro->notifier); 39062306a36Sopenharmony_ci spin_unlock(&raw_notifier_lock); 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci rtnl_lock(); 39362306a36Sopenharmony_ci lock_sock(sk); 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci /* remove current filters & unregister */ 39662306a36Sopenharmony_ci if (ro->bound) { 39762306a36Sopenharmony_ci if (ro->dev) { 39862306a36Sopenharmony_ci raw_disable_allfilters(dev_net(ro->dev), ro->dev, sk); 39962306a36Sopenharmony_ci netdev_put(ro->dev, &ro->dev_tracker); 40062306a36Sopenharmony_ci } else { 40162306a36Sopenharmony_ci raw_disable_allfilters(sock_net(sk), NULL, sk); 40262306a36Sopenharmony_ci } 40362306a36Sopenharmony_ci } 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci if (ro->count > 1) 40662306a36Sopenharmony_ci kfree(ro->filter); 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci ro->ifindex = 0; 40962306a36Sopenharmony_ci ro->bound = 0; 41062306a36Sopenharmony_ci ro->dev = NULL; 41162306a36Sopenharmony_ci ro->count = 0; 41262306a36Sopenharmony_ci free_percpu(ro->uniq); 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci sock_orphan(sk); 41562306a36Sopenharmony_ci sock->sk = NULL; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci release_sock(sk); 41862306a36Sopenharmony_ci rtnl_unlock(); 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci sock_put(sk); 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci return 0; 42362306a36Sopenharmony_ci} 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_cistatic int raw_bind(struct socket *sock, struct sockaddr *uaddr, int len) 42662306a36Sopenharmony_ci{ 42762306a36Sopenharmony_ci struct sockaddr_can *addr = (struct sockaddr_can *)uaddr; 42862306a36Sopenharmony_ci struct sock *sk = sock->sk; 42962306a36Sopenharmony_ci struct raw_sock *ro = raw_sk(sk); 43062306a36Sopenharmony_ci struct net_device *dev = NULL; 43162306a36Sopenharmony_ci int ifindex; 43262306a36Sopenharmony_ci int err = 0; 43362306a36Sopenharmony_ci int notify_enetdown = 0; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci if (len < RAW_MIN_NAMELEN) 43662306a36Sopenharmony_ci return -EINVAL; 43762306a36Sopenharmony_ci if (addr->can_family != AF_CAN) 43862306a36Sopenharmony_ci return -EINVAL; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci rtnl_lock(); 44162306a36Sopenharmony_ci lock_sock(sk); 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci if (ro->bound && addr->can_ifindex == ro->ifindex) 44462306a36Sopenharmony_ci goto out; 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci if (addr->can_ifindex) { 44762306a36Sopenharmony_ci dev = dev_get_by_index(sock_net(sk), addr->can_ifindex); 44862306a36Sopenharmony_ci if (!dev) { 44962306a36Sopenharmony_ci err = -ENODEV; 45062306a36Sopenharmony_ci goto out; 45162306a36Sopenharmony_ci } 45262306a36Sopenharmony_ci if (dev->type != ARPHRD_CAN) { 45362306a36Sopenharmony_ci err = -ENODEV; 45462306a36Sopenharmony_ci goto out_put_dev; 45562306a36Sopenharmony_ci } 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci if (!(dev->flags & IFF_UP)) 45862306a36Sopenharmony_ci notify_enetdown = 1; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci ifindex = dev->ifindex; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci /* filters set by default/setsockopt */ 46362306a36Sopenharmony_ci err = raw_enable_allfilters(sock_net(sk), dev, sk); 46462306a36Sopenharmony_ci if (err) 46562306a36Sopenharmony_ci goto out_put_dev; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci } else { 46862306a36Sopenharmony_ci ifindex = 0; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci /* filters set by default/setsockopt */ 47162306a36Sopenharmony_ci err = raw_enable_allfilters(sock_net(sk), NULL, sk); 47262306a36Sopenharmony_ci } 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci if (!err) { 47562306a36Sopenharmony_ci if (ro->bound) { 47662306a36Sopenharmony_ci /* unregister old filters */ 47762306a36Sopenharmony_ci if (ro->dev) { 47862306a36Sopenharmony_ci raw_disable_allfilters(dev_net(ro->dev), 47962306a36Sopenharmony_ci ro->dev, sk); 48062306a36Sopenharmony_ci /* drop reference to old ro->dev */ 48162306a36Sopenharmony_ci netdev_put(ro->dev, &ro->dev_tracker); 48262306a36Sopenharmony_ci } else { 48362306a36Sopenharmony_ci raw_disable_allfilters(sock_net(sk), NULL, sk); 48462306a36Sopenharmony_ci } 48562306a36Sopenharmony_ci } 48662306a36Sopenharmony_ci ro->ifindex = ifindex; 48762306a36Sopenharmony_ci ro->bound = 1; 48862306a36Sopenharmony_ci /* bind() ok -> hold a reference for new ro->dev */ 48962306a36Sopenharmony_ci ro->dev = dev; 49062306a36Sopenharmony_ci if (ro->dev) 49162306a36Sopenharmony_ci netdev_hold(ro->dev, &ro->dev_tracker, GFP_KERNEL); 49262306a36Sopenharmony_ci } 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ciout_put_dev: 49562306a36Sopenharmony_ci /* remove potential reference from dev_get_by_index() */ 49662306a36Sopenharmony_ci if (dev) 49762306a36Sopenharmony_ci dev_put(dev); 49862306a36Sopenharmony_ciout: 49962306a36Sopenharmony_ci release_sock(sk); 50062306a36Sopenharmony_ci rtnl_unlock(); 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci if (notify_enetdown) { 50362306a36Sopenharmony_ci sk->sk_err = ENETDOWN; 50462306a36Sopenharmony_ci if (!sock_flag(sk, SOCK_DEAD)) 50562306a36Sopenharmony_ci sk_error_report(sk); 50662306a36Sopenharmony_ci } 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci return err; 50962306a36Sopenharmony_ci} 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_cistatic int raw_getname(struct socket *sock, struct sockaddr *uaddr, 51262306a36Sopenharmony_ci int peer) 51362306a36Sopenharmony_ci{ 51462306a36Sopenharmony_ci struct sockaddr_can *addr = (struct sockaddr_can *)uaddr; 51562306a36Sopenharmony_ci struct sock *sk = sock->sk; 51662306a36Sopenharmony_ci struct raw_sock *ro = raw_sk(sk); 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci if (peer) 51962306a36Sopenharmony_ci return -EOPNOTSUPP; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci memset(addr, 0, RAW_MIN_NAMELEN); 52262306a36Sopenharmony_ci addr->can_family = AF_CAN; 52362306a36Sopenharmony_ci addr->can_ifindex = ro->ifindex; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci return RAW_MIN_NAMELEN; 52662306a36Sopenharmony_ci} 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_cistatic int raw_setsockopt(struct socket *sock, int level, int optname, 52962306a36Sopenharmony_ci sockptr_t optval, unsigned int optlen) 53062306a36Sopenharmony_ci{ 53162306a36Sopenharmony_ci struct sock *sk = sock->sk; 53262306a36Sopenharmony_ci struct raw_sock *ro = raw_sk(sk); 53362306a36Sopenharmony_ci struct can_filter *filter = NULL; /* dyn. alloc'ed filters */ 53462306a36Sopenharmony_ci struct can_filter sfilter; /* single filter */ 53562306a36Sopenharmony_ci struct net_device *dev = NULL; 53662306a36Sopenharmony_ci can_err_mask_t err_mask = 0; 53762306a36Sopenharmony_ci int fd_frames; 53862306a36Sopenharmony_ci int count = 0; 53962306a36Sopenharmony_ci int err = 0; 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci if (level != SOL_CAN_RAW) 54262306a36Sopenharmony_ci return -EINVAL; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci switch (optname) { 54562306a36Sopenharmony_ci case CAN_RAW_FILTER: 54662306a36Sopenharmony_ci if (optlen % sizeof(struct can_filter) != 0) 54762306a36Sopenharmony_ci return -EINVAL; 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci if (optlen > CAN_RAW_FILTER_MAX * sizeof(struct can_filter)) 55062306a36Sopenharmony_ci return -EINVAL; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci count = optlen / sizeof(struct can_filter); 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci if (count > 1) { 55562306a36Sopenharmony_ci /* filter does not fit into dfilter => alloc space */ 55662306a36Sopenharmony_ci filter = memdup_sockptr(optval, optlen); 55762306a36Sopenharmony_ci if (IS_ERR(filter)) 55862306a36Sopenharmony_ci return PTR_ERR(filter); 55962306a36Sopenharmony_ci } else if (count == 1) { 56062306a36Sopenharmony_ci if (copy_from_sockptr(&sfilter, optval, sizeof(sfilter))) 56162306a36Sopenharmony_ci return -EFAULT; 56262306a36Sopenharmony_ci } 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci rtnl_lock(); 56562306a36Sopenharmony_ci lock_sock(sk); 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci dev = ro->dev; 56862306a36Sopenharmony_ci if (ro->bound && dev) { 56962306a36Sopenharmony_ci if (dev->reg_state != NETREG_REGISTERED) { 57062306a36Sopenharmony_ci if (count > 1) 57162306a36Sopenharmony_ci kfree(filter); 57262306a36Sopenharmony_ci err = -ENODEV; 57362306a36Sopenharmony_ci goto out_fil; 57462306a36Sopenharmony_ci } 57562306a36Sopenharmony_ci } 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci if (ro->bound) { 57862306a36Sopenharmony_ci /* (try to) register the new filters */ 57962306a36Sopenharmony_ci if (count == 1) 58062306a36Sopenharmony_ci err = raw_enable_filters(sock_net(sk), dev, sk, 58162306a36Sopenharmony_ci &sfilter, 1); 58262306a36Sopenharmony_ci else 58362306a36Sopenharmony_ci err = raw_enable_filters(sock_net(sk), dev, sk, 58462306a36Sopenharmony_ci filter, count); 58562306a36Sopenharmony_ci if (err) { 58662306a36Sopenharmony_ci if (count > 1) 58762306a36Sopenharmony_ci kfree(filter); 58862306a36Sopenharmony_ci goto out_fil; 58962306a36Sopenharmony_ci } 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci /* remove old filter registrations */ 59262306a36Sopenharmony_ci raw_disable_filters(sock_net(sk), dev, sk, ro->filter, 59362306a36Sopenharmony_ci ro->count); 59462306a36Sopenharmony_ci } 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci /* remove old filter space */ 59762306a36Sopenharmony_ci if (ro->count > 1) 59862306a36Sopenharmony_ci kfree(ro->filter); 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci /* link new filters to the socket */ 60162306a36Sopenharmony_ci if (count == 1) { 60262306a36Sopenharmony_ci /* copy filter data for single filter */ 60362306a36Sopenharmony_ci ro->dfilter = sfilter; 60462306a36Sopenharmony_ci filter = &ro->dfilter; 60562306a36Sopenharmony_ci } 60662306a36Sopenharmony_ci ro->filter = filter; 60762306a36Sopenharmony_ci ro->count = count; 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci out_fil: 61062306a36Sopenharmony_ci release_sock(sk); 61162306a36Sopenharmony_ci rtnl_unlock(); 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci break; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci case CAN_RAW_ERR_FILTER: 61662306a36Sopenharmony_ci if (optlen != sizeof(err_mask)) 61762306a36Sopenharmony_ci return -EINVAL; 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci if (copy_from_sockptr(&err_mask, optval, optlen)) 62062306a36Sopenharmony_ci return -EFAULT; 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci err_mask &= CAN_ERR_MASK; 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci rtnl_lock(); 62562306a36Sopenharmony_ci lock_sock(sk); 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci dev = ro->dev; 62862306a36Sopenharmony_ci if (ro->bound && dev) { 62962306a36Sopenharmony_ci if (dev->reg_state != NETREG_REGISTERED) { 63062306a36Sopenharmony_ci err = -ENODEV; 63162306a36Sopenharmony_ci goto out_err; 63262306a36Sopenharmony_ci } 63362306a36Sopenharmony_ci } 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci /* remove current error mask */ 63662306a36Sopenharmony_ci if (ro->bound) { 63762306a36Sopenharmony_ci /* (try to) register the new err_mask */ 63862306a36Sopenharmony_ci err = raw_enable_errfilter(sock_net(sk), dev, sk, 63962306a36Sopenharmony_ci err_mask); 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci if (err) 64262306a36Sopenharmony_ci goto out_err; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci /* remove old err_mask registration */ 64562306a36Sopenharmony_ci raw_disable_errfilter(sock_net(sk), dev, sk, 64662306a36Sopenharmony_ci ro->err_mask); 64762306a36Sopenharmony_ci } 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci /* link new err_mask to the socket */ 65062306a36Sopenharmony_ci ro->err_mask = err_mask; 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci out_err: 65362306a36Sopenharmony_ci release_sock(sk); 65462306a36Sopenharmony_ci rtnl_unlock(); 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci break; 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci case CAN_RAW_LOOPBACK: 65962306a36Sopenharmony_ci if (optlen != sizeof(ro->loopback)) 66062306a36Sopenharmony_ci return -EINVAL; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci if (copy_from_sockptr(&ro->loopback, optval, optlen)) 66362306a36Sopenharmony_ci return -EFAULT; 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci break; 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci case CAN_RAW_RECV_OWN_MSGS: 66862306a36Sopenharmony_ci if (optlen != sizeof(ro->recv_own_msgs)) 66962306a36Sopenharmony_ci return -EINVAL; 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci if (copy_from_sockptr(&ro->recv_own_msgs, optval, optlen)) 67262306a36Sopenharmony_ci return -EFAULT; 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci break; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci case CAN_RAW_FD_FRAMES: 67762306a36Sopenharmony_ci if (optlen != sizeof(fd_frames)) 67862306a36Sopenharmony_ci return -EINVAL; 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci if (copy_from_sockptr(&fd_frames, optval, optlen)) 68162306a36Sopenharmony_ci return -EFAULT; 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci /* Enabling CAN XL includes CAN FD */ 68462306a36Sopenharmony_ci if (ro->xl_frames && !fd_frames) 68562306a36Sopenharmony_ci return -EINVAL; 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci ro->fd_frames = fd_frames; 68862306a36Sopenharmony_ci break; 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci case CAN_RAW_XL_FRAMES: 69162306a36Sopenharmony_ci if (optlen != sizeof(ro->xl_frames)) 69262306a36Sopenharmony_ci return -EINVAL; 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci if (copy_from_sockptr(&ro->xl_frames, optval, optlen)) 69562306a36Sopenharmony_ci return -EFAULT; 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci /* Enabling CAN XL includes CAN FD */ 69862306a36Sopenharmony_ci if (ro->xl_frames) 69962306a36Sopenharmony_ci ro->fd_frames = ro->xl_frames; 70062306a36Sopenharmony_ci break; 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci case CAN_RAW_JOIN_FILTERS: 70362306a36Sopenharmony_ci if (optlen != sizeof(ro->join_filters)) 70462306a36Sopenharmony_ci return -EINVAL; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci if (copy_from_sockptr(&ro->join_filters, optval, optlen)) 70762306a36Sopenharmony_ci return -EFAULT; 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci break; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci default: 71262306a36Sopenharmony_ci return -ENOPROTOOPT; 71362306a36Sopenharmony_ci } 71462306a36Sopenharmony_ci return err; 71562306a36Sopenharmony_ci} 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_cistatic int raw_getsockopt(struct socket *sock, int level, int optname, 71862306a36Sopenharmony_ci char __user *optval, int __user *optlen) 71962306a36Sopenharmony_ci{ 72062306a36Sopenharmony_ci struct sock *sk = sock->sk; 72162306a36Sopenharmony_ci struct raw_sock *ro = raw_sk(sk); 72262306a36Sopenharmony_ci int len; 72362306a36Sopenharmony_ci void *val; 72462306a36Sopenharmony_ci int err = 0; 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci if (level != SOL_CAN_RAW) 72762306a36Sopenharmony_ci return -EINVAL; 72862306a36Sopenharmony_ci if (get_user(len, optlen)) 72962306a36Sopenharmony_ci return -EFAULT; 73062306a36Sopenharmony_ci if (len < 0) 73162306a36Sopenharmony_ci return -EINVAL; 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci switch (optname) { 73462306a36Sopenharmony_ci case CAN_RAW_FILTER: 73562306a36Sopenharmony_ci lock_sock(sk); 73662306a36Sopenharmony_ci if (ro->count > 0) { 73762306a36Sopenharmony_ci int fsize = ro->count * sizeof(struct can_filter); 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci /* user space buffer to small for filter list? */ 74062306a36Sopenharmony_ci if (len < fsize) { 74162306a36Sopenharmony_ci /* return -ERANGE and needed space in optlen */ 74262306a36Sopenharmony_ci err = -ERANGE; 74362306a36Sopenharmony_ci if (put_user(fsize, optlen)) 74462306a36Sopenharmony_ci err = -EFAULT; 74562306a36Sopenharmony_ci } else { 74662306a36Sopenharmony_ci if (len > fsize) 74762306a36Sopenharmony_ci len = fsize; 74862306a36Sopenharmony_ci if (copy_to_user(optval, ro->filter, len)) 74962306a36Sopenharmony_ci err = -EFAULT; 75062306a36Sopenharmony_ci } 75162306a36Sopenharmony_ci } else { 75262306a36Sopenharmony_ci len = 0; 75362306a36Sopenharmony_ci } 75462306a36Sopenharmony_ci release_sock(sk); 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci if (!err) 75762306a36Sopenharmony_ci err = put_user(len, optlen); 75862306a36Sopenharmony_ci return err; 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci case CAN_RAW_ERR_FILTER: 76162306a36Sopenharmony_ci if (len > sizeof(can_err_mask_t)) 76262306a36Sopenharmony_ci len = sizeof(can_err_mask_t); 76362306a36Sopenharmony_ci val = &ro->err_mask; 76462306a36Sopenharmony_ci break; 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci case CAN_RAW_LOOPBACK: 76762306a36Sopenharmony_ci if (len > sizeof(int)) 76862306a36Sopenharmony_ci len = sizeof(int); 76962306a36Sopenharmony_ci val = &ro->loopback; 77062306a36Sopenharmony_ci break; 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci case CAN_RAW_RECV_OWN_MSGS: 77362306a36Sopenharmony_ci if (len > sizeof(int)) 77462306a36Sopenharmony_ci len = sizeof(int); 77562306a36Sopenharmony_ci val = &ro->recv_own_msgs; 77662306a36Sopenharmony_ci break; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci case CAN_RAW_FD_FRAMES: 77962306a36Sopenharmony_ci if (len > sizeof(int)) 78062306a36Sopenharmony_ci len = sizeof(int); 78162306a36Sopenharmony_ci val = &ro->fd_frames; 78262306a36Sopenharmony_ci break; 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci case CAN_RAW_XL_FRAMES: 78562306a36Sopenharmony_ci if (len > sizeof(int)) 78662306a36Sopenharmony_ci len = sizeof(int); 78762306a36Sopenharmony_ci val = &ro->xl_frames; 78862306a36Sopenharmony_ci break; 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci case CAN_RAW_JOIN_FILTERS: 79162306a36Sopenharmony_ci if (len > sizeof(int)) 79262306a36Sopenharmony_ci len = sizeof(int); 79362306a36Sopenharmony_ci val = &ro->join_filters; 79462306a36Sopenharmony_ci break; 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci default: 79762306a36Sopenharmony_ci return -ENOPROTOOPT; 79862306a36Sopenharmony_ci } 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci if (put_user(len, optlen)) 80162306a36Sopenharmony_ci return -EFAULT; 80262306a36Sopenharmony_ci if (copy_to_user(optval, val, len)) 80362306a36Sopenharmony_ci return -EFAULT; 80462306a36Sopenharmony_ci return 0; 80562306a36Sopenharmony_ci} 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_cistatic bool raw_bad_txframe(struct raw_sock *ro, struct sk_buff *skb, int mtu) 80862306a36Sopenharmony_ci{ 80962306a36Sopenharmony_ci /* Classical CAN -> no checks for flags and device capabilities */ 81062306a36Sopenharmony_ci if (can_is_can_skb(skb)) 81162306a36Sopenharmony_ci return false; 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci /* CAN FD -> needs to be enabled and a CAN FD or CAN XL device */ 81462306a36Sopenharmony_ci if (ro->fd_frames && can_is_canfd_skb(skb) && 81562306a36Sopenharmony_ci (mtu == CANFD_MTU || can_is_canxl_dev_mtu(mtu))) 81662306a36Sopenharmony_ci return false; 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci /* CAN XL -> needs to be enabled and a CAN XL device */ 81962306a36Sopenharmony_ci if (ro->xl_frames && can_is_canxl_skb(skb) && 82062306a36Sopenharmony_ci can_is_canxl_dev_mtu(mtu)) 82162306a36Sopenharmony_ci return false; 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci return true; 82462306a36Sopenharmony_ci} 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_cistatic int raw_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) 82762306a36Sopenharmony_ci{ 82862306a36Sopenharmony_ci struct sock *sk = sock->sk; 82962306a36Sopenharmony_ci struct raw_sock *ro = raw_sk(sk); 83062306a36Sopenharmony_ci struct sockcm_cookie sockc; 83162306a36Sopenharmony_ci struct sk_buff *skb; 83262306a36Sopenharmony_ci struct net_device *dev; 83362306a36Sopenharmony_ci int ifindex; 83462306a36Sopenharmony_ci int err = -EINVAL; 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci /* check for valid CAN frame sizes */ 83762306a36Sopenharmony_ci if (size < CANXL_HDR_SIZE + CANXL_MIN_DLEN || size > CANXL_MTU) 83862306a36Sopenharmony_ci return -EINVAL; 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci if (msg->msg_name) { 84162306a36Sopenharmony_ci DECLARE_SOCKADDR(struct sockaddr_can *, addr, msg->msg_name); 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci if (msg->msg_namelen < RAW_MIN_NAMELEN) 84462306a36Sopenharmony_ci return -EINVAL; 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci if (addr->can_family != AF_CAN) 84762306a36Sopenharmony_ci return -EINVAL; 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci ifindex = addr->can_ifindex; 85062306a36Sopenharmony_ci } else { 85162306a36Sopenharmony_ci ifindex = ro->ifindex; 85262306a36Sopenharmony_ci } 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci dev = dev_get_by_index(sock_net(sk), ifindex); 85562306a36Sopenharmony_ci if (!dev) 85662306a36Sopenharmony_ci return -ENXIO; 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci skb = sock_alloc_send_skb(sk, size + sizeof(struct can_skb_priv), 85962306a36Sopenharmony_ci msg->msg_flags & MSG_DONTWAIT, &err); 86062306a36Sopenharmony_ci if (!skb) 86162306a36Sopenharmony_ci goto put_dev; 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci can_skb_reserve(skb); 86462306a36Sopenharmony_ci can_skb_prv(skb)->ifindex = dev->ifindex; 86562306a36Sopenharmony_ci can_skb_prv(skb)->skbcnt = 0; 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci /* fill the skb before testing for valid CAN frames */ 86862306a36Sopenharmony_ci err = memcpy_from_msg(skb_put(skb, size), msg, size); 86962306a36Sopenharmony_ci if (err < 0) 87062306a36Sopenharmony_ci goto free_skb; 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci err = -EINVAL; 87362306a36Sopenharmony_ci if (raw_bad_txframe(ro, skb, dev->mtu)) 87462306a36Sopenharmony_ci goto free_skb; 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci sockcm_init(&sockc, sk); 87762306a36Sopenharmony_ci if (msg->msg_controllen) { 87862306a36Sopenharmony_ci err = sock_cmsg_send(sk, msg, &sockc); 87962306a36Sopenharmony_ci if (unlikely(err)) 88062306a36Sopenharmony_ci goto free_skb; 88162306a36Sopenharmony_ci } 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci skb->dev = dev; 88462306a36Sopenharmony_ci skb->priority = sk->sk_priority; 88562306a36Sopenharmony_ci skb->mark = READ_ONCE(sk->sk_mark); 88662306a36Sopenharmony_ci skb->tstamp = sockc.transmit_time; 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci skb_setup_tx_timestamp(skb, sockc.tsflags); 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci err = can_send(skb, ro->loopback); 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci dev_put(dev); 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci if (err) 89562306a36Sopenharmony_ci goto send_failed; 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci return size; 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_cifree_skb: 90062306a36Sopenharmony_ci kfree_skb(skb); 90162306a36Sopenharmony_ciput_dev: 90262306a36Sopenharmony_ci dev_put(dev); 90362306a36Sopenharmony_cisend_failed: 90462306a36Sopenharmony_ci return err; 90562306a36Sopenharmony_ci} 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_cistatic int raw_recvmsg(struct socket *sock, struct msghdr *msg, size_t size, 90862306a36Sopenharmony_ci int flags) 90962306a36Sopenharmony_ci{ 91062306a36Sopenharmony_ci struct sock *sk = sock->sk; 91162306a36Sopenharmony_ci struct sk_buff *skb; 91262306a36Sopenharmony_ci int err = 0; 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci if (flags & MSG_ERRQUEUE) 91562306a36Sopenharmony_ci return sock_recv_errqueue(sk, msg, size, 91662306a36Sopenharmony_ci SOL_CAN_RAW, SCM_CAN_RAW_ERRQUEUE); 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci skb = skb_recv_datagram(sk, flags, &err); 91962306a36Sopenharmony_ci if (!skb) 92062306a36Sopenharmony_ci return err; 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci if (size < skb->len) 92362306a36Sopenharmony_ci msg->msg_flags |= MSG_TRUNC; 92462306a36Sopenharmony_ci else 92562306a36Sopenharmony_ci size = skb->len; 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci err = memcpy_to_msg(msg, skb->data, size); 92862306a36Sopenharmony_ci if (err < 0) { 92962306a36Sopenharmony_ci skb_free_datagram(sk, skb); 93062306a36Sopenharmony_ci return err; 93162306a36Sopenharmony_ci } 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci sock_recv_cmsgs(msg, sk, skb); 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci if (msg->msg_name) { 93662306a36Sopenharmony_ci __sockaddr_check_size(RAW_MIN_NAMELEN); 93762306a36Sopenharmony_ci msg->msg_namelen = RAW_MIN_NAMELEN; 93862306a36Sopenharmony_ci memcpy(msg->msg_name, skb->cb, msg->msg_namelen); 93962306a36Sopenharmony_ci } 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci /* assign the flags that have been recorded in raw_rcv() */ 94262306a36Sopenharmony_ci msg->msg_flags |= *(raw_flags(skb)); 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci skb_free_datagram(sk, skb); 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci return size; 94762306a36Sopenharmony_ci} 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_cistatic int raw_sock_no_ioctlcmd(struct socket *sock, unsigned int cmd, 95062306a36Sopenharmony_ci unsigned long arg) 95162306a36Sopenharmony_ci{ 95262306a36Sopenharmony_ci /* no ioctls for socket layer -> hand it down to NIC layer */ 95362306a36Sopenharmony_ci return -ENOIOCTLCMD; 95462306a36Sopenharmony_ci} 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_cistatic const struct proto_ops raw_ops = { 95762306a36Sopenharmony_ci .family = PF_CAN, 95862306a36Sopenharmony_ci .release = raw_release, 95962306a36Sopenharmony_ci .bind = raw_bind, 96062306a36Sopenharmony_ci .connect = sock_no_connect, 96162306a36Sopenharmony_ci .socketpair = sock_no_socketpair, 96262306a36Sopenharmony_ci .accept = sock_no_accept, 96362306a36Sopenharmony_ci .getname = raw_getname, 96462306a36Sopenharmony_ci .poll = datagram_poll, 96562306a36Sopenharmony_ci .ioctl = raw_sock_no_ioctlcmd, 96662306a36Sopenharmony_ci .gettstamp = sock_gettstamp, 96762306a36Sopenharmony_ci .listen = sock_no_listen, 96862306a36Sopenharmony_ci .shutdown = sock_no_shutdown, 96962306a36Sopenharmony_ci .setsockopt = raw_setsockopt, 97062306a36Sopenharmony_ci .getsockopt = raw_getsockopt, 97162306a36Sopenharmony_ci .sendmsg = raw_sendmsg, 97262306a36Sopenharmony_ci .recvmsg = raw_recvmsg, 97362306a36Sopenharmony_ci .mmap = sock_no_mmap, 97462306a36Sopenharmony_ci}; 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_cistatic struct proto raw_proto __read_mostly = { 97762306a36Sopenharmony_ci .name = "CAN_RAW", 97862306a36Sopenharmony_ci .owner = THIS_MODULE, 97962306a36Sopenharmony_ci .obj_size = sizeof(struct raw_sock), 98062306a36Sopenharmony_ci .init = raw_init, 98162306a36Sopenharmony_ci}; 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_cistatic const struct can_proto raw_can_proto = { 98462306a36Sopenharmony_ci .type = SOCK_RAW, 98562306a36Sopenharmony_ci .protocol = CAN_RAW, 98662306a36Sopenharmony_ci .ops = &raw_ops, 98762306a36Sopenharmony_ci .prot = &raw_proto, 98862306a36Sopenharmony_ci}; 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_cistatic struct notifier_block canraw_notifier = { 99162306a36Sopenharmony_ci .notifier_call = raw_notifier 99262306a36Sopenharmony_ci}; 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_cistatic __init int raw_module_init(void) 99562306a36Sopenharmony_ci{ 99662306a36Sopenharmony_ci int err; 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci pr_info("can: raw protocol\n"); 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci err = register_netdevice_notifier(&canraw_notifier); 100162306a36Sopenharmony_ci if (err) 100262306a36Sopenharmony_ci return err; 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci err = can_proto_register(&raw_can_proto); 100562306a36Sopenharmony_ci if (err < 0) { 100662306a36Sopenharmony_ci pr_err("can: registration of raw protocol failed\n"); 100762306a36Sopenharmony_ci goto register_proto_failed; 100862306a36Sopenharmony_ci } 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci return 0; 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ciregister_proto_failed: 101362306a36Sopenharmony_ci unregister_netdevice_notifier(&canraw_notifier); 101462306a36Sopenharmony_ci return err; 101562306a36Sopenharmony_ci} 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_cistatic __exit void raw_module_exit(void) 101862306a36Sopenharmony_ci{ 101962306a36Sopenharmony_ci can_proto_unregister(&raw_can_proto); 102062306a36Sopenharmony_ci unregister_netdevice_notifier(&canraw_notifier); 102162306a36Sopenharmony_ci} 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_cimodule_init(raw_module_init); 102462306a36Sopenharmony_cimodule_exit(raw_module_exit); 1025