static int raw_release(struct socket *sock) { struct sock *sk = sock->sk; struct raw_sock *ro = raw_sk(sk); unregister_netdevice_notifier(&ro->notifier); lock_sock(sk); /* remove current filters & unregister */ if (ro->bound) { if (ro->ifindex) { struct net_device *dev; dev = dev_get_by_index(&init_net, ro->ifindex); if (dev) { raw_disable_allfilters(dev, sk); dev_put(dev); } } else raw_disable_allfilters(NULL, sk); } if (ro->count > 1) kfree(ro->filter); ro->ifindex = 0; ro->bound = 0; ro->count = 0; sock_orphan(sk); sock->sk = NULL; release_sock(sk); sock_put(sk); return 0; }
static int raw_init(struct sock *sk) { struct raw_sock *ro = raw_sk(sk); ro->bound = 0; ro->ifindex = 0; /* set default filter to single entry dfilter */ ro->dfilter.can_id = 0; ro->dfilter.can_mask = MASK_ALL; ro->filter = &ro->dfilter; ro->count = 1; /* set default loopback behaviour */ ro->loopback = 1; ro->recv_own_msgs = 0; /* set notifier */ ro->notifier.notifier_call = raw_notifier; register_netdevice_notifier(&ro->notifier); return 0; }
static int raw_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen) { struct sock *sk = sock->sk; struct raw_sock *ro = raw_sk(sk); int len; void *val; int err = 0; if (level != SOL_CAN_RAW) return -EINVAL; if (get_user(len, optlen)) return -EFAULT; if (len < 0) return -EINVAL; switch (optname) { case CAN_RAW_FILTER: lock_sock(sk); if (ro->count > 0) { int fsize = ro->count * sizeof(struct can_filter); if (len > fsize) len = fsize; err = copy_to_user(optval, ro->filter, len); } else len = 0; release_sock(sk); if (!err) err = put_user(len, optlen); return err; case CAN_RAW_ERR_FILTER: if (len > sizeof(can_err_mask_t)) len = sizeof(can_err_mask_t); val = &ro->err_mask; break; case CAN_RAW_LOOPBACK: if (len > sizeof(int)) len = sizeof(int); val = &ro->loopback; break; case CAN_RAW_RECV_OWN_MSGS: if (len > sizeof(int)) len = sizeof(int); val = &ro->recv_own_msgs; break; default: return -ENOPROTOOPT; } if (put_user(len, optlen)) return -EFAULT; if (copy_to_user(optval, val, len)) return -EFAULT; return 0; }
static int raw_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen) { struct sock *sk = sock->sk; struct raw_sock *ro = raw_sk(sk); struct can_filter *filter = NULL; /* dyn. alloc'ed filters */ struct can_filter sfilter; /* single filter */ struct net_device *dev = NULL; can_err_mask_t err_mask = 0; int count = 0; int err = 0; if (level != SOL_CAN_RAW) return -EINVAL; if (optlen < 0) return -EINVAL; switch (optname) { case CAN_RAW_FILTER: if (optlen % sizeof(struct can_filter) != 0) return -EINVAL; count = optlen / sizeof(struct can_filter); if (count > 1) { /* filter does not fit into dfilter => alloc space */ filter = kmalloc(optlen, GFP_KERNEL); if (!filter) return -ENOMEM; err = copy_from_user(filter, optval, optlen); if (err) { kfree(filter); return err; } } else if (count == 1) { err = copy_from_user(&sfilter, optval, optlen); if (err) return err; } lock_sock(sk); if (ro->bound && ro->ifindex) dev = dev_get_by_index(&init_net, ro->ifindex); if (ro->bound) { /* (try to) register the new filters */ if (count == 1) err = raw_enable_filters(dev, sk, &sfilter, 1); else err = raw_enable_filters(dev, sk, filter, count); if (err) { if (count > 1) kfree(filter); goto out_fil; } /* remove old filter registrations */ raw_disable_filters(dev, sk, ro->filter, ro->count); } /* remove old filter space */ if (ro->count > 1) kfree(ro->filter); /* link new filters to the socket */ if (count == 1) { /* copy filter data for single filter */ ro->dfilter = sfilter; filter = &ro->dfilter; } ro->filter = filter; ro->count = count; out_fil: if (dev) dev_put(dev); release_sock(sk); break; case CAN_RAW_ERR_FILTER: if (optlen != sizeof(err_mask)) return -EINVAL; err = copy_from_user(&err_mask, optval, optlen); if (err) return err; err_mask &= CAN_ERR_MASK; lock_sock(sk); if (ro->bound && ro->ifindex) dev = dev_get_by_index(&init_net, ro->ifindex); /* remove current error mask */ if (ro->bound) { /* (try to) register the new err_mask */ err = raw_enable_errfilter(dev, sk, err_mask); if (err) goto out_err; /* remove old err_mask registration */ raw_disable_errfilter(dev, sk, ro->err_mask); } /* link new err_mask to the socket */ ro->err_mask = err_mask; out_err: if (dev) dev_put(dev); release_sock(sk); break; case CAN_RAW_LOOPBACK: if (optlen != sizeof(ro->loopback)) return -EINVAL; err = copy_from_user(&ro->loopback, optval, optlen); break; case CAN_RAW_RECV_OWN_MSGS: if (optlen != sizeof(ro->recv_own_msgs)) return -EINVAL; err = copy_from_user(&ro->recv_own_msgs, optval, optlen); break; default: return -ENOPROTOOPT; } return err; }
static int raw_bind(struct socket *sock, struct sockaddr *uaddr, int len) { struct sockaddr_can *addr = (struct sockaddr_can *)uaddr; struct sock *sk = sock->sk; struct raw_sock *ro = raw_sk(sk); int ifindex; int err = 0; int notify_enetdown = 0; if (len < sizeof(*addr)) return -EINVAL; lock_sock(sk); if (ro->bound && addr->can_ifindex == ro->ifindex) goto out; if (addr->can_ifindex) { struct net_device *dev; dev = dev_get_by_index(&init_net, addr->can_ifindex); if (!dev) { err = -ENODEV; goto out; } if (dev->type != ARPHRD_CAN) { dev_put(dev); err = -ENODEV; goto out; } if (!(dev->flags & IFF_UP)) notify_enetdown = 1; ifindex = dev->ifindex; /* filters set by default/setsockopt */ err = raw_enable_allfilters(dev, sk); dev_put(dev); } else { ifindex = 0; /* filters set by default/setsockopt */ err = raw_enable_allfilters(NULL, sk); } if (!err) { if (ro->bound) { /* unregister old filters */ if (ro->ifindex) { struct net_device *dev; dev = dev_get_by_index(&init_net, ro->ifindex); if (dev) { raw_disable_allfilters(dev, sk); dev_put(dev); } } else raw_disable_allfilters(NULL, sk); } ro->ifindex = ifindex; ro->bound = 1; } out: release_sock(sk); if (notify_enetdown) { sk->sk_err = ENETDOWN; if (!sock_flag(sk, SOCK_DEAD)) sk->sk_error_report(sk); } return err; }
static int raw_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen) { struct sock *sk = sock->sk; struct raw_opt *ro = raw_sk(sk); struct can_filter *filter = ro->filter; int count = ro->count; int len; if (level != SOL_CAN_RAW) return -EINVAL; switch (optname) { case CAN_RAW_FILTER: if (get_user(len, optlen)) return -EFAULT; if (count && filter) { int filter_size = count * sizeof(struct can_filter); if (len < filter_size) return -EINVAL; if (len > filter_size) len = filter_size; if (copy_to_user(optval, filter, len)) return -EFAULT; } else len = 0; if (put_user(len, optlen)) return -EFAULT; break; case CAN_RAW_ERR_FILTER: if (get_user(len, optlen)) return -EFAULT; if (len < sizeof(can_err_mask_t)) return -EINVAL; if (len > sizeof(can_err_mask_t)) len = sizeof(can_err_mask_t); if (copy_to_user(optval, &ro->err_mask, len)) return -EFAULT; if (put_user(len, optlen)) return -EFAULT; break; case CAN_RAW_LOOPBACK: if (get_user(len, optlen)) return -EFAULT; if (len < sizeof(int)) return -EINVAL; if (len > sizeof(int)) len = sizeof(int); if (copy_to_user(optval, &ro->loopback, len)) return -EFAULT; if (put_user(len, optlen)) return -EFAULT; break; case CAN_RAW_RECV_OWN_MSGS: if (get_user(len, optlen)) return -EFAULT; if (len < sizeof(int)) return -EINVAL; if (len > sizeof(int)) len = sizeof(int); if (copy_to_user(optval, &ro->recv_own_msgs, len)) return -EFAULT; if (put_user(len, optlen)) return -EFAULT; break; default: return -ENOPROTOOPT; } return 0; }
static int raw_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen) { struct sock *sk = sock->sk; struct raw_opt *ro = raw_sk(sk); struct can_filter *filter = NULL; /* dyn. alloc'ed filters */ struct can_filter sfilter; /* single filter */ struct net_device *dev = NULL; can_err_mask_t err_mask = 0; int count = 0; int err; if (level != SOL_CAN_RAW) return -EINVAL; switch (optname) { case CAN_RAW_FILTER: if (optlen % sizeof(struct can_filter) != 0) return -EINVAL; count = optlen / sizeof(struct can_filter); if (count > 1) { /* filter does not fit into dfilter => alloc space */ filter = kmalloc(optlen, GFP_KERNEL); if (!filter) return -ENOMEM; err = copy_from_user(filter, optval, optlen); if (err) { kfree(filter); return err; } } else if (count == 1) { err = copy_from_user(&sfilter, optval, optlen); if (err) return err; } if (ro->bound && ro->ifindex) dev = dev_get_by_index(ro->ifindex); /* remove current filters & unregister */ if (ro->bound) raw_remove_filters(dev, sk); if (ro->count > 1) kfree(ro->filter); if (count == 1) { /* copy filter data for single filter */ ro->dfilter = sfilter; filter = &ro->dfilter; } /* add new filters & register */ ro->filter = filter; ro->count = count; if (ro->bound) raw_add_filters(dev, sk); if (dev) dev_put(dev); break; case CAN_RAW_ERR_FILTER: if (optlen != sizeof(err_mask)) return -EINVAL; err = copy_from_user(&err_mask, optval, optlen); if (err) return err; err_mask &= CAN_ERR_MASK; if (ro->bound && ro->ifindex) dev = dev_get_by_index(ro->ifindex); /* remove current error mask */ if (ro->err_mask && ro->bound) can_rx_unregister(dev, 0, ro->err_mask | CAN_ERR_FLAG, raw_rcv, sk); /* add new error mask */ ro->err_mask = err_mask; if (ro->err_mask && ro->bound) can_rx_register(dev, 0, ro->err_mask | CAN_ERR_FLAG, raw_rcv, sk, IDENT); if (dev) dev_put(dev); break; case CAN_RAW_LOOPBACK: if (optlen != sizeof(ro->loopback)) return -EINVAL; err = copy_from_user(&ro->loopback, optval, optlen); if (err) return err; break; case CAN_RAW_RECV_OWN_MSGS: if (optlen != sizeof(ro->recv_own_msgs)) return -EINVAL; err = copy_from_user(&ro->recv_own_msgs, optval, optlen); if (err) return err; break; default: return -ENOPROTOOPT; } return 0; }
static int raw_bind(struct socket *sock, struct sockaddr *uaddr, int len) { struct sockaddr_can *addr = (struct sockaddr_can *)uaddr; struct sock *sk = sock->sk; struct raw_opt *ro = raw_sk(sk); struct net_device *dev; DBG("socket %p to device %d\n", sock, addr->can_ifindex); if (len < sizeof(*addr)) return -EINVAL; if (ro->bound) { #ifdef CAN_RAW_SUPPORT_REBIND /* remove current bindings / notifier */ if (ro->ifindex) { dev = dev_get_by_index(ro->ifindex); if (!dev) { DBG("could not find device %d\n", addr->can_ifindex); return -ENODEV; } if (!(dev->flags & IFF_UP)) { sk->sk_err = ENETDOWN; if (!sock_flag(sk, SOCK_DEAD)) sk->sk_error_report(sk); goto out; } can_dev_unregister(dev, raw_notifier, sk); } else dev = NULL; /* unregister current filters for this device */ raw_remove_filters(dev, sk); if (dev) dev_put(dev); ro->bound = 0; #else return -EINVAL; #endif } if (addr->can_ifindex) { dev = dev_get_by_index(addr->can_ifindex); if (!dev) { DBG("could not find device %d\n", addr->can_ifindex); return -ENODEV; } if (!(dev->flags & IFF_UP)) { sk->sk_err = ENETDOWN; if (!sock_flag(sk, SOCK_DEAD)) sk->sk_error_report(sk); goto out; } can_dev_register(dev, raw_notifier, sk); } else dev = NULL; ro->ifindex = addr->can_ifindex; /* filters set by default/setsockopt */ raw_add_filters(dev, sk); /* error frame filter set by setsockopt */ if (ro->err_mask) can_rx_register(dev, 0, ro->err_mask | CAN_ERR_FLAG, raw_rcv, sk, IDENT); ro->bound = 1; out: if (dev) dev_put(dev); return 0; }
static int raw_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t size) { struct sock *sk = sock->sk; struct raw_sock *ro = raw_sk(sk); struct sk_buff *skb; struct net_device *dev; int ifindex; int err; if (msg->msg_name) { struct sockaddr_can *addr = (struct sockaddr_can *)msg->msg_name; if (msg->msg_namelen < sizeof(*addr)) return -EINVAL; if (addr->can_family != AF_CAN) return -EINVAL; ifindex = addr->can_ifindex; } else ifindex = ro->ifindex; if (size != sizeof(struct can_frame)) return -EINVAL; dev = dev_get_by_index(&init_net, ifindex); if (!dev) return -ENXIO; skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT, &err); if (!skb) goto put_dev; err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size); if (err < 0) goto free_skb; err = sock_tx_timestamp(sk, &skb_shinfo(skb)->tx_flags); if (err < 0) goto free_skb; /* to be able to check the received tx sock reference in raw_rcv() */ skb_shinfo(skb)->tx_flags |= SKBTX_DRV_NEEDS_SK_REF; skb->dev = dev; skb->sk = sk; err = can_send(skb, ro->loopback); dev_put(dev); if (err) goto send_failed; return size; free_skb: kfree_skb(skb); put_dev: dev_put(dev); send_failed: return err; }
static void raw_rcv(struct sk_buff *oskb, void *data) { struct sock *sk = (struct sock *)data; struct raw_sock *ro = raw_sk(sk); struct sockaddr_can *addr; struct sk_buff *skb; unsigned int *pflags; /* check the received tx sock reference */ if (!ro->recv_own_msgs && oskb->sk == sk) return; /* do not pass non-CAN2.0 frames to a legacy socket */ if (!ro->fd_frames && oskb->len != CAN_MTU) return; /* eliminate multiple filter matches for the same skb */ if (this_cpu_ptr(ro->uniq)->skb == oskb && this_cpu_ptr(ro->uniq)->skbcnt == can_skb_prv(oskb)->skbcnt) { if (ro->join_filters) { this_cpu_inc(ro->uniq->join_rx_count); /* drop frame until all enabled filters matched */ if (this_cpu_ptr(ro->uniq)->join_rx_count < ro->count) return; } else { return; } } else { this_cpu_ptr(ro->uniq)->skb = oskb; this_cpu_ptr(ro->uniq)->skbcnt = can_skb_prv(oskb)->skbcnt; this_cpu_ptr(ro->uniq)->join_rx_count = 1; /* drop first frame to check all enabled filters? */ if (ro->join_filters && ro->count > 1) return; } /* clone the given skb to be able to enqueue it into the rcv queue */ skb = skb_clone(oskb, GFP_ATOMIC); if (!skb) return; /* * Put the datagram to the queue so that raw_recvmsg() can * get it from there. We need to pass the interface index to * raw_recvmsg(). We pass a whole struct sockaddr_can in skb->cb * containing the interface index. */ sock_skb_cb_check_size(sizeof(struct sockaddr_can)); addr = (struct sockaddr_can *)skb->cb; memset(addr, 0, sizeof(*addr)); addr->can_family = AF_CAN; addr->can_ifindex = skb->dev->ifindex; /* add CAN specific message flags for raw_recvmsg() */ pflags = raw_flags(skb); *pflags = 0; if (oskb->sk) *pflags |= MSG_DONTROUTE; if (oskb->sk == sk) *pflags |= MSG_CONFIRM; if (sock_queue_rcv_skb(sk, skb) < 0) kfree_skb(skb); }
static int raw_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; struct raw_sock *ro = raw_sk(sk); struct can_filter *filter = NULL; struct can_filter sfilter; struct net_device *dev = NULL; can_err_mask_t err_mask = 0; int count = 0; int err = 0; if (level != SOL_CAN_RAW) return -EINVAL; switch (optname) { case CAN_RAW_FILTER: if (optlen % sizeof(struct can_filter) != 0) return -EINVAL; count = optlen / sizeof(struct can_filter); if (count > 1) { filter = memdup_user(optval, optlen); if (IS_ERR(filter)) return PTR_ERR(filter); } else if (count == 1) { if (copy_from_user(&sfilter, optval, sizeof(sfilter))) return -EFAULT; } lock_sock(sk); if (ro->bound && ro->ifindex) dev = dev_get_by_index(&init_net, ro->ifindex); if (ro->bound) { if (count == 1) err = raw_enable_filters(dev, sk, &sfilter, 1); else err = raw_enable_filters(dev, sk, filter, count); if (err) { if (count > 1) kfree(filter); goto out_fil; } raw_disable_filters(dev, sk, ro->filter, ro->count); } if (ro->count > 1) kfree(ro->filter); if (count == 1) { ro->dfilter = sfilter; filter = &ro->dfilter; } ro->filter = filter; ro->count = count; out_fil: if (dev) dev_put(dev); release_sock(sk); break; case CAN_RAW_ERR_FILTER: if (optlen != sizeof(err_mask)) return -EINVAL; if (copy_from_user(&err_mask, optval, optlen)) return -EFAULT; err_mask &= CAN_ERR_MASK; lock_sock(sk); if (ro->bound && ro->ifindex) dev = dev_get_by_index(&init_net, ro->ifindex); if (ro->bound) { err = raw_enable_errfilter(dev, sk, err_mask); if (err) goto out_err; raw_disable_errfilter(dev, sk, ro->err_mask); } ro->err_mask = err_mask; out_err: if (dev) dev_put(dev); release_sock(sk); break; case CAN_RAW_LOOPBACK: if (optlen != sizeof(ro->loopback)) return -EINVAL; if (copy_from_user(&ro->loopback, optval, optlen)) return -EFAULT; break; case CAN_RAW_RECV_OWN_MSGS: if (optlen != sizeof(ro->recv_own_msgs)) return -EINVAL; if (copy_from_user(&ro->recv_own_msgs, optval, optlen)) return -EFAULT; break; default: return -ENOPROTOOPT; } return err; }
static int raw_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t size) { struct sock *sk = sock->sk; struct raw_sock *ro = raw_sk(sk); struct sk_buff *skb; struct net_device *dev; int ifindex; int err; if (msg->msg_name) { struct sockaddr_can *addr = (struct sockaddr_can *)msg->msg_name; if (msg->msg_namelen < sizeof(*addr)) return -EINVAL; if (addr->can_family != AF_CAN) return -EINVAL; ifindex = addr->can_ifindex; } else ifindex = ro->ifindex; if (ro->fd_frames) { if (unlikely(size != CANFD_MTU && size != CAN_MTU)) return -EINVAL; } else { if (unlikely(size != CAN_MTU)) return -EINVAL; } dev = dev_get_by_index(&init_net, ifindex); if (!dev) return -ENXIO; skb = sock_alloc_send_skb(sk, size + sizeof(struct can_skb_priv), msg->msg_flags & MSG_DONTWAIT, &err); if (!skb) goto put_dev; can_skb_reserve(skb); can_skb_prv(skb)->ifindex = dev->ifindex; err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size); if (err < 0) goto free_skb; err = sock_tx_timestamp(sk, &skb_shinfo(skb)->tx_flags); if (err < 0) goto free_skb; skb->dev = dev; skb->sk = sk; err = can_send(skb, ro->loopback); dev_put(dev); if (err) goto send_failed; return size; free_skb: kfree_skb(skb); put_dev: dev_put(dev); send_failed: return err; }