1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate * 26*7c478bd9Sstevel@tonic-gate * socket.c, Code implementing a simple socket interface. 27*7c478bd9Sstevel@tonic-gate */ 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 30*7c478bd9Sstevel@tonic-gate 31*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 32*7c478bd9Sstevel@tonic-gate #include "socket_impl.h" 33*7c478bd9Sstevel@tonic-gate #include <sys/isa_defs.h> 34*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 35*7c478bd9Sstevel@tonic-gate #include <sys/bootconf.h> 36*7c478bd9Sstevel@tonic-gate #include <sys/socket.h> 37*7c478bd9Sstevel@tonic-gate #include <netinet/in.h> 38*7c478bd9Sstevel@tonic-gate #include <netinet/ip.h> 39*7c478bd9Sstevel@tonic-gate #include <netinet/tcp.h> 40*7c478bd9Sstevel@tonic-gate #include <sys/uio.h> 41*7c478bd9Sstevel@tonic-gate #include <sys/salib.h> 42*7c478bd9Sstevel@tonic-gate #include "socket_inet.h" 43*7c478bd9Sstevel@tonic-gate #include "ipv4.h" 44*7c478bd9Sstevel@tonic-gate #include "ipv4_impl.h" 45*7c478bd9Sstevel@tonic-gate #include "udp_inet.h" 46*7c478bd9Sstevel@tonic-gate #include "tcp_inet.h" 47*7c478bd9Sstevel@tonic-gate #include "mac.h" 48*7c478bd9Sstevel@tonic-gate #include "mac_impl.h" 49*7c478bd9Sstevel@tonic-gate #include <sys/promif.h> 50*7c478bd9Sstevel@tonic-gate 51*7c478bd9Sstevel@tonic-gate struct inetboot_socket sockets[MAXSOCKET] = { 0 }; 52*7c478bd9Sstevel@tonic-gate 53*7c478bd9Sstevel@tonic-gate /* Default send and receive socket buffer size */ 54*7c478bd9Sstevel@tonic-gate #define SO_DEF_SNDBUF 48*1024 55*7c478bd9Sstevel@tonic-gate #define SO_DEF_RCVBUF 48*1024 56*7c478bd9Sstevel@tonic-gate 57*7c478bd9Sstevel@tonic-gate /* Default max socket buffer size */ 58*7c478bd9Sstevel@tonic-gate #define SO_MAX_BUF 4*1024*1024 59*7c478bd9Sstevel@tonic-gate 60*7c478bd9Sstevel@tonic-gate static ssize_t dgram_sendto(int, const void *, size_t, int, 61*7c478bd9Sstevel@tonic-gate const struct sockaddr *, int); 62*7c478bd9Sstevel@tonic-gate static ssize_t stream_sendto(int, const void *, size_t, int); 63*7c478bd9Sstevel@tonic-gate static int bind_check(int, const struct sockaddr *); 64*7c478bd9Sstevel@tonic-gate static int quickbind(int); 65*7c478bd9Sstevel@tonic-gate 66*7c478bd9Sstevel@tonic-gate /* Check the validity of a fd and return the socket index of that fd. */ 67*7c478bd9Sstevel@tonic-gate int 68*7c478bd9Sstevel@tonic-gate so_check_fd(int fd, int *errno) 69*7c478bd9Sstevel@tonic-gate { 70*7c478bd9Sstevel@tonic-gate int i; 71*7c478bd9Sstevel@tonic-gate 72*7c478bd9Sstevel@tonic-gate i = FD_TO_SOCKET(fd); 73*7c478bd9Sstevel@tonic-gate if (i < 0 || i >= MAXSOCKET) { 74*7c478bd9Sstevel@tonic-gate *errno = ENOTSOCK; 75*7c478bd9Sstevel@tonic-gate return (-1); 76*7c478bd9Sstevel@tonic-gate } 77*7c478bd9Sstevel@tonic-gate if (sockets[i].type == INETBOOT_UNUSED) { 78*7c478bd9Sstevel@tonic-gate *errno = ENOTSOCK; 79*7c478bd9Sstevel@tonic-gate return (-1); 80*7c478bd9Sstevel@tonic-gate } 81*7c478bd9Sstevel@tonic-gate return (i); 82*7c478bd9Sstevel@tonic-gate } 83*7c478bd9Sstevel@tonic-gate 84*7c478bd9Sstevel@tonic-gate /* 85*7c478bd9Sstevel@tonic-gate * Create an endpoint for network communication. Returns a descriptor. 86*7c478bd9Sstevel@tonic-gate * 87*7c478bd9Sstevel@tonic-gate * Notes: 88*7c478bd9Sstevel@tonic-gate * Only PF_INET communication domains are supported. Within 89*7c478bd9Sstevel@tonic-gate * this domain, only SOCK_RAW, SOCK_DGRAM and SOCK_STREAM types are 90*7c478bd9Sstevel@tonic-gate * supported. 91*7c478bd9Sstevel@tonic-gate */ 92*7c478bd9Sstevel@tonic-gate int 93*7c478bd9Sstevel@tonic-gate socket(int domain, int type, int protocol) 94*7c478bd9Sstevel@tonic-gate { 95*7c478bd9Sstevel@tonic-gate static int sock_initialized; 96*7c478bd9Sstevel@tonic-gate int i; 97*7c478bd9Sstevel@tonic-gate 98*7c478bd9Sstevel@tonic-gate errno = 0; 99*7c478bd9Sstevel@tonic-gate 100*7c478bd9Sstevel@tonic-gate if (!sock_initialized) { 101*7c478bd9Sstevel@tonic-gate for (i = 0; i < MAXSOCKET; i++) 102*7c478bd9Sstevel@tonic-gate sockets[i].type = INETBOOT_UNUSED; 103*7c478bd9Sstevel@tonic-gate sock_initialized = B_TRUE; 104*7c478bd9Sstevel@tonic-gate } 105*7c478bd9Sstevel@tonic-gate if (domain != AF_INET) { 106*7c478bd9Sstevel@tonic-gate errno = EPROTONOSUPPORT; 107*7c478bd9Sstevel@tonic-gate return (-1); 108*7c478bd9Sstevel@tonic-gate } 109*7c478bd9Sstevel@tonic-gate 110*7c478bd9Sstevel@tonic-gate /* Find available socket */ 111*7c478bd9Sstevel@tonic-gate for (i = 0; i < MAXSOCKET; i++) { 112*7c478bd9Sstevel@tonic-gate if (sockets[i].type == INETBOOT_UNUSED) 113*7c478bd9Sstevel@tonic-gate break; 114*7c478bd9Sstevel@tonic-gate } 115*7c478bd9Sstevel@tonic-gate if (i >= MAXSOCKET) { 116*7c478bd9Sstevel@tonic-gate errno = EMFILE; /* No slots left. */ 117*7c478bd9Sstevel@tonic-gate return (-1); 118*7c478bd9Sstevel@tonic-gate } 119*7c478bd9Sstevel@tonic-gate 120*7c478bd9Sstevel@tonic-gate /* Some socket initialization... */ 121*7c478bd9Sstevel@tonic-gate sockets[i].so_rcvbuf = SO_DEF_RCVBUF; 122*7c478bd9Sstevel@tonic-gate sockets[i].so_sndbuf = SO_DEF_SNDBUF; 123*7c478bd9Sstevel@tonic-gate 124*7c478bd9Sstevel@tonic-gate /* 125*7c478bd9Sstevel@tonic-gate * Note that we ignore the protocol field for SOCK_DGRAM and 126*7c478bd9Sstevel@tonic-gate * SOCK_STREAM. When we support different protocols in future, 127*7c478bd9Sstevel@tonic-gate * this needs to be changed. 128*7c478bd9Sstevel@tonic-gate */ 129*7c478bd9Sstevel@tonic-gate switch (type) { 130*7c478bd9Sstevel@tonic-gate case SOCK_RAW: 131*7c478bd9Sstevel@tonic-gate ipv4_raw_socket(&sockets[i], (uint8_t)protocol); 132*7c478bd9Sstevel@tonic-gate break; 133*7c478bd9Sstevel@tonic-gate case SOCK_DGRAM: 134*7c478bd9Sstevel@tonic-gate udp_socket_init(&sockets[i]); 135*7c478bd9Sstevel@tonic-gate break; 136*7c478bd9Sstevel@tonic-gate case SOCK_STREAM: 137*7c478bd9Sstevel@tonic-gate tcp_socket_init(&sockets[i]); 138*7c478bd9Sstevel@tonic-gate break; 139*7c478bd9Sstevel@tonic-gate default: 140*7c478bd9Sstevel@tonic-gate errno = EPROTOTYPE; 141*7c478bd9Sstevel@tonic-gate break; 142*7c478bd9Sstevel@tonic-gate } 143*7c478bd9Sstevel@tonic-gate 144*7c478bd9Sstevel@tonic-gate if (errno != 0) 145*7c478bd9Sstevel@tonic-gate return (-1); 146*7c478bd9Sstevel@tonic-gate 147*7c478bd9Sstevel@tonic-gate /* IPv4 generic initialization. */ 148*7c478bd9Sstevel@tonic-gate ipv4_socket_init(&sockets[i]); 149*7c478bd9Sstevel@tonic-gate 150*7c478bd9Sstevel@tonic-gate /* MAC generic initialization. */ 151*7c478bd9Sstevel@tonic-gate mac_socket_init(&sockets[i]); 152*7c478bd9Sstevel@tonic-gate 153*7c478bd9Sstevel@tonic-gate return (i + SOCKETTYPE); 154*7c478bd9Sstevel@tonic-gate } 155*7c478bd9Sstevel@tonic-gate 156*7c478bd9Sstevel@tonic-gate int 157*7c478bd9Sstevel@tonic-gate getsockname(int s, struct sockaddr *name, socklen_t *namelen) 158*7c478bd9Sstevel@tonic-gate { 159*7c478bd9Sstevel@tonic-gate int i; 160*7c478bd9Sstevel@tonic-gate 161*7c478bd9Sstevel@tonic-gate errno = 0; 162*7c478bd9Sstevel@tonic-gate if ((i = so_check_fd(s, &errno)) == -1) 163*7c478bd9Sstevel@tonic-gate return (-1); 164*7c478bd9Sstevel@tonic-gate 165*7c478bd9Sstevel@tonic-gate if (*namelen < sizeof (struct sockaddr_in)) { 166*7c478bd9Sstevel@tonic-gate errno = ENOMEM; 167*7c478bd9Sstevel@tonic-gate return (-1); 168*7c478bd9Sstevel@tonic-gate } 169*7c478bd9Sstevel@tonic-gate 170*7c478bd9Sstevel@tonic-gate /* Structure assignment... */ 171*7c478bd9Sstevel@tonic-gate *((struct sockaddr_in *)name) = sockets[i].bind; 172*7c478bd9Sstevel@tonic-gate *namelen = sizeof (struct sockaddr_in); 173*7c478bd9Sstevel@tonic-gate return (0); 174*7c478bd9Sstevel@tonic-gate } 175*7c478bd9Sstevel@tonic-gate 176*7c478bd9Sstevel@tonic-gate /* 177*7c478bd9Sstevel@tonic-gate * The socket options we support are: 178*7c478bd9Sstevel@tonic-gate * SO_RCVTIMEO - Value is in msecs, and is of uint32_t. 179*7c478bd9Sstevel@tonic-gate * SO_DONTROUTE - Value is an int, and is a boolean (nonzero if set). 180*7c478bd9Sstevel@tonic-gate * SO_REUSEADDR - Value is an int boolean. 181*7c478bd9Sstevel@tonic-gate * SO_RCVBUF - Value is an int. 182*7c478bd9Sstevel@tonic-gate * SO_SNDBUF - Value is an int. 183*7c478bd9Sstevel@tonic-gate */ 184*7c478bd9Sstevel@tonic-gate int 185*7c478bd9Sstevel@tonic-gate getsockopt(int s, int level, int option, void *optval, socklen_t *optlen) 186*7c478bd9Sstevel@tonic-gate { 187*7c478bd9Sstevel@tonic-gate int i; 188*7c478bd9Sstevel@tonic-gate 189*7c478bd9Sstevel@tonic-gate errno = 0; 190*7c478bd9Sstevel@tonic-gate if ((i = so_check_fd(s, &errno)) == -1) 191*7c478bd9Sstevel@tonic-gate return (-1); 192*7c478bd9Sstevel@tonic-gate 193*7c478bd9Sstevel@tonic-gate switch (level) { 194*7c478bd9Sstevel@tonic-gate case SOL_SOCKET: { 195*7c478bd9Sstevel@tonic-gate switch (option) { 196*7c478bd9Sstevel@tonic-gate case SO_RCVTIMEO: 197*7c478bd9Sstevel@tonic-gate if (*optlen == sizeof (uint32_t)) { 198*7c478bd9Sstevel@tonic-gate *(uint32_t *)optval = sockets[i].in_timeout; 199*7c478bd9Sstevel@tonic-gate } else { 200*7c478bd9Sstevel@tonic-gate *optlen = 0; 201*7c478bd9Sstevel@tonic-gate errno = EINVAL; 202*7c478bd9Sstevel@tonic-gate } 203*7c478bd9Sstevel@tonic-gate break; 204*7c478bd9Sstevel@tonic-gate case SO_DONTROUTE: 205*7c478bd9Sstevel@tonic-gate if (*optlen == sizeof (int)) { 206*7c478bd9Sstevel@tonic-gate *(int *)optval = 207*7c478bd9Sstevel@tonic-gate (sockets[i].out_flags & SO_DONTROUTE); 208*7c478bd9Sstevel@tonic-gate } else { 209*7c478bd9Sstevel@tonic-gate *optlen = 0; 210*7c478bd9Sstevel@tonic-gate errno = EINVAL; 211*7c478bd9Sstevel@tonic-gate } 212*7c478bd9Sstevel@tonic-gate break; 213*7c478bd9Sstevel@tonic-gate case SO_REUSEADDR: 214*7c478bd9Sstevel@tonic-gate if (*optlen == sizeof (int)) { 215*7c478bd9Sstevel@tonic-gate *(int *)optval = 216*7c478bd9Sstevel@tonic-gate (sockets[i].so_opt & SO_REUSEADDR); 217*7c478bd9Sstevel@tonic-gate } else { 218*7c478bd9Sstevel@tonic-gate *optlen = 0; 219*7c478bd9Sstevel@tonic-gate errno = EINVAL; 220*7c478bd9Sstevel@tonic-gate } 221*7c478bd9Sstevel@tonic-gate break; 222*7c478bd9Sstevel@tonic-gate case SO_RCVBUF: 223*7c478bd9Sstevel@tonic-gate if (*optlen == sizeof (int)) { 224*7c478bd9Sstevel@tonic-gate *(int *)optval = sockets[i].so_rcvbuf; 225*7c478bd9Sstevel@tonic-gate } else { 226*7c478bd9Sstevel@tonic-gate *optlen = 0; 227*7c478bd9Sstevel@tonic-gate errno = EINVAL; 228*7c478bd9Sstevel@tonic-gate } 229*7c478bd9Sstevel@tonic-gate break; 230*7c478bd9Sstevel@tonic-gate case SO_SNDBUF: 231*7c478bd9Sstevel@tonic-gate if (*optlen == sizeof (int)) { 232*7c478bd9Sstevel@tonic-gate *(int *)optval = sockets[i].so_sndbuf; 233*7c478bd9Sstevel@tonic-gate } else { 234*7c478bd9Sstevel@tonic-gate *optlen = 0; 235*7c478bd9Sstevel@tonic-gate errno = EINVAL; 236*7c478bd9Sstevel@tonic-gate } 237*7c478bd9Sstevel@tonic-gate break; 238*7c478bd9Sstevel@tonic-gate case SO_LINGER: 239*7c478bd9Sstevel@tonic-gate if (*optlen == sizeof (struct linger)) { 240*7c478bd9Sstevel@tonic-gate /* struct copy */ 241*7c478bd9Sstevel@tonic-gate *(struct linger *)optval = sockets[i].so_linger; 242*7c478bd9Sstevel@tonic-gate } else { 243*7c478bd9Sstevel@tonic-gate *optlen = 0; 244*7c478bd9Sstevel@tonic-gate errno = EINVAL; 245*7c478bd9Sstevel@tonic-gate } 246*7c478bd9Sstevel@tonic-gate default: 247*7c478bd9Sstevel@tonic-gate errno = ENOPROTOOPT; 248*7c478bd9Sstevel@tonic-gate break; 249*7c478bd9Sstevel@tonic-gate } 250*7c478bd9Sstevel@tonic-gate break; 251*7c478bd9Sstevel@tonic-gate } /* case SOL_SOCKET */ 252*7c478bd9Sstevel@tonic-gate case IPPROTO_TCP: 253*7c478bd9Sstevel@tonic-gate case IPPROTO_IP: { 254*7c478bd9Sstevel@tonic-gate switch (option) { 255*7c478bd9Sstevel@tonic-gate default: 256*7c478bd9Sstevel@tonic-gate *optlen = 0; 257*7c478bd9Sstevel@tonic-gate errno = ENOPROTOOPT; 258*7c478bd9Sstevel@tonic-gate break; 259*7c478bd9Sstevel@tonic-gate } 260*7c478bd9Sstevel@tonic-gate break; 261*7c478bd9Sstevel@tonic-gate } /* case IPPROTO_IP or IPPROTO_TCP */ 262*7c478bd9Sstevel@tonic-gate default: 263*7c478bd9Sstevel@tonic-gate errno = ENOPROTOOPT; 264*7c478bd9Sstevel@tonic-gate break; 265*7c478bd9Sstevel@tonic-gate } /* switch (level) */ 266*7c478bd9Sstevel@tonic-gate 267*7c478bd9Sstevel@tonic-gate if (errno != 0) 268*7c478bd9Sstevel@tonic-gate return (-1); 269*7c478bd9Sstevel@tonic-gate else 270*7c478bd9Sstevel@tonic-gate return (0); 271*7c478bd9Sstevel@tonic-gate } 272*7c478bd9Sstevel@tonic-gate 273*7c478bd9Sstevel@tonic-gate /* 274*7c478bd9Sstevel@tonic-gate * Generate a network-order source port from the privileged range if 275*7c478bd9Sstevel@tonic-gate * "reserved" is true, dynamic/private range otherwise. We consider the 276*7c478bd9Sstevel@tonic-gate * range of 512-1023 privileged ports as ports we can use. This mirrors 277*7c478bd9Sstevel@tonic-gate * historical rpc client practice for privileged port selection. 278*7c478bd9Sstevel@tonic-gate */ 279*7c478bd9Sstevel@tonic-gate in_port_t 280*7c478bd9Sstevel@tonic-gate get_source_port(boolean_t reserved) 281*7c478bd9Sstevel@tonic-gate { 282*7c478bd9Sstevel@tonic-gate static in_port_t dynamic = IPPORT_DYNAMIC_START - 1, 283*7c478bd9Sstevel@tonic-gate rsvdport = (IPPORT_RESERVED / 2) - 1; 284*7c478bd9Sstevel@tonic-gate in_port_t p; 285*7c478bd9Sstevel@tonic-gate 286*7c478bd9Sstevel@tonic-gate if (reserved) { 287*7c478bd9Sstevel@tonic-gate if (++rsvdport >= IPPORT_RESERVED) 288*7c478bd9Sstevel@tonic-gate p = rsvdport = IPPORT_RESERVED / 2; 289*7c478bd9Sstevel@tonic-gate else 290*7c478bd9Sstevel@tonic-gate p = rsvdport; 291*7c478bd9Sstevel@tonic-gate } else 292*7c478bd9Sstevel@tonic-gate p = ++dynamic; 293*7c478bd9Sstevel@tonic-gate 294*7c478bd9Sstevel@tonic-gate return (htons(p)); 295*7c478bd9Sstevel@tonic-gate } 296*7c478bd9Sstevel@tonic-gate 297*7c478bd9Sstevel@tonic-gate /* 298*7c478bd9Sstevel@tonic-gate * The socket options we support are: 299*7c478bd9Sstevel@tonic-gate * SO_RECVTIMEO - Value is uint32_t msecs. 300*7c478bd9Sstevel@tonic-gate * SO_DONTROUTE - Value is int boolean (nonzero == TRUE, zero == FALSE). 301*7c478bd9Sstevel@tonic-gate * SO_REUSEADDR - value is int boolean. 302*7c478bd9Sstevel@tonic-gate * SO_RCVBUF - Value is int. 303*7c478bd9Sstevel@tonic-gate * SO_SNDBUF - Value is int. 304*7c478bd9Sstevel@tonic-gate */ 305*7c478bd9Sstevel@tonic-gate int 306*7c478bd9Sstevel@tonic-gate setsockopt(int s, int level, int option, const void *optval, socklen_t optlen) 307*7c478bd9Sstevel@tonic-gate { 308*7c478bd9Sstevel@tonic-gate int i; 309*7c478bd9Sstevel@tonic-gate 310*7c478bd9Sstevel@tonic-gate errno = 0; 311*7c478bd9Sstevel@tonic-gate if ((i = so_check_fd(s, &errno)) == -1) 312*7c478bd9Sstevel@tonic-gate return (-1); 313*7c478bd9Sstevel@tonic-gate 314*7c478bd9Sstevel@tonic-gate switch (level) { 315*7c478bd9Sstevel@tonic-gate case SOL_SOCKET: { 316*7c478bd9Sstevel@tonic-gate switch (option) { 317*7c478bd9Sstevel@tonic-gate case SO_RCVTIMEO: 318*7c478bd9Sstevel@tonic-gate if (optlen == sizeof (uint32_t)) 319*7c478bd9Sstevel@tonic-gate sockets[i].in_timeout = *(uint32_t *)optval; 320*7c478bd9Sstevel@tonic-gate else { 321*7c478bd9Sstevel@tonic-gate errno = EINVAL; 322*7c478bd9Sstevel@tonic-gate } 323*7c478bd9Sstevel@tonic-gate break; 324*7c478bd9Sstevel@tonic-gate case SO_DONTROUTE: 325*7c478bd9Sstevel@tonic-gate if (optlen == sizeof (int)) { 326*7c478bd9Sstevel@tonic-gate if (*(int *)optval) 327*7c478bd9Sstevel@tonic-gate sockets[i].out_flags |= SO_DONTROUTE; 328*7c478bd9Sstevel@tonic-gate else 329*7c478bd9Sstevel@tonic-gate sockets[i].out_flags &= ~SO_DONTROUTE; 330*7c478bd9Sstevel@tonic-gate } else { 331*7c478bd9Sstevel@tonic-gate errno = EINVAL; 332*7c478bd9Sstevel@tonic-gate } 333*7c478bd9Sstevel@tonic-gate break; 334*7c478bd9Sstevel@tonic-gate case SO_REUSEADDR: 335*7c478bd9Sstevel@tonic-gate if (optlen == sizeof (int)) { 336*7c478bd9Sstevel@tonic-gate if (*(int *)optval) 337*7c478bd9Sstevel@tonic-gate sockets[i].so_opt |= SO_REUSEADDR; 338*7c478bd9Sstevel@tonic-gate else 339*7c478bd9Sstevel@tonic-gate sockets[i].so_opt &= ~SO_REUSEADDR; 340*7c478bd9Sstevel@tonic-gate } else { 341*7c478bd9Sstevel@tonic-gate errno = EINVAL; 342*7c478bd9Sstevel@tonic-gate } 343*7c478bd9Sstevel@tonic-gate break; 344*7c478bd9Sstevel@tonic-gate case SO_RCVBUF: 345*7c478bd9Sstevel@tonic-gate if (optlen == sizeof (int)) { 346*7c478bd9Sstevel@tonic-gate sockets[i].so_rcvbuf = *(int *)optval; 347*7c478bd9Sstevel@tonic-gate if (sockets[i].so_rcvbuf > SO_MAX_BUF) 348*7c478bd9Sstevel@tonic-gate sockets[i].so_rcvbuf = SO_MAX_BUF; 349*7c478bd9Sstevel@tonic-gate (void) tcp_opt_set(sockets[i].pcb, 350*7c478bd9Sstevel@tonic-gate level, option, optval, optlen); 351*7c478bd9Sstevel@tonic-gate } else { 352*7c478bd9Sstevel@tonic-gate errno = EINVAL; 353*7c478bd9Sstevel@tonic-gate } 354*7c478bd9Sstevel@tonic-gate break; 355*7c478bd9Sstevel@tonic-gate case SO_SNDBUF: 356*7c478bd9Sstevel@tonic-gate if (optlen == sizeof (int)) { 357*7c478bd9Sstevel@tonic-gate sockets[i].so_sndbuf = *(int *)optval; 358*7c478bd9Sstevel@tonic-gate if (sockets[i].so_sndbuf > SO_MAX_BUF) 359*7c478bd9Sstevel@tonic-gate sockets[i].so_sndbuf = SO_MAX_BUF; 360*7c478bd9Sstevel@tonic-gate (void) tcp_opt_set(sockets[i].pcb, 361*7c478bd9Sstevel@tonic-gate level, option, optval, optlen); 362*7c478bd9Sstevel@tonic-gate } else { 363*7c478bd9Sstevel@tonic-gate errno = EINVAL; 364*7c478bd9Sstevel@tonic-gate } 365*7c478bd9Sstevel@tonic-gate break; 366*7c478bd9Sstevel@tonic-gate case SO_LINGER: 367*7c478bd9Sstevel@tonic-gate if (optlen == sizeof (struct linger)) { 368*7c478bd9Sstevel@tonic-gate /* struct copy */ 369*7c478bd9Sstevel@tonic-gate sockets[i].so_linger = *(struct linger *)optval; 370*7c478bd9Sstevel@tonic-gate (void) tcp_opt_set(sockets[i].pcb, 371*7c478bd9Sstevel@tonic-gate level, option, optval, optlen); 372*7c478bd9Sstevel@tonic-gate } else { 373*7c478bd9Sstevel@tonic-gate errno = EINVAL; 374*7c478bd9Sstevel@tonic-gate } 375*7c478bd9Sstevel@tonic-gate break; 376*7c478bd9Sstevel@tonic-gate default: 377*7c478bd9Sstevel@tonic-gate errno = ENOPROTOOPT; 378*7c478bd9Sstevel@tonic-gate break; 379*7c478bd9Sstevel@tonic-gate } 380*7c478bd9Sstevel@tonic-gate break; 381*7c478bd9Sstevel@tonic-gate } /* case SOL_SOCKET */ 382*7c478bd9Sstevel@tonic-gate case IPPROTO_TCP: 383*7c478bd9Sstevel@tonic-gate case IPPROTO_IP: { 384*7c478bd9Sstevel@tonic-gate switch (option) { 385*7c478bd9Sstevel@tonic-gate default: 386*7c478bd9Sstevel@tonic-gate errno = ENOPROTOOPT; 387*7c478bd9Sstevel@tonic-gate break; 388*7c478bd9Sstevel@tonic-gate } 389*7c478bd9Sstevel@tonic-gate break; 390*7c478bd9Sstevel@tonic-gate } /* case IPPROTO_IP or IPPROTO_TCP */ 391*7c478bd9Sstevel@tonic-gate default: 392*7c478bd9Sstevel@tonic-gate errno = ENOPROTOOPT; 393*7c478bd9Sstevel@tonic-gate break; 394*7c478bd9Sstevel@tonic-gate } /* switch (level) */ 395*7c478bd9Sstevel@tonic-gate 396*7c478bd9Sstevel@tonic-gate if (errno != 0) 397*7c478bd9Sstevel@tonic-gate return (-1); 398*7c478bd9Sstevel@tonic-gate else 399*7c478bd9Sstevel@tonic-gate return (0); 400*7c478bd9Sstevel@tonic-gate } 401*7c478bd9Sstevel@tonic-gate 402*7c478bd9Sstevel@tonic-gate /* 403*7c478bd9Sstevel@tonic-gate * Shut down part of a full-duplex connection. 404*7c478bd9Sstevel@tonic-gate * 405*7c478bd9Sstevel@tonic-gate * Only supported for TCP sockets 406*7c478bd9Sstevel@tonic-gate */ 407*7c478bd9Sstevel@tonic-gate int 408*7c478bd9Sstevel@tonic-gate shutdown(int s, int how) 409*7c478bd9Sstevel@tonic-gate { 410*7c478bd9Sstevel@tonic-gate int sock_id; 411*7c478bd9Sstevel@tonic-gate int i; 412*7c478bd9Sstevel@tonic-gate 413*7c478bd9Sstevel@tonic-gate errno = 0; 414*7c478bd9Sstevel@tonic-gate if ((sock_id = so_check_fd(s, &errno)) == -1) 415*7c478bd9Sstevel@tonic-gate return (-1); 416*7c478bd9Sstevel@tonic-gate 417*7c478bd9Sstevel@tonic-gate /* shutdown only supported for TCP sockets */ 418*7c478bd9Sstevel@tonic-gate if (sockets[sock_id].type != INETBOOT_STREAM) { 419*7c478bd9Sstevel@tonic-gate errno = EOPNOTSUPP; 420*7c478bd9Sstevel@tonic-gate return (-1); 421*7c478bd9Sstevel@tonic-gate } 422*7c478bd9Sstevel@tonic-gate 423*7c478bd9Sstevel@tonic-gate if (!(sockets[sock_id].so_state & SS_ISCONNECTED)) { 424*7c478bd9Sstevel@tonic-gate errno = ENOTCONN; 425*7c478bd9Sstevel@tonic-gate return (-1); 426*7c478bd9Sstevel@tonic-gate } 427*7c478bd9Sstevel@tonic-gate 428*7c478bd9Sstevel@tonic-gate switch (how) { 429*7c478bd9Sstevel@tonic-gate case 0: 430*7c478bd9Sstevel@tonic-gate sockets[sock_id].so_state |= SS_CANTRCVMORE; 431*7c478bd9Sstevel@tonic-gate break; 432*7c478bd9Sstevel@tonic-gate case 1: 433*7c478bd9Sstevel@tonic-gate sockets[sock_id].so_state |= SS_CANTSENDMORE; 434*7c478bd9Sstevel@tonic-gate break; 435*7c478bd9Sstevel@tonic-gate case 2: 436*7c478bd9Sstevel@tonic-gate sockets[sock_id].so_state |= (SS_CANTRCVMORE | SS_CANTSENDMORE); 437*7c478bd9Sstevel@tonic-gate break; 438*7c478bd9Sstevel@tonic-gate default: 439*7c478bd9Sstevel@tonic-gate errno = EINVAL; 440*7c478bd9Sstevel@tonic-gate return (-1); 441*7c478bd9Sstevel@tonic-gate } 442*7c478bd9Sstevel@tonic-gate 443*7c478bd9Sstevel@tonic-gate switch (sockets[sock_id].so_state & 444*7c478bd9Sstevel@tonic-gate (SS_CANTRCVMORE | SS_CANTSENDMORE)) { 445*7c478bd9Sstevel@tonic-gate case (SS_CANTRCVMORE | SS_CANTSENDMORE): 446*7c478bd9Sstevel@tonic-gate /* Call lower level protocol close routine. */ 447*7c478bd9Sstevel@tonic-gate for (i = TRANSPORT_LVL; i >= MEDIA_LVL; i--) { 448*7c478bd9Sstevel@tonic-gate if (sockets[sock_id].close[i] != NULL) { 449*7c478bd9Sstevel@tonic-gate (void) sockets[sock_id].close[i](sock_id); 450*7c478bd9Sstevel@tonic-gate } 451*7c478bd9Sstevel@tonic-gate } 452*7c478bd9Sstevel@tonic-gate nuke_grams(&sockets[sock_id].inq); 453*7c478bd9Sstevel@tonic-gate break; 454*7c478bd9Sstevel@tonic-gate case SS_CANTRCVMORE: 455*7c478bd9Sstevel@tonic-gate nuke_grams(&sockets[sock_id].inq); 456*7c478bd9Sstevel@tonic-gate break; 457*7c478bd9Sstevel@tonic-gate case SS_CANTSENDMORE: 458*7c478bd9Sstevel@tonic-gate /* Call lower level protocol close routine. */ 459*7c478bd9Sstevel@tonic-gate if (tcp_shutdown(sock_id) < 0) 460*7c478bd9Sstevel@tonic-gate return (-1); 461*7c478bd9Sstevel@tonic-gate break; 462*7c478bd9Sstevel@tonic-gate default: 463*7c478bd9Sstevel@tonic-gate errno = EINVAL; 464*7c478bd9Sstevel@tonic-gate return (-1); 465*7c478bd9Sstevel@tonic-gate } 466*7c478bd9Sstevel@tonic-gate 467*7c478bd9Sstevel@tonic-gate return (0); 468*7c478bd9Sstevel@tonic-gate } 469*7c478bd9Sstevel@tonic-gate 470*7c478bd9Sstevel@tonic-gate /* 471*7c478bd9Sstevel@tonic-gate * "close" a socket. 472*7c478bd9Sstevel@tonic-gate */ 473*7c478bd9Sstevel@tonic-gate int 474*7c478bd9Sstevel@tonic-gate socket_close(int s) 475*7c478bd9Sstevel@tonic-gate { 476*7c478bd9Sstevel@tonic-gate int sock_id, i; 477*7c478bd9Sstevel@tonic-gate 478*7c478bd9Sstevel@tonic-gate errno = 0; 479*7c478bd9Sstevel@tonic-gate if ((sock_id = so_check_fd(s, &errno)) == -1) 480*7c478bd9Sstevel@tonic-gate return (-1); 481*7c478bd9Sstevel@tonic-gate 482*7c478bd9Sstevel@tonic-gate /* Call lower level protocol close routine. */ 483*7c478bd9Sstevel@tonic-gate for (i = TRANSPORT_LVL; i >= MEDIA_LVL; i--) { 484*7c478bd9Sstevel@tonic-gate if (sockets[sock_id].close[i] != NULL) { 485*7c478bd9Sstevel@tonic-gate /* 486*7c478bd9Sstevel@tonic-gate * Note that the close() routine of other 487*7c478bd9Sstevel@tonic-gate * layers can return an error. But right 488*7c478bd9Sstevel@tonic-gate * now, the only mechanism to report that 489*7c478bd9Sstevel@tonic-gate * back is for the close() routine to set 490*7c478bd9Sstevel@tonic-gate * the errno and socket_close() will return 491*7c478bd9Sstevel@tonic-gate * an error. But the close operation will 492*7c478bd9Sstevel@tonic-gate * not be stopped. 493*7c478bd9Sstevel@tonic-gate */ 494*7c478bd9Sstevel@tonic-gate (void) sockets[sock_id].close[i](sock_id); 495*7c478bd9Sstevel@tonic-gate } 496*7c478bd9Sstevel@tonic-gate } 497*7c478bd9Sstevel@tonic-gate 498*7c478bd9Sstevel@tonic-gate /* 499*7c478bd9Sstevel@tonic-gate * Clear the input queue. This has to be done 500*7c478bd9Sstevel@tonic-gate * after the lower level protocol close routines have been 501*7c478bd9Sstevel@tonic-gate * called as they may want to do something about the queue. 502*7c478bd9Sstevel@tonic-gate */ 503*7c478bd9Sstevel@tonic-gate nuke_grams(&sockets[sock_id].inq); 504*7c478bd9Sstevel@tonic-gate 505*7c478bd9Sstevel@tonic-gate bzero((caddr_t)&sockets[sock_id], sizeof (struct inetboot_socket)); 506*7c478bd9Sstevel@tonic-gate sockets[sock_id].type = INETBOOT_UNUSED; 507*7c478bd9Sstevel@tonic-gate 508*7c478bd9Sstevel@tonic-gate return (0); 509*7c478bd9Sstevel@tonic-gate } 510*7c478bd9Sstevel@tonic-gate 511*7c478bd9Sstevel@tonic-gate /* 512*7c478bd9Sstevel@tonic-gate * Read up to `nbyte' of data from socket `s' into `buf'; if non-zero, 513*7c478bd9Sstevel@tonic-gate * then give up after `read_timeout' seconds. Returns the number of 514*7c478bd9Sstevel@tonic-gate * bytes read, or -1 on failure. 515*7c478bd9Sstevel@tonic-gate */ 516*7c478bd9Sstevel@tonic-gate int 517*7c478bd9Sstevel@tonic-gate socket_read(int s, void *buf, size_t nbyte, int read_timeout) 518*7c478bd9Sstevel@tonic-gate { 519*7c478bd9Sstevel@tonic-gate ssize_t n; 520*7c478bd9Sstevel@tonic-gate uint_t start, diff; 521*7c478bd9Sstevel@tonic-gate struct sockaddr from; 522*7c478bd9Sstevel@tonic-gate uint_t fromlen = sizeof (from); 523*7c478bd9Sstevel@tonic-gate 524*7c478bd9Sstevel@tonic-gate /* 525*7c478bd9Sstevel@tonic-gate * keep calling non-blocking recvfrom until something received 526*7c478bd9Sstevel@tonic-gate * or an error occurs 527*7c478bd9Sstevel@tonic-gate */ 528*7c478bd9Sstevel@tonic-gate start = prom_gettime(); 529*7c478bd9Sstevel@tonic-gate while ((n = recvfrom(s, buf, nbyte, 0, &from, &fromlen)) == 0) { 530*7c478bd9Sstevel@tonic-gate diff = (uint_t)((prom_gettime() - start) + 500) / 1000; 531*7c478bd9Sstevel@tonic-gate if (read_timeout != 0 && diff > read_timeout) { 532*7c478bd9Sstevel@tonic-gate errno = EINTR; 533*7c478bd9Sstevel@tonic-gate return (-1); 534*7c478bd9Sstevel@tonic-gate } 535*7c478bd9Sstevel@tonic-gate } 536*7c478bd9Sstevel@tonic-gate return (n); 537*7c478bd9Sstevel@tonic-gate } 538*7c478bd9Sstevel@tonic-gate 539*7c478bd9Sstevel@tonic-gate /* 540*7c478bd9Sstevel@tonic-gate * Write up to `nbyte' bytes of data from `buf' to the address pointed to 541*7c478bd9Sstevel@tonic-gate * `addr' using socket `s'. Returns the number of bytes writte on success, 542*7c478bd9Sstevel@tonic-gate * or -1 on failure. 543*7c478bd9Sstevel@tonic-gate */ 544*7c478bd9Sstevel@tonic-gate int 545*7c478bd9Sstevel@tonic-gate socket_write(int s, const void *buf, size_t nbyte, struct sockaddr_in *addr) 546*7c478bd9Sstevel@tonic-gate { 547*7c478bd9Sstevel@tonic-gate return (sendto(s, buf, nbyte, 0, (struct sockaddr *)addr, 548*7c478bd9Sstevel@tonic-gate sizeof (*addr))); 549*7c478bd9Sstevel@tonic-gate } 550*7c478bd9Sstevel@tonic-gate 551*7c478bd9Sstevel@tonic-gate static int 552*7c478bd9Sstevel@tonic-gate bind_check(int sock_id, const struct sockaddr *addr) 553*7c478bd9Sstevel@tonic-gate { 554*7c478bd9Sstevel@tonic-gate int k; 555*7c478bd9Sstevel@tonic-gate struct sockaddr_in *in_addr = (struct sockaddr_in *)addr; 556*7c478bd9Sstevel@tonic-gate 557*7c478bd9Sstevel@tonic-gate /* Do not check for duplicate bind() if SO_REUSEADDR option is set. */ 558*7c478bd9Sstevel@tonic-gate if (! (sockets[sock_id].so_opt & SO_REUSEADDR)) { 559*7c478bd9Sstevel@tonic-gate for (k = 0; k < MAXSOCKET; k++) { 560*7c478bd9Sstevel@tonic-gate if (sockets[k].type != INETBOOT_UNUSED && 561*7c478bd9Sstevel@tonic-gate sockets[k].proto == sockets[sock_id].proto && 562*7c478bd9Sstevel@tonic-gate sockets[k].bound) { 563*7c478bd9Sstevel@tonic-gate if ((sockets[k].bind.sin_addr.s_addr == 564*7c478bd9Sstevel@tonic-gate in_addr->sin_addr.s_addr) && 565*7c478bd9Sstevel@tonic-gate (sockets[k].bind.sin_port == 566*7c478bd9Sstevel@tonic-gate in_addr->sin_port)) { 567*7c478bd9Sstevel@tonic-gate errno = EADDRINUSE; 568*7c478bd9Sstevel@tonic-gate return (-1); 569*7c478bd9Sstevel@tonic-gate } 570*7c478bd9Sstevel@tonic-gate } 571*7c478bd9Sstevel@tonic-gate } 572*7c478bd9Sstevel@tonic-gate } 573*7c478bd9Sstevel@tonic-gate return (0); 574*7c478bd9Sstevel@tonic-gate } 575*7c478bd9Sstevel@tonic-gate 576*7c478bd9Sstevel@tonic-gate /* Assign a name to an unnamed socket. */ 577*7c478bd9Sstevel@tonic-gate int 578*7c478bd9Sstevel@tonic-gate bind(int s, const struct sockaddr *name, socklen_t namelen) 579*7c478bd9Sstevel@tonic-gate { 580*7c478bd9Sstevel@tonic-gate int i; 581*7c478bd9Sstevel@tonic-gate 582*7c478bd9Sstevel@tonic-gate errno = 0; 583*7c478bd9Sstevel@tonic-gate 584*7c478bd9Sstevel@tonic-gate if ((i = so_check_fd(s, &errno)) == -1) 585*7c478bd9Sstevel@tonic-gate return (-1); 586*7c478bd9Sstevel@tonic-gate 587*7c478bd9Sstevel@tonic-gate if (name == NULL) { 588*7c478bd9Sstevel@tonic-gate /* unbind */ 589*7c478bd9Sstevel@tonic-gate if (sockets[i].bound) { 590*7c478bd9Sstevel@tonic-gate bzero((caddr_t)&sockets[i].bind, 591*7c478bd9Sstevel@tonic-gate sizeof (struct sockaddr_in)); 592*7c478bd9Sstevel@tonic-gate sockets[i].bound = B_FALSE; 593*7c478bd9Sstevel@tonic-gate } 594*7c478bd9Sstevel@tonic-gate return (0); 595*7c478bd9Sstevel@tonic-gate } 596*7c478bd9Sstevel@tonic-gate if (namelen != sizeof (struct sockaddr_in) || name == NULL) { 597*7c478bd9Sstevel@tonic-gate errno = EINVAL; 598*7c478bd9Sstevel@tonic-gate return (-1); 599*7c478bd9Sstevel@tonic-gate } 600*7c478bd9Sstevel@tonic-gate if (name->sa_family != AF_INET) { 601*7c478bd9Sstevel@tonic-gate errno = EAFNOSUPPORT; 602*7c478bd9Sstevel@tonic-gate return (-1); 603*7c478bd9Sstevel@tonic-gate } 604*7c478bd9Sstevel@tonic-gate if (sockets[i].bound) { 605*7c478bd9Sstevel@tonic-gate if (bcmp((caddr_t)&sockets[i].bind, (caddr_t)name, 606*7c478bd9Sstevel@tonic-gate namelen) == 0) { 607*7c478bd9Sstevel@tonic-gate /* attempt to bind to same address ok... */ 608*7c478bd9Sstevel@tonic-gate return (0); 609*7c478bd9Sstevel@tonic-gate } 610*7c478bd9Sstevel@tonic-gate errno = EINVAL; /* already bound */ 611*7c478bd9Sstevel@tonic-gate return (-1); 612*7c478bd9Sstevel@tonic-gate } 613*7c478bd9Sstevel@tonic-gate 614*7c478bd9Sstevel@tonic-gate if (errno != 0) { 615*7c478bd9Sstevel@tonic-gate return (-1); 616*7c478bd9Sstevel@tonic-gate } 617*7c478bd9Sstevel@tonic-gate 618*7c478bd9Sstevel@tonic-gate /* Check for duplicate bind(). */ 619*7c478bd9Sstevel@tonic-gate if (bind_check(i, name) < 0) 620*7c478bd9Sstevel@tonic-gate return (-1); 621*7c478bd9Sstevel@tonic-gate 622*7c478bd9Sstevel@tonic-gate bcopy((caddr_t)name, (caddr_t)&sockets[i].bind, namelen); 623*7c478bd9Sstevel@tonic-gate if (sockets[i].type == INETBOOT_STREAM) { 624*7c478bd9Sstevel@tonic-gate if (tcp_bind(i) < 0) { 625*7c478bd9Sstevel@tonic-gate return (-1); 626*7c478bd9Sstevel@tonic-gate } 627*7c478bd9Sstevel@tonic-gate } 628*7c478bd9Sstevel@tonic-gate sockets[i].bound = B_TRUE; 629*7c478bd9Sstevel@tonic-gate 630*7c478bd9Sstevel@tonic-gate return (0); 631*7c478bd9Sstevel@tonic-gate } 632*7c478bd9Sstevel@tonic-gate 633*7c478bd9Sstevel@tonic-gate static int 634*7c478bd9Sstevel@tonic-gate quickbind(int sock_id) 635*7c478bd9Sstevel@tonic-gate { 636*7c478bd9Sstevel@tonic-gate int i; 637*7c478bd9Sstevel@tonic-gate struct sockaddr_in addr; 638*7c478bd9Sstevel@tonic-gate 639*7c478bd9Sstevel@tonic-gate /* 640*7c478bd9Sstevel@tonic-gate * XXX This needs more work. Right now, if ipv4_setipaddr() 641*7c478bd9Sstevel@tonic-gate * have not been called, this will be wrong. But we need 642*7c478bd9Sstevel@tonic-gate * something better. Need to be revisited. 643*7c478bd9Sstevel@tonic-gate */ 644*7c478bd9Sstevel@tonic-gate ipv4_getipaddr(&addr.sin_addr); 645*7c478bd9Sstevel@tonic-gate addr.sin_family = AF_INET; 646*7c478bd9Sstevel@tonic-gate 647*7c478bd9Sstevel@tonic-gate for (i = SMALLEST_ANON_PORT; i <= LARGEST_ANON_PORT; i++) { 648*7c478bd9Sstevel@tonic-gate addr.sin_port = htons(i); 649*7c478bd9Sstevel@tonic-gate if (bind_check(sock_id, (struct sockaddr *)&addr) == 0) 650*7c478bd9Sstevel@tonic-gate break; 651*7c478bd9Sstevel@tonic-gate } 652*7c478bd9Sstevel@tonic-gate /* Need to clear errno as it is probably set by bind_check(). */ 653*7c478bd9Sstevel@tonic-gate errno = 0; 654*7c478bd9Sstevel@tonic-gate 655*7c478bd9Sstevel@tonic-gate if (i <= LARGEST_ANON_PORT) { 656*7c478bd9Sstevel@tonic-gate bcopy((caddr_t)&addr, (caddr_t)&sockets[sock_id].bind, 657*7c478bd9Sstevel@tonic-gate sizeof (struct sockaddr_in)); 658*7c478bd9Sstevel@tonic-gate sockets[sock_id].bound = B_TRUE; 659*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 660*7c478bd9Sstevel@tonic-gate printf("quick bind done addr %s port %d\n", 661*7c478bd9Sstevel@tonic-gate inet_ntoa(sockets[sock_id].bind.sin_addr), 662*7c478bd9Sstevel@tonic-gate ntohs(sockets[sock_id].bind.sin_port)); 663*7c478bd9Sstevel@tonic-gate #endif 664*7c478bd9Sstevel@tonic-gate return (0); 665*7c478bd9Sstevel@tonic-gate } else { 666*7c478bd9Sstevel@tonic-gate return (-1); 667*7c478bd9Sstevel@tonic-gate } 668*7c478bd9Sstevel@tonic-gate } 669*7c478bd9Sstevel@tonic-gate 670*7c478bd9Sstevel@tonic-gate int 671*7c478bd9Sstevel@tonic-gate listen(int fd, int backlog) 672*7c478bd9Sstevel@tonic-gate { 673*7c478bd9Sstevel@tonic-gate int sock_id; 674*7c478bd9Sstevel@tonic-gate 675*7c478bd9Sstevel@tonic-gate errno = 0; 676*7c478bd9Sstevel@tonic-gate if ((sock_id = so_check_fd(fd, &errno)) == -1) 677*7c478bd9Sstevel@tonic-gate return (-1); 678*7c478bd9Sstevel@tonic-gate 679*7c478bd9Sstevel@tonic-gate if (sockets[sock_id].type != INETBOOT_STREAM) { 680*7c478bd9Sstevel@tonic-gate errno = EOPNOTSUPP; 681*7c478bd9Sstevel@tonic-gate return (-1); 682*7c478bd9Sstevel@tonic-gate } 683*7c478bd9Sstevel@tonic-gate if (sockets[sock_id].so_error != 0) { 684*7c478bd9Sstevel@tonic-gate errno = sockets[sock_id].so_error; 685*7c478bd9Sstevel@tonic-gate return (-1); 686*7c478bd9Sstevel@tonic-gate } 687*7c478bd9Sstevel@tonic-gate return (tcp_listen(sock_id, backlog)); 688*7c478bd9Sstevel@tonic-gate } 689*7c478bd9Sstevel@tonic-gate 690*7c478bd9Sstevel@tonic-gate int 691*7c478bd9Sstevel@tonic-gate accept(int fd, struct sockaddr *addr, socklen_t *addr_len) 692*7c478bd9Sstevel@tonic-gate { 693*7c478bd9Sstevel@tonic-gate int sock_id; 694*7c478bd9Sstevel@tonic-gate int new_sd; 695*7c478bd9Sstevel@tonic-gate 696*7c478bd9Sstevel@tonic-gate errno = 0; 697*7c478bd9Sstevel@tonic-gate if ((sock_id = so_check_fd(fd, &errno)) == -1) 698*7c478bd9Sstevel@tonic-gate return (-1); 699*7c478bd9Sstevel@tonic-gate 700*7c478bd9Sstevel@tonic-gate if (sockets[sock_id].type != INETBOOT_STREAM) { 701*7c478bd9Sstevel@tonic-gate errno = EOPNOTSUPP; 702*7c478bd9Sstevel@tonic-gate return (-1); 703*7c478bd9Sstevel@tonic-gate } 704*7c478bd9Sstevel@tonic-gate if (sockets[sock_id].so_error != 0) { 705*7c478bd9Sstevel@tonic-gate errno = sockets[sock_id].so_error; 706*7c478bd9Sstevel@tonic-gate return (-1); 707*7c478bd9Sstevel@tonic-gate } 708*7c478bd9Sstevel@tonic-gate if ((new_sd = tcp_accept(sock_id, addr, addr_len)) == -1) 709*7c478bd9Sstevel@tonic-gate return (-1); 710*7c478bd9Sstevel@tonic-gate sock_id = so_check_fd(new_sd, &errno); 711*7c478bd9Sstevel@tonic-gate sockets[sock_id].so_state |= SS_ISCONNECTED; 712*7c478bd9Sstevel@tonic-gate return (new_sd); 713*7c478bd9Sstevel@tonic-gate } 714*7c478bd9Sstevel@tonic-gate 715*7c478bd9Sstevel@tonic-gate int 716*7c478bd9Sstevel@tonic-gate connect(int fd, const struct sockaddr *addr, socklen_t addr_len) 717*7c478bd9Sstevel@tonic-gate { 718*7c478bd9Sstevel@tonic-gate int sock_id; 719*7c478bd9Sstevel@tonic-gate int so_type; 720*7c478bd9Sstevel@tonic-gate 721*7c478bd9Sstevel@tonic-gate errno = 0; 722*7c478bd9Sstevel@tonic-gate if ((sock_id = so_check_fd(fd, &errno)) == -1) 723*7c478bd9Sstevel@tonic-gate return (-1); 724*7c478bd9Sstevel@tonic-gate 725*7c478bd9Sstevel@tonic-gate so_type = sockets[sock_id].type; 726*7c478bd9Sstevel@tonic-gate 727*7c478bd9Sstevel@tonic-gate if (addr == NULL || addr_len == 0) { 728*7c478bd9Sstevel@tonic-gate errno = EINVAL; 729*7c478bd9Sstevel@tonic-gate return (-1); 730*7c478bd9Sstevel@tonic-gate } 731*7c478bd9Sstevel@tonic-gate /* Don't allow connect for raw socket. */ 732*7c478bd9Sstevel@tonic-gate if (so_type == INETBOOT_RAW) { 733*7c478bd9Sstevel@tonic-gate errno = EPROTONOSUPPORT; 734*7c478bd9Sstevel@tonic-gate return (-1); 735*7c478bd9Sstevel@tonic-gate } 736*7c478bd9Sstevel@tonic-gate 737*7c478bd9Sstevel@tonic-gate if (sockets[sock_id].so_state & SS_ISCONNECTED) { 738*7c478bd9Sstevel@tonic-gate errno = EINVAL; 739*7c478bd9Sstevel@tonic-gate return (-1); 740*7c478bd9Sstevel@tonic-gate } 741*7c478bd9Sstevel@tonic-gate 742*7c478bd9Sstevel@tonic-gate if (sockets[sock_id].so_error != 0) { 743*7c478bd9Sstevel@tonic-gate errno = sockets[sock_id].so_error; 744*7c478bd9Sstevel@tonic-gate return (-1); 745*7c478bd9Sstevel@tonic-gate } 746*7c478bd9Sstevel@tonic-gate 747*7c478bd9Sstevel@tonic-gate /* If the socket is not bound, we need to do a quick bind. */ 748*7c478bd9Sstevel@tonic-gate if (!sockets[sock_id].bound) { 749*7c478bd9Sstevel@tonic-gate /* For TCP socket, just call tcp_bind(). */ 750*7c478bd9Sstevel@tonic-gate if (so_type == INETBOOT_STREAM) { 751*7c478bd9Sstevel@tonic-gate if (tcp_bind(sock_id) < 0) 752*7c478bd9Sstevel@tonic-gate return (-1); 753*7c478bd9Sstevel@tonic-gate } else { 754*7c478bd9Sstevel@tonic-gate if (quickbind(sock_id) < 0) { 755*7c478bd9Sstevel@tonic-gate errno = EADDRNOTAVAIL; 756*7c478bd9Sstevel@tonic-gate return (-1); 757*7c478bd9Sstevel@tonic-gate } 758*7c478bd9Sstevel@tonic-gate } 759*7c478bd9Sstevel@tonic-gate } 760*7c478bd9Sstevel@tonic-gate /* Should do some sanity check for addr .... */ 761*7c478bd9Sstevel@tonic-gate bcopy((caddr_t)addr, &sockets[sock_id].remote, 762*7c478bd9Sstevel@tonic-gate sizeof (struct sockaddr_in)); 763*7c478bd9Sstevel@tonic-gate 764*7c478bd9Sstevel@tonic-gate if (sockets[sock_id].type == INETBOOT_STREAM) { 765*7c478bd9Sstevel@tonic-gate /* Call TCP connect routine. */ 766*7c478bd9Sstevel@tonic-gate if (tcp_connect(sock_id) == 0) 767*7c478bd9Sstevel@tonic-gate sockets[sock_id].so_state |= SS_ISCONNECTED; 768*7c478bd9Sstevel@tonic-gate else { 769*7c478bd9Sstevel@tonic-gate if (sockets[sock_id].so_error != 0) 770*7c478bd9Sstevel@tonic-gate errno = sockets[sock_id].so_error; 771*7c478bd9Sstevel@tonic-gate return (-1); 772*7c478bd9Sstevel@tonic-gate } 773*7c478bd9Sstevel@tonic-gate } else { 774*7c478bd9Sstevel@tonic-gate sockets[sock_id].so_state |= SS_ISCONNECTED; 775*7c478bd9Sstevel@tonic-gate } 776*7c478bd9Sstevel@tonic-gate return (0); 777*7c478bd9Sstevel@tonic-gate } 778*7c478bd9Sstevel@tonic-gate 779*7c478bd9Sstevel@tonic-gate /* Just a wrapper around recvfrom(). */ 780*7c478bd9Sstevel@tonic-gate ssize_t 781*7c478bd9Sstevel@tonic-gate recv(int s, void *buf, size_t len, int flags) 782*7c478bd9Sstevel@tonic-gate { 783*7c478bd9Sstevel@tonic-gate return (recvfrom(s, buf, len, flags, NULL, NULL)); 784*7c478bd9Sstevel@tonic-gate } 785*7c478bd9Sstevel@tonic-gate 786*7c478bd9Sstevel@tonic-gate /* 787*7c478bd9Sstevel@tonic-gate * Receive messages from a connectionless socket. Legal flags are 0 and 788*7c478bd9Sstevel@tonic-gate * MSG_DONTWAIT. MSG_WAITALL is not currently supported. 789*7c478bd9Sstevel@tonic-gate * 790*7c478bd9Sstevel@tonic-gate * Returns length of message for success, -1 if error occurred. 791*7c478bd9Sstevel@tonic-gate */ 792*7c478bd9Sstevel@tonic-gate ssize_t 793*7c478bd9Sstevel@tonic-gate recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, 794*7c478bd9Sstevel@tonic-gate socklen_t *fromlen) 795*7c478bd9Sstevel@tonic-gate { 796*7c478bd9Sstevel@tonic-gate int sock_id, i; 797*7c478bd9Sstevel@tonic-gate ssize_t datalen, bytes = 0; 798*7c478bd9Sstevel@tonic-gate struct inetgram *icp; 799*7c478bd9Sstevel@tonic-gate enum SockType so_type; 800*7c478bd9Sstevel@tonic-gate char *tmp_buf; 801*7c478bd9Sstevel@tonic-gate mblk_t *mp; 802*7c478bd9Sstevel@tonic-gate 803*7c478bd9Sstevel@tonic-gate errno = 0; 804*7c478bd9Sstevel@tonic-gate 805*7c478bd9Sstevel@tonic-gate if ((sock_id = so_check_fd(s, &errno)) == -1) { 806*7c478bd9Sstevel@tonic-gate errno = EINVAL; 807*7c478bd9Sstevel@tonic-gate return (-1); 808*7c478bd9Sstevel@tonic-gate } 809*7c478bd9Sstevel@tonic-gate 810*7c478bd9Sstevel@tonic-gate if (sockets[sock_id].type == INETBOOT_STREAM && 811*7c478bd9Sstevel@tonic-gate !(sockets[sock_id].so_state & SS_ISCONNECTED)) { 812*7c478bd9Sstevel@tonic-gate errno = ENOTCONN; 813*7c478bd9Sstevel@tonic-gate return (-1); 814*7c478bd9Sstevel@tonic-gate } 815*7c478bd9Sstevel@tonic-gate 816*7c478bd9Sstevel@tonic-gate if (buf == NULL || len == 0) { 817*7c478bd9Sstevel@tonic-gate errno = EINVAL; 818*7c478bd9Sstevel@tonic-gate return (-1); 819*7c478bd9Sstevel@tonic-gate } 820*7c478bd9Sstevel@tonic-gate /* Yup - MSG_WAITALL not implemented */ 821*7c478bd9Sstevel@tonic-gate if ((flags & ~MSG_DONTWAIT) != 0) { 822*7c478bd9Sstevel@tonic-gate errno = EINVAL; 823*7c478bd9Sstevel@tonic-gate return (-1); 824*7c478bd9Sstevel@tonic-gate } 825*7c478bd9Sstevel@tonic-gate 826*7c478bd9Sstevel@tonic-gate retry: 827*7c478bd9Sstevel@tonic-gate if (sockets[sock_id].inq == NULL) { 828*7c478bd9Sstevel@tonic-gate /* Go out and check the wire */ 829*7c478bd9Sstevel@tonic-gate for (i = MEDIA_LVL; i < APP_LVL; i++) { 830*7c478bd9Sstevel@tonic-gate if (sockets[sock_id].input[i] != NULL) { 831*7c478bd9Sstevel@tonic-gate if (sockets[sock_id].input[i](sock_id) < 0) { 832*7c478bd9Sstevel@tonic-gate if (sockets[sock_id].so_error != 0) { 833*7c478bd9Sstevel@tonic-gate errno = 834*7c478bd9Sstevel@tonic-gate sockets[sock_id].so_error; 835*7c478bd9Sstevel@tonic-gate } 836*7c478bd9Sstevel@tonic-gate return (-1); 837*7c478bd9Sstevel@tonic-gate } 838*7c478bd9Sstevel@tonic-gate } 839*7c478bd9Sstevel@tonic-gate } 840*7c478bd9Sstevel@tonic-gate } 841*7c478bd9Sstevel@tonic-gate 842*7c478bd9Sstevel@tonic-gate so_type = sockets[sock_id].type; 843*7c478bd9Sstevel@tonic-gate 844*7c478bd9Sstevel@tonic-gate /* Remove unknown inetgrams from the head of inq. Can this happen? */ 845*7c478bd9Sstevel@tonic-gate while ((icp = sockets[sock_id].inq) != NULL) { 846*7c478bd9Sstevel@tonic-gate if ((so_type == INETBOOT_DGRAM || 847*7c478bd9Sstevel@tonic-gate so_type == INETBOOT_STREAM) && 848*7c478bd9Sstevel@tonic-gate icp->igm_level != APP_LVL) { 849*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 850*7c478bd9Sstevel@tonic-gate printf("recvfrom: unexpected level %d frame found\n", 851*7c478bd9Sstevel@tonic-gate icp->igm_level); 852*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 853*7c478bd9Sstevel@tonic-gate del_gram(&sockets[sock_id].inq, icp, B_TRUE); 854*7c478bd9Sstevel@tonic-gate continue; 855*7c478bd9Sstevel@tonic-gate } else { 856*7c478bd9Sstevel@tonic-gate break; 857*7c478bd9Sstevel@tonic-gate } 858*7c478bd9Sstevel@tonic-gate } 859*7c478bd9Sstevel@tonic-gate 860*7c478bd9Sstevel@tonic-gate 861*7c478bd9Sstevel@tonic-gate if (icp == NULL) { 862*7c478bd9Sstevel@tonic-gate /* 863*7c478bd9Sstevel@tonic-gate * Checking for error should be done everytime a lower layer 864*7c478bd9Sstevel@tonic-gate * input routing is called. For example, if TCP gets a RST, 865*7c478bd9Sstevel@tonic-gate * this should be reported asap. 866*7c478bd9Sstevel@tonic-gate */ 867*7c478bd9Sstevel@tonic-gate if (sockets[sock_id].so_state & SS_CANTRCVMORE) { 868*7c478bd9Sstevel@tonic-gate if (sockets[sock_id].so_error != 0) { 869*7c478bd9Sstevel@tonic-gate errno = sockets[sock_id].so_error; 870*7c478bd9Sstevel@tonic-gate return (-1); 871*7c478bd9Sstevel@tonic-gate } else { 872*7c478bd9Sstevel@tonic-gate return (0); 873*7c478bd9Sstevel@tonic-gate } 874*7c478bd9Sstevel@tonic-gate } 875*7c478bd9Sstevel@tonic-gate 876*7c478bd9Sstevel@tonic-gate if ((flags & MSG_DONTWAIT) == 0) 877*7c478bd9Sstevel@tonic-gate goto retry; /* wait forever */ 878*7c478bd9Sstevel@tonic-gate 879*7c478bd9Sstevel@tonic-gate /* no data */ 880*7c478bd9Sstevel@tonic-gate errno = EWOULDBLOCK; 881*7c478bd9Sstevel@tonic-gate return (-1); 882*7c478bd9Sstevel@tonic-gate } 883*7c478bd9Sstevel@tonic-gate 884*7c478bd9Sstevel@tonic-gate if (from != NULL && fromlen != NULL) { 885*7c478bd9Sstevel@tonic-gate switch (so_type) { 886*7c478bd9Sstevel@tonic-gate case INETBOOT_STREAM: 887*7c478bd9Sstevel@tonic-gate /* Need to copy from the socket's remote address. */ 888*7c478bd9Sstevel@tonic-gate bcopy(&(sockets[sock_id].remote), from, MIN(*fromlen, 889*7c478bd9Sstevel@tonic-gate sizeof (struct sockaddr_in))); 890*7c478bd9Sstevel@tonic-gate break; 891*7c478bd9Sstevel@tonic-gate case INETBOOT_RAW: 892*7c478bd9Sstevel@tonic-gate case INETBOOT_DGRAM: 893*7c478bd9Sstevel@tonic-gate default: 894*7c478bd9Sstevel@tonic-gate if (*fromlen > sizeof (icp->igm_saddr)) 895*7c478bd9Sstevel@tonic-gate *fromlen = sizeof (icp->igm_saddr); 896*7c478bd9Sstevel@tonic-gate bcopy((caddr_t)&(icp->igm_saddr), (caddr_t)from, 897*7c478bd9Sstevel@tonic-gate MIN(*fromlen, sizeof (struct sockaddr_in))); 898*7c478bd9Sstevel@tonic-gate break; 899*7c478bd9Sstevel@tonic-gate } 900*7c478bd9Sstevel@tonic-gate } 901*7c478bd9Sstevel@tonic-gate 902*7c478bd9Sstevel@tonic-gate mp = icp->igm_mp; 903*7c478bd9Sstevel@tonic-gate switch (so_type) { 904*7c478bd9Sstevel@tonic-gate case INETBOOT_STREAM: 905*7c478bd9Sstevel@tonic-gate /* 906*7c478bd9Sstevel@tonic-gate * If the message has igm_id == TCP_CALLB_MAGIC_ID, we need 907*7c478bd9Sstevel@tonic-gate * to drain the data held by tcp and try again. 908*7c478bd9Sstevel@tonic-gate */ 909*7c478bd9Sstevel@tonic-gate if (icp->igm_id == TCP_CALLB_MAGIC_ID) { 910*7c478bd9Sstevel@tonic-gate del_gram(&sockets[sock_id].inq, icp, B_TRUE); 911*7c478bd9Sstevel@tonic-gate tcp_rcv_drain_sock(sock_id); 912*7c478bd9Sstevel@tonic-gate goto retry; 913*7c478bd9Sstevel@tonic-gate } 914*7c478bd9Sstevel@tonic-gate 915*7c478bd9Sstevel@tonic-gate /* TCP should put only user data in the inetgram. */ 916*7c478bd9Sstevel@tonic-gate tmp_buf = (char *)buf; 917*7c478bd9Sstevel@tonic-gate while (len > 0 && icp != NULL) { 918*7c478bd9Sstevel@tonic-gate datalen = mp->b_wptr - mp->b_rptr; 919*7c478bd9Sstevel@tonic-gate if (len < datalen) { 920*7c478bd9Sstevel@tonic-gate bcopy(mp->b_rptr, tmp_buf, len); 921*7c478bd9Sstevel@tonic-gate bytes += len; 922*7c478bd9Sstevel@tonic-gate mp->b_rptr += len; 923*7c478bd9Sstevel@tonic-gate break; 924*7c478bd9Sstevel@tonic-gate } else { 925*7c478bd9Sstevel@tonic-gate bcopy(mp->b_rptr, tmp_buf, datalen); 926*7c478bd9Sstevel@tonic-gate len -= datalen; 927*7c478bd9Sstevel@tonic-gate bytes += datalen; 928*7c478bd9Sstevel@tonic-gate tmp_buf += datalen; 929*7c478bd9Sstevel@tonic-gate del_gram(&sockets[sock_id].inq, icp, B_TRUE); 930*7c478bd9Sstevel@tonic-gate 931*7c478bd9Sstevel@tonic-gate /* 932*7c478bd9Sstevel@tonic-gate * If we have any embedded magic messages just 933*7c478bd9Sstevel@tonic-gate * drop them. 934*7c478bd9Sstevel@tonic-gate */ 935*7c478bd9Sstevel@tonic-gate while ((icp = sockets[sock_id].inq) != NULL) { 936*7c478bd9Sstevel@tonic-gate if (icp->igm_id != TCP_CALLB_MAGIC_ID) 937*7c478bd9Sstevel@tonic-gate break; 938*7c478bd9Sstevel@tonic-gate del_gram(&sockets[sock_id].inq, icp, 939*7c478bd9Sstevel@tonic-gate B_TRUE); 940*7c478bd9Sstevel@tonic-gate } 941*7c478bd9Sstevel@tonic-gate 942*7c478bd9Sstevel@tonic-gate if (icp == NULL) 943*7c478bd9Sstevel@tonic-gate break; 944*7c478bd9Sstevel@tonic-gate mp = icp->igm_mp; 945*7c478bd9Sstevel@tonic-gate } 946*7c478bd9Sstevel@tonic-gate } 947*7c478bd9Sstevel@tonic-gate sockets[sock_id].so_rcvbuf += (int32_t)bytes; 948*7c478bd9Sstevel@tonic-gate break; 949*7c478bd9Sstevel@tonic-gate case INETBOOT_DGRAM: 950*7c478bd9Sstevel@tonic-gate datalen = mp->b_wptr - mp->b_rptr; 951*7c478bd9Sstevel@tonic-gate if (len < datalen) 952*7c478bd9Sstevel@tonic-gate bytes = len; 953*7c478bd9Sstevel@tonic-gate else 954*7c478bd9Sstevel@tonic-gate bytes = datalen; 955*7c478bd9Sstevel@tonic-gate bcopy(mp->b_rptr, buf, bytes); 956*7c478bd9Sstevel@tonic-gate del_gram(&sockets[sock_id].inq, icp, B_TRUE); 957*7c478bd9Sstevel@tonic-gate break; 958*7c478bd9Sstevel@tonic-gate case INETBOOT_RAW: 959*7c478bd9Sstevel@tonic-gate default: 960*7c478bd9Sstevel@tonic-gate datalen = mp->b_wptr - mp->b_rptr; 961*7c478bd9Sstevel@tonic-gate if (len < datalen) 962*7c478bd9Sstevel@tonic-gate bytes = len; 963*7c478bd9Sstevel@tonic-gate else 964*7c478bd9Sstevel@tonic-gate bytes = datalen; 965*7c478bd9Sstevel@tonic-gate bcopy(mp->b_rptr, buf, bytes); 966*7c478bd9Sstevel@tonic-gate del_gram(&sockets[sock_id].inq, icp, B_TRUE); 967*7c478bd9Sstevel@tonic-gate break; 968*7c478bd9Sstevel@tonic-gate } 969*7c478bd9Sstevel@tonic-gate 970*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 971*7c478bd9Sstevel@tonic-gate printf("recvfrom(%d): data: (0x%x,%d)\n", sock_id, 972*7c478bd9Sstevel@tonic-gate (icp != NULL) ? icp->igm_mp : 0, bytes); 973*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 974*7c478bd9Sstevel@tonic-gate return (bytes); 975*7c478bd9Sstevel@tonic-gate } 976*7c478bd9Sstevel@tonic-gate 977*7c478bd9Sstevel@tonic-gate 978*7c478bd9Sstevel@tonic-gate /* Just a wrapper around sendto(). */ 979*7c478bd9Sstevel@tonic-gate ssize_t 980*7c478bd9Sstevel@tonic-gate send(int s, const void *msg, size_t len, int flags) 981*7c478bd9Sstevel@tonic-gate { 982*7c478bd9Sstevel@tonic-gate return (sendto(s, msg, len, flags, NULL, 0)); 983*7c478bd9Sstevel@tonic-gate } 984*7c478bd9Sstevel@tonic-gate 985*7c478bd9Sstevel@tonic-gate /* 986*7c478bd9Sstevel@tonic-gate * Transmit a message through a socket. 987*7c478bd9Sstevel@tonic-gate * 988*7c478bd9Sstevel@tonic-gate * Supported flags: MSG_DONTROUTE or 0. 989*7c478bd9Sstevel@tonic-gate */ 990*7c478bd9Sstevel@tonic-gate ssize_t 991*7c478bd9Sstevel@tonic-gate sendto(int s, const void *msg, size_t len, int flags, const struct sockaddr *to, 992*7c478bd9Sstevel@tonic-gate socklen_t tolen) 993*7c478bd9Sstevel@tonic-gate { 994*7c478bd9Sstevel@tonic-gate enum SockType so_type; 995*7c478bd9Sstevel@tonic-gate int sock_id; 996*7c478bd9Sstevel@tonic-gate ssize_t bytes; 997*7c478bd9Sstevel@tonic-gate 998*7c478bd9Sstevel@tonic-gate errno = 0; 999*7c478bd9Sstevel@tonic-gate 1000*7c478bd9Sstevel@tonic-gate if ((sock_id = so_check_fd(s, &errno)) == -1) { 1001*7c478bd9Sstevel@tonic-gate return (-1); 1002*7c478bd9Sstevel@tonic-gate } 1003*7c478bd9Sstevel@tonic-gate if (msg == NULL) { 1004*7c478bd9Sstevel@tonic-gate errno = EINVAL; 1005*7c478bd9Sstevel@tonic-gate return (-1); 1006*7c478bd9Sstevel@tonic-gate } 1007*7c478bd9Sstevel@tonic-gate so_type = sockets[sock_id].type; 1008*7c478bd9Sstevel@tonic-gate if ((flags & ~MSG_DONTROUTE) != 0) { 1009*7c478bd9Sstevel@tonic-gate errno = EINVAL; 1010*7c478bd9Sstevel@tonic-gate return (-1); 1011*7c478bd9Sstevel@tonic-gate } 1012*7c478bd9Sstevel@tonic-gate if (sockets[sock_id].so_error != 0) { 1013*7c478bd9Sstevel@tonic-gate errno = sockets[sock_id].so_error; 1014*7c478bd9Sstevel@tonic-gate return (-1); 1015*7c478bd9Sstevel@tonic-gate } 1016*7c478bd9Sstevel@tonic-gate if (to != NULL && to->sa_family != AF_INET) { 1017*7c478bd9Sstevel@tonic-gate errno = EAFNOSUPPORT; 1018*7c478bd9Sstevel@tonic-gate return (-1); 1019*7c478bd9Sstevel@tonic-gate } 1020*7c478bd9Sstevel@tonic-gate 1021*7c478bd9Sstevel@tonic-gate switch (so_type) { 1022*7c478bd9Sstevel@tonic-gate case INETBOOT_RAW: 1023*7c478bd9Sstevel@tonic-gate case INETBOOT_DGRAM: 1024*7c478bd9Sstevel@tonic-gate if (!(sockets[sock_id].so_state & SS_ISCONNECTED) && 1025*7c478bd9Sstevel@tonic-gate (to == NULL || tolen != sizeof (struct sockaddr_in))) { 1026*7c478bd9Sstevel@tonic-gate errno = EINVAL; 1027*7c478bd9Sstevel@tonic-gate return (-1); 1028*7c478bd9Sstevel@tonic-gate } 1029*7c478bd9Sstevel@tonic-gate bytes = dgram_sendto(sock_id, msg, len, flags, to, tolen); 1030*7c478bd9Sstevel@tonic-gate break; 1031*7c478bd9Sstevel@tonic-gate case INETBOOT_STREAM: 1032*7c478bd9Sstevel@tonic-gate if (!((sockets[sock_id].so_state & SS_ISCONNECTED) || 1033*7c478bd9Sstevel@tonic-gate (sockets[sock_id].so_state & SS_ISCONNECTING))) { 1034*7c478bd9Sstevel@tonic-gate errno = EINVAL; 1035*7c478bd9Sstevel@tonic-gate return (-1); 1036*7c478bd9Sstevel@tonic-gate } 1037*7c478bd9Sstevel@tonic-gate if (sockets[sock_id].so_state & SS_CANTSENDMORE) { 1038*7c478bd9Sstevel@tonic-gate errno = EPIPE; 1039*7c478bd9Sstevel@tonic-gate return (-1); 1040*7c478bd9Sstevel@tonic-gate } 1041*7c478bd9Sstevel@tonic-gate bytes = stream_sendto(sock_id, msg, len, flags); 1042*7c478bd9Sstevel@tonic-gate break; 1043*7c478bd9Sstevel@tonic-gate default: 1044*7c478bd9Sstevel@tonic-gate /* Should not happen... */ 1045*7c478bd9Sstevel@tonic-gate errno = EPROTOTYPE; 1046*7c478bd9Sstevel@tonic-gate return (-1); 1047*7c478bd9Sstevel@tonic-gate } 1048*7c478bd9Sstevel@tonic-gate return (bytes); 1049*7c478bd9Sstevel@tonic-gate } 1050*7c478bd9Sstevel@tonic-gate 1051*7c478bd9Sstevel@tonic-gate static ssize_t 1052*7c478bd9Sstevel@tonic-gate dgram_sendto(int i, const void *msg, size_t len, int flags, 1053*7c478bd9Sstevel@tonic-gate const struct sockaddr *to, int tolen) 1054*7c478bd9Sstevel@tonic-gate { 1055*7c478bd9Sstevel@tonic-gate struct inetgram oc; 1056*7c478bd9Sstevel@tonic-gate int l, offset; 1057*7c478bd9Sstevel@tonic-gate size_t tlen; 1058*7c478bd9Sstevel@tonic-gate mblk_t *mp; 1059*7c478bd9Sstevel@tonic-gate 1060*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 1061*7c478bd9Sstevel@tonic-gate { 1062*7c478bd9Sstevel@tonic-gate struct sockaddr_in *sin = (struct sockaddr_in *)to; 1063*7c478bd9Sstevel@tonic-gate printf("sendto(%d): msg of length: %d sent to port %d and host: %s\n", 1064*7c478bd9Sstevel@tonic-gate i, len, ntohs(sin->sin_port), inet_ntoa(sin->sin_addr)); 1065*7c478bd9Sstevel@tonic-gate } 1066*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 1067*7c478bd9Sstevel@tonic-gate 1068*7c478bd9Sstevel@tonic-gate nuke_grams(&sockets[i].inq); /* flush the input queue */ 1069*7c478bd9Sstevel@tonic-gate 1070*7c478bd9Sstevel@tonic-gate /* calculate offset for data */ 1071*7c478bd9Sstevel@tonic-gate offset = sockets[i].headerlen[MEDIA_LVL](NULL) + 1072*7c478bd9Sstevel@tonic-gate (sockets[i].headerlen[NETWORK_LVL])(NULL); 1073*7c478bd9Sstevel@tonic-gate 1074*7c478bd9Sstevel@tonic-gate bzero((caddr_t)&oc, sizeof (oc)); 1075*7c478bd9Sstevel@tonic-gate if (sockets[i].type != INETBOOT_RAW) { 1076*7c478bd9Sstevel@tonic-gate offset += (sockets[i].headerlen[TRANSPORT_LVL])(NULL); 1077*7c478bd9Sstevel@tonic-gate oc.igm_level = TRANSPORT_LVL; 1078*7c478bd9Sstevel@tonic-gate } else 1079*7c478bd9Sstevel@tonic-gate oc.igm_level = NETWORK_LVL; 1080*7c478bd9Sstevel@tonic-gate oc.igm_oflags = flags; 1081*7c478bd9Sstevel@tonic-gate 1082*7c478bd9Sstevel@tonic-gate if (to != NULL) { 1083*7c478bd9Sstevel@tonic-gate bcopy((caddr_t)to, (caddr_t)&oc.igm_saddr, tolen); 1084*7c478bd9Sstevel@tonic-gate } else { 1085*7c478bd9Sstevel@tonic-gate bcopy((caddr_t)&sockets[i].remote, (caddr_t)&oc.igm_saddr, 1086*7c478bd9Sstevel@tonic-gate sizeof (struct sockaddr_in)); 1087*7c478bd9Sstevel@tonic-gate } 1088*7c478bd9Sstevel@tonic-gate 1089*7c478bd9Sstevel@tonic-gate /* Get a legal source port if the socket isn't bound. */ 1090*7c478bd9Sstevel@tonic-gate if (sockets[i].bound == B_FALSE && 1091*7c478bd9Sstevel@tonic-gate ntohs(oc.igm_saddr.sin_port == 0)) { 1092*7c478bd9Sstevel@tonic-gate ((struct sockaddr_in *)&oc.igm_saddr)->sin_port = 1093*7c478bd9Sstevel@tonic-gate get_source_port(B_FALSE); 1094*7c478bd9Sstevel@tonic-gate } 1095*7c478bd9Sstevel@tonic-gate 1096*7c478bd9Sstevel@tonic-gate /* Round up to 16bit value for checksum purposes */ 1097*7c478bd9Sstevel@tonic-gate if (sockets[i].type == INETBOOT_DGRAM) { 1098*7c478bd9Sstevel@tonic-gate tlen = ((len + sizeof (uint16_t) - 1) & 1099*7c478bd9Sstevel@tonic-gate ~(sizeof (uint16_t) - 1)); 1100*7c478bd9Sstevel@tonic-gate } else 1101*7c478bd9Sstevel@tonic-gate tlen = len; 1102*7c478bd9Sstevel@tonic-gate 1103*7c478bd9Sstevel@tonic-gate if ((oc.igm_mp = allocb(tlen + offset, 0)) == NULL) { 1104*7c478bd9Sstevel@tonic-gate errno = ENOMEM; 1105*7c478bd9Sstevel@tonic-gate return (-1); 1106*7c478bd9Sstevel@tonic-gate } 1107*7c478bd9Sstevel@tonic-gate mp = oc.igm_mp; 1108*7c478bd9Sstevel@tonic-gate mp->b_rptr = mp->b_wptr += offset; 1109*7c478bd9Sstevel@tonic-gate bcopy((caddr_t)msg, mp->b_wptr, len); 1110*7c478bd9Sstevel@tonic-gate mp->b_wptr += len; 1111*7c478bd9Sstevel@tonic-gate for (l = TRANSPORT_LVL; l >= MEDIA_LVL; l--) { 1112*7c478bd9Sstevel@tonic-gate if (sockets[i].output[l] != NULL) { 1113*7c478bd9Sstevel@tonic-gate if (sockets[i].output[l](i, &oc) < 0) { 1114*7c478bd9Sstevel@tonic-gate freeb(mp); 1115*7c478bd9Sstevel@tonic-gate if (errno == 0) 1116*7c478bd9Sstevel@tonic-gate errno = EIO; 1117*7c478bd9Sstevel@tonic-gate return (-1); 1118*7c478bd9Sstevel@tonic-gate } 1119*7c478bd9Sstevel@tonic-gate } 1120*7c478bd9Sstevel@tonic-gate } 1121*7c478bd9Sstevel@tonic-gate freeb(mp); 1122*7c478bd9Sstevel@tonic-gate return (len); 1123*7c478bd9Sstevel@tonic-gate } 1124*7c478bd9Sstevel@tonic-gate 1125*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1126*7c478bd9Sstevel@tonic-gate static ssize_t 1127*7c478bd9Sstevel@tonic-gate stream_sendto(int i, const void *msg, size_t len, int flags) 1128*7c478bd9Sstevel@tonic-gate { 1129*7c478bd9Sstevel@tonic-gate int cnt; 1130*7c478bd9Sstevel@tonic-gate 1131*7c478bd9Sstevel@tonic-gate assert(sockets[i].pcb != NULL); 1132*7c478bd9Sstevel@tonic-gate 1133*7c478bd9Sstevel@tonic-gate /* 1134*7c478bd9Sstevel@tonic-gate * Call directly TCP's send routine. We do this because TCP 1135*7c478bd9Sstevel@tonic-gate * needs to decide whether to send out the data. 1136*7c478bd9Sstevel@tonic-gate * 1137*7c478bd9Sstevel@tonic-gate * Note also that currently, TCP ignores all flags passed in for 1138*7c478bd9Sstevel@tonic-gate * TCP socket. 1139*7c478bd9Sstevel@tonic-gate */ 1140*7c478bd9Sstevel@tonic-gate if ((cnt = tcp_send(i, sockets[i].pcb, msg, len)) < 0) { 1141*7c478bd9Sstevel@tonic-gate if (sockets[i].so_error != 0) 1142*7c478bd9Sstevel@tonic-gate errno = sockets[i].so_error; 1143*7c478bd9Sstevel@tonic-gate return (-1); 1144*7c478bd9Sstevel@tonic-gate } else { 1145*7c478bd9Sstevel@tonic-gate return (cnt); 1146*7c478bd9Sstevel@tonic-gate } 1147*7c478bd9Sstevel@tonic-gate } 1148*7c478bd9Sstevel@tonic-gate 1149*7c478bd9Sstevel@tonic-gate /* 1150*7c478bd9Sstevel@tonic-gate * Returns ptr to the last inetgram in the list, or null if list is null 1151*7c478bd9Sstevel@tonic-gate */ 1152*7c478bd9Sstevel@tonic-gate struct inetgram * 1153*7c478bd9Sstevel@tonic-gate last_gram(struct inetgram *igp) 1154*7c478bd9Sstevel@tonic-gate { 1155*7c478bd9Sstevel@tonic-gate struct inetgram *wp; 1156*7c478bd9Sstevel@tonic-gate for (wp = igp; wp != NULL; wp = wp->igm_next) { 1157*7c478bd9Sstevel@tonic-gate if (wp->igm_next == NULL) 1158*7c478bd9Sstevel@tonic-gate return (wp); 1159*7c478bd9Sstevel@tonic-gate } 1160*7c478bd9Sstevel@tonic-gate return (NULL); 1161*7c478bd9Sstevel@tonic-gate } 1162*7c478bd9Sstevel@tonic-gate 1163*7c478bd9Sstevel@tonic-gate /* 1164*7c478bd9Sstevel@tonic-gate * Adds an inetgram or list of inetgrams to the end of the list. 1165*7c478bd9Sstevel@tonic-gate */ 1166*7c478bd9Sstevel@tonic-gate void 1167*7c478bd9Sstevel@tonic-gate add_grams(struct inetgram **igpp, struct inetgram *newgp) 1168*7c478bd9Sstevel@tonic-gate { 1169*7c478bd9Sstevel@tonic-gate struct inetgram *wp; 1170*7c478bd9Sstevel@tonic-gate 1171*7c478bd9Sstevel@tonic-gate if (newgp == NULL) 1172*7c478bd9Sstevel@tonic-gate return; 1173*7c478bd9Sstevel@tonic-gate 1174*7c478bd9Sstevel@tonic-gate if (*igpp == NULL) 1175*7c478bd9Sstevel@tonic-gate *igpp = newgp; 1176*7c478bd9Sstevel@tonic-gate else { 1177*7c478bd9Sstevel@tonic-gate wp = last_gram(*igpp); 1178*7c478bd9Sstevel@tonic-gate wp->igm_next = newgp; 1179*7c478bd9Sstevel@tonic-gate } 1180*7c478bd9Sstevel@tonic-gate } 1181*7c478bd9Sstevel@tonic-gate 1182*7c478bd9Sstevel@tonic-gate /* 1183*7c478bd9Sstevel@tonic-gate * Nuke a whole list of grams. 1184*7c478bd9Sstevel@tonic-gate */ 1185*7c478bd9Sstevel@tonic-gate void 1186*7c478bd9Sstevel@tonic-gate nuke_grams(struct inetgram **lgpp) 1187*7c478bd9Sstevel@tonic-gate { 1188*7c478bd9Sstevel@tonic-gate while (*lgpp != NULL) 1189*7c478bd9Sstevel@tonic-gate del_gram(lgpp, *lgpp, B_TRUE); 1190*7c478bd9Sstevel@tonic-gate } 1191*7c478bd9Sstevel@tonic-gate 1192*7c478bd9Sstevel@tonic-gate /* 1193*7c478bd9Sstevel@tonic-gate * Remove the referenced inetgram. List is altered accordingly. Destroy the 1194*7c478bd9Sstevel@tonic-gate * referenced inetgram if freeit is B_TRUE. 1195*7c478bd9Sstevel@tonic-gate */ 1196*7c478bd9Sstevel@tonic-gate void 1197*7c478bd9Sstevel@tonic-gate del_gram(struct inetgram **lgpp, struct inetgram *igp, int freeit) 1198*7c478bd9Sstevel@tonic-gate { 1199*7c478bd9Sstevel@tonic-gate struct inetgram *wp, *pp = NULL; 1200*7c478bd9Sstevel@tonic-gate 1201*7c478bd9Sstevel@tonic-gate if (lgpp == NULL || igp == NULL) 1202*7c478bd9Sstevel@tonic-gate return; 1203*7c478bd9Sstevel@tonic-gate 1204*7c478bd9Sstevel@tonic-gate wp = *lgpp; 1205*7c478bd9Sstevel@tonic-gate while (wp != NULL) { 1206*7c478bd9Sstevel@tonic-gate if (wp == igp) { 1207*7c478bd9Sstevel@tonic-gate /* detach wp from the list */ 1208*7c478bd9Sstevel@tonic-gate if (*lgpp == wp) 1209*7c478bd9Sstevel@tonic-gate *lgpp = (*lgpp)->igm_next; 1210*7c478bd9Sstevel@tonic-gate else 1211*7c478bd9Sstevel@tonic-gate pp->igm_next = wp->igm_next; 1212*7c478bd9Sstevel@tonic-gate igp->igm_next = NULL; 1213*7c478bd9Sstevel@tonic-gate 1214*7c478bd9Sstevel@tonic-gate if (freeit) { 1215*7c478bd9Sstevel@tonic-gate if (igp->igm_mp != NULL) 1216*7c478bd9Sstevel@tonic-gate freeb(igp->igm_mp); 1217*7c478bd9Sstevel@tonic-gate bkmem_free((caddr_t)igp, 1218*7c478bd9Sstevel@tonic-gate sizeof (struct inetgram)); 1219*7c478bd9Sstevel@tonic-gate } 1220*7c478bd9Sstevel@tonic-gate break; 1221*7c478bd9Sstevel@tonic-gate } 1222*7c478bd9Sstevel@tonic-gate pp = wp; 1223*7c478bd9Sstevel@tonic-gate wp = wp->igm_next; 1224*7c478bd9Sstevel@tonic-gate } 1225*7c478bd9Sstevel@tonic-gate } 1226*7c478bd9Sstevel@tonic-gate 1227*7c478bd9Sstevel@tonic-gate struct nct_t nct[] = { 1228*7c478bd9Sstevel@tonic-gate "bootp", NCT_BOOTP_DHCP, 1229*7c478bd9Sstevel@tonic-gate "dhcp", NCT_BOOTP_DHCP, 1230*7c478bd9Sstevel@tonic-gate "rarp", NCT_RARP_BOOTPARAMS, 1231*7c478bd9Sstevel@tonic-gate "manual", NCT_MANUAL 1232*7c478bd9Sstevel@tonic-gate }; 1233*7c478bd9Sstevel@tonic-gate int nct_entries = sizeof (nct) / sizeof (nct[0]); 1234*7c478bd9Sstevel@tonic-gate 1235*7c478bd9Sstevel@tonic-gate /* 1236*7c478bd9Sstevel@tonic-gate * Figure out from the bootpath what kind of network configuration strategy 1237*7c478bd9Sstevel@tonic-gate * we should use. Returns the network config strategy. 1238*7c478bd9Sstevel@tonic-gate */ 1239*7c478bd9Sstevel@tonic-gate int 1240*7c478bd9Sstevel@tonic-gate get_netconfig_strategy(void) 1241*7c478bd9Sstevel@tonic-gate { 1242*7c478bd9Sstevel@tonic-gate int i; 1243*7c478bd9Sstevel@tonic-gate #if !defined(__i386) 1244*7c478bd9Sstevel@tonic-gate /* sparc */ 1245*7c478bd9Sstevel@tonic-gate #define ISSPACE(c) (c == ' ' || c == '\t' || c == '\n' || c == '\0') 1246*7c478bd9Sstevel@tonic-gate char lbootpath[OBP_MAXPATHLEN]; 1247*7c478bd9Sstevel@tonic-gate char net_options[NCT_BUFSIZE]; 1248*7c478bd9Sstevel@tonic-gate char *op, *nop, *sp; 1249*7c478bd9Sstevel@tonic-gate dnode_t cn; 1250*7c478bd9Sstevel@tonic-gate int proplen; 1251*7c478bd9Sstevel@tonic-gate 1252*7c478bd9Sstevel@tonic-gate /* If the PROM DHCP cache exists, we're done */ 1253*7c478bd9Sstevel@tonic-gate if (prom_cached_reply(B_TRUE)) 1254*7c478bd9Sstevel@tonic-gate return (NCT_BOOTP_DHCP); 1255*7c478bd9Sstevel@tonic-gate 1256*7c478bd9Sstevel@tonic-gate /* 1257*7c478bd9Sstevel@tonic-gate * Newer (version 4) PROMs will put the name in the 1258*7c478bd9Sstevel@tonic-gate * "net-config-strategy" property. 1259*7c478bd9Sstevel@tonic-gate */ 1260*7c478bd9Sstevel@tonic-gate cn = prom_finddevice("/chosen"); 1261*7c478bd9Sstevel@tonic-gate if ((proplen = prom_getproplen(cn, "net-config-strategy")) < 1262*7c478bd9Sstevel@tonic-gate sizeof (net_options)) { 1263*7c478bd9Sstevel@tonic-gate (void) prom_getprop(cn, "net-config-strategy", net_options); 1264*7c478bd9Sstevel@tonic-gate net_options[proplen] = '\0'; 1265*7c478bd9Sstevel@tonic-gate } else { 1266*7c478bd9Sstevel@tonic-gate 1267*7c478bd9Sstevel@tonic-gate /* 1268*7c478bd9Sstevel@tonic-gate * We're reduced to sacanning bootpath for the prototol to use. 1269*7c478bd9Sstevel@tonic-gate * Since there was no "net-config-strategy" property, this is 1270*7c478bd9Sstevel@tonic-gate * an old PROM, so we need to excise any extraneous key/value 1271*7c478bd9Sstevel@tonic-gate * initializations from bootpath[]. 1272*7c478bd9Sstevel@tonic-gate */ 1273*7c478bd9Sstevel@tonic-gate for (op = prom_bootpath(), sp = lbootpath; op != NULL && 1274*7c478bd9Sstevel@tonic-gate !ISSPACE(*op); sp++, op++) 1275*7c478bd9Sstevel@tonic-gate *sp = *op; 1276*7c478bd9Sstevel@tonic-gate *sp = '\0'; 1277*7c478bd9Sstevel@tonic-gate /* find the last '/' (in the device path) */ 1278*7c478bd9Sstevel@tonic-gate if ((op = strrchr(lbootpath, '/')) == NULL) /* last '/' */ 1279*7c478bd9Sstevel@tonic-gate op = lbootpath; 1280*7c478bd9Sstevel@tonic-gate else 1281*7c478bd9Sstevel@tonic-gate op++; 1282*7c478bd9Sstevel@tonic-gate /* then look for the ':' separating it from the protocol */ 1283*7c478bd9Sstevel@tonic-gate while (*op != ':' && *op != '\0') 1284*7c478bd9Sstevel@tonic-gate op++; 1285*7c478bd9Sstevel@tonic-gate 1286*7c478bd9Sstevel@tonic-gate if (*op == ':') { 1287*7c478bd9Sstevel@tonic-gate for (nop = net_options, op++; 1288*7c478bd9Sstevel@tonic-gate *op != '\0' && *op != '/' && !ISSPACE(*op) && 1289*7c478bd9Sstevel@tonic-gate nop < &net_options[NCT_BUFSIZE]; nop++, op++) 1290*7c478bd9Sstevel@tonic-gate *nop = *op; 1291*7c478bd9Sstevel@tonic-gate *nop = '\0'; 1292*7c478bd9Sstevel@tonic-gate } else 1293*7c478bd9Sstevel@tonic-gate net_options[0] = '\0'; 1294*7c478bd9Sstevel@tonic-gate } 1295*7c478bd9Sstevel@tonic-gate 1296*7c478bd9Sstevel@tonic-gate #undef ISSPACE 1297*7c478bd9Sstevel@tonic-gate #else 1298*7c478bd9Sstevel@tonic-gate /* i86 */ 1299*7c478bd9Sstevel@tonic-gate extern struct bootops bootops; 1300*7c478bd9Sstevel@tonic-gate extern int bgetprop(struct bootops *, char *, caddr_t, int, phandle_t); 1301*7c478bd9Sstevel@tonic-gate char net_options[MAXNAMELEN]; 1302*7c478bd9Sstevel@tonic-gate 1303*7c478bd9Sstevel@tonic-gate /* 1304*7c478bd9Sstevel@tonic-gate * Look at net-config-strategy boot property to determine what protocol 1305*7c478bd9Sstevel@tonic-gate * will be used. 1306*7c478bd9Sstevel@tonic-gate */ 1307*7c478bd9Sstevel@tonic-gate (void) bgetprop(&bootops, "net-config-strategy", net_options, 1308*7c478bd9Sstevel@tonic-gate sizeof (net_options), 0); 1309*7c478bd9Sstevel@tonic-gate 1310*7c478bd9Sstevel@tonic-gate #endif /* __i386 */ 1311*7c478bd9Sstevel@tonic-gate 1312*7c478bd9Sstevel@tonic-gate for (i = 0; i < nct_entries; i++) 1313*7c478bd9Sstevel@tonic-gate if (strcmp(net_options, nct[i].p_name) == 0) 1314*7c478bd9Sstevel@tonic-gate return (nct[i].p_id); 1315*7c478bd9Sstevel@tonic-gate 1316*7c478bd9Sstevel@tonic-gate return (NCT_DEFAULT); 1317*7c478bd9Sstevel@tonic-gate } 1318*7c478bd9Sstevel@tonic-gate 1319*7c478bd9Sstevel@tonic-gate /* Modified STREAM routines for ease of porting core TCP code. */ 1320*7c478bd9Sstevel@tonic-gate 1321*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1322*7c478bd9Sstevel@tonic-gate mblk_t * 1323*7c478bd9Sstevel@tonic-gate allocb(size_t size, uint_t pri) 1324*7c478bd9Sstevel@tonic-gate { 1325*7c478bd9Sstevel@tonic-gate unsigned char *base; 1326*7c478bd9Sstevel@tonic-gate mblk_t *mp; 1327*7c478bd9Sstevel@tonic-gate 1328*7c478bd9Sstevel@tonic-gate if ((mp = (mblk_t *)bkmem_zalloc(sizeof (mblk_t))) == NULL) 1329*7c478bd9Sstevel@tonic-gate return (NULL); 1330*7c478bd9Sstevel@tonic-gate if ((base = (unsigned char *)bkmem_zalloc(size)) == NULL) 1331*7c478bd9Sstevel@tonic-gate return (NULL); 1332*7c478bd9Sstevel@tonic-gate 1333*7c478bd9Sstevel@tonic-gate mp->b_next = mp->b_prev = mp->b_cont = NULL; 1334*7c478bd9Sstevel@tonic-gate mp->b_rptr = mp->b_wptr = mp->b_datap = (unsigned char *)base; 1335*7c478bd9Sstevel@tonic-gate mp->b_size = size; 1336*7c478bd9Sstevel@tonic-gate 1337*7c478bd9Sstevel@tonic-gate return (mp); 1338*7c478bd9Sstevel@tonic-gate } 1339*7c478bd9Sstevel@tonic-gate 1340*7c478bd9Sstevel@tonic-gate void 1341*7c478bd9Sstevel@tonic-gate freeb(mblk_t *mp) 1342*7c478bd9Sstevel@tonic-gate { 1343*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 1344*7c478bd9Sstevel@tonic-gate printf("freeb datap %x\n", mp->b_datap); 1345*7c478bd9Sstevel@tonic-gate #endif 1346*7c478bd9Sstevel@tonic-gate bkmem_free((caddr_t)(mp->b_datap), mp->b_size); 1347*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 1348*7c478bd9Sstevel@tonic-gate printf("freeb mp %x\n", mp); 1349*7c478bd9Sstevel@tonic-gate #endif 1350*7c478bd9Sstevel@tonic-gate bkmem_free((caddr_t)mp, sizeof (mblk_t)); 1351*7c478bd9Sstevel@tonic-gate } 1352*7c478bd9Sstevel@tonic-gate 1353*7c478bd9Sstevel@tonic-gate void 1354*7c478bd9Sstevel@tonic-gate freemsg(mblk_t *mp) 1355*7c478bd9Sstevel@tonic-gate { 1356*7c478bd9Sstevel@tonic-gate while (mp) { 1357*7c478bd9Sstevel@tonic-gate mblk_t *mp_cont = mp->b_cont; 1358*7c478bd9Sstevel@tonic-gate 1359*7c478bd9Sstevel@tonic-gate freeb(mp); 1360*7c478bd9Sstevel@tonic-gate mp = mp_cont; 1361*7c478bd9Sstevel@tonic-gate } 1362*7c478bd9Sstevel@tonic-gate } 1363*7c478bd9Sstevel@tonic-gate 1364*7c478bd9Sstevel@tonic-gate mblk_t * 1365*7c478bd9Sstevel@tonic-gate copyb(mblk_t *bp) 1366*7c478bd9Sstevel@tonic-gate { 1367*7c478bd9Sstevel@tonic-gate mblk_t *nbp; 1368*7c478bd9Sstevel@tonic-gate unsigned char *ndp; 1369*7c478bd9Sstevel@tonic-gate 1370*7c478bd9Sstevel@tonic-gate assert((uintptr_t)(bp->b_wptr - bp->b_rptr) >= 0); 1371*7c478bd9Sstevel@tonic-gate 1372*7c478bd9Sstevel@tonic-gate if (!(nbp = allocb(bp->b_size, 0))) 1373*7c478bd9Sstevel@tonic-gate return (NULL); 1374*7c478bd9Sstevel@tonic-gate nbp->b_cont = NULL; 1375*7c478bd9Sstevel@tonic-gate ndp = nbp->b_datap; 1376*7c478bd9Sstevel@tonic-gate 1377*7c478bd9Sstevel@tonic-gate nbp->b_rptr = ndp + (bp->b_rptr - bp->b_datap); 1378*7c478bd9Sstevel@tonic-gate nbp->b_wptr = nbp->b_rptr + (bp->b_wptr - bp->b_rptr); 1379*7c478bd9Sstevel@tonic-gate bcopy(bp->b_datap, nbp->b_datap, bp->b_size); 1380*7c478bd9Sstevel@tonic-gate return (nbp); 1381*7c478bd9Sstevel@tonic-gate } 1382*7c478bd9Sstevel@tonic-gate 1383*7c478bd9Sstevel@tonic-gate /* To simplify things, dupb() is implemented as copyb(). */ 1384*7c478bd9Sstevel@tonic-gate mblk_t * 1385*7c478bd9Sstevel@tonic-gate dupb(mblk_t *mp) 1386*7c478bd9Sstevel@tonic-gate { 1387*7c478bd9Sstevel@tonic-gate return (copyb(mp)); 1388*7c478bd9Sstevel@tonic-gate } 1389*7c478bd9Sstevel@tonic-gate 1390*7c478bd9Sstevel@tonic-gate /* 1391*7c478bd9Sstevel@tonic-gate * get number of data bytes in message 1392*7c478bd9Sstevel@tonic-gate */ 1393*7c478bd9Sstevel@tonic-gate size_t 1394*7c478bd9Sstevel@tonic-gate msgdsize(mblk_t *bp) 1395*7c478bd9Sstevel@tonic-gate { 1396*7c478bd9Sstevel@tonic-gate size_t count = 0; 1397*7c478bd9Sstevel@tonic-gate 1398*7c478bd9Sstevel@tonic-gate for (; bp != NULL; bp = bp->b_cont) { 1399*7c478bd9Sstevel@tonic-gate assert(bp->b_wptr >= bp->b_rptr); 1400*7c478bd9Sstevel@tonic-gate count += bp->b_wptr - bp->b_rptr; 1401*7c478bd9Sstevel@tonic-gate } 1402*7c478bd9Sstevel@tonic-gate return (count); 1403*7c478bd9Sstevel@tonic-gate } 1404