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