1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Based on net/ipv4/devinet.c
4 * Authors: Ross Biro
5 * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
6 * Mark Evans, <evansmp@uhura.aston.ac.uk>
7 *
8 * Additional Authors:
9 * Alan Cox, <gw4pts@gw4pts.ampr.org>
10 * Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
11 *
12 * Changes:
13 * Alexey Kuznetsov: pa_* fields are replaced with ifaddr
14 * lists.
15 * Cyrus Durgin: updated for kmod
16 * Matthias Andree: in devinet_ioctl, compare label and
17 * address (4.4BSD alias style support),
18 * fall back to comparing just the label
19 * if no match found.
20 *
21 * Based on net/core/dev_ioctl.c
22 * No Authors, no Copyright
23 *
24 * NewIP INET
25 * An implementation of the TCP/IP protocol suite for the LINUX
26 * operating system. NewIP INET is implemented using the BSD Socket
27 * interface as the means of communication with the user level.
28 *
29 * DEVICE - NEWIP device support.
30 */
31 #define pr_fmt(fmt) KBUILD_MODNAME ": [%s:%d] " fmt, __func__, __LINE__
32
33 #include <linux/netdevice.h>
34
35 #include <net/nip_fib.h>
36 #include <net/nip_addrconf.h>
37 #include "tcp_nip_parameter.h"
38
nip_dev_ifconf(struct net * net,struct ifconf * ifc,int size)39 int nip_dev_ifconf(struct net *net, struct ifconf *ifc, int size)
40 {
41 struct net_device *dev;
42 char __user *pos;
43 int len;
44 int total;
45
46 pos = ifc->ifc_buf;
47 len = ifc->ifc_len;
48
49 total = 0;
50 for_each_netdev(net, dev) {
51 int done;
52
53 if (!pos)
54 done = ninet_gifconf(dev, NULL, 0, size);
55 else
56 done = ninet_gifconf(dev, pos + total,
57 len - total, size);
58 if (done < 0)
59 return -EFAULT;
60 total += done;
61 }
62
63 ifc->ifc_len = total;
64
65 return 0;
66 }
67
ninet_gifconf(struct net_device * dev,char __user * buf,int len,int size)68 int ninet_gifconf(struct net_device *dev, char __user *buf, int len, int size)
69 {
70 struct ninet_dev *nin_dev = __nin_dev_get(dev);
71 const struct ninet_ifaddr *ifa;
72 struct ifreq ifr;
73 int done = 0;
74
75 if (WARN_ON(size > sizeof(struct ifreq)))
76 goto out;
77 if (!nin_dev)
78 goto out;
79
80 list_for_each_entry(ifa, &nin_dev->addr_list, if_list) {
81 ifa = rcu_dereference_protected(ifa, lockdep_is_held(&ifa->lock));
82 if (!ifa) {
83 done = -EFAULT;
84 break;
85 }
86 if (!buf) {
87 done += size;
88 continue;
89 }
90 if (len < size)
91 break;
92 memset(&ifr, 0, sizeof(struct ifreq));
93 strcpy(ifr.ifr_name, ifa->rt->dst.dev->name);
94
95 (*(struct sockaddr_nin *)&ifr.ifr_addr).sin_family = AF_NINET;
96 memcpy(&((struct sockaddr_nin *)&ifr.ifr_addr)->sin_addr, &ifa->addr,
97 sizeof(struct nip_addr));
98
99 if (copy_to_user(buf + done, &ifr, size)) {
100 done = -EFAULT;
101 break;
102 }
103 len -= size;
104 done += size;
105 }
106 out:
107 return done;
108 }
109
110