1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
  23  */
  24 
  25 /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
  26 /*        All Rights Reserved   */
  27 
  28 /*
  29  * University Copyright- Copyright (c) 1982, 1986, 1988
  30  * The Regents of the University of California
  31  * All Rights Reserved
  32  *
  33  * University Acknowledgment- Portions of this document are derived from
  34  * software developed by the University of California, Berkeley, and its
  35  * contributors.
  36  */
  37 
  38 #include <sys/types.h>
  39 #include <sys/socket.h>
  40 #include <sys/stropts.h>
  41 #include <sys/stream.h>
  42 #include <sys/socketvar.h>
  43 #include <errno.h>
  44 #include <unistd.h>
  45 #include <stdlib.h>
  46 
  47 extern int _so_socket();
  48 extern int _s_netconfig_path();
  49 extern int _setsockopt();
  50 
  51 int _socket_create(int, int, int, int);
  52 
  53 #pragma weak socket = _socket
  54 
  55 int
  56 _socket(int family, int type, int protocol)
  57 {
  58         return (_socket_create(family, type, protocol, SOV_DEFAULT));
  59 }
  60 
  61 /*
  62  * Used by the BCP library.
  63  */
  64 int
  65 _socket_bsd(int family, int type, int protocol)
  66 {
  67         return (_socket_create(family, type, protocol, SOV_SOCKBSD));
  68 }
  69 
  70 int
  71 _socket_svr4(int family, int type, int protocol)
  72 {
  73         return (_socket_create(family, type, protocol, SOV_SOCKSTREAM));
  74 }
  75 
  76 int
  77 __xnet_socket(int family, int type, int protocol)
  78 {
  79         return (_socket_create(family, type, protocol, SOV_XPG4_2));
  80 }
  81 
  82 /*
  83  * Create a socket endpoint for socket() and socketpair().
  84  * In SunOS 4.X and in SunOS 5.X prior to XPG 4.2 the only error
  85  * that could be returned due to invalid <family, type, protocol>
  86  * was EPROTONOSUPPORT. (While the SunOS 4.X source contains EPROTOTYPE
  87  * error as well that error can only be generated if the kernel is
  88  * incorrectly configured.)
  89  * For backwards compatibility only applications that request XPG 4.2
  90  * (through c89 or XOPEN_SOURCE) will get EPROTOTYPE or EAFNOSUPPORT errors.
  91  */
  92 int
  93 _socket_create(int family, int type, int protocol, int version)
  94 {
  95         int fd;
  96 
  97         /*
  98          * Try creating without knowing the device assuming that
  99          * the transport provider is registered in /etc/sock2path.d.
 100          * If none found fall back to using /etc/netconfig to look
 101          * up the name of the transport device name. This provides
 102          * backwards compatibility for transport providers that have not
 103          * yet been converted to using /etc/sock2path.d.
 104          * XXX When all transport providers use /etc/sock2path.d. this
 105          * part of the code can be removed.
 106          */
 107         fd = _so_socket(family, type, protocol, NULL, version);
 108         if (fd == -1) {
 109                 char *devpath;
 110                 int saved_errno = errno;
 111                 int prototype = 0;
 112 
 113                 switch (saved_errno) {
 114                 case EAFNOSUPPORT:
 115                 case EPROTOTYPE:
 116                         if (version != SOV_XPG4_2)
 117                                 saved_errno = EPROTONOSUPPORT;
 118                         break;
 119                 case EPROTONOSUPPORT:
 120                         break;
 121 
 122                 default:
 123                         errno = saved_errno;
 124                         return (-1);
 125                 }
 126                 if (_s_netconfig_path(family, type, protocol,
 127                     &devpath, &prototype) == -1) {
 128                         errno = saved_errno;
 129                         return (-1);
 130                 }
 131                 fd = _so_socket(family, type, protocol, devpath, version);
 132                 free(devpath);
 133                 if (fd == -1) {
 134                         errno = saved_errno;
 135                         return (-1);
 136                 }
 137                 if (prototype != 0) {
 138                         if (_setsockopt(fd, SOL_SOCKET, SO_PROTOTYPE,
 139                             (caddr_t)&prototype, (int)sizeof (prototype)) < 0) {
 140                                 (void) close(fd);
 141                                 /*
 142                                  * setsockopt often fails with ENOPROTOOPT
 143                                  * but socket() should fail with
 144                                  * EPROTONOSUPPORT.
 145                                  */
 146                                 errno = EPROTONOSUPPORT;
 147                                 return (-1);
 148                         }
 149                 }
 150         }
 151         return (fd);
 152 }