uipc_syscalls_40.c revision 1.8
1/*	$NetBSD: uipc_syscalls_40.c,v 1.8 2014/11/26 09:53:53 ozaki-r Exp $	*/
2
3/* written by Pavel Cahyna, 2006. Public domain. */
4
5#include <sys/cdefs.h>
6__KERNEL_RCSID(0, "$NetBSD: uipc_syscalls_40.c,v 1.8 2014/11/26 09:53:53 ozaki-r Exp $");
7
8/*
9 * System call interface to the socket abstraction.
10 */
11
12#include <sys/param.h>
13#include <sys/kernel.h>
14#include <sys/msg.h>
15#include <sys/sysctl.h>
16#include <sys/syscallargs.h>
17#include <sys/errno.h>
18
19#include <net/if.h>
20
21#include <compat/sys/socket.h>
22#include <compat/sys/sockio.h>
23
24#ifdef COMPAT_OIFREQ
25/*
26 * Return interface configuration
27 * of system.  List may be used
28 * in later ioctl's (above) to get
29 * other information.
30 */
31/*ARGSUSED*/
32int
33compat_ifconf(u_long cmd, void *data)
34{
35	struct oifconf *ifc = data;
36	struct ifnet *ifp;
37	struct ifaddr *ifa;
38	struct oifreq ifr, *ifrp = NULL;
39	int space = 0, error = 0;
40	const int sz = (int)sizeof(ifr);
41	const bool docopy = ifc->ifc_req != NULL;
42
43	if (docopy) {
44		space = ifc->ifc_len;
45		ifrp = ifc->ifc_req;
46	}
47
48	IFNET_FOREACH(ifp) {
49		(void)strncpy(ifr.ifr_name, ifp->if_xname,
50		    sizeof(ifr.ifr_name));
51		if (ifr.ifr_name[sizeof(ifr.ifr_name) - 1] != '\0')
52			return ENAMETOOLONG;
53		if (IFADDR_EMPTY(ifp)) {
54			memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
55			if (space >= sz) {
56				error = copyout(&ifr, ifrp, sz);
57				if (error != 0)
58					return (error);
59				ifrp++;
60			}
61			space -= sizeof(ifr);
62			continue;
63		}
64
65		IFADDR_FOREACH(ifa, ifp) {
66			struct sockaddr *sa = ifa->ifa_addr;
67#ifdef COMPAT_OSOCK
68			if (cmd == OOSIOCGIFCONF) {
69				struct osockaddr *osa =
70				    (struct osockaddr *)&ifr.ifr_addr;
71				/*
72				 * If it does not fit, we don't bother with it
73				 */
74				if (sa->sa_len > sizeof(*osa))
75					continue;
76				memcpy(&ifr.ifr_addr, sa, sa->sa_len);
77				osa->sa_family = sa->sa_family;
78				if (space >= sz) {
79					error = copyout(&ifr, ifrp, sz);
80					ifrp++;
81				}
82			} else
83#endif
84			if (sa->sa_len <= sizeof(*sa)) {
85				memcpy(&ifr.ifr_addr, sa, sa->sa_len);
86				if (space >= sz) {
87					error = copyout(&ifr, ifrp, sz);
88					ifrp++;
89				}
90			} else {
91				space -= sa->sa_len - sizeof(*sa);
92				if (space >= sz) {
93					error = copyout(&ifr, ifrp,
94					    sizeof(ifr.ifr_name));
95					if (error == 0) {
96						error = copyout(sa,
97						    &ifrp->ifr_addr,
98						    sa->sa_len);
99					}
100					ifrp = (struct oifreq *)
101						(sa->sa_len +
102						 (char *)&ifrp->ifr_addr);
103				}
104			}
105			if (error != 0)
106				return (error);
107			space -= sz;
108		}
109	}
110	if (docopy)
111		ifc->ifc_len -= space;
112	else
113		ifc->ifc_len = -space;
114	return (0);
115}
116#endif
117