Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
ip_up_down [2018/10/04 10:35] rpjdayip_up_down [2018/10/04 11:09] (current) – [__dev_change_flags()] rpjday
Line 260: Line 260:
 </code> </code>
  
 +===== Sockets and ioctl calls (net/socket.c) =====
 +
 +==== socket_file_ops ====
 +
 +<code>
 +static const struct file_operations socket_file_ops = {
 + .owner = THIS_MODULE,
 + .llseek = no_llseek,
 + .read_iter = sock_read_iter,
 + .write_iter = sock_write_iter,
 + .poll = sock_poll,
 + .unlocked_ioctl = sock_ioctl,
 +#ifdef CONFIG_COMPAT
 + .compat_ioctl = compat_sock_ioctl,
 +#endif
 + .mmap = sock_mmap,
 + .release = sock_close,
 + .fasync = sock_fasync,
 + .sendpage = sock_sendpage,
 + .splice_write = generic_splice_sendpage,
 + .splice_read = sock_splice_read,
 +};
 +</code>
 +
 +==== sock_ioctl() ====
 +
 +<code>
 +static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg)
 +{
 + struct socket *sock;
 + struct sock *sk;
 + void __user *argp = (void __user *)arg;
 + int pid, err;
 + struct net *net;
 +
 + sock = file->private_data;
 + sk = sock->sk;
 + net = sock_net(sk);
 +
 +... snip ...
 +
 + default:
 + err = sock_do_ioctl(net, sock, cmd, arg,
 +     sizeof(struct ifreq));
 + break;
 + }
 + return err;
 +}
 +</code>
 +
 +==== sock_do_ioctl() ====
 +
 +<code>
 +static long sock_do_ioctl(struct net *net, struct socket *sock,
 +   unsigned int cmd, unsigned long arg,
 +   unsigned int ifreq_size)
 +{
 + int err;
 + void __user *argp = (void __user *)arg;
 +
 + err = sock->ops->ioctl(sock, cmd, arg);
 +
 + /*
 + * If this ioctl is unknown try to hand it down
 + * to the NIC driver.
 + */
 + if (err != -ENOIOCTLCMD)
 + return err;
 +
 + if (cmd == SIOCGIFCONF) {
 + struct ifconf ifc;
 + if (copy_from_user(&ifc, argp, sizeof(struct ifconf)))
 + return -EFAULT;
 + rtnl_lock();
 + err = dev_ifconf(net, &ifc, sizeof(struct ifreq));
 + rtnl_unlock();
 + if (!err && copy_to_user(argp, &ifc, sizeof(struct ifconf)))
 + err = -EFAULT;
 + } else {
 + struct ifreq ifr;
 + bool need_copyout;
 + if (copy_from_user(&ifr, argp, ifreq_size))
 + return -EFAULT;
 + err = dev_ioctl(net, cmd, &ifr, &need_copyout);
 + if (!err && need_copyout)
 + if (copy_to_user(argp, &ifr, ifreq_size))
 + return -EFAULT;
 + }
 + return err;
 +}
 +</code>
 ===== struct ifreq ===== ===== struct ifreq =====
  
