Home | History | Annotate | Line # | Download | only in common
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*/
     47 int
     48 compat_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