• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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