Line 309: Line 400:
 #define ifr_newname ifr_ifru.ifru_newname /* New name */ #define ifr_newname ifr_ifru.ifru_newname /* New name */
 #define ifr_settings ifr_ifru.ifru_settings /* Device/proto settings*/ #define ifr_settings ifr_ifru.ifru_settings /* Device/proto settings*/
 +</code>
 +
 +===== net/core/dev_ioctl.c =====
 +
 +==== dev_ioctl() ====
 +
 +<code>
 +int dev_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr, bool *need_copyout)
 +{
 +
 +... snip ...
 +
 + switch (cmd) {
 + /*
 + * These ioctl calls:
 + * - can be done by all.
 + * - atomic and do not require locking.
 + * - return a value
 + */
 + case SIOCGIFFLAGS:
 + case SIOCGIFMETRIC:
 + case SIOCGIFMTU:
 + case SIOCGIFHWADDR:
 + case SIOCGIFSLAVE:
 + case SIOCGIFMAP:
 + case SIOCGIFINDEX:
 + case SIOCGIFTXQLEN:
 + dev_load(net, ifr->ifr_name);
 + rcu_read_lock();
 + ret = dev_ifsioc_locked(net, ifr, cmd);
 + rcu_read_unlock();
 + if (colon)
 + *colon = ':';
 + return ret;
 +
 +... snip ...
 +
 + case SIOCSIFFLAGS:
 + case SIOCSIFMETRIC:
 + case SIOCSIFMTU:
 + case SIOCSIFHWADDR:
 + case SIOCSIFSLAVE:
 + case SIOCADDMULTI:
 + case SIOCDELMULTI:
 + case SIOCSIFHWBROADCAST:
 + case SIOCSMIIREG:
 + case SIOCBONDENSLAVE:
 + case SIOCBONDRELEASE:
 + case SIOCBONDSETHWADDR:
 + case SIOCBONDCHANGEACTIVE:
 + case SIOCBRADDIF:
 + case SIOCBRDELIF:
 + case SIOCSHWTSTAMP:
 + if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
 + return -EPERM;
 + /* fall through */
 + case SIOCBONDSLAVEINFOQUERY:
 + case SIOCBONDINFOQUERY:
 + dev_load(net, ifr->ifr_name);
 + rtnl_lock();
 + ret = dev_ifsioc(net, ifr, cmd);
 + rtnl_unlock();
 + if (need_copyout)
 + *need_copyout = false;
 + return ret;
 +</code>
 +
 +==== dev_ifsioc() ====
 +
 +<code>
 +static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd)
 +{
 + int err;
 + struct net_device *dev = __dev_get_by_name(net, ifr->ifr_name);
 + const struct net_device_ops *ops;
 +
 + if (!dev)
 + return -ENODEV;
 +
 + ops = dev->netdev_ops;
 +
 + switch (cmd) {
 + case SIOCSIFFLAGS: /* Set interface flags */
 + return dev_change_flags(dev, ifr->ifr_flags);
 +</code>
 +
 +===== net/core/dev.c =====
 +
 +==== dev_change_flags() ====
 +
 +<code>
 +int dev_change_flags(struct net_device *dev, unsigned int flags)
 +{
 + int ret;
 + unsigned int changes, old_flags = dev->flags, old_gflags = dev->gflags;
 +
 + ret = __dev_change_flags(dev, flags);
 + if (ret < 0)
 + return ret;
 +
 + changes = (old_flags ^ dev->flags) | (old_gflags ^ dev->gflags);
 + __dev_notify_flags(dev, old_flags, changes);
 + return ret;
 +}
 +</code>
 +
 +==== __dev_change_flags() ====
 +
 +<code>
 +int __dev_change_flags(struct net_device *dev, unsigned int flags)
 +{
 + unsigned int old_flags = dev->flags;
 + int ret;
 +
 + ASSERT_RTNL();
 +
 + /*
 + * Set the flags on our device.
 + */
 +
 + dev->flags = (flags & (IFF_DEBUG | IFF_NOTRAILERS | IFF_NOARP |
 +        IFF_DYNAMIC | IFF_MULTICAST | IFF_PORTSEL |
 +        IFF_AUTOMEDIA)) |
 +      (dev->flags & (IFF_UP | IFF_VOLATILE | IFF_PROMISC |
 +     IFF_ALLMULTI));
 +
 +... snip ...
 +
 + ret = 0;
 + if ((old_flags ^ flags) & IFF_UP) {
 + if (old_flags & IFF_UP)
 + __dev_close(dev);
 + else
 + ret = __dev_open(dev);
 + }
 </code> </code>
  • ip_up_down.1538649342.txt.gz
  • Last modified: 2018/10/04 10:35
  • by rpjday