User Tools

Site Tools


ip_up_down

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 09:04]
rpjday [do_chflags()]
ip_up_down [2018/10/04 11:09] (current)
rpjday [__dev_change_flags()]
Line 11: Line 11:
  
   * [[https://​git.kernel.org/​pub/​scm/​network/​iproute2/​iproute2.git|iproute2]]   * [[https://​git.kernel.org/​pub/​scm/​network/​iproute2/​iproute2.git|iproute2]]
 +
 +Issues:
 +
 +  * ''​iplink.c''​ redefines ''​iplink_req''​ for no reason (line 218)
 +  * Define ''​HAVE_LIBMNL''​ for error support.
  
 ===== Structures ===== ===== Structures =====
Line 79: Line 84:
 </​code>​ </​code>​
  
-==== struct ifreq ==== 
- 
-From [[https://​git.kernel.org/​pub/​scm/​linux/​kernel/​git/​torvalds/​linux.git/​tree/​include/​uapi/​linux/​if.h|include/​uapi/​linux/​if.h]]:​ 
- 
-<​code>​ 
-/* for compatibility with glibc net/if.h */ 
-#if __UAPI_DEF_IF_IFREQ 
-struct ifreq { 
-#define IFHWADDRLEN 6 
- union 
- { 
- char ifrn_name[IFNAMSIZ];​ /​* if name, e.g. "​en0"​ */ 
- } ifr_ifrn; 
-  
- union { 
- struct sockaddr ifru_addr; 
- struct sockaddr ifru_dstaddr;​ 
- struct sockaddr ifru_broadaddr;​ 
- struct sockaddr ifru_netmask;​ 
- struct ​ sockaddr ifru_hwaddr;​ 
- short ifru_flags;​ 
- int ifru_ivalue;​ 
- int ifru_mtu;​ 
- struct ​ ifmap ifru_map; 
- char ifru_slave[IFNAMSIZ];​ /​* Just fits the size */ 
- char ifru_newname[IFNAMSIZ];​ 
- void __user * ifru_data;​ 
- struct if_settings ifru_settings;​ 
- } ifr_ifru; 
-}; 
-#endif /* __UAPI_DEF_IF_IFREQ */ 
- 
-#define ifr_name ifr_ifrn.ifrn_name /​* interface name */ 
-#define ifr_hwaddr ifr_ifru.ifru_hwaddr /​* MAC address */ 
-#​define ifr_addr ifr_ifru.ifru_addr /​* address */ 
-#​define ifr_dstaddr ifr_ifru.ifru_dstaddr /​* other end of p-p lnk */ 
-#​define ifr_broadaddr ifr_ifru.ifru_broadaddr /​* broadcast address */ 
-#​define ifr_netmask ifr_ifru.ifru_netmask /​* interface net mask */ 
-#​define ifr_flags ifr_ifru.ifru_flags /​* flags */ 
-#​define ifr_metric ifr_ifru.ifru_ivalue /​* metric */ 
-#​define ifr_mtu ifr_ifru.ifru_mtu /​* mtu */ 
-#define ifr_map ifr_ifru.ifru_map /​* device map */ 
-#define ifr_slave ifr_ifru.ifru_slave /​* slave device */ 
-#​define ifr_data ifr_ifru.ifru_data /​* for use by interface */​ 
-#define ifr_ifindex ifr_ifru.ifru_ivalue /​* interface index */ 
-#define ifr_bandwidth ifr_ifru.ifru_ivalue ​   /* link bandwidth */​ 
-#define ifr_qlen ifr_ifru.ifru_ivalue /​* Queue length */ 
-#define ifr_newname ifr_ifru.ifru_newname /​* New name */ 
-#define ifr_settings ifr_ifru.ifru_settings /​* Device/​proto settings*/ 
-</​code>​ 
 ===== Usage ===== ===== Usage =====
  
Line 243: Line 198:
  
 ==== do_set() ==== ==== do_set() ====
 +
 +Modify the appropriate flags:
  
 <​code>​ <​code>​
Line 301: Line 258:
         return err;         return err;
 } }
 +</​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 =====
 +
 +From [[https://​git.kernel.org/​pub/​scm/​linux/​kernel/​git/​torvalds/​linux.git/​tree/​include/​uapi/​linux/​if.h|include/​uapi/​linux/​if.h]]:​
 +
 +<​code>​
 +/* for compatibility with glibc net/if.h */
 +#if __UAPI_DEF_IF_IFREQ
 +struct ifreq {
 +#define IFHWADDRLEN 6
 + union
 + {
 + char ifrn_name[IFNAMSIZ];​ /​* if name, e.g. "​en0"​ */
 + } ifr_ifrn;
 +
 + union {
 + struct sockaddr ifru_addr;
 + struct sockaddr ifru_dstaddr;​
 + struct sockaddr ifru_broadaddr;​
 + struct sockaddr ifru_netmask;​
 + struct ​ sockaddr ifru_hwaddr;​
 + short ifru_flags;​
 + int ifru_ivalue;​
 + int ifru_mtu;​
 + struct ​ ifmap ifru_map;
 + char ifru_slave[IFNAMSIZ];​ /​* Just fits the size */
 + char ifru_newname[IFNAMSIZ];​
 + void __user * ifru_data;​
 + struct if_settings ifru_settings;​
 + } ifr_ifru;
 +};
 +#endif /* __UAPI_DEF_IF_IFREQ */
 +
 +#define ifr_name ifr_ifrn.ifrn_name /​* interface name */
 +#define ifr_hwaddr ifr_ifru.ifru_hwaddr /​* MAC address */
 +#​define ifr_addr ifr_ifru.ifru_addr /​* address */
 +#​define ifr_dstaddr ifr_ifru.ifru_dstaddr /​* other end of p-p lnk */
 +#​define ifr_broadaddr ifr_ifru.ifru_broadaddr /​* broadcast address */
 +#​define ifr_netmask ifr_ifru.ifru_netmask /​* interface net mask */
 +#​define ifr_flags ifr_ifru.ifru_flags /​* flags */
 +#​define ifr_metric ifr_ifru.ifru_ivalue /​* metric */
 +#​define ifr_mtu ifr_ifru.ifru_mtu /​* mtu */
 +#define ifr_map ifr_ifru.ifru_map /​* device map */
 +#define ifr_slave ifr_ifru.ifru_slave /​* slave device */
 +#​define ifr_data ifr_ifru.ifru_data /​* for use by interface */​
 +#define ifr_ifindex ifr_ifru.ifru_ivalue /​* interface index */
 +#define ifr_bandwidth ifr_ifru.ifru_ivalue ​   /* link bandwidth */​
 +#define ifr_qlen ifr_ifru.ifru_ivalue /​* Queue length */
 +#define ifr_newname ifr_ifru.ifru_newname /​* New name */
 +#define ifr_settings ifr_ifru.ifru_settings /​* Device/​proto settings*/
 </​code>​ </​code>​
  
 ===== net/​core/​dev_ioctl.c ===== ===== 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>​
ip_up_down.1538643877.txt.gz ยท Last modified: 2018/10/04 09:04 by rpjday