10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*6747Sga159272 * Common Development and Distribution License (the "License").
6*6747Sga159272 * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*6747Sga159272 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate *
250Sstevel@tonic-gate * socket.c, Code implementing a simple socket interface.
260Sstevel@tonic-gate */
270Sstevel@tonic-gate
280Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
290Sstevel@tonic-gate
300Sstevel@tonic-gate #include <sys/types.h>
310Sstevel@tonic-gate #include "socket_impl.h"
320Sstevel@tonic-gate #include <sys/isa_defs.h>
330Sstevel@tonic-gate #include <sys/sysmacros.h>
340Sstevel@tonic-gate #include <sys/bootconf.h>
350Sstevel@tonic-gate #include <sys/socket.h>
360Sstevel@tonic-gate #include <netinet/in.h>
370Sstevel@tonic-gate #include <netinet/ip.h>
380Sstevel@tonic-gate #include <netinet/tcp.h>
390Sstevel@tonic-gate #include <sys/uio.h>
400Sstevel@tonic-gate #include <sys/salib.h>
410Sstevel@tonic-gate #include "socket_inet.h"
420Sstevel@tonic-gate #include "ipv4.h"
430Sstevel@tonic-gate #include "ipv4_impl.h"
440Sstevel@tonic-gate #include "udp_inet.h"
450Sstevel@tonic-gate #include "tcp_inet.h"
460Sstevel@tonic-gate #include "mac.h"
470Sstevel@tonic-gate #include "mac_impl.h"
480Sstevel@tonic-gate #include <sys/promif.h>
490Sstevel@tonic-gate
500Sstevel@tonic-gate struct inetboot_socket sockets[MAXSOCKET] = { 0 };
510Sstevel@tonic-gate
520Sstevel@tonic-gate /* Default send and receive socket buffer size */
530Sstevel@tonic-gate #define SO_DEF_SNDBUF 48*1024
540Sstevel@tonic-gate #define SO_DEF_RCVBUF 48*1024
550Sstevel@tonic-gate
560Sstevel@tonic-gate /* Default max socket buffer size */
570Sstevel@tonic-gate #define SO_MAX_BUF 4*1024*1024
580Sstevel@tonic-gate
590Sstevel@tonic-gate static ssize_t dgram_sendto(int, const void *, size_t, int,
600Sstevel@tonic-gate const struct sockaddr *, int);
610Sstevel@tonic-gate static ssize_t stream_sendto(int, const void *, size_t, int);
620Sstevel@tonic-gate static int bind_check(int, const struct sockaddr *);
630Sstevel@tonic-gate static int quickbind(int);
640Sstevel@tonic-gate
650Sstevel@tonic-gate /* Check the validity of a fd and return the socket index of that fd. */
660Sstevel@tonic-gate int
so_check_fd(int fd,int * errno)670Sstevel@tonic-gate so_check_fd(int fd, int *errno)
680Sstevel@tonic-gate {
690Sstevel@tonic-gate int i;
700Sstevel@tonic-gate
710Sstevel@tonic-gate i = FD_TO_SOCKET(fd);
720Sstevel@tonic-gate if (i < 0 || i >= MAXSOCKET) {
730Sstevel@tonic-gate *errno = ENOTSOCK;
740Sstevel@tonic-gate return (-1);
750Sstevel@tonic-gate }
760Sstevel@tonic-gate if (sockets[i].type == INETBOOT_UNUSED) {
770Sstevel@tonic-gate *errno = ENOTSOCK;
780Sstevel@tonic-gate return (-1);
790Sstevel@tonic-gate }
800Sstevel@tonic-gate return (i);
810Sstevel@tonic-gate }
820Sstevel@tonic-gate
830Sstevel@tonic-gate /*
840Sstevel@tonic-gate * Create an endpoint for network communication. Returns a descriptor.
850Sstevel@tonic-gate *
860Sstevel@tonic-gate * Notes:
870Sstevel@tonic-gate * Only PF_INET communication domains are supported. Within
880Sstevel@tonic-gate * this domain, only SOCK_RAW, SOCK_DGRAM and SOCK_STREAM types are
890Sstevel@tonic-gate * supported.
900Sstevel@tonic-gate */
910Sstevel@tonic-gate int
socket(int domain,int type,int protocol)920Sstevel@tonic-gate socket(int domain, int type, int protocol)
930Sstevel@tonic-gate {
940Sstevel@tonic-gate static int sock_initialized;
950Sstevel@tonic-gate int i;
960Sstevel@tonic-gate
970Sstevel@tonic-gate errno = 0;
980Sstevel@tonic-gate
990Sstevel@tonic-gate if (!sock_initialized) {
1000Sstevel@tonic-gate for (i = 0; i < MAXSOCKET; i++)
1010Sstevel@tonic-gate sockets[i].type = INETBOOT_UNUSED;
1020Sstevel@tonic-gate sock_initialized = B_TRUE;
1030Sstevel@tonic-gate }
1040Sstevel@tonic-gate if (domain != AF_INET) {
1050Sstevel@tonic-gate errno = EPROTONOSUPPORT;
1060Sstevel@tonic-gate return (-1);
1070Sstevel@tonic-gate }
1080Sstevel@tonic-gate
1090Sstevel@tonic-gate /* Find available socket */
1100Sstevel@tonic-gate for (i = 0; i < MAXSOCKET; i++) {
1110Sstevel@tonic-gate if (sockets[i].type == INETBOOT_UNUSED)
1120Sstevel@tonic-gate break;
1130Sstevel@tonic-gate }
1140Sstevel@tonic-gate if (i >= MAXSOCKET) {
1150Sstevel@tonic-gate errno = EMFILE; /* No slots left. */
1160Sstevel@tonic-gate return (-1);
1170Sstevel@tonic-gate }
1180Sstevel@tonic-gate
1190Sstevel@tonic-gate /* Some socket initialization... */
1200Sstevel@tonic-gate sockets[i].so_rcvbuf = SO_DEF_RCVBUF;
1210Sstevel@tonic-gate sockets[i].so_sndbuf = SO_DEF_SNDBUF;
1220Sstevel@tonic-gate
1230Sstevel@tonic-gate /*
1240Sstevel@tonic-gate * Note that we ignore the protocol field for SOCK_DGRAM and
1250Sstevel@tonic-gate * SOCK_STREAM. When we support different protocols in future,
1260Sstevel@tonic-gate * this needs to be changed.
1270Sstevel@tonic-gate */
1280Sstevel@tonic-gate switch (type) {
1290Sstevel@tonic-gate case SOCK_RAW:
1300Sstevel@tonic-gate ipv4_raw_socket(&sockets[i], (uint8_t)protocol);
1310Sstevel@tonic-gate break;
1320Sstevel@tonic-gate case SOCK_DGRAM:
1330Sstevel@tonic-gate udp_socket_init(&sockets[i]);
1340Sstevel@tonic-gate break;
1350Sstevel@tonic-gate case SOCK_STREAM:
1360Sstevel@tonic-gate tcp_socket_init(&sockets[i]);
1370Sstevel@tonic-gate break;
1380Sstevel@tonic-gate default:
1390Sstevel@tonic-gate errno = EPROTOTYPE;
1400Sstevel@tonic-gate break;
1410Sstevel@tonic-gate }
1420Sstevel@tonic-gate
1430Sstevel@tonic-gate if (errno != 0)
1440Sstevel@tonic-gate return (-1);
1450Sstevel@tonic-gate
1460Sstevel@tonic-gate /* IPv4 generic initialization. */
1470Sstevel@tonic-gate ipv4_socket_init(&sockets[i]);
1480Sstevel@tonic-gate
1490Sstevel@tonic-gate /* MAC generic initialization. */
1500Sstevel@tonic-gate mac_socket_init(&sockets[i]);
1510Sstevel@tonic-gate
1520Sstevel@tonic-gate return (i + SOCKETTYPE);
1530Sstevel@tonic-gate }
1540Sstevel@tonic-gate
1550Sstevel@tonic-gate int
getsockname(int s,struct sockaddr * name,socklen_t * namelen)1560Sstevel@tonic-gate getsockname(int s, struct sockaddr *name, socklen_t *namelen)
1570Sstevel@tonic-gate {
1580Sstevel@tonic-gate int i;
1590Sstevel@tonic-gate
1600Sstevel@tonic-gate errno = 0;
1610Sstevel@tonic-gate if ((i = so_check_fd(s, &errno)) == -1)
1620Sstevel@tonic-gate return (-1);
1630Sstevel@tonic-gate
1640Sstevel@tonic-gate if (*namelen < sizeof (struct sockaddr_in)) {
1650Sstevel@tonic-gate errno = ENOMEM;
1660Sstevel@tonic-gate return (-1);
1670Sstevel@tonic-gate }
1680Sstevel@tonic-gate
1690Sstevel@tonic-gate /* Structure assignment... */
1700Sstevel@tonic-gate *((struct sockaddr_in *)name) = sockets[i].bind;
1710Sstevel@tonic-gate *namelen = sizeof (struct sockaddr_in);
1720Sstevel@tonic-gate return (0);
1730Sstevel@tonic-gate }
1740Sstevel@tonic-gate
1750Sstevel@tonic-gate /*
1760Sstevel@tonic-gate * The socket options we support are:
1770Sstevel@tonic-gate * SO_RCVTIMEO - Value is in msecs, and is of uint32_t.
1780Sstevel@tonic-gate * SO_DONTROUTE - Value is an int, and is a boolean (nonzero if set).
1790Sstevel@tonic-gate * SO_REUSEADDR - Value is an int boolean.
1800Sstevel@tonic-gate * SO_RCVBUF - Value is an int.
1810Sstevel@tonic-gate * SO_SNDBUF - Value is an int.
1820Sstevel@tonic-gate */
1830Sstevel@tonic-gate int
getsockopt(int s,int level,int option,void * optval,socklen_t * optlen)1840Sstevel@tonic-gate getsockopt(int s, int level, int option, void *optval, socklen_t *optlen)
1850Sstevel@tonic-gate {
1860Sstevel@tonic-gate int i;
1870Sstevel@tonic-gate
1880Sstevel@tonic-gate errno = 0;
1890Sstevel@tonic-gate if ((i = so_check_fd(s, &errno)) == -1)
1900Sstevel@tonic-gate return (-1);
1910Sstevel@tonic-gate
1920Sstevel@tonic-gate switch (level) {
1930Sstevel@tonic-gate case SOL_SOCKET: {
1940Sstevel@tonic-gate switch (option) {
1950Sstevel@tonic-gate case SO_RCVTIMEO:
1960Sstevel@tonic-gate if (*optlen == sizeof (uint32_t)) {
1970Sstevel@tonic-gate *(uint32_t *)optval = sockets[i].in_timeout;
1980Sstevel@tonic-gate } else {
1990Sstevel@tonic-gate *optlen = 0;
2000Sstevel@tonic-gate errno = EINVAL;
2010Sstevel@tonic-gate }
2020Sstevel@tonic-gate break;
2030Sstevel@tonic-gate case SO_DONTROUTE:
2040Sstevel@tonic-gate if (*optlen == sizeof (int)) {
2050Sstevel@tonic-gate *(int *)optval =
2060Sstevel@tonic-gate (sockets[i].out_flags & SO_DONTROUTE);
2070Sstevel@tonic-gate } else {
2080Sstevel@tonic-gate *optlen = 0;
2090Sstevel@tonic-gate errno = EINVAL;
2100Sstevel@tonic-gate }
2110Sstevel@tonic-gate break;
2120Sstevel@tonic-gate case SO_REUSEADDR:
2130Sstevel@tonic-gate if (*optlen == sizeof (int)) {
2140Sstevel@tonic-gate *(int *)optval =
2150Sstevel@tonic-gate (sockets[i].so_opt & SO_REUSEADDR);
2160Sstevel@tonic-gate } else {
2170Sstevel@tonic-gate *optlen = 0;
2180Sstevel@tonic-gate errno = EINVAL;
2190Sstevel@tonic-gate }
2200Sstevel@tonic-gate break;
2210Sstevel@tonic-gate case SO_RCVBUF:
2220Sstevel@tonic-gate if (*optlen == sizeof (int)) {
2230Sstevel@tonic-gate *(int *)optval = sockets[i].so_rcvbuf;
2240Sstevel@tonic-gate } else {
2250Sstevel@tonic-gate *optlen = 0;
2260Sstevel@tonic-gate errno = EINVAL;
2270Sstevel@tonic-gate }
2280Sstevel@tonic-gate break;
2290Sstevel@tonic-gate case SO_SNDBUF:
2300Sstevel@tonic-gate if (*optlen == sizeof (int)) {
2310Sstevel@tonic-gate *(int *)optval = sockets[i].so_sndbuf;
2320Sstevel@tonic-gate } else {
2330Sstevel@tonic-gate *optlen = 0;
2340Sstevel@tonic-gate errno = EINVAL;
2350Sstevel@tonic-gate }
2360Sstevel@tonic-gate break;
2370Sstevel@tonic-gate case SO_LINGER:
2380Sstevel@tonic-gate if (*optlen == sizeof (struct linger)) {
2390Sstevel@tonic-gate /* struct copy */
2400Sstevel@tonic-gate *(struct linger *)optval = sockets[i].so_linger;
2410Sstevel@tonic-gate } else {
2420Sstevel@tonic-gate *optlen = 0;
2430Sstevel@tonic-gate errno = EINVAL;
2440Sstevel@tonic-gate }
2450Sstevel@tonic-gate default:
2460Sstevel@tonic-gate errno = ENOPROTOOPT;
2470Sstevel@tonic-gate break;
2480Sstevel@tonic-gate }
2490Sstevel@tonic-gate break;
2500Sstevel@tonic-gate } /* case SOL_SOCKET */
2510Sstevel@tonic-gate case IPPROTO_TCP:
2520Sstevel@tonic-gate case IPPROTO_IP: {
2530Sstevel@tonic-gate switch (option) {
2540Sstevel@tonic-gate default:
2550Sstevel@tonic-gate *optlen = 0;
2560Sstevel@tonic-gate errno = ENOPROTOOPT;
2570Sstevel@tonic-gate break;
2580Sstevel@tonic-gate }
2590Sstevel@tonic-gate break;
2600Sstevel@tonic-gate } /* case IPPROTO_IP or IPPROTO_TCP */
2610Sstevel@tonic-gate default:
2620Sstevel@tonic-gate errno = ENOPROTOOPT;
2630Sstevel@tonic-gate break;
2640Sstevel@tonic-gate } /* switch (level) */
2650Sstevel@tonic-gate
2660Sstevel@tonic-gate if (errno != 0)
2670Sstevel@tonic-gate return (-1);
2680Sstevel@tonic-gate else
2690Sstevel@tonic-gate return (0);
2700Sstevel@tonic-gate }
2710Sstevel@tonic-gate
2720Sstevel@tonic-gate /*
2730Sstevel@tonic-gate * Generate a network-order source port from the privileged range if
2740Sstevel@tonic-gate * "reserved" is true, dynamic/private range otherwise. We consider the
2750Sstevel@tonic-gate * range of 512-1023 privileged ports as ports we can use. This mirrors
2760Sstevel@tonic-gate * historical rpc client practice for privileged port selection.
2770Sstevel@tonic-gate */
2780Sstevel@tonic-gate in_port_t
get_source_port(boolean_t reserved)2790Sstevel@tonic-gate get_source_port(boolean_t reserved)
2800Sstevel@tonic-gate {
2810Sstevel@tonic-gate static in_port_t dynamic = IPPORT_DYNAMIC_START - 1,
282*6747Sga159272 rsvdport = (IPPORT_RESERVED / 2) - 1;
2830Sstevel@tonic-gate in_port_t p;
2840Sstevel@tonic-gate
2850Sstevel@tonic-gate if (reserved) {
2860Sstevel@tonic-gate if (++rsvdport >= IPPORT_RESERVED)
2870Sstevel@tonic-gate p = rsvdport = IPPORT_RESERVED / 2;
2880Sstevel@tonic-gate else
2890Sstevel@tonic-gate p = rsvdport;
2900Sstevel@tonic-gate } else
2910Sstevel@tonic-gate p = ++dynamic;
2920Sstevel@tonic-gate
2930Sstevel@tonic-gate return (htons(p));
2940Sstevel@tonic-gate }
2950Sstevel@tonic-gate
2960Sstevel@tonic-gate /*
2970Sstevel@tonic-gate * The socket options we support are:
2980Sstevel@tonic-gate * SO_RECVTIMEO - Value is uint32_t msecs.
2990Sstevel@tonic-gate * SO_DONTROUTE - Value is int boolean (nonzero == TRUE, zero == FALSE).
3000Sstevel@tonic-gate * SO_REUSEADDR - value is int boolean.
3010Sstevel@tonic-gate * SO_RCVBUF - Value is int.
3020Sstevel@tonic-gate * SO_SNDBUF - Value is int.
3030Sstevel@tonic-gate */
3040Sstevel@tonic-gate int
setsockopt(int s,int level,int option,const void * optval,socklen_t optlen)3050Sstevel@tonic-gate setsockopt(int s, int level, int option, const void *optval, socklen_t optlen)
3060Sstevel@tonic-gate {
3070Sstevel@tonic-gate int i;
3080Sstevel@tonic-gate
3090Sstevel@tonic-gate errno = 0;
3100Sstevel@tonic-gate if ((i = so_check_fd(s, &errno)) == -1)
3110Sstevel@tonic-gate return (-1);
3120Sstevel@tonic-gate
3130Sstevel@tonic-gate switch (level) {
3140Sstevel@tonic-gate case SOL_SOCKET: {
3150Sstevel@tonic-gate switch (option) {
3160Sstevel@tonic-gate case SO_RCVTIMEO:
3170Sstevel@tonic-gate if (optlen == sizeof (uint32_t))
3180Sstevel@tonic-gate sockets[i].in_timeout = *(uint32_t *)optval;
3190Sstevel@tonic-gate else {
3200Sstevel@tonic-gate errno = EINVAL;
3210Sstevel@tonic-gate }
3220Sstevel@tonic-gate break;
3230Sstevel@tonic-gate case SO_DONTROUTE:
3240Sstevel@tonic-gate if (optlen == sizeof (int)) {
3250Sstevel@tonic-gate if (*(int *)optval)
3260Sstevel@tonic-gate sockets[i].out_flags |= SO_DONTROUTE;
3270Sstevel@tonic-gate else
3280Sstevel@tonic-gate sockets[i].out_flags &= ~SO_DONTROUTE;
3290Sstevel@tonic-gate } else {
3300Sstevel@tonic-gate errno = EINVAL;
3310Sstevel@tonic-gate }
3320Sstevel@tonic-gate break;
3330Sstevel@tonic-gate case SO_REUSEADDR:
3340Sstevel@tonic-gate if (optlen == sizeof (int)) {
3350Sstevel@tonic-gate if (*(int *)optval)
3360Sstevel@tonic-gate sockets[i].so_opt |= SO_REUSEADDR;
3370Sstevel@tonic-gate else
3380Sstevel@tonic-gate sockets[i].so_opt &= ~SO_REUSEADDR;
3390Sstevel@tonic-gate } else {
3400Sstevel@tonic-gate errno = EINVAL;
3410Sstevel@tonic-gate }
3420Sstevel@tonic-gate break;
3430Sstevel@tonic-gate case SO_RCVBUF:
3440Sstevel@tonic-gate if (optlen == sizeof (int)) {
3450Sstevel@tonic-gate sockets[i].so_rcvbuf = *(int *)optval;
3460Sstevel@tonic-gate if (sockets[i].so_rcvbuf > SO_MAX_BUF)
3470Sstevel@tonic-gate sockets[i].so_rcvbuf = SO_MAX_BUF;
3480Sstevel@tonic-gate (void) tcp_opt_set(sockets[i].pcb,
3490Sstevel@tonic-gate level, option, optval, optlen);
3500Sstevel@tonic-gate } else {
3510Sstevel@tonic-gate errno = EINVAL;
3520Sstevel@tonic-gate }
3530Sstevel@tonic-gate break;
3540Sstevel@tonic-gate case SO_SNDBUF:
3550Sstevel@tonic-gate if (optlen == sizeof (int)) {
3560Sstevel@tonic-gate sockets[i].so_sndbuf = *(int *)optval;
3570Sstevel@tonic-gate if (sockets[i].so_sndbuf > SO_MAX_BUF)
3580Sstevel@tonic-gate sockets[i].so_sndbuf = SO_MAX_BUF;
3590Sstevel@tonic-gate (void) tcp_opt_set(sockets[i].pcb,
3600Sstevel@tonic-gate level, option, optval, optlen);
3610Sstevel@tonic-gate } else {
3620Sstevel@tonic-gate errno = EINVAL;
3630Sstevel@tonic-gate }
3640Sstevel@tonic-gate break;
3650Sstevel@tonic-gate case SO_LINGER:
3660Sstevel@tonic-gate if (optlen == sizeof (struct linger)) {
3670Sstevel@tonic-gate /* struct copy */
3680Sstevel@tonic-gate sockets[i].so_linger = *(struct linger *)optval;
3690Sstevel@tonic-gate (void) tcp_opt_set(sockets[i].pcb,
3700Sstevel@tonic-gate level, option, optval, optlen);
3710Sstevel@tonic-gate } else {
3720Sstevel@tonic-gate errno = EINVAL;
3730Sstevel@tonic-gate }
3740Sstevel@tonic-gate break;
3750Sstevel@tonic-gate default:
3760Sstevel@tonic-gate errno = ENOPROTOOPT;
3770Sstevel@tonic-gate break;
3780Sstevel@tonic-gate }
3790Sstevel@tonic-gate break;
3800Sstevel@tonic-gate } /* case SOL_SOCKET */
3810Sstevel@tonic-gate case IPPROTO_TCP:
3820Sstevel@tonic-gate case IPPROTO_IP: {
3830Sstevel@tonic-gate switch (option) {
3840Sstevel@tonic-gate default:
3850Sstevel@tonic-gate errno = ENOPROTOOPT;
3860Sstevel@tonic-gate break;
3870Sstevel@tonic-gate }
3880Sstevel@tonic-gate break;
3890Sstevel@tonic-gate } /* case IPPROTO_IP or IPPROTO_TCP */
3900Sstevel@tonic-gate default:
3910Sstevel@tonic-gate errno = ENOPROTOOPT;
3920Sstevel@tonic-gate break;
3930Sstevel@tonic-gate } /* switch (level) */
3940Sstevel@tonic-gate
3950Sstevel@tonic-gate if (errno != 0)
3960Sstevel@tonic-gate return (-1);
3970Sstevel@tonic-gate else
3980Sstevel@tonic-gate return (0);
3990Sstevel@tonic-gate }
4000Sstevel@tonic-gate
4010Sstevel@tonic-gate /*
4020Sstevel@tonic-gate * Shut down part of a full-duplex connection.
4030Sstevel@tonic-gate *
4040Sstevel@tonic-gate * Only supported for TCP sockets
4050Sstevel@tonic-gate */
4060Sstevel@tonic-gate int
shutdown(int s,int how)4070Sstevel@tonic-gate shutdown(int s, int how)
4080Sstevel@tonic-gate {
4090Sstevel@tonic-gate int sock_id;
4100Sstevel@tonic-gate int i;
4110Sstevel@tonic-gate
4120Sstevel@tonic-gate errno = 0;
4130Sstevel@tonic-gate if ((sock_id = so_check_fd(s, &errno)) == -1)
4140Sstevel@tonic-gate return (-1);
4150Sstevel@tonic-gate
4160Sstevel@tonic-gate /* shutdown only supported for TCP sockets */
4170Sstevel@tonic-gate if (sockets[sock_id].type != INETBOOT_STREAM) {
4180Sstevel@tonic-gate errno = EOPNOTSUPP;
4190Sstevel@tonic-gate return (-1);
4200Sstevel@tonic-gate }
4210Sstevel@tonic-gate
4220Sstevel@tonic-gate if (!(sockets[sock_id].so_state & SS_ISCONNECTED)) {
4230Sstevel@tonic-gate errno = ENOTCONN;
4240Sstevel@tonic-gate return (-1);
4250Sstevel@tonic-gate }
4260Sstevel@tonic-gate
4270Sstevel@tonic-gate switch (how) {
4280Sstevel@tonic-gate case 0:
4290Sstevel@tonic-gate sockets[sock_id].so_state |= SS_CANTRCVMORE;
4300Sstevel@tonic-gate break;
4310Sstevel@tonic-gate case 1:
4320Sstevel@tonic-gate sockets[sock_id].so_state |= SS_CANTSENDMORE;
4330Sstevel@tonic-gate break;
4340Sstevel@tonic-gate case 2:
4350Sstevel@tonic-gate sockets[sock_id].so_state |= (SS_CANTRCVMORE | SS_CANTSENDMORE);
4360Sstevel@tonic-gate break;
4370Sstevel@tonic-gate default:
4380Sstevel@tonic-gate errno = EINVAL;
4390Sstevel@tonic-gate return (-1);
4400Sstevel@tonic-gate }
4410Sstevel@tonic-gate
4420Sstevel@tonic-gate switch (sockets[sock_id].so_state &
443*6747Sga159272 (SS_CANTRCVMORE | SS_CANTSENDMORE)) {
4440Sstevel@tonic-gate case (SS_CANTRCVMORE | SS_CANTSENDMORE):
4450Sstevel@tonic-gate /* Call lower level protocol close routine. */
4460Sstevel@tonic-gate for (i = TRANSPORT_LVL; i >= MEDIA_LVL; i--) {
4470Sstevel@tonic-gate if (sockets[sock_id].close[i] != NULL) {
4480Sstevel@tonic-gate (void) sockets[sock_id].close[i](sock_id);
4490Sstevel@tonic-gate }
4500Sstevel@tonic-gate }
4510Sstevel@tonic-gate nuke_grams(&sockets[sock_id].inq);
4520Sstevel@tonic-gate break;
4530Sstevel@tonic-gate case SS_CANTRCVMORE:
4540Sstevel@tonic-gate nuke_grams(&sockets[sock_id].inq);
4550Sstevel@tonic-gate break;
4560Sstevel@tonic-gate case SS_CANTSENDMORE:
4570Sstevel@tonic-gate /* Call lower level protocol close routine. */
4580Sstevel@tonic-gate if (tcp_shutdown(sock_id) < 0)
4590Sstevel@tonic-gate return (-1);
4600Sstevel@tonic-gate break;
4610Sstevel@tonic-gate default:
4620Sstevel@tonic-gate errno = EINVAL;
4630Sstevel@tonic-gate return (-1);
4640Sstevel@tonic-gate }
4650Sstevel@tonic-gate
4660Sstevel@tonic-gate return (0);
4670Sstevel@tonic-gate }
4680Sstevel@tonic-gate
4690Sstevel@tonic-gate /*
4700Sstevel@tonic-gate * "close" a socket.
4710Sstevel@tonic-gate */
4720Sstevel@tonic-gate int
socket_close(int s)4730Sstevel@tonic-gate socket_close(int s)
4740Sstevel@tonic-gate {
4750Sstevel@tonic-gate int sock_id, i;
4760Sstevel@tonic-gate
4770Sstevel@tonic-gate errno = 0;
4780Sstevel@tonic-gate if ((sock_id = so_check_fd(s, &errno)) == -1)
4790Sstevel@tonic-gate return (-1);
4800Sstevel@tonic-gate
4810Sstevel@tonic-gate /* Call lower level protocol close routine. */
4820Sstevel@tonic-gate for (i = TRANSPORT_LVL; i >= MEDIA_LVL; i--) {
4830Sstevel@tonic-gate if (sockets[sock_id].close[i] != NULL) {
4840Sstevel@tonic-gate /*
4850Sstevel@tonic-gate * Note that the close() routine of other
4860Sstevel@tonic-gate * layers can return an error. But right
4870Sstevel@tonic-gate * now, the only mechanism to report that
4880Sstevel@tonic-gate * back is for the close() routine to set
4890Sstevel@tonic-gate * the errno and socket_close() will return
4900Sstevel@tonic-gate * an error. But the close operation will
4910Sstevel@tonic-gate * not be stopped.
4920Sstevel@tonic-gate */
4930Sstevel@tonic-gate (void) sockets[sock_id].close[i](sock_id);
4940Sstevel@tonic-gate }
4950Sstevel@tonic-gate }
4960Sstevel@tonic-gate
4970Sstevel@tonic-gate /*
4980Sstevel@tonic-gate * Clear the input queue. This has to be done
4990Sstevel@tonic-gate * after the lower level protocol close routines have been
5000Sstevel@tonic-gate * called as they may want to do something about the queue.
5010Sstevel@tonic-gate */
5020Sstevel@tonic-gate nuke_grams(&sockets[sock_id].inq);
5030Sstevel@tonic-gate
5040Sstevel@tonic-gate bzero((caddr_t)&sockets[sock_id], sizeof (struct inetboot_socket));
5050Sstevel@tonic-gate sockets[sock_id].type = INETBOOT_UNUSED;
5060Sstevel@tonic-gate
5070Sstevel@tonic-gate return (0);
5080Sstevel@tonic-gate }
5090Sstevel@tonic-gate
5100Sstevel@tonic-gate /*
5110Sstevel@tonic-gate * Read up to `nbyte' of data from socket `s' into `buf'; if non-zero,
5120Sstevel@tonic-gate * then give up after `read_timeout' seconds. Returns the number of
5130Sstevel@tonic-gate * bytes read, or -1 on failure.
5140Sstevel@tonic-gate */
5150Sstevel@tonic-gate int
socket_read(int s,void * buf,size_t nbyte,int read_timeout)5160Sstevel@tonic-gate socket_read(int s, void *buf, size_t nbyte, int read_timeout)
5170Sstevel@tonic-gate {
5180Sstevel@tonic-gate ssize_t n;
5190Sstevel@tonic-gate uint_t start, diff;
5200Sstevel@tonic-gate
5210Sstevel@tonic-gate /*
5220Sstevel@tonic-gate * keep calling non-blocking recvfrom until something received
5230Sstevel@tonic-gate * or an error occurs
5240Sstevel@tonic-gate */
5250Sstevel@tonic-gate start = prom_gettime();
526517Sjk115741 for (;;) {
527517Sjk115741 n = recvfrom(s, buf, nbyte, MSG_DONTWAIT, NULL, NULL);
528517Sjk115741 if (n == -1 && errno == EWOULDBLOCK) {
529517Sjk115741 diff = (uint_t)((prom_gettime() - start) + 500) / 1000;
530517Sjk115741 if (read_timeout != 0 && diff > read_timeout) {
531517Sjk115741 errno = EINTR;
532517Sjk115741 return (-1);
533517Sjk115741 }
534517Sjk115741 } else {
535517Sjk115741 return (n);
5360Sstevel@tonic-gate }
5370Sstevel@tonic-gate }
5380Sstevel@tonic-gate }
5390Sstevel@tonic-gate
5400Sstevel@tonic-gate /*
5410Sstevel@tonic-gate * Write up to `nbyte' bytes of data from `buf' to the address pointed to
5420Sstevel@tonic-gate * `addr' using socket `s'. Returns the number of bytes writte on success,
5430Sstevel@tonic-gate * or -1 on failure.
5440Sstevel@tonic-gate */
5450Sstevel@tonic-gate int
socket_write(int s,const void * buf,size_t nbyte,struct sockaddr_in * addr)5460Sstevel@tonic-gate socket_write(int s, const void *buf, size_t nbyte, struct sockaddr_in *addr)
5470Sstevel@tonic-gate {
5480Sstevel@tonic-gate return (sendto(s, buf, nbyte, 0, (struct sockaddr *)addr,
5490Sstevel@tonic-gate sizeof (*addr)));
5500Sstevel@tonic-gate }
5510Sstevel@tonic-gate
5520Sstevel@tonic-gate static int
bind_check(int sock_id,const struct sockaddr * addr)5530Sstevel@tonic-gate bind_check(int sock_id, const struct sockaddr *addr)
5540Sstevel@tonic-gate {
5550Sstevel@tonic-gate int k;
5560Sstevel@tonic-gate struct sockaddr_in *in_addr = (struct sockaddr_in *)addr;
5570Sstevel@tonic-gate
5580Sstevel@tonic-gate /* Do not check for duplicate bind() if SO_REUSEADDR option is set. */
5590Sstevel@tonic-gate if (! (sockets[sock_id].so_opt & SO_REUSEADDR)) {
5600Sstevel@tonic-gate for (k = 0; k < MAXSOCKET; k++) {
5610Sstevel@tonic-gate if (sockets[k].type != INETBOOT_UNUSED &&
5620Sstevel@tonic-gate sockets[k].proto == sockets[sock_id].proto &&
5630Sstevel@tonic-gate sockets[k].bound) {
5640Sstevel@tonic-gate if ((sockets[k].bind.sin_addr.s_addr ==
5650Sstevel@tonic-gate in_addr->sin_addr.s_addr) &&
5660Sstevel@tonic-gate (sockets[k].bind.sin_port ==
5670Sstevel@tonic-gate in_addr->sin_port)) {
5680Sstevel@tonic-gate errno = EADDRINUSE;
5690Sstevel@tonic-gate return (-1);
5700Sstevel@tonic-gate }
5710Sstevel@tonic-gate }
5720Sstevel@tonic-gate }
5730Sstevel@tonic-gate }
5740Sstevel@tonic-gate return (0);
5750Sstevel@tonic-gate }
5760Sstevel@tonic-gate
5770Sstevel@tonic-gate /* Assign a name to an unnamed socket. */
5780Sstevel@tonic-gate int
bind(int s,const struct sockaddr * name,socklen_t namelen)5790Sstevel@tonic-gate bind(int s, const struct sockaddr *name, socklen_t namelen)
5800Sstevel@tonic-gate {
5810Sstevel@tonic-gate int i;
5820Sstevel@tonic-gate
5830Sstevel@tonic-gate errno = 0;
5840Sstevel@tonic-gate
5850Sstevel@tonic-gate if ((i = so_check_fd(s, &errno)) == -1)
5860Sstevel@tonic-gate return (-1);
5870Sstevel@tonic-gate
5880Sstevel@tonic-gate if (name == NULL) {
5890Sstevel@tonic-gate /* unbind */
5900Sstevel@tonic-gate if (sockets[i].bound) {
5910Sstevel@tonic-gate bzero((caddr_t)&sockets[i].bind,
5920Sstevel@tonic-gate sizeof (struct sockaddr_in));
5930Sstevel@tonic-gate sockets[i].bound = B_FALSE;
5940Sstevel@tonic-gate }
5950Sstevel@tonic-gate return (0);
5960Sstevel@tonic-gate }
5970Sstevel@tonic-gate if (namelen != sizeof (struct sockaddr_in) || name == NULL) {
5980Sstevel@tonic-gate errno = EINVAL;
5990Sstevel@tonic-gate return (-1);
6000Sstevel@tonic-gate }
6010Sstevel@tonic-gate if (name->sa_family != AF_INET) {
6020Sstevel@tonic-gate errno = EAFNOSUPPORT;
6030Sstevel@tonic-gate return (-1);
6040Sstevel@tonic-gate }
6050Sstevel@tonic-gate if (sockets[i].bound) {
6060Sstevel@tonic-gate if (bcmp((caddr_t)&sockets[i].bind, (caddr_t)name,
6070Sstevel@tonic-gate namelen) == 0) {
6080Sstevel@tonic-gate /* attempt to bind to same address ok... */
6090Sstevel@tonic-gate return (0);
6100Sstevel@tonic-gate }
6110Sstevel@tonic-gate errno = EINVAL; /* already bound */
6120Sstevel@tonic-gate return (-1);
6130Sstevel@tonic-gate }
6140Sstevel@tonic-gate
6150Sstevel@tonic-gate if (errno != 0) {
6160Sstevel@tonic-gate return (-1);
6170Sstevel@tonic-gate }
6180Sstevel@tonic-gate
6190Sstevel@tonic-gate /* Check for duplicate bind(). */
6200Sstevel@tonic-gate if (bind_check(i, name) < 0)
6210Sstevel@tonic-gate return (-1);
6220Sstevel@tonic-gate
6230Sstevel@tonic-gate bcopy((caddr_t)name, (caddr_t)&sockets[i].bind, namelen);
6240Sstevel@tonic-gate if (sockets[i].type == INETBOOT_STREAM) {
6250Sstevel@tonic-gate if (tcp_bind(i) < 0) {
6260Sstevel@tonic-gate return (-1);
6270Sstevel@tonic-gate }
6280Sstevel@tonic-gate }
6290Sstevel@tonic-gate sockets[i].bound = B_TRUE;
6300Sstevel@tonic-gate
6310Sstevel@tonic-gate return (0);
6320Sstevel@tonic-gate }
6330Sstevel@tonic-gate
6340Sstevel@tonic-gate static int
quickbind(int sock_id)6350Sstevel@tonic-gate quickbind(int sock_id)
6360Sstevel@tonic-gate {
6370Sstevel@tonic-gate int i;
6380Sstevel@tonic-gate struct sockaddr_in addr;
6390Sstevel@tonic-gate
6400Sstevel@tonic-gate /*
6410Sstevel@tonic-gate * XXX This needs more work. Right now, if ipv4_setipaddr()
6420Sstevel@tonic-gate * have not been called, this will be wrong. But we need
6430Sstevel@tonic-gate * something better. Need to be revisited.
6440Sstevel@tonic-gate */
6450Sstevel@tonic-gate ipv4_getipaddr(&addr.sin_addr);
6460Sstevel@tonic-gate addr.sin_family = AF_INET;
6470Sstevel@tonic-gate
6480Sstevel@tonic-gate for (i = SMALLEST_ANON_PORT; i <= LARGEST_ANON_PORT; i++) {
6490Sstevel@tonic-gate addr.sin_port = htons(i);
6500Sstevel@tonic-gate if (bind_check(sock_id, (struct sockaddr *)&addr) == 0)
6510Sstevel@tonic-gate break;
6520Sstevel@tonic-gate }
6530Sstevel@tonic-gate /* Need to clear errno as it is probably set by bind_check(). */
6540Sstevel@tonic-gate errno = 0;
6550Sstevel@tonic-gate
6560Sstevel@tonic-gate if (i <= LARGEST_ANON_PORT) {
6570Sstevel@tonic-gate bcopy((caddr_t)&addr, (caddr_t)&sockets[sock_id].bind,
6580Sstevel@tonic-gate sizeof (struct sockaddr_in));
6590Sstevel@tonic-gate sockets[sock_id].bound = B_TRUE;
6600Sstevel@tonic-gate #ifdef DEBUG
6610Sstevel@tonic-gate printf("quick bind done addr %s port %d\n",
6620Sstevel@tonic-gate inet_ntoa(sockets[sock_id].bind.sin_addr),
663*6747Sga159272 ntohs(sockets[sock_id].bind.sin_port));
6640Sstevel@tonic-gate #endif
6650Sstevel@tonic-gate return (0);
6660Sstevel@tonic-gate } else {
6670Sstevel@tonic-gate return (-1);
6680Sstevel@tonic-gate }
6690Sstevel@tonic-gate }
6700Sstevel@tonic-gate
6710Sstevel@tonic-gate int
listen(int fd,int backlog)6720Sstevel@tonic-gate listen(int fd, int backlog)
6730Sstevel@tonic-gate {
6740Sstevel@tonic-gate int sock_id;
6750Sstevel@tonic-gate
6760Sstevel@tonic-gate errno = 0;
6770Sstevel@tonic-gate if ((sock_id = so_check_fd(fd, &errno)) == -1)
6780Sstevel@tonic-gate return (-1);
6790Sstevel@tonic-gate
6800Sstevel@tonic-gate if (sockets[sock_id].type != INETBOOT_STREAM) {
6810Sstevel@tonic-gate errno = EOPNOTSUPP;
6820Sstevel@tonic-gate return (-1);
6830Sstevel@tonic-gate }
6840Sstevel@tonic-gate if (sockets[sock_id].so_error != 0) {
6850Sstevel@tonic-gate errno = sockets[sock_id].so_error;
6860Sstevel@tonic-gate return (-1);
6870Sstevel@tonic-gate }
6880Sstevel@tonic-gate return (tcp_listen(sock_id, backlog));
6890Sstevel@tonic-gate }
6900Sstevel@tonic-gate
6910Sstevel@tonic-gate int
accept(int fd,struct sockaddr * addr,socklen_t * addr_len)6920Sstevel@tonic-gate accept(int fd, struct sockaddr *addr, socklen_t *addr_len)
6930Sstevel@tonic-gate {
6940Sstevel@tonic-gate int sock_id;
6950Sstevel@tonic-gate int new_sd;
6960Sstevel@tonic-gate
6970Sstevel@tonic-gate errno = 0;
6980Sstevel@tonic-gate if ((sock_id = so_check_fd(fd, &errno)) == -1)
6990Sstevel@tonic-gate return (-1);
7000Sstevel@tonic-gate
7010Sstevel@tonic-gate if (sockets[sock_id].type != INETBOOT_STREAM) {
7020Sstevel@tonic-gate errno = EOPNOTSUPP;
7030Sstevel@tonic-gate return (-1);
7040Sstevel@tonic-gate }
7050Sstevel@tonic-gate if (sockets[sock_id].so_error != 0) {
7060Sstevel@tonic-gate errno = sockets[sock_id].so_error;
7070Sstevel@tonic-gate return (-1);
7080Sstevel@tonic-gate }
7090Sstevel@tonic-gate if ((new_sd = tcp_accept(sock_id, addr, addr_len)) == -1)
7100Sstevel@tonic-gate return (-1);
7110Sstevel@tonic-gate sock_id = so_check_fd(new_sd, &errno);
7120Sstevel@tonic-gate sockets[sock_id].so_state |= SS_ISCONNECTED;
7130Sstevel@tonic-gate return (new_sd);
7140Sstevel@tonic-gate }
7150Sstevel@tonic-gate
7160Sstevel@tonic-gate int
connect(int fd,const struct sockaddr * addr,socklen_t addr_len)7170Sstevel@tonic-gate connect(int fd, const struct sockaddr *addr, socklen_t addr_len)
7180Sstevel@tonic-gate {
7190Sstevel@tonic-gate int sock_id;
7200Sstevel@tonic-gate int so_type;
7210Sstevel@tonic-gate
7220Sstevel@tonic-gate errno = 0;
7230Sstevel@tonic-gate if ((sock_id = so_check_fd(fd, &errno)) == -1)
7240Sstevel@tonic-gate return (-1);
7250Sstevel@tonic-gate
7260Sstevel@tonic-gate so_type = sockets[sock_id].type;
7270Sstevel@tonic-gate
7280Sstevel@tonic-gate if (addr == NULL || addr_len == 0) {
7290Sstevel@tonic-gate errno = EINVAL;
7300Sstevel@tonic-gate return (-1);
7310Sstevel@tonic-gate }
7320Sstevel@tonic-gate /* Don't allow connect for raw socket. */
7330Sstevel@tonic-gate if (so_type == INETBOOT_RAW) {
7340Sstevel@tonic-gate errno = EPROTONOSUPPORT;
7350Sstevel@tonic-gate return (-1);
7360Sstevel@tonic-gate }
7370Sstevel@tonic-gate
7380Sstevel@tonic-gate if (sockets[sock_id].so_state & SS_ISCONNECTED) {
7390Sstevel@tonic-gate errno = EINVAL;
7400Sstevel@tonic-gate return (-1);
7410Sstevel@tonic-gate }
7420Sstevel@tonic-gate
7430Sstevel@tonic-gate if (sockets[sock_id].so_error != 0) {
7440Sstevel@tonic-gate errno = sockets[sock_id].so_error;
7450Sstevel@tonic-gate return (-1);
7460Sstevel@tonic-gate }
7470Sstevel@tonic-gate
7480Sstevel@tonic-gate /* If the socket is not bound, we need to do a quick bind. */
7490Sstevel@tonic-gate if (!sockets[sock_id].bound) {
7500Sstevel@tonic-gate /* For TCP socket, just call tcp_bind(). */
7510Sstevel@tonic-gate if (so_type == INETBOOT_STREAM) {
7520Sstevel@tonic-gate if (tcp_bind(sock_id) < 0)
7530Sstevel@tonic-gate return (-1);
7540Sstevel@tonic-gate } else {
7550Sstevel@tonic-gate if (quickbind(sock_id) < 0) {
7560Sstevel@tonic-gate errno = EADDRNOTAVAIL;
7570Sstevel@tonic-gate return (-1);
7580Sstevel@tonic-gate }
7590Sstevel@tonic-gate }
7600Sstevel@tonic-gate }
7610Sstevel@tonic-gate /* Should do some sanity check for addr .... */
7620Sstevel@tonic-gate bcopy((caddr_t)addr, &sockets[sock_id].remote,
7630Sstevel@tonic-gate sizeof (struct sockaddr_in));
7640Sstevel@tonic-gate
7650Sstevel@tonic-gate if (sockets[sock_id].type == INETBOOT_STREAM) {
7660Sstevel@tonic-gate /* Call TCP connect routine. */
7670Sstevel@tonic-gate if (tcp_connect(sock_id) == 0)
7680Sstevel@tonic-gate sockets[sock_id].so_state |= SS_ISCONNECTED;
7690Sstevel@tonic-gate else {
7700Sstevel@tonic-gate if (sockets[sock_id].so_error != 0)
7710Sstevel@tonic-gate errno = sockets[sock_id].so_error;
7720Sstevel@tonic-gate return (-1);
7730Sstevel@tonic-gate }
7740Sstevel@tonic-gate } else {
7750Sstevel@tonic-gate sockets[sock_id].so_state |= SS_ISCONNECTED;
7760Sstevel@tonic-gate }
7770Sstevel@tonic-gate return (0);
7780Sstevel@tonic-gate }
7790Sstevel@tonic-gate
7800Sstevel@tonic-gate /* Just a wrapper around recvfrom(). */
7810Sstevel@tonic-gate ssize_t
recv(int s,void * buf,size_t len,int flags)7820Sstevel@tonic-gate recv(int s, void *buf, size_t len, int flags)
7830Sstevel@tonic-gate {
7840Sstevel@tonic-gate return (recvfrom(s, buf, len, flags, NULL, NULL));
7850Sstevel@tonic-gate }
7860Sstevel@tonic-gate
7870Sstevel@tonic-gate /*
7880Sstevel@tonic-gate * Receive messages from a connectionless socket. Legal flags are 0 and
7890Sstevel@tonic-gate * MSG_DONTWAIT. MSG_WAITALL is not currently supported.
7900Sstevel@tonic-gate *
7910Sstevel@tonic-gate * Returns length of message for success, -1 if error occurred.
7920Sstevel@tonic-gate */
7930Sstevel@tonic-gate ssize_t
recvfrom(int s,void * buf,size_t len,int flags,struct sockaddr * from,socklen_t * fromlen)7940Sstevel@tonic-gate recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from,
7950Sstevel@tonic-gate socklen_t *fromlen)
7960Sstevel@tonic-gate {
7970Sstevel@tonic-gate int sock_id, i;
7980Sstevel@tonic-gate ssize_t datalen, bytes = 0;
7990Sstevel@tonic-gate struct inetgram *icp;
8000Sstevel@tonic-gate enum SockType so_type;
8010Sstevel@tonic-gate char *tmp_buf;
8020Sstevel@tonic-gate mblk_t *mp;
8030Sstevel@tonic-gate
8040Sstevel@tonic-gate errno = 0;
8050Sstevel@tonic-gate
8060Sstevel@tonic-gate if ((sock_id = so_check_fd(s, &errno)) == -1) {
8070Sstevel@tonic-gate errno = EINVAL;
8080Sstevel@tonic-gate return (-1);
8090Sstevel@tonic-gate }
8100Sstevel@tonic-gate
8110Sstevel@tonic-gate if (sockets[sock_id].type == INETBOOT_STREAM &&
8120Sstevel@tonic-gate !(sockets[sock_id].so_state & SS_ISCONNECTED)) {
8130Sstevel@tonic-gate errno = ENOTCONN;
8140Sstevel@tonic-gate return (-1);
8150Sstevel@tonic-gate }
8160Sstevel@tonic-gate
8170Sstevel@tonic-gate if (buf == NULL || len == 0) {
8180Sstevel@tonic-gate errno = EINVAL;
8190Sstevel@tonic-gate return (-1);
8200Sstevel@tonic-gate }
8210Sstevel@tonic-gate /* Yup - MSG_WAITALL not implemented */
8220Sstevel@tonic-gate if ((flags & ~MSG_DONTWAIT) != 0) {
8230Sstevel@tonic-gate errno = EINVAL;
8240Sstevel@tonic-gate return (-1);
8250Sstevel@tonic-gate }
8260Sstevel@tonic-gate
8270Sstevel@tonic-gate retry:
8280Sstevel@tonic-gate if (sockets[sock_id].inq == NULL) {
8290Sstevel@tonic-gate /* Go out and check the wire */
8300Sstevel@tonic-gate for (i = MEDIA_LVL; i < APP_LVL; i++) {
8310Sstevel@tonic-gate if (sockets[sock_id].input[i] != NULL) {
8320Sstevel@tonic-gate if (sockets[sock_id].input[i](sock_id) < 0) {
8330Sstevel@tonic-gate if (sockets[sock_id].so_error != 0) {
8340Sstevel@tonic-gate errno =
8350Sstevel@tonic-gate sockets[sock_id].so_error;
8360Sstevel@tonic-gate }
8370Sstevel@tonic-gate return (-1);
8380Sstevel@tonic-gate }
8390Sstevel@tonic-gate }
8400Sstevel@tonic-gate }
8410Sstevel@tonic-gate }
8420Sstevel@tonic-gate
8430Sstevel@tonic-gate so_type = sockets[sock_id].type;
8440Sstevel@tonic-gate
8450Sstevel@tonic-gate /* Remove unknown inetgrams from the head of inq. Can this happen? */
8460Sstevel@tonic-gate while ((icp = sockets[sock_id].inq) != NULL) {
8470Sstevel@tonic-gate if ((so_type == INETBOOT_DGRAM ||
8480Sstevel@tonic-gate so_type == INETBOOT_STREAM) &&
8490Sstevel@tonic-gate icp->igm_level != APP_LVL) {
8500Sstevel@tonic-gate #ifdef DEBUG
8510Sstevel@tonic-gate printf("recvfrom: unexpected level %d frame found\n",
8520Sstevel@tonic-gate icp->igm_level);
8530Sstevel@tonic-gate #endif /* DEBUG */
8540Sstevel@tonic-gate del_gram(&sockets[sock_id].inq, icp, B_TRUE);
8550Sstevel@tonic-gate continue;
8560Sstevel@tonic-gate } else {
8570Sstevel@tonic-gate break;
8580Sstevel@tonic-gate }
8590Sstevel@tonic-gate }
8600Sstevel@tonic-gate
8610Sstevel@tonic-gate
8620Sstevel@tonic-gate if (icp == NULL) {
8630Sstevel@tonic-gate /*
8640Sstevel@tonic-gate * Checking for error should be done everytime a lower layer
8650Sstevel@tonic-gate * input routing is called. For example, if TCP gets a RST,
8660Sstevel@tonic-gate * this should be reported asap.
8670Sstevel@tonic-gate */
8680Sstevel@tonic-gate if (sockets[sock_id].so_state & SS_CANTRCVMORE) {
8690Sstevel@tonic-gate if (sockets[sock_id].so_error != 0) {
8700Sstevel@tonic-gate errno = sockets[sock_id].so_error;
8710Sstevel@tonic-gate return (-1);
8720Sstevel@tonic-gate } else {
8730Sstevel@tonic-gate return (0);
8740Sstevel@tonic-gate }
8750Sstevel@tonic-gate }
8760Sstevel@tonic-gate
8770Sstevel@tonic-gate if ((flags & MSG_DONTWAIT) == 0)
8780Sstevel@tonic-gate goto retry; /* wait forever */
8790Sstevel@tonic-gate
8800Sstevel@tonic-gate /* no data */
8810Sstevel@tonic-gate errno = EWOULDBLOCK;
8820Sstevel@tonic-gate return (-1);
8830Sstevel@tonic-gate }
8840Sstevel@tonic-gate
8850Sstevel@tonic-gate if (from != NULL && fromlen != NULL) {
8860Sstevel@tonic-gate switch (so_type) {
8870Sstevel@tonic-gate case INETBOOT_STREAM:
8880Sstevel@tonic-gate /* Need to copy from the socket's remote address. */
8890Sstevel@tonic-gate bcopy(&(sockets[sock_id].remote), from, MIN(*fromlen,
8900Sstevel@tonic-gate sizeof (struct sockaddr_in)));
8910Sstevel@tonic-gate break;
8920Sstevel@tonic-gate case INETBOOT_RAW:
8930Sstevel@tonic-gate case INETBOOT_DGRAM:
8940Sstevel@tonic-gate default:
8950Sstevel@tonic-gate if (*fromlen > sizeof (icp->igm_saddr))
8960Sstevel@tonic-gate *fromlen = sizeof (icp->igm_saddr);
8970Sstevel@tonic-gate bcopy((caddr_t)&(icp->igm_saddr), (caddr_t)from,
8980Sstevel@tonic-gate MIN(*fromlen, sizeof (struct sockaddr_in)));
8990Sstevel@tonic-gate break;
9000Sstevel@tonic-gate }
9010Sstevel@tonic-gate }
9020Sstevel@tonic-gate
9030Sstevel@tonic-gate mp = icp->igm_mp;
9040Sstevel@tonic-gate switch (so_type) {
9050Sstevel@tonic-gate case INETBOOT_STREAM:
9060Sstevel@tonic-gate /*
9070Sstevel@tonic-gate * If the message has igm_id == TCP_CALLB_MAGIC_ID, we need
9080Sstevel@tonic-gate * to drain the data held by tcp and try again.
9090Sstevel@tonic-gate */
9100Sstevel@tonic-gate if (icp->igm_id == TCP_CALLB_MAGIC_ID) {
9110Sstevel@tonic-gate del_gram(&sockets[sock_id].inq, icp, B_TRUE);
9120Sstevel@tonic-gate tcp_rcv_drain_sock(sock_id);
9130Sstevel@tonic-gate goto retry;
9140Sstevel@tonic-gate }
9150Sstevel@tonic-gate
9160Sstevel@tonic-gate /* TCP should put only user data in the inetgram. */
9170Sstevel@tonic-gate tmp_buf = (char *)buf;
9180Sstevel@tonic-gate while (len > 0 && icp != NULL) {
9190Sstevel@tonic-gate datalen = mp->b_wptr - mp->b_rptr;
9200Sstevel@tonic-gate if (len < datalen) {
9210Sstevel@tonic-gate bcopy(mp->b_rptr, tmp_buf, len);
9220Sstevel@tonic-gate bytes += len;
9230Sstevel@tonic-gate mp->b_rptr += len;
9240Sstevel@tonic-gate break;
9250Sstevel@tonic-gate } else {
9260Sstevel@tonic-gate bcopy(mp->b_rptr, tmp_buf, datalen);
9270Sstevel@tonic-gate len -= datalen;
9280Sstevel@tonic-gate bytes += datalen;
9290Sstevel@tonic-gate tmp_buf += datalen;
9300Sstevel@tonic-gate del_gram(&sockets[sock_id].inq, icp, B_TRUE);
9310Sstevel@tonic-gate
9320Sstevel@tonic-gate /*
9330Sstevel@tonic-gate * If we have any embedded magic messages just
9340Sstevel@tonic-gate * drop them.
9350Sstevel@tonic-gate */
9360Sstevel@tonic-gate while ((icp = sockets[sock_id].inq) != NULL) {
9370Sstevel@tonic-gate if (icp->igm_id != TCP_CALLB_MAGIC_ID)
9380Sstevel@tonic-gate break;
9390Sstevel@tonic-gate del_gram(&sockets[sock_id].inq, icp,
940*6747Sga159272 B_TRUE);
9410Sstevel@tonic-gate }
9420Sstevel@tonic-gate
9430Sstevel@tonic-gate if (icp == NULL)
9440Sstevel@tonic-gate break;
9450Sstevel@tonic-gate mp = icp->igm_mp;
9460Sstevel@tonic-gate }
9470Sstevel@tonic-gate }
9480Sstevel@tonic-gate sockets[sock_id].so_rcvbuf += (int32_t)bytes;
9490Sstevel@tonic-gate break;
9500Sstevel@tonic-gate case INETBOOT_DGRAM:
9510Sstevel@tonic-gate datalen = mp->b_wptr - mp->b_rptr;
9520Sstevel@tonic-gate if (len < datalen)
9530Sstevel@tonic-gate bytes = len;
9540Sstevel@tonic-gate else
9550Sstevel@tonic-gate bytes = datalen;
9560Sstevel@tonic-gate bcopy(mp->b_rptr, buf, bytes);
9570Sstevel@tonic-gate del_gram(&sockets[sock_id].inq, icp, B_TRUE);
9580Sstevel@tonic-gate break;
9590Sstevel@tonic-gate case INETBOOT_RAW:
9600Sstevel@tonic-gate default:
9610Sstevel@tonic-gate datalen = mp->b_wptr - mp->b_rptr;
9620Sstevel@tonic-gate if (len < datalen)
9630Sstevel@tonic-gate bytes = len;
9640Sstevel@tonic-gate else
9650Sstevel@tonic-gate bytes = datalen;
9660Sstevel@tonic-gate bcopy(mp->b_rptr, buf, bytes);
9670Sstevel@tonic-gate del_gram(&sockets[sock_id].inq, icp, B_TRUE);
9680Sstevel@tonic-gate break;
9690Sstevel@tonic-gate }
9700Sstevel@tonic-gate
9710Sstevel@tonic-gate #ifdef DEBUG
9720Sstevel@tonic-gate printf("recvfrom(%d): data: (0x%x,%d)\n", sock_id,
9730Sstevel@tonic-gate (icp != NULL) ? icp->igm_mp : 0, bytes);
9740Sstevel@tonic-gate #endif /* DEBUG */
9750Sstevel@tonic-gate return (bytes);
9760Sstevel@tonic-gate }
9770Sstevel@tonic-gate
9780Sstevel@tonic-gate
9790Sstevel@tonic-gate /* Just a wrapper around sendto(). */
9800Sstevel@tonic-gate ssize_t
send(int s,const void * msg,size_t len,int flags)9810Sstevel@tonic-gate send(int s, const void *msg, size_t len, int flags)
9820Sstevel@tonic-gate {
9830Sstevel@tonic-gate return (sendto(s, msg, len, flags, NULL, 0));
9840Sstevel@tonic-gate }
9850Sstevel@tonic-gate
9860Sstevel@tonic-gate /*
9870Sstevel@tonic-gate * Transmit a message through a socket.
9880Sstevel@tonic-gate *
9890Sstevel@tonic-gate * Supported flags: MSG_DONTROUTE or 0.
9900Sstevel@tonic-gate */
9910Sstevel@tonic-gate ssize_t
sendto(int s,const void * msg,size_t len,int flags,const struct sockaddr * to,socklen_t tolen)9920Sstevel@tonic-gate sendto(int s, const void *msg, size_t len, int flags, const struct sockaddr *to,
9930Sstevel@tonic-gate socklen_t tolen)
9940Sstevel@tonic-gate {
9950Sstevel@tonic-gate enum SockType so_type;
9960Sstevel@tonic-gate int sock_id;
9970Sstevel@tonic-gate ssize_t bytes;
9980Sstevel@tonic-gate
9990Sstevel@tonic-gate errno = 0;
10000Sstevel@tonic-gate
10010Sstevel@tonic-gate if ((sock_id = so_check_fd(s, &errno)) == -1) {
10020Sstevel@tonic-gate return (-1);
10030Sstevel@tonic-gate }
10040Sstevel@tonic-gate if (msg == NULL) {
10050Sstevel@tonic-gate errno = EINVAL;
10060Sstevel@tonic-gate return (-1);
10070Sstevel@tonic-gate }
10080Sstevel@tonic-gate so_type = sockets[sock_id].type;
10090Sstevel@tonic-gate if ((flags & ~MSG_DONTROUTE) != 0) {
10100Sstevel@tonic-gate errno = EINVAL;
10110Sstevel@tonic-gate return (-1);
10120Sstevel@tonic-gate }
10130Sstevel@tonic-gate if (sockets[sock_id].so_error != 0) {
10140Sstevel@tonic-gate errno = sockets[sock_id].so_error;
10150Sstevel@tonic-gate return (-1);
10160Sstevel@tonic-gate }
10170Sstevel@tonic-gate if (to != NULL && to->sa_family != AF_INET) {
10180Sstevel@tonic-gate errno = EAFNOSUPPORT;
10190Sstevel@tonic-gate return (-1);
10200Sstevel@tonic-gate }
10210Sstevel@tonic-gate
10220Sstevel@tonic-gate switch (so_type) {
10230Sstevel@tonic-gate case INETBOOT_RAW:
10240Sstevel@tonic-gate case INETBOOT_DGRAM:
10250Sstevel@tonic-gate if (!(sockets[sock_id].so_state & SS_ISCONNECTED) &&
10260Sstevel@tonic-gate (to == NULL || tolen != sizeof (struct sockaddr_in))) {
10270Sstevel@tonic-gate errno = EINVAL;
10280Sstevel@tonic-gate return (-1);
10290Sstevel@tonic-gate }
10300Sstevel@tonic-gate bytes = dgram_sendto(sock_id, msg, len, flags, to, tolen);
10310Sstevel@tonic-gate break;
10320Sstevel@tonic-gate case INETBOOT_STREAM:
10330Sstevel@tonic-gate if (!((sockets[sock_id].so_state & SS_ISCONNECTED) ||
10340Sstevel@tonic-gate (sockets[sock_id].so_state & SS_ISCONNECTING))) {
10350Sstevel@tonic-gate errno = EINVAL;
10360Sstevel@tonic-gate return (-1);
10370Sstevel@tonic-gate }
10380Sstevel@tonic-gate if (sockets[sock_id].so_state & SS_CANTSENDMORE) {
10390Sstevel@tonic-gate errno = EPIPE;
10400Sstevel@tonic-gate return (-1);
10410Sstevel@tonic-gate }
10420Sstevel@tonic-gate bytes = stream_sendto(sock_id, msg, len, flags);
10430Sstevel@tonic-gate break;
10440Sstevel@tonic-gate default:
10450Sstevel@tonic-gate /* Should not happen... */
10460Sstevel@tonic-gate errno = EPROTOTYPE;
10470Sstevel@tonic-gate return (-1);
10480Sstevel@tonic-gate }
10490Sstevel@tonic-gate return (bytes);
10500Sstevel@tonic-gate }
10510Sstevel@tonic-gate
10520Sstevel@tonic-gate static ssize_t
dgram_sendto(int i,const void * msg,size_t len,int flags,const struct sockaddr * to,int tolen)10530Sstevel@tonic-gate dgram_sendto(int i, const void *msg, size_t len, int flags,
10540Sstevel@tonic-gate const struct sockaddr *to, int tolen)
10550Sstevel@tonic-gate {
10560Sstevel@tonic-gate struct inetgram oc;
10570Sstevel@tonic-gate int l, offset;
10580Sstevel@tonic-gate size_t tlen;
10590Sstevel@tonic-gate mblk_t *mp;
10600Sstevel@tonic-gate
10610Sstevel@tonic-gate #ifdef DEBUG
10620Sstevel@tonic-gate {
10630Sstevel@tonic-gate struct sockaddr_in *sin = (struct sockaddr_in *)to;
10640Sstevel@tonic-gate printf("sendto(%d): msg of length: %d sent to port %d and host: %s\n",
10650Sstevel@tonic-gate i, len, ntohs(sin->sin_port), inet_ntoa(sin->sin_addr));
10660Sstevel@tonic-gate }
10670Sstevel@tonic-gate #endif /* DEBUG */
10680Sstevel@tonic-gate
10690Sstevel@tonic-gate nuke_grams(&sockets[i].inq); /* flush the input queue */
10700Sstevel@tonic-gate
10710Sstevel@tonic-gate /* calculate offset for data */
10720Sstevel@tonic-gate offset = sockets[i].headerlen[MEDIA_LVL](NULL) +
10730Sstevel@tonic-gate (sockets[i].headerlen[NETWORK_LVL])(NULL);
10740Sstevel@tonic-gate
10750Sstevel@tonic-gate bzero((caddr_t)&oc, sizeof (oc));
10760Sstevel@tonic-gate if (sockets[i].type != INETBOOT_RAW) {
10770Sstevel@tonic-gate offset += (sockets[i].headerlen[TRANSPORT_LVL])(NULL);
10780Sstevel@tonic-gate oc.igm_level = TRANSPORT_LVL;
10790Sstevel@tonic-gate } else
10800Sstevel@tonic-gate oc.igm_level = NETWORK_LVL;
10810Sstevel@tonic-gate oc.igm_oflags = flags;
10820Sstevel@tonic-gate
10830Sstevel@tonic-gate if (to != NULL) {
10840Sstevel@tonic-gate bcopy((caddr_t)to, (caddr_t)&oc.igm_saddr, tolen);
10850Sstevel@tonic-gate } else {
10860Sstevel@tonic-gate bcopy((caddr_t)&sockets[i].remote, (caddr_t)&oc.igm_saddr,
10870Sstevel@tonic-gate sizeof (struct sockaddr_in));
10880Sstevel@tonic-gate }
10890Sstevel@tonic-gate
10900Sstevel@tonic-gate /* Get a legal source port if the socket isn't bound. */
10910Sstevel@tonic-gate if (sockets[i].bound == B_FALSE &&
10920Sstevel@tonic-gate ntohs(oc.igm_saddr.sin_port == 0)) {
10930Sstevel@tonic-gate ((struct sockaddr_in *)&oc.igm_saddr)->sin_port =
10940Sstevel@tonic-gate get_source_port(B_FALSE);
10950Sstevel@tonic-gate }
10960Sstevel@tonic-gate
10970Sstevel@tonic-gate /* Round up to 16bit value for checksum purposes */
10980Sstevel@tonic-gate if (sockets[i].type == INETBOOT_DGRAM) {
10990Sstevel@tonic-gate tlen = ((len + sizeof (uint16_t) - 1) &
11000Sstevel@tonic-gate ~(sizeof (uint16_t) - 1));
11010Sstevel@tonic-gate } else
11020Sstevel@tonic-gate tlen = len;
11030Sstevel@tonic-gate
11040Sstevel@tonic-gate if ((oc.igm_mp = allocb(tlen + offset, 0)) == NULL) {
11050Sstevel@tonic-gate errno = ENOMEM;
11060Sstevel@tonic-gate return (-1);
11070Sstevel@tonic-gate }
11080Sstevel@tonic-gate mp = oc.igm_mp;
11090Sstevel@tonic-gate mp->b_rptr = mp->b_wptr += offset;
11100Sstevel@tonic-gate bcopy((caddr_t)msg, mp->b_wptr, len);
11110Sstevel@tonic-gate mp->b_wptr += len;
11120Sstevel@tonic-gate for (l = TRANSPORT_LVL; l >= MEDIA_LVL; l--) {
11130Sstevel@tonic-gate if (sockets[i].output[l] != NULL) {
11140Sstevel@tonic-gate if (sockets[i].output[l](i, &oc) < 0) {
11150Sstevel@tonic-gate freeb(mp);
11160Sstevel@tonic-gate if (errno == 0)
11170Sstevel@tonic-gate errno = EIO;
11180Sstevel@tonic-gate return (-1);
11190Sstevel@tonic-gate }
11200Sstevel@tonic-gate }
11210Sstevel@tonic-gate }
11220Sstevel@tonic-gate freeb(mp);
11230Sstevel@tonic-gate return (len);
11240Sstevel@tonic-gate }
11250Sstevel@tonic-gate
11260Sstevel@tonic-gate /* ARGSUSED */
11270Sstevel@tonic-gate static ssize_t
stream_sendto(int i,const void * msg,size_t len,int flags)11280Sstevel@tonic-gate stream_sendto(int i, const void *msg, size_t len, int flags)
11290Sstevel@tonic-gate {
11300Sstevel@tonic-gate int cnt;
11310Sstevel@tonic-gate
11320Sstevel@tonic-gate assert(sockets[i].pcb != NULL);
11330Sstevel@tonic-gate
11340Sstevel@tonic-gate /*
11350Sstevel@tonic-gate * Call directly TCP's send routine. We do this because TCP
11360Sstevel@tonic-gate * needs to decide whether to send out the data.
11370Sstevel@tonic-gate *
11380Sstevel@tonic-gate * Note also that currently, TCP ignores all flags passed in for
11390Sstevel@tonic-gate * TCP socket.
11400Sstevel@tonic-gate */
11410Sstevel@tonic-gate if ((cnt = tcp_send(i, sockets[i].pcb, msg, len)) < 0) {
11420Sstevel@tonic-gate if (sockets[i].so_error != 0)
11430Sstevel@tonic-gate errno = sockets[i].so_error;
11440Sstevel@tonic-gate return (-1);
11450Sstevel@tonic-gate } else {
11460Sstevel@tonic-gate return (cnt);
11470Sstevel@tonic-gate }
11480Sstevel@tonic-gate }
11490Sstevel@tonic-gate
11500Sstevel@tonic-gate /*
11510Sstevel@tonic-gate * Returns ptr to the last inetgram in the list, or null if list is null
11520Sstevel@tonic-gate */
11530Sstevel@tonic-gate struct inetgram *
last_gram(struct inetgram * igp)11540Sstevel@tonic-gate last_gram(struct inetgram *igp)
11550Sstevel@tonic-gate {
11560Sstevel@tonic-gate struct inetgram *wp;
11570Sstevel@tonic-gate for (wp = igp; wp != NULL; wp = wp->igm_next) {
11580Sstevel@tonic-gate if (wp->igm_next == NULL)
11590Sstevel@tonic-gate return (wp);
11600Sstevel@tonic-gate }
11610Sstevel@tonic-gate return (NULL);
11620Sstevel@tonic-gate }
11630Sstevel@tonic-gate
11640Sstevel@tonic-gate /*
11650Sstevel@tonic-gate * Adds an inetgram or list of inetgrams to the end of the list.
11660Sstevel@tonic-gate */
11670Sstevel@tonic-gate void
add_grams(struct inetgram ** igpp,struct inetgram * newgp)11680Sstevel@tonic-gate add_grams(struct inetgram **igpp, struct inetgram *newgp)
11690Sstevel@tonic-gate {
11700Sstevel@tonic-gate struct inetgram *wp;
11710Sstevel@tonic-gate
11720Sstevel@tonic-gate if (newgp == NULL)
11730Sstevel@tonic-gate return;
11740Sstevel@tonic-gate
11750Sstevel@tonic-gate if (*igpp == NULL)
11760Sstevel@tonic-gate *igpp = newgp;
11770Sstevel@tonic-gate else {
11780Sstevel@tonic-gate wp = last_gram(*igpp);
11790Sstevel@tonic-gate wp->igm_next = newgp;
11800Sstevel@tonic-gate }
11810Sstevel@tonic-gate }
11820Sstevel@tonic-gate
11830Sstevel@tonic-gate /*
11840Sstevel@tonic-gate * Nuke a whole list of grams.
11850Sstevel@tonic-gate */
11860Sstevel@tonic-gate void
nuke_grams(struct inetgram ** lgpp)11870Sstevel@tonic-gate nuke_grams(struct inetgram **lgpp)
11880Sstevel@tonic-gate {
11890Sstevel@tonic-gate while (*lgpp != NULL)
11900Sstevel@tonic-gate del_gram(lgpp, *lgpp, B_TRUE);
11910Sstevel@tonic-gate }
11920Sstevel@tonic-gate
11930Sstevel@tonic-gate /*
11940Sstevel@tonic-gate * Remove the referenced inetgram. List is altered accordingly. Destroy the
11950Sstevel@tonic-gate * referenced inetgram if freeit is B_TRUE.
11960Sstevel@tonic-gate */
11970Sstevel@tonic-gate void
del_gram(struct inetgram ** lgpp,struct inetgram * igp,int freeit)11980Sstevel@tonic-gate del_gram(struct inetgram **lgpp, struct inetgram *igp, int freeit)
11990Sstevel@tonic-gate {
12000Sstevel@tonic-gate struct inetgram *wp, *pp = NULL;
12010Sstevel@tonic-gate
12020Sstevel@tonic-gate if (lgpp == NULL || igp == NULL)
12030Sstevel@tonic-gate return;
12040Sstevel@tonic-gate
12050Sstevel@tonic-gate wp = *lgpp;
12060Sstevel@tonic-gate while (wp != NULL) {
12070Sstevel@tonic-gate if (wp == igp) {
12080Sstevel@tonic-gate /* detach wp from the list */
12090Sstevel@tonic-gate if (*lgpp == wp)
12100Sstevel@tonic-gate *lgpp = (*lgpp)->igm_next;
12110Sstevel@tonic-gate else
12120Sstevel@tonic-gate pp->igm_next = wp->igm_next;
12130Sstevel@tonic-gate igp->igm_next = NULL;
12140Sstevel@tonic-gate
12150Sstevel@tonic-gate if (freeit) {
12160Sstevel@tonic-gate if (igp->igm_mp != NULL)
12170Sstevel@tonic-gate freeb(igp->igm_mp);
12180Sstevel@tonic-gate bkmem_free((caddr_t)igp,
12190Sstevel@tonic-gate sizeof (struct inetgram));
12200Sstevel@tonic-gate }
12210Sstevel@tonic-gate break;
12220Sstevel@tonic-gate }
12230Sstevel@tonic-gate pp = wp;
12240Sstevel@tonic-gate wp = wp->igm_next;
12250Sstevel@tonic-gate }
12260Sstevel@tonic-gate }
12270Sstevel@tonic-gate
12280Sstevel@tonic-gate struct nct_t nct[] = {
12290Sstevel@tonic-gate "bootp", NCT_BOOTP_DHCP,
12300Sstevel@tonic-gate "dhcp", NCT_BOOTP_DHCP,
12310Sstevel@tonic-gate "rarp", NCT_RARP_BOOTPARAMS,
12320Sstevel@tonic-gate "manual", NCT_MANUAL
12330Sstevel@tonic-gate };
12340Sstevel@tonic-gate int nct_entries = sizeof (nct) / sizeof (nct[0]);
12350Sstevel@tonic-gate
12360Sstevel@tonic-gate /*
12370Sstevel@tonic-gate * Figure out from the bootpath what kind of network configuration strategy
12380Sstevel@tonic-gate * we should use. Returns the network config strategy.
12390Sstevel@tonic-gate */
12400Sstevel@tonic-gate int
get_netconfig_strategy(void)12410Sstevel@tonic-gate get_netconfig_strategy(void)
12420Sstevel@tonic-gate {
12430Sstevel@tonic-gate int i;
12440Sstevel@tonic-gate #define ISSPACE(c) (c == ' ' || c == '\t' || c == '\n' || c == '\0')
12450Sstevel@tonic-gate char lbootpath[OBP_MAXPATHLEN];
12460Sstevel@tonic-gate char net_options[NCT_BUFSIZE];
12470Sstevel@tonic-gate char *op, *nop, *sp;
1248789Sahrens pnode_t cn;
12490Sstevel@tonic-gate int proplen;
12500Sstevel@tonic-gate
12510Sstevel@tonic-gate /* If the PROM DHCP cache exists, we're done */
12520Sstevel@tonic-gate if (prom_cached_reply(B_TRUE))
12530Sstevel@tonic-gate return (NCT_BOOTP_DHCP);
12540Sstevel@tonic-gate
12550Sstevel@tonic-gate /*
12560Sstevel@tonic-gate * Newer (version 4) PROMs will put the name in the
12570Sstevel@tonic-gate * "net-config-strategy" property.
12580Sstevel@tonic-gate */
12590Sstevel@tonic-gate cn = prom_finddevice("/chosen");
12600Sstevel@tonic-gate if ((proplen = prom_getproplen(cn, "net-config-strategy")) <
12610Sstevel@tonic-gate sizeof (net_options)) {
12620Sstevel@tonic-gate (void) prom_getprop(cn, "net-config-strategy", net_options);
12630Sstevel@tonic-gate net_options[proplen] = '\0';
12640Sstevel@tonic-gate } else {
12650Sstevel@tonic-gate
12660Sstevel@tonic-gate /*
12670Sstevel@tonic-gate * We're reduced to sacanning bootpath for the prototol to use.
12680Sstevel@tonic-gate * Since there was no "net-config-strategy" property, this is
12690Sstevel@tonic-gate * an old PROM, so we need to excise any extraneous key/value
12700Sstevel@tonic-gate * initializations from bootpath[].
12710Sstevel@tonic-gate */
12720Sstevel@tonic-gate for (op = prom_bootpath(), sp = lbootpath; op != NULL &&
12730Sstevel@tonic-gate !ISSPACE(*op); sp++, op++)
12740Sstevel@tonic-gate *sp = *op;
12750Sstevel@tonic-gate *sp = '\0';
12760Sstevel@tonic-gate /* find the last '/' (in the device path) */
12770Sstevel@tonic-gate if ((op = strrchr(lbootpath, '/')) == NULL) /* last '/' */
12780Sstevel@tonic-gate op = lbootpath;
12790Sstevel@tonic-gate else
12800Sstevel@tonic-gate op++;
12810Sstevel@tonic-gate /* then look for the ':' separating it from the protocol */
12820Sstevel@tonic-gate while (*op != ':' && *op != '\0')
12830Sstevel@tonic-gate op++;
12840Sstevel@tonic-gate
12850Sstevel@tonic-gate if (*op == ':') {
12860Sstevel@tonic-gate for (nop = net_options, op++;
12870Sstevel@tonic-gate *op != '\0' && *op != '/' && !ISSPACE(*op) &&
12880Sstevel@tonic-gate nop < &net_options[NCT_BUFSIZE]; nop++, op++)
12890Sstevel@tonic-gate *nop = *op;
12900Sstevel@tonic-gate *nop = '\0';
12910Sstevel@tonic-gate } else
12920Sstevel@tonic-gate net_options[0] = '\0';
12930Sstevel@tonic-gate }
12940Sstevel@tonic-gate
12950Sstevel@tonic-gate #undef ISSPACE
12960Sstevel@tonic-gate
12970Sstevel@tonic-gate for (i = 0; i < nct_entries; i++)
12980Sstevel@tonic-gate if (strcmp(net_options, nct[i].p_name) == 0)
12990Sstevel@tonic-gate return (nct[i].p_id);
13000Sstevel@tonic-gate
13010Sstevel@tonic-gate return (NCT_DEFAULT);
13020Sstevel@tonic-gate }
13030Sstevel@tonic-gate
13040Sstevel@tonic-gate /* Modified STREAM routines for ease of porting core TCP code. */
13050Sstevel@tonic-gate
13060Sstevel@tonic-gate /*ARGSUSED*/
13070Sstevel@tonic-gate mblk_t *
allocb(size_t size,uint_t pri)13080Sstevel@tonic-gate allocb(size_t size, uint_t pri)
13090Sstevel@tonic-gate {
13100Sstevel@tonic-gate unsigned char *base;
13110Sstevel@tonic-gate mblk_t *mp;
13120Sstevel@tonic-gate
13130Sstevel@tonic-gate if ((mp = (mblk_t *)bkmem_zalloc(sizeof (mblk_t))) == NULL)
13140Sstevel@tonic-gate return (NULL);
13150Sstevel@tonic-gate if ((base = (unsigned char *)bkmem_zalloc(size)) == NULL)
13160Sstevel@tonic-gate return (NULL);
13170Sstevel@tonic-gate
13180Sstevel@tonic-gate mp->b_next = mp->b_prev = mp->b_cont = NULL;
13190Sstevel@tonic-gate mp->b_rptr = mp->b_wptr = mp->b_datap = (unsigned char *)base;
13200Sstevel@tonic-gate mp->b_size = size;
13210Sstevel@tonic-gate
13220Sstevel@tonic-gate return (mp);
13230Sstevel@tonic-gate }
13240Sstevel@tonic-gate
13250Sstevel@tonic-gate void
freeb(mblk_t * mp)13260Sstevel@tonic-gate freeb(mblk_t *mp)
13270Sstevel@tonic-gate {
13280Sstevel@tonic-gate #ifdef DEBUG
13290Sstevel@tonic-gate printf("freeb datap %x\n", mp->b_datap);
13300Sstevel@tonic-gate #endif
13310Sstevel@tonic-gate bkmem_free((caddr_t)(mp->b_datap), mp->b_size);
13320Sstevel@tonic-gate #ifdef DEBUG
13330Sstevel@tonic-gate printf("freeb mp %x\n", mp);
13340Sstevel@tonic-gate #endif
13350Sstevel@tonic-gate bkmem_free((caddr_t)mp, sizeof (mblk_t));
13360Sstevel@tonic-gate }
13370Sstevel@tonic-gate
13380Sstevel@tonic-gate void
freemsg(mblk_t * mp)13390Sstevel@tonic-gate freemsg(mblk_t *mp)
13400Sstevel@tonic-gate {
13410Sstevel@tonic-gate while (mp) {
13420Sstevel@tonic-gate mblk_t *mp_cont = mp->b_cont;
13430Sstevel@tonic-gate
13440Sstevel@tonic-gate freeb(mp);
13450Sstevel@tonic-gate mp = mp_cont;
13460Sstevel@tonic-gate }
13470Sstevel@tonic-gate }
13480Sstevel@tonic-gate
13490Sstevel@tonic-gate mblk_t *
copyb(mblk_t * bp)13500Sstevel@tonic-gate copyb(mblk_t *bp)
13510Sstevel@tonic-gate {
13520Sstevel@tonic-gate mblk_t *nbp;
13530Sstevel@tonic-gate unsigned char *ndp;
13540Sstevel@tonic-gate
13550Sstevel@tonic-gate assert((uintptr_t)(bp->b_wptr - bp->b_rptr) >= 0);
13560Sstevel@tonic-gate
13570Sstevel@tonic-gate if (!(nbp = allocb(bp->b_size, 0)))
13580Sstevel@tonic-gate return (NULL);
13590Sstevel@tonic-gate nbp->b_cont = NULL;
13600Sstevel@tonic-gate ndp = nbp->b_datap;
13610Sstevel@tonic-gate
13620Sstevel@tonic-gate nbp->b_rptr = ndp + (bp->b_rptr - bp->b_datap);
13630Sstevel@tonic-gate nbp->b_wptr = nbp->b_rptr + (bp->b_wptr - bp->b_rptr);
13640Sstevel@tonic-gate bcopy(bp->b_datap, nbp->b_datap, bp->b_size);
13650Sstevel@tonic-gate return (nbp);
13660Sstevel@tonic-gate }
13670Sstevel@tonic-gate
13680Sstevel@tonic-gate /* To simplify things, dupb() is implemented as copyb(). */
13690Sstevel@tonic-gate mblk_t *
dupb(mblk_t * mp)13700Sstevel@tonic-gate dupb(mblk_t *mp)
13710Sstevel@tonic-gate {
13720Sstevel@tonic-gate return (copyb(mp));
13730Sstevel@tonic-gate }
13740Sstevel@tonic-gate
13750Sstevel@tonic-gate /*
13760Sstevel@tonic-gate * get number of data bytes in message
13770Sstevel@tonic-gate */
13780Sstevel@tonic-gate size_t
msgdsize(mblk_t * bp)13790Sstevel@tonic-gate msgdsize(mblk_t *bp)
13800Sstevel@tonic-gate {
13810Sstevel@tonic-gate size_t count = 0;
13820Sstevel@tonic-gate
13830Sstevel@tonic-gate for (; bp != NULL; bp = bp->b_cont) {
13840Sstevel@tonic-gate assert(bp->b_wptr >= bp->b_rptr);
13850Sstevel@tonic-gate count += bp->b_wptr - bp->b_rptr;
13860Sstevel@tonic-gate }
13870Sstevel@tonic-gate return (count);
13880Sstevel@tonic-gate }
1389