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 /* 23 * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 27 /* All Rights Reserved */ 28 29 /* 30 * Portions of this source code were derived from Berkeley 4.3 BSD 31 * under license from the Regents of the University of California. 32 */ 33 34 #include <sys/types.h> 35 #include <sys/socket.h> 36 #include <sys/stat.h> 37 #include <netinet/in.h> 38 #include <errno.h> 39 #include <unistd.h> 40 #include <stdlib.h> 41 #include <string.h> 42 43 /* 44 * XXX The functions in this file are only needed to support transport 45 * providers that have not yet been converted to use /etc/sock2path.d. 46 * Once all transport providers have been converted this file can be 47 * removed. 48 */ 49 50 static struct netconfig *_s_match_netconf(int family, int type, int proto, 51 void **nethandle); 52 53 /* 54 * The following two string arrays map a number as specified 55 * by a user of sockets, to the string as would be returned 56 * by a call to getnetconfig(). 57 * 58 * They are used by _s_match_netconf(); 59 * 60 * proto_sw contains protocol entries for which there is a corresponding 61 * /dev device. All others would presumably use raw IP and download the 62 * desired protocol. 63 */ 64 static char *proto_sw[] = { 65 "", 66 "icmp", /* 1 = ICMP */ 67 "", 68 "", 69 "", 70 "", 71 "tcp", /* 6 = TCP */ 72 "", 73 "", 74 "", 75 "", 76 "", 77 "", 78 "", 79 "", 80 "", 81 "", 82 "udp", /* 17 = UDP */ 83 }; 84 85 static char *family_sw[] = { 86 "-", /* 0 = AF_UNSPEC */ 87 "loopback", /* 1 = AF_UNIX */ 88 "inet", /* 2 = AF_INET */ 89 "implink", /* 3 = AF_IMPLINK */ 90 "pup", /* 4 = AF_PUP */ 91 "chaos", /* 5 = AF_CHAOS */ 92 "ns", /* 6 = AF_NS */ 93 "nbs", /* 7 = AF_NBS */ 94 "ecma", /* 8 = AF_ECMA */ 95 "datakit", /* 9 = AF_DATAKIT */ 96 "ccitt", /* 10 = AF_CCITT */ 97 "sna", /* 11 = AF_SNA */ 98 "decnet", /* 12 = AF_DECnet */ 99 "dli", /* 13 = AF_DLI */ 100 "lat", /* 14 = AF_LAT */ 101 "hylink", /* 15 = AF_HYLINK */ 102 "appletalk", /* 16 = AF_APPLETALK */ 103 "nit", /* 17 = AF_NIT */ 104 "ieee802", /* 18 = AF_802 */ 105 "osi", /* 19 = AF_OSI */ 106 "x25", /* 20 = AF_X25 */ 107 "osinet", /* 21 = AF_OSINET */ 108 "gosip", /* 22 = AF_GOSIP */ 109 "ipx", /* 23 = AF_IPX */ 110 "route", /* 24 = AF_ROUTE */ 111 "link", /* 25 = AF_LINK */ 112 "inet6", /* 26 = AF_INET6 */ 113 "key", /* 27 = AF_KEY */ 114 }; 115 116 /* 117 * Lookup family/type/protocol in /etc/netconfig. 118 * Returns the pathname and a prototype value (to be passed into SO_PROTOTYPE) 119 * The path is malloc'ed and has to be freed by the caller. 120 */ 121 int 122 _s_netconfig_path(int family, int type, int protocol, 123 char **pathp, int *prototype) 124 { 125 struct netconfig *net; 126 void *nethandle; 127 struct stat stats; 128 129 net = _s_match_netconf(family, type, protocol, &nethandle); 130 if (net == NULL) 131 return (-1); 132 133 if (strcmp(net->nc_proto, NC_NOPROTO) != 0) 134 *prototype = 0; 135 else 136 *prototype = protocol; 137 138 retry: 139 if (stat(net->nc_device, &stats) < 0) { 140 switch (errno) { 141 case EINTR: 142 goto retry; 143 144 case ENOENT: 145 case ENOLINK: 146 case ELOOP: 147 case EMULTIHOP: 148 case ENOTDIR: 149 errno = EPFNOSUPPORT; 150 break; 151 } 152 endnetconfig(nethandle); /* finished with netconfig struct */ 153 return (-1); 154 } 155 if (!S_ISCHR(stats.st_mode)) { 156 errno = EPFNOSUPPORT; 157 endnetconfig(nethandle); /* finished with netconfig struct */ 158 return (-1); 159 } 160 *pathp = malloc(strlen(net->nc_device) + 1); 161 if (*pathp == NULL) { 162 endnetconfig(nethandle); 163 errno = ENOMEM; 164 return (-1); 165 } 166 (void) strcpy(*pathp, net->nc_device); 167 endnetconfig(nethandle); /* finished with netconfig struct */ 168 return (0); 169 } 170 171 /* 172 * Match config entry for protocol 173 * requested. 174 */ 175 static struct netconfig * 176 _s_match_netconf(int family, int type, int proto, void **nethandle) 177 { 178 struct netconfig *net; 179 struct netconfig *maybe; 180 char *oproto; 181 182 if (family < 0 || 183 family >= (int)sizeof (family_sw) / (int)sizeof (char *) || 184 proto < 0 || proto >= IPPROTO_MAX) { 185 errno = EPROTONOSUPPORT; 186 return (NULL); 187 } 188 if (proto) { 189 if (proto >= (int)sizeof (proto_sw) / (int)sizeof (char *)) 190 oproto = ""; 191 else 192 oproto = proto_sw[proto]; 193 } 194 195 /* 196 * Loop through each entry in netconfig 197 * until one matches or we reach the end. 198 */ 199 if ((*nethandle = setnetconfig()) == NULL) { 200 return (NULL); 201 } 202 203 maybe = NULL; 204 while ((net = getnetconfig(*nethandle)) != NULL) { 205 /* 206 * We make a copy of net->nc_semantics rather than modifying 207 * it in place because the network selection code shares the 208 * structures returned by getnetconfig() among all its callers. 209 * See bug #1160886 for more details. 210 */ 211 unsigned int semantics = net->nc_semantics; 212 213 if (semantics == NC_TPI_COTS_ORD) 214 semantics = NC_TPI_COTS; 215 if (proto) { 216 if (strcmp(net->nc_protofmly, family_sw[family]) == 0 && 217 semantics == type && 218 strcmp(net->nc_proto, oproto) == 0) 219 break; 220 221 if (strcmp(net->nc_protofmly, family_sw[family]) == 0 && 222 type == SOCK_RAW && 223 semantics == SOCK_RAW && 224 strcmp(net->nc_proto, NC_NOPROTO) == 0 && 225 maybe == NULL) 226 maybe = net; /* in case no exact match */ 227 228 continue; 229 } else { 230 if (strcmp(net->nc_protofmly, family_sw[family]) == 0 && 231 semantics == type) { 232 break; 233 } 234 } 235 } 236 if (net == NULL && maybe) 237 net = maybe; 238 239 if (net == NULL) { 240 endnetconfig(*nethandle); 241 errno = EPROTONOSUPPORT; 242 return (NULL); 243 } 244 245 return (net); 246 }