Differences
This shows you the differences between two versions of the page.
| Both sides previous revision Previous revision Next revision | Previous revision | ||
| ip_up_down [2018/10/04 10:52] – [Sockets and ioctl calls] rpjday | ip_up_down [2018/10/04 11:09] (current) – [__dev_change_flags()] rpjday | ||
|---|---|---|---|
| Line 407: | Line 407: | ||
| < | < | ||
| + | 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, | ||
| + | rcu_read_lock(); | ||
| + | ret = dev_ifsioc_locked(net, | ||
| + | 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-> | ||
| + | return -EPERM; | ||
| + | /* fall through */ | ||
| + | case SIOCBONDSLAVEINFOQUERY: | ||
| + | case SIOCBONDINFOQUERY: | ||
| + | dev_load(net, | ||
| + | rtnl_lock(); | ||
| + | ret = dev_ifsioc(net, | ||
| + | rtnl_unlock(); | ||
| + | if (need_copyout) | ||
| + | *need_copyout = false; | ||
| + | return ret; | ||
| </ | </ | ||
| + | ==== dev_ifsioc() ==== | ||
| + | < | ||
| + | static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd) | ||
| + | { | ||
| + | int err; | ||
| + | struct net_device *dev = __dev_get_by_name(net, | ||
| + | const struct net_device_ops *ops; | ||
| + | |||
| + | if (!dev) | ||
| + | return -ENODEV; | ||
| + | |||
| + | ops = dev-> | ||
| + | |||
| + | switch (cmd) { | ||
| + | case SIOCSIFFLAGS: | ||
| + | return dev_change_flags(dev, | ||
| + | </ | ||
| + | |||
| + | ===== net/ | ||
| + | |||
| + | ==== dev_change_flags() ==== | ||
| + | |||
| + | < | ||
| + | int dev_change_flags(struct net_device *dev, unsigned int flags) | ||
| + | { | ||
| + | int ret; | ||
| + | unsigned int changes, old_flags = dev-> | ||
| + | |||
| + | ret = __dev_change_flags(dev, | ||
| + | if (ret < 0) | ||
| + | return ret; | ||
| + | |||
| + | changes = (old_flags ^ dev-> | ||
| + | __dev_notify_flags(dev, | ||
| + | return ret; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ==== __dev_change_flags() ==== | ||
| + | |||
| + | < | ||
| + | int __dev_change_flags(struct net_device *dev, unsigned int flags) | ||
| + | { | ||
| + | unsigned int old_flags = dev-> | ||
| + | int ret; | ||
| + | |||
| + | ASSERT_RTNL(); | ||
| + | |||
| + | /* | ||
| + | * Set the flags on our device. | ||
| + | */ | ||
| + | |||
| + | dev-> | ||
| + | | ||
| + | | ||
| + | | ||
| + | IFF_ALLMULTI)); | ||
| + | |||
| + | ... snip ... | ||
| + | |||
| + | ret = 0; | ||
| + | if ((old_flags ^ flags) & IFF_UP) { | ||
| + | if (old_flags & IFF_UP) | ||
| + | __dev_close(dev); | ||
| + | else | ||
| + | ret = __dev_open(dev); | ||
| + | } | ||
| + | </ | ||