uipc_syscalls_40.c revision 1.1
1/*	$NetBSD: uipc_syscalls_40.c,v 1.1 2007/05/29 21:32:27 christos 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.1 2007/05/29 21:32:27 christos Exp $");
7
8/*
9 * System call interface to the socket abstraction.
10 */
11
12#include "opt_compat_netbsd.h"
13#include "opt_compat_linux.h"
14#include "opt_compat_svr4.h"
15#include "opt_compat_ultrix.h"
16#include "opt_compat_43.h"
17
18#include <sys/param.h>
19#include <sys/kernel.h>
20#include <sys/msg.h>
21#include <sys/sysctl.h>
22#include <sys/mount.h>
23#include <sys/syscallargs.h>
24#include <sys/errno.h>
25
26#include <net/if.h>
27
28#if defined(COMPAT_43) || defined(COMPAT_LINUX) || defined(COMPAT_SVR4) || \
29    defined(COMPAT_ULTRIX) || defined(LKM)
30#define COMPAT_OSOCK
31#include <compat/sys/socket.h>
32#endif
33
34#if defined(COMPAT_09) || defined(COMPAT_10) || defined(COMPAT_11) || \
35    defined(COMPAT_12) || defined(COMPAT_13) || defined(COMPAT_14) || \
36    defined(COMPAT_15) || defined(COMPAT_16) || defined(COMPAT_20) || \
37    defined(COMPAT_30) || defined(COMPAT_40)
38#include <compat/sys/sockio.h>
39#endif
40/*
41 * Return interface configuration
42 * of system.  List may be used
43 * in later ioctl's (above) to get
44 * other information.
45 */
46/*ARGSUSED*/
47int
48compat_ifconf(u_long cmd, void *data)
49{
50	struct oifconf *ifc = data;
51	struct ifnet *ifp;
52	struct ifaddr *ifa;
53	struct oifreq ifr, *ifrp;
54	int space = ifc->ifc_len, error = 0;
55	const int sz = (int)sizeof(ifr);
56	int sign;
57
58	if ((ifrp = ifc->ifc_req) == NULL) {
59		space = 0;
60		sign = -1;
61	} else {
62		sign = 1;
63	}
64	IFNET_FOREACH(ifp) {
65		(void)strncpy(ifr.ifr_name, ifp->if_xname,
66		    sizeof(ifr.ifr_name));
67		if (ifr.ifr_name[sizeof(ifr.ifr_name) - 1] != '\0')
68			return ENAMETOOLONG;
69		if (TAILQ_EMPTY(&ifp->if_addrlist)) {
70			memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
71			if (ifrp != NULL && space >= sz) {
72				error = copyout(&ifr, ifrp, sz);
73				if (error != 0)
74					break;
75				ifrp++;
76			}
77			space -= sizeof(ifr) * sign;
78			continue;
79		}
80
81		TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
82			struct sockaddr *sa = ifa->ifa_addr;
83#ifdef COMPAT_OSOCK
84			if (cmd == OOSIOCGIFCONF) {
85				struct osockaddr *osa =
86					 (struct osockaddr *)&ifr.ifr_addr;
87				/*
88				 * If it does not fit, we don't bother with it
89				 */
90				if (sa->sa_len > sizeof(*osa))
91					continue;
92				memcpy(&ifr.ifr_addr, sa, sa->sa_len);
93				osa->sa_family = sa->sa_family;
94				if (ifrp != NULL && space >= sz) {
95					error = copyout(&ifr, ifrp, sz);
96					ifrp++;
97				}
98			} else
99#endif
100			if (sa->sa_len <= sizeof(*sa)) {
101				memcpy(&ifr.ifr_addr, sa, sa->sa_len);
102				if (ifrp != NULL && space >= sz) {
103					error = copyout(&ifr, ifrp, sz);
104					ifrp++;
105				}
106			} else {
107				space -= (sa->sa_len - sizeof(*sa)) * sign;
108				if (ifrp != NULL && space >= sz) {
109					error = copyout(&ifr, ifrp,
110					    sizeof(ifr.ifr_name));
111					if (error == 0) {
112						error = copyout(sa,
113						    &ifrp->ifr_addr,
114						    sa->sa_len);
115					}
116					ifrp = (struct oifreq *)
117						(sa->sa_len +
118						 (char *)&ifrp->ifr_addr);
119				}
120			}
121			if (error != 0)
122				break;
123			space -= sz * sign;
124		}
125	}
126	if (ifrp != NULL)
127		ifc->ifc_len -= space;
128	else
129		ifc->ifc_len = space;
130	return error;
131}
132