1 | // SPDX-License-Identifier: GPL-2.0 |
2 | #include <linux/kmod.h> |
3 | #include <linux/netdevice.h> |
4 | #include <linux/inetdevice.h> |
5 | #include <linux/etherdevice.h> |
6 | #include <linux/rtnetlink.h> |
7 | #include <linux/net_tstamp.h> |
8 | #include <linux/phylib_stubs.h> |
9 | #include <linux/wireless.h> |
10 | #include <linux/if_bridge.h> |
11 | #include <net/dsa_stubs.h> |
12 | #include <net/wext.h> |
13 | |
14 | #include "dev.h" |
15 | |
16 | /* |
17 | * Map an interface index to its name (SIOCGIFNAME) |
18 | */ |
19 | |
20 | /* |
21 | * We need this ioctl for efficient implementation of the |
22 | * if_indextoname() function required by the IPv6 API. Without |
23 | * it, we would have to search all the interfaces to find a |
24 | * match. --pb |
25 | */ |
26 | |
27 | static int dev_ifname(struct net *net, struct ifreq *ifr) |
28 | { |
29 | ifr->ifr_name[IFNAMSIZ-1] = 0; |
30 | return netdev_get_name(net, name: ifr->ifr_name, ifindex: ifr->ifr_ifindex); |
31 | } |
32 | |
33 | /* |
34 | * Perform a SIOCGIFCONF call. This structure will change |
35 | * size eventually, and there is nothing I can do about it. |
36 | * Thus we will need a 'compatibility mode'. |
37 | */ |
38 | int dev_ifconf(struct net *net, struct ifconf __user *uifc) |
39 | { |
40 | struct net_device *dev; |
41 | void __user *pos; |
42 | size_t size; |
43 | int len, total = 0, done; |
44 | |
45 | /* both the ifconf and the ifreq structures are slightly different */ |
46 | if (in_compat_syscall()) { |
47 | struct compat_ifconf ifc32; |
48 | |
49 | if (copy_from_user(to: &ifc32, from: uifc, n: sizeof(struct compat_ifconf))) |
50 | return -EFAULT; |
51 | |
52 | pos = compat_ptr(uptr: ifc32.ifcbuf); |
53 | len = ifc32.ifc_len; |
54 | size = sizeof(struct compat_ifreq); |
55 | } else { |
56 | struct ifconf ifc; |
57 | |
58 | if (copy_from_user(to: &ifc, from: uifc, n: sizeof(struct ifconf))) |
59 | return -EFAULT; |
60 | |
61 | pos = ifc.ifc_buf; |
62 | len = ifc.ifc_len; |
63 | size = sizeof(struct ifreq); |
64 | } |
65 | |
66 | /* Loop over the interfaces, and write an info block for each. */ |
67 | rtnl_lock(); |
68 | for_each_netdev(net, dev) { |
69 | if (!pos) |
70 | done = inet_gifconf(dev, NULL, len: 0, size); |
71 | else |
72 | done = inet_gifconf(dev, buf: pos + total, |
73 | len: len - total, size); |
74 | if (done < 0) { |
75 | rtnl_unlock(); |
76 | return -EFAULT; |
77 | } |
78 | total += done; |
79 | } |
80 | rtnl_unlock(); |
81 | |
82 | return put_user(total, &uifc->ifc_len); |
83 | } |
84 | |
85 | static int dev_getifmap(struct net_device *dev, struct ifreq *ifr) |
86 | { |
87 | struct ifmap *ifmap = &ifr->ifr_map; |
88 | |
89 | if (in_compat_syscall()) { |
90 | struct compat_ifmap *cifmap = (struct compat_ifmap *)ifmap; |
91 | |
92 | cifmap->mem_start = dev->mem_start; |
93 | cifmap->mem_end = dev->mem_end; |
94 | cifmap->base_addr = dev->base_addr; |
95 | cifmap->irq = dev->irq; |
96 | cifmap->dma = dev->dma; |
97 | cifmap->port = dev->if_port; |
98 | |
99 | return 0; |
100 | } |
101 | |
102 | ifmap->mem_start = dev->mem_start; |
103 | ifmap->mem_end = dev->mem_end; |
104 | ifmap->base_addr = dev->base_addr; |
105 | ifmap->irq = dev->irq; |
106 | ifmap->dma = dev->dma; |
107 | ifmap->port = dev->if_port; |
108 | |
109 | return 0; |
110 | } |
111 | |
112 | static int dev_setifmap(struct net_device *dev, struct ifreq *ifr) |
113 | { |
114 | struct compat_ifmap *cifmap = (struct compat_ifmap *)&ifr->ifr_map; |
115 | |
116 | if (!dev->netdev_ops->ndo_set_config) |
117 | return -EOPNOTSUPP; |
118 | |
119 | if (in_compat_syscall()) { |
120 | struct ifmap ifmap = { |
121 | .mem_start = cifmap->mem_start, |
122 | .mem_end = cifmap->mem_end, |
123 | .base_addr = cifmap->base_addr, |
124 | .irq = cifmap->irq, |
125 | .dma = cifmap->dma, |
126 | .port = cifmap->port, |
127 | }; |
128 | |
129 | return dev->netdev_ops->ndo_set_config(dev, &ifmap); |
130 | } |
131 | |
132 | return dev->netdev_ops->ndo_set_config(dev, &ifr->ifr_map); |
133 | } |
134 | |
135 | /* |
136 | * Perform the SIOCxIFxxx calls, inside rcu_read_lock() |
137 | */ |
138 | static int dev_ifsioc_locked(struct net *net, struct ifreq *ifr, unsigned int cmd) |
139 | { |
140 | int err; |
141 | struct net_device *dev = dev_get_by_name_rcu(net, name: ifr->ifr_name); |
142 | |
143 | if (!dev) |
144 | return -ENODEV; |
145 | |
146 | switch (cmd) { |
147 | case SIOCGIFFLAGS: /* Get interface flags */ |
148 | ifr->ifr_flags = (short) dev_get_flags(dev); |
149 | return 0; |
150 | |
151 | case SIOCGIFMETRIC: /* Get the metric on the interface |
152 | (currently unused) */ |
153 | ifr->ifr_metric = 0; |
154 | return 0; |
155 | |
156 | case SIOCGIFMTU: /* Get the MTU of a device */ |
157 | ifr->ifr_mtu = dev->mtu; |
158 | return 0; |
159 | |
160 | case SIOCGIFSLAVE: |
161 | err = -EINVAL; |
162 | break; |
163 | |
164 | case SIOCGIFMAP: |
165 | return dev_getifmap(dev, ifr); |
166 | |
167 | case SIOCGIFINDEX: |
168 | ifr->ifr_ifindex = dev->ifindex; |
169 | return 0; |
170 | |
171 | case SIOCGIFTXQLEN: |
172 | ifr->ifr_qlen = dev->tx_queue_len; |
173 | return 0; |
174 | |
175 | default: |
176 | /* dev_ioctl() should ensure this case |
177 | * is never reached |
178 | */ |
179 | WARN_ON(1); |
180 | err = -ENOTTY; |
181 | break; |
182 | |
183 | } |
184 | return err; |
185 | } |
186 | |
187 | static int net_hwtstamp_validate(const struct kernel_hwtstamp_config *cfg) |
188 | { |
189 | enum hwtstamp_tx_types tx_type; |
190 | enum hwtstamp_rx_filters rx_filter; |
191 | int tx_type_valid = 0; |
192 | int rx_filter_valid = 0; |
193 | |
194 | if (cfg->flags & ~HWTSTAMP_FLAG_MASK) |
195 | return -EINVAL; |
196 | |
197 | tx_type = cfg->tx_type; |
198 | rx_filter = cfg->rx_filter; |
199 | |
200 | switch (tx_type) { |
201 | case HWTSTAMP_TX_OFF: |
202 | case HWTSTAMP_TX_ON: |
203 | case HWTSTAMP_TX_ONESTEP_SYNC: |
204 | case HWTSTAMP_TX_ONESTEP_P2P: |
205 | tx_type_valid = 1; |
206 | break; |
207 | case __HWTSTAMP_TX_CNT: |
208 | /* not a real value */ |
209 | break; |
210 | } |
211 | |
212 | switch (rx_filter) { |
213 | case HWTSTAMP_FILTER_NONE: |
214 | case HWTSTAMP_FILTER_ALL: |
215 | case HWTSTAMP_FILTER_SOME: |
216 | case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: |
217 | case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: |
218 | case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: |
219 | case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: |
220 | case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: |
221 | case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: |
222 | case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: |
223 | case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: |
224 | case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: |
225 | case HWTSTAMP_FILTER_PTP_V2_EVENT: |
226 | case HWTSTAMP_FILTER_PTP_V2_SYNC: |
227 | case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: |
228 | case HWTSTAMP_FILTER_NTP_ALL: |
229 | rx_filter_valid = 1; |
230 | break; |
231 | case __HWTSTAMP_FILTER_CNT: |
232 | /* not a real value */ |
233 | break; |
234 | } |
235 | |
236 | if (!tx_type_valid || !rx_filter_valid) |
237 | return -ERANGE; |
238 | |
239 | return 0; |
240 | } |
241 | |
242 | static int dev_eth_ioctl(struct net_device *dev, |
243 | struct ifreq *ifr, unsigned int cmd) |
244 | { |
245 | const struct net_device_ops *ops = dev->netdev_ops; |
246 | |
247 | if (!ops->ndo_eth_ioctl) |
248 | return -EOPNOTSUPP; |
249 | |
250 | if (!netif_device_present(dev)) |
251 | return -ENODEV; |
252 | |
253 | return ops->ndo_eth_ioctl(dev, ifr, cmd); |
254 | } |
255 | |
256 | /** |
257 | * dev_get_hwtstamp_phylib() - Get hardware timestamping settings of NIC |
258 | * or of attached phylib PHY |
259 | * @dev: Network device |
260 | * @cfg: Timestamping configuration structure |
261 | * |
262 | * Helper for enforcing a common policy that phylib timestamping, if available, |
263 | * should take precedence in front of hardware timestamping provided by the |
264 | * netdev. |
265 | * |
266 | * Note: phy_mii_ioctl() only handles SIOCSHWTSTAMP (not SIOCGHWTSTAMP), and |
267 | * there only exists a phydev->mii_ts->hwtstamp() method. So this will return |
268 | * -EOPNOTSUPP for phylib for now, which is still more accurate than letting |
269 | * the netdev handle the GET request. |
270 | */ |
271 | static int dev_get_hwtstamp_phylib(struct net_device *dev, |
272 | struct kernel_hwtstamp_config *cfg) |
273 | { |
274 | if (phy_has_hwtstamp(phydev: dev->phydev)) |
275 | return phy_hwtstamp_get(phydev: dev->phydev, config: cfg); |
276 | |
277 | return dev->netdev_ops->ndo_hwtstamp_get(dev, cfg); |
278 | } |
279 | |
280 | static int dev_get_hwtstamp(struct net_device *dev, struct ifreq *ifr) |
281 | { |
282 | const struct net_device_ops *ops = dev->netdev_ops; |
283 | struct kernel_hwtstamp_config kernel_cfg = {}; |
284 | struct hwtstamp_config cfg; |
285 | int err; |
286 | |
287 | if (!ops->ndo_hwtstamp_get) |
288 | return dev_eth_ioctl(dev, ifr, SIOCGHWTSTAMP); /* legacy */ |
289 | |
290 | if (!netif_device_present(dev)) |
291 | return -ENODEV; |
292 | |
293 | kernel_cfg.ifr = ifr; |
294 | err = dev_get_hwtstamp_phylib(dev, cfg: &kernel_cfg); |
295 | if (err) |
296 | return err; |
297 | |
298 | /* If the request was resolved through an unconverted driver, omit |
299 | * the copy_to_user(), since the implementation has already done that |
300 | */ |
301 | if (!kernel_cfg.copied_to_user) { |
302 | hwtstamp_config_from_kernel(cfg: &cfg, kernel_cfg: &kernel_cfg); |
303 | |
304 | if (copy_to_user(to: ifr->ifr_data, from: &cfg, n: sizeof(cfg))) |
305 | return -EFAULT; |
306 | } |
307 | |
308 | return 0; |
309 | } |
310 | |
311 | /** |
312 | * dev_set_hwtstamp_phylib() - Change hardware timestamping of NIC |
313 | * or of attached phylib PHY |
314 | * @dev: Network device |
315 | * @cfg: Timestamping configuration structure |
316 | * @extack: Netlink extended ack message structure, for error reporting |
317 | * |
318 | * Helper for enforcing a common policy that phylib timestamping, if available, |
319 | * should take precedence in front of hardware timestamping provided by the |
320 | * netdev. If the netdev driver needs to perform specific actions even for PHY |
321 | * timestamping to work properly (a switch port must trap the timestamped |
322 | * frames and not forward them), it must set IFF_SEE_ALL_HWTSTAMP_REQUESTS in |
323 | * dev->priv_flags. |
324 | */ |
325 | int dev_set_hwtstamp_phylib(struct net_device *dev, |
326 | struct kernel_hwtstamp_config *cfg, |
327 | struct netlink_ext_ack *extack) |
328 | { |
329 | const struct net_device_ops *ops = dev->netdev_ops; |
330 | bool phy_ts = phy_has_hwtstamp(phydev: dev->phydev); |
331 | struct kernel_hwtstamp_config old_cfg = {}; |
332 | bool changed = false; |
333 | int err; |
334 | |
335 | cfg->source = phy_ts ? HWTSTAMP_SOURCE_PHYLIB : HWTSTAMP_SOURCE_NETDEV; |
336 | |
337 | if (phy_ts && (dev->priv_flags & IFF_SEE_ALL_HWTSTAMP_REQUESTS)) { |
338 | err = ops->ndo_hwtstamp_get(dev, &old_cfg); |
339 | if (err) |
340 | return err; |
341 | } |
342 | |
343 | if (!phy_ts || (dev->priv_flags & IFF_SEE_ALL_HWTSTAMP_REQUESTS)) { |
344 | err = ops->ndo_hwtstamp_set(dev, cfg, extack); |
345 | if (err) { |
346 | if (extack->_msg) |
347 | netdev_err(dev, format: "%s\n" , extack->_msg); |
348 | return err; |
349 | } |
350 | } |
351 | |
352 | if (phy_ts && (dev->priv_flags & IFF_SEE_ALL_HWTSTAMP_REQUESTS)) |
353 | changed = kernel_hwtstamp_config_changed(a: &old_cfg, b: cfg); |
354 | |
355 | if (phy_ts) { |
356 | err = phy_hwtstamp_set(phydev: dev->phydev, config: cfg, extack); |
357 | if (err) { |
358 | if (changed) |
359 | ops->ndo_hwtstamp_set(dev, &old_cfg, NULL); |
360 | return err; |
361 | } |
362 | } |
363 | |
364 | return 0; |
365 | } |
366 | EXPORT_SYMBOL_GPL(dev_set_hwtstamp_phylib); |
367 | |
368 | static int dev_set_hwtstamp(struct net_device *dev, struct ifreq *ifr) |
369 | { |
370 | const struct net_device_ops *ops = dev->netdev_ops; |
371 | struct kernel_hwtstamp_config kernel_cfg = {}; |
372 | struct netlink_ext_ack extack = {}; |
373 | struct hwtstamp_config cfg; |
374 | int err; |
375 | |
376 | if (copy_from_user(to: &cfg, from: ifr->ifr_data, n: sizeof(cfg))) |
377 | return -EFAULT; |
378 | |
379 | hwtstamp_config_to_kernel(kernel_cfg: &kernel_cfg, cfg: &cfg); |
380 | kernel_cfg.ifr = ifr; |
381 | |
382 | err = net_hwtstamp_validate(cfg: &kernel_cfg); |
383 | if (err) |
384 | return err; |
385 | |
386 | err = dsa_conduit_hwtstamp_validate(dev, config: &kernel_cfg, extack: &extack); |
387 | if (err) { |
388 | if (extack._msg) |
389 | netdev_err(dev, format: "%s\n" , extack._msg); |
390 | return err; |
391 | } |
392 | |
393 | if (!ops->ndo_hwtstamp_set) |
394 | return dev_eth_ioctl(dev, ifr, SIOCSHWTSTAMP); /* legacy */ |
395 | |
396 | if (!netif_device_present(dev)) |
397 | return -ENODEV; |
398 | |
399 | err = dev_set_hwtstamp_phylib(dev, &kernel_cfg, &extack); |
400 | if (err) |
401 | return err; |
402 | |
403 | /* The driver may have modified the configuration, so copy the |
404 | * updated version of it back to user space |
405 | */ |
406 | if (!kernel_cfg.copied_to_user) { |
407 | hwtstamp_config_from_kernel(cfg: &cfg, kernel_cfg: &kernel_cfg); |
408 | |
409 | if (copy_to_user(to: ifr->ifr_data, from: &cfg, n: sizeof(cfg))) |
410 | return -EFAULT; |
411 | } |
412 | |
413 | return 0; |
414 | } |
415 | |
416 | static int generic_hwtstamp_ioctl_lower(struct net_device *dev, int cmd, |
417 | struct kernel_hwtstamp_config *kernel_cfg) |
418 | { |
419 | struct ifreq ifrr; |
420 | int err; |
421 | |
422 | strscpy_pad(ifrr.ifr_name, dev->name, IFNAMSIZ); |
423 | ifrr.ifr_ifru = kernel_cfg->ifr->ifr_ifru; |
424 | |
425 | err = dev_eth_ioctl(dev, ifr: &ifrr, cmd); |
426 | if (err) |
427 | return err; |
428 | |
429 | kernel_cfg->ifr->ifr_ifru = ifrr.ifr_ifru; |
430 | kernel_cfg->copied_to_user = true; |
431 | |
432 | return 0; |
433 | } |
434 | |
435 | int generic_hwtstamp_get_lower(struct net_device *dev, |
436 | struct kernel_hwtstamp_config *kernel_cfg) |
437 | { |
438 | const struct net_device_ops *ops = dev->netdev_ops; |
439 | |
440 | if (!netif_device_present(dev)) |
441 | return -ENODEV; |
442 | |
443 | if (ops->ndo_hwtstamp_get) |
444 | return dev_get_hwtstamp_phylib(dev, cfg: kernel_cfg); |
445 | |
446 | /* Legacy path: unconverted lower driver */ |
447 | return generic_hwtstamp_ioctl_lower(dev, SIOCGHWTSTAMP, kernel_cfg); |
448 | } |
449 | EXPORT_SYMBOL(generic_hwtstamp_get_lower); |
450 | |
451 | int generic_hwtstamp_set_lower(struct net_device *dev, |
452 | struct kernel_hwtstamp_config *kernel_cfg, |
453 | struct netlink_ext_ack *extack) |
454 | { |
455 | const struct net_device_ops *ops = dev->netdev_ops; |
456 | |
457 | if (!netif_device_present(dev)) |
458 | return -ENODEV; |
459 | |
460 | if (ops->ndo_hwtstamp_set) |
461 | return dev_set_hwtstamp_phylib(dev, kernel_cfg, extack); |
462 | |
463 | /* Legacy path: unconverted lower driver */ |
464 | return generic_hwtstamp_ioctl_lower(dev, SIOCSHWTSTAMP, kernel_cfg); |
465 | } |
466 | EXPORT_SYMBOL(generic_hwtstamp_set_lower); |
467 | |
468 | static int dev_siocbond(struct net_device *dev, |
469 | struct ifreq *ifr, unsigned int cmd) |
470 | { |
471 | const struct net_device_ops *ops = dev->netdev_ops; |
472 | |
473 | if (ops->ndo_siocbond) { |
474 | if (netif_device_present(dev)) |
475 | return ops->ndo_siocbond(dev, ifr, cmd); |
476 | else |
477 | return -ENODEV; |
478 | } |
479 | |
480 | return -EOPNOTSUPP; |
481 | } |
482 | |
483 | static int dev_siocdevprivate(struct net_device *dev, struct ifreq *ifr, |
484 | void __user *data, unsigned int cmd) |
485 | { |
486 | const struct net_device_ops *ops = dev->netdev_ops; |
487 | |
488 | if (ops->ndo_siocdevprivate) { |
489 | if (netif_device_present(dev)) |
490 | return ops->ndo_siocdevprivate(dev, ifr, data, cmd); |
491 | else |
492 | return -ENODEV; |
493 | } |
494 | |
495 | return -EOPNOTSUPP; |
496 | } |
497 | |
498 | static int dev_siocwandev(struct net_device *dev, struct if_settings *ifs) |
499 | { |
500 | const struct net_device_ops *ops = dev->netdev_ops; |
501 | |
502 | if (ops->ndo_siocwandev) { |
503 | if (netif_device_present(dev)) |
504 | return ops->ndo_siocwandev(dev, ifs); |
505 | else |
506 | return -ENODEV; |
507 | } |
508 | |
509 | return -EOPNOTSUPP; |
510 | } |
511 | |
512 | /* |
513 | * Perform the SIOCxIFxxx calls, inside rtnl_lock() |
514 | */ |
515 | static int dev_ifsioc(struct net *net, struct ifreq *ifr, void __user *data, |
516 | unsigned int cmd) |
517 | { |
518 | int err; |
519 | struct net_device *dev = __dev_get_by_name(net, name: ifr->ifr_name); |
520 | const struct net_device_ops *ops; |
521 | netdevice_tracker dev_tracker; |
522 | |
523 | if (!dev) |
524 | return -ENODEV; |
525 | |
526 | ops = dev->netdev_ops; |
527 | |
528 | switch (cmd) { |
529 | case SIOCSIFFLAGS: /* Set interface flags */ |
530 | return dev_change_flags(dev, flags: ifr->ifr_flags, NULL); |
531 | |
532 | case SIOCSIFMETRIC: /* Set the metric on the interface |
533 | (currently unused) */ |
534 | return -EOPNOTSUPP; |
535 | |
536 | case SIOCSIFMTU: /* Set the MTU of a device */ |
537 | return dev_set_mtu(dev, ifr->ifr_mtu); |
538 | |
539 | case SIOCSIFHWADDR: |
540 | if (dev->addr_len > sizeof(struct sockaddr)) |
541 | return -EINVAL; |
542 | return dev_set_mac_address_user(dev, sa: &ifr->ifr_hwaddr, NULL); |
543 | |
544 | case SIOCSIFHWBROADCAST: |
545 | if (ifr->ifr_hwaddr.sa_family != dev->type) |
546 | return -EINVAL; |
547 | memcpy(dev->broadcast, ifr->ifr_hwaddr.sa_data, |
548 | min(sizeof(ifr->ifr_hwaddr.sa_data_min), |
549 | (size_t)dev->addr_len)); |
550 | call_netdevice_notifiers(val: NETDEV_CHANGEADDR, dev); |
551 | return 0; |
552 | |
553 | case SIOCSIFMAP: |
554 | return dev_setifmap(dev, ifr); |
555 | |
556 | case SIOCADDMULTI: |
557 | if (!ops->ndo_set_rx_mode || |
558 | ifr->ifr_hwaddr.sa_family != AF_UNSPEC) |
559 | return -EINVAL; |
560 | if (!netif_device_present(dev)) |
561 | return -ENODEV; |
562 | return dev_mc_add_global(dev, addr: ifr->ifr_hwaddr.sa_data); |
563 | |
564 | case SIOCDELMULTI: |
565 | if (!ops->ndo_set_rx_mode || |
566 | ifr->ifr_hwaddr.sa_family != AF_UNSPEC) |
567 | return -EINVAL; |
568 | if (!netif_device_present(dev)) |
569 | return -ENODEV; |
570 | return dev_mc_del_global(dev, addr: ifr->ifr_hwaddr.sa_data); |
571 | |
572 | case SIOCSIFTXQLEN: |
573 | if (ifr->ifr_qlen < 0) |
574 | return -EINVAL; |
575 | return dev_change_tx_queue_len(dev, new_len: ifr->ifr_qlen); |
576 | |
577 | case SIOCSIFNAME: |
578 | ifr->ifr_newname[IFNAMSIZ-1] = '\0'; |
579 | return dev_change_name(dev, newname: ifr->ifr_newname); |
580 | |
581 | case SIOCWANDEV: |
582 | return dev_siocwandev(dev, ifs: &ifr->ifr_settings); |
583 | |
584 | case SIOCBRADDIF: |
585 | case SIOCBRDELIF: |
586 | if (!netif_device_present(dev)) |
587 | return -ENODEV; |
588 | if (!netif_is_bridge_master(dev)) |
589 | return -EOPNOTSUPP; |
590 | netdev_hold(dev, tracker: &dev_tracker, GFP_KERNEL); |
591 | rtnl_unlock(); |
592 | err = br_ioctl_call(net, br: netdev_priv(dev), cmd, ifr, NULL); |
593 | netdev_put(dev, tracker: &dev_tracker); |
594 | rtnl_lock(); |
595 | return err; |
596 | |
597 | case SIOCDEVPRIVATE ... SIOCDEVPRIVATE + 15: |
598 | return dev_siocdevprivate(dev, ifr, data, cmd); |
599 | |
600 | case SIOCSHWTSTAMP: |
601 | return dev_set_hwtstamp(dev, ifr); |
602 | |
603 | case SIOCGHWTSTAMP: |
604 | return dev_get_hwtstamp(dev, ifr); |
605 | |
606 | case SIOCGMIIPHY: |
607 | case SIOCGMIIREG: |
608 | case SIOCSMIIREG: |
609 | return dev_eth_ioctl(dev, ifr, cmd); |
610 | |
611 | case SIOCBONDENSLAVE: |
612 | case SIOCBONDRELEASE: |
613 | case SIOCBONDSETHWADDR: |
614 | case SIOCBONDSLAVEINFOQUERY: |
615 | case SIOCBONDINFOQUERY: |
616 | case SIOCBONDCHANGEACTIVE: |
617 | return dev_siocbond(dev, ifr, cmd); |
618 | |
619 | /* Unknown ioctl */ |
620 | default: |
621 | err = -EINVAL; |
622 | } |
623 | return err; |
624 | } |
625 | |
626 | /** |
627 | * dev_load - load a network module |
628 | * @net: the applicable net namespace |
629 | * @name: name of interface |
630 | * |
631 | * If a network interface is not present and the process has suitable |
632 | * privileges this function loads the module. If module loading is not |
633 | * available in this kernel then it becomes a nop. |
634 | */ |
635 | |
636 | void dev_load(struct net *net, const char *name) |
637 | { |
638 | struct net_device *dev; |
639 | int no_module; |
640 | |
641 | rcu_read_lock(); |
642 | dev = dev_get_by_name_rcu(net, name); |
643 | rcu_read_unlock(); |
644 | |
645 | no_module = !dev; |
646 | if (no_module && capable(CAP_NET_ADMIN)) |
647 | no_module = request_module("netdev-%s" , name); |
648 | if (no_module && capable(CAP_SYS_MODULE)) |
649 | request_module("%s" , name); |
650 | } |
651 | EXPORT_SYMBOL(dev_load); |
652 | |
653 | /* |
654 | * This function handles all "interface"-type I/O control requests. The actual |
655 | * 'doing' part of this is dev_ifsioc above. |
656 | */ |
657 | |
658 | /** |
659 | * dev_ioctl - network device ioctl |
660 | * @net: the applicable net namespace |
661 | * @cmd: command to issue |
662 | * @ifr: pointer to a struct ifreq in user space |
663 | * @data: data exchanged with userspace |
664 | * @need_copyout: whether or not copy_to_user() should be called |
665 | * |
666 | * Issue ioctl functions to devices. This is normally called by the |
667 | * user space syscall interfaces but can sometimes be useful for |
668 | * other purposes. The return value is the return from the syscall if |
669 | * positive or a negative errno code on error. |
670 | */ |
671 | |
672 | int dev_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr, |
673 | void __user *data, bool *need_copyout) |
674 | { |
675 | int ret; |
676 | char *colon; |
677 | |
678 | if (need_copyout) |
679 | *need_copyout = true; |
680 | if (cmd == SIOCGIFNAME) |
681 | return dev_ifname(net, ifr); |
682 | |
683 | ifr->ifr_name[IFNAMSIZ-1] = 0; |
684 | |
685 | colon = strchr(ifr->ifr_name, ':'); |
686 | if (colon) |
687 | *colon = 0; |
688 | |
689 | /* |
690 | * See which interface the caller is talking about. |
691 | */ |
692 | |
693 | switch (cmd) { |
694 | case SIOCGIFHWADDR: |
695 | dev_load(net, ifr->ifr_name); |
696 | ret = dev_get_mac_address(sa: &ifr->ifr_hwaddr, net, dev_name: ifr->ifr_name); |
697 | if (colon) |
698 | *colon = ':'; |
699 | return ret; |
700 | /* |
701 | * These ioctl calls: |
702 | * - can be done by all. |
703 | * - atomic and do not require locking. |
704 | * - return a value |
705 | */ |
706 | case SIOCGIFFLAGS: |
707 | case SIOCGIFMETRIC: |
708 | case SIOCGIFMTU: |
709 | case SIOCGIFSLAVE: |
710 | case SIOCGIFMAP: |
711 | case SIOCGIFINDEX: |
712 | case SIOCGIFTXQLEN: |
713 | dev_load(net, ifr->ifr_name); |
714 | rcu_read_lock(); |
715 | ret = dev_ifsioc_locked(net, ifr, cmd); |
716 | rcu_read_unlock(); |
717 | if (colon) |
718 | *colon = ':'; |
719 | return ret; |
720 | |
721 | case SIOCETHTOOL: |
722 | dev_load(net, ifr->ifr_name); |
723 | ret = dev_ethtool(net, ifr, userdata: data); |
724 | if (colon) |
725 | *colon = ':'; |
726 | return ret; |
727 | |
728 | /* |
729 | * These ioctl calls: |
730 | * - require superuser power. |
731 | * - require strict serialization. |
732 | * - return a value |
733 | */ |
734 | case SIOCGMIIPHY: |
735 | case SIOCGMIIREG: |
736 | case SIOCSIFNAME: |
737 | dev_load(net, ifr->ifr_name); |
738 | if (!ns_capable(ns: net->user_ns, CAP_NET_ADMIN)) |
739 | return -EPERM; |
740 | rtnl_lock(); |
741 | ret = dev_ifsioc(net, ifr, data, cmd); |
742 | rtnl_unlock(); |
743 | if (colon) |
744 | *colon = ':'; |
745 | return ret; |
746 | |
747 | /* |
748 | * These ioctl calls: |
749 | * - require superuser power. |
750 | * - require strict serialization. |
751 | * - do not return a value |
752 | */ |
753 | case SIOCSIFMAP: |
754 | case SIOCSIFTXQLEN: |
755 | if (!capable(CAP_NET_ADMIN)) |
756 | return -EPERM; |
757 | fallthrough; |
758 | /* |
759 | * These ioctl calls: |
760 | * - require local superuser power. |
761 | * - require strict serialization. |
762 | * - do not return a value |
763 | */ |
764 | case SIOCSIFFLAGS: |
765 | case SIOCSIFMETRIC: |
766 | case SIOCSIFMTU: |
767 | case SIOCSIFHWADDR: |
768 | case SIOCSIFSLAVE: |
769 | case SIOCADDMULTI: |
770 | case SIOCDELMULTI: |
771 | case SIOCSIFHWBROADCAST: |
772 | case SIOCSMIIREG: |
773 | case SIOCBONDENSLAVE: |
774 | case SIOCBONDRELEASE: |
775 | case SIOCBONDSETHWADDR: |
776 | case SIOCBONDCHANGEACTIVE: |
777 | case SIOCBRADDIF: |
778 | case SIOCBRDELIF: |
779 | case SIOCSHWTSTAMP: |
780 | if (!ns_capable(ns: net->user_ns, CAP_NET_ADMIN)) |
781 | return -EPERM; |
782 | fallthrough; |
783 | case SIOCBONDSLAVEINFOQUERY: |
784 | case SIOCBONDINFOQUERY: |
785 | dev_load(net, ifr->ifr_name); |
786 | rtnl_lock(); |
787 | ret = dev_ifsioc(net, ifr, data, cmd); |
788 | rtnl_unlock(); |
789 | if (need_copyout) |
790 | *need_copyout = false; |
791 | return ret; |
792 | |
793 | case SIOCGIFMEM: |
794 | /* Get the per device memory space. We can add this but |
795 | * currently do not support it */ |
796 | case SIOCSIFMEM: |
797 | /* Set the per device memory buffer space. |
798 | * Not applicable in our case */ |
799 | case SIOCSIFLINK: |
800 | return -ENOTTY; |
801 | |
802 | /* |
803 | * Unknown or private ioctl. |
804 | */ |
805 | default: |
806 | if (cmd == SIOCWANDEV || |
807 | cmd == SIOCGHWTSTAMP || |
808 | (cmd >= SIOCDEVPRIVATE && |
809 | cmd <= SIOCDEVPRIVATE + 15)) { |
810 | dev_load(net, ifr->ifr_name); |
811 | rtnl_lock(); |
812 | ret = dev_ifsioc(net, ifr, data, cmd); |
813 | rtnl_unlock(); |
814 | return ret; |
815 | } |
816 | return -ENOTTY; |
817 | } |
818 | } |
819 | |