summaryrefslogtreecommitdiff
path: root/usr/src/lib/libsocket
diff options
context:
space:
mode:
authorstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
committerstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
commit7c478bd95313f5f23a4c958a745db2134aa03244 (patch)
treec871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/lib/libsocket
downloadillumos-joyent-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz
OpenSolaris Launch
Diffstat (limited to 'usr/src/lib/libsocket')
-rw-r--r--usr/src/lib/libsocket/Makefile60
-rw-r--r--usr/src/lib/libsocket/Makefile.com74
-rw-r--r--usr/src/lib/libsocket/amd64/Makefile44
-rw-r--r--usr/src/lib/libsocket/amd64/byteorder.s60
-rw-r--r--usr/src/lib/libsocket/common/llib-lsocket126
-rw-r--r--usr/src/lib/libsocket/i386/Makefile43
-rw-r--r--usr/src/lib/libsocket/i386/byteorder.s60
-rw-r--r--usr/src/lib/libsocket/inet/bindresvport.c127
-rw-r--r--usr/src/lib/libsocket/inet/bootparams_getbyname.c107
-rw-r--r--usr/src/lib/libsocket/inet/byteorder.c61
-rw-r--r--usr/src/lib/libsocket/inet/ether_addr.c311
-rw-r--r--usr/src/lib/libsocket/inet/getaddrinfo.c806
-rw-r--r--usr/src/lib/libsocket/inet/getnameinfo.c378
-rw-r--r--usr/src/lib/libsocket/inet/getnetent.c86
-rw-r--r--usr/src/lib/libsocket/inet/getnetent_r.c215
-rw-r--r--usr/src/lib/libsocket/inet/getprotoent.c86
-rw-r--r--usr/src/lib/libsocket/inet/getprotoent_r.c209
-rw-r--r--usr/src/lib/libsocket/inet/getservbyname_r.c124
-rw-r--r--usr/src/lib/libsocket/inet/getservent.c86
-rw-r--r--usr/src/lib/libsocket/inet/getservent_r.c100
-rw-r--r--usr/src/lib/libsocket/inet/inet6_opt.c300
-rw-r--r--usr/src/lib/libsocket/inet/inet6_rthdr.c180
-rw-r--r--usr/src/lib/libsocket/inet/inet_lnaof.c61
-rw-r--r--usr/src/lib/libsocket/inet/inet_mkaddr.c66
-rw-r--r--usr/src/lib/libsocket/inet/inet_network.c99
-rw-r--r--usr/src/lib/libsocket/inet/interface_id.c355
-rw-r--r--usr/src/lib/libsocket/inet/link_addr.c135
-rw-r--r--usr/src/lib/libsocket/inet/netmasks.c277
-rw-r--r--usr/src/lib/libsocket/inet/rcmd.c820
-rw-r--r--usr/src/lib/libsocket/inet/rexec.c189
-rw-r--r--usr/src/lib/libsocket/inet/ruserpass.c270
-rw-r--r--usr/src/lib/libsocket/inet/sourcefilter.c229
-rw-r--r--usr/src/lib/libsocket/socket/_soutil.c254
-rw-r--r--usr/src/lib/libsocket/socket/sockatmark.c46
-rw-r--r--usr/src/lib/libsocket/socket/socket.c156
-rw-r--r--usr/src/lib/libsocket/socket/socketpair.c130
-rw-r--r--usr/src/lib/libsocket/socket/weaks.c264
-rw-r--r--usr/src/lib/libsocket/sparc/Makefile33
-rw-r--r--usr/src/lib/libsocket/sparcv9/Makefile34
-rw-r--r--usr/src/lib/libsocket/spec/Makefile29
-rw-r--r--usr/src/lib/libsocket/spec/Makefile.targ36
-rw-r--r--usr/src/lib/libsocket/spec/amd64/Makefile44
-rw-r--r--usr/src/lib/libsocket/spec/i386/Makefile44
-rw-r--r--usr/src/lib/libsocket/spec/socket.spec895
-rw-r--r--usr/src/lib/libsocket/spec/sparc/Makefile44
-rw-r--r--usr/src/lib/libsocket/spec/sparcv9/Makefile45
-rw-r--r--usr/src/lib/libsocket/spec/svr4msg.spec131
-rw-r--r--usr/src/lib/libsocket/spec/versions84
-rw-r--r--usr/src/lib/libsocket/spec/xpgmsg.spec48
49 files changed, 8461 insertions, 0 deletions
diff --git a/usr/src/lib/libsocket/Makefile b/usr/src/lib/libsocket/Makefile
new file mode 100644
index 0000000000..6252e47d92
--- /dev/null
+++ b/usr/src/lib/libsocket/Makefile
@@ -0,0 +1,60 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright (c) 1993-2001 by Sun Microsystems, Inc.
+# All rights reserved.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.lib
+
+SUBDIRS = $(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+
+all := TARGET= all
+clean := TARGET= clean
+clobber := TARGET= clobber
+install := TARGET= install
+lint := TARGET= lint
+
+POFILE = libsocket.po
+MSGFILES = `$(GREP) -l gettext */*.[ch]`
+XGETFLAGS += -a
+TEXT_DOMAIN = SUNW_OST_NETRPC
+
+.KEEP_STATE:
+
+all clean clobber install: spec .WAIT $(SUBDIRS)
+
+lint: $(SUBDIRS)
+
+_msg: $(MSGDOMAINPOFILE)
+
+$(POFILE): pofile_MSGFILES
+
+$(SUBDIRS) spec: FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include $(SRC)/Makefile.msg.targ
diff --git a/usr/src/lib/libsocket/Makefile.com b/usr/src/lib/libsocket/Makefile.com
new file mode 100644
index 0000000000..4664a4e7bb
--- /dev/null
+++ b/usr/src/lib/libsocket/Makefile.com
@@ -0,0 +1,74 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+LIBRARY = libsocket.a
+VERS = .1
+
+INETOBJS = bindresvport.o bootparams_getbyname.o byteorder.o ether_addr.o \
+ getaddrinfo.o getnameinfo.o getnetent.o getnetent_r.o \
+ getprotoent.o getprotoent_r.o getservbyname_r.o getservent.o \
+ getservent_r.o inet_lnaof.o inet_mkaddr.o inet_network.o \
+ inet6_opt.o inet6_rthdr.o interface_id.o link_addr.o \
+ netmasks.o rcmd.o rexec.o ruserpass.o sourcefilter.o
+SOCKOBJS = _soutil.o sockatmark.o socket.o socketpair.o weaks.o
+OBJECTS = $(INETOBJS) $(SOCKOBJS)
+
+include ../../Makefile.lib
+
+# install this library in the root filesystem
+include ../../Makefile.rootfs
+
+LIBS = $(DYNLIB) $(LINTLIB)
+
+SRCS = $(INETOBJS:%.o=../inet/%.c) $(SOCKOBJS:%.o=../socket/%.c)
+$(LINTLIB):= SRCS = $(SRCDIR)/$(LINTSRC)
+LDLIBS += -lnsl -lc
+
+SRCDIR = ../common
+MAPDIR = ../spec/$(TRANSMACH)
+SPECMAPFILE = $(MAPDIR)/mapfile
+
+CPPFLAGS += -DSYSV -D_REENTRANT -I../../common/inc
+%/rcmd.o := CPPFLAGS += -DNIS
+
+.KEEP_STATE:
+
+all:
+
+lint: lintcheck
+
+# libsocket build rules
+pics/%.o: ../inet/%.c
+ $(COMPILE.c) -o $@ $<
+ $(POST_PROCESS_O)
+
+pics/%.o: ../socket/%.c
+ $(COMPILE.c) -o $@ $<
+ $(POST_PROCESS_O)
+
+include ../../Makefile.targ
diff --git a/usr/src/lib/libsocket/amd64/Makefile b/usr/src/lib/libsocket/amd64/Makefile
new file mode 100644
index 0000000000..de119509d4
--- /dev/null
+++ b/usr/src/lib/libsocket/amd64/Makefile
@@ -0,0 +1,44 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+# the following entry needs to be defined before the inclusion
+# of ../Makefile.com, otherwise inet/byteorder.c will be used
+# instead of amd64/byteorder.s
+
+objs/%.o pics/%.o: %.s
+ $(COMPILE.s) -o $@ $<
+ $(POST_PROCESS_O)
+
+ASFLAGS += -P -D__STDC__ -D_ASM
+
+include ../Makefile.com
+include ../../Makefile.lib.64
+
+all: $(LIBS)
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64)
diff --git a/usr/src/lib/libsocket/amd64/byteorder.s b/usr/src/lib/libsocket/amd64/byteorder.s
new file mode 100644
index 0000000000..04d10df546
--- /dev/null
+++ b/usr/src/lib/libsocket/amd64/byteorder.s
@@ -0,0 +1,60 @@
+/
+/ Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+/ Use is subject to license terms.
+/
+/ CDDL HEADER START
+/
+/ The contents of this file are subject to the terms of the
+/ Common Development and Distribution License, Version 1.0 only
+/ (the "License"). You may not use this file except in compliance
+/ with the License.
+/
+/ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+/ or http://www.opensolaris.org/os/licensing.
+/ See the License for the specific language governing permissions
+/ and limitations under the License.
+/
+/ When distributing Covered Code, include this CDDL HEADER in each
+/ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+/ If applicable, add the following below this CDDL HEADER, with the
+/ fields enclosed by brackets "[]" replaced with your own identifying
+/ information: Portions Copyright [yyyy] [name of copyright owner]
+/
+/ CDDL HEADER END
+/
+ .ident "%Z%%M% %I% %E% SMI"
+
+ .file "byteorder.s"
+
+#include <sys/asm_linkage.h>
+
+/
+/ uint32_t htonl(uint32_t hl);
+/ uint32_t ntohl(uint32_t nl);
+/
+/ reverses the byte order of the argument.
+/
+
+ ENTRY(htonl)
+ ENTRY(ntohl)
+ movl %edi, %eax
+ bswap %eax
+ ret
+ SET_SIZE(htonl)
+ SET_SIZE(ntohl)
+
+/
+/ uint16_t htons(uint16_t hs);
+/ uint16_t ntohs(uint16_t ns);
+/
+/ reverses the byte order of the argument.
+/
+
+ ENTRY(htons)
+ ENTRY(ntohs)
+ movl %edi, %eax
+ bswap %eax
+ shr $16, %eax
+ ret
+ SET_SIZE(htons)
+ SET_SIZE(ntohs)
diff --git a/usr/src/lib/libsocket/common/llib-lsocket b/usr/src/lib/libsocket/common/llib-lsocket
new file mode 100644
index 0000000000..f74c8cea92
--- /dev/null
+++ b/usr/src/lib/libsocket/common/llib-lsocket
@@ -0,0 +1,126 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/* LINTLIBRARY */
+/* PROTOLIB1 */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <sys/uio.h>
+#include <sys/isa_defs.h>
+#include <arpa/inet.h>
+#include <sys/ethernet.h>
+#include <netdb.h>
+#include <net/if_dl.h>
+
+/*
+ * usr/src/lib/libsocket/inet routines not prototyped in the above
+ * header files.
+ */
+
+/* bindresvport.c */
+int bindresvport(int sd, struct sockaddr_in *sin);
+
+/* bootparams_getbyname.c */
+int bootparams_getbyname(char *name, char *linebuf, int linelen);
+
+/* inet6_rthdr.c */
+int __inet6_rthdr_add(void *, const struct in6_addr *);
+struct in6_addr *__inet6_rthdr_getaddr(void *, int);
+
+/* netmasks.c */
+int getnetmaskbynet(const struct in_addr net, struct in_addr *mask);
+int getnetmaskbyaddr(const struct in_addr addr, struct in_addr *mask);
+
+/* ruserpass.c */
+void _ruserpass(const char *host, char **aname, char **apass);
+
+/*
+ * usr/src/lib/libsocket/socket routines
+ */
+
+/* _soutil.c */
+
+/* socket.c */
+int socket(int domain, int type, int protocol);
+int _socket(int domain, int type, int protocol);
+int _socket_bsd(int family, int type, int protocol);
+int __xnet_socket(int family, int type, int protocol);
+
+/* socketpair.c */
+int socketpair(int domain, int type, int protocol, int sv[]);
+int _socketpair(int domain, int type, int protocol, int *sv);
+int _socketpair_bsd(int domain, int type, int protocol, int *sv);
+int __xnet_socketpair(int domain, int type, int protocol, int *sv);
+
+/* weaks.c */
+int bind(int s, const struct sockaddr *name, socklen_t namelen);
+int listen(int s, int backlog);
+int accept(int s, struct sockaddr *addr, Psocklen_t addrlen);
+int connect(int s, const struct sockaddr *name, socklen_t namelen);
+int shutdown(int s, int how);
+ssize_t recv(int s, void *buf, size_t len, int flags);
+ssize_t recvfrom(int s, void *buf, size_t len, int flags,
+ struct sockaddr *from, Psocklen_t fromlen);
+ssize_t recvmsg(int s, struct msghdr *msg, int flags);
+ssize_t send(int s, const void *msg, size_t len, int flags);
+ssize_t sendmsg(int s, const struct msghdr *msg, int flags);
+ssize_t sendto(int s, const void *msg, size_t len, int flags,
+ const struct sockaddr *to, socklen_t tolen);
+int getpeername(int s, struct sockaddr *name, Psocklen_t namelen);
+int getsockname(int s, struct sockaddr *name, Psocklen_t namelen);
+int getsockopt(int s, int level, int optname, void *optval, Psocklen_t optlen);
+int setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen);
+
+int _bind(int s, const struct sockaddr *name, int namelen);
+int _listen(int s, int backlog);
+int _accept(int s, struct sockaddr *addr, int *addrlen);
+int _connect(int s, struct sockaddr *name, int namelen);
+int _shutdown(int s, int how);
+int _recv(int s, char *buf, int len, int flags);
+int _recvfrom(int s, char *buf, int len, int flags,
+ struct sockaddr *from, int *fromlen);
+int _recvmsg(int s, struct msghdr *msg, int flags);
+int _send(int s, const char *msg, int len, int flags);
+int _sendmsg(int s, const struct msghdr *msg, int flags);
+int _sendto(int s, const char *msg, int len, int flags,
+ const struct sockaddr *to, int tolen);
+int _getpeername(int s, struct sockaddr *name, int *namelen);
+int _getsockname(int s, struct sockaddr *name, int *namelen);
+int _getsockopt(int s, int level, int optname, char *optval, int *optlen);
+int _setsockopt(int s, int level, int optname, const char *optval, int optlen);
+int __xnet_bind(int sock, const struct sockaddr *addr, socklen_t addrlen);
+int __xnet_listen(int sock, int backlog);
+int __xnet_connect(int sock, const struct sockaddr *addr, socklen_t addrlen);
+int __xnet_recvmsg(int sock, struct msghdr *msg, int flags);
+int __xnet_sendmsg(int sock, const struct msghdr *msg, int flags);
+int __xnet_sendto(int sock, const void *buf, size_t len, int flags,
+ const struct sockaddr *addr, socklen_t addrlen);
+int __xnet_getsockopt(int sock, int level, int option_name,
+ void *option_value, socklen_t *option_lenp);
diff --git a/usr/src/lib/libsocket/i386/Makefile b/usr/src/lib/libsocket/i386/Makefile
new file mode 100644
index 0000000000..ea3915839c
--- /dev/null
+++ b/usr/src/lib/libsocket/i386/Makefile
@@ -0,0 +1,43 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+# the following entry needs to be defined before the inclusion
+# of ../Makefile.com, otherwise inet/byteorder.c will be used
+# instead of i386/byteorder.s
+
+objs/%.o pics/%.o: %.s
+ $(COMPILE.s) -o $@ $<
+ $(POST_PROCESS_O)
+
+ASFLAGS += -P -D__STDC__ -D_ASM
+
+include ../Makefile.com
+
+all: $(LIBS)
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/libsocket/i386/byteorder.s b/usr/src/lib/libsocket/i386/byteorder.s
new file mode 100644
index 0000000000..3b58df4707
--- /dev/null
+++ b/usr/src/lib/libsocket/i386/byteorder.s
@@ -0,0 +1,60 @@
+/
+/ Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+/ Use is subject to license terms.
+/
+/ CDDL HEADER START
+/
+/ The contents of this file are subject to the terms of the
+/ Common Development and Distribution License, Version 1.0 only
+/ (the "License"). You may not use this file except in compliance
+/ with the License.
+/
+/ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+/ or http://www.opensolaris.org/os/licensing.
+/ See the License for the specific language governing permissions
+/ and limitations under the License.
+/
+/ When distributing Covered Code, include this CDDL HEADER in each
+/ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+/ If applicable, add the following below this CDDL HEADER, with the
+/ fields enclosed by brackets "[]" replaced with your own identifying
+/ information: Portions Copyright [yyyy] [name of copyright owner]
+/
+/ CDDL HEADER END
+/
+ .ident "%Z%%M% %I% %E% SMI"
+
+ .file "byteorder.s"
+
+#include <sys/asm_linkage.h>
+
+/
+/ uint32_t htonl(uint32_t hl);
+/ uint32_t ntohl(uint32_t nl);
+/
+/ reverses the byte order of the argument.
+/
+
+ ENTRY(htonl)
+ ENTRY(ntohl)
+ movl 4(%esp), %eax / %eax = hl
+ bswap %eax / reverses the byte order of %eax
+ ret / return (%eax)
+ SET_SIZE(htonl)
+ SET_SIZE(ntohl)
+
+/
+/ uint16_t htons(uint16_t hs);
+/ uint16_t ntohs(uint16_t ns);
+/
+/ reverses the byte order of the argument.
+/
+
+ ENTRY(htons)
+ ENTRY(ntohs)
+ movl 4(%esp), %eax / %eax = hs
+ bswap %eax / reverses the byte order of %eax
+ shrl $16, %eax / moves high 16-bit to low 16-bit
+ ret / return (%eax)
+ SET_SIZE(htons)
+ SET_SIZE(ntohs)
diff --git a/usr/src/lib/libsocket/inet/bindresvport.c b/usr/src/lib/libsocket/inet/bindresvport.c
new file mode 100644
index 0000000000..d3cc2f5b8a
--- /dev/null
+++ b/usr/src/lib/libsocket/inet/bindresvport.c
@@ -0,0 +1,127 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Portions of this source code were derived from Berkeley 4.3 BSD
+ * under license from the Regents of the University of California.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netinet/udp.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef SYSV
+#define bzero(s, len) (void) memset((s), 0, (len))
+#endif
+
+
+/*
+ * Bind a socket to a privileged IP port
+ */
+int
+bindresvport(int sd, struct sockaddr_in *sin)
+{
+ struct sockaddr_in myaddr;
+ struct sockaddr_in *bindaddr;
+ int level, optname;
+ int optval, len;
+ int ret;
+
+ bindaddr = sin;
+ if (bindaddr == (struct sockaddr_in *)0) {
+ bindaddr = &myaddr;
+ bzero(bindaddr, sizeof (*bindaddr));
+ bindaddr->sin_family = AF_INET;
+ } else if (bindaddr->sin_family != AF_INET) {
+ errno = EPFNOSUPPORT;
+ return (-1);
+ }
+
+ len = sizeof (optval);
+ if (getsockopt(sd, SOL_SOCKET, SO_TYPE, &optval, &len) < 0) {
+ return (-1);
+ }
+ /*
+ * Use *_ANONPRIVBIND to ask the kernel to pick a port in the
+ * priviledged range for us.
+ */
+ if (optval == SOCK_STREAM) {
+ level = IPPROTO_TCP;
+ optname = TCP_ANONPRIVBIND;
+ } else if (optval == SOCK_DGRAM) {
+ level = IPPROTO_UDP;
+ optname = UDP_ANONPRIVBIND;
+ } else {
+ errno = EPROTONOSUPPORT;
+ return (-1);
+ }
+
+ optval = 1;
+ if (setsockopt(sd, level, optname, &optval, sizeof (optval)) < 0) {
+ return (-1);
+ }
+
+ bindaddr->sin_port = 0;
+ ret = bind(sd, (struct sockaddr *)bindaddr,
+ sizeof (struct sockaddr_in));
+
+ /*
+ * Always turn off the option when we are done. Note that by doing
+ * this, if the caller has set this option before calling
+ * bindresvport(), it will be unset. But this should never happen...
+ */
+ optval = 0;
+ (void) setsockopt(sd, level, optname, &optval, sizeof (optval));
+
+ if (ret >= 0 && sin != NULL) {
+ /*
+ * Historical note:
+ *
+ * Past versions of this bindresvport() code have
+ * returned with the reserved port number bound
+ * filled in its "sin" parameter (if passed in), perhaps
+ * "accidently" because of the structure of historical code.
+ *
+ * This is not documented but the behavior is
+ * explicitly retained here for compatibility to minimize
+ * risk to applications, even though it is not clear if this
+ * was a design intent.
+ */
+ len = sizeof (struct sockaddr_in);
+ (void) getsockname(sd, (struct sockaddr *)bindaddr, &len);
+ }
+ return (ret);
+}
diff --git a/usr/src/lib/libsocket/inet/bootparams_getbyname.c b/usr/src/lib/libsocket/inet/bootparams_getbyname.c
new file mode 100644
index 0000000000..d071a81c2a
--- /dev/null
+++ b/usr/src/lib/libsocket/inet/bootparams_getbyname.c
@@ -0,0 +1,107 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ * Copyright 1997 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <nss_dbdefs.h>
+
+static int str2bootent(const char *, int, void *, char *, int);
+
+static DEFINE_NSS_DB_ROOT(db_root);
+
+static void
+_nss_initf_bootparams(nss_db_params_t *p)
+{
+ p->name = NSS_DBNAM_BOOTPARAMS;
+ p->default_config = NSS_DEFCONF_BOOTPARAMS;
+}
+
+int
+bootparams_getbyname(
+ char *name, /* lookup key */
+ char *linebuf, /* buffer to put the answer in */
+ int linelen /* max # of bytes to put into linebuf */
+)
+{
+ nss_XbyY_args_t arg;
+ nss_status_t res;
+
+ NSS_XbyY_INIT(&arg, linebuf, linebuf, linelen, str2bootent);
+ arg.key.name = name;
+ res = nss_search(&db_root, _nss_initf_bootparams,
+ NSS_DBOP_BOOTPARAMS_BYNAME, &arg);
+ (void) NSS_XbyY_FINI(&arg);
+ return (arg.status = res);
+}
+
+/*
+ * Return values: 0 = success, 1 = parse error, 2 = erange ...
+ * The structure pointer passed in is a buffer in the caller's space.
+ * instring and buffer should be separate areas.
+ * The calling routine does all the real parsing; we just check limits and
+ * store the entry in the buffer we were passed by the caller.
+ * NOTE: we expect the data we're passed (in instr) has had the host's name
+ * stripped off the begining.
+ */
+/* ARGSUSED */
+static int
+str2bootent(
+ const char *instr,
+ int lenstr,
+ void *ent, /* really (char *) */
+ char *buffer,
+ int buflen
+)
+{
+ const char *p, *limit;
+
+ if ((instr >= buffer && (buffer + buflen) > instr) ||
+ (buffer >= instr && (instr + lenstr) > buffer)) {
+ return (NSS_STR_PARSE_PARSE);
+ }
+ p = instr;
+ limit = p + lenstr;
+
+ /* Skip over leading whitespace */
+ while (p < limit && isspace(*p)) {
+ p++;
+ }
+ if (p >= limit) {
+ /* Syntax error -- no data! */
+ return (NSS_STR_PARSE_PARSE);
+ }
+ lenstr -= (p - instr);
+ if (buflen <= lenstr) { /* not enough buffer */
+ return (NSS_STR_PARSE_ERANGE);
+ }
+ (void) memcpy(buffer, p, lenstr);
+ buffer[lenstr] = '\0';
+
+ return (NSS_STR_PARSE_SUCCESS);
+}
diff --git a/usr/src/lib/libsocket/inet/byteorder.c b/usr/src/lib/libsocket/inet/byteorder.c
new file mode 100644
index 0000000000..1b325c6c5e
--- /dev/null
+++ b/usr/src/lib/libsocket/inet/byteorder.c
@@ -0,0 +1,61 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/isa_defs.h>
+#include <sys/types.h>
+
+
+#ifdef _LITTLE_ENDIAN
+#error Use ISA-specific byteorder.s on a little-endian machine.
+
+#else /* !_LITTLE_ENDIAN */
+
+uint32_t
+htonl(uint32_t in)
+{
+ return (in);
+}
+
+uint32_t
+ntohl(uint32_t in)
+{
+ return (in);
+}
+
+uint16_t
+htons(uint16_t in)
+{
+ return (in);
+}
+
+uint16_t
+ntohs(uint16_t in)
+{
+ return (in);
+}
+#endif /* _LITTLE_ENDIAN */
diff --git a/usr/src/lib/libsocket/inet/ether_addr.c b/usr/src/lib/libsocket/inet/ether_addr.c
new file mode 100644
index 0000000000..7bf8d069ef
--- /dev/null
+++ b/usr/src/lib/libsocket/inet/ether_addr.c
@@ -0,0 +1,311 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * University Copyright- Copyright (c) 1982, 1986, 1988
+ * The Regents of the University of California
+ * All Rights Reserved
+ *
+ * University Acknowledgment- Portions of this document are derived from
+ * software developed by the University of California, Berkeley, and its
+ * contributors.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * All routines necessary to deal the "ethers" database. The sources
+ * contain mappings between 48 bit ethernet addresses and corresponding
+ * hosts names. The addresses have an ascii representation of the form
+ * "x:x:x:x:x:x" where x is a hex number between 0x00 and 0xff; the
+ * bytes are always in network order.
+ */
+
+#include "mtlib.h"
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <thread.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <nss_dbdefs.h>
+
+static int str2ether(const char *, int, void *, char *, int);
+
+static DEFINE_NSS_DB_ROOT(db_root);
+
+static void
+_nss_initf_ethers(nss_db_params_t *p)
+{
+ p->name = NSS_DBNAM_ETHERS;
+ p->default_config = NSS_DEFCONF_ETHERS;
+}
+
+/*
+ * Given a host's name, this routine finds the corresponding 48 bit
+ * ethernet address based on the "ethers" policy in /etc/nsswitch.conf.
+ * Returns zero if successful, non-zero otherwise.
+ */
+int
+ether_hostton(
+ const char *host, /* function input */
+ struct ether_addr *e /* function output */
+)
+{
+ nss_XbyY_args_t arg;
+ nss_status_t res;
+
+ /*
+ * let the backend do the allocation to store stuff for parsing.
+ */
+ NSS_XbyY_INIT(&arg, e, NULL, 0, str2ether);
+ arg.key.name = host;
+ res = nss_search(&db_root, _nss_initf_ethers,
+ NSS_DBOP_ETHERS_HOSTTON, &arg);
+ (void) NSS_XbyY_FINI(&arg);
+ return (arg.status = res);
+}
+
+/*
+ * Given a 48 bit ethernet address, it finds the corresponding hostname
+ * ethernet address based on the "ethers" policy in /etc/nsswitch.conf.
+ * Returns zero if successful, non-zero otherwise.
+ */
+int
+ether_ntohost(
+ char *host, /* function output */
+ const struct ether_addr *e /* function input */
+)
+{
+ nss_XbyY_args_t arg;
+ nss_status_t res;
+
+ /*
+ * let the backend do the allocation to store stuff for parsing.
+ */
+ NSS_XbyY_INIT(&arg, NULL, host, 0, str2ether);
+ arg.key.ether = (void *)e;
+ res = nss_search(&db_root, _nss_initf_ethers,
+ NSS_DBOP_ETHERS_NTOHOST, &arg);
+ /* memcpy(host, ether_res.host, strlen(ether_res.host)); */
+ (void) NSS_XbyY_FINI(&arg);
+ return (arg.status = res);
+}
+
+/*
+ * Parses a line from "ethers" database into its components. The line has
+ * the form 8:0:20:1:17:c8 krypton
+ * where the first part is a 48 bit ethernet address and the second is
+ * the corresponding hosts name.
+ * Returns zero if successful, non-zero otherwise.
+ */
+int
+ether_line(
+ const char *s, /* the string to be parsed */
+ struct ether_addr *e, /* ethernet address struct to be filled in */
+ char *hostname /* hosts name to be set */
+)
+{
+ int i;
+ uint_t t[6];
+
+ i = sscanf(s, " %x:%x:%x:%x:%x:%x %s",
+ &t[0], &t[1], &t[2], &t[3], &t[4], &t[5], hostname);
+ if (i != 7) {
+ return (7 - i);
+ }
+ for (i = 0; i < 6; i++)
+ e->ether_addr_octet[i] = (uchar_t)t[i];
+ return (0);
+}
+
+/*
+ * Parses a line from "ethers" database into its components.
+ * Useful for the vile purposes of the backends that
+ * expect a str2ether() format.
+ *
+ * This function, after parsing the instr line, will
+ * place the resulting struct ether_addr in b->buf.result only if
+ * b->buf.result is initialized (not NULL). I.e. it always happens
+ * for "files" backend (that needs to parse input line and
+ * then do a match for the ether key) and happens for "nis"
+ * backend only if the call was ether_hostton.
+ *
+ * Also, it will place the resulting hostname into b->buf.buffer
+ * only if b->buf.buffer is initialized. I.e. it always happens
+ * for "files" backend (that needs to parse input line and
+ * then do a match for the host key) and happens for "nis"
+ * backend only if the call was ether_ntohost.
+ *
+ * Cannot use the sscanf() technique for parsing because instr
+ * is a read-only, not necessarily null-terminated, buffer.
+ *
+ * Return values: 0 = success, 1 = parse error, 2 = erange ...
+ * The structure pointer passed in is a structure in the caller's space
+ * wherein the field pointers would be set to areas in the buffer if
+ * need be. instring and buffer should be separate areas.
+ */
+#define DIGIT(x) (isdigit(x) ? (x) - '0' : \
+ islower(x) ? (x) + 10 - 'a' : (x) + 10 - 'A')
+#define lisalnum(x) (isdigit(x) || \
+ ((x) >= 'a' && (x) <= 'z') || ((x) >= 'A' && (x) <= 'Z'))
+/* ARGSUSED */
+static int
+str2ether(const char *instr, int lenstr, void *ent, char *buffer, int buflen)
+{
+ uchar_t *ether = (uchar_t *)ent;
+ char *host = buffer;
+ const char *p, *limit, *start;
+ ptrdiff_t i;
+
+ p = instr;
+ limit = p + lenstr;
+
+ /* skip beginning whitespace, if any */
+ while (p < limit && isspace(*p))
+ p++;
+
+ if (ether) { /* parse ether */
+ for (i = 0; i < 6; i++) {
+ int j = 0, n = 0;
+
+ start = p;
+ while (p < limit && lisalnum(start[j])) {
+ /* don't worry about overflow here */
+ n = 16 * n + DIGIT(start[j]);
+ j++;
+ p++;
+ }
+ if (*p != ':' && i < 5) {
+ return (NSS_STR_PARSE_PARSE);
+ } else {
+ p++;
+ *(ether + i) = (uchar_t)n;
+ }
+ }
+ } else { /* skip ether */
+ while (p < limit && !isspace(*p))
+ p++;
+ }
+ if (host) { /* parse host */
+ while (p < limit && isspace(*p)) /* skip whitespace */
+ p++;
+ start = p;
+ while (p < limit && !isspace(*p)) /* skip hostname */
+ p++;
+ if ((i = (p - start)) < MAXHOSTNAMELEN) {
+ (void) memcpy(host, start, i);
+ host[i] = '\0';
+ } else
+ return (NSS_STR_PARSE_ERANGE); /* failure */
+ }
+ return (NSS_STR_PARSE_SUCCESS);
+}
+
+typedef struct {
+ char ea_string[18];
+ struct ether_addr ea_addr;
+} eabuf_t;
+
+static eabuf_t *
+ea_buf(void)
+{
+ static thread_key_t key;
+ static int key_once = 0;
+ static mutex_t tsd_lock = DEFAULTMUTEX;
+ static eabuf_t ea_main;
+ eabuf_t *eabuf = NULL;
+
+ if (thr_main())
+ return (&ea_main);
+
+ if (key_once == 0) {
+ (void) mutex_lock(&tsd_lock);
+ if (key_once == 0) {
+ if (thr_keycreate(&key, free) != 0) {
+ (void) mutex_unlock(&tsd_lock);
+ return (NULL);
+ }
+ key_once = 1;
+ }
+ (void) mutex_unlock(&tsd_lock);
+ }
+ (void) thr_getspecific(key, (void **)&eabuf);
+ if (eabuf == NULL) {
+ eabuf = malloc(sizeof (eabuf_t));
+ (void) thr_setspecific(key, eabuf);
+ }
+ return (eabuf);
+}
+
+/*
+ * Converts a 48 bit ethernet number to its string representation.
+ */
+char *
+ether_ntoa(const struct ether_addr *e)
+{
+ eabuf_t *eabuf;
+ char *s;
+
+ if ((eabuf = ea_buf()) == NULL)
+ return (NULL);
+ s = eabuf->ea_string;
+ (void) sprintf(s, "%x:%x:%x:%x:%x:%x",
+ e->ether_addr_octet[0], e->ether_addr_octet[1],
+ e->ether_addr_octet[2], e->ether_addr_octet[3],
+ e->ether_addr_octet[4], e->ether_addr_octet[5]);
+ return (s);
+}
+
+/*
+ * Converts an ethernet address representation back into its 48 bits.
+ */
+struct ether_addr *
+ether_aton(const char *s)
+{
+ eabuf_t *eabuf;
+ struct ether_addr *e;
+ int i;
+ uint_t t[6];
+
+ if ((eabuf = ea_buf()) == NULL)
+ return (NULL);
+ e = &eabuf->ea_addr;
+ i = sscanf(s, " %x:%x:%x:%x:%x:%x",
+ &t[0], &t[1], &t[2], &t[3], &t[4], &t[5]);
+ if (i != 6)
+ return (NULL);
+ for (i = 0; i < 6; i++)
+ e->ether_addr_octet[i] = (uchar_t)t[i];
+ return (e);
+}
diff --git a/usr/src/lib/libsocket/inet/getaddrinfo.c b/usr/src/lib/libsocket/inet/getaddrinfo.c
new file mode 100644
index 0000000000..9d978a7496
--- /dev/null
+++ b/usr/src/lib/libsocket/inet/getaddrinfo.c
@@ -0,0 +1,806 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <nss_dbdefs.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <string.h>
+#include <strings.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <net/if.h>
+
+extern char *_dgettext(const char *, const char *);
+
+#define ai2sin(x) ((struct sockaddr_in *)((x)->ai_addr))
+#define ai2sin6(x) ((struct sockaddr_in6 *)((x)->ai_addr))
+
+#define HOST_BROADCAST "255.255.255.255"
+
+/*
+ * getaddrinfo() returns EAI_NONAME in some cases, however
+ * since EAI_NONAME is not part of SUSv3 it needed to be
+ * masked in the standards compliant environment.
+ * GAIV_DEFAULT and GAIV_XPG6 accomplish this.
+ */
+#define GAIV_DEFAULT 0
+#define GAIV_XPG6 1
+
+/*
+ * Storage allocation for global variables in6addr_any and
+ * in6addr_loopback. The extern declarations for these
+ * variables are defined in <netinet/in.h>. These two
+ * variables could have been defined in any of the "C" files
+ * in libsocket. They are defined here with other IPv6
+ * related interfaces.
+ */
+const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
+const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
+
+/* AI_MASK: all valid flags for addrinfo */
+#define AI_MASK (AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST \
+ | AI_ADDRCONFIG | AI_NUMERICSERV | AI_V4MAPPED | AI_ALL)
+#define ANY 0
+/* function prototypes for used by getaddrinfo() routine */
+static int get_addr(int family, const char *hostname, struct addrinfo *aip,
+ struct addrinfo *cur, ushort_t port, int version);
+static uint_t getscopeidfromzone(const struct sockaddr_in6 *sa,
+ const char *zone, uint32_t *sin6_scope_id);
+static boolean_t str_isnumber(const char *p);
+
+/*
+ * getaddrinfo:
+ *
+ * Purpose:
+ * Routine for performing Address-to-nodename in a
+ * protocol-independent fashion.
+ * Description and history of the routine:
+ * Nodename-to-address translation is done in a protocol-
+ * independent fashion using the getaddrinfo() function
+ * that is taken from the IEEE POSIX 1003.1g.
+ *
+ * The official specification for this function will be the
+ * final POSIX standard, with the following additional
+ * requirements:
+ *
+ * - getaddrinfo() must be thread safe
+ * - The AI_NUMERICHOST is new.
+ * - All fields in socket address structures returned by
+ *
+ * getaddrinfo() that are not filled in through an explicit
+ * argument (e.g., sin6_flowinfo and sin_zero) must be set to 0.
+ * (This makes it easier to compare socket address structures).
+ *
+ * Input Parameters:
+ * nodename - pointer to null-terminated strings that represents
+ * a hostname or literal ip address (IPv4/IPv6) or this
+ * pointer can be NULL.
+ * servname - pointer to null-terminated strings that represents
+ * a servicename or literal port number or this
+ * pointer can be NULL.
+ * hints - optional argument that points to an addrinfo structure
+ * to provide hints on the type of socket that the caller
+ * supports.
+ * Possible setting of the ai_flags member of the hints structure:
+ * AI_PASSIVE - If set, the caller plans to use the returned socket
+ * address in a call to bind(). In this case, it the
+ * nodename argument is NULL, then the IP address portion
+ * of the socket address structure will be set to
+ * INADDR_ANY for IPv4 or IN6ADDR_ANY_INIT for IPv6.
+ * AI_PASSIVE - If not set, then the returned socket address will be
+ * ready for a call to connect() (for conn-oriented) or
+ * connect(), sendto(), or sendmsg() (for connectionless).
+ * In this case, if nodename is NULL, then the IP address
+ * portion of the socket address structure will be set to
+ * the loopback address.
+ * AI_CANONNAME - If set, then upon successful return the ai_canonname
+ * field of the first addrinfo structure in the linked
+ * list will point to a NULL-terminated string
+ * containing the canonical name of the specified nodename.
+ * AI_NUMERICHOST - If set, then a non-NULL nodename string must be a numeric
+ * host address string. Otherwise an error of EAI_NONAME
+ * is returned. This flag prevents any type of name
+ * resolution service from being called.
+ * AI_NUMERICSERV - If set, then a non-null servname string supplied shall
+ * be a numeric port string. Otherwise, an [EAI_NONAME]
+ * error shall be returned. This flag shall prevent any
+ * type of name resolution service from being invoked.
+ * AI_V4MAPPED - If set, along with an ai_family of AF_INET6, then
+ * getaddrinfo() shall return IPv4-mapped IPv6 addresses
+ * on finding no matching IPv6 addresses ( ai_addrlen shall
+ * be 16). The AI_V4MAPPED flag shall be ignored unless
+ * ai_family equals AF_INET6.
+ * AI_ALL - If the AI_ALL flag is used with the AI_V4MAPPED flag,
+ * then getaddrinfo() shall return all matching IPv6 and
+ * IPv4 addresses. The AI_ALL flag without the AI_V4MAPPED
+ * flag is ignored.
+ * Output Parameters:
+ * res - upon successful return a pointer to a linked list of one
+ * or more addrinfo structures is returned through this
+ * argument. The caller can process each addrinfo structures
+ * in this list by following the ai_next pointer, until a
+ * NULL pointer is encountered. In each returned addrinfo
+ * structure the three members ai_family, ai_socktype, and
+ * ai_protocol are corresponding arguments for a call to the
+ * socket() function. In each addrinfo structure the ai_addr
+ * field points to filled-in socket address structure whose
+ * length is specified by the ai_addrlen member.
+ *
+ * Return Value:
+ * This function returns 0 upon success or a nonzero error code. The
+ * following names are nonzero error codes from getaddrinfo(), and are
+ * defined in <netdb.h>.
+ * EAI_ADDRFAMILY - address family not supported
+ * EAI_AGAIN - DNS temporary failure
+ * EAI_BADFLAGS - invalid ai_flags
+ * EAI_FAIL - DNS non-recoverable failure
+ * EAI_FAMILY - ai_family not supported
+ * EAI_MEMORY - memory allocation failure
+ * EAI_NODATA - no address associated with nodename
+ * EAI_NONAME - host/servname not known
+ * EAI_SERVICE - servname not supported for ai_socktype
+ * EAI_SOCKTYPE - ai_socktype not supported
+ * EAI_SYSTEM - system error in errno
+ *
+ * Memory Allocation:
+ * All of the information returned by getaddrinfo() is dynamically
+ * allocated: the addrinfo structures, and the socket address
+ * structures and canonical node name strings pointed to by the
+ * addrinfo structures.
+ */
+
+
+static int
+_getaddrinfo(const char *hostname, const char *servname,
+ const struct addrinfo *hints, struct addrinfo **res, int version)
+{
+ struct addrinfo *cur;
+ struct addrinfo *aip;
+ struct addrinfo ai;
+ int error;
+ ushort_t port;
+
+ cur = &ai;
+ aip = &ai;
+
+ aip->ai_flags = 0;
+ aip->ai_family = PF_UNSPEC;
+ aip->ai_socktype = 0;
+ aip->ai_protocol = 0;
+#ifdef __sparcv9
+ /*
+ * We need to clear _ai_pad to preserve binary
+ * compatibility with previously compiled 64-bit
+ * applications by guaranteeing the upper 32-bits
+ * are empty.
+ */
+ aip->_ai_pad = 0;
+#endif /* __sparcv9 */
+ aip->ai_addrlen = 0;
+ aip->ai_canonname = NULL;
+ aip->ai_addr = NULL;
+ aip->ai_next = NULL;
+ port = 0;
+
+ /* if nodename nor servname provided */
+ if (hostname == NULL && servname == NULL) {
+ *res = NULL;
+ return (EAI_NONAME);
+ }
+ if (hints != NULL) {
+ /* check for bad flags in hints */
+ if ((hints->ai_flags != 0) && (hints->ai_flags & ~AI_MASK)) {
+ *res = NULL;
+ return (EAI_BADFLAGS);
+ }
+ if ((hostname == NULL || *hostname == '\0') &&
+ (hints->ai_flags & AI_CANONNAME)) {
+ *res = NULL;
+ return (EAI_BADFLAGS);
+ }
+ if (hints->ai_family != PF_UNSPEC &&
+ hints->ai_family != PF_INET &&
+ hints->ai_family != PF_INET6) {
+ *res = NULL;
+ return (EAI_FAMILY);
+ }
+
+ (void) memcpy(aip, hints, sizeof (*aip));
+#ifdef __sparcv9
+ /*
+ * We need to clear _ai_pad to preserve binary
+ * compatibility. See prior comment.
+ */
+ aip->_ai_pad = 0;
+#endif /* __sparcv9 */
+ switch (aip->ai_socktype) {
+ case ANY:
+ switch (aip->ai_protocol) {
+ case ANY:
+ break;
+ case IPPROTO_UDP:
+ aip->ai_socktype = SOCK_DGRAM;
+ break;
+ case IPPROTO_TCP:
+ aip->ai_socktype = SOCK_STREAM;
+ break;
+ default:
+ aip->ai_socktype = SOCK_RAW;
+ break;
+ }
+ break;
+ case SOCK_RAW:
+ break;
+ case SOCK_DGRAM:
+ aip->ai_protocol = IPPROTO_UDP;
+ break;
+ case SOCK_STREAM:
+ aip->ai_protocol = IPPROTO_TCP;
+ break;
+ default:
+ *res = NULL;
+ return (EAI_SOCKTYPE);
+ }
+ }
+
+ /*
+ * Get the service.
+ */
+
+ if (servname != NULL) {
+ struct servent result;
+ int bufsize = 128;
+ char *buf = NULL;
+ struct servent *sp;
+ char *proto = NULL;
+
+ switch (aip->ai_socktype) {
+ case ANY:
+ proto = NULL;
+ break;
+ case SOCK_DGRAM:
+ proto = "udp";
+ break;
+ case SOCK_STREAM:
+ proto = "tcp";
+ break;
+ }
+ /*
+ * Servname string can be a decimal port number.
+ * If we already know the socket type there is no need
+ * to call getservbyport.
+ */
+ if (aip->ai_flags & AI_NUMERICSERV) {
+ if (!str_isnumber(servname)) {
+ return (EAI_NONAME);
+ }
+ port = htons(atoi(servname));
+ } else if (str_isnumber(servname)) {
+ port = htons(atoi(servname));
+ if (aip->ai_socktype == ANY) {
+ do {
+ if (buf != NULL)
+ free(buf);
+ bufsize *= 2;
+ buf = malloc(bufsize);
+ if (buf == NULL) {
+ *res = NULL;
+ return (EAI_MEMORY);
+ }
+
+ sp = getservbyport_r(port, proto,
+ &result, buf, bufsize);
+ if (sp == NULL && errno != ERANGE) {
+ free(buf);
+ *res = NULL;
+ return (EAI_SERVICE);
+ }
+ /*
+ * errno == ERANGE so our scratch buffer space
+ * wasn't big enough. Double it and try
+ * again.
+ */
+ } while (sp == NULL);
+ }
+ } else {
+ do {
+ if (buf != NULL)
+ free(buf);
+ bufsize *= 2;
+ buf = malloc(bufsize);
+ if (buf == NULL) {
+ *res = NULL;
+ return (EAI_MEMORY);
+ }
+
+ sp = getservbyname_r(servname, proto, &result,
+ buf, bufsize);
+ if (sp == NULL && errno != ERANGE) {
+ free(buf);
+ *res = NULL;
+ return (EAI_SERVICE);
+ }
+ /*
+ * errno == ERANGE so our scratch buffer space wasn't
+ * big enough. Double it and try again.
+ */
+ } while (sp == NULL);
+
+ port = sp->s_port;
+ }
+ if (aip->ai_socktype == ANY) {
+ if (aip->ai_flags & AI_NUMERICSERV) {
+ /*
+ * RFC 2553bis doesn't allow us to use the
+ * any resolver to find out if there is a
+ * match. We could walk the service file
+ * with *servent(). Given the commonality of
+ * calling getaddrinfo() with a number and
+ * ANY protocol we won't add that at this time.
+ */
+ return (EAI_NONAME);
+ }
+
+ if (strcmp(sp->s_proto, "udp") == 0) {
+ aip->ai_socktype = SOCK_DGRAM;
+ aip->ai_protocol = IPPROTO_UDP;
+ } else if (strcmp(sp->s_proto, "tcp") == 0) {
+ aip->ai_socktype = SOCK_STREAM;
+ aip->ai_protocol = IPPROTO_TCP;
+ } else {
+ if (buf != NULL)
+ free(buf);
+
+ *res = NULL;
+ errno = EPROTONOSUPPORT;
+ return (EAI_SYSTEM);
+ }
+ }
+
+ if (buf != NULL)
+ free(buf);
+ }
+
+ /*
+ * hostname is NULL
+ * case 1: AI_PASSIVE bit set : anyaddr 0.0.0.0 or ::
+ * case 2: AI_PASSIVE bit not set : localhost 127.0.0.1 or ::1
+ */
+
+ if (hostname == NULL) {
+ struct addrinfo *nai;
+ socklen_t addrlen;
+ char *canonname;
+
+ if (aip->ai_family == PF_INET)
+ goto v4only;
+ /* create IPv6 addrinfo */
+ nai = malloc(sizeof (struct addrinfo));
+ if (nai == NULL)
+ goto nomem;
+ *nai = *aip;
+ addrlen = sizeof (struct sockaddr_in6);
+ nai->ai_addr = malloc(addrlen);
+ if (nai->ai_addr == NULL) {
+ freeaddrinfo(nai);
+ goto nomem;
+ }
+ bzero(nai->ai_addr, addrlen);
+ nai->ai_addrlen = addrlen;
+ nai->ai_family = PF_INET6;
+ nai->ai_protocol = 0;
+ nai->ai_canonname = NULL;
+ if (nai->ai_flags & AI_PASSIVE) {
+ ai2sin6(nai)->sin6_addr = in6addr_any;
+ } else {
+ ai2sin6(nai)->sin6_addr = in6addr_loopback;
+ if (nai->ai_flags & AI_CANONNAME) {
+ canonname = strdup("loopback");
+ if (canonname == NULL) {
+ freeaddrinfo(nai);
+ goto nomem;
+ }
+ nai->ai_canonname = canonname;
+ }
+ }
+ ai2sin6(nai)->sin6_family = PF_INET6;
+ ai2sin6(nai)->sin6_port = port;
+ cur->ai_next = nai;
+ cur = nai;
+ if (aip->ai_family == PF_INET6) {
+ cur->ai_next = NULL;
+ goto success;
+ }
+ /* If address family is PF_UNSPEC or PF_INET */
+v4only:
+ /* create IPv4 addrinfo */
+ nai = malloc(sizeof (struct addrinfo));
+ if (nai == NULL)
+ goto nomem;
+ *nai = *aip;
+ addrlen = sizeof (struct sockaddr_in);
+ nai->ai_addr = malloc(addrlen);
+ if (nai->ai_addr == NULL) {
+ freeaddrinfo(nai);
+ goto nomem;
+ }
+ bzero(nai->ai_addr, addrlen);
+ nai->ai_addrlen = addrlen;
+ nai->ai_family = PF_INET;
+ nai->ai_protocol = 0;
+ nai->ai_canonname = NULL;
+ if (nai->ai_flags & AI_PASSIVE) {
+ ai2sin(nai)->sin_addr.s_addr = INADDR_ANY;
+ } else {
+ ai2sin(nai)->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ if (nai->ai_flags & AI_CANONNAME &&
+ nai->ai_family != PF_UNSPEC) {
+ canonname = strdup("loopback");
+ if (canonname == NULL) {
+ freeaddrinfo(nai);
+ goto nomem;
+ }
+ nai->ai_canonname = canonname;
+ }
+ }
+ ai2sin(nai)->sin_family = PF_INET;
+ ai2sin(nai)->sin_port = port;
+ cur->ai_next = nai;
+ cur = nai;
+ cur->ai_next = NULL;
+ goto success;
+ }
+
+ /* hostname string is a literal address or an alphabetical name */
+ error = get_addr(aip->ai_family, hostname, aip, cur, port, version);
+ if (error) {
+ *res = NULL;
+ return (error);
+ }
+
+success:
+ *res = aip->ai_next;
+ return (0);
+
+nomem:
+ return (EAI_MEMORY);
+}
+
+int
+getaddrinfo(const char *hostname, const char *servname,
+ const struct addrinfo *hints, struct addrinfo **res)
+{
+ return (_getaddrinfo(hostname, servname, hints, res, GAIV_DEFAULT));
+}
+
+int
+__xnet_getaddrinfo(const char *hostname, const char *servname,
+ const struct addrinfo *hints, struct addrinfo **res)
+{
+ return (_getaddrinfo(hostname, servname, hints, res, GAIV_XPG6));
+}
+
+static int
+get_addr(int family, const char *hostname, struct addrinfo *aip, struct
+ addrinfo *cur, ushort_t port, int version)
+{
+ struct hostent *hp;
+ char _hostname[MAXHOSTNAMELEN];
+ int i, errnum;
+ struct addrinfo *nai;
+ int addrlen;
+ char *canonname;
+ boolean_t firsttime = B_TRUE;
+ boolean_t create_v6_addrinfo;
+ struct in_addr v4addr;
+ struct in6_addr v6addr;
+ struct in6_addr *v6addrp;
+ char *zonestr = NULL;
+
+ /*
+ * Check for existence of address-zoneid delimiter '%'
+ * If the delimiter exists, parse the zoneid portion of
+ * <addr>%<zone_id>
+ */
+ if ((zonestr = strchr(hostname, '%')) != NULL) {
+ /* make sure we have room for <addr> portion of hostname */
+ if (((zonestr - hostname) + 1) > sizeof (_hostname)) {
+ return (EAI_MEMORY);
+ }
+
+ /* chop off and save <zone_id> portion */
+ (void) strlcpy(_hostname, hostname, (zonestr - hostname) + 1);
+ ++zonestr; /* make zonestr point at start of <zone-id> */
+ /* ensure zone is valid */
+ if ((*zonestr == '\0') || (strlen(zonestr) > LIFNAMSIZ)) {
+ return (EAI_NONAME);
+ }
+ } else {
+ size_t hlen = sizeof (_hostname);
+
+ if (strlcpy(_hostname, hostname, hlen) >= hlen) {
+ return (EAI_MEMORY);
+ }
+ }
+
+ /* Check to see if AI_NUMERICHOST bit is set */
+ if (aip->ai_flags & AI_NUMERICHOST) {
+ /* check to see if _hostname points to a literal IP address */
+ if (!((inet_addr(_hostname) != ((in_addr_t)-1)) ||
+ (strcmp(_hostname, HOST_BROADCAST) == 0) ||
+ (inet_pton(AF_INET6, _hostname, &v6addr) > 0))) {
+ return (EAI_NONAME);
+ }
+ }
+
+ /* if hostname argument is literal, name service doesn't get called */
+ if (family == PF_UNSPEC) {
+ hp = getipnodebyname(_hostname, AF_INET6, AI_ALL |
+ aip->ai_flags | AI_V4MAPPED, &errnum);
+ } else {
+ hp = getipnodebyname(_hostname, family, aip->ai_flags, &errnum);
+ }
+
+ if (hp == NULL) {
+ switch (errnum) {
+ case HOST_NOT_FOUND:
+ return (EAI_NONAME);
+ case TRY_AGAIN:
+ return (EAI_AGAIN);
+ case NO_RECOVERY:
+ return (EAI_FAIL);
+ case NO_ADDRESS:
+ if (version == GAIV_XPG6)
+ return (EAI_NONAME);
+ return (EAI_NODATA);
+ default:
+ return (EAI_SYSTEM);
+ }
+ }
+
+ for (i = 0; hp->h_addr_list[i]; i++) {
+ /* Determine if an IPv6 addrinfo structure should be created */
+ create_v6_addrinfo = B_TRUE;
+ if (hp->h_addrtype == AF_INET6) {
+ v6addrp = (struct in6_addr *)hp->h_addr_list[i];
+ if (!(aip->ai_flags & AI_V4MAPPED) &&
+ IN6_IS_ADDR_V4MAPPED(v6addrp)) {
+ create_v6_addrinfo = B_FALSE;
+ IN6_V4MAPPED_TO_INADDR(v6addrp, &v4addr);
+ }
+ } else if (hp->h_addrtype == AF_INET) {
+ create_v6_addrinfo = B_FALSE;
+ (void) memcpy(&v4addr, hp->h_addr_list[i],
+ sizeof (struct in_addr));
+ } else {
+ return (EAI_SYSTEM);
+ }
+
+ if (create_v6_addrinfo) {
+ /* create IPv6 addrinfo */
+ nai = malloc(sizeof (struct addrinfo));
+ if (nai == NULL)
+ goto nomem;
+ *nai = *aip;
+ addrlen = sizeof (struct sockaddr_in6);
+ nai->ai_addr = malloc(addrlen);
+ if (nai->ai_addr == NULL) {
+ freeaddrinfo(nai);
+ goto nomem;
+ }
+ bzero(nai->ai_addr, addrlen);
+ nai->ai_addrlen = addrlen;
+ nai->ai_family = PF_INET6;
+ nai->ai_protocol = 0;
+
+ (void) memcpy(ai2sin6(nai)->sin6_addr.s6_addr,
+ hp->h_addr_list[i], sizeof (struct in6_addr));
+ nai->ai_canonname = NULL;
+ if ((nai->ai_flags & AI_CANONNAME) && firsttime) {
+ canonname = strdup(hp->h_name);
+ if (canonname == NULL) {
+ freeaddrinfo(nai);
+ goto nomem;
+ }
+ nai->ai_canonname = canonname;
+ firsttime = B_FALSE;
+ }
+ ai2sin6(nai)->sin6_family = PF_INET6;
+ ai2sin6(nai)->sin6_port = port;
+ /* set sin6_scope_id */
+ if (zonestr != NULL) {
+ /*
+ * Translate 'zonestr' into a valid
+ * sin6_scope_id.
+ */
+ if ((errnum =
+ getscopeidfromzone(ai2sin6(nai), zonestr,
+ &ai2sin6(nai)->sin6_scope_id)) != 0) {
+ return (errnum);
+ }
+ } else {
+ ai2sin6(nai)->sin6_scope_id = 0;
+ }
+ } else {
+ /* create IPv4 addrinfo */
+ nai = malloc(sizeof (struct addrinfo));
+ if (nai == NULL)
+ goto nomem;
+ *nai = *aip;
+ addrlen = sizeof (struct sockaddr_in);
+ nai->ai_addr = malloc(addrlen);
+ if (nai->ai_addr == NULL) {
+ freeaddrinfo(nai);
+ goto nomem;
+ }
+ bzero(nai->ai_addr, addrlen);
+ nai->ai_addrlen = addrlen;
+ nai->ai_family = PF_INET;
+ nai->ai_protocol = 0;
+ (void) memcpy(&(ai2sin(nai)->sin_addr.s_addr),
+ &v4addr, sizeof (struct in_addr));
+ nai->ai_canonname = NULL;
+ if (nai->ai_flags & AI_CANONNAME && firsttime) {
+ canonname = strdup(hp->h_name);
+ if (canonname == NULL) {
+ freeaddrinfo(nai);
+ goto nomem;
+ }
+ nai->ai_canonname = canonname;
+ firsttime = B_FALSE;
+ }
+ ai2sin(nai)->sin_family = PF_INET;
+ ai2sin(nai)->sin_port = port;
+ }
+
+ cur->ai_next = nai;
+ cur = nai;
+ }
+ cur->ai_next = NULL;
+ freehostent(hp);
+ return (0);
+
+nomem:
+ freehostent(hp);
+ return (EAI_MEMORY);
+
+}
+
+/*
+ * getscopeidfromzone(sa, zone, sin6_scope_id)
+ *
+ * Converts the string pointed to by 'zone' into a sin6_scope_id.
+ * 'zone' will either be a pointer to an interface name or will
+ * be a literal sin6_scope_id.
+ *
+ * 0 is returned on success and the output parameter 'sin6_scope_id' will
+ * be set to a valid sin6_scope_id.
+ * EAI_NONAME is returned for either of two reasons:
+ * 1. The IPv6 address pointed to by sa->sin6_addr is not
+ * part of the 'link scope' (ie link local, nodelocal multicast or
+ * linklocal multicast address)
+ * 2. The string pointed to by 'zone' can not be translate to a valid
+ * sin6_scope_id.
+ */
+static uint_t
+getscopeidfromzone(const struct sockaddr_in6 *sa, const char *zone,
+ uint32_t *sin6_scope_id) {
+ const in6_addr_t *addr = &sa->sin6_addr;
+ ulong_t ul_scope_id;
+ char *endp;
+
+ if (IN6_IS_ADDR_LINKSCOPE(addr)) {
+ /*
+ * Look up interface index associated with interface name
+ * pointed to by 'zone'. Since the address is part of the link
+ * scope, there is a one-to-one relationship between interface
+ * index and sin6_scope_id.
+ * If an interface index can not be found for 'zone', then
+ * treat 'zone' as a literal sin6_scope_id value.
+ */
+ if ((*sin6_scope_id = if_nametoindex(zone)) != 0) {
+ return (0);
+ } else {
+ if ((ul_scope_id = strtoul(zone, &endp, 10)) != 0) {
+ /* check that entire string was read */
+ if (*endp != '\0') {
+ return (EAI_NONAME);
+ }
+ *sin6_scope_id =
+ (uint32_t)(ul_scope_id & 0xffffffffUL);
+ } else {
+ return (EAI_NONAME);
+ }
+ }
+ } else {
+ return (EAI_NONAME);
+ }
+ return (0);
+}
+
+
+void
+freeaddrinfo(struct addrinfo *ai)
+{
+ struct addrinfo *next;
+
+ do {
+ next = ai->ai_next;
+ if (ai->ai_canonname)
+ free(ai->ai_canonname);
+ if (ai->ai_addr)
+ free(ai->ai_addr);
+ free(ai);
+ ai = next;
+ } while (ai != NULL);
+}
+
+static boolean_t
+str_isnumber(const char *p)
+{
+ char *q = (char *)p;
+ while (*q) {
+ if (!isdigit(*q))
+ return (B_FALSE);
+ q++;
+ }
+ return (B_TRUE);
+}
+static const char *gai_errlist[] = {
+ "name translation error 0 (no error)", /* 0 */
+ "specified address family not supported", /* 1 EAI_ADDRFAMILY */
+ "temporary name resolution failure", /* 2 EAI_AGAIN */
+ "invalid flags", /* 3 EAI_BADFLAGS */
+ "non-recoverable name resolution failure", /* 4 EAI_FAIL */
+ "specified address family not supported", /* 5 EAI_FAMILY */
+ "memory allocation failure", /* 6 EAI_MEMORY */
+ "no address for the specified node name", /* 7 EAI_NODATA */
+ "node name or service name not known", /* 8 EAI_NONAME */
+ "service name not available for the specified socket type",
+ /* 9 EAI_SERVICE */
+ "specified socket type not supported", /* 10 EAI_SOCKTYPE */
+ "system error", /* 11 EAI_SYSTEM */
+};
+static int gai_nerr = { sizeof (gai_errlist)/sizeof (gai_errlist[0]) };
+
+const char *
+gai_strerror(int ecode)
+{
+ if (ecode < 0)
+ return (_dgettext(TEXT_DOMAIN,
+ "name translation internal error"));
+ else if (ecode < gai_nerr)
+ return (_dgettext(TEXT_DOMAIN, gai_errlist[ecode]));
+ return (_dgettext(TEXT_DOMAIN, "unknown name translation error"));
+}
diff --git a/usr/src/lib/libsocket/inet/getnameinfo.c b/usr/src/lib/libsocket/inet/getnameinfo.c
new file mode 100644
index 0000000000..3b707bb7f7
--- /dev/null
+++ b/usr/src/lib/libsocket/inet/getnameinfo.c
@@ -0,0 +1,378 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <nss_dbdefs.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <net/if.h>
+
+#define sa2sin(x) ((struct sockaddr_in *)(x))
+#define sa2sin6(x) ((struct sockaddr_in6 *)(x))
+
+#define NI_MASK (NI_NOFQDN | NI_NUMERICHOST | NI_NAMEREQD | NI_NUMERICSERV | \
+ NI_DGRAM | NI_WITHSCOPEID)
+
+static int addzoneid(const struct sockaddr_in6 *sa, char *host,
+ size_t hostlen);
+static size_t getzonestr(const struct sockaddr_in6 *sa, char *zonestr,
+ size_t zonelen);
+static const char *_inet_ntop_native();
+/*
+ * getnameinfo:
+ *
+ * Purpose:
+ * Routine for performing Address-to-nodename in a
+ * protocol-independent fashion.
+ * Description:
+ * This function looks up an IP address and port number provided
+ * by the caller in the name service database and returns the nodename
+ * and servname respectively in the buffers provided by the caller.
+ * Input Parameters:
+ * sa - points to either a sockaddr_in structure (for
+ * IPv4) or a sockaddr_in6 structure (for IPv6).
+ * salen - length of the sockaddr_in or sockaddr_in6 structure.
+ * hostlen - length of caller supplied "host" buffer
+ * servlen - length of caller supplied "serv" buffer
+ * flags - changes default actions based on setting.
+ * Possible settings for "flags":
+ * NI_NOFQDN - Always return nodename portion of the fully-qualified
+ * domain name (FQDN).
+ * NI_NUMERICHOST - Always return numeric form of the host's
+ * address.
+ * NI_NAMEREQD - If hostname cannot be located in database,
+ * don't return numeric form of address - return
+ * an error instead.
+ * NI_NUMERICSERV - Always return numeric form of the service address
+ * instead of its name.
+ * NI_DGRAM - Specifies that the service is a datagram service, and
+ * causes getservbyport() to be called with a second
+ * argument of "udp" instead of its default "tcp".
+ * Output Parameters:
+ * host - return the nodename associcated with the IP address in the
+ * buffer pointed to by the "host" argument.
+ * serv - return the service name associated with the port number
+ * in the buffer pointed to by the "serv" argument.
+ * Return Value:
+ * This function indicates successful completion by a zero return
+ * value; a non-zero return value indicates failure.
+ */
+int
+getnameinfo(const struct sockaddr *sa, socklen_t salen,
+ char *host, socklen_t hostlen,
+ char *serv, socklen_t servlen, int flags)
+{
+ char *addr;
+ size_t alen, slen;
+ in_port_t port;
+ int errnum;
+ int err;
+
+ /* Verify correctness of buffer lengths */
+ if ((hostlen == 0) && (servlen == 0))
+ return (EAI_FAIL);
+ /* Verify correctness of possible flag settings */
+ if ((flags != 0) && (flags & ~NI_MASK))
+ return (EAI_BADFLAGS);
+ if (sa == NULL)
+ return (EAI_ADDRFAMILY);
+ switch (sa->sa_family) {
+ case AF_INET:
+ addr = (char *)&sa2sin(sa)->sin_addr;
+ alen = sizeof (struct in_addr);
+ slen = sizeof (struct sockaddr_in);
+ port = (sa2sin(sa)->sin_port); /* network byte order */
+ break;
+ case AF_INET6:
+ addr = (char *)&sa2sin6(sa)->sin6_addr;
+ alen = sizeof (struct in6_addr);
+ slen = sizeof (struct sockaddr_in6);
+ port = (sa2sin6(sa)->sin6_port); /* network byte order */
+ break;
+ default:
+ return (EAI_FAMILY);
+ }
+ if (salen != slen)
+ return (EAI_FAIL);
+ /*
+ * Case 1: if Caller sets hostlen != 0, then
+ * fill in "host" buffer that user passed in
+ * with appropriate text string.
+ */
+ if (hostlen != 0) {
+ if (flags & NI_NUMERICHOST) {
+ /* Caller wants the host's numeric address */
+ if (inet_ntop(sa->sa_family, addr,
+ host, hostlen) == NULL)
+ return (EAI_SYSTEM);
+ } else {
+ struct hostent *hp;
+
+ /* Caller wants the name of host */
+ hp = getipnodebyaddr(addr, alen, sa->sa_family,
+ &errnum);
+ if (hp != NULL) {
+ if (flags & NI_NOFQDN) {
+ char *dot;
+ /*
+ * Caller doesn't want fully-qualified
+ * name.
+ */
+ dot = strchr(hp->h_name, '.');
+ if (dot != NULL)
+ *dot = '\0';
+ }
+ if (strlen(hp->h_name) + 1 > hostlen) {
+ freehostent(hp);
+ return (EAI_OVERFLOW);
+ }
+ (void) strcpy(host, hp->h_name);
+ freehostent(hp);
+ } else {
+ /*
+ * Host's name cannot be located in the name
+ * service database. If NI_NAMEREQD is set,
+ * return error; otherwise, return host's
+ * numeric address.
+ */
+ if (flags & NI_NAMEREQD) {
+ switch (errnum) {
+ case HOST_NOT_FOUND:
+ return (EAI_NONAME);
+ case TRY_AGAIN:
+ return (EAI_AGAIN);
+ case NO_RECOVERY:
+ return (EAI_FAIL);
+ case NO_ADDRESS:
+ return (EAI_NODATA);
+ default:
+ return (EAI_SYSTEM);
+ }
+ }
+ if (_inet_ntop_native(sa->sa_family, addr,
+ host, hostlen) == NULL)
+ return (EAI_SYSTEM);
+ }
+ }
+
+ /*
+ * Check for a non-zero sin6_scope_id, indicating a
+ * zone-id needs to be appended to the resultant 'host'
+ * string.
+ */
+ if ((sa->sa_family == AF_INET6) &&
+ (sa2sin6(sa)->sin6_scope_id != 0)) {
+ /*
+ * According to draft-ietf-ipngwg-scoping-arch-XX, only
+ * non-global scope addresses can make use of the
+ * <addr>%<zoneid> format. This implemenation
+ * supports only link scope addresses, since the use of
+ * site-local addressing is not yet fully specified.
+ * If the address meets this criteria, attempt to add a
+ * zone-id to 'host'. If it does not, return
+ * EAI_NONAME.
+ */
+ if (IN6_IS_ADDR_LINKSCOPE(&(sa2sin6(sa)->sin6_addr))) {
+ if ((err = addzoneid(sa2sin6(sa), host,
+ hostlen)) != 0) {
+ return (err);
+ }
+ } else {
+ return (EAI_NONAME);
+ }
+ }
+ }
+ /*
+ * Case 2: if Caller sets servlen != 0, then
+ * fill in "serv" buffer that user passed in
+ * with appropriate text string.
+ */
+ if (servlen != 0) {
+ char port_buf[10];
+ int portlen;
+
+ if (flags & NI_NUMERICSERV) {
+ /* Caller wants the textual form of the port number */
+ portlen = snprintf(port_buf, sizeof (port_buf), "%hu",
+ ntohs(port));
+ if (servlen < portlen + 1)
+ return (EAI_OVERFLOW);
+ (void) strcpy(serv, port_buf);
+ } else {
+ struct servent *sp;
+ /*
+ * Caller wants the name of the service.
+ * If NI_DGRAM is set, get service name for
+ * specified port for udp.
+ */
+ sp = getservbyport(port,
+ flags & NI_DGRAM ? "udp" : "tcp");
+ if (sp != NULL) {
+ if (servlen < strlen(sp->s_name) + 1)
+ return (EAI_OVERFLOW);
+ (void) strcpy(serv, sp->s_name);
+ } else {
+ /*
+ * if service is not in the name server's
+ * database, fill buffer with numeric form for
+ * port number.
+ */
+ portlen = snprintf(port_buf, sizeof (port_buf),
+ "%hu", ntohs(port));
+ if (servlen < portlen + 1)
+ return (EAI_OVERFLOW);
+ (void) strcpy(serv, port_buf);
+ }
+ }
+ }
+ return (0);
+}
+
+/*
+ * addzoneid(sa, host, hostlen)
+ *
+ * Appends a zone-id to the input 'host' string if the input sin6_scope_id
+ * is non-zero. The resultant 'host' string would be of the form
+ * 'host'%'zone-id'. Where 'zone-id' can be either an interface name or a
+ * literal interface index.
+ *
+ * Return Values:
+ * 0 - on success
+ * EAI_MEMORY - an error occured when forming the output string
+ */
+static int
+addzoneid(const struct sockaddr_in6 *sa, char *host, size_t hostlen)
+{
+ char zonestr[LIFNAMSIZ];
+ size_t zonelen;
+ size_t addrlen = strlen(host);
+
+ /* make sure zonelen is valid sizeof (<addr>%<zoneid>\0) */
+ if (((zonelen = getzonestr(sa, zonestr, sizeof (zonestr))) == 0) ||
+ ((addrlen + 1 + zonelen + 1) > hostlen)) {
+ return (EAI_MEMORY);
+ }
+
+ /* Create address string of form <addr>%<zoneid> */
+ host[addrlen] = '%'; /* place address-zoneid delimiter */
+ (void) strlcpy((host + addrlen + 1), zonestr, (zonelen + 1));
+ return (0);
+}
+
+/*
+ * getzonestr(sa, zonestr)
+ *
+ * parse zone string from input sockaddr_in6
+ *
+ * Note: This function calls if_indextoname, a very poor interface,
+ * defined in RFC2553, for converting an interface index to an
+ * interface name. Callers of this function must be sure that
+ * zonestr is atleast LIFNAMSIZ in length, since this is the longest
+ * possible value if_indextoname will return.
+ *
+ * Return values:
+ * 0 an error with calling this function occured
+ * >0 zonestr is filled with a valid zoneid string and the return value is the
+ * length of that string.
+ */
+static size_t
+getzonestr(const struct sockaddr_in6 *sa, char *zonestr, size_t zonelen)
+{
+ const in6_addr_t *addr;
+ uint32_t ifindex;
+ char *retstr;
+
+ if (zonestr == NULL) {
+ return (0);
+ }
+
+ addr = &sa->sin6_addr;
+ /*
+ * Since this implementation only supports link scope addresses,
+ * there is a one-to-one mapping between interface index and
+ * sin6_scope_id.
+ */
+ ifindex = sa->sin6_scope_id;
+
+ if ((retstr = if_indextoname(ifindex, zonestr)) != NULL) {
+ return (strlen(retstr));
+ } else {
+ int n;
+
+ /*
+ * Failed to convert ifindex into an interface name,
+ * simply return the literal value of ifindex as
+ * a string.
+ */
+ if ((n = snprintf(zonestr, zonelen, "%u",
+ ifindex)) < 0) {
+ return (0);
+ } else {
+ if (n >= zonelen) {
+ return (0);
+ }
+ return (n);
+ }
+ }
+}
+
+
+/*
+ * This is a wrapper function for inet_ntop(). In case the af is AF_INET6
+ * and the address pointed by src is a IPv4-mapped IPv6 address, it
+ * returns printable IPv4 address, not IPv4-mapped IPv6 address. In other cases
+ * it behaves just like inet_ntop().
+ */
+static const char *
+_inet_ntop_native(int af, const void *src, char *dst, size_t size)
+{
+ struct in_addr src4;
+ const char *result;
+
+ if (af == AF_INET6) {
+ if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)src)) {
+ IN6_V4MAPPED_TO_INADDR((struct in6_addr *)src, &src4);
+ result = inet_ntop(AF_INET, &src4, dst, size);
+ } else {
+ result = inet_ntop(AF_INET6, src, dst, size);
+ }
+ } else {
+ result = inet_ntop(af, src, dst, size);
+ }
+
+ return (result);
+}
diff --git a/usr/src/lib/libsocket/inet/getnetent.c b/usr/src/lib/libsocket/inet/getnetent.c
new file mode 100644
index 0000000000..194416a36c
--- /dev/null
+++ b/usr/src/lib/libsocket/inet/getnetent.c
@@ -0,0 +1,86 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1986-1992,2001 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <netdb.h>
+#include <nss_dbdefs.h>
+
+
+#ifdef NSS_INCLUDE_UNSAFE
+
+/*
+ * Ye olde non-reentrant interface (MT-unsafe, caveat utor)
+ */
+
+/*
+ * Don't free this, even on an endnetent(), because bitter experience shows
+ * that there's production code that does getXXXbyYYY(), then endXXXent(),
+ * and then continues to use the pointer it got back.
+ */
+static nss_XbyY_buf_t *buffer;
+#define GETBUF() \
+NSS_XbyY_ALLOC(&buffer, (int)sizeof (struct netent), NSS_BUFLEN_NETWORKS)
+ /* === ?? set ENOMEM on failure? */
+
+struct netent *
+getnetbyname(const char *nam)
+{
+ nss_XbyY_buf_t *b;
+ struct netent *res = 0;
+
+ if ((b = GETBUF()) != 0) {
+ res = getnetbyname_r(nam, b->result, b->buffer, b->buflen);
+ }
+ return (res);
+}
+
+struct netent *
+getnetbyaddr(in_addr_t net, int type)
+{
+ nss_XbyY_buf_t *b;
+ struct netent *res = 0;
+
+ if ((b = GETBUF()) != 0) {
+ res = getnetbyaddr_r(net, type, b->result,
+ b->buffer, b->buflen);
+ }
+ return (res);
+}
+
+struct netent *
+getnetent(void)
+{
+ nss_XbyY_buf_t *b;
+ struct netent *res = 0;
+
+ if ((b = GETBUF()) != 0) {
+ res = getnetent_r(b->result, b->buffer, b->buflen);
+ }
+ return (res);
+}
+
+#endif /* NSS_INCLUDE_UNSAFE */
diff --git a/usr/src/lib/libsocket/inet/getnetent_r.c b/usr/src/lib/libsocket/inet/getnetent_r.c
new file mode 100644
index 0000000000..1484809b15
--- /dev/null
+++ b/usr/src/lib/libsocket/inet/getnetent_r.c
@@ -0,0 +1,215 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1986-2002 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <string.h>
+#include <nss_dbdefs.h>
+
+
+static int str2netent(const char *, int, void *, char *, int);
+
+static int net_stayopen;
+/*
+ * Unsynchronized, but it affects only
+ * efficiency, not correctness
+ */
+
+static DEFINE_NSS_DB_ROOT(db_root);
+static DEFINE_NSS_GETENT(context);
+
+static void
+_nss_initf_net(nss_db_params_t *p)
+{
+ p->name = NSS_DBNAM_NETWORKS;
+ p->default_config = NSS_DEFCONF_NETWORKS;
+}
+
+struct netent *
+getnetbyname_r(const char *name, struct netent *result,
+ char *buffer, int buflen)
+{
+ nss_XbyY_args_t arg;
+ nss_status_t res;
+
+ NSS_XbyY_INIT(&arg, result, buffer, buflen, str2netent);
+ arg.key.name = name;
+ arg.stayopen = net_stayopen;
+ res = nss_search(&db_root, _nss_initf_net,
+ NSS_DBOP_NETWORKS_BYNAME, &arg);
+ arg.status = res;
+ (void) NSS_XbyY_FINI(&arg);
+ return ((struct netent *)arg.returnval);
+}
+
+struct netent *
+getnetbyaddr_r(long net, int type, struct netent *result,
+ char *buffer, int buflen)
+{
+ nss_XbyY_args_t arg;
+ nss_status_t res;
+
+ NSS_XbyY_INIT(&arg, result, buffer, buflen, str2netent);
+ arg.key.netaddr.net = (uint32_t)net;
+ arg.key.netaddr.type = type;
+ arg.stayopen = net_stayopen;
+ res = nss_search(&db_root, _nss_initf_net,
+ NSS_DBOP_NETWORKS_BYADDR, &arg);
+ arg.status = res;
+ (void) NSS_XbyY_FINI(&arg);
+ return ((struct netent *)arg.returnval);
+}
+
+int
+setnetent(int stay)
+{
+ net_stayopen |= stay; /* === Or maybe just "=" ? */
+ nss_setent(&db_root, _nss_initf_net, &context);
+ return (0);
+}
+
+int
+endnetent()
+{
+ net_stayopen = 0;
+ nss_endent(&db_root, _nss_initf_net, &context);
+ nss_delete(&db_root);
+ return (0);
+}
+
+struct netent *
+getnetent_r(struct netent *result, char *buffer, int buflen)
+{
+ nss_XbyY_args_t arg;
+ nss_status_t res;
+
+ NSS_XbyY_INIT(&arg, result, buffer, buflen, str2netent);
+ /* No stayopen flag; of course you stay open for iteration */
+ res = nss_getent(&db_root, _nss_initf_net, &context, &arg);
+ arg.status = res;
+ (void) NSS_XbyY_FINI(&arg);
+ return ((struct netent *)arg.returnval);
+}
+
+/*
+ * Return values: 0 = success, 1 = parse error, 2 = erange ...
+ * The structure pointer passed in is a structure in the caller's space
+ * wherein the field pointers would be set to areas in the buffer if
+ * need be. instring and buffer should be separate areas.
+ */
+static int
+str2netent(const char *instr, int lenstr,
+ void *ent /* really (struct netnet *) */, char *buffer, int buflen)
+{
+ struct netent *net = (struct netent *)ent;
+ const char *p, *numstart, *limit, *namestart;
+ int namelen = 0;
+ ptrdiff_t numlen;
+ char numbuf[16];
+
+ if ((instr >= buffer && (buffer + buflen) > instr) ||
+ (buffer >= instr && (instr + lenstr) > buffer)) {
+ return (NSS_STR_PARSE_PARSE);
+ }
+
+ p = instr;
+ limit = p + lenstr;
+
+ while (p < limit && isspace(*p)) {
+ p++;
+ }
+ namestart = p;
+ while (p < limit && !isspace(*p)) {
+ p++; /* Skip over the canonical name */
+ }
+ namelen = (int)(p - namestart);
+
+ if (buflen <= namelen) { /* not enough buffer */
+ return (NSS_STR_PARSE_ERANGE);
+ }
+ (void) memcpy(buffer, namestart, namelen);
+ buffer[namelen] = '\0';
+ net->n_name = buffer;
+
+ while (p < limit && isspace(*p)) {
+ p++;
+ }
+ if (p >= limit) {
+ /* Syntax error -- no net number */
+ return (NSS_STR_PARSE_PARSE);
+ }
+ numstart = p;
+ do {
+ p++; /* Find the end of the net number */
+ } while (p < limit && !isspace(*p));
+ numlen = p - numstart;
+ if (numlen >= (ptrdiff_t)sizeof (numbuf)) {
+ /* Syntax error -- supposed number is too long */
+ return (NSS_STR_PARSE_PARSE);
+ }
+ (void) memcpy(numbuf, numstart, numlen);
+ numbuf[numlen] = '\0';
+ net->n_net = inet_network(numbuf);
+ if (net->n_net == (in_addr_t)-1) {
+ /* inet_network failed to parse the string */
+ return (NSS_STR_PARSE_PARSE);
+ }
+
+ net->n_addrtype = AF_INET;
+
+ while (p < limit && isspace(*p)) {
+ p++;
+ }
+ /*
+ * Although nss_files_XY_all calls us with # stripped,
+ * we should be able to deal with it here in order to
+ * be more useful.
+ */
+ if (p >= limit || *p == '#') { /* no aliases, no problem */
+ char **ptr;
+
+ ptr = (char **)ROUND_UP(buffer + namelen + 1,
+ sizeof (char *));
+ if ((char *)ptr >= buffer + buflen) {
+ net->n_aliases = 0; /* hope they don't try to peek in */
+ return (NSS_STR_PARSE_ERANGE);
+ } else {
+ *ptr = 0;
+ net->n_aliases = ptr;
+ return (NSS_STR_PARSE_SUCCESS);
+ }
+ }
+ net->n_aliases = _nss_netdb_aliases(p, lenstr - (int)(p - instr),
+ buffer + namelen + 1, buflen - namelen - 1);
+ return (NSS_STR_PARSE_SUCCESS);
+}
diff --git a/usr/src/lib/libsocket/inet/getprotoent.c b/usr/src/lib/libsocket/inet/getprotoent.c
new file mode 100644
index 0000000000..c19398e963
--- /dev/null
+++ b/usr/src/lib/libsocket/inet/getprotoent.c
@@ -0,0 +1,86 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1986-1992,2001 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <netdb.h>
+#include <nss_dbdefs.h>
+
+
+#ifdef NSS_INCLUDE_UNSAFE
+
+/*
+ * Ye olde non-reentrant interface (MT-unsafe, caveat utor)
+ */
+
+/*
+ * Don't free this, even on an endprotoent(), because bitter experience shows
+ * that there's production code that does getXXXbyYYY(), then endXXXent(),
+ * and then continues to use the pointer it got back.
+ */
+static nss_XbyY_buf_t *buffer;
+#define GETBUF() \
+NSS_XbyY_ALLOC(&buffer, (int)sizeof (struct protoent), NSS_BUFLEN_PROTOCOLS)
+ /* === ?? set ENOMEM on failure? */
+
+struct protoent *
+getprotobyname(const char *nam)
+{
+ nss_XbyY_buf_t *b;
+ struct protoent *res = 0;
+
+ if ((b = GETBUF()) != 0) {
+ res = getprotobyname_r(nam, b->result, b->buffer, b->buflen);
+ }
+ return (res);
+}
+
+struct protoent *
+getprotobynumber(int proto)
+{
+ nss_XbyY_buf_t *b;
+ struct protoent *res = 0;
+
+ if ((b = GETBUF()) != 0) {
+ res = getprotobynumber_r(proto, b->result,
+ b->buffer, b->buflen);
+ }
+ return (res);
+}
+
+struct protoent *
+getprotoent()
+{
+ nss_XbyY_buf_t *b;
+ struct protoent *res = 0;
+
+ if ((b = GETBUF()) != 0) {
+ res = getprotoent_r(b->result, b->buffer, b->buflen);
+ }
+ return (res);
+}
+
+#endif /* NSS_INCLUDE_UNSAFE */
diff --git a/usr/src/lib/libsocket/inet/getprotoent_r.c b/usr/src/lib/libsocket/inet/getprotoent_r.c
new file mode 100644
index 0000000000..e1cb1c7f0b
--- /dev/null
+++ b/usr/src/lib/libsocket/inet/getprotoent_r.c
@@ -0,0 +1,209 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1986-1992 by Sun Microsystems Inc.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <ctype.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <string.h>
+#include <nss_dbdefs.h>
+
+static int str2protoent(const char *, int, void *,
+ char *, int);
+
+static int proto_stayopen;
+/*
+ * Unsynchronized, but it affects only
+ * efficiency, not correctness
+ */
+
+static DEFINE_NSS_DB_ROOT(db_root);
+static DEFINE_NSS_GETENT(context);
+
+static void
+_nss_initf_proto(nss_db_params_t *p)
+{
+ p->name = NSS_DBNAM_PROTOCOLS;
+ p->default_config = NSS_DEFCONF_PROTOCOLS;
+}
+
+struct protoent *
+getprotobyname_r(const char *name, struct protoent *result,
+ char *buffer, int buflen)
+{
+ nss_XbyY_args_t arg;
+ nss_status_t res;
+
+ NSS_XbyY_INIT(&arg, result, buffer, buflen, str2protoent);
+ arg.key.name = name;
+ arg.stayopen = proto_stayopen;
+ res = nss_search(&db_root, _nss_initf_proto,
+ NSS_DBOP_PROTOCOLS_BYNAME, &arg);
+ arg.status = res;
+ (void) NSS_XbyY_FINI(&arg);
+ return ((struct protoent *)arg.returnval);
+}
+
+struct protoent *
+getprotobynumber_r(int proto, struct protoent *result, char *buffer, int buflen)
+{
+ nss_XbyY_args_t arg;
+ nss_status_t res;
+
+ NSS_XbyY_INIT(&arg, result, buffer, buflen, str2protoent);
+ arg.key.number = proto;
+ arg.stayopen = proto_stayopen;
+ res = nss_search(&db_root, _nss_initf_proto,
+ NSS_DBOP_PROTOCOLS_BYNUMBER, &arg);
+ arg.status = res;
+ (void) NSS_XbyY_FINI(&arg);
+ return ((struct protoent *)arg.returnval);
+}
+
+int
+setprotoent(int stay)
+{
+ proto_stayopen = stay;
+ nss_setent(&db_root, _nss_initf_proto, &context);
+ return (0);
+}
+
+int
+endprotoent()
+{
+ proto_stayopen = 0;
+ nss_endent(&db_root, _nss_initf_proto, &context);
+ nss_delete(&db_root);
+ return (0);
+}
+
+struct protoent *
+getprotoent_r(struct protoent *result, char *buffer, int buflen)
+{
+ nss_XbyY_args_t arg;
+ nss_status_t res;
+
+ NSS_XbyY_INIT(&arg, result, buffer, buflen, str2protoent);
+ /* No stayopen flag; of course you stay open for iteration */
+ res = nss_getent(&db_root, _nss_initf_proto, &context, &arg);
+ arg.status = res;
+ (void) NSS_XbyY_FINI(&arg);
+ return ((struct protoent *)arg.returnval);
+}
+
+/*
+ * Return values: 0 = success, 1 = parse error, 2 = erange ...
+ * The structure pointer passed in is a structure in the caller's space
+ * wherein the field pointers would be set to areas in the buffer if
+ * need be. instring and buffer should be separate areas. Let's not
+ * fight over crumbs.
+ */
+static int
+str2protoent(const char *instr, int lenstr,
+ void *ent /* it is really (struct protoent *) */,
+ char *buffer, int buflen)
+{
+ struct protoent *proto = (struct protoent *)ent;
+ const char *p, *numstart, *namestart, *limit;
+ int numlen, namelen = 0;
+ char numbuf[16];
+ char *numend;
+
+ if ((instr >= buffer && (buffer + buflen) > instr) ||
+ (buffer >= instr && (instr + lenstr) > buffer)) {
+ return (NSS_STR_PARSE_PARSE);
+ }
+
+ p = instr;
+ limit = p + lenstr;
+
+ while (p < limit && isspace(*p)) {
+ p++;
+ }
+ namestart = p;
+ while (p < limit && !isspace(*p)) {
+ p++; /* Skip over the canonical name */
+ }
+ namelen = (int)(p - namestart);
+
+ if (buflen <= namelen) { /* not enough buffer */
+ return (NSS_STR_PARSE_ERANGE);
+ }
+ (void) memcpy(buffer, namestart, namelen);
+ buffer[namelen] = '\0';
+ proto->p_name = buffer;
+
+ while (p < limit && isspace(*p)) {
+ p++;
+ }
+ if (p >= limit) {
+ /* Syntax error -- no proto number */
+ return (NSS_STR_PARSE_PARSE);
+ }
+ numstart = p;
+ do {
+ p++; /* Find the end of the proto number */
+ } while (p < limit && !isspace(*p));
+ numlen = (int)(p - numstart);
+ if (numlen >= (int)sizeof (numbuf)) {
+ /* Syntax error -- supposed number is too long */
+ return (NSS_STR_PARSE_PARSE);
+ }
+ (void) memcpy(numbuf, numstart, (size_t)numlen);
+ numbuf[numlen] = '\0';
+ proto->p_proto = (int)strtol(numbuf, &numend, 10);
+ if (*numend != '\0') {
+ /* Syntax error -- protocol number isn't a number */
+ return (NSS_STR_PARSE_PARSE);
+ }
+
+ while (p < limit && isspace(*p)) {
+ p++;
+ }
+ /*
+ * Although nss_files_XY_all calls us with # stripped,
+ * we should be able to deal with it here in order to
+ * be more useful.
+ */
+ if (p >= limit || *p == '#') { /* no aliases, no problem */
+ char **ptr;
+
+ ptr = (char **)ROUND_UP(buffer + namelen + 1,
+ sizeof (char *));
+ if ((char *)ptr >= buffer + buflen) {
+ /* hope they don't try to peek in */
+ proto->p_aliases = 0;
+ return (NSS_STR_PARSE_ERANGE);
+ } else {
+ *ptr = 0;
+ proto->p_aliases = ptr;
+ return (NSS_STR_PARSE_SUCCESS);
+ }
+ }
+ proto->p_aliases = _nss_netdb_aliases(p, lenstr - (int)(p - instr),
+ buffer + namelen + 1, buflen - namelen - 1);
+ return (NSS_STR_PARSE_SUCCESS);
+}
diff --git a/usr/src/lib/libsocket/inet/getservbyname_r.c b/usr/src/lib/libsocket/inet/getservbyname_r.c
new file mode 100644
index 0000000000..4af830e51d
--- /dev/null
+++ b/usr/src/lib/libsocket/inet/getservbyname_r.c
@@ -0,0 +1,124 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1991-1994 Sun Microsystems, Inc
+ *
+ * lib/libsocket/inet/getservbyname_r.c
+ *
+ * getservbyname_r() is defined in this file. It is implemented on top of
+ * _get_hostserv_inetnetdir_byname() which is also used to implement
+ * netdir_getbyname() for inet family transports. In turn the common code
+ * uses the name service switch policy for "hosts" and "services" unless
+ * the administrator chooses to bypass the name service switch by
+ * specifying third-party supplied nametoaddr libs for inet transports
+ * in /etc/netconfig.
+ *
+ * getservbyport_r() is similarly related to _get_hostserv_inetnetdir_byaddr()
+ * and netdir_getbyaddr();
+ *
+ * The common code lives in lib/libnsl/nss/netdir_inet.c.
+ *
+ * getservent_r(), setservent() and endservent() are *not* implemented on top
+ * of the common interface; they go straight to the switch and are
+ * defined in getservent_r.c.
+ *
+ * There is absolutely no data sharing, not even the stayopen flag or
+ * enumeration state, between getservbyYY_r() and getservent_r();
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <netdb.h>
+#include <netdir.h>
+#include <sys/types.h>
+#include <nss_netdir.h>
+
+extern int str2servent(const char *, int, void *, char *, int);
+extern struct netconfig *__rpc_getconfip();
+
+struct servent *
+getservbyname_r(const char *name, const char *proto, struct servent *result,
+ char *buffer, int buflen)
+{
+ struct netconfig *nconf;
+ struct nss_netdirbyname_in nssin;
+ union nss_netdirbyname_out nssout;
+ int neterr;
+
+ if ((nconf = __rpc_getconfip("udp")) == NULL &&
+ (nconf = __rpc_getconfip("tcp")) == NULL) {
+ return ((struct servent *)NULL);
+ }
+ nssin.op_t = NSS_SERV;
+ nssin.arg.nss.serv.name = name;
+ nssin.arg.nss.serv.proto = proto;
+ nssin.arg.nss.serv.buf = buffer;
+ nssin.arg.nss.serv.buflen = buflen;
+
+ nssout.nss.serv = result;
+
+ /*
+ * We pass in nconf and let the implementation of the long-named func
+ * decide whether to use the switch based on nc_nlookups.
+ */
+ neterr = _get_hostserv_inetnetdir_byname(nconf, &nssin, &nssout);
+
+ (void) freenetconfigent(nconf);
+ if (neterr != ND_OK) {
+ return ((struct servent *)NULL);
+ }
+ return (nssout.nss.serv);
+}
+
+struct servent *
+getservbyport_r(int port, const char *proto, struct servent *result,
+ char *buffer, int buflen)
+{
+ struct netconfig *nconf;
+ struct nss_netdirbyaddr_in nssin;
+ union nss_netdirbyaddr_out nssout;
+ int neterr;
+
+ if ((nconf = __rpc_getconfip("udp")) == NULL &&
+ (nconf = __rpc_getconfip("tcp")) == NULL) {
+ return ((struct servent *)NULL);
+ }
+ nssin.op_t = NSS_SERV;
+ nssin.arg.nss.serv.port = port;
+ nssin.arg.nss.serv.proto = proto;
+ nssin.arg.nss.serv.buf = buffer;
+ nssin.arg.nss.serv.buflen = buflen;
+
+ nssout.nss.serv = result;
+
+ /*
+ * We pass in nconf and let the implementation of this long-named func
+ * decide whether to use the switch based on nc_nlookups.
+ */
+ neterr = _get_hostserv_inetnetdir_byaddr(nconf, &nssin, &nssout);
+
+ (void) freenetconfigent(nconf);
+ if (neterr != ND_OK) {
+ return ((struct servent *)NULL);
+ }
+ return (nssout.nss.serv);
+}
diff --git a/usr/src/lib/libsocket/inet/getservent.c b/usr/src/lib/libsocket/inet/getservent.c
new file mode 100644
index 0000000000..9dfb4215a8
--- /dev/null
+++ b/usr/src/lib/libsocket/inet/getservent.c
@@ -0,0 +1,86 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1986-1994,2001 by Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Ye olde non-reentrant interface (MT-unsafe, caveat utor)
+ *
+ * lib/libsocket/inet/getservent.c
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <netdb.h>
+#include <nss_dbdefs.h>
+
+#ifdef NSS_INCLUDE_UNSAFE
+
+/*
+ * Don't free this, even on an endservent(), because bitter experience shows
+ * that there's production code that does getXXXbyYYY(), then endXXXent(),
+ * and then continues to use the pointer it got back.
+ */
+static nss_XbyY_buf_t *buffer;
+#define GETBUF() \
+NSS_XbyY_ALLOC(&buffer, (int)sizeof (struct servent), NSS_BUFLEN_SERVICES)
+ /* === ?? set ENOMEM on failure? */
+
+struct servent *
+getservbyname(const char *nam, const char *proto)
+{
+ nss_XbyY_buf_t *b;
+ struct servent *res = 0;
+
+ if ((b = GETBUF()) != 0) {
+ res = getservbyname_r(nam, proto,
+ b->result, b->buffer, b->buflen);
+ }
+ return (res);
+}
+
+struct servent *
+getservbyport(int port, const char *proto)
+{
+ nss_XbyY_buf_t *b;
+ struct servent *res = 0;
+
+ if ((b = GETBUF()) != 0) {
+ res = getservbyport_r(port, proto,
+ b->result, b->buffer, b->buflen);
+ }
+ return (res);
+}
+
+struct servent *
+getservent(void)
+{
+ nss_XbyY_buf_t *b;
+ struct servent *res = 0;
+
+ if ((b = GETBUF()) != 0) {
+ res = getservent_r(b->result, b->buffer, b->buflen);
+ }
+ return (res);
+}
+
+#endif /* NSS_INCLUDE_UNSAFE */
diff --git a/usr/src/lib/libsocket/inet/getservent_r.c b/usr/src/lib/libsocket/inet/getservent_r.c
new file mode 100644
index 0000000000..6eb9ff49a2
--- /dev/null
+++ b/usr/src/lib/libsocket/inet/getservent_r.c
@@ -0,0 +1,100 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1986-1994 by Sun Microsystems Inc.
+ *
+ * lib/libsocket/inet/getservent_r.c
+ *
+ * This file defines and implements the re-entrant enumeration routines for
+ * services: setservent(), getservent_r(), and endservent(). They consult
+ * the switch policy directly and do not "share" their enumeration state
+ * nor the stayopen flag with the implentation of the more common
+ * getservbyname_r()/getservbyport_r(). The latter follows a tortuous
+ * route in order to be consistent with netdir_getbyYY() (see
+ * getservbyname_r.c and lib/libnsl/nss/netdir_inet.c).
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <nss_dbdefs.h>
+
+/*
+ * str2servent is implemented in libnsl, libnsl/nss/netdir_inet.c, since
+ * the "engine" of the new gethost/getserv/netdir lives in libnsl.
+ */
+int str2servent(const char *, int, void *, char *, int);
+
+/*
+ * Unsynchronized, but it affects only
+ * efficiency, not correctness.
+ */
+static int services_stayopen;
+static DEFINE_NSS_DB_ROOT(db_root);
+static DEFINE_NSS_GETENT(context);
+
+static void
+_nss_initf_services(nss_db_params_t *p)
+{
+ p->name = NSS_DBNAM_SERVICES;
+ p->default_config = NSS_DEFCONF_SERVICES;
+}
+
+int
+setservent(int stay)
+{
+ services_stayopen |= stay;
+ nss_setent(&db_root, _nss_initf_services, &context);
+ return (0);
+}
+
+int
+endservent()
+{
+ services_stayopen = 0;
+ nss_endent(&db_root, _nss_initf_services, &context);
+ nss_delete(&db_root);
+ return (0);
+}
+
+struct servent *
+getservent_r(struct servent *result, char *buffer, int buflen)
+{
+ nss_XbyY_args_t arg;
+ nss_status_t res;
+
+ NSS_XbyY_INIT(&arg, result, buffer, buflen, str2servent);
+ /*
+ * Setting proto to NULL here is a bit of a hack since we share
+ * the parsing code in the NIS+ backend with our getservbyYY()
+ * brethren who can search on 1-1/2 key. If they pass a NULL
+ * proto, the parsing code deals with it by picking the protocol
+ * from the first NIS+ matching object and combining all entries
+ * with "that" proto field. NIS+ is the only name service, so far,
+ * that can return multiple entries on a lookup.
+ */
+ arg.key.serv.proto = NULL;
+ /* === No stayopen flag; of course you stay open for iteration */
+ res = nss_getent(&db_root, _nss_initf_services, &context, &arg);
+ arg.status = res;
+ return (struct servent *)NSS_XbyY_FINI(&arg);
+}
diff --git a/usr/src/lib/libsocket/inet/inet6_opt.c b/usr/src/lib/libsocket/inet/inet6_opt.c
new file mode 100644
index 0000000000..42b923c5b3
--- /dev/null
+++ b/usr/src/lib/libsocket/inet/inet6_opt.c
@@ -0,0 +1,300 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This code is conformant to RFC 3542.
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/sysmacros.h>
+#include <netinet/in.h>
+#include <netinet/ip6.h>
+
+#include <stdio.h>
+
+#define bufpos(p) ((p) - (uint8_t *)extbuf)
+
+/*
+ * Section 10.1 RFC3542. This function returns the size of the empty
+ * extension header. If extbuf is not NULL then it initializes its length
+ * field. If extlen is invalid then -1 is returned.
+ */
+int
+inet6_opt_init(void *extbuf, socklen_t extlen)
+{
+ if (extbuf && ((extlen < 0) || (extlen % 8))) {
+ return (-1);
+ }
+
+ if (extbuf) {
+ *(uint8_t *)extbuf = 0;
+ *((uint8_t *)extbuf + 1) = extlen/8 - 1;
+ }
+
+ return (2);
+}
+
+/*
+ * Section 10.2 RFC3542. This function appends an option to an already
+ * initialized option buffer. inet6_opt_append() returns the total length
+ * after adding the option.
+ */
+int
+inet6_opt_append(void *extbuf, socklen_t extlen, int offset, uint8_t type,
+ socklen_t len, uint_t align, void **databufp)
+{
+ uint8_t *p;
+ socklen_t endlen;
+ int remainder, padbytes;
+
+ if (align > len ||
+ (align != 1 && align != 2 && align != 4 && align != 8) ||
+ len < 0 || len > 255 || type < 2) {
+ return (-1);
+ }
+
+ if (extbuf) {
+ /*
+ * The length of the buffer is the minimum of the length
+ * passed in and the length stamped onto the buffer. The
+ * length stamped onto the buffer is the number of 8 byte
+ * octets in the buffer minus 1.
+ */
+ extlen = MIN(extlen, (*((uint8_t *)extbuf + 1) + 1) * 8);
+ }
+
+ remainder = (offset + 2 + len) % align;
+ if (remainder == 0) {
+ padbytes = 0;
+ } else {
+ padbytes = align - remainder;
+ }
+
+ endlen = offset + padbytes + 2 + len;
+ if ((endlen > extlen) || !extbuf) {
+ if (extbuf) {
+ return (-1);
+ } else {
+ return (endlen);
+ }
+ }
+
+ p = (uint8_t *)extbuf + offset;
+ if (padbytes != 0) {
+ /*
+ * Pad out the buffer here with pad options. If its only
+ * one byte then there is a special TLV with no L or V, just
+ * a zero to say skip this byte. For two bytes or more
+ * we have a special TLV with type 0 and length the number of
+ * padbytes.
+ */
+ if (padbytes == 1) {
+ *p = IP6OPT_PAD1;
+ } else {
+ *p = IP6OPT_PADN;
+ *(p + 1) = padbytes - 2;
+ memset(p + 2, 0, padbytes - 2);
+ }
+ p += padbytes;
+ }
+
+ *p++ = type;
+ *p++ = len;
+ if (databufp) {
+ *databufp = p;
+ }
+ return (endlen);
+}
+
+/*
+ * Section 10.3 RFC3542. This function returns the updated total length.
+ * This functions inserts pad options to complete the option header as
+ * needed.
+ */
+int
+inet6_opt_finish(void *extbuf, socklen_t extlen, int offset)
+{
+ uint8_t *p;
+ int padbytes;
+
+ if (extbuf) {
+ /*
+ * The length of the buffer is the minimum of the length
+ * passed in and the length stamped onto the buffer. The
+ * length stamped onto the buffer is the number of 8 byte
+ * octets in the buffer minus 1.
+ */
+ extlen = MIN(extlen, (*((uint8_t *)extbuf + 1) + 1) * 8);
+ }
+
+ padbytes = 8 - (offset % 8);
+ if (padbytes == 8)
+ padbytes = 0;
+
+ if ((offset + padbytes > extlen) || !extbuf) {
+ if (extbuf) {
+ return (-1);
+ } else {
+ return (offset + padbytes);
+ }
+ }
+
+ p = (uint8_t *)extbuf + offset;
+ if (padbytes != 0) {
+ /*
+ * Pad out the buffer here with pad options. If its only
+ * one byte then there is a special TLV with no L or V, just
+ * a zero to say skip this byte. For two bytes or more
+ * we have a special TLV with type 0 and length the number of
+ * padbytes.
+ */
+ if (padbytes == 1) {
+ *p = IP6OPT_PAD1;
+ } else {
+ *p = IP6OPT_PADN;
+ *(p + 1) = padbytes - 2;
+ memset(p + 2, 0, padbytes - 2);
+ }
+ p += padbytes;
+ }
+
+ return (offset + padbytes);
+}
+
+/*
+ * Section 10.4 RFC3542. Ths function takes a pointer to the data as
+ * returned by inet6_opt_append and inserts the data.
+ */
+int
+inet6_opt_set_val(void *databuf, int offset, void *val, socklen_t vallen)
+{
+ memcpy((uint8_t *)databuf + offset, val, vallen);
+ return (offset + vallen);
+}
+
+/*
+ * Section 10.5 RFC 3542. Starting walking the option header offset into the
+ * header. Returns where we left off. You take the output of this function
+ * and pass it back in as offset to iterate. -1 is returned on error.
+ *
+ * We use the fact that the first unsigned 8 bit quantity in the option
+ * header is the type and the second is the length.
+ */
+int
+inet6_opt_next(void *extbuf, socklen_t extlen, int offset, uint8_t *typep,
+ socklen_t *lenp, void **databufp)
+{
+ uint8_t *p;
+ uint8_t *end;
+
+ /*
+ * The length of the buffer is the minimum of the length
+ * passed in and the length stamped onto the buffer. The
+ * length stamped onto the buffer is the number of 8 byte
+ * octets in the buffer minus 1.
+ */
+ extlen = MIN(extlen, (*((uint8_t *)extbuf + 1) + 1) * 8);
+ end = (uint8_t *)extbuf + extlen;
+ if (offset == 0) {
+ offset = 2;
+ }
+
+ /* assumption: IP6OPT_PAD1 == 0 and IP6OPT_PADN == 1 */
+ p = (uint8_t *)extbuf + offset;
+ while (*p == IP6OPT_PAD1 || *p == IP6OPT_PADN) {
+ switch (*p) {
+ case IP6OPT_PAD1:
+ p++;
+ break;
+ case IP6OPT_PADN:
+ /* *(p + 1) is the length of the option. */
+ if (p + 2 + *(p + 1) >= end)
+ return (-1);
+ p += *(p + 1) + 2;
+ break;
+ }
+ }
+
+ /* type, len, and data must fit... */
+ if ((p + 2 >= end) || (p + 2 + *(p + 1) > end)) {
+ return (-1);
+ }
+
+ if (typep) {
+ *typep = *p;
+ }
+ if (lenp) {
+ *lenp = *(p + 1);
+ }
+ if (databufp) {
+ *databufp = p + 2;
+ }
+
+ return ((p - (uint8_t *)extbuf) + 2 + *lenp);
+}
+
+/*
+ * Section 10.6 RFC 3542. Starting walking the option header offset into the
+ * header. Returns where we left off. You take the output of this function
+ * and pass it back in as offset to iterate. -1 is returned on error.
+ *
+ * We use the fact that the first unsigned 8 bit quantity in the option
+ * header is the type and the second is the length.
+ */
+int
+inet6_opt_find(void *extbuf, socklen_t extlen, int offset, uint8_t type,
+ socklen_t *lenp, void **databufp)
+{
+ uint8_t newtype;
+
+ do {
+ offset = inet6_opt_next(extbuf, extlen, offset, &newtype, lenp,
+ databufp);
+
+ if (offset == -1)
+ return (-1);
+ } while (newtype != type);
+
+ /* value to feed back into inet6_opt_find() as offset */
+ return (offset);
+}
+
+/*
+ * Section 10.7 RFC 3542. databuf should be a pointer as returned by
+ * inet6_opt_next or inet6_opt_find. The data is extracted from the option
+ * at that point.
+ */
+int
+inet6_opt_get_val(void *databuf, int offset, void *val, socklen_t vallen)
+{
+ memcpy(val, (uint8_t *)databuf + offset, vallen);
+ return (offset + vallen);
+}
diff --git a/usr/src/lib/libsocket/inet/inet6_rthdr.c b/usr/src/lib/libsocket/inet/inet6_rthdr.c
new file mode 100644
index 0000000000..4134f8a196
--- /dev/null
+++ b/usr/src/lib/libsocket/inet/inet6_rthdr.c
@@ -0,0 +1,180 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2003 Sun Microsystems, Inc.
+ * All rights reserved. Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This code is conformant to revision 7 of 2292bis. Some of these functions
+ * were provided (named inet6_rthdr_) in a very similar form in RFC 2292.
+ * The RFC 2292 variants are not supported.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/ip6.h>
+#include <unistd.h>
+#include <errno.h>
+
+#define MAX_RTHDR0_SEGMENTS 127
+
+/*
+ * Return amount of space needed to hold N segments for the specified
+ * routing type. Does NOT include space for cmsghdr.
+ */
+socklen_t
+inet6_rth_space(int type, int segments)
+{
+ if (type != IPV6_RTHDR_TYPE_0 || segments < 0 ||
+ segments > MAX_RTHDR0_SEGMENTS)
+ return (0);
+
+ return (sizeof (struct ip6_rthdr0) +
+ segments * sizeof (struct in6_addr));
+}
+
+/*
+ * Initializes rthdr structure. Verifies the segments against the length of
+ * the buffer.
+ * Note that a routing header can only hold 127 segments since the length field
+ * in the header is just a byte.
+ */
+void *
+inet6_rth_init(void *bp, socklen_t bp_len, int type, int segments)
+{
+ struct ip6_rthdr0 *rthdr;
+
+ if (type != IPV6_RTHDR_TYPE_0 || segments < 0 ||
+ segments > MAX_RTHDR0_SEGMENTS)
+ return (NULL);
+
+ if (bp_len < sizeof (struct ip6_rthdr0) +
+ segments * sizeof (struct in6_addr))
+ return (NULL);
+
+ rthdr = (struct ip6_rthdr0 *)bp;
+ rthdr->ip6r0_nxt = 0;
+ rthdr->ip6r0_len = (segments * 2);
+ rthdr->ip6r0_type = type;
+ rthdr->ip6r0_segleft = 0; /* Incremented by rthdr_add */
+ *(uint32_t *)&rthdr->ip6r0_reserved = 0;
+ return (bp);
+}
+
+/*
+ * Add one more address to the routing header. Fails when there is no more
+ * room.
+ */
+int
+inet6_rth_add(void *bp, const struct in6_addr *addr)
+{
+ struct ip6_rthdr0 *rthdr;
+ struct in6_addr *addrs;
+
+ rthdr = (struct ip6_rthdr0 *)bp;
+ if ((rthdr->ip6r0_segleft + 1) * 2 > rthdr->ip6r0_len) {
+ /* Not room for one more */
+ return (-1);
+ }
+ addrs = (struct in6_addr *)((char *)rthdr + sizeof (*rthdr));
+ addrs[rthdr->ip6r0_segleft++] = *addr;
+ return (0);
+}
+
+/*
+ * Reverse a source route. Both arguments can point to the same buffer.
+ */
+int
+inet6_rth_reverse(const void *in, void *out)
+{
+ struct ip6_rthdr0 *rtin, *rtout;
+ int i, segments;
+ struct in6_addr tmp;
+ struct in6_addr *rtout_addrs;
+ struct in6_addr *rtin_addrs;
+
+ rtin = (struct ip6_rthdr0 *)in;
+ rtout = (struct ip6_rthdr0 *)out;
+
+ if (rtout->ip6r0_type != 0 || rtin->ip6r0_type != 0 ||
+ rtout->ip6r0_len > MAX_RTHDR0_SEGMENTS * 2 ||
+ rtin->ip6r0_len > MAX_RTHDR0_SEGMENTS * 2 ||
+ rtout->ip6r0_len != rtin->ip6r0_len)
+ return (-1);
+
+ segments = rtin->ip6r0_len / 2;
+ rtout_addrs = (struct in6_addr *)((char *)rtout + sizeof (*rtout));
+ rtin_addrs = (struct in6_addr *)((char *)rtin + sizeof (*rtin));
+ for (i = 0; i < (segments + 1)/2; i++) {
+ tmp = rtin_addrs[i];
+ rtout_addrs[i] = rtin_addrs[segments - 1 - i];
+ rtout_addrs[segments - 1 - i] = tmp;
+ }
+ rtout->ip6r0_segleft = segments;
+ return (0);
+}
+
+/*
+ * Return the number of segments in the routing header.
+ */
+int
+inet6_rth_segments(const void *bp)
+{
+ struct ip6_rthdr0 *rthdr;
+
+ rthdr = (struct ip6_rthdr0 *)bp;
+ if (rthdr->ip6r0_type == 0) {
+ if (rthdr->ip6r0_len > MAX_RTHDR0_SEGMENTS * 2) {
+ return (-1);
+ } else {
+ return (rthdr->ip6r0_len / 2);
+ }
+ } else {
+ return (-1);
+ }
+}
+
+/*
+ * Return a pointer to an element in the source route.
+ * This uses the C convention for index [0, size-1].
+ */
+struct in6_addr *
+inet6_rth_getaddr(const void *bp, int index)
+{
+ struct ip6_rthdr0 *rthdr;
+ struct in6_addr *rv;
+
+ rthdr = (struct ip6_rthdr0 *)bp;
+ if (index >= rthdr->ip6r0_len/2 || index < 0)
+ return (NULL);
+
+ rv = (struct in6_addr *)((char *)rthdr + sizeof (*rthdr));
+ return (&rv[index]);
+}
diff --git a/usr/src/lib/libsocket/inet/inet_lnaof.c b/usr/src/lib/libsocket/inet/inet_lnaof.c
new file mode 100644
index 0000000000..eeadb0d6cd
--- /dev/null
+++ b/usr/src/lib/libsocket/inet/inet_lnaof.c
@@ -0,0 +1,61 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1997 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * University Copyright- Copyright (c) 1982, 1986, 1988
+ * The Regents of the University of California
+ * All Rights Reserved
+ *
+ * University Acknowledgment- Portions of this document are derived from
+ * software developed by the University of California, Berkeley, and its
+ * contributors.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <netinet/in.h>
+
+/*
+ * Return the local network address portion of an
+ * internet address; handles class a/b/c network
+ * number formats.
+ */
+int
+inet_lnaof(struct in_addr in)
+{
+ uint32_t i = ntohl(in.s_addr);
+
+ if (IN_CLASSA(i))
+ return ((i)&IN_CLASSA_HOST);
+ else if (IN_CLASSB(i))
+ return ((i)&IN_CLASSB_HOST);
+ else
+ return ((i)&IN_CLASSC_HOST);
+}
diff --git a/usr/src/lib/libsocket/inet/inet_mkaddr.c b/usr/src/lib/libsocket/inet/inet_mkaddr.c
new file mode 100644
index 0000000000..6c0127264d
--- /dev/null
+++ b/usr/src/lib/libsocket/inet/inet_mkaddr.c
@@ -0,0 +1,66 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2001 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * University Copyright- Copyright (c) 1982, 1986, 1988
+ * The Regents of the University of California
+ * All Rights Reserved
+ *
+ * University Acknowledgment- Portions of this document are derived from
+ * software developed by the University of California, Berkeley, and its
+ * contributors.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <netinet/in.h>
+
+/*
+ * Formulate an Internet address from network + host. Used in
+ * building addresses stored in the ifnet structure.
+ */
+struct in_addr
+inet_makeaddr(ipaddr_t net, ipaddr_t host)
+{
+ ipaddr_t addr;
+ struct in_addr inaddr;
+
+ if (net < 128)
+ addr = (net << IN_CLASSA_NSHIFT) | (host & IN_CLASSA_HOST);
+ else if (net < 65536)
+ addr = (net << IN_CLASSB_NSHIFT) | (host & IN_CLASSB_HOST);
+ else if (net < 16777216L)
+ addr = (net << IN_CLASSC_NSHIFT) | (host & IN_CLASSC_HOST);
+ else
+ addr = net | host;
+ addr = htonl(addr);
+ inaddr.s_addr = addr;
+ return (inaddr);
+}
diff --git a/usr/src/lib/libsocket/inet/inet_network.c b/usr/src/lib/libsocket/inet/inet_network.c
new file mode 100644
index 0000000000..b7512dc228
--- /dev/null
+++ b/usr/src/lib/libsocket/inet/inet_network.c
@@ -0,0 +1,99 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2001 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * University Copyright- Copyright (c) 1982, 1986, 1988
+ * The Regents of the University of California
+ * All Rights Reserved
+ *
+ * University Acknowledgment- Portions of this document are derived from
+ * software developed by the University of California, Berkeley, and its
+ * contributors.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <ctype.h>
+#include <netinet/in.h>
+
+/*
+ * Internet network address interpretation routine.
+ * The library routines call this routine to interpret
+ * network numbers.
+ */
+in_addr_t
+inet_network(const char *cp)
+{
+ in_addr_t val;
+ int base;
+ ptrdiff_t n;
+ char c;
+ in_addr_t parts[4], *pp = parts;
+ int i;
+
+again:
+ val = 0; base = 10;
+ if (*cp == '0') {
+ if (*++cp == 'x' || *cp == 'X')
+ base = 16, cp++;
+ else
+ base = 8;
+ }
+ while ((c = *cp) != NULL) {
+ if (isdigit(c)) {
+ if ((c - '0') >= base)
+ break;
+ val = (val * base) + (c - '0');
+ cp++;
+ continue;
+ }
+ if (base == 16 && isxdigit(c)) {
+ val = (val << 4) + (c + 10 - (islower(c) ? 'a' : 'A'));
+ cp++;
+ continue;
+ }
+ break;
+ }
+ if (pp >= parts + 4 || val > 0xff)
+ return ((in_addr_t)-1);
+ *pp++ = val;
+ if (*cp == '.') {
+ cp++;
+ goto again;
+ }
+ if (*cp != '\0' && !isspace(*cp))
+ return ((in_addr_t)-1);
+ n = pp - parts;
+ for (val = 0, i = 0; i < n; i++) {
+ val <<= 8;
+ val |= parts[i];
+ }
+ return (val);
+}
diff --git a/usr/src/lib/libsocket/inet/interface_id.c b/usr/src/lib/libsocket/inet/interface_id.c
new file mode 100644
index 0000000000..2a512b025f
--- /dev/null
+++ b/usr/src/lib/libsocket/inet/interface_id.c
@@ -0,0 +1,355 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <inet/common.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <sys/sockio.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <errno.h>
+
+#define IPIF_SEPARATOR_CHAR ":"
+
+/*
+ * Given an interface name, this function retrives the associated
+ * index value. Returns index value if successful, zero otherwise.
+ * The length of the supplied interface name must be at most
+ * IF_NAMESIZE-1 bytes
+ */
+uint32_t
+if_nametoindex(const char *ifname)
+{
+ int s;
+ struct lifreq lifr;
+ int save_err;
+ size_t size;
+
+
+ /* Make sure the given name is not NULL */
+ if ((ifname == NULL)||(*ifname == '\0')) {
+ errno = ENXIO;
+ return (0);
+ }
+
+ /*
+ * Fill up the interface name in the ioctl
+ * request message. Make sure that the length of
+ * the given interface name <= (IF_NAMESIZE-1)
+ */
+ size = strlen(ifname);
+ if (size > (IF_NAMESIZE - 1)) {
+ errno = EINVAL;
+ return (0);
+ }
+
+ strncpy(lifr.lifr_name, ifname, size +1);
+
+ /* Check the v4 interfaces first */
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s >= 0) {
+ if (ioctl(s, SIOCGLIFINDEX, (caddr_t)&lifr) >= 0) {
+ (void) close(s);
+ return (lifr.lifr_index);
+ }
+ (void) close(s);
+ }
+
+ /* Check the v6 interface list */
+ s = socket(AF_INET6, SOCK_DGRAM, 0);
+ if (s < 0)
+ return (0);
+
+ if (ioctl(s, SIOCGLIFINDEX, (caddr_t)&lifr) < 0)
+ lifr.lifr_index = 0;
+
+ save_err = errno;
+ (void) close(s);
+ errno = save_err;
+ return (lifr.lifr_index);
+}
+
+/*
+ * Given an index, this function returns the associated interface
+ * name in the supplied buffer ifname.
+ * Returns physical interface name if successful, NULL otherwise.
+ * The interface name returned will be at most IF_NAMESIZE-1 bytes.
+ */
+char *
+if_indextoname(uint32_t ifindex, char *ifname)
+{
+ int n;
+ int s;
+ char *buf;
+ uint32_t index;
+ struct lifnum lifn;
+ struct lifconf lifc;
+ struct lifreq *lifrp;
+ int numifs;
+ size_t bufsize;
+ boolean_t found;
+
+ /* A interface index of 0 is invalid */
+ if (ifindex == 0) {
+ errno = ENXIO;
+ return (NULL);
+ }
+
+ s = socket(AF_INET6, SOCK_DGRAM, 0);
+ if (s < 0) {
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ return (NULL);
+ }
+ }
+
+ /* Prepare to send a SIOCGLIFNUM request message */
+ lifn.lifn_family = AF_UNSPEC;
+ lifn.lifn_flags = LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES;
+ if (ioctl(s, SIOCGLIFNUM, (char *)&lifn) < 0) {
+ int save_err = errno;
+ (void) close(s);
+ errno = save_err;
+ return (NULL);
+ }
+ numifs = lifn.lifn_count;
+
+ /*
+ * Provide enough buffer to obtain the interface
+ * list from the kernel as response to a SIOCGLIFCONF
+ * request
+ */
+
+ bufsize = numifs * sizeof (struct lifreq);
+ buf = malloc(bufsize);
+ if (buf == NULL) {
+ int save_err = errno;
+ (void) close(s);
+ errno = save_err;
+ return (NULL);
+ }
+ lifc.lifc_family = AF_UNSPEC;
+ lifc.lifc_flags = LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES;
+ lifc.lifc_len = bufsize;
+ lifc.lifc_buf = buf;
+ if (ioctl(s, SIOCGLIFCONF, (char *)&lifc) < 0) {
+ int save_err = errno;
+ (void) close(s);
+ errno = save_err;
+ free(buf);
+ return (NULL);
+ }
+
+ lifrp = lifc.lifc_req;
+ found = B_FALSE;
+ for (n = lifc.lifc_len / sizeof (struct lifreq); n > 0; n--, lifrp++) {
+ /*
+ * Obtain the index value of each interface, and
+ * match to see if the retrived index value matches
+ * the given one. If so we have return the corresponding
+ * device name of that interface.
+ */
+ size_t size;
+
+ index = if_nametoindex(lifrp->lifr_name);
+ if (index == 0)
+ /* Oops the interface just disappeared */
+ continue;
+ if (index == ifindex) {
+ size = strcspn(lifrp->lifr_name,
+ (char *)IPIF_SEPARATOR_CHAR);
+ lifrp->lifr_name[size] = '\0';
+ found = B_TRUE;
+ (void) strncpy(ifname, lifrp->lifr_name,
+ size + 1);
+ break;
+ }
+ }
+ (void) close(s);
+ free(buf);
+ if (!found) {
+ errno = ENXIO;
+ return (NULL);
+ }
+ return (ifname);
+}
+
+/*
+ * This function returns all the interface names and indexes
+ */
+struct if_nameindex *
+if_nameindex(void)
+{
+ int n;
+ int s;
+ boolean_t found;
+ char *buf;
+ struct lifnum lifn;
+ struct lifconf lifc;
+ struct lifreq *lifrp;
+ int numifs;
+ int index;
+ int i;
+ int physinterf_num;
+ size_t bufsize;
+ struct if_nameindex *interface_list;
+ struct if_nameindex *interface_entry;
+
+ s = socket(AF_INET6, SOCK_DGRAM, 0);
+ if (s < 0) {
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s < 0)
+ return (NULL);
+ }
+
+ lifn.lifn_family = AF_UNSPEC;
+ lifn.lifn_flags = LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES;
+ if (ioctl(s, SIOCGLIFNUM, (char *)&lifn) < 0)
+ return (NULL);
+ numifs = lifn.lifn_count;
+
+ bufsize = numifs * sizeof (struct lifreq);
+ buf = malloc(bufsize);
+ if (buf == NULL) {
+ int save_err = errno;
+ (void) close(s);
+ errno = save_err;
+ return (NULL);
+ }
+ lifc.lifc_family = AF_UNSPEC;
+ lifc.lifc_flags = LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES;
+ lifc.lifc_len = bufsize;
+ lifc.lifc_buf = buf;
+ if (ioctl(s, SIOCGLIFCONF, (char *)&lifc) < 0) {
+ int save_err = errno;
+ (void) close(s);
+ errno = save_err;
+ free(buf);
+ return (NULL);
+ }
+
+ lifrp = lifc.lifc_req;
+ (void) close(s);
+
+ /* Allocate the array of if_nameindex structure */
+ interface_list = malloc((numifs + 1) * sizeof (struct if_nameindex));
+ if (!interface_list) {
+ int save_err = errno;
+ free(buf);
+ errno = save_err;
+ return (NULL);
+ }
+ /*
+ * Make sure that terminator structure automatically
+ * happens to be all zeroes.
+ */
+ bzero(interface_list, ((numifs + 1) * sizeof (struct if_nameindex)));
+ interface_entry = interface_list;
+ physinterf_num = 0;
+ for (n = numifs; n > 0; n--, lifrp++) {
+ size_t size;
+
+ size = strcspn(lifrp->lifr_name, (char *)IPIF_SEPARATOR_CHAR);
+ lifrp->lifr_name[size] = '\0';
+ found = B_FALSE;
+ /*
+ * Search the current array to see if this interface
+ * already exists
+ */
+
+ for (i = 0; i < physinterf_num; i++) {
+ if (strcmp(interface_entry[i].if_name,
+ lifrp->lifr_name) == 0) {
+ found = B_TRUE;
+ break;
+ }
+ }
+
+allocate_new:
+ /* New one. Allocate an array element and fill it */
+ if (!found) {
+ if ((interface_entry[physinterf_num].if_name =
+ strdup(lifrp->lifr_name)) == NULL) {
+ int save_err;
+
+ if_freenameindex(interface_list);
+ save_err = errno;
+ free(buf);
+ errno = save_err;
+ return (NULL);
+ }
+
+ /*
+ * Obtain the index value for the interface
+ */
+ interface_entry[physinterf_num].if_index =
+ if_nametoindex(lifrp->lifr_name);
+ physinterf_num++;
+ }
+ }
+
+ /* Create the last one of the array */
+ interface_entry[physinterf_num].if_name = NULL;
+ interface_entry[physinterf_num].if_index = 0;
+
+ /* Free up the excess array space */
+ free(buf);
+ interface_list = realloc(interface_list, ((physinterf_num + 1) *
+ sizeof (struct if_nameindex)));
+
+ return (interface_list);
+}
+
+/*
+ * This function frees the the array that is created while
+ * the if_nameindex function.
+ */
+void
+if_freenameindex(struct if_nameindex *ptr)
+{
+
+ if (ptr == NULL)
+ return;
+
+
+ /* First free the if_name member in each array element */
+ while (ptr->if_name != NULL) {
+ free(ptr->if_name);
+ ptr++;
+ }
+
+ /* Now free up the array space */
+ free(ptr);
+}
diff --git a/usr/src/lib/libsocket/inet/link_addr.c b/usr/src/lib/libsocket/inet/link_addr.c
new file mode 100644
index 0000000000..36840521ab
--- /dev/null
+++ b/usr/src/lib/libsocket/inet/link_addr.c
@@ -0,0 +1,135 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Function implementations to convert between link layer addresses and
+ * ascii representations of the form "x:x:x:...:x:x:x" where x is a hex
+ * number between 0x00 and 0xff; the bytes are always in network order.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <net/if_dl.h>
+
+/*
+ * Converts a "size" bytes long mac address to its string representation.
+ * Currently, the "mactype" is unused, but in the future, the string
+ * can be modulated by "mactype" (IFT_* value from <net/if_types.h>)
+ */
+/* ARGSUSED */
+char *
+_link_ntoa(const unsigned char *macaddr, char *str, int size, int mactype)
+{
+ char *buf;
+ int i, n;
+
+ if (((buf = str) == NULL) &&
+ ((buf = malloc(3 * size)) == NULL))
+ return (NULL);
+ n = sprintf(buf, "%x", *macaddr++);
+ for (i = 0; i < (size - 1); i++)
+ n += sprintf(buf+n, ":%x", *macaddr++);
+ return (buf);
+}
+
+/*
+ * Converts a string possibly representing a link address into its
+ * bit format, returning length of the address in bytes.
+ */
+uchar_t *
+_link_aton(const char *ascaddr, int *maclen)
+{
+ unsigned char cval, num = 0;
+ int idx = 0, numcolons = 0, digits = 0;
+ uchar_t *netaddr;
+ const char *cptr;
+ char lastc = ':';
+
+ while (isspace(*ascaddr))
+ ascaddr++;
+
+ /*
+ * Find how many :'s in the string. Also sanity check
+ * the string for valid hex chars, absence of white
+ * spaces, not starting or ending with :, absence of
+ * consecutive :'s, excessive digits per element
+ * and non-null string.
+ */
+ cptr = ascaddr;
+ while ((cval = *cptr++) != '\0') {
+ if (cval == ':') {
+ if (lastc == ':')
+ break;
+ numcolons++;
+ digits = 0;
+ } else if (!isxdigit(cval)) {
+ break;
+ } else {
+ digits++;
+ }
+
+ if (digits > 2)
+ break;
+
+ lastc = cval;
+ }
+ if ((lastc == ':') || (cval != '\0' && !isspace(cval)) ||
+ (digits > 2)) {
+ *maclen = -1;
+ return (NULL);
+ }
+
+ if ((netaddr = malloc(numcolons)) == NULL) {
+ *maclen = 0;
+ return (NULL);
+ }
+
+ for (;;) {
+ cval = *ascaddr++;
+ if (isdigit(cval)) {
+ num = (num << 4) | (cval - '0');
+ } else if (isxdigit(cval)) {
+ num = (num << 4) |
+ (cval - (isupper(cval) ? 'A' : 'a') + 10);
+ } else if (cval == ':') {
+ netaddr[idx++] = num;
+ num = 0;
+ } else {
+ /*
+ * We must have hit a whitespace. Stop
+ * parsing now.
+ */
+ netaddr[idx++] = num;
+ break;
+ }
+ }
+ *maclen = idx;
+ return (netaddr);
+}
diff --git a/usr/src/lib/libsocket/inet/netmasks.c b/usr/src/lib/libsocket/inet/netmasks.c
new file mode 100644
index 0000000000..e944e00e84
--- /dev/null
+++ b/usr/src/lib/libsocket/inet/netmasks.c
@@ -0,0 +1,277 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * All routines necessary to deal the "netmasks" database. The sources
+ * contain mappings between 32 bit Internet addresses and corresponding
+ * 32 bit Internet address masks. The addresses are in dotted internet
+ * address notation.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <nss_dbdefs.h>
+
+static int str2addr(const char *, int, void *, char *, int);
+
+static DEFINE_NSS_DB_ROOT(db_root);
+
+static void
+_nss_initf_netmasks(nss_db_params_t *p)
+{
+ p->name = NSS_DBNAM_NETMASKS;
+ p->default_config = NSS_DEFCONF_NETMASKS;
+}
+
+/*
+ * Print a network number such as 129.144 as well as an IP address.
+ * Assumes network byte order for both IP addresses and network numbers
+ * (Network numbers are normally passed around in host byte order).
+ */
+static char *
+inet_nettoa(struct in_addr in)
+{
+ uint32_t addr = in.s_addr;
+ uchar_t *up = (uchar_t *)&addr;
+ static char result[256];
+
+ /* Omit leading zeros */
+ if (up[0]) {
+ (void) sprintf(result, "%d.%d.%d.%d",
+ up[0], up[1], up[2], up[3]);
+ } else if (up[1]) {
+ (void) sprintf(result, "%d.%d.%d", up[1], up[2], up[3]);
+ } else if (up[2]) {
+ (void) sprintf(result, "%d.%d", up[2], up[3]);
+ } else {
+ (void) sprintf(result, "%d", up[3]);
+ }
+ return (result);
+}
+
+/*
+ * Given a 32 bit key look it up in the netmasks database
+ * based on the "netmasks" policy in /etc/nsswitch.conf.
+ * If the key is a network number with the trailing zero's removed
+ * (e.g. "192.9.200") this routine can't use inet_ntoa to convert
+ * the address to the string key.
+ * Returns zero if successful, non-zero otherwise.
+ */
+static int
+getnetmaskbykey(const struct in_addr addr, struct in_addr *mask)
+{
+ nss_XbyY_args_t arg;
+ nss_status_t res;
+ char tmp[NSS_LINELEN_NETMASKS];
+
+ /*
+ * let the backend do the allocation to store stuff for parsing.
+ * To simplify things, we put the dotted internet address form of
+ * the network address in the 'name' field as a filter to speed
+ * up the lookup.
+ */
+ NSS_XbyY_INIT(&arg, mask, NULL, 0, str2addr);
+ (void) strcpy(tmp, inet_nettoa(addr));
+ arg.key.name = tmp;
+ res = nss_search(&db_root, _nss_initf_netmasks,
+ NSS_DBOP_NETMASKS_BYNET, &arg);
+ (void) NSS_XbyY_FINI(&arg);
+ return (arg.status = res);
+}
+
+/*
+ * Given a 32 bit internet network number, it finds the corresponding netmask
+ * address based on the "netmasks" policy in /etc/nsswitch.conf.
+ * Returns zero if successful, non-zero otherwise.
+ * Check both for the (masked) network number and the shifted network
+ * number (e.g., both "10.0.0.0" and "10").
+ * Assumes that the caller passes in an unshifted number (or an IP address).
+ */
+int
+getnetmaskbynet(const struct in_addr net, struct in_addr *mask)
+{
+ struct in_addr net1, net2;
+ uint32_t i;
+
+ i = ntohl(net.s_addr);
+
+ /*
+ * Try looking for the network number both with and without
+ * the trailing zeros.
+ */
+ if ((i & IN_CLASSA_NET) == 0) {
+ /* Assume already a right-shifted network number */
+ net2.s_addr = htonl(i);
+ if ((i & IN_CLASSB_NET) != 0) {
+ net1.s_addr = htonl(i << IN_CLASSC_NSHIFT);
+ } else if ((i & IN_CLASSC_NET) != 0) {
+ net1.s_addr = htonl(i << IN_CLASSB_NSHIFT);
+ } else {
+ net1.s_addr = htonl(i << IN_CLASSA_NSHIFT);
+ }
+ } else if (IN_CLASSA(i)) {
+ net1.s_addr = htonl(i & IN_CLASSA_NET);
+ net2.s_addr = htonl(i >> IN_CLASSA_NSHIFT);
+ } else if (IN_CLASSB(i)) {
+ net1.s_addr = htonl(i & IN_CLASSB_NET);
+ net2.s_addr = htonl(i >> IN_CLASSB_NSHIFT);
+ } else {
+ net1.s_addr = htonl(i & IN_CLASSC_NET);
+ net2.s_addr = htonl(i >> IN_CLASSC_NSHIFT);
+ }
+
+ if (getnetmaskbykey(net1, mask) == 0) {
+ return (0);
+ }
+ if (getnetmaskbykey(net2, mask) == 0) {
+ return (0);
+ }
+ return (-1);
+}
+
+/*
+ * Find the netmask used for an IP address.
+ * Returns zero if successful, non-zero otherwise.
+ *
+ * Support Variable Length Subnetmasks by looking for the longest
+ * matching subnetmask in the database.
+ * Start by looking for a match for the full IP address and
+ * mask off one rightmost bit after another until we find a match.
+ * Note that for a match the found netmask must match what was used
+ * for the lookup masking.
+ * As a fallback for compatibility finally lookup the network
+ * number with and without the trailing zeros.
+ * In order to suppress redundant lookups in the name service
+ * we keep the previous lookup key and compare against it before
+ * doing the lookup.
+ */
+int
+getnetmaskbyaddr(const struct in_addr addr, struct in_addr *mask)
+{
+ struct in_addr prevnet, net;
+ uint32_t i, maskoff;
+
+ i = ntohl(addr.s_addr);
+ prevnet.s_addr = 0;
+ mask->s_addr = 0;
+
+ for (maskoff = 0xFFFFFFFF; maskoff != 0; maskoff = maskoff << 1) {
+ net.s_addr = htonl(i & maskoff);
+
+ if (net.s_addr != prevnet.s_addr) {
+ if (getnetmaskbykey(net, mask) != 0) {
+ mask->s_addr = 0;
+ }
+ }
+ if (htonl(maskoff) == mask->s_addr)
+ return (0);
+
+ prevnet.s_addr = net.s_addr;
+ }
+
+ /*
+ * Non-VLSM fallback.
+ * Try looking for the network number with and without the trailing
+ * zeros.
+ */
+ return (getnetmaskbynet(addr, mask));
+}
+
+/*
+ * Parse netmasks entry into its components. The network address is placed
+ * in buffer for use by check_addr for 'files' backend, to match the network
+ * address. The network address is placed in the buffer as a network order
+ * internet address, if buffer is non null. The network order form of the mask
+ * itself is placed in 'ent'.
+ */
+int
+str2addr(const char *instr, int lenstr, void *ent, char *buffer, int buflen)
+{
+ int retval;
+ struct in_addr *mask = (struct in_addr *)ent;
+ const char *p, *limit, *start;
+ struct in_addr addr;
+ int i;
+ char tmp[NSS_LINELEN_NETMASKS];
+
+ p = instr;
+ limit = p + lenstr;
+ retval = NSS_STR_PARSE_PARSE;
+
+ while (p < limit && isspace(*p)) /* skip leading whitespace */
+ p++;
+
+ if (buffer) { /* for 'files' backend verification */
+ for (start = p, i = 0; p < limit && !isspace(*p); p++)
+ i++;
+ if (p < limit && i < buflen) {
+ (void) memcpy(tmp, start, i);
+ tmp[i] = '\0';
+ addr.s_addr = inet_addr(tmp);
+ /* Addr will always be an ipv4 address (32bits) */
+ if (addr.s_addr == 0xffffffffUL)
+ return (NSS_STR_PARSE_PARSE);
+ else {
+ (void) memcpy(buffer, (char *)&addr,
+ sizeof (struct in_addr));
+ }
+ } else
+ return (NSS_STR_PARSE_ERANGE);
+ }
+
+ while (p < limit && isspace(*p)) /* skip intermediate */
+ p++;
+
+ if (mask) {
+ for (start = p, i = 0; p < limit && !isspace(*p); p++)
+ i++;
+ if (p <= limit) {
+ if ((i + 1) > NSS_LINELEN_NETMASKS)
+ return (NSS_STR_PARSE_ERANGE);
+ (void) memcpy(tmp, start, i);
+ tmp[i] = '\0';
+ addr.s_addr = inet_addr(tmp);
+ /* Addr will always be an ipv4 address (32bits) */
+ if (addr.s_addr == 0xffffffffUL)
+ retval = NSS_STR_PARSE_PARSE;
+ else {
+ mask->s_addr = addr.s_addr;
+ retval = NSS_STR_PARSE_SUCCESS;
+ }
+ }
+ }
+
+ return (retval);
+}
diff --git a/usr/src/lib/libsocket/inet/rcmd.c b/usr/src/lib/libsocket/inet/rcmd.c
new file mode 100644
index 0000000000..8cb2cd1291
--- /dev/null
+++ b/usr/src/lib/libsocket/inet/rcmd.c
@@ -0,0 +1,820 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * University Copyright- Copyright (c) 1982, 1986, 1988
+ * The Regents of the University of California
+ * All Rights Reserved
+ *
+ * University Acknowledgment- Portions of this document are derived from
+ * software developed by the University of California, Berkeley, and its
+ * contributors.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <limits.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <pwd.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/file.h>
+#include <signal.h>
+#include <libintl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <inet/common.h>
+
+#include <netdb.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <grp.h>
+#include <arpa/inet.h>
+
+#include <priv_utils.h>
+
+#ifdef SYSV
+#define bcopy(s1, s2, len) (void) memcpy(s2, s1, len)
+#define bzero(s, len) (void) memset(s, 0, len)
+#define index(s, c) strchr(s, c)
+char *strchr();
+#else
+char *index();
+#endif /* SYSV */
+
+extern char *_dgettext();
+extern int _sigaction();
+extern int _sigaddset();
+extern int _sigprocmask();
+extern int _fcntl();
+extern int usingypmap();
+
+static int _validuser(FILE *hostf, char *rhost, const char *luser,
+ const char *ruser, int baselen);
+static int _checkhost(char *rhost, char *lhost, int len);
+
+
+#ifdef NIS
+static char *domain;
+#endif
+
+int rcmd(char **ahost, unsigned short rport, const char *locuser,
+ const char *remuser, const char *cmd, int *fd2p)
+{
+ int rcmd_ret;
+
+ rcmd_ret = rcmd_af(ahost, rport, locuser, remuser, cmd, fd2p,
+ AF_INET);
+ return (rcmd_ret);
+}
+
+int rcmd_af(char **ahost, unsigned short rport, const char *locuser,
+ const char *remuser, const char *cmd, int *fd2p, int af)
+{
+ int s, timo = 1;
+ ssize_t retval;
+ pid_t pid;
+ struct sockaddr_storage caddr, faddr;
+ struct sockaddr_in *sin;
+ struct sockaddr_in6 *sin6;
+ struct addrinfo hints;
+ struct addrinfo *res, *resp;
+ size_t addrlen;
+ int rc;
+#define MAX_SHORTSTRLEN 6
+ char aport[MAX_SHORTSTRLEN];
+ char c;
+ int lport = 0;
+#ifdef SYSV
+ sigset_t oldmask;
+ sigset_t newmask;
+ struct sigaction oldaction;
+ struct sigaction newaction;
+#else
+ int oldmask;
+#endif /* SYSV */
+ fd_set fdset;
+ int selret;
+ char *addr;
+ static char hostname[MAXHOSTNAMELEN];
+ socklen_t len;
+ char abuf[INET6_ADDRSTRLEN];
+
+ if (!(af == AF_INET || af == AF_INET6 || af == AF_UNSPEC)) {
+ errno = EAFNOSUPPORT;
+ return (-1);
+ }
+
+ pid = getpid();
+ memset(&hints, 0, sizeof (hints));
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_CANONNAME;
+ if (af == AF_INET6) {
+ hints.ai_flags |= AI_V4MAPPED;
+ hints.ai_family = AF_UNSPEC;
+ } else {
+ hints.ai_family = af;
+ }
+ (void) snprintf(aport, MAX_SHORTSTRLEN, "%u", ntohs(rport));
+ rc = getaddrinfo(*ahost, aport, &hints, &res);
+ if (rc != 0) {
+ (void) fprintf(stderr,
+ _dgettext(TEXT_DOMAIN, "%s: unknown host%s\n"),
+ *ahost, rc == EAI_AGAIN ? " (try again later)" : "");
+ return (-1);
+ }
+ resp = res;
+ (void) strlcpy(hostname, res->ai_canonname, MAXHOSTNAMELEN);
+ *ahost = hostname;
+#ifdef SYSV
+ /* ignore SIGPIPE */
+ bzero((char *)&newaction, sizeof (newaction));
+ newaction.sa_handler = SIG_IGN;
+ (void) _sigaction(SIGPIPE, &newaction, &oldaction);
+
+ /* block SIGURG */
+ bzero((char *)&newmask, sizeof (newmask));
+ (void) _sigaddset(&newmask, SIGURG);
+ (void) _sigprocmask(SIG_BLOCK, &newmask, &oldmask);
+#else
+ oldmask = _sigblock(sigmask(SIGURG));
+#endif /* SYSV */
+ for (;;) {
+ s = rresvport_af(&lport, res->ai_family);
+ if (s < 0) {
+ int af = res->ai_family;
+
+ /*
+ * See if we have any addresses of a different type
+ * to try.
+ */
+ while (res != NULL && res->ai_family == af)
+ res = res->ai_next;
+
+ if (res != NULL)
+ continue;
+
+ if (errno == EAGAIN)
+ (void) fprintf(stderr,
+ _dgettext(TEXT_DOMAIN,
+ "socket: All ports in use\n"));
+ else
+ perror("rcmd: socket");
+#ifdef SYSV
+ /* restore original SIGPIPE handler */
+ (void) _sigaction(SIGPIPE, &oldaction,
+ (struct sigaction *)0);
+
+ /* restore original signal mask */
+ (void) _sigprocmask(SIG_SETMASK, &oldmask,
+ (sigset_t *)0);
+#else
+ sigsetmask(oldmask);
+#endif /* SYSV */
+ freeaddrinfo(resp);
+ return (-1);
+ }
+ bzero((char *)&caddr, sizeof (caddr));
+ bcopy(res->ai_addr, &caddr, res->ai_addrlen);
+ addrlen = res->ai_addrlen;
+ if (af == AF_INET6 && res->ai_addr->sa_family == AF_INET) {
+ struct in6_addr ia6;
+ struct sockaddr_in6 *in6addr;
+ IN6_INADDR_TO_V4MAPPED(&((struct sockaddr_in *)
+ res->ai_addr)->sin_addr, &ia6);
+ in6addr = (struct sockaddr_in6 *)&caddr;
+ in6addr->sin6_addr = ia6;
+ in6addr->sin6_family = AF_INET6;
+ addrlen = sizeof (struct sockaddr_in6);
+ }
+ (void) _fcntl(s, F_SETOWN, pid);
+ if (connect(s, (struct sockaddr *)&caddr, addrlen) >= 0)
+ break;
+ (void) close(s);
+ if (errno == EADDRINUSE) {
+ lport = 0;
+ continue;
+ }
+ if (errno == ECONNREFUSED && timo <= 16) {
+ (void) sleep(timo);
+ timo *= 2;
+ continue;
+ }
+ if (res->ai_next != NULL) {
+ int oerrno = errno;
+ if (res->ai_addr->sa_family == AF_INET6)
+ addr = (char *)&((struct sockaddr_in6 *)
+ res->ai_addr)->sin6_addr;
+ else
+ addr = (char *)&((struct sockaddr_in *)
+ res->ai_addr)->sin_addr;
+ (void) fprintf(stderr,
+ _dgettext(TEXT_DOMAIN, "connect to address %s: "),
+ inet_ntop(res->ai_addr->sa_family, addr,
+ abuf, sizeof (abuf)));
+ errno = oerrno;
+ perror(0);
+ res = res->ai_next;
+ if (res->ai_addr->sa_family == AF_INET6)
+ addr = (char *)&((struct sockaddr_in6 *)
+ res->ai_addr)->sin6_addr;
+ else
+ addr = (char *)&((struct sockaddr_in *)
+ res->ai_addr)->sin_addr;
+ (void) fprintf(stderr,
+ _dgettext(TEXT_DOMAIN, "Trying %s...\n"),
+ inet_ntop(res->ai_addr->sa_family, addr,
+ abuf, sizeof (abuf)));
+ continue;
+ }
+ perror(*ahost);
+ freeaddrinfo(resp);
+#ifdef SYSV
+ /* restore original SIGPIPE handler */
+ (void) _sigaction(SIGPIPE, &oldaction,
+ (struct sigaction *)0);
+
+ /* restore original signal mask */
+ (void) _sigprocmask(SIG_SETMASK, &oldmask, (sigset_t *)0);
+#else
+ sigsetmask(oldmask);
+#endif /* SYSV */
+ return (-1);
+ }
+ lport = 0;
+ if (fd2p == 0) {
+ (void) write(s, "", 1);
+ } else {
+ int s2 = rresvport_af(&lport, res->ai_family), s3;
+
+ len = (socklen_t)sizeof (faddr);
+
+ if (s2 < 0)
+ goto bad;
+ (void) listen(s2, 1);
+ (void) snprintf(aport, MAX_SHORTSTRLEN, "%d", lport);
+ if (write(s, aport, strlen(aport)+1) != strlen(aport)+1) {
+ perror(_dgettext(TEXT_DOMAIN,
+ "write: setting up stderr"));
+ (void) close(s2);
+ goto bad;
+ }
+ FD_ZERO(&fdset);
+ FD_SET(s, &fdset);
+ FD_SET(s2, &fdset);
+ while ((selret = select(FD_SETSIZE, &fdset, (fd_set *)0,
+ (fd_set *)0, (struct timeval *)0)) > 0) {
+ if (FD_ISSET(s, &fdset)) {
+ /*
+ * Something's wrong: we should get no
+ * data on this connection at this point,
+ * so we assume that the connection has
+ * gone away.
+ */
+ (void) close(s2);
+ goto bad;
+ }
+ if (FD_ISSET(s2, &fdset)) {
+ /*
+ * We assume this is an incoming connect
+ * request and proceed normally.
+ */
+ s3 = accept(s2, (struct sockaddr *)&faddr,
+ &len);
+ FD_CLR(s2, &fdset);
+ (void) close(s2);
+ if (s3 < 0) {
+ perror("accept");
+ lport = 0;
+ goto bad;
+ }
+ else
+ break;
+ }
+ }
+ if (selret == -1) {
+ /*
+ * This should not happen, and we treat it as
+ * a fatal error.
+ */
+ (void) close(s2);
+ goto bad;
+ }
+
+ *fd2p = s3;
+ switch (faddr.ss_family) {
+ case AF_INET:
+ sin = (struct sockaddr_in *)&faddr;
+ if (ntohs(sin->sin_port) >= IPPORT_RESERVED) {
+ (void) fprintf(stderr,
+ _dgettext(TEXT_DOMAIN,
+ "socket: protocol failure in circuit "
+ "setup.\n"));
+ goto bad2;
+ }
+ break;
+ case AF_INET6:
+ sin6 = (struct sockaddr_in6 *)&faddr;
+ if (ntohs(sin6->sin6_port) >= IPPORT_RESERVED) {
+ (void) fprintf(stderr,
+ _dgettext(TEXT_DOMAIN,
+ "socket: protocol failure in circuit "
+ "setup.\n"));
+ goto bad2;
+ }
+ break;
+ default:
+ (void) fprintf(stderr,
+ _dgettext(TEXT_DOMAIN,
+ "socket: protocol failure in circuit setup.\n"));
+ goto bad2;
+ }
+ }
+ (void) write(s, locuser, strlen(locuser)+1);
+ (void) write(s, remuser, strlen(remuser)+1);
+ (void) write(s, cmd, strlen(cmd)+1);
+ retval = read(s, &c, 1);
+ if (retval != 1) {
+ if (retval == 0) {
+ (void) fprintf(stderr,
+ _dgettext(TEXT_DOMAIN,
+ "Protocol error, %s closed connection\n"),
+ *ahost);
+ } else if (retval < 0) {
+ perror(*ahost);
+ } else {
+ (void) fprintf(stderr,
+ _dgettext(TEXT_DOMAIN,
+ "Protocol error, %s sent %d bytes\n"),
+ *ahost, retval);
+ }
+ goto bad2;
+ }
+ if (c != 0) {
+ while (read(s, &c, 1) == 1) {
+ (void) write(2, &c, 1);
+ if (c == '\n')
+ break;
+ }
+ goto bad2;
+ }
+#ifdef SYSV
+ /* restore original SIGPIPE handler */
+ (void) _sigaction(SIGPIPE, &oldaction, (struct sigaction *)0);
+
+ /* restore original signal mask */
+ (void) _sigprocmask(SIG_SETMASK, &oldmask, (sigset_t *)0);
+#else
+ sigsetmask(oldmask);
+#endif /* SYSV */
+ freeaddrinfo(resp);
+ return (s);
+bad2:
+ if (lport)
+ (void) close(*fd2p);
+bad:
+ (void) close(s);
+#ifdef SYSV
+ /* restore original SIGPIPE handler */
+ (void) _sigaction(SIGPIPE, &oldaction, (struct sigaction *)0);
+
+ /* restore original signal mask */
+ (void) _sigprocmask(SIG_SETMASK, &oldmask, (sigset_t *)0);
+#else
+ sigsetmask(oldmask);
+#endif /* SYSV */
+ freeaddrinfo(resp);
+ return (-1);
+}
+
+static int
+_rresvport_addr(int *alport, struct sockaddr_storage *addr)
+{
+ struct sockaddr_in *sin;
+ struct sockaddr_in6 *sin6;
+ int s;
+ socklen_t len;
+ int on = 1;
+ int off = 0;
+
+ if (addr->ss_family == AF_INET) {
+ sin = (struct sockaddr_in *)addr;
+ len = sizeof (struct sockaddr_in);
+ } else if (addr->ss_family == AF_INET6) {
+ sin6 = (struct sockaddr_in6 *)addr;
+ len = sizeof (struct sockaddr_in6);
+ } else {
+ errno = EAFNOSUPPORT;
+ return (-1);
+ }
+ s = socket(addr->ss_family, SOCK_STREAM, 0);
+ if (s < 0)
+ return (-1);
+
+ /*
+ * Set TCP_EXCLBIND to get a "unique" port, which is not bound
+ * to any other sockets.
+ */
+ if (setsockopt(s, IPPROTO_TCP, TCP_EXCLBIND, &on, sizeof (on)) < 0) {
+ (void) close(s);
+ return (-1);
+ }
+
+ /* Try to bind() to the given port first. */
+ if (*alport != 0) {
+ if (addr->ss_family == AF_INET) {
+ sin->sin_port = htons((ushort_t)*alport);
+ } else {
+ sin6->sin6_port = htons((ushort_t)*alport);
+ }
+ if (bind(s, (struct sockaddr *)addr, len) >= 0) {
+ /* To be safe, need to turn off TCP_EXCLBIND. */
+ (void) setsockopt(s, IPPROTO_TCP, TCP_EXCLBIND, &off,
+ sizeof (off));
+ return (s);
+ }
+ if (errno != EADDRINUSE) {
+ (void) close(s);
+ return (-1);
+ }
+ }
+
+ /*
+ * If no port is given or the above bind() does not succeed, set
+ * TCP_ANONPRIVBIND option to ask the kernel to pick a port in the
+ * priviledged range for us.
+ */
+ if (setsockopt(s, IPPROTO_TCP, TCP_ANONPRIVBIND, &on,
+ sizeof (on)) < 0) {
+ (void) close(s);
+ return (-1);
+ }
+ if (addr->ss_family == AF_INET) {
+ sin->sin_port = 0;
+ } else {
+ sin6->sin6_port = 0;
+ }
+ if (bind(s, (struct sockaddr *)addr, len) >= 0) {
+ /*
+ * We need to tell the caller what the port is.
+ */
+ if (getsockname(s, (struct sockaddr *)addr, &len) < 0) {
+ (void) close(s);
+ return (-1);
+ }
+ switch (addr->ss_family) {
+ case AF_INET6:
+ sin6 = (struct sockaddr_in6 *)addr;
+ *alport = ntohs(sin6->sin6_port);
+ break;
+ case AF_INET:
+ sin = (struct sockaddr_in *)addr;
+ *alport = ntohs(sin->sin_port);
+ break;
+ }
+
+ /*
+ * To be safe, always turn off these options when we are done.
+ */
+ (void) setsockopt(s, IPPROTO_TCP, TCP_ANONPRIVBIND, &off,
+ sizeof (off));
+ (void) setsockopt(s, IPPROTO_TCP, TCP_EXCLBIND, &off,
+ sizeof (off));
+ return (s);
+ }
+ (void) close(s);
+ return (-1);
+}
+
+int
+rresvport_addr(int *alport, struct sockaddr_storage *addr)
+{
+ int res, err;
+
+ (void) __priv_bracket(PRIV_ON);
+
+ res = _rresvport_addr(alport, addr);
+
+ err = errno;
+ (void) __priv_bracket(PRIV_OFF);
+ errno = err;
+
+ return (res);
+}
+
+int
+rresvport_af(int *alport, int af)
+{
+ struct sockaddr_storage laddr;
+
+ bzero(&laddr, sizeof (laddr));
+ if (af == AF_INET || af == AF_INET6) {
+ laddr.ss_family = (sa_family_t)af;
+ } else {
+ errno = EAFNOSUPPORT;
+ return (-1);
+ }
+ return (rresvport_addr(alport, &laddr));
+}
+
+int
+rresvport(int *alport)
+{
+ return (rresvport_af(alport, AF_INET));
+}
+
+int
+ruserok(const char *rhost, int superuser, const char *ruser, const char *luser)
+{
+ FILE *hostf;
+ char fhost[MAXHOSTNAMELEN];
+ const char *sp;
+ char *p;
+ int baselen = -1;
+
+ struct stat64 sbuf;
+ struct passwd *pwd;
+ char pbuf[MAXPATHLEN];
+ uid_t uid = (uid_t)-1;
+ gid_t gid = (gid_t)-1;
+ gid_t grouplist[NGROUPS_MAX];
+ int ngroups;
+
+ sp = rhost;
+ p = fhost;
+ while (*sp) {
+ if (*sp == '.') {
+ if (baselen == -1)
+ baselen = (int)(sp - rhost);
+ *p++ = *sp++;
+ } else {
+ *p++ = isupper(*sp) ? tolower(*sp++) : *sp++;
+ }
+ }
+ *p = '\0';
+
+ /* check /etc/hosts.equiv */
+ if (!superuser) {
+ if ((hostf = fopen("/etc/hosts.equiv", "r")) != NULL) {
+ if (!_validuser(hostf, fhost, luser, ruser, baselen)) {
+ (void) fclose(hostf);
+ return (0);
+ }
+ (void) fclose(hostf);
+ }
+ }
+
+ /* check ~/.rhosts */
+
+ if ((pwd = getpwnam(luser)) == NULL)
+ return (-1);
+ (void) strcpy(pbuf, pwd->pw_dir);
+ (void) strcat(pbuf, "/.rhosts");
+
+ /*
+ * Read .rhosts as the local user to avoid NFS mapping the root uid
+ * to something that can't read .rhosts.
+ */
+ gid = getegid();
+ uid = geteuid();
+ if ((ngroups = getgroups(NGROUPS_MAX, grouplist)) == -1)
+ return (-1);
+
+ (void) setegid(pwd->pw_gid);
+ initgroups(pwd->pw_name, pwd->pw_gid);
+ (void) seteuid(pwd->pw_uid);
+ if ((hostf = fopen(pbuf, "r")) == NULL) {
+ if (gid != (gid_t)-1)
+ (void) setegid(gid);
+ if (uid != (uid_t)-1)
+ (void) seteuid(uid);
+ setgroups(ngroups, grouplist);
+ return (-1);
+ }
+ (void) fstat64(fileno(hostf), &sbuf);
+ if (sbuf.st_uid && sbuf.st_uid != pwd->pw_uid) {
+ (void) fclose(hostf);
+ if (gid != (gid_t)-1)
+ (void) setegid(gid);
+ if (uid != (uid_t)-1)
+ (void) seteuid(uid);
+ setgroups(ngroups, grouplist);
+ return (-1);
+ }
+
+ if (!_validuser(hostf, fhost, luser, ruser, baselen)) {
+ (void) fclose(hostf);
+ if (gid != (gid_t)-1)
+ (void) setegid(gid);
+ if (uid != (uid_t)-1)
+ (void) seteuid(uid);
+ setgroups(ngroups, grouplist);
+ return (0);
+ }
+
+ (void) fclose(hostf);
+ if (gid != (gid_t)-1)
+ (void) setegid(gid);
+ if (uid != (uid_t)-1)
+ (void) seteuid(uid);
+ setgroups(ngroups, grouplist);
+ return (-1);
+}
+
+static int
+_validuser(FILE *hostf, char *rhost, const char *luser,
+ const char *ruser, int baselen)
+{
+ char *user;
+ char ahost[BUFSIZ];
+ char *uchost = (char *)NULL;
+ int hostmatch, usermatch;
+ char *p;
+
+#ifdef NIS
+ if (domain == NULL) {
+ (void) usingypmap(&domain, NULL);
+ }
+#endif /* NIS */
+
+ while (fgets(ahost, (int)sizeof (ahost), hostf)) {
+ uchost = (char *)NULL;
+ hostmatch = usermatch = 0;
+ p = ahost;
+ /*
+ * We can get a line bigger than our buffer. If so we skip
+ * the offending line.
+ */
+ if (strchr(p, '\n') == NULL) {
+ while (fgets(ahost, (int)sizeof (ahost), hostf) &&
+ strchr(ahost, '\n') == NULL)
+ ;
+ continue;
+ }
+ while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') {
+ /*
+ * Both host and user ``names'' can be netgroups,
+ * and must have their case preserved. Case is
+ * preserved for user names because we break out
+ * of this loop when finding a field separator.
+ * To do so for host names, we must make a copy of
+ * the host name field.
+ */
+ if (isupper(*p)) {
+ if (uchost == (char *)NULL)
+ uchost = strdup(ahost);
+ *p = tolower(*p);
+ }
+ p++;
+ }
+ if (*p != '\0' && uchost != (char *)NULL)
+ uchost[p - ahost] = '\0';
+ if (*p == ' ' || *p == '\t') {
+ *p++ = '\0';
+ while (*p == ' ' || *p == '\t')
+ p++;
+ user = p;
+ while (*p != '\n' && *p != ' ' && *p != '\t' &&
+ *p != '\0')
+ p++;
+ } else
+ user = p;
+ *p = '\0';
+ if (ahost[0] == '+' && ahost[1] == 0)
+ hostmatch = 1;
+#ifdef NIS
+ else if (ahost[0] == '+' && ahost[1] == '@')
+ if (uchost != (char *)NULL)
+ hostmatch = innetgr(uchost + 2, rhost,
+ NULL, domain);
+ else
+ hostmatch = innetgr(ahost + 2, rhost,
+ NULL, domain);
+ else if (ahost[0] == '-' && ahost[1] == '@') {
+ if (uchost != (char *)NULL) {
+ if (innetgr(uchost + 2, rhost, NULL, domain))
+ break;
+ } else {
+ if (innetgr(ahost + 2, rhost, NULL, domain))
+ break;
+ }
+ }
+#endif /* NIS */
+ else if (ahost[0] == '-') {
+ if (_checkhost(rhost, ahost+1, baselen))
+ break;
+ }
+ else
+ hostmatch = _checkhost(rhost, ahost, baselen);
+ if (user[0]) {
+ if (user[0] == '+' && user[1] == 0)
+ usermatch = 1;
+#ifdef NIS
+ else if (user[0] == '+' && user[1] == '@')
+ usermatch = innetgr(user+2, NULL,
+ ruser, domain);
+ else if (user[0] == '-' && user[1] == '@') {
+ if (hostmatch &&
+ innetgr(user+2, NULL, ruser, domain))
+ break;
+ }
+#endif /* NIS */
+ else if (user[0] == '-') {
+ if (hostmatch && (strcmp(user+1, ruser) == 0))
+ break;
+ }
+ else
+ usermatch = (strcmp(user, ruser) == 0);
+ }
+ else
+ usermatch = (strcmp(ruser, luser) == 0);
+ if (uchost != (char *)NULL)
+ free(uchost);
+ if (hostmatch && usermatch)
+ return (0);
+ }
+
+ if (uchost != (char *)NULL)
+ free(uchost);
+ return (-1);
+}
+
+static int
+_checkhost(char *rhost, char *lhost, int len)
+{
+ static char *ldomain;
+ static char *domainp;
+ static int nodomain;
+ char *cp;
+
+ if (ldomain == NULL) {
+ ldomain = (char *)malloc(MAXHOSTNAMELEN+1);
+ if (ldomain == 0)
+ return (0);
+ }
+
+ if (len == -1)
+ return (strcmp(rhost, lhost) == 0);
+ if (strncmp(rhost, lhost, len))
+ return (0);
+ if (strcmp(rhost, lhost) == 0)
+ return (1);
+ if (*(lhost + len) != '\0')
+ return (0);
+ if (nodomain)
+ return (0);
+ if (!domainp) {
+ /*
+ * "domainp" points after the first dot in the host name
+ */
+ if (gethostname(ldomain, MAXHOSTNAMELEN) == -1) {
+ nodomain = 1;
+ return (0);
+ }
+ ldomain[MAXHOSTNAMELEN] = NULL;
+ if ((domainp = index(ldomain, '.')) == (char *)NULL) {
+ nodomain = 1;
+ return (0);
+ }
+ domainp++;
+ cp = domainp;
+ while (*cp) {
+ *cp = isupper(*cp) ? tolower(*cp) : *cp;
+ cp++;
+ }
+ }
+ return (strcmp(domainp, rhost + len + 1) == 0);
+}
diff --git a/usr/src/lib/libsocket/inet/rexec.c b/usr/src/lib/libsocket/inet/rexec.c
new file mode 100644
index 0000000000..b663fa2523
--- /dev/null
+++ b/usr/src/lib/libsocket/inet/rexec.c
@@ -0,0 +1,189 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * University Copyright- Copyright (c) 1982, 1986, 1988
+ * The Regents of the University of California
+ * All Rights Reserved
+ *
+ * University Acknowledgment- Portions of this document are derived from
+ * software developed by the University of California, Berkeley, and its
+ * contributors.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+
+#include <stdio.h>
+#include <netdb.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <libintl.h>
+
+#ifdef SYSV
+#define bcopy(a, b, c) (void) memcpy((b), (a), (c))
+#endif
+
+#define MAX_SHORTSTRLEN 6
+
+extern char *_dgettext();
+
+void _ruserpass(const char *host, char **aname, char **apass);
+
+int rexec(char **ahost, unsigned short rport, const char *name,
+ const char *pass, const char *cmd, int *fd2p)
+{
+ return (rexec_af(ahost, rport, name, pass, cmd, fd2p, AF_INET));
+}
+
+int rexec_af(char **ahost, unsigned short rport, const char *name,
+ const char *pass, const char *cmd, int *fd2p, int af)
+{
+ int s, timo = 1, s3;
+ char c;
+ ushort_t port;
+ static char hostname[MAXHOSTNAMELEN];
+ int rc;
+ struct addrinfo *res;
+ struct addrinfo hints;
+ char aport[MAX_SHORTSTRLEN];
+
+ if (!(af == AF_INET || af == AF_INET6 || af == AF_UNSPEC)) {
+ (void) fprintf(stderr,
+ _dgettext(TEXT_DOMAIN, "%d: Address family not "
+ "supported\n"), af);
+ errno = EAFNOSUPPORT;
+ return (-1);
+ }
+ memset(&hints, 0, sizeof (hints));
+ (void) snprintf(aport, MAX_SHORTSTRLEN, "%u", ntohs(rport));
+ hints.ai_flags = AI_CANONNAME|AI_ADDRCONFIG|AI_V4MAPPED;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_family = af;
+ rc = getaddrinfo(*ahost, aport, &hints, &res);
+
+ if (rc != 0) {
+ (void) fprintf(stderr,
+ _dgettext(TEXT_DOMAIN, "%s: unknown host\n"),
+ *ahost);
+ return (-1);
+ }
+ (void) strlcpy(hostname, res->ai_canonname, MAXHOSTNAMELEN);
+ *ahost = hostname;
+ _ruserpass(res->ai_canonname, (char **)&name, (char **)&pass);
+retry:
+ s = socket(res->ai_addr->sa_family, res->ai_socktype, res->ai_protocol);
+ if (s < 0) {
+ perror("rexec: socket");
+ freeaddrinfo(res);
+ return (-1);
+ }
+ if (connect(s, res->ai_addr, res->ai_addrlen) != 0) {
+ if (errno == ECONNREFUSED && timo <= 16) {
+ (void) close(s);
+ (void) sleep(timo);
+ timo *= 2;
+ goto retry;
+ }
+ perror(*ahost);
+ (void) close(s);
+ freeaddrinfo(res);
+ return (-1);
+ }
+ if (fd2p == 0) {
+ (void) write(s, "", 1);
+ port = 0;
+ } else {
+ int s2;
+ socklen_t sin2len;
+ struct sockaddr_storage sin2, from;
+
+ s2 = socket(res->ai_family, SOCK_STREAM, 0);
+ if (s2 < 0) {
+ (void) close(s);
+ freeaddrinfo(res);
+ return (-1);
+ }
+ (void) listen(s2, 1);
+ sin2len = (socklen_t)sizeof (sin2);
+ if (getsockname(s2, (struct sockaddr *)&sin2, &sin2len) < 0) {
+ perror("getsockname");
+ (void) close(s2);
+ goto bad;
+ }
+ if (res->ai_family == AF_INET6) {
+ port = ((struct sockaddr_in6 *)&sin2)->sin6_port;
+ } else {
+ port = ((struct sockaddr_in *)&sin2)->sin_port;
+ }
+ (void) snprintf(aport, MAX_SHORTSTRLEN, "%u", port);
+ (void) write(s, aport, strlen(aport)+1);
+ {
+ socklen_t len = (socklen_t)sizeof (from);
+ s3 = accept(s2, (struct sockaddr *)&from, &len);
+ (void) close(s2);
+ if (s3 < 0) {
+ perror("accept");
+ port = 0;
+ goto bad;
+ }
+ }
+ *fd2p = s3;
+ }
+ (void) write(s, name, strlen(name) + 1);
+ /* should public key encypt the password here */
+ (void) write(s, pass, strlen(pass) + 1);
+ (void) write(s, cmd, strlen(cmd) + 1);
+ if (read(s, &c, 1) != 1) {
+ perror(*ahost);
+ goto bad;
+ }
+ if (c != 0) {
+ while (read(s, &c, 1) == 1) {
+ (void) write(2, &c, 1);
+ if (c == '\n')
+ break;
+ }
+ goto bad;
+ }
+ freeaddrinfo(res);
+ return (s);
+bad:
+ if (port)
+ (void) close(*fd2p);
+ (void) close(s);
+ freeaddrinfo(res);
+ return (-1);
+}
diff --git a/usr/src/lib/libsocket/inet/ruserpass.c b/usr/src/lib/libsocket/inet/ruserpass.c
new file mode 100644
index 0000000000..475bcf0ae3
--- /dev/null
+++ b/usr/src/lib/libsocket/inet/ruserpass.c
@@ -0,0 +1,270 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1998 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * University Copyright- Copyright (c) 1982, 1986, 1988
+ * The Regents of the University of California
+ * All Rights Reserved
+ *
+ * University Acknowledgment- Portions of this document are derived from
+ * software developed by the University of California, Berkeley, and its
+ * contributors.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <unistd.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <libintl.h>
+
+extern char *_dgettext();
+
+#ifdef SYSV
+#define index strchr
+#endif /* SYSV */
+
+static void rnetrc(const char *host, char **aname, char **apass);
+static int token();
+
+#define DEFAULT 1
+#define LOGIN 2
+#define PASSWD 3
+#define NOTIFY 4
+#define WRITE 5
+#define YES 6
+#define NO 7
+#define COMMAND 8
+#define FORCE 9
+#define ID 10
+#define MACHINE 11
+
+#define MAXTOKEN 11
+#define NTOKENS (MAXTOKEN - 1 + 2 + 1) /* two duplicates and null, minus id */
+
+static struct ruserdata {
+ char tokval[100];
+ struct toktab {
+ char *tokstr;
+ int tval;
+ } toktab[NTOKENS];
+ FILE *cfile;
+} *ruserdata, *_ruserdata();
+
+
+static struct ruserdata *
+_ruserdata()
+{
+ struct ruserdata *d = ruserdata;
+ struct toktab *t;
+
+ if (d == 0) {
+ if ((d = (struct ruserdata *)
+ calloc(1, sizeof (struct ruserdata))) == NULL) {
+ return (NULL);
+ }
+ ruserdata = d;
+ t = d->toktab;
+ t->tokstr = "default"; t++->tval = DEFAULT;
+ t->tokstr = "login"; t++->tval = LOGIN;
+ t->tokstr = "password"; t++->tval = PASSWD;
+ t->tokstr = "notify"; t++->tval = NOTIFY;
+ t->tokstr = "write"; t++->tval = WRITE;
+ t->tokstr = "yes"; t++->tval = YES;
+ t->tokstr = "y"; t++->tval = YES;
+ t->tokstr = "no"; t++->tval = NO;
+ t->tokstr = "n"; t++->tval = NO;
+ t->tokstr = "command"; t++->tval = COMMAND;
+ t->tokstr = "force"; t++->tval = FORCE;
+ t->tokstr = "machine"; t++->tval = MACHINE;
+ t->tokstr = 0; t->tval = 0;
+ }
+ return (d);
+}
+
+
+#define MAXANAME 16
+
+void
+_ruserpass(const char *host, char **aname, char **apass)
+{
+
+ if (*aname == 0 || *apass == 0)
+ rnetrc(host, aname, apass);
+ if (*aname == 0) {
+ char myname[L_cuserid];
+
+ *aname = malloc(MAXANAME + 1);
+ (void) cuserid(myname);
+ (void) printf(_dgettext(TEXT_DOMAIN, "Name (%s:%s): "), host, myname);
+ (void) fflush(stdout);
+ if (read(2, *aname, MAXANAME) <= 0)
+ exit(1);
+ aname[0][MAXANAME] = '\0';
+ if ((*aname)[0] == '\n')
+ (void) strcpy(*aname, myname);
+ else
+ if (index(*aname, '\n'))
+ *index(*aname, '\n') = 0;
+ }
+ if (*aname && *apass == 0) {
+ (void) printf(_dgettext(TEXT_DOMAIN, "Password (%s:%s): "),
+ host, *aname);
+ (void) fflush(stdout);
+ *apass = getpass("");
+ }
+}
+
+
+static void
+rnetrc(const char *host, char **aname, char **apass)
+{
+ struct ruserdata *d = _ruserdata();
+ char *hdir, buf[BUFSIZ];
+ int t;
+ struct stat64 stb;
+
+ if (d == 0)
+ return;
+
+ hdir = getenv("HOME");
+ if (hdir == NULL)
+ hdir = ".";
+ (void) sprintf(buf, "%s/.netrc", hdir);
+ d->cfile = fopen(buf, "r");
+ if (d->cfile == NULL) {
+ if (errno != ENOENT)
+ perror(buf);
+ return;
+ }
+next:
+ while ((t = token()))
+ switch (t) {
+
+ case DEFAULT:
+ (void) token();
+ continue;
+
+ case MACHINE:
+ if (token() != ID || strcmp(host, d->tokval))
+ continue;
+ while ((t = token()) != 0 && t != MACHINE)
+ switch (t) {
+
+ case LOGIN:
+ if (token())
+ if (*aname == 0) {
+ *aname = malloc(strlen(d->tokval) + 1);
+ (void) strcpy(*aname, d->tokval);
+ } else {
+ if (strcmp(*aname, d->tokval))
+ goto next;
+ }
+ break;
+ case PASSWD:
+ if (fstat64(fileno(d->cfile), &stb) >= 0 &&
+ (stb.st_mode & 077) != 0) {
+ (void) fprintf(stderr,
+ _dgettext(TEXT_DOMAIN,
+ "Error - .netrc file not correct mode.\n"));
+ (void) fprintf(stderr,
+ _dgettext(TEXT_DOMAIN,
+ "Remove password or correct mode.\n"));
+ exit(1);
+ }
+ if (token() && *apass == 0) {
+ *apass = malloc(strlen(d->tokval) + 1);
+ (void) strcpy(*apass, d->tokval);
+ }
+ break;
+ case COMMAND:
+ case NOTIFY:
+ case WRITE:
+ case FORCE:
+ (void) token();
+ break;
+ default:
+ (void) fprintf(stderr,
+ _dgettext(TEXT_DOMAIN, "Unknown .netrc option %s\n"),
+ d->tokval);
+ break;
+ }
+ goto done;
+ }
+done:
+ (void) fclose(d->cfile);
+}
+
+static int
+token()
+{
+ struct ruserdata *d = _ruserdata();
+ char *cp;
+ int c;
+ struct toktab *t;
+
+ if (d == 0)
+ return (0);
+
+ if (feof(d->cfile))
+ return (0);
+ while ((c = getc(d->cfile)) != EOF &&
+ (c == '\n' || c == '\t' || c == ' ' || c == ','))
+ continue;
+ if (c == EOF)
+ return (0);
+ cp = d->tokval;
+ if (c == '"') {
+ while ((c = getc(d->cfile)) != EOF && c != '"') {
+ if (c == '\\')
+ c = getc(d->cfile);
+ *cp++ = (char)c;
+ }
+ } else {
+ *cp++ = (char)c;
+ while ((c = getc(d->cfile)) != EOF &&
+ c != '\n' && c != '\t' && c != ' ' && c != ',') {
+ if (c == '\\')
+ c = getc(d->cfile);
+ *cp++ = (char)c;
+ }
+ }
+ *cp = 0;
+ if (d->tokval[0] == 0)
+ return (0);
+ for (t = d->toktab; t->tokstr; t++)
+ if ((strcmp(t->tokstr, d->tokval) == 0))
+ return (t->tval);
+ return (ID);
+}
diff --git a/usr/src/lib/libsocket/inet/sourcefilter.c b/usr/src/lib/libsocket/inet/sourcefilter.c
new file mode 100644
index 0000000000..77181226b0
--- /dev/null
+++ b/usr/src/lib/libsocket/inet/sourcefilter.c
@@ -0,0 +1,229 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stropts.h>
+#include <errno.h>
+#include <sys/sysmacros.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <netinet/in.h>
+
+int
+getsourcefilter(int s, uint32_t interface, struct sockaddr *group,
+ socklen_t grouplen, uint32_t *fmode, uint_t *numsrc,
+ struct sockaddr_storage *slist)
+{
+ struct group_filter *gf;
+ int mallocsize, orig_numsrc, cpsize, rtnerr;
+
+ mallocsize = (*numsrc == 0) ?
+ sizeof (struct group_filter) : GROUP_FILTER_SIZE(*numsrc);
+ gf = (struct group_filter *)malloc(mallocsize);
+ if (gf == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+
+ gf->gf_interface = interface;
+ gf->gf_numsrc = orig_numsrc = *numsrc;
+ switch (group->sa_family) {
+ case AF_INET:
+ if (grouplen < sizeof (struct sockaddr_in)) {
+ rtnerr = ENOPROTOOPT;
+ goto done;
+ }
+ (void) memcpy((void *)&gf->gf_group, (void *)group,
+ sizeof (struct sockaddr_in));
+ break;
+ case AF_INET6:
+ if (grouplen < sizeof (struct sockaddr_in6)) {
+ rtnerr = ENOPROTOOPT;
+ goto done;
+ }
+ (void) memcpy((void *)&gf->gf_group, (void *)group,
+ sizeof (struct sockaddr_in6));
+ break;
+ default:
+ rtnerr = EAFNOSUPPORT;
+ goto done;
+ }
+
+ rtnerr = ioctl(s, SIOCGMSFILTER, (void *)gf);
+ if (rtnerr == -1) {
+ rtnerr = errno;
+ goto done;
+ }
+
+ *fmode = gf->gf_fmode;
+ *numsrc = gf->gf_numsrc;
+ cpsize = MIN(orig_numsrc, *numsrc) * sizeof (struct sockaddr_storage);
+ (void) memcpy((void *)slist, (void *)gf->gf_slist, cpsize);
+
+done:
+ free(gf);
+ errno = rtnerr;
+ if (errno != 0)
+ return (-1);
+
+ return (0);
+}
+
+int
+setsourcefilter(int s, uint32_t interface, struct sockaddr *group,
+ socklen_t grouplen, uint32_t fmode, uint_t numsrc,
+ struct sockaddr_storage *slist)
+{
+ struct group_filter *gf;
+ int mallocsize, rtnerr;
+
+ mallocsize = (numsrc == 0) ?
+ sizeof (struct group_filter) : GROUP_FILTER_SIZE(numsrc);
+ gf = (struct group_filter *)malloc(mallocsize);
+ if (gf == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+
+ switch (group->sa_family) {
+ case AF_INET:
+ if (grouplen < sizeof (struct sockaddr_in)) {
+ rtnerr = ENOPROTOOPT;
+ goto done;
+ }
+ (void) memcpy((void *)&gf->gf_group, (void *)group,
+ sizeof (struct sockaddr_in));
+ break;
+ case AF_INET6:
+ if (grouplen < sizeof (struct sockaddr_in6)) {
+ rtnerr = ENOPROTOOPT;
+ goto done;
+ }
+ (void) memcpy((void *)&gf->gf_group, (void *)group,
+ sizeof (struct sockaddr_in6));
+ break;
+ default:
+ rtnerr = EAFNOSUPPORT;
+ goto done;
+ }
+ gf->gf_interface = interface;
+ gf->gf_fmode = fmode;
+ gf->gf_numsrc = numsrc;
+ (void) memcpy((void *)gf->gf_slist, (void *)slist,
+ (numsrc * sizeof (struct sockaddr_storage)));
+
+ rtnerr = ioctl(s, SIOCSMSFILTER, (void *)gf);
+ if (rtnerr == -1) {
+ rtnerr = errno;
+ }
+
+done:
+ free(gf);
+ errno = rtnerr;
+ if (errno != 0)
+ return (-1);
+
+ return (0);
+}
+
+int
+getipv4sourcefilter(int s, struct in_addr interface, struct in_addr group,
+ uint32_t *fmode, uint32_t *numsrc, struct in_addr *slist)
+{
+ struct ip_msfilter *imsf;
+ int mallocsize, orig_numsrc, cpsize, rtnerr;
+
+ mallocsize = (*numsrc == 0) ?
+ sizeof (struct ip_msfilter) : IP_MSFILTER_SIZE(*numsrc);
+ imsf = (struct ip_msfilter *)malloc(mallocsize);
+ if (imsf == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+
+ imsf->imsf_interface = interface;
+ imsf->imsf_numsrc = orig_numsrc = *numsrc;
+ imsf->imsf_multiaddr = group;
+
+ rtnerr = ioctl(s, SIOCGIPMSFILTER, (void *)imsf);
+ if (rtnerr == -1) {
+ rtnerr = errno;
+ goto done;
+ }
+
+ *fmode = imsf->imsf_fmode;
+ *numsrc = imsf->imsf_numsrc;
+ cpsize = MIN(orig_numsrc, *numsrc) * sizeof (struct in_addr);
+ (void) memcpy((void *)slist, (void *)imsf->imsf_slist, cpsize);
+
+done:
+ free(imsf);
+ errno = rtnerr;
+ if (errno != 0)
+ return (-1);
+
+ return (0);
+}
+
+int
+setipv4sourcefilter(int s, struct in_addr interface, struct in_addr group,
+ uint32_t fmode, uint32_t numsrc, struct in_addr *slist)
+{
+ struct ip_msfilter *imsf;
+ int mallocsize, rtnerr;
+
+ mallocsize = (numsrc == 0) ?
+ sizeof (struct ip_msfilter) : IP_MSFILTER_SIZE(numsrc);
+ imsf = (struct ip_msfilter *)malloc(mallocsize);
+ if (imsf == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+
+ imsf->imsf_multiaddr = group;
+ imsf->imsf_interface = interface;
+ imsf->imsf_fmode = fmode;
+ imsf->imsf_numsrc = numsrc;
+ (void) memcpy((void *)imsf->imsf_slist, (void *)slist,
+ (numsrc * sizeof (struct in_addr)));
+
+ rtnerr = ioctl(s, SIOCSIPMSFILTER, (void *)imsf);
+ if (rtnerr == -1) {
+ rtnerr = errno;
+ }
+
+ free(imsf);
+ errno = rtnerr;
+ if (errno != 0)
+ return (-1);
+
+ return (0);
+}
diff --git a/usr/src/lib/libsocket/socket/_soutil.c b/usr/src/lib/libsocket/socket/_soutil.c
new file mode 100644
index 0000000000..732b544ac6
--- /dev/null
+++ b/usr/src/lib/libsocket/socket/_soutil.c
@@ -0,0 +1,254 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1989 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Portions of this source code were derived from Berkeley 4.3 BSD
+ * under license from the Regents of the University of California.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+extern int _stat();
+
+/*
+ * XXX The functions in this file are only needed to support transport
+ * providers that have not yet been converted to use /etc/sock2path.
+ * Once all transport providers have been converted this file can be
+ * removed.
+ */
+
+static struct netconfig *_s_match_netconf(int family, int type, int proto,
+ void **nethandle);
+
+/*
+ * The following two string arrays map a number as specified
+ * by a user of sockets, to the string as would be returned
+ * by a call to getnetconfig().
+ *
+ * They are used by _s_match_netconf();
+ *
+ * proto_sw contains protocol entries for which there is a corresponding
+ * /dev device. All others would presumably use raw IP and download the
+ * desired protocol.
+ */
+static char *proto_sw[] = {
+ "",
+ "icmp", /* 1 = ICMP */
+ "",
+ "",
+ "",
+ "",
+ "tcp", /* 6 = TCP */
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "udp", /* 17 = UDP */
+};
+
+static char *family_sw[] = {
+ "-", /* 0 = AF_UNSPEC */
+ "loopback", /* 1 = AF_UNIX */
+ "inet", /* 2 = AF_INET */
+ "implink", /* 3 = AF_IMPLINK */
+ "pup", /* 4 = AF_PUP */
+ "chaos", /* 5 = AF_CHAOS */
+ "ns", /* 6 = AF_NS */
+ "nbs", /* 7 = AF_NBS */
+ "ecma", /* 8 = AF_ECMA */
+ "datakit", /* 9 = AF_DATAKIT */
+ "ccitt", /* 10 = AF_CCITT */
+ "sna", /* 11 = AF_SNA */
+ "decnet", /* 12 = AF_DECnet */
+ "dli", /* 13 = AF_DLI */
+ "lat", /* 14 = AF_LAT */
+ "hylink", /* 15 = AF_HYLINK */
+ "appletalk", /* 16 = AF_APPLETALK */
+ "nit", /* 17 = AF_NIT */
+ "ieee802", /* 18 = AF_802 */
+ "osi", /* 19 = AF_OSI */
+ "x25", /* 20 = AF_X25 */
+ "osinet", /* 21 = AF_OSINET */
+ "gosip", /* 22 = AF_GOSIP */
+ "ipx", /* 23 = AF_IPX */
+ "route", /* 24 = AF_ROUTE */
+ "link", /* 25 = AF_LINK */
+ "inet6", /* 26 = AF_INET6 */
+ "key", /* 27 = AF_KEY */
+};
+
+/*
+ * Lookup family/type/protocol in /etc/netconfig.
+ * Returns the pathname and a prototype value (to be passed into SO_PROTOTYPE)
+ * The path is malloc'ed and has to be freed by the caller.
+ */
+int
+_s_netconfig_path(int family, int type, int protocol,
+ char **pathp, int *prototype)
+{
+ struct netconfig *net;
+ void *nethandle;
+ struct stat stats;
+
+ net = _s_match_netconf(family, type, protocol, &nethandle);
+ if (net == NULL)
+ return (-1);
+
+ if (strcmp(net->nc_proto, NC_NOPROTO) != 0)
+ *prototype = 0;
+ else
+ *prototype = protocol;
+
+retry:
+#if defined(i386)
+ if (_xstat(_STAT_VER, net->nc_device, &stats) < 0) {
+#else
+ if (_stat(net->nc_device, &stats) < 0) {
+#endif
+ switch (errno) {
+ case EINTR:
+ goto retry;
+
+ case ENOENT:
+ case ENOLINK:
+ case ELOOP:
+ case EMULTIHOP:
+ case ENOTDIR:
+ errno = EPFNOSUPPORT;
+ break;
+ }
+ endnetconfig(nethandle); /* finished with netconfig struct */
+ return (-1);
+ }
+ if (!S_ISCHR(stats.st_mode)) {
+ errno = EPFNOSUPPORT;
+ endnetconfig(nethandle); /* finished with netconfig struct */
+ return (-1);
+ }
+ *pathp = malloc(strlen(net->nc_device) + 1);
+ if (*pathp == NULL) {
+ endnetconfig(nethandle);
+ errno = ENOMEM;
+ return (-1);
+ }
+ (void) strcpy(*pathp, net->nc_device);
+ endnetconfig(nethandle); /* finished with netconfig struct */
+ return (0);
+}
+
+/*
+ * Match config entry for protocol
+ * requested.
+ */
+static struct netconfig *
+_s_match_netconf(int family, int type, int proto, void **nethandle)
+{
+ struct netconfig *net;
+ struct netconfig *maybe;
+ char *oproto;
+
+ if (family < 0 ||
+ family >= (int)sizeof (family_sw) / (int)sizeof (char *) ||
+ proto < 0 || proto >= IPPROTO_MAX) {
+ errno = EPROTONOSUPPORT;
+ return (NULL);
+ }
+ if (proto) {
+ if (proto >= (int)sizeof (proto_sw) / (int)sizeof (char *))
+ oproto = "";
+ else oproto = proto_sw[proto];
+ }
+
+ /*
+ * Loop through each entry in netconfig
+ * until one matches or we reach the end.
+ */
+ if ((*nethandle = setnetconfig()) == NULL) {
+ return (NULL);
+ }
+
+ maybe = NULL;
+ while ((net = getnetconfig(*nethandle)) != NULL) {
+ /*
+ * We make a copy of net->nc_semantics rather than modifying
+ * it in place because the network selection code shares the
+ * structures returned by getnetconfig() among all its callers.
+ * See bug #1160886 for more details.
+ */
+ unsigned int semantics = net->nc_semantics;
+
+ if (semantics == NC_TPI_COTS_ORD)
+ semantics = NC_TPI_COTS;
+ if (proto) {
+ if (strcmp(net->nc_protofmly, family_sw[family]) == 0 &&
+ semantics == type &&
+ strcmp(net->nc_proto, oproto) == 0)
+ break;
+
+ if (strcmp(net->nc_protofmly, family_sw[family]) == 0 &&
+ type == SOCK_RAW &&
+ semantics == SOCK_RAW &&
+ strcmp(net->nc_proto, NC_NOPROTO) == 0 &&
+ maybe == NULL)
+ maybe = net; /* in case no exact match */
+
+ continue;
+ } else {
+ if (strcmp(net->nc_protofmly, family_sw[family]) == 0 &&
+ semantics == type) {
+ break;
+ }
+ }
+ }
+ if (net == NULL && maybe)
+ net = maybe;
+
+ if (net == NULL) {
+ endnetconfig(*nethandle);
+ errno = EPROTONOSUPPORT;
+ return (NULL);
+ }
+
+ return (net);
+}
diff --git a/usr/src/lib/libsocket/socket/sockatmark.c b/usr/src/lib/libsocket/socket/sockatmark.c
new file mode 100644
index 0000000000..9f30e1bbd3
--- /dev/null
+++ b/usr/src/lib/libsocket/socket/sockatmark.c
@@ -0,0 +1,46 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/sockio.h>
+#include <unistd.h>
+
+#pragma weak sockatmark = _sockatmark
+
+/*
+ * Determine whether the socket is at the out-of-band
+ * data mark.
+ */
+int
+_sockatmark(int sock)
+{
+ int val;
+
+ if (ioctl(sock, SIOCATMARK, &val) == -1)
+ return (-1);
+ return (val);
+}
diff --git a/usr/src/lib/libsocket/socket/socket.c b/usr/src/lib/libsocket/socket/socket.c
new file mode 100644
index 0000000000..3e99ed4900
--- /dev/null
+++ b/usr/src/lib/libsocket/socket/socket.c
@@ -0,0 +1,156 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1997 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * University Copyright- Copyright (c) 1982, 1986, 1988
+ * The Regents of the University of California
+ * All Rights Reserved
+ *
+ * University Acknowledgment- Portions of this document are derived from
+ * software developed by the University of California, Berkeley, and its
+ * contributors.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stropts.h>
+#include <sys/stream.h>
+#include <sys/socketvar.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+extern int _so_socket();
+extern int _s_netconfig_path();
+extern int _setsockopt();
+
+int _socket_create(int, int, int, int);
+
+#pragma weak socket = _socket
+
+int
+_socket(int family, int type, int protocol)
+{
+ return (_socket_create(family, type, protocol, SOV_DEFAULT));
+}
+
+/*
+ * Used by the BCP library.
+ */
+int
+_socket_bsd(int family, int type, int protocol)
+{
+ return (_socket_create(family, type, protocol, SOV_SOCKBSD));
+}
+
+int
+_socket_svr4(int family, int type, int protocol)
+{
+ return (_socket_create(family, type, protocol, SOV_SOCKSTREAM));
+}
+
+int
+__xnet_socket(int family, int type, int protocol)
+{
+ return (_socket_create(family, type, protocol, SOV_XPG4_2));
+}
+
+/*
+ * Create a socket endpoint for socket() and socketpair().
+ * In SunOS 4.X and in SunOS 5.X prior to XPG 4.2 the only error
+ * that could be returned due to invalid <family, type, protocol>
+ * was EPROTONOSUPPORT. (While the SunOS 4.X source contains EPROTOTYPE
+ * error as well that error can only be generated if the kernel is
+ * incorrectly configured.)
+ * For backwards compatibility only applications that request XPG 4.2
+ * (through c89 or XOPEN_SOURCE) will get EPROTOTYPE or EAFNOSUPPORT errors.
+ */
+int
+_socket_create(int family, int type, int protocol, int version)
+{
+ int fd;
+
+ /*
+ * Try creating without knowing the device assuming that
+ * the transport provider is registered in /etc/sock2path.
+ * If none found fall back to using /etc/netconfig to look
+ * up the name of the transport device name. This provides
+ * backwards compatibility for transport providers that have not
+ * yet been converted to using /etc/sock2path.
+ * XXX When all transport providers use /etc/sock2path this
+ * part of the code can be removed.
+ */
+ fd = _so_socket(family, type, protocol, NULL, version);
+ if (fd == -1) {
+ char *devpath;
+ int saved_errno = errno;
+ int prototype = 0;
+
+ switch (saved_errno) {
+ case EAFNOSUPPORT:
+ case EPROTOTYPE:
+ if (version != SOV_XPG4_2)
+ saved_errno = EPROTONOSUPPORT;
+ break;
+ case EPROTONOSUPPORT:
+ break;
+
+ default:
+ errno = saved_errno;
+ return (-1);
+ }
+ if (_s_netconfig_path(family, type, protocol,
+ &devpath, &prototype) == -1) {
+ errno = saved_errno;
+ return (-1);
+ }
+ fd = _so_socket(family, type, protocol, devpath, version);
+ free(devpath);
+ if (fd == -1) {
+ errno = saved_errno;
+ return (-1);
+ }
+ if (prototype != 0) {
+ if (_setsockopt(fd, SOL_SOCKET, SO_PROTOTYPE,
+ (caddr_t)&prototype, (int)sizeof (prototype)) < 0) {
+ (void) close(fd);
+ /*
+ * setsockopt often fails with ENOPROTOOPT
+ * but socket() should fail with
+ * EPROTONOSUPPORT.
+ */
+ errno = EPROTONOSUPPORT;
+ return (-1);
+ }
+ }
+ }
+ return (fd);
+}
diff --git a/usr/src/lib/libsocket/socket/socketpair.c b/usr/src/lib/libsocket/socket/socketpair.c
new file mode 100644
index 0000000000..d9bbc8f461
--- /dev/null
+++ b/usr/src/lib/libsocket/socket/socketpair.c
@@ -0,0 +1,130 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1997 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * University Copyright- Copyright (c) 1982, 1986, 1988
+ * The Regents of the University of California
+ * All Rights Reserved
+ *
+ * University Acknowledgment- Portions of this document are derived from
+ * software developed by the University of California, Berkeley, and its
+ * contributors.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stropts.h>
+#include <sys/stream.h>
+#include <sys/socketvar.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+extern int _socket_create(int, int, int, int);
+extern int _so_socketpair(int*);
+
+int _socketpair_create(int, int, int, int*, int);
+
+#pragma weak socketpair = _socketpair
+
+int
+_socketpair(int family, int type, int protocol, int sv[2])
+{
+ return (_socketpair_create(family, type, protocol, sv, SOV_DEFAULT));
+}
+
+/*
+ * Used by the BCP library.
+ */
+int
+_socketpair_bsd(int family, int type, int protocol, int sv[2])
+{
+ return (_socketpair_create(family, type, protocol, sv, SOV_SOCKBSD));
+}
+
+int
+_socketpair_svr4(int family, int type, int protocol, int sv[2])
+{
+ return (_socketpair_create(family, type, protocol, sv,
+ SOV_SOCKSTREAM));
+}
+
+int
+__xnet_socketpair(int family, int type, int protocol, int sv[2])
+{
+ return (_socketpair_create(family, type, protocol, sv,
+ SOV_XPG4_2));
+}
+
+int
+_socketpair_create(int family, int type, int protocol, int sv[2], int version)
+{
+ int res;
+ int fd1, fd2;
+
+ /*
+ * Create the two sockets and pass them to _so_socketpair, which
+ * will connect them together.
+ */
+ fd1 = _socket_create(family, type, protocol, version);
+ if (fd1 < 0)
+ return (-1);
+ fd2 = _socket_create(family, type, protocol, version);
+ if (fd2 < 0) {
+ int error = errno;
+
+ (void) close(fd1);
+ errno = error;
+ return (-1);
+ }
+ sv[0] = fd1;
+ sv[1] = fd2;
+ res = _so_socketpair(sv);
+ if (res < 0) {
+ int error = errno;
+
+ (void) close(fd1);
+ (void) close(fd2);
+ errno = error;
+ return (-1);
+ }
+ /*
+ * Check if kernel returned different fds in which case we close
+ * the original ones. This is the case for SOCK_STREAM where
+ * one of the original sockets is used as a listener and
+ * _so_socketpair passes out the newly accepted socket.
+ */
+ if (sv[0] != fd1)
+ (void) close(fd1);
+ if (sv[1] != fd2)
+ (void) close(fd2);
+ return (res);
+}
diff --git a/usr/src/lib/libsocket/socket/weaks.c b/usr/src/lib/libsocket/socket/weaks.c
new file mode 100644
index 0000000000..ddca64c410
--- /dev/null
+++ b/usr/src/lib/libsocket/socket/weaks.c
@@ -0,0 +1,264 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stropts.h>
+#include <sys/stream.h>
+#include <sys/socketvar.h>
+#include <sys/sockio.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stropts.h>
+#include <stdio.h>
+#include <strings.h>
+#include <netinet/sctp.h>
+
+#pragma weak bind = _bind
+#pragma weak listen = _listen
+#pragma weak accept = _accept
+#pragma weak connect = _connect
+#pragma weak shutdown = _shutdown
+#pragma weak recv = _recv
+#pragma weak recvfrom = _recvfrom
+#pragma weak recvmsg = _recvmsg
+#pragma weak send = _send
+#pragma weak sendmsg = _sendmsg
+#pragma weak sendto = _sendto
+#pragma weak getpeername = _getpeername
+#pragma weak getsockname = _getsockname
+#pragma weak getsockopt = _getsockopt
+#pragma weak setsockopt = _setsockopt
+
+extern int _so_bind();
+extern int _so_listen();
+extern int _so_accept();
+extern int _so_connect();
+extern int _so_shutdown();
+extern int _so_recv();
+extern int _so_recvfrom();
+extern int _so_recvmsg();
+extern int _so_send();
+extern int _so_sendmsg();
+extern int _so_sendto();
+extern int _so_getpeername();
+extern int _so_getsockopt();
+extern int _so_setsockopt();
+extern int _so_setsockname();
+extern int _so_getsockname();
+
+/*
+ * Note that regular sockets use SOV_SOCKBSD here to not allow a rebind of an
+ * already bound socket.
+ */
+int
+_bind(int sock, struct sockaddr *addr, int addrlen)
+{
+ return (_so_bind(sock, addr, addrlen, SOV_SOCKBSD));
+}
+
+int
+_listen(int sock, int backlog)
+{
+ return (_so_listen(sock, backlog, SOV_DEFAULT));
+}
+
+int
+_accept(int sock, struct sockaddr *addr, int *addrlen)
+{
+ return (_so_accept(sock, addr, addrlen, SOV_DEFAULT));
+}
+
+int
+_connect(int sock, struct sockaddr *addr, int addrlen)
+{
+ return (_so_connect(sock, addr, addrlen, SOV_DEFAULT));
+}
+
+int
+_shutdown(int sock, int how)
+{
+ return (_so_shutdown(sock, how, SOV_DEFAULT));
+}
+
+int
+_recv(int sock, char *buf, int len, int flags)
+{
+ return (_so_recv(sock, buf, len, flags & ~MSG_XPG4_2));
+}
+
+int
+_recvfrom(int sock, char *buf, int len, int flags,
+ struct sockaddr *addr, int *addrlen)
+{
+ return (_so_recvfrom(sock, buf, len, flags & ~MSG_XPG4_2,
+ addr, addrlen));
+}
+
+int
+_recvmsg(int sock, struct msghdr *msg, int flags)
+{
+ return (_so_recvmsg(sock, msg, flags & ~MSG_XPG4_2));
+}
+
+int
+_send(int sock, char *buf, int len, int flags)
+{
+ return (_so_send(sock, buf, len, flags & ~MSG_XPG4_2));
+}
+
+int
+_sendmsg(int sock, struct msghdr *msg, int flags)
+{
+ return (_so_sendmsg(sock, msg, flags & ~MSG_XPG4_2));
+}
+
+int
+_sendto(int sock, char *buf, int len, int flags,
+ struct sockaddr *addr, int *addrlen)
+{
+ return (_so_sendto(sock, buf, len, flags & ~MSG_XPG4_2,
+ addr, addrlen));
+}
+
+int
+_getpeername(int sock, struct sockaddr *name, int *namelen)
+{
+ return (_so_getpeername(sock, name, namelen, SOV_DEFAULT));
+}
+
+int
+_getsockname(int sock, struct sockaddr *name, int *namelen)
+{
+ return (_so_getsockname(sock, name, namelen, SOV_DEFAULT));
+}
+
+int
+_getsockopt(int sock, int level, int optname, char *optval, int *optlen)
+{
+ if (level == IPPROTO_SCTP) {
+ sctp_assoc_t id = 0;
+ socklen_t len = *optlen;
+ int err = 0;
+ struct sctpopt sopt;
+
+ switch (optname) {
+ case SCTP_RTOINFO:
+ case SCTP_ASSOCINFO:
+ case SCTP_SET_PEER_PRIMARY_ADDR:
+ case SCTP_PRIMARY_ADDR:
+ case SCTP_PEER_ADDR_PARAMS:
+ case SCTP_STATUS:
+ case SCTP_GET_PEER_ADDR_INFO:
+ /*
+ * Association ID is the first element params struct
+ */
+ bcopy(optval, &id, sizeof (id));
+ break;
+ case SCTP_DEFAULT_SEND_PARAM:
+ bcopy(&((struct sctp_sndrcvinfo *)
+ optval)->sinfo_assoc_id, &id, sizeof (id));
+ break;
+ }
+
+ sopt.sopt_aid = id;
+ sopt.sopt_name = optname;
+ sopt.sopt_val = optval;
+ sopt.sopt_len = len;
+ if (ioctl(sock, SIOCSCTPGOPT, &sopt) == -1) {
+ err = -1;
+ } else {
+ *optlen = sopt.sopt_len;
+ }
+ return (err);
+ } else {
+ return (_so_getsockopt(sock, level, optname, optval, optlen,
+ SOV_DEFAULT));
+ }
+}
+
+int
+_setsockopt(int sock, int level, int optname, char *optval, int optlen)
+{
+ return (_so_setsockopt(sock, level, optname, optval, optlen,
+ SOV_DEFAULT));
+}
+
+int
+__xnet_bind(int sock, const struct sockaddr *addr, socklen_t addrlen)
+{
+ return (_so_bind(sock, addr, addrlen, SOV_XPG4_2));
+}
+
+
+int
+__xnet_listen(int sock, int backlog)
+{
+ return (_so_listen(sock, backlog, SOV_XPG4_2));
+}
+
+int
+__xnet_connect(int sock, const struct sockaddr *addr, socklen_t addrlen)
+{
+ return (_so_connect(sock, addr, addrlen, SOV_XPG4_2));
+}
+
+int
+__xnet_recvmsg(int sock, struct msghdr *msg, int flags)
+{
+ return (_so_recvmsg(sock, msg, flags | MSG_XPG4_2));
+}
+
+int
+__xnet_sendmsg(int sock, const struct msghdr *msg, int flags)
+{
+ return (_so_sendmsg(sock, msg, flags | MSG_XPG4_2));
+}
+
+int
+__xnet_sendto(int sock, const void *buf, size_t len, int flags,
+ const struct sockaddr *addr, socklen_t addrlen)
+{
+ return (_so_sendto(sock, buf, len, flags | MSG_XPG4_2,
+ addr, addrlen));
+}
+
+int
+__xnet_getsockopt(int sock, int level, int option_name,
+ void *option_value, socklen_t *option_lenp)
+{
+ if (level == IPPROTO_SCTP) {
+ return (_getsockopt(sock, level, option_name, option_value,
+ (int *)option_lenp));
+ } else {
+ return (_so_getsockopt(sock, level, option_name, option_value,
+ option_lenp, SOV_XPG4_2));
+ }
+}
diff --git a/usr/src/lib/libsocket/sparc/Makefile b/usr/src/lib/libsocket/sparc/Makefile
new file mode 100644
index 0000000000..c3ea53cfe4
--- /dev/null
+++ b/usr/src/lib/libsocket/sparc/Makefile
@@ -0,0 +1,33 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright (c) 1997-2001 by Sun Microsystems, Inc.
+# All rights reserved.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+all: $(LIBS)
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/libsocket/sparcv9/Makefile b/usr/src/lib/libsocket/sparcv9/Makefile
new file mode 100644
index 0000000000..2eafde412a
--- /dev/null
+++ b/usr/src/lib/libsocket/sparcv9/Makefile
@@ -0,0 +1,34 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 1997-2003 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+include ../../Makefile.lib.64
+
+all: $(LIBS)
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64)
diff --git a/usr/src/lib/libsocket/spec/Makefile b/usr/src/lib/libsocket/spec/Makefile
new file mode 100644
index 0000000000..e64c72ecb3
--- /dev/null
+++ b/usr/src/lib/libsocket/spec/Makefile
@@ -0,0 +1,29 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright (c) 1998-1999 by Sun Microsystems, Inc.
+# All rights reserved.
+#
+# lib/libsocket/spec/Makefile
+
+include $(SRC)/lib/Makefile.spec.arch
diff --git a/usr/src/lib/libsocket/spec/Makefile.targ b/usr/src/lib/libsocket/spec/Makefile.targ
new file mode 100644
index 0000000000..9cc59c24e7
--- /dev/null
+++ b/usr/src/lib/libsocket/spec/Makefile.targ
@@ -0,0 +1,36 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright (c) 1998-1999 by Sun Microsystems, Inc.
+# All rights reserved.
+#
+# lib/libsocket/spec/Makefile.targ
+
+LIBRARY = libsocket.a
+VERS = .1
+
+OBJECTS = socket.o \
+ svr4msg.o \
+ xpgmsg.o
+
+SPECCPP = -I..
diff --git a/usr/src/lib/libsocket/spec/amd64/Makefile b/usr/src/lib/libsocket/spec/amd64/Makefile
new file mode 100644
index 0000000000..453c0ea671
--- /dev/null
+++ b/usr/src/lib/libsocket/spec/amd64/Makefile
@@ -0,0 +1,44 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+.KEEP_STATE:
+
+include ../Makefile.targ
+
+# Add arch specific objects here
+OBJECTS +=
+
+include $(SRC)/lib/Makefile.lib
+include $(SRC)/lib/Makefile.lib.64
+
+# Uncomment the following if the linker complains
+#amd64_C_PICFLAGS = -K PIC
+
+include $(SRC)/lib/Makefile.spec
+
+install: $(ROOTABILIB64)
diff --git a/usr/src/lib/libsocket/spec/i386/Makefile b/usr/src/lib/libsocket/spec/i386/Makefile
new file mode 100644
index 0000000000..e5a8b4318a
--- /dev/null
+++ b/usr/src/lib/libsocket/spec/i386/Makefile
@@ -0,0 +1,44 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright (c) 1998-1999 by Sun Microsystems, Inc.
+# All rights reserved.
+#
+# lib/libsocket/spec/i386/Makefile
+
+.KEEP_STATE:
+
+include ../Makefile.targ
+
+# Add arch specific objects here
+OBJECTS +=
+
+include $(SRC)/lib/Makefile.lib
+
+# Uncomment the following if the linker complains
+#i386_C_PICFLAGS = -K PIC
+
+include $(SRC)/lib/Makefile.spec
+
+install: $(ROOTABILIB)
diff --git a/usr/src/lib/libsocket/spec/socket.spec b/usr/src/lib/libsocket/spec/socket.spec
new file mode 100644
index 0000000000..bb614f918b
--- /dev/null
+++ b/usr/src/lib/libsocket/spec/socket.spec
@@ -0,0 +1,895 @@
+#
+# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+# NOTE: Look at "versions" file for more details on why there may
+# appear to be "gaps" in version number space.
+
+function endservent
+include <netdb.h>
+declaration int endservent(void)
+version SUNW_0.7
+end
+
+function __xnet_bind
+include <sys/types.h>, <sys/socket.h>
+declaration int __xnet_bind(int socket, const struct sockaddr *address, \
+ socklen_t address_len)
+version SUNW_1.1
+errno EACCES EADDRINUSE EADDRNOTAVAIL EBADF EINVAL ENOSR \
+ ENOTSOCK EIO EISDIR ELOOP ENOENT ENOTDIR EROFS
+exception
+end
+
+function __xnet_connect
+include <sys/types.h>, <sys/socket.h>
+declaration int __xnet_connect(int socket, const struct sockaddr *address, \
+ socklen_t address_len)
+version SUNW_1.1
+errno EACCES EADDRINUSE EADDRNOTAVAIL EAFNOSUPPORT EALREADY EBADF \
+ ECONNREFUSED EINPROGRESS EINTR EINVAL EIO EISCONN ELOOP \
+ ENETUNREACH ENOENT ENOSR ENXIO ETIMEDOUT ENOTDIR \
+ ENOTSOCK EPROTOTYPE
+exception $return == -1
+end
+
+function __xnet_getsockopt
+include <sys/types.h>, <sys/socket.h>
+declaration int __xnet_getsockopt(int socket, int level, \
+ int option_name, void *option_value, \
+ Psocklen_t option_len)
+version SUNW_1.1
+errno EBADF ENOPROTOOPT ENOTSOCK EINVAL EOPNOTSUPP ENOBUFS ENOSR
+exception $return == -1
+end
+
+function __xnet_listen
+include <sys/types.h>, <sys/socket.h>
+declaration int __xnet_listen(int socket, int backlog)
+version SUNW_1.1
+errno EBADF ENOTSOCK EOPNOTSUPP EINVAL EDESTADDRREQ ENOBUFS
+exception $return == -1
+end
+
+function __xnet_sendto
+include <sys/types.h>, <sys/socket.h>
+declaration int __xnet_sendto(int socket, const void *message, \
+ size_t length, int flags, \
+ const struct sockaddr *dest_addr, size_t dest_len)
+version SUNW_1.1
+errno EAFNOSUPPORT EBADF ECONNRESET EINTR EMSGSIZE ENOTCONN \
+ ENOTSOCK EOPNOTSUPP EPIPE EWOULDBLOCK EAGAIN EACCES \
+ EIO ELOOP ENAMETOOLONG ENOENT ENOTDIR EDESTADDRREQ \
+ EHOSTUNREACH EISCONN ENETDOWN ENETUNREACH ENOBUFS \
+ ENOMEM ENOSR
+exception $return == -1
+end
+
+function __xnet_socket
+include <sys/types.h>, <sys/socket.h>
+declaration int __xnet_socket(int domain, int type, int protocol)
+version SUNW_1.1
+errno EACCES EAFNOSUPPORT EMFILE ENFILE EPROTONOSUPPORT EPROTOTYPE \
+ ENOBUFS ENOMEM ENOSR
+exception $return == -1
+end
+
+function __xnet_socketpair
+include <sys/types.h>, <sys/socket.h>
+declaration int __xnet_socketpair(int domain, int type, int protocol, \
+ int socket_vector[2])
+version SUNW_1.1
+errno EAFNOSUPPORT EMFILE ENFILE EOPNOTSUPP EPROTONOSUPPORT \
+ EPROTOTYPE EACCES ENOMEM ENOBUFS ENOSR
+exception $return == -1
+end
+
+function accept
+include <sys/types.h>, <sys/socket.h>
+declaration int accept(int s, struct sockaddr *addr, void *addrlen)
+version i386=SUNW_0.7 sparc=SISCD_2.3 sparcv9=SUNW_0.7 amd64=SUNW_0.7
+errno EBADF EINTR ENODEV ENOMEM ENOSR ENOTSOCK EOPNOTSUPP EPROTO \
+ EWOULDBLOCK
+exception $return == -1
+end
+
+function bind
+include <sys/types.h>, <sys/socket.h>
+declaration int bind(int s, const struct sockaddr *name, socklen_t namelen)
+version i386=SUNW_0.7 sparc=SISCD_2.3 sparcv9=SUNW_0.7 amd64=SUNW_0.7
+errno EACCES EADDRINUSE EADDRNOTAVAIL EBADF EINVAL ENOSR ENOTSOCK \
+ EIO EISDIR ELOOP ENOENT ENOTDIR EROFS
+exception
+end
+
+function bindresvport
+version SUNWprivate_1.1
+end
+
+function connect
+include <sys/types.h>, <sys/socket.h>
+declaration int connect(int s, const struct sockaddr *name, \
+ socklen_t namelen)
+version i386=SUNW_0.7 sparc=SISCD_2.3 sparcv9=SUNW_0.7 amd64=SUNW_0.7
+errno EACCES EADDRINUSE EADDRNOTAVAIL EAFNOSUPPORT EALREADY EBADF \
+ ECONNREFUSED EINPROGRESS EINTR EINVAL EIO EISCONN \
+ ELOOP ENETUNREACH ENOENT ENOSR ENXIO ETIMEDOUT \
+ ENOTDIR ENOTSOCK EPROTOTYPE
+exception $return == -1
+end
+
+function endnetent
+include <netdb.h>
+declaration int endnetent(void)
+version SUNW_0.7
+exception $return == -1
+end
+
+function endprotoent
+include <netdb.h>
+declaration int endprotoent(void)
+version SUNW_0.7
+errno ERANGE
+end
+
+function ether_aton
+include <sys/types.h>
+include <sys/socket.h>
+include <net/if.h>
+include <netinet/in.h>
+include <netinet/if_ether.h>
+declaration struct ether_addr *ether_aton (const char *s)
+version SUNW_0.7
+exception
+end
+
+function ether_hostton
+include <sys/types.h>
+include <sys/socket.h>
+include <net/if.h>
+include <netinet/in.h>
+include <netinet/if_ether.h>
+declaration int ether_hostton (const char *hostname, struct ether_addr *e)
+version SUNW_0.7
+exception
+end
+
+function ether_line
+include <sys/types.h>
+include <sys/socket.h>
+include <net/if.h>
+include <netinet/in.h>
+include <netinet/if_ether.h>
+declaration int ether_line (const char *l, struct ether_addr *e, \
+ char *hostname)
+version SUNW_0.7
+exception
+end
+
+function ether_ntoa
+include <sys/types.h>
+include <sys/socket.h>
+include <net/if.h>
+include <netinet/in.h>
+include <netinet/if_ether.h>
+declaration char *ether_ntoa (const struct ether_addr *e)
+version SUNW_0.7
+exception
+end
+
+function ether_ntohost
+include <sys/types.h>
+include <sys/socket.h>
+include <net/if.h>
+include <netinet/in.h>
+include <netinet/if_ether.h>
+declaration int ether_ntohost (char *hostname, const struct ether_addr *e)
+version SUNW_0.7
+exception
+end
+
+function freeaddrinfo
+include <sys/socket.h>
+include <netdb.h>
+declaration void freeaddrinfo(struct addrinfo *ai)
+version SUNW_1.4
+end
+
+function gai_strerror
+include <sys/socket.h>
+include <netdb.h>
+declaration const char *gai_strerror(int ecode)
+version SUNW_1.4
+end
+
+function getaddrinfo
+include <sys/socket.h>
+include <netdb.h>
+declaration int getaddrinfo(const char *hostname, const char *servname, \
+ const struct addrinfo *hints, struct addrinfo **res)
+version SUNW_1.4
+exception $return != 0
+end
+
+function __xnet_getaddrinfo
+include <sys/socket.h>
+include <netdb.h>
+declaration int __xnet_getaddrinfo(const char *hostname, \
+ const char *servname, const struct addrinfo *hints, \
+ struct addrinfo **res)
+version SUNW_1.5
+exception $return != 0
+end
+
+function getnameinfo
+include <sys/socket.h>
+include <netdb.h>
+declaration int getnameinfo(const struct sockaddr *sa, socklen_t salen, \
+ char *host, socklen_t hostlen, char *serv, \
+ socklen_t servlen, int flags)
+version SUNW_1.4
+exception $return != 0
+end
+
+function getnetbyaddr
+include <netdb.h>
+declaration struct netent *getnetbyaddr(in_addr_t net, int type)
+version SUNW_0.7
+exception $return == 0
+end
+
+function getnetbyaddr_r
+include <netdb.h>
+declaration struct netent *getnetbyaddr_r(long net, int type, \
+ struct netent *result, char *buffer, int buflen)
+version SUNW_0.7
+exception $return == 0
+end
+
+function getnetbyname
+include <netdb.h>
+declaration struct netent *getnetbyname(const char *name)
+version SUNW_0.7
+exception $return == 0
+end
+
+function getnetbyname_r
+include <netdb.h>
+declaration struct netent *getnetbyname_r(const char *name, \
+ struct netent *result, char *buffer, int buflen)
+version SUNW_0.7
+exception $return == 0
+end
+
+function getnetent
+include <netdb.h>
+declaration struct netent *getnetent(void)
+version SUNW_0.7
+exception $return == 0
+end
+
+function getnetent_r
+include <netdb.h>
+declaration struct netent *getnetent_r(struct netent *result, \
+ char *buffer, int buflen)
+version SUNW_0.7
+exception $return == 0
+end
+
+function getpeername
+include <sys/socket.h>
+declaration int getpeername(int s, struct sockaddr *name, \
+ Psocklen_t namelen)
+version i386=SUNW_0.7 sparc=SISCD_2.3 sparcv9=SUNW_0.7 amd64=SUNW_0.7
+errno EBADF ENOMEM ENOSR ENOTCONN ENOTSOCK
+exception $return == -1
+end
+
+function getprotobyname
+include <netdb.h>
+declaration struct protoent *getprotobyname(const char *name)
+version i386=SUNW_0.7 sparc=SISCD_2.3 sparcv9=SUNW_0.7 amd64=SUNW_0.7
+errno ERANGE
+exception $return == 0
+end
+
+function getprotobyname_r
+include <netdb.h>
+declaration struct protoent *getprotobyname_r(const char *name, \
+ struct protoent *result, char *buffer, int buflen)
+version SUNW_0.7
+errno ERANGE
+exception $return == 0
+end
+
+function getprotobynumber
+include <netdb.h>
+declaration struct protoent *getprotobynumber(int proto)
+version i386=SUNW_0.7 sparc=SISCD_2.3 sparcv9=SUNW_0.7 amd64=SUNW_0.7
+errno ERANGE
+exception $return == 0
+end
+
+function getprotobynumber_r
+include <netdb.h>
+declaration struct protoent *getprotobynumber_r(int proto, \
+ struct protoent *result, char *buffer, int buflen)
+version SUNW_0.7
+errno ERANGE
+exception $return == 0
+end
+
+function getprotoent
+include <netdb.h>
+declaration struct protoent *getprotoent(void)
+version i386=SUNW_0.7 sparc=SISCD_2.3 sparcv9=SUNW_0.7 amd64=SUNW_0.7
+errno ERANGE
+exception $return == 0
+end
+
+function getprotoent_r
+include <netdb.h>
+declaration struct protoent *getprotoent_r(struct protoent *result, \
+ char *buffer, int buflen)
+version SUNW_0.7
+errno ERANGE
+exception $return == 0
+end
+
+function getservbyname
+include <netdb.h>
+declaration struct servent *getservbyname(const char *name, \
+ const char *proto)
+version i386=SUNW_0.7 sparc=SISCD_2.3 sparcv9=SUNW_0.7 amd64=SUNW_0.7
+exception $return == 0
+end
+
+function getservbyname_r
+include <netdb.h>
+declaration struct servent *getservbyname_r(const char *name, \
+ const char *proto, struct servent *result, \
+ char *buffer, int buflen)
+version SUNW_0.7
+exception $return == 0
+end
+
+function getservbyport
+include <netdb.h>
+declaration struct servent *getservbyport(int port, const char *proto)
+version i386=SUNW_0.7 sparc=SISCD_2.3 sparcv9=SUNW_0.7 amd64=SUNW_0.7
+exception $return == 0
+end
+
+function getservbyport_r
+include <netdb.h>
+declaration struct servent *getservbyport_r(int port, const char *proto, \
+ struct servent *result, char *buffer, int buflen)
+version SUNW_0.7
+exception $return == 0
+end
+
+function getservent
+include <netdb.h>
+declaration struct servent *getservent(void)
+version SUNW_0.7
+exception $return == 0
+end
+
+function getservent_r
+include <netdb.h>
+declaration struct servent *getservent_r(struct servent *result, \
+ char *buffer, int buflen)
+version SUNW_0.7
+exception $return == 0
+end
+
+function getsockname
+include <sys/types.h>
+include <sys/socket.h>
+declaration int getsockname(int s, struct sockaddr *name, void *namelen)
+version i386=SUNW_0.7 sparc=SISCD_2.3 sparcv9=SUNW_0.7 amd64=SUNW_0.7
+errno EBADF ENOMEM ENOSR ENOTSOCK
+exception $return == -1
+end
+
+function getsockopt
+include <sys/types.h>
+include <sys/socket.h>
+declaration int getsockopt(int s, int level, int optname, void *optval, \
+ void *optlen)
+version i386=SUNW_0.7 sparc=SISCD_2.3 sparcv9=SUNW_0.7 amd64=SUNW_0.7
+errno EBADF ENOMEM ENOPROTOOPT ENOSR ENOTSOCK
+exception $return == -1
+end
+
+function getsourcefilter
+include <netinet/in.h>
+declaration int getsourcefilter(int s, uint32_t interface, \
+ struct sockaddr *group, socklen_t grouplen, \
+ uint32_t *fmode, uint_t *numsrc, \
+ struct sockaddr_storage *slist)
+version SUNW_1.6
+errno EBADF ENOPROTOOPT ENOSR ENOTSOCK ENXIO EADDRNOTAVAIL
+exception $return == -1
+end
+
+function getipv4sourcefilter
+include <netinet/in.h>
+declaration int getipv4sourcefilter(int s, struct in_addr interface, \
+ struct in_addr group, uint32_t *fmode, \
+ uint32_t *numsrc, struct in_addr *slist)
+version SUNW_1.6
+errno EBADF ENOPROTOOPT ENOSR ENOTSOCK ENXIO EADDRNOTAVAIL
+exception $return == -1
+end
+
+function htonl
+include <sys/types.h>
+include <netinet/in.h>
+include <inttypes.h>
+declaration uint32_t htonl(uint32_t hostlong)
+version SUNW_0.7
+end
+
+function htons
+include <sys/types.h>
+include <netinet/in.h>
+include <inttypes.h>
+declaration uint16_t htons(uint16_t hostshort)
+version SUNW_0.7
+end
+
+function if_freenameindex
+include <net/if.h>
+declaration void if_freenameindex(struct if_nameindex *ptr)
+version SUNW_1.4
+end
+
+function if_indextoname
+include <net/if.h>
+declaration char *if_indextoname(uint32_t ifindex, char *ifname)
+version SUNW_1.4
+exception $return == 0
+end
+
+function if_nametoindex
+include <net/if.h>
+declaration uint32_t if_nametoindex(const char *ifname)
+version SUNW_1.4
+exception $return == 0
+end
+
+function if_nameindex
+include <net/if.h>
+declaration struct if_nameindex *if_nameindex(void)
+version SUNW_1.4
+exception $return == 0
+end
+
+data in6addr_any
+declaration const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT
+version SUNW_1.4
+end
+
+data in6addr_loopback
+declaration const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT
+version SUNW_1.4
+end
+
+function inet_lnaof
+include <sys/types.h>
+include <netinet/in.h>
+declaration in_addr_t inet_lnaof(struct in_addr in)
+# see inet_lnaof inet (3n) - Internet address manipulation
+version i386=SUNW_0.7 sparc=SISCD_2.3 sparcv9=SUNW_0.7 amd64=SUNW_0.7
+end
+
+function inet_makeaddr
+include <sys/types.h>
+include <netinet/in.h>
+declaration struct in_addr inet_makeaddr(in_addr_t net, in_addr_t lna)
+# see inet_makeaddr inet (3n) - Internet address manipulation
+version i386=SUNW_0.7 sparc=SISCD_2.3 sparcv9=SUNW_0.7 amd64=SUNW_0.7
+end
+
+function inet_network
+include <sys/types.h>
+include <netinet/in.h>
+declaration in_addr_t inet_network(const char *cp)
+# see inet_network inet (3n) - Internet address manipulation
+version i386=SUNW_0.7 sparc=SISCD_2.3 sparcv9=SUNW_0.7 amd64=SUNW_0.7
+end
+
+function listen
+include <sys/types.h>
+include <sys/socket.h>
+declaration int listen(int socket, int backlog)
+version i386=SUNW_0.7 sparc=SISCD_2.3 sparcv9=SUNW_0.7 amd64=SUNW_0.7
+errno EBADF ENOTSOCK EOPNOTSUPP EINVAL EDESTADDRREQ ENOBUFS
+exception $return == -1
+end
+
+function ntohl
+include <sys/types.h>
+include <netinet/in.h>
+include <inttypes.h>
+declaration uint32_t ntohl(uint32_t netlong)
+version SUNW_0.7
+end
+
+function ntohs
+include <sys/types.h>
+include <netinet/in.h>
+include <inttypes.h>
+declaration uint16_t ntohs(uint16_t netshort)
+version SUNW_0.7
+end
+
+function rcmd
+include <netdb.h>
+declaration int rcmd(char **ahost, unsigned short inport, \
+ const char *luser, const char *ruser, const char *cmd, \
+ int *fd2p)
+version SUNW_0.7
+exception $return == -1
+end
+
+function rcmd_af
+include <netdb.h>
+declaration int rcmd_af(char **ahost, unsigned short inport, \
+ const char *luser, const char *ruser, \
+ const char *cmd, int *fd2p, int af)
+version SUNW_1.4
+exception $return == -1
+end
+
+function recv
+include <sys/types.h>
+include <sys/socket.h>
+include <sys/uio.h>
+declaration ssize_t recv(int s, void *buf, size_t len, int flags)
+version i386=SUNW_0.7 sparc=SISCD_2.3 sparcv9=SUNW_0.7 amd64=SUNW_0.7
+errno EBADF EINTR EIO ENOMEM ENOSR ENOTSOCK ESTALE EWOULDBLOCK
+exception $return == -1
+end
+
+function recvfrom
+include <sys/types.h>
+include <sys/socket.h>
+include <sys/uio.h>
+declaration ssize_t recvfrom(int s, void *buf, size_t len, int flags, \
+ struct sockaddr *from, void *fromlen)
+version i386=SUNW_0.7 sparc=SISCD_2.3 sparcv9=SUNW_0.7 amd64=SUNW_0.7
+errno EBADF EINTR EIO ENOMEM ENOSR ENOTSOCK ESTALE EWOULDBLOCK
+exception $return == -1
+end
+
+function rexec
+include <netdb.h>
+declaration int rexec(char **ahost, unsigned short inport, \
+ const char *user, const char *passwd, const char *cmd, \
+ int *fd2p)
+version SUNW_0.7
+exception $return == -1
+end
+
+function rexec_af
+include <netdb.h>
+declaration int rexec_af(char **ahost, unsigned short inport, \
+ const char *user, const char *passwd, \
+ const char *cmd, int *fd2p, int af)
+version SUNW_1.4
+exception $return == -1
+end
+
+function rresvport
+include <netdb.h>
+declaration int rresvport(int *port)
+version SUNW_0.7
+exception $return == -1
+end
+
+function rresvport_af
+include <netdb.h>
+declaration int rresvport_af(int *alport, int af)
+version SUNW_1.4
+exception $return == -1
+end
+
+function rresvport_addr
+include <netdb.h>
+declaration int rresvport_addr(int *alport, struct sockaddr_storage *addr)
+version SUNWprivate_1.1
+exception $return == -1
+end
+
+function ruserok
+include <netdb.h>
+declaration int ruserok(const char *rhost, int suser, const char *ruser, \
+ const char *luser)
+version SUNW_0.7
+exception $return == -1
+end
+
+function send
+include <sys/types.h>
+include <sys/socket.h>
+declaration ssize_t send(int s, const void *msg, size_t len, int flags)
+version i386=SUNW_0.7 sparc=SISCD_2.3 sparcv9=SUNW_0.7 amd64=SUNW_0.7
+errno EBADF EINTR EINVAL EMSGSIZE ENOMEM ENOSR ENOTSOCK EWOULDBLOCK
+exception $return == -1
+end
+
+function sendto
+include <sys/types.h>
+include <sys/socket.h>
+declaration ssize_t sendto(int s, const void *msg, size_t len, int flags, \
+ const struct sockaddr *to, socklen_t tolen)
+version i386=SUNW_0.7 sparc=SISCD_2.3 sparcv9=SUNW_0.7 amd64=SUNW_0.7
+errno EBADF EINTR EINVAL EMSGSIZE ENOMEM ENOSR ENOTSOCK EWOULDBLOCK
+exception $return == -1
+end
+
+function setnetent
+include <netdb.h>
+declaration int setnetent(int stayopen)
+version SUNW_0.7
+exception $return == -1
+end
+
+function setprotoent
+include <netdb.h>
+declaration int setprotoent(int stayopen)
+version SUNW_0.7
+errno ERANGE
+end
+
+function setservent
+include <netdb.h>
+declaration int setservent(int stayopen)
+version SUNW_0.7
+exception $return == 0
+end
+
+function setsockopt
+include <sys/types.h>
+include <sys/socket.h>
+declaration int setsockopt(int s, int level, int optname, \
+ const void *optval, socklen_t optlen)
+version i386=SUNW_0.7 sparc=SISCD_2.3 sparcv9=SUNW_0.7 amd64=SUNW_0.7
+errno EBADF ENOMEM ENOPROTOOPT ENOSR ENOTSOCK
+exception $return == -1
+end
+
+function setsourcefilter
+include <netinet/in.h>
+declaration int setsourcefilter(int s, uint32_t interface, \
+ struct sockaddr *group, socklen_t grouplen, \
+ uint32_t fmode, uint_t numsrc, \
+ struct sockaddr_storage *slist)
+version SUNW_1.6
+errno EBADF ENOPROTOOPT ENOSR ENOTSOCK ENXIO ENOBUFS
+exception $return == -1
+end
+
+function setipv4sourcefilter
+include <netinet/in.h>
+declaration int setipv4sourcefilter(int s, struct in_addr interface, \
+ struct in_addr group, uint32_t fmode,
+ uint32_t numsrc, struct in_addr *slist)
+version SUNW_1.6
+errno EBADF ENOPROTOOPT ENOSR ENOTSOCK ENXIO ENOBUFS
+exception $return == -1
+end
+
+function shutdown
+declaration int shutdown(int s, int how)
+version i386=SUNW_0.7 sparc=SISCD_2.3 sparcv9=SUNW_0.7 amd64=SUNW_0.7
+errno EBADF ENOMEM ENOSR ENOTCONN ENOTSOCK
+exception $return == -1
+end
+
+function sockatmark
+declaration int sockatmark(int socket)
+version SUNW_1.5
+errno EBADF ENOTTY
+exception $return == -1
+end
+
+function socket
+include <sys/types.h>
+include <sys/socket.h>
+declaration int socket(int domain, int type, int protocol)
+version i386=SUNW_0.7 sparc=SISCD_2.3 sparcv9=SUNW_0.7 amd64=SUNW_0.7
+errno EACCES EMFILE ENOMEM ENOSR EPROTONOSUPPORT
+exception $return == -1
+end
+
+function socketpair
+include <sys/types.h>
+include <sys/socket.h>
+declaration int socketpair(int domain, int type, int protocol, int sv[2])
+version SUNW_0.7
+errno EAFNOSUPPORT EMFILE ENOMEM ENOSR EOPNOTSUPP EPROTONOSUPPORT
+exception $return == -1
+end
+
+function _link_ntoa
+include <net/if_dl.h>
+declaration char *_link_ntoa(const unsigned char *, char *, int, int)
+version SUNWprivate_1.3
+exception $return == 0
+end
+
+function _link_aton
+include <net/if_dl.h>
+declaration unsigned char *_link_aton(const char *, int *)
+version SUNWprivate_1.3
+exception $return == 0
+end
+
+# IPv6 routing header manipulation
+function inet6_rth_add
+include <netinet/in.h>
+declaration int inet6_rth_add(void *bp, const struct in6_addr *addr)
+version SUNW_1.5
+errno
+exception $return == -1
+end
+
+function inet6_rth_init
+include <netinet/in.h>
+declaration void *inet6_rth_init(void *bp, socklen_t bp_len, int type, int segments)
+version SUNW_1.5
+errno
+exception $return == 0
+end
+
+function inet6_rth_getaddr
+include <netinet/in.h>
+declaration struct in6_addr *inet6_rth_getaddr(const void *bp, int index)
+version SUNW_1.5
+errno
+exception $return == 0
+end
+
+function inet6_rth_reverse
+include <netinet/in.h>
+declaration int inet6_rth_reverse(const void *in, void *out)
+version SUNW_1.5
+errno
+exception $return == -1
+end
+
+function inet6_rth_segments
+include <netinet/in.h>
+declaration int inet6_rth_segments(const void *bp)
+version SUNW_1.5
+errno
+exception $return == -1
+end
+
+function inet6_rth_space
+include <unistd.h>
+declaration socklen_t inet6_rth_space(int type, int segments)
+version SUNW_1.5
+errno
+exception $return == 0
+end
+
+# IPv6 option header manipulation
+function inet6_opt_init
+include <netinet/in.h>, <sys/socket.h>
+declaration int inet6_opt_init(void *extbuf, socklen_t extlen)
+version SUNW_1.5
+errno
+exception $return == -1
+end
+
+function inet6_opt_append
+include <netinet/in.h>, <sys/socket.h>
+declaration int inet6_opt_append(void *extbuf, socklen_t extlen,\
+ int offset, uint8_t type, socklen_t len, uint_t align,\
+ void **databufp)
+version SUNW_1.5
+errno
+exception $return == -1
+end
+
+function inet6_opt_finish
+include <netinet/in.h>, <sys/socket.h>
+declaration int inet6_opt_finish(void *extbuf, socklen_t extlen,\
+ int offset)
+version SUNW_1.5
+errno
+exception $return == -1
+end
+
+function inet6_opt_set_val
+include <netinet/in.h>, <sys/socket.h>
+declaration int inet6_opt_set_val(void *databuf, int offset, void *val,\
+ socklen_t vallen)
+version SUNW_1.5
+errno
+exception $return == -1
+end
+
+function inet6_opt_next
+include <netinet/in.h>, <sys/socket.h>
+declaration int inet6_opt_next(void *extbuf, socklen_t extlen, int offset,\
+ uint8_t *typep, socklen_t *lenp, void **databufp)
+version SUNW_1.5
+errno
+exception $return == -1
+end
+
+function inet6_opt_find
+include <netinet/in.h>, <sys/socket.h>
+declaration int inet6_opt_find(void *extbuf, socklen_t extlen, int offset,\
+ uint8_t type, socklen_t *lenp, void **databufp)
+version SUNW_1.5
+errno
+exception $return == -1
+end
+
+function inet6_opt_get_val
+include <netinet/in.h>, <sys/socket.h>
+declaration int inet6_opt_get_val(void *databuf, int offset, void *val,\
+ socklen_t vallen)
+version SUNW_1.5
+errno
+exception $return == -1
+end
+
+# mh mailing system
+function _ruserpass
+version SUNWprivate_1.1
+end
+
+# BCP
+function _socket_bsd
+version SUNWprivate_1.1
+end
+
+# BCP
+function _socketpair_bsd
+version SUNWprivate_1.1
+end
+
+# rpc.bootparamd
+function bootparams_getbyname
+version SUNWprivate_1.1
+end
+
+# ifconfig
+function getnetmaskbyaddr
+version SUNWprivate_1.2
+end
+
+# in.dhcpd, dhcp admin
+function getnetmaskbynet
+version SUNWprivate_1.2
+end
diff --git a/usr/src/lib/libsocket/spec/sparc/Makefile b/usr/src/lib/libsocket/spec/sparc/Makefile
new file mode 100644
index 0000000000..3de398fdd4
--- /dev/null
+++ b/usr/src/lib/libsocket/spec/sparc/Makefile
@@ -0,0 +1,44 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright (c) 1998-1999 by Sun Microsystems, Inc.
+# All rights reserved.
+#
+# lib/libsocket/spec/sparc/Makefile
+
+.KEEP_STATE:
+
+include ../Makefile.targ
+
+# Add arch specific objects here
+OBJECTS +=
+
+include $(SRC)/lib/Makefile.lib
+
+# Uncomment the following if the linker complains
+#sparc_C_PICFLAGS = -K PIC
+
+include $(SRC)/lib/Makefile.spec
+
+install: $(ROOTABILIB)
diff --git a/usr/src/lib/libsocket/spec/sparcv9/Makefile b/usr/src/lib/libsocket/spec/sparcv9/Makefile
new file mode 100644
index 0000000000..378854c037
--- /dev/null
+++ b/usr/src/lib/libsocket/spec/sparcv9/Makefile
@@ -0,0 +1,45 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright (c) 1998-1999 by Sun Microsystems, Inc.
+# All rights reserved.
+#
+# lib/libsocket/spec/sparcv9/Makefile
+
+.KEEP_STATE:
+
+include ../Makefile.targ
+
+# Add arch specific objects here
+OBJECTS +=
+
+include $(SRC)/lib/Makefile.lib
+include $(SRC)/lib/Makefile.lib.64
+
+# Uncomment the following if the linker complains
+sparcv9_C_PICFLAGS = -K PIC
+
+include $(SRC)/lib/Makefile.spec
+
+install: $(ROOTABILIB64)
diff --git a/usr/src/lib/libsocket/spec/svr4msg.spec b/usr/src/lib/libsocket/spec/svr4msg.spec
new file mode 100644
index 0000000000..47f236948c
--- /dev/null
+++ b/usr/src/lib/libsocket/spec/svr4msg.spec
@@ -0,0 +1,131 @@
+#
+# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+function recvmsg
+include "svr4msg_spec.h", <sys/types.h>, <sys/socket.h>
+declaration ssize_t recvmsg(int s, struct SVR4_msghdr *msg, int flags)
+version i386=SUNW_0.7 sparc=SISCD_2.3 sparcv9=SUNW_0.7 amd64=SUNW_0.7
+errno EBADF EINTR EIO ENOMEM ENOSR ENOTSOCK ESTALE EWOULDBLOCK
+exception $return == -1
+end
+
+function sendmsg
+include "svr4msg_spec.h", <sys/types.h>, <sys/socket.h>
+declaration ssize_t sendmsg(int s, const struct SVR4_msghdr *msg, int flags )
+version i386=SUNW_0.7 sparc=SISCD_2.3 sparcv9=SUNW_0.7 amd64=SUNW_0.7
+errno EBADF EINTR EINVAL EMSGSIZE ENOMEM ENOSR ENOTSOCK EWOULDBLOCK
+exception $return == -1
+end
+
+#
+# weak interfaces
+#
+function _recvmsg
+weak recvmsg
+version SUNWprivate_1.1
+end
+
+function _sendmsg
+weak sendmsg
+version SUNWprivate_1.1
+end
+
+function _socket
+weak socket
+version SUNWprivate_1.1
+end
+
+function _socketpair
+weak socketpair
+version SUNWprivate_1.1
+end
+
+function _bind
+weak bind
+version SUNWprivate_1.1
+end
+
+function _listen
+weak listen
+version SUNWprivate_1.1
+end
+
+function _accept
+weak accept
+version SUNWprivate_1.1
+end
+
+function _connect
+weak connect
+version SUNWprivate_1.1
+end
+
+function _shutdown
+weak shutdown
+version SUNWprivate_1.1
+end
+
+function _recv
+weak recv
+version SUNWprivate_1.1
+end
+
+function _recvfrom
+weak recvfrom
+version SUNWprivate_1.1
+end
+
+function _send
+weak send
+version SUNWprivate_1.1
+end
+
+function _sendto
+weak sendto
+version SUNWprivate_1.1
+end
+
+function _getpeername
+weak getpeername
+version SUNWprivate_1.1
+end
+
+function _getsockname
+weak getsockname
+version SUNWprivate_1.1
+end
+
+function _getsockopt
+weak getsockopt
+version SUNWprivate_1.1
+end
+
+function _setsockopt
+weak setsockopt
+version SUNWprivate_1.1
+end
+
diff --git a/usr/src/lib/libsocket/spec/versions b/usr/src/lib/libsocket/spec/versions
new file mode 100644
index 0000000000..5ad9b43212
--- /dev/null
+++ b/usr/src/lib/libsocket/spec/versions
@@ -0,0 +1,84 @@
+#
+# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Note (re: SUNW_1.2 .. SUNW_1.3):
+# Even though the SUNW_1.2 and SUNW_1.3 versions now contain no
+# symbols these versions MUST be present. This is because applications
+# built on 2.6 Beta (when they did contain symbols explicitly) may
+# depend on them.
+#
+# All symbol content for Solaris2.6 is now contained in SUNW_1.1,
+# and (the now empty) versions SUNW_1.2 and SUNW_1.3 must be kept.
+#
+i386 {
+ SUNW_1.6: {SUNW_1.5};
+ SUNW_1.5: {SUNW_1.4};
+ SUNW_1.4: {SUNW_1.3};
+ SUNW_1.3: {SUNW_1.2};
+ SUNW_1.2: {SUNW_1.1};
+ SUNW_1.1: {SUNW_0.7};
+ SUNW_0.7;
+ SUNWprivate_1.3: {SUNWprivate_1.2};
+ SUNWprivate_1.2: {SUNWprivate_1.1};
+ SUNWprivate_1.1;
+}
+sparc {
+ SUNW_1.6: {SUNW_1.5};
+ SUNW_1.5: {SUNW_1.4};
+ SUNW_1.4: {SUNW_1.3};
+ SUNW_1.3: {SUNW_1.2};
+ SUNW_1.2: {SUNW_1.1};
+ SUNW_1.1: {SUNW_0.7};
+ SUNW_0.7: {SISCD_2.3};
+ SISCD_2.3;
+ SUNWprivate_1.3: {SUNWprivate_1.2};
+ SUNWprivate_1.2: {SUNWprivate_1.1};
+ SUNWprivate_1.1;
+}
+sparcv9 {
+ SUNW_1.6: {SUNW_1.5};
+ SUNW_1.5: {SUNW_1.4};
+ SUNW_1.4: {SUNW_1.3};
+ SUNW_1.3: {SUNW_1.2};
+ SUNW_1.2: {SUNW_1.1};
+ SUNW_1.1: {SUNW_0.7};
+ SUNW_0.7;
+ SUNWprivate_1.3: {SUNWprivate_1.2};
+ SUNWprivate_1.2: {SUNWprivate_1.1};
+ SUNWprivate_1.1;
+}
+amd64 {
+ SUNW_1.6: {SUNW_1.5};
+ SUNW_1.5: {SUNW_1.4};
+ SUNW_1.4: {SUNW_1.3};
+ SUNW_1.3: {SUNW_1.2};
+ SUNW_1.2: {SUNW_1.1};
+ SUNW_1.1: {SUNW_0.7};
+ SUNW_0.7;
+ SUNWprivate_1.3: {SUNWprivate_1.2};
+ SUNWprivate_1.2: {SUNWprivate_1.1};
+ SUNWprivate_1.1;
+}
diff --git a/usr/src/lib/libsocket/spec/xpgmsg.spec b/usr/src/lib/libsocket/spec/xpgmsg.spec
new file mode 100644
index 0000000000..61ffcef9f8
--- /dev/null
+++ b/usr/src/lib/libsocket/spec/xpgmsg.spec
@@ -0,0 +1,48 @@
+#
+# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+
+function __xnet_recvmsg
+include "xpgmsg_spec.h", <sys/types.h>, <sys/socket.h>
+declaration ssize_t __xnet_recvmsg(int socket, struct XPG_msghdr *msg, \
+ int flags)
+version SUNW_1.1
+errno EBADF ENOTSOCK EINVAL EWOULDBLOCK EAGAIN EINTR EOPNOTSUPP \
+ ENOTCONN ETIMEDOUT ECONNRESET EIO ENOBUFS ENOMEM ENOSR
+exception $return == -1
+end
+
+function __xnet_sendmsg
+include "xpgmsg_spec.h", <sys/types.h>, <sys/socket.h>
+declaration ssize_t __xnet_sendmsg(int socket, const struct XPG_msghdr *msg, \
+ int flags )
+version SUNW_1.1
+errno EAFNOSUPPORT EBADF ECONNRESET EINTR EINVAL EMSGSIZE ENOTCONN \
+ ENOTSOCK EOPNOTSUPP EPIPE EWOULDBLOCK EAGAIN EACCES EIO \
+ ELOOP ENAMETOOLONG ENOENT ENOTDIR EDESTADDRREQ EHOSTUNREACH \
+ EISCONN ENETDOWN ENETUNREACH ENOBUFS ENOSR
+exception $return == -1
+end