17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 227c478bd9Sstevel@tonic-gate /* 23d045b987Smasputra * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate /* Copyright (c) 1990 Mentat Inc. */ 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate const char udp_version[] = "%Z%%M% %I% %E% SMI"; 317c478bd9Sstevel@tonic-gate 327c478bd9Sstevel@tonic-gate #include <sys/types.h> 337c478bd9Sstevel@tonic-gate #include <sys/stream.h> 34ff550d0eSmasputra #include <sys/dlpi.h> 35ff550d0eSmasputra #include <sys/pattr.h> 367c478bd9Sstevel@tonic-gate #include <sys/stropts.h> 377c478bd9Sstevel@tonic-gate #include <sys/strlog.h> 387c478bd9Sstevel@tonic-gate #include <sys/strsun.h> 397c478bd9Sstevel@tonic-gate #define _SUN_TPI_VERSION 2 407c478bd9Sstevel@tonic-gate #include <sys/tihdr.h> 417c478bd9Sstevel@tonic-gate #include <sys/timod.h> 427c478bd9Sstevel@tonic-gate #include <sys/tiuser.h> 437c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 447c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 457c478bd9Sstevel@tonic-gate #include <sys/strsubr.h> 467c478bd9Sstevel@tonic-gate #include <sys/suntpi.h> 477c478bd9Sstevel@tonic-gate #include <sys/xti_inet.h> 487c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 497c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 507c478bd9Sstevel@tonic-gate #include <sys/policy.h> 517c478bd9Sstevel@tonic-gate #include <sys/ucred.h> 527c478bd9Sstevel@tonic-gate #include <sys/zone.h> 537c478bd9Sstevel@tonic-gate 547c478bd9Sstevel@tonic-gate #include <sys/socket.h> 55ff550d0eSmasputra #include <sys/sockio.h> 567c478bd9Sstevel@tonic-gate #include <sys/vtrace.h> 577c478bd9Sstevel@tonic-gate #include <sys/debug.h> 587c478bd9Sstevel@tonic-gate #include <sys/isa_defs.h> 597c478bd9Sstevel@tonic-gate #include <sys/random.h> 607c478bd9Sstevel@tonic-gate #include <netinet/in.h> 617c478bd9Sstevel@tonic-gate #include <netinet/ip6.h> 627c478bd9Sstevel@tonic-gate #include <netinet/icmp6.h> 637c478bd9Sstevel@tonic-gate #include <netinet/udp.h> 647c478bd9Sstevel@tonic-gate #include <net/if.h> 65ff550d0eSmasputra #include <net/route.h> 667c478bd9Sstevel@tonic-gate 677c478bd9Sstevel@tonic-gate #include <inet/common.h> 687c478bd9Sstevel@tonic-gate #include <inet/ip.h> 69ff550d0eSmasputra #include <inet/ip_impl.h> 707c478bd9Sstevel@tonic-gate #include <inet/ip6.h> 717c478bd9Sstevel@tonic-gate #include <inet/ip_ire.h> 72ff550d0eSmasputra #include <inet/ip_if.h> 73ff550d0eSmasputra #include <inet/ip_multi.h> 747c478bd9Sstevel@tonic-gate #include <inet/mi.h> 757c478bd9Sstevel@tonic-gate #include <inet/mib2.h> 767c478bd9Sstevel@tonic-gate #include <inet/nd.h> 777c478bd9Sstevel@tonic-gate #include <inet/optcom.h> 787c478bd9Sstevel@tonic-gate #include <inet/snmpcom.h> 797c478bd9Sstevel@tonic-gate #include <inet/kstatcom.h> 807c478bd9Sstevel@tonic-gate #include <inet/udp_impl.h> 81ff550d0eSmasputra #include <inet/ipclassifier.h> 82ff550d0eSmasputra #include <inet/ipsec_impl.h> 83ff550d0eSmasputra #include <inet/ipp_common.h> 847c478bd9Sstevel@tonic-gate 857c478bd9Sstevel@tonic-gate /* 86ff550d0eSmasputra * The ipsec_info.h header file is here since it has the definition for the 877c478bd9Sstevel@tonic-gate * M_CTL message types used by IP to convey information to the ULP. The 887c478bd9Sstevel@tonic-gate * ipsec_info.h needs the pfkeyv2.h, hence the latters presence. 897c478bd9Sstevel@tonic-gate */ 907c478bd9Sstevel@tonic-gate #include <net/pfkeyv2.h> 917c478bd9Sstevel@tonic-gate #include <inet/ipsec_info.h> 927c478bd9Sstevel@tonic-gate 937c478bd9Sstevel@tonic-gate /* 947c478bd9Sstevel@tonic-gate * Synchronization notes: 957c478bd9Sstevel@tonic-gate * 96ff550d0eSmasputra * UDP uses a combination of its internal perimeter, a global lock and 97ff550d0eSmasputra * a set of bind hash locks to protect its data structures. Please see 98ff550d0eSmasputra * the note above udp_mode_assertions for details about the internal 99ff550d0eSmasputra * perimeter. 1007c478bd9Sstevel@tonic-gate * 101ff550d0eSmasputra * When a UDP endpoint is bound to a local port, it is inserted into 1027c478bd9Sstevel@tonic-gate * a bind hash list. The list consists of an array of udp_fanout_t buckets. 1037c478bd9Sstevel@tonic-gate * The size of the array is controlled by the udp_bind_fanout_size variable. 1047c478bd9Sstevel@tonic-gate * This variable can be changed in /etc/system if the default value is 105ff550d0eSmasputra * not large enough. Each bind hash bucket is protected by a per bucket 106ff550d0eSmasputra * lock. It protects the udp_bind_hash and udp_ptpbhn fields in the udp_t 1077c478bd9Sstevel@tonic-gate * structure. An UDP endpoint is removed from the bind hash list only 1087c478bd9Sstevel@tonic-gate * when it is being unbound or being closed. The per bucket lock also 109ff550d0eSmasputra * protects a UDP endpoint's state changes. 110ff550d0eSmasputra * 111ff550d0eSmasputra * Plumbing notes: 112ff550d0eSmasputra * 113ff550d0eSmasputra * Both udp and ip are merged, but the streams plumbing is kept unchanged 114ff550d0eSmasputra * in that udp is always pushed atop /dev/ip. This is done to preserve 115ff550d0eSmasputra * backwards compatibility for certain applications which rely on such 116ff550d0eSmasputra * plumbing geometry to do things such as issuing I_POP on the stream 117ff550d0eSmasputra * in order to obtain direct access to /dev/ip, etc. 118ff550d0eSmasputra * 119ff550d0eSmasputra * All UDP processings happen in the /dev/ip instance; the udp module 120ff550d0eSmasputra * instance does not possess any state about the endpoint, and merely 121ff550d0eSmasputra * acts as a dummy module whose presence is to keep the streams plumbing 122ff550d0eSmasputra * appearance unchanged. At open time /dev/ip allocates a conn_t that 123ff550d0eSmasputra * happens to embed a udp_t. This stays dormant until the time udp is 124ff550d0eSmasputra * pushed, which indicates to /dev/ip that it must convert itself from 125ff550d0eSmasputra * an IP to a UDP endpoint. 126ff550d0eSmasputra * 127ff550d0eSmasputra * We only allow for the following plumbing cases: 128ff550d0eSmasputra * 129ff550d0eSmasputra * Normal: 130ff550d0eSmasputra * /dev/ip is first opened and later udp is pushed directly on top. 131ff550d0eSmasputra * This is the default action that happens when a udp socket or 132ff550d0eSmasputra * /dev/udp is opened. The conn_t created by /dev/ip instance is 133ff550d0eSmasputra * now shared and is marked with IPCL_UDP. 134ff550d0eSmasputra * 135ff550d0eSmasputra * SNMP-only: 136ff550d0eSmasputra * udp is pushed on top of a module other than /dev/ip. When this 137ff550d0eSmasputra * happens it will support only SNMP semantics. A new conn_t is 138ff550d0eSmasputra * allocated and marked with IPCL_UDPMOD. 139ff550d0eSmasputra * 140ff550d0eSmasputra * The above cases imply that we don't support any intermediate module to 141ff550d0eSmasputra * reside in between /dev/ip and udp -- in fact, we never supported such 142ff550d0eSmasputra * scenario in the past as the inter-layer communication semantics have 143ff550d0eSmasputra * always been private. Also note that the normal case allows for SNMP 144ff550d0eSmasputra * requests to be processed in addition to the rest of UDP operations. 145ff550d0eSmasputra * 146ff550d0eSmasputra * The normal case plumbing is depicted by the following diagram: 147ff550d0eSmasputra * 148ff550d0eSmasputra * +---------------+---------------+ 149ff550d0eSmasputra * | | | udp 150ff550d0eSmasputra * | udp_wq | udp_rq | 151ff550d0eSmasputra * | | UDP_RD | 152ff550d0eSmasputra * | | | 153ff550d0eSmasputra * +---------------+---------------+ 154ff550d0eSmasputra * | ^ 155ff550d0eSmasputra * v | 156ff550d0eSmasputra * +---------------+---------------+ 157ff550d0eSmasputra * | | | /dev/ip 158ff550d0eSmasputra * | ip_wq | ip_rq | conn_t 159ff550d0eSmasputra * | UDP_WR | | 160ff550d0eSmasputra * | | | 161ff550d0eSmasputra * +---------------+---------------+ 162ff550d0eSmasputra * 163ff550d0eSmasputra * Messages arriving at udp_wq from above will end up in ip_wq before 164ff550d0eSmasputra * it gets processed, i.e. udp write entry points will advance udp_wq 165ff550d0eSmasputra * and use its q_next value as ip_wq in order to use the conn_t that 166ff550d0eSmasputra * is stored in its q_ptr. Likewise, messages generated by ip to the 167ff550d0eSmasputra * module above udp will appear as if they are originated from udp_rq, 168ff550d0eSmasputra * i.e. putnext() calls to the module above udp is done using the 169ff550d0eSmasputra * udp_rq instead of ip_rq in order to avoid udp_rput() which does 170ff550d0eSmasputra * nothing more than calling putnext(). 171ff550d0eSmasputra * 172ff550d0eSmasputra * The above implies the following rule of thumb: 173ff550d0eSmasputra * 174ff550d0eSmasputra * 1. udp_t is obtained from conn_t, which is created by the /dev/ip 175ff550d0eSmasputra * instance and is stored in q_ptr of both ip_wq and ip_rq. There 176ff550d0eSmasputra * is no direct reference to conn_t from either udp_wq or udp_rq. 177ff550d0eSmasputra * 178ff550d0eSmasputra * 2. Write-side entry points of udp can obtain the conn_t via the 179ff550d0eSmasputra * Q_TO_CONN() macro, using the queue value obtain from UDP_WR(). 180ff550d0eSmasputra * 181ff550d0eSmasputra * 3. While in /dev/ip context, putnext() to the module above udp can 182ff550d0eSmasputra * be done by supplying the queue value obtained from UDP_RD(). 183ff550d0eSmasputra * 1847c478bd9Sstevel@tonic-gate */ 1857c478bd9Sstevel@tonic-gate 186ff550d0eSmasputra static queue_t *UDP_WR(queue_t *); 187ff550d0eSmasputra static queue_t *UDP_RD(queue_t *); 188ff550d0eSmasputra 189ff550d0eSmasputra udp_stat_t udp_statistics = { 190ff550d0eSmasputra { "udp_ip_send", KSTAT_DATA_UINT64 }, 191ff550d0eSmasputra { "udp_ip_ire_send", KSTAT_DATA_UINT64 }, 192ff550d0eSmasputra { "udp_ire_null", KSTAT_DATA_UINT64 }, 193ff550d0eSmasputra { "udp_drain", KSTAT_DATA_UINT64 }, 194ff550d0eSmasputra { "udp_sock_fallback", KSTAT_DATA_UINT64 }, 195ff550d0eSmasputra { "udp_rrw_busy", KSTAT_DATA_UINT64 }, 196ff550d0eSmasputra { "udp_rrw_msgcnt", KSTAT_DATA_UINT64 }, 197ff550d0eSmasputra { "udp_out_sw_cksum", KSTAT_DATA_UINT64 }, 198ff550d0eSmasputra { "udp_out_sw_cksum_bytes", KSTAT_DATA_UINT64 }, 199ff550d0eSmasputra { "udp_out_opt", KSTAT_DATA_UINT64 }, 200ff550d0eSmasputra { "udp_out_err_notconn", KSTAT_DATA_UINT64 }, 201ff550d0eSmasputra { "udp_out_err_output", KSTAT_DATA_UINT64 }, 202ff550d0eSmasputra { "udp_out_err_tudr", KSTAT_DATA_UINT64 }, 203ff550d0eSmasputra { "udp_in_pktinfo", KSTAT_DATA_UINT64 }, 204ff550d0eSmasputra { "udp_in_recvdstaddr", KSTAT_DATA_UINT64 }, 205ff550d0eSmasputra { "udp_in_recvopts", KSTAT_DATA_UINT64 }, 206ff550d0eSmasputra { "udp_in_recvif", KSTAT_DATA_UINT64 }, 207ff550d0eSmasputra { "udp_in_recvslla", KSTAT_DATA_UINT64 }, 208ff550d0eSmasputra { "udp_in_recvucred", KSTAT_DATA_UINT64 }, 209ff550d0eSmasputra { "udp_in_recvttl", KSTAT_DATA_UINT64 }, 210ff550d0eSmasputra { "udp_in_recvhopopts", KSTAT_DATA_UINT64 }, 211ff550d0eSmasputra { "udp_in_recvhoplimit", KSTAT_DATA_UINT64 }, 212ff550d0eSmasputra { "udp_in_recvdstopts", KSTAT_DATA_UINT64 }, 213ff550d0eSmasputra { "udp_in_recvrtdstopts", KSTAT_DATA_UINT64 }, 214ff550d0eSmasputra { "udp_in_recvrthdr", KSTAT_DATA_UINT64 }, 215ff550d0eSmasputra { "udp_in_recvpktinfo", KSTAT_DATA_UINT64 }, 216ff550d0eSmasputra { "udp_in_recvtclass", KSTAT_DATA_UINT64 }, 217ff550d0eSmasputra #ifdef DEBUG 218ff550d0eSmasputra { "udp_data_conn", KSTAT_DATA_UINT64 }, 219ff550d0eSmasputra { "udp_data_notconn", KSTAT_DATA_UINT64 }, 220ff550d0eSmasputra #endif 221ff550d0eSmasputra }; 222ff550d0eSmasputra 223ff550d0eSmasputra static kstat_t *udp_ksp; 224ff550d0eSmasputra struct kmem_cache *udp_cache; 225ff550d0eSmasputra 2267c478bd9Sstevel@tonic-gate /* 2277c478bd9Sstevel@tonic-gate * Bind hash list size and hash function. It has to be a power of 2 for 2287c478bd9Sstevel@tonic-gate * hashing. 2297c478bd9Sstevel@tonic-gate */ 2307c478bd9Sstevel@tonic-gate #define UDP_BIND_FANOUT_SIZE 512 2317c478bd9Sstevel@tonic-gate #define UDP_BIND_HASH(lport) \ 2327c478bd9Sstevel@tonic-gate ((ntohs((uint16_t)lport)) & (udp_bind_fanout_size - 1)) 2337c478bd9Sstevel@tonic-gate 2347c478bd9Sstevel@tonic-gate /* UDP bind fanout hash structure. */ 2357c478bd9Sstevel@tonic-gate typedef struct udp_fanout_s { 2367c478bd9Sstevel@tonic-gate udp_t *uf_udp; 2377c478bd9Sstevel@tonic-gate kmutex_t uf_lock; 2387c478bd9Sstevel@tonic-gate #if defined(_LP64) || defined(_I32LPx) 2397c478bd9Sstevel@tonic-gate char uf_pad[48]; 2407c478bd9Sstevel@tonic-gate #else 2417c478bd9Sstevel@tonic-gate char uf_pad[56]; 2427c478bd9Sstevel@tonic-gate #endif 2437c478bd9Sstevel@tonic-gate } udp_fanout_t; 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate uint_t udp_bind_fanout_size = UDP_BIND_FANOUT_SIZE; 2467c478bd9Sstevel@tonic-gate /* udp_fanout_t *udp_bind_fanout. */ 2477c478bd9Sstevel@tonic-gate static udp_fanout_t *udp_bind_fanout; 2487c478bd9Sstevel@tonic-gate 2497c478bd9Sstevel@tonic-gate /* 2507c478bd9Sstevel@tonic-gate * This controls the rate some ndd info report functions can be used 2517c478bd9Sstevel@tonic-gate * by non-priviledged users. It stores the last time such info is 2527c478bd9Sstevel@tonic-gate * requested. When those report functions are called again, this 2537c478bd9Sstevel@tonic-gate * is checked with the current time and compare with the ndd param 2547c478bd9Sstevel@tonic-gate * udp_ndd_get_info_interval. 2557c478bd9Sstevel@tonic-gate */ 2567c478bd9Sstevel@tonic-gate static clock_t udp_last_ndd_get_info_time; 2577c478bd9Sstevel@tonic-gate #define NDD_TOO_QUICK_MSG \ 2587c478bd9Sstevel@tonic-gate "ndd get info rate too high for non-priviledged users, try again " \ 2597c478bd9Sstevel@tonic-gate "later.\n" 2607c478bd9Sstevel@tonic-gate #define NDD_OUT_OF_BUF_MSG "<< Out of buffer >>\n" 2617c478bd9Sstevel@tonic-gate 2627c478bd9Sstevel@tonic-gate static void udp_addr_req(queue_t *q, mblk_t *mp); 2637c478bd9Sstevel@tonic-gate static void udp_bind(queue_t *q, mblk_t *mp); 2647c478bd9Sstevel@tonic-gate static void udp_bind_hash_insert(udp_fanout_t *uf, udp_t *udp); 2657c478bd9Sstevel@tonic-gate static void udp_bind_hash_remove(udp_t *udp, boolean_t caller_holds_lock); 2667c478bd9Sstevel@tonic-gate static int udp_build_hdrs(queue_t *q, udp_t *udp); 2677c478bd9Sstevel@tonic-gate static void udp_capability_req(queue_t *q, mblk_t *mp); 2687c478bd9Sstevel@tonic-gate static int udp_close(queue_t *q); 2697c478bd9Sstevel@tonic-gate static void udp_connect(queue_t *q, mblk_t *mp); 2707c478bd9Sstevel@tonic-gate static void udp_disconnect(queue_t *q, mblk_t *mp); 2717c478bd9Sstevel@tonic-gate static void udp_err_ack(queue_t *q, mblk_t *mp, t_scalar_t t_error, 2727c478bd9Sstevel@tonic-gate int sys_error); 2737c478bd9Sstevel@tonic-gate static void udp_err_ack_prim(queue_t *q, mblk_t *mp, int primitive, 2747c478bd9Sstevel@tonic-gate t_scalar_t tlierr, int unixerr); 2757c478bd9Sstevel@tonic-gate static int udp_extra_priv_ports_get(queue_t *q, mblk_t *mp, caddr_t cp, 2767c478bd9Sstevel@tonic-gate cred_t *cr); 2777c478bd9Sstevel@tonic-gate static int udp_extra_priv_ports_add(queue_t *q, mblk_t *mp, 2787c478bd9Sstevel@tonic-gate char *value, caddr_t cp, cred_t *cr); 2797c478bd9Sstevel@tonic-gate static int udp_extra_priv_ports_del(queue_t *q, mblk_t *mp, 2807c478bd9Sstevel@tonic-gate char *value, caddr_t cp, cred_t *cr); 2817c478bd9Sstevel@tonic-gate static void udp_icmp_error(queue_t *q, mblk_t *mp); 2827c478bd9Sstevel@tonic-gate static void udp_icmp_error_ipv6(queue_t *q, mblk_t *mp); 2837c478bd9Sstevel@tonic-gate static void udp_info_req(queue_t *q, mblk_t *mp); 2847c478bd9Sstevel@tonic-gate static mblk_t *udp_ip_bind_mp(udp_t *udp, t_scalar_t bind_prim, 2857c478bd9Sstevel@tonic-gate t_scalar_t addr_length); 2867c478bd9Sstevel@tonic-gate static int udp_open(queue_t *q, dev_t *devp, int flag, int sflag, 2877c478bd9Sstevel@tonic-gate cred_t *credp); 2887c478bd9Sstevel@tonic-gate static int udp_unitdata_opt_process(queue_t *q, mblk_t *mp, 2897c478bd9Sstevel@tonic-gate int *errorp, void *thisdg_attrs); 2907c478bd9Sstevel@tonic-gate static boolean_t udp_opt_allow_udr_set(t_scalar_t level, t_scalar_t name); 2917c478bd9Sstevel@tonic-gate static int udp_param_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *cr); 2927c478bd9Sstevel@tonic-gate static boolean_t udp_param_register(udpparam_t *udppa, int cnt); 2937c478bd9Sstevel@tonic-gate static int udp_param_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp, 2947c478bd9Sstevel@tonic-gate cred_t *cr); 2957c478bd9Sstevel@tonic-gate static int udp_pkt_set(uchar_t *invalp, uint_t inlen, boolean_t sticky, 2967c478bd9Sstevel@tonic-gate uchar_t **optbufp, uint_t *optlenp); 2977c478bd9Sstevel@tonic-gate static void udp_report_item(mblk_t *mp, udp_t *udp); 2987c478bd9Sstevel@tonic-gate static void udp_rput(queue_t *q, mblk_t *mp); 299ff550d0eSmasputra static void udp_rput_other(queue_t *, mblk_t *); 300ff550d0eSmasputra static int udp_rinfop(queue_t *q, infod_t *dp); 301ff550d0eSmasputra static int udp_rrw(queue_t *q, struiod_t *dp); 3027c478bd9Sstevel@tonic-gate static void udp_rput_bind_ack(queue_t *q, mblk_t *mp); 3037c478bd9Sstevel@tonic-gate static int udp_status_report(queue_t *q, mblk_t *mp, caddr_t cp, 3047c478bd9Sstevel@tonic-gate cred_t *cr); 305ff550d0eSmasputra static void udp_send_data(udp_t *udp, queue_t *q, mblk_t *mp, ipha_t *ipha); 306ff550d0eSmasputra static void udp_ud_err(queue_t *q, mblk_t *mp, uchar_t *destaddr, 307ff550d0eSmasputra t_scalar_t destlen, t_scalar_t err); 3087c478bd9Sstevel@tonic-gate static void udp_unbind(queue_t *q, mblk_t *mp); 3097c478bd9Sstevel@tonic-gate static in_port_t udp_update_next_port(in_port_t port, boolean_t random); 3107c478bd9Sstevel@tonic-gate static void udp_wput(queue_t *q, mblk_t *mp); 311ff550d0eSmasputra static mblk_t *udp_output_v4(conn_t *, mblk_t *mp, ipaddr_t v4dst, 312ff550d0eSmasputra uint16_t port, uint_t srcid, int *error); 313ff550d0eSmasputra static mblk_t *udp_output_v6(conn_t *connp, mblk_t *mp, sin6_t *sin6, 314ff550d0eSmasputra t_scalar_t tudr_optlen, int *error); 3157c478bd9Sstevel@tonic-gate static void udp_wput_other(queue_t *q, mblk_t *mp); 3167c478bd9Sstevel@tonic-gate static void udp_wput_iocdata(queue_t *q, mblk_t *mp); 317ff550d0eSmasputra static void udp_output(conn_t *connp, mblk_t *mp, struct sockaddr *addr, 318ff550d0eSmasputra socklen_t addrlen); 319ff550d0eSmasputra static size_t udp_set_rcv_hiwat(udp_t *udp, size_t size); 3207c478bd9Sstevel@tonic-gate 3217c478bd9Sstevel@tonic-gate static void udp_kstat_init(void); 3227c478bd9Sstevel@tonic-gate static void udp_kstat_fini(void); 3237c478bd9Sstevel@tonic-gate static int udp_kstat_update(kstat_t *kp, int rw); 324ff550d0eSmasputra static void udp_input_wrapper(void *arg, mblk_t *mp, void *arg2); 325ff550d0eSmasputra static void udp_rput_other_wrapper(void *arg, mblk_t *mp, void *arg2); 326ff550d0eSmasputra static void udp_wput_other_wrapper(void *arg, mblk_t *mp, void *arg2); 327ff550d0eSmasputra static void udp_resume_bind_cb(void *arg, mblk_t *mp, void *arg2); 328ff550d0eSmasputra 329ff550d0eSmasputra static void udp_rcv_enqueue(queue_t *q, udp_t *udp, mblk_t *mp, 330ff550d0eSmasputra uint_t pkt_len); 331ff550d0eSmasputra static void udp_rcv_drain(queue_t *q, udp_t *udp, boolean_t closing); 332ff550d0eSmasputra static void udp_enter(conn_t *, mblk_t *, sqproc_t, uint8_t); 333ff550d0eSmasputra static void udp_exit(conn_t *); 334ff550d0eSmasputra static void udp_become_writer(conn_t *, mblk_t *, sqproc_t, uint8_t); 335ff550d0eSmasputra #ifdef DEBUG 336ff550d0eSmasputra static void udp_mode_assertions(udp_t *, int); 337ff550d0eSmasputra #endif /* DEBUG */ 3387c478bd9Sstevel@tonic-gate 3397c478bd9Sstevel@tonic-gate major_t UDP6_MAJ; 340ff550d0eSmasputra #define UDP6 "udp6" 341ff550d0eSmasputra 342ff550d0eSmasputra #define UDP_RECV_HIWATER (56 * 1024) 343ff550d0eSmasputra #define UDP_RECV_LOWATER 128 344ff550d0eSmasputra #define UDP_XMIT_HIWATER (56 * 1024) 345ff550d0eSmasputra #define UDP_XMIT_LOWATER 1024 346ff550d0eSmasputra 347ff550d0eSmasputra static struct module_info udp_info = { 348ff550d0eSmasputra UDP_MOD_ID, UDP_MOD_NAME, 1, INFPSZ, UDP_RECV_HIWATER, UDP_RECV_LOWATER 349ff550d0eSmasputra }; 3507c478bd9Sstevel@tonic-gate 351ff550d0eSmasputra static struct qinit udp_rinit = { 352ff550d0eSmasputra (pfi_t)udp_rput, NULL, udp_open, udp_close, NULL, 353ff550d0eSmasputra &udp_info, NULL, udp_rrw, udp_rinfop, STRUIOT_STANDARD 354ff550d0eSmasputra }; 3557c478bd9Sstevel@tonic-gate 356ff550d0eSmasputra static struct qinit udp_winit = { 357ff550d0eSmasputra (pfi_t)udp_wput, NULL, NULL, NULL, NULL, 358ff550d0eSmasputra &udp_info, NULL, NULL, NULL, STRUIOT_NONE 3597c478bd9Sstevel@tonic-gate }; 3607c478bd9Sstevel@tonic-gate 361d045b987Smasputra static struct qinit winit = { 362d045b987Smasputra (pfi_t)putnext, NULL, NULL, NULL, NULL, 363d045b987Smasputra &udp_info, NULL, NULL, NULL, STRUIOT_NONE 364d045b987Smasputra }; 365d045b987Smasputra 366ff550d0eSmasputra /* Support for just SNMP if UDP is not pushed directly over device IP */ 367ff550d0eSmasputra struct qinit udp_snmp_rinit = { 368ff550d0eSmasputra (pfi_t)putnext, NULL, udp_open, ip_snmpmod_close, NULL, 369ff550d0eSmasputra &udp_info, NULL, NULL, NULL, STRUIOT_NONE 3707c478bd9Sstevel@tonic-gate }; 3717c478bd9Sstevel@tonic-gate 372ff550d0eSmasputra struct qinit udp_snmp_winit = { 373ff550d0eSmasputra (pfi_t)ip_snmpmod_wput, NULL, udp_open, ip_snmpmod_close, NULL, 374ff550d0eSmasputra &udp_info, NULL, NULL, NULL, STRUIOT_NONE 3757c478bd9Sstevel@tonic-gate }; 3767c478bd9Sstevel@tonic-gate 3777c478bd9Sstevel@tonic-gate struct streamtab udpinfo = { 378d045b987Smasputra &udp_rinit, &winit 3797c478bd9Sstevel@tonic-gate }; 3807c478bd9Sstevel@tonic-gate 3817c478bd9Sstevel@tonic-gate static sin_t sin_null; /* Zero address for quick clears */ 3827c478bd9Sstevel@tonic-gate static sin6_t sin6_null; /* Zero address for quick clears */ 3837c478bd9Sstevel@tonic-gate 3847c478bd9Sstevel@tonic-gate /* Hint not protected by any lock */ 3857c478bd9Sstevel@tonic-gate static in_port_t udp_g_next_port_to_try; 3867c478bd9Sstevel@tonic-gate 3877c478bd9Sstevel@tonic-gate /* 388ff550d0eSmasputra * Extra privileged ports. In host byte order. 3897c478bd9Sstevel@tonic-gate */ 3907c478bd9Sstevel@tonic-gate #define UDP_NUM_EPRIV_PORTS 64 3917c478bd9Sstevel@tonic-gate static int udp_g_num_epriv_ports = UDP_NUM_EPRIV_PORTS; 3927c478bd9Sstevel@tonic-gate static in_port_t udp_g_epriv_ports[UDP_NUM_EPRIV_PORTS] = { 2049, 4045 }; 3937c478bd9Sstevel@tonic-gate 3947c478bd9Sstevel@tonic-gate /* Only modified during _init and _fini thus no locking is needed. */ 3957c478bd9Sstevel@tonic-gate static IDP udp_g_nd; /* Points to table of UDP ND variables. */ 3967c478bd9Sstevel@tonic-gate 3977c478bd9Sstevel@tonic-gate /* MIB-2 stuff for SNMP */ 3987c478bd9Sstevel@tonic-gate static mib2_udp_t udp_mib; /* SNMP fixed size info */ 3997c478bd9Sstevel@tonic-gate static kstat_t *udp_mibkp; /* kstat exporting udp_mib data */ 4007c478bd9Sstevel@tonic-gate 401ff550d0eSmasputra #define UDP_MAXPACKET_IPV4 (IP_MAXPACKET - UDPH_SIZE - IP_SIMPLE_HDR_LENGTH) 4027c478bd9Sstevel@tonic-gate 4037c478bd9Sstevel@tonic-gate /* Default structure copied into T_INFO_ACK messages */ 4047c478bd9Sstevel@tonic-gate static struct T_info_ack udp_g_t_info_ack_ipv4 = { 4057c478bd9Sstevel@tonic-gate T_INFO_ACK, 4067c478bd9Sstevel@tonic-gate UDP_MAXPACKET_IPV4, /* TSDU_size. Excl. headers */ 4077c478bd9Sstevel@tonic-gate T_INVALID, /* ETSU_size. udp does not support expedited data. */ 4087c478bd9Sstevel@tonic-gate T_INVALID, /* CDATA_size. udp does not support connect data. */ 4097c478bd9Sstevel@tonic-gate T_INVALID, /* DDATA_size. udp does not support disconnect data. */ 4107c478bd9Sstevel@tonic-gate sizeof (sin_t), /* ADDR_size. */ 4117c478bd9Sstevel@tonic-gate 0, /* OPT_size - not initialized here */ 4127c478bd9Sstevel@tonic-gate UDP_MAXPACKET_IPV4, /* TIDU_size. Excl. headers */ 4137c478bd9Sstevel@tonic-gate T_CLTS, /* SERV_type. udp supports connection-less. */ 4147c478bd9Sstevel@tonic-gate TS_UNBND, /* CURRENT_state. This is set from udp_state. */ 4157c478bd9Sstevel@tonic-gate (XPG4_1|SENDZERO) /* PROVIDER_flag */ 4167c478bd9Sstevel@tonic-gate }; 4177c478bd9Sstevel@tonic-gate 418ff550d0eSmasputra #define UDP_MAXPACKET_IPV6 (IP_MAXPACKET - UDPH_SIZE - IPV6_HDR_LEN) 419ff550d0eSmasputra 4207c478bd9Sstevel@tonic-gate static struct T_info_ack udp_g_t_info_ack_ipv6 = { 4217c478bd9Sstevel@tonic-gate T_INFO_ACK, 4227c478bd9Sstevel@tonic-gate UDP_MAXPACKET_IPV6, /* TSDU_size. Excl. headers */ 4237c478bd9Sstevel@tonic-gate T_INVALID, /* ETSU_size. udp does not support expedited data. */ 4247c478bd9Sstevel@tonic-gate T_INVALID, /* CDATA_size. udp does not support connect data. */ 4257c478bd9Sstevel@tonic-gate T_INVALID, /* DDATA_size. udp does not support disconnect data. */ 4267c478bd9Sstevel@tonic-gate sizeof (sin6_t), /* ADDR_size. */ 4277c478bd9Sstevel@tonic-gate 0, /* OPT_size - not initialized here */ 4287c478bd9Sstevel@tonic-gate UDP_MAXPACKET_IPV6, /* TIDU_size. Excl. headers */ 4297c478bd9Sstevel@tonic-gate T_CLTS, /* SERV_type. udp supports connection-less. */ 4307c478bd9Sstevel@tonic-gate TS_UNBND, /* CURRENT_state. This is set from udp_state. */ 4317c478bd9Sstevel@tonic-gate (XPG4_1|SENDZERO) /* PROVIDER_flag */ 4327c478bd9Sstevel@tonic-gate }; 4337c478bd9Sstevel@tonic-gate 4347c478bd9Sstevel@tonic-gate /* largest UDP port number */ 4357c478bd9Sstevel@tonic-gate #define UDP_MAX_PORT 65535 4367c478bd9Sstevel@tonic-gate 4377c478bd9Sstevel@tonic-gate /* 4387c478bd9Sstevel@tonic-gate * Table of ND variables supported by udp. These are loaded into udp_g_nd 4397c478bd9Sstevel@tonic-gate * in udp_open. 4407c478bd9Sstevel@tonic-gate * All of these are alterable, within the min/max values given, at run time. 4417c478bd9Sstevel@tonic-gate */ 442ff550d0eSmasputra /* BEGIN CSTYLED */ 443ff550d0eSmasputra udpparam_t udp_param_arr[] = { 444ff550d0eSmasputra /*min max value name */ 445ff550d0eSmasputra { 0L, 256, 32, "udp_wroff_extra" }, 446ff550d0eSmasputra { 1L, 255, 255, "udp_ipv4_ttl" }, 447ff550d0eSmasputra { 0, IPV6_MAX_HOPS, IPV6_DEFAULT_HOPS, "udp_ipv6_hoplimit"}, 448ff550d0eSmasputra { 1024, (32 * 1024), 1024, "udp_smallest_nonpriv_port" }, 449ff550d0eSmasputra { 0, 1, 1, "udp_do_checksum" }, 450ff550d0eSmasputra { 1024, UDP_MAX_PORT, (32 * 1024), "udp_smallest_anon_port" }, 451ff550d0eSmasputra { 1024, UDP_MAX_PORT, UDP_MAX_PORT, "udp_largest_anon_port" }, 452ff550d0eSmasputra { UDP_XMIT_LOWATER, (1<<30), UDP_XMIT_HIWATER, "udp_xmit_hiwat"}, 453ff550d0eSmasputra { 0, (1<<30), UDP_XMIT_LOWATER, "udp_xmit_lowat"}, 454ff550d0eSmasputra { UDP_RECV_LOWATER, (1<<30), UDP_RECV_HIWATER, "udp_recv_hiwat"}, 455ff550d0eSmasputra { 65536, (1<<30), 2*1024*1024, "udp_max_buf"}, 456ff550d0eSmasputra { 100, 60000, 1000, "udp_ndd_get_info_interval"}, 4577c478bd9Sstevel@tonic-gate }; 458ff550d0eSmasputra /* END CSTYLED */ 4597c478bd9Sstevel@tonic-gate 4607c478bd9Sstevel@tonic-gate /* 4617c478bd9Sstevel@tonic-gate * The smallest anonymous port in the priviledged port range which UDP 4627c478bd9Sstevel@tonic-gate * looks for free port. Use in the option UDP_ANONPRIVBIND. 4637c478bd9Sstevel@tonic-gate */ 4647c478bd9Sstevel@tonic-gate static in_port_t udp_min_anonpriv_port = 512; 4657c478bd9Sstevel@tonic-gate 4667c478bd9Sstevel@tonic-gate /* If set to 0, pick ephemeral port sequentially; otherwise randomly. */ 4677c478bd9Sstevel@tonic-gate uint32_t udp_random_anon_port = 1; 4687c478bd9Sstevel@tonic-gate 4697c478bd9Sstevel@tonic-gate /* 4707c478bd9Sstevel@tonic-gate * Hook functions to enable cluster networking. 4717c478bd9Sstevel@tonic-gate * On non-clustered systems these vectors must always be NULL 4727c478bd9Sstevel@tonic-gate */ 4737c478bd9Sstevel@tonic-gate 4747c478bd9Sstevel@tonic-gate void (*cl_inet_bind)(uchar_t protocol, sa_family_t addr_family, 475ff550d0eSmasputra uint8_t *laddrp, in_port_t lport) = NULL; 4767c478bd9Sstevel@tonic-gate void (*cl_inet_unbind)(uint8_t protocol, sa_family_t addr_family, 477ff550d0eSmasputra uint8_t *laddrp, in_port_t lport) = NULL; 478ff550d0eSmasputra 479ff550d0eSmasputra typedef union T_primitives *t_primp_t; 480ff550d0eSmasputra 481ff550d0eSmasputra #define UDP_ENQUEUE_MP(udp, mp, proc, tag) { \ 482ff550d0eSmasputra ASSERT((mp)->b_prev == NULL && (mp)->b_queue == NULL); \ 483ff550d0eSmasputra ASSERT(MUTEX_HELD(&(udp)->udp_connp->conn_lock)); \ 484ff550d0eSmasputra (mp)->b_queue = (queue_t *)((uintptr_t)tag); \ 485ff550d0eSmasputra (mp)->b_prev = (mblk_t *)proc; \ 486ff550d0eSmasputra if ((udp)->udp_mphead == NULL) \ 487ff550d0eSmasputra (udp)->udp_mphead = (mp); \ 488ff550d0eSmasputra else \ 489ff550d0eSmasputra (udp)->udp_mptail->b_next = (mp); \ 490ff550d0eSmasputra (udp)->udp_mptail = (mp); \ 491ff550d0eSmasputra (udp)->udp_mpcount++; \ 492ff550d0eSmasputra } 493ff550d0eSmasputra 494ff550d0eSmasputra #define UDP_READERS_INCREF(udp) { \ 495ff550d0eSmasputra ASSERT(MUTEX_HELD(&(udp)->udp_connp->conn_lock)); \ 496ff550d0eSmasputra (udp)->udp_reader_count++; \ 497ff550d0eSmasputra } 498ff550d0eSmasputra 499ff550d0eSmasputra #define UDP_READERS_DECREF(udp) { \ 500ff550d0eSmasputra ASSERT(MUTEX_HELD(&(udp)->udp_connp->conn_lock)); \ 501ff550d0eSmasputra (udp)->udp_reader_count--; \ 502ff550d0eSmasputra if ((udp)->udp_reader_count == 0) \ 503ff550d0eSmasputra cv_broadcast(&(udp)->udp_connp->conn_cv); \ 504ff550d0eSmasputra } 505ff550d0eSmasputra 506ff550d0eSmasputra #define UDP_SQUEUE_DECREF(udp) { \ 507ff550d0eSmasputra ASSERT(MUTEX_HELD(&(udp)->udp_connp->conn_lock)); \ 508ff550d0eSmasputra (udp)->udp_squeue_count--; \ 509ff550d0eSmasputra if ((udp)->udp_squeue_count == 0) \ 510ff550d0eSmasputra cv_broadcast(&(udp)->udp_connp->conn_cv); \ 511ff550d0eSmasputra } 512ff550d0eSmasputra 513ff550d0eSmasputra /* 514ff550d0eSmasputra * Notes on UDP endpoint synchronization: 515ff550d0eSmasputra * 516ff550d0eSmasputra * UDP needs exclusive operation on a per endpoint basis, when executing 517ff550d0eSmasputra * functions that modify the endpoint state. udp_rput_other() deals with 518ff550d0eSmasputra * packets with IP options, and processing these packets end up having 519ff550d0eSmasputra * to update the endpoint's option related state. udp_wput_other() deals 520ff550d0eSmasputra * with control operations from the top, e.g. connect() that needs to 521ff550d0eSmasputra * update the endpoint state. These could be synchronized using locks, 522ff550d0eSmasputra * but the current version uses squeues for this purpose. squeues may 523ff550d0eSmasputra * give performance improvement for certain cases such as connected UDP 524ff550d0eSmasputra * sockets; thus the framework allows for using squeues. 525ff550d0eSmasputra * 526ff550d0eSmasputra * The perimeter routines are described as follows: 527ff550d0eSmasputra * 528ff550d0eSmasputra * udp_enter(): 529ff550d0eSmasputra * Enter the UDP endpoint perimeter. 530ff550d0eSmasputra * 531ff550d0eSmasputra * udp_become_writer(): 532ff550d0eSmasputra * Become exclusive on the UDP endpoint. Specifies a function 533ff550d0eSmasputra * that will be called exclusively either immediately or later 534ff550d0eSmasputra * when the perimeter is available exclusively. 535ff550d0eSmasputra * 536ff550d0eSmasputra * udp_exit(): 537ff550d0eSmasputra * Exit the UDP perimeter. 538ff550d0eSmasputra * 539ff550d0eSmasputra * Entering UDP from the top or from the bottom must be done using 540ff550d0eSmasputra * udp_enter(). No lock must be held while attempting to enter the UDP 541ff550d0eSmasputra * perimeter. When finished, udp_exit() must be called to get out of 542ff550d0eSmasputra * the perimeter. 543ff550d0eSmasputra * 544ff550d0eSmasputra * UDP operates in either MT_HOT mode or in SQUEUE mode. In MT_HOT mode, 545ff550d0eSmasputra * multiple threads may enter a UDP endpoint concurrently. This is used 546ff550d0eSmasputra * for sending and/or receiving normal data. Control operations and other 547ff550d0eSmasputra * special cases call udp_become_writer() to become exclusive on a per 548ff550d0eSmasputra * endpoint basis and this results in transitioning to SQUEUE mode. squeue 549ff550d0eSmasputra * by definition serializes access to the conn_t. When there are no more 550ff550d0eSmasputra * pending messages on the squeue for the UDP connection, the endpoint 551ff550d0eSmasputra * reverts to MT_HOT mode. During the interregnum when not all MT threads 552ff550d0eSmasputra * of an endpoint have finished, messages are queued in the UDP endpoint 553ff550d0eSmasputra * and the UDP is in UDP_MT_QUEUED mode or UDP_QUEUED_SQUEUE mode. 554ff550d0eSmasputra * 555ff550d0eSmasputra * These modes have the following analogs: 556ff550d0eSmasputra * 557ff550d0eSmasputra * UDP_MT_HOT/udp_reader_count==0 none 558ff550d0eSmasputra * UDP_MT_HOT/udp_reader_count>0 RW_READ_LOCK 559ff550d0eSmasputra * UDP_MT_QUEUED RW_WRITE_WANTED 560ff550d0eSmasputra * UDP_SQUEUE or UDP_QUEUED_SQUEUE RW_WRITE_LOCKED 561ff550d0eSmasputra * 562ff550d0eSmasputra * Stable modes: UDP_MT_HOT, UDP_SQUEUE 563ff550d0eSmasputra * Transient modes: UDP_MT_QUEUED, UDP_QUEUED_SQUEUE 564ff550d0eSmasputra * 565ff550d0eSmasputra * While in stable modes, UDP keeps track of the number of threads 566ff550d0eSmasputra * operating on the endpoint. The udp_reader_count variable represents 567ff550d0eSmasputra * the number of threads entering the endpoint as readers while it is 568ff550d0eSmasputra * in UDP_MT_HOT mode. Transitioning to UDP_SQUEUE happens when there 569ff550d0eSmasputra * is only a single reader, i.e. when this counter drops to 1. Likewise, 570ff550d0eSmasputra * udp_squeue_count represents the number of threads operating on the 571ff550d0eSmasputra * endpoint's squeue while it is in UDP_SQUEUE mode. The mode transition 572ff550d0eSmasputra * to UDP_MT_HOT happens after the last thread exits the endpoint, i.e. 573ff550d0eSmasputra * when this counter drops to 0. 574ff550d0eSmasputra * 575ff550d0eSmasputra * The default mode is set to UDP_MT_HOT and UDP alternates between 576ff550d0eSmasputra * UDP_MT_HOT and UDP_SQUEUE as shown in the state transition below. 577ff550d0eSmasputra * 578ff550d0eSmasputra * Mode transition: 579ff550d0eSmasputra * ---------------------------------------------------------------- 580ff550d0eSmasputra * old mode Event New mode 581ff550d0eSmasputra * ---------------------------------------------------------------- 582ff550d0eSmasputra * UDP_MT_HOT Call to udp_become_writer() UDP_SQUEUE 583ff550d0eSmasputra * and udp_reader_count == 1 584ff550d0eSmasputra * 585ff550d0eSmasputra * UDP_MT_HOT Call to udp_become_writer() UDP_MT_QUEUED 586ff550d0eSmasputra * and udp_reader_count > 1 587ff550d0eSmasputra * 588ff550d0eSmasputra * UDP_MT_QUEUED udp_reader_count drops to zero UDP_QUEUED_SQUEUE 589ff550d0eSmasputra * 590ff550d0eSmasputra * UDP_QUEUED_SQUEUE All messages enqueued on the UDP_SQUEUE 591ff550d0eSmasputra * internal UDP queue successfully 592ff550d0eSmasputra * moved to squeue AND udp_squeue_count != 0 593ff550d0eSmasputra * 594ff550d0eSmasputra * UDP_QUEUED_SQUEUE All messages enqueued on the UDP_MT_HOT 595ff550d0eSmasputra * internal UDP queue successfully 596ff550d0eSmasputra * moved to squeue AND udp_squeue_count 597ff550d0eSmasputra * drops to zero 598ff550d0eSmasputra * 599ff550d0eSmasputra * UDP_SQUEUE udp_squeue_count drops to zero UDP_MT_HOT 600ff550d0eSmasputra * ---------------------------------------------------------------- 601ff550d0eSmasputra */ 602ff550d0eSmasputra 603ff550d0eSmasputra static queue_t * 604ff550d0eSmasputra UDP_WR(queue_t *q) 605ff550d0eSmasputra { 606ff550d0eSmasputra ASSERT(q->q_ptr == NULL && _OTHERQ(q)->q_ptr == NULL); 607ff550d0eSmasputra ASSERT(WR(q)->q_next != NULL && WR(q)->q_next->q_ptr != NULL); 608ff550d0eSmasputra ASSERT(IPCL_IS_UDP(Q_TO_CONN(WR(q)->q_next))); 609ff550d0eSmasputra 610ff550d0eSmasputra return (_WR(q)->q_next); 611ff550d0eSmasputra } 612ff550d0eSmasputra 613ff550d0eSmasputra static queue_t * 614ff550d0eSmasputra UDP_RD(queue_t *q) 615ff550d0eSmasputra { 616ff550d0eSmasputra ASSERT(q->q_ptr != NULL && _OTHERQ(q)->q_ptr != NULL); 617ff550d0eSmasputra ASSERT(IPCL_IS_UDP(Q_TO_CONN(q))); 618ff550d0eSmasputra ASSERT(RD(q)->q_next != NULL && RD(q)->q_next->q_ptr == NULL); 619ff550d0eSmasputra 620ff550d0eSmasputra return (_RD(q)->q_next); 621ff550d0eSmasputra } 622ff550d0eSmasputra 623ff550d0eSmasputra #ifdef DEBUG 624ff550d0eSmasputra #define UDP_MODE_ASSERTIONS(udp, caller) udp_mode_assertions(udp, caller) 625ff550d0eSmasputra #else 626ff550d0eSmasputra #define UDP_MODE_ASSERTIONS(udp, caller) 627ff550d0eSmasputra #endif 628ff550d0eSmasputra 629ff550d0eSmasputra /* Invariants */ 630ff550d0eSmasputra #ifdef DEBUG 631ff550d0eSmasputra 632ff550d0eSmasputra uint32_t udp_count[4]; 633ff550d0eSmasputra 634ff550d0eSmasputra /* Context of udp_mode_assertions */ 635ff550d0eSmasputra #define UDP_ENTER 1 636ff550d0eSmasputra #define UDP_BECOME_WRITER 2 637ff550d0eSmasputra #define UDP_EXIT 3 638ff550d0eSmasputra 639ff550d0eSmasputra static void 640ff550d0eSmasputra udp_mode_assertions(udp_t *udp, int caller) 641ff550d0eSmasputra { 642ff550d0eSmasputra ASSERT(MUTEX_HELD(&udp->udp_connp->conn_lock)); 643ff550d0eSmasputra 644ff550d0eSmasputra switch (udp->udp_mode) { 645ff550d0eSmasputra case UDP_MT_HOT: 646ff550d0eSmasputra /* 647ff550d0eSmasputra * Messages have not yet been enqueued on the internal queue, 648ff550d0eSmasputra * otherwise we would have switched to UDP_MT_QUEUED. Likewise 649ff550d0eSmasputra * by definition, there can't be any messages enqueued on the 650ff550d0eSmasputra * squeue. The UDP could be quiescent, so udp_reader_count 651ff550d0eSmasputra * could be zero at entry. 652ff550d0eSmasputra */ 653ff550d0eSmasputra ASSERT(udp->udp_mphead == NULL && udp->udp_mpcount == 0 && 654ff550d0eSmasputra udp->udp_squeue_count == 0); 655ff550d0eSmasputra ASSERT(caller == UDP_ENTER || udp->udp_reader_count != 0); 656ff550d0eSmasputra udp_count[0]++; 657ff550d0eSmasputra break; 658ff550d0eSmasputra 659ff550d0eSmasputra case UDP_MT_QUEUED: 660ff550d0eSmasputra /* 661ff550d0eSmasputra * The last MT thread to exit the udp perimeter empties the 662ff550d0eSmasputra * internal queue and then switches the UDP to 663ff550d0eSmasputra * UDP_QUEUED_SQUEUE mode. Since we are still in UDP_MT_QUEUED 664ff550d0eSmasputra * mode, it means there must be at least 1 MT thread still in 665ff550d0eSmasputra * the perimeter and at least 1 message on the internal queue. 666ff550d0eSmasputra */ 667ff550d0eSmasputra ASSERT(udp->udp_reader_count >= 1 && udp->udp_mphead != NULL && 668ff550d0eSmasputra udp->udp_mpcount != 0 && udp->udp_squeue_count == 0); 669ff550d0eSmasputra udp_count[1]++; 670ff550d0eSmasputra break; 671ff550d0eSmasputra 672ff550d0eSmasputra case UDP_QUEUED_SQUEUE: 673ff550d0eSmasputra /* 674ff550d0eSmasputra * The switch has happened from MT to SQUEUE. So there can't 675ff550d0eSmasputra * any MT threads. Messages could still pile up on the internal 676ff550d0eSmasputra * queue until the transition is complete and we move to 677ff550d0eSmasputra * UDP_SQUEUE mode. We can't assert on nonzero udp_squeue_count 678ff550d0eSmasputra * since the squeue could drain any time. 679ff550d0eSmasputra */ 680ff550d0eSmasputra ASSERT(udp->udp_reader_count == 0); 681ff550d0eSmasputra udp_count[2]++; 682ff550d0eSmasputra break; 683ff550d0eSmasputra 684ff550d0eSmasputra case UDP_SQUEUE: 685ff550d0eSmasputra /* 686ff550d0eSmasputra * The transition is complete. Thre can't be any messages on 687ff550d0eSmasputra * the internal queue. The udp could be quiescent or the squeue 688ff550d0eSmasputra * could drain any time, so we can't assert on nonzero 689ff550d0eSmasputra * udp_squeue_count during entry. Nor can we assert that 690ff550d0eSmasputra * udp_reader_count is zero, since, a reader thread could have 691ff550d0eSmasputra * directly become writer in line by calling udp_become_writer 692ff550d0eSmasputra * without going through the queued states. 693ff550d0eSmasputra */ 694ff550d0eSmasputra ASSERT(udp->udp_mphead == NULL && udp->udp_mpcount == 0); 695ff550d0eSmasputra ASSERT(caller == UDP_ENTER || udp->udp_squeue_count != 0); 696ff550d0eSmasputra udp_count[3]++; 697ff550d0eSmasputra break; 698ff550d0eSmasputra } 699ff550d0eSmasputra } 700ff550d0eSmasputra #endif 701ff550d0eSmasputra 702ff550d0eSmasputra #define _UDP_ENTER(connp, mp, proc, tag) { \ 703ff550d0eSmasputra udp_t *_udp = (connp)->conn_udp; \ 704ff550d0eSmasputra \ 705ff550d0eSmasputra mutex_enter(&(connp)->conn_lock); \ 706ff550d0eSmasputra if ((connp)->conn_state_flags & CONN_CLOSING) { \ 707ff550d0eSmasputra mutex_exit(&(connp)->conn_lock); \ 708ff550d0eSmasputra freemsg(mp); \ 709ff550d0eSmasputra } else { \ 710ff550d0eSmasputra UDP_MODE_ASSERTIONS(_udp, UDP_ENTER); \ 711ff550d0eSmasputra \ 712ff550d0eSmasputra switch (_udp->udp_mode) { \ 713ff550d0eSmasputra case UDP_MT_HOT: \ 714ff550d0eSmasputra /* We can execute as reader right away. */ \ 715ff550d0eSmasputra UDP_READERS_INCREF(_udp); \ 716ff550d0eSmasputra mutex_exit(&(connp)->conn_lock); \ 717ff550d0eSmasputra (*(proc))(connp, mp, (connp)->conn_sqp); \ 718ff550d0eSmasputra break; \ 719ff550d0eSmasputra \ 720ff550d0eSmasputra case UDP_SQUEUE: \ 721ff550d0eSmasputra /* \ 722ff550d0eSmasputra * We are in squeue mode, send the \ 723ff550d0eSmasputra * packet to the squeue \ 724ff550d0eSmasputra */ \ 725ff550d0eSmasputra _udp->udp_squeue_count++; \ 726ff550d0eSmasputra CONN_INC_REF_LOCKED(connp); \ 727ff550d0eSmasputra mutex_exit(&(connp)->conn_lock); \ 728ff550d0eSmasputra squeue_enter((connp)->conn_sqp, mp, proc, \ 729ff550d0eSmasputra connp, tag); \ 730ff550d0eSmasputra break; \ 731ff550d0eSmasputra \ 732ff550d0eSmasputra case UDP_MT_QUEUED: \ 733ff550d0eSmasputra case UDP_QUEUED_SQUEUE: \ 734ff550d0eSmasputra /* \ 735ff550d0eSmasputra * Some messages may have been enqueued \ 736ff550d0eSmasputra * ahead of us. Enqueue the new message \ 737ff550d0eSmasputra * at the tail of the internal queue to \ 738ff550d0eSmasputra * preserve message ordering. \ 739ff550d0eSmasputra */ \ 740ff550d0eSmasputra UDP_ENQUEUE_MP(_udp, mp, proc, tag); \ 741ff550d0eSmasputra mutex_exit(&(connp)->conn_lock); \ 742ff550d0eSmasputra break; \ 743ff550d0eSmasputra } \ 744ff550d0eSmasputra } \ 745ff550d0eSmasputra } 746ff550d0eSmasputra 747ff550d0eSmasputra static void 748ff550d0eSmasputra udp_enter(conn_t *connp, mblk_t *mp, sqproc_t proc, uint8_t tag) 749ff550d0eSmasputra { 750ff550d0eSmasputra _UDP_ENTER(connp, mp, proc, tag); 751ff550d0eSmasputra } 752ff550d0eSmasputra 753ff550d0eSmasputra static void 754ff550d0eSmasputra udp_become_writer(conn_t *connp, mblk_t *mp, sqproc_t proc, uint8_t tag) 755ff550d0eSmasputra { 756ff550d0eSmasputra udp_t *udp; 757ff550d0eSmasputra 758ff550d0eSmasputra udp = connp->conn_udp; 759ff550d0eSmasputra 760ff550d0eSmasputra mutex_enter(&connp->conn_lock); 761ff550d0eSmasputra 762ff550d0eSmasputra UDP_MODE_ASSERTIONS(udp, UDP_BECOME_WRITER); 763ff550d0eSmasputra 764ff550d0eSmasputra switch (udp->udp_mode) { 765ff550d0eSmasputra case UDP_MT_HOT: 766ff550d0eSmasputra if (udp->udp_reader_count == 1) { 767ff550d0eSmasputra /* 768ff550d0eSmasputra * We are the only MT thread. Switch to squeue mode 769ff550d0eSmasputra * immediately. 770ff550d0eSmasputra */ 771ff550d0eSmasputra udp->udp_mode = UDP_SQUEUE; 772ff550d0eSmasputra udp->udp_squeue_count = 1; 773ff550d0eSmasputra CONN_INC_REF_LOCKED(connp); 774ff550d0eSmasputra mutex_exit(&connp->conn_lock); 775ff550d0eSmasputra squeue_enter(connp->conn_sqp, mp, proc, connp, tag); 776ff550d0eSmasputra return; 777ff550d0eSmasputra } 778ff550d0eSmasputra /* FALLTHRU */ 779ff550d0eSmasputra 780ff550d0eSmasputra case UDP_MT_QUEUED: 781ff550d0eSmasputra /* Enqueue the packet internally in UDP */ 782ff550d0eSmasputra udp->udp_mode = UDP_MT_QUEUED; 783ff550d0eSmasputra UDP_ENQUEUE_MP(udp, mp, proc, tag); 784ff550d0eSmasputra mutex_exit(&connp->conn_lock); 785ff550d0eSmasputra return; 786ff550d0eSmasputra 787ff550d0eSmasputra case UDP_SQUEUE: 788ff550d0eSmasputra case UDP_QUEUED_SQUEUE: 789ff550d0eSmasputra /* 790ff550d0eSmasputra * We are already exclusive. i.e. we are already 791ff550d0eSmasputra * writer. Simply call the desired function. 792ff550d0eSmasputra */ 793ff550d0eSmasputra udp->udp_squeue_count++; 794ff550d0eSmasputra mutex_exit(&connp->conn_lock); 795ff550d0eSmasputra (*proc)(connp, mp, connp->conn_sqp); 796ff550d0eSmasputra return; 797ff550d0eSmasputra } 798ff550d0eSmasputra } 799ff550d0eSmasputra 800ff550d0eSmasputra /* 801ff550d0eSmasputra * Transition from MT mode to SQUEUE mode, when the last MT thread 802ff550d0eSmasputra * is exiting the UDP perimeter. Move all messages from the internal 803ff550d0eSmasputra * udp queue to the squeue. A better way would be to move all the 804ff550d0eSmasputra * messages in one shot, this needs more support from the squeue framework 805ff550d0eSmasputra */ 806ff550d0eSmasputra static void 807ff550d0eSmasputra udp_switch_to_squeue(udp_t *udp) 808ff550d0eSmasputra { 809ff550d0eSmasputra mblk_t *mp; 810ff550d0eSmasputra mblk_t *mp_next; 811ff550d0eSmasputra sqproc_t proc; 812ff550d0eSmasputra uint8_t tag; 813ff550d0eSmasputra conn_t *connp = udp->udp_connp; 814ff550d0eSmasputra 815ff550d0eSmasputra ASSERT(MUTEX_HELD(&connp->conn_lock)); 816ff550d0eSmasputra ASSERT(udp->udp_mode == UDP_MT_QUEUED); 817ff550d0eSmasputra while (udp->udp_mphead != NULL) { 818ff550d0eSmasputra mp = udp->udp_mphead; 819ff550d0eSmasputra udp->udp_mphead = NULL; 820ff550d0eSmasputra udp->udp_mptail = NULL; 821ff550d0eSmasputra udp->udp_mpcount = 0; 822ff550d0eSmasputra udp->udp_mode = UDP_QUEUED_SQUEUE; 823ff550d0eSmasputra mutex_exit(&connp->conn_lock); 824ff550d0eSmasputra /* 825ff550d0eSmasputra * It is best not to hold any locks across the calls 826ff550d0eSmasputra * to squeue functions. Since we drop the lock we 827ff550d0eSmasputra * need to go back and check the udp_mphead once again 828ff550d0eSmasputra * after the squeue_fill and hence the while loop at 829ff550d0eSmasputra * the top of this function 830ff550d0eSmasputra */ 831ff550d0eSmasputra for (; mp != NULL; mp = mp_next) { 832ff550d0eSmasputra mp_next = mp->b_next; 833ff550d0eSmasputra proc = (sqproc_t)mp->b_prev; 834ff550d0eSmasputra tag = (uint8_t)((uintptr_t)mp->b_queue); 835ff550d0eSmasputra mp->b_next = NULL; 836ff550d0eSmasputra mp->b_prev = NULL; 837ff550d0eSmasputra mp->b_queue = NULL; 838ff550d0eSmasputra CONN_INC_REF(connp); 839ff550d0eSmasputra udp->udp_squeue_count++; 840ff550d0eSmasputra squeue_fill(connp->conn_sqp, mp, proc, connp, 841ff550d0eSmasputra tag); 842ff550d0eSmasputra } 843ff550d0eSmasputra mutex_enter(&connp->conn_lock); 844ff550d0eSmasputra } 845ff550d0eSmasputra /* 846ff550d0eSmasputra * udp_squeue_count of zero implies that the squeue has drained 847ff550d0eSmasputra * even before we arrived here (i.e. after the squeue_fill above) 848ff550d0eSmasputra */ 849ff550d0eSmasputra udp->udp_mode = (udp->udp_squeue_count != 0) ? 850ff550d0eSmasputra UDP_SQUEUE : UDP_MT_HOT; 851ff550d0eSmasputra } 852ff550d0eSmasputra 853ff550d0eSmasputra #define _UDP_EXIT(connp) { \ 854ff550d0eSmasputra udp_t *_udp = (connp)->conn_udp; \ 855ff550d0eSmasputra \ 856ff550d0eSmasputra mutex_enter(&(connp)->conn_lock); \ 857ff550d0eSmasputra UDP_MODE_ASSERTIONS(_udp, UDP_EXIT); \ 858ff550d0eSmasputra \ 859ff550d0eSmasputra switch (_udp->udp_mode) { \ 860ff550d0eSmasputra case UDP_MT_HOT: \ 861ff550d0eSmasputra UDP_READERS_DECREF(_udp); \ 862ff550d0eSmasputra mutex_exit(&(connp)->conn_lock); \ 863ff550d0eSmasputra break; \ 864ff550d0eSmasputra \ 865ff550d0eSmasputra case UDP_SQUEUE: \ 866ff550d0eSmasputra UDP_SQUEUE_DECREF(_udp); \ 867ff550d0eSmasputra if (_udp->udp_squeue_count == 0) \ 868ff550d0eSmasputra _udp->udp_mode = UDP_MT_HOT; \ 869ff550d0eSmasputra mutex_exit(&(connp)->conn_lock); \ 870ff550d0eSmasputra break; \ 871ff550d0eSmasputra \ 872ff550d0eSmasputra case UDP_MT_QUEUED: \ 873ff550d0eSmasputra /* \ 874ff550d0eSmasputra * If this is the last MT thread, we need to \ 875ff550d0eSmasputra * switch to squeue mode \ 876ff550d0eSmasputra */ \ 877ff550d0eSmasputra UDP_READERS_DECREF(_udp); \ 878ff550d0eSmasputra if (_udp->udp_reader_count == 0) \ 879ff550d0eSmasputra udp_switch_to_squeue(_udp); \ 880ff550d0eSmasputra mutex_exit(&(connp)->conn_lock); \ 881ff550d0eSmasputra break; \ 882ff550d0eSmasputra \ 883ff550d0eSmasputra case UDP_QUEUED_SQUEUE: \ 884ff550d0eSmasputra UDP_SQUEUE_DECREF(_udp); \ 885ff550d0eSmasputra /* \ 886ff550d0eSmasputra * Even if the udp_squeue_count drops to zero, we \ 887ff550d0eSmasputra * don't want to change udp_mode to UDP_MT_HOT here. \ 888ff550d0eSmasputra * The thread in udp_switch_to_squeue will take care \ 889ff550d0eSmasputra * of the transition to UDP_MT_HOT, after emptying \ 890ff550d0eSmasputra * any more new messages that have been enqueued in \ 891ff550d0eSmasputra * udp_mphead. \ 892ff550d0eSmasputra */ \ 893ff550d0eSmasputra mutex_exit(&(connp)->conn_lock); \ 894ff550d0eSmasputra break; \ 895ff550d0eSmasputra } \ 896ff550d0eSmasputra } 897ff550d0eSmasputra 898ff550d0eSmasputra static void 899ff550d0eSmasputra udp_exit(conn_t *connp) 900ff550d0eSmasputra { 901ff550d0eSmasputra _UDP_EXIT(connp); 902ff550d0eSmasputra } 9037c478bd9Sstevel@tonic-gate 9047c478bd9Sstevel@tonic-gate /* 9057c478bd9Sstevel@tonic-gate * Return the next anonymous port in the priviledged port range for 9067c478bd9Sstevel@tonic-gate * bind checking. 9077c478bd9Sstevel@tonic-gate */ 9087c478bd9Sstevel@tonic-gate static in_port_t 9097c478bd9Sstevel@tonic-gate udp_get_next_priv_port(void) 9107c478bd9Sstevel@tonic-gate { 9117c478bd9Sstevel@tonic-gate static in_port_t next_priv_port = IPPORT_RESERVED - 1; 9127c478bd9Sstevel@tonic-gate 9137c478bd9Sstevel@tonic-gate if (next_priv_port < udp_min_anonpriv_port) { 9147c478bd9Sstevel@tonic-gate next_priv_port = IPPORT_RESERVED - 1; 9157c478bd9Sstevel@tonic-gate } 9167c478bd9Sstevel@tonic-gate return (next_priv_port--); 9177c478bd9Sstevel@tonic-gate } 9187c478bd9Sstevel@tonic-gate 9197c478bd9Sstevel@tonic-gate /* UDP bind hash report triggered via the Named Dispatch mechanism. */ 9207c478bd9Sstevel@tonic-gate /* ARGSUSED */ 9217c478bd9Sstevel@tonic-gate static int 9227c478bd9Sstevel@tonic-gate udp_bind_hash_report(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *cr) 9237c478bd9Sstevel@tonic-gate { 9247c478bd9Sstevel@tonic-gate udp_fanout_t *udpf; 9257c478bd9Sstevel@tonic-gate int i; 9267c478bd9Sstevel@tonic-gate zoneid_t zoneid; 927ff550d0eSmasputra conn_t *connp; 928ff550d0eSmasputra udp_t *udp; 929ff550d0eSmasputra 930ff550d0eSmasputra connp = Q_TO_CONN(q); 931ff550d0eSmasputra udp = connp->conn_udp; 9327c478bd9Sstevel@tonic-gate 9337c478bd9Sstevel@tonic-gate /* Refer to comments in udp_status_report(). */ 9347c478bd9Sstevel@tonic-gate if (cr == NULL || secpolicy_net_config(cr, B_TRUE) != 0) { 9357c478bd9Sstevel@tonic-gate if (ddi_get_lbolt() - udp_last_ndd_get_info_time < 9367c478bd9Sstevel@tonic-gate drv_usectohz(udp_ndd_get_info_interval * 1000)) { 9377c478bd9Sstevel@tonic-gate (void) mi_mpprintf(mp, NDD_TOO_QUICK_MSG); 9387c478bd9Sstevel@tonic-gate return (0); 9397c478bd9Sstevel@tonic-gate } 9407c478bd9Sstevel@tonic-gate } 9417c478bd9Sstevel@tonic-gate if ((mp->b_cont = allocb(ND_MAX_BUF_LEN, BPRI_HI)) == NULL) { 9427c478bd9Sstevel@tonic-gate /* The following may work even if we cannot get a large buf. */ 9437c478bd9Sstevel@tonic-gate (void) mi_mpprintf(mp, NDD_OUT_OF_BUF_MSG); 9447c478bd9Sstevel@tonic-gate return (0); 9457c478bd9Sstevel@tonic-gate } 9467c478bd9Sstevel@tonic-gate 9477c478bd9Sstevel@tonic-gate (void) mi_mpprintf(mp, 9487c478bd9Sstevel@tonic-gate "UDP " MI_COL_HDRPAD_STR 9497c478bd9Sstevel@tonic-gate /* 12345678[89ABCDEF] */ 9507c478bd9Sstevel@tonic-gate " zone lport src addr dest addr port state"); 9517c478bd9Sstevel@tonic-gate /* 1234 12345 xxx.xxx.xxx.xxx xxx.xxx.xxx.xxx 12345 UNBOUND */ 9527c478bd9Sstevel@tonic-gate 953ff550d0eSmasputra zoneid = connp->conn_zoneid; 9547c478bd9Sstevel@tonic-gate 9557c478bd9Sstevel@tonic-gate for (i = 0; i < udp_bind_fanout_size; i++) { 9567c478bd9Sstevel@tonic-gate udpf = &udp_bind_fanout[i]; 9577c478bd9Sstevel@tonic-gate mutex_enter(&udpf->uf_lock); 9587c478bd9Sstevel@tonic-gate 9597c478bd9Sstevel@tonic-gate /* Print the hash index. */ 9607c478bd9Sstevel@tonic-gate udp = udpf->uf_udp; 9617c478bd9Sstevel@tonic-gate if (zoneid != GLOBAL_ZONEID) { 9627c478bd9Sstevel@tonic-gate /* skip to first entry in this zone; might be none */ 9637c478bd9Sstevel@tonic-gate while (udp != NULL && 964ff550d0eSmasputra udp->udp_connp->conn_zoneid != zoneid) 9657c478bd9Sstevel@tonic-gate udp = udp->udp_bind_hash; 9667c478bd9Sstevel@tonic-gate } 9677c478bd9Sstevel@tonic-gate if (udp != NULL) { 9687c478bd9Sstevel@tonic-gate uint_t print_len, buf_len; 9697c478bd9Sstevel@tonic-gate 9707c478bd9Sstevel@tonic-gate buf_len = mp->b_cont->b_datap->db_lim - 9717c478bd9Sstevel@tonic-gate mp->b_cont->b_wptr; 9727c478bd9Sstevel@tonic-gate print_len = snprintf((char *)mp->b_cont->b_wptr, 9737c478bd9Sstevel@tonic-gate buf_len, "%d\n", i); 9747c478bd9Sstevel@tonic-gate if (print_len < buf_len) { 9757c478bd9Sstevel@tonic-gate mp->b_cont->b_wptr += print_len; 9767c478bd9Sstevel@tonic-gate } else { 9777c478bd9Sstevel@tonic-gate mp->b_cont->b_wptr += buf_len; 9787c478bd9Sstevel@tonic-gate } 9797c478bd9Sstevel@tonic-gate for (; udp != NULL; udp = udp->udp_bind_hash) { 9807c478bd9Sstevel@tonic-gate if (zoneid == GLOBAL_ZONEID || 981ff550d0eSmasputra zoneid == udp->udp_connp->conn_zoneid) 9827c478bd9Sstevel@tonic-gate udp_report_item(mp->b_cont, udp); 9837c478bd9Sstevel@tonic-gate } 9847c478bd9Sstevel@tonic-gate } 9857c478bd9Sstevel@tonic-gate mutex_exit(&udpf->uf_lock); 9867c478bd9Sstevel@tonic-gate } 9877c478bd9Sstevel@tonic-gate udp_last_ndd_get_info_time = ddi_get_lbolt(); 9887c478bd9Sstevel@tonic-gate return (0); 9897c478bd9Sstevel@tonic-gate } 9907c478bd9Sstevel@tonic-gate 9917c478bd9Sstevel@tonic-gate /* 9927c478bd9Sstevel@tonic-gate * Hash list removal routine for udp_t structures. 9937c478bd9Sstevel@tonic-gate */ 9947c478bd9Sstevel@tonic-gate static void 9957c478bd9Sstevel@tonic-gate udp_bind_hash_remove(udp_t *udp, boolean_t caller_holds_lock) 9967c478bd9Sstevel@tonic-gate { 9977c478bd9Sstevel@tonic-gate udp_t *udpnext; 9987c478bd9Sstevel@tonic-gate kmutex_t *lockp; 9997c478bd9Sstevel@tonic-gate 10007c478bd9Sstevel@tonic-gate if (udp->udp_ptpbhn == NULL) 10017c478bd9Sstevel@tonic-gate return; 10027c478bd9Sstevel@tonic-gate 10037c478bd9Sstevel@tonic-gate /* 10047c478bd9Sstevel@tonic-gate * Extract the lock pointer in case there are concurrent 10057c478bd9Sstevel@tonic-gate * hash_remove's for this instance. 10067c478bd9Sstevel@tonic-gate */ 10077c478bd9Sstevel@tonic-gate ASSERT(udp->udp_port != 0); 10087c478bd9Sstevel@tonic-gate if (!caller_holds_lock) { 10097c478bd9Sstevel@tonic-gate lockp = &udp_bind_fanout[UDP_BIND_HASH(udp->udp_port)].uf_lock; 10107c478bd9Sstevel@tonic-gate ASSERT(lockp != NULL); 10117c478bd9Sstevel@tonic-gate mutex_enter(lockp); 10127c478bd9Sstevel@tonic-gate } 10137c478bd9Sstevel@tonic-gate if (udp->udp_ptpbhn != NULL) { 10147c478bd9Sstevel@tonic-gate udpnext = udp->udp_bind_hash; 10157c478bd9Sstevel@tonic-gate if (udpnext != NULL) { 10167c478bd9Sstevel@tonic-gate udpnext->udp_ptpbhn = udp->udp_ptpbhn; 10177c478bd9Sstevel@tonic-gate udp->udp_bind_hash = NULL; 10187c478bd9Sstevel@tonic-gate } 10197c478bd9Sstevel@tonic-gate *udp->udp_ptpbhn = udpnext; 10207c478bd9Sstevel@tonic-gate udp->udp_ptpbhn = NULL; 10217c478bd9Sstevel@tonic-gate } 10227c478bd9Sstevel@tonic-gate if (!caller_holds_lock) { 10237c478bd9Sstevel@tonic-gate mutex_exit(lockp); 10247c478bd9Sstevel@tonic-gate } 10257c478bd9Sstevel@tonic-gate } 10267c478bd9Sstevel@tonic-gate 10277c478bd9Sstevel@tonic-gate static void 10287c478bd9Sstevel@tonic-gate udp_bind_hash_insert(udp_fanout_t *uf, udp_t *udp) 10297c478bd9Sstevel@tonic-gate { 10307c478bd9Sstevel@tonic-gate udp_t **udpp; 10317c478bd9Sstevel@tonic-gate udp_t *udpnext; 10327c478bd9Sstevel@tonic-gate 10337c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&uf->uf_lock)); 10347c478bd9Sstevel@tonic-gate if (udp->udp_ptpbhn != NULL) { 10357c478bd9Sstevel@tonic-gate udp_bind_hash_remove(udp, B_TRUE); 10367c478bd9Sstevel@tonic-gate } 10377c478bd9Sstevel@tonic-gate udpp = &uf->uf_udp; 10387c478bd9Sstevel@tonic-gate udpnext = udpp[0]; 10397c478bd9Sstevel@tonic-gate if (udpnext != NULL) { 10407c478bd9Sstevel@tonic-gate /* 10417c478bd9Sstevel@tonic-gate * If the new udp bound to the INADDR_ANY address 10427c478bd9Sstevel@tonic-gate * and the first one in the list is not bound to 10437c478bd9Sstevel@tonic-gate * INADDR_ANY we skip all entries until we find the 10447c478bd9Sstevel@tonic-gate * first one bound to INADDR_ANY. 10457c478bd9Sstevel@tonic-gate * This makes sure that applications binding to a 10467c478bd9Sstevel@tonic-gate * specific address get preference over those binding to 10477c478bd9Sstevel@tonic-gate * INADDR_ANY. 10487c478bd9Sstevel@tonic-gate */ 10497c478bd9Sstevel@tonic-gate if (V6_OR_V4_INADDR_ANY(udp->udp_bound_v6src) && 10507c478bd9Sstevel@tonic-gate !V6_OR_V4_INADDR_ANY(udpnext->udp_bound_v6src)) { 10517c478bd9Sstevel@tonic-gate while ((udpnext = udpp[0]) != NULL && 10527c478bd9Sstevel@tonic-gate !V6_OR_V4_INADDR_ANY( 10537c478bd9Sstevel@tonic-gate udpnext->udp_bound_v6src)) { 10547c478bd9Sstevel@tonic-gate udpp = &(udpnext->udp_bind_hash); 10557c478bd9Sstevel@tonic-gate } 10567c478bd9Sstevel@tonic-gate if (udpnext != NULL) 10577c478bd9Sstevel@tonic-gate udpnext->udp_ptpbhn = &udp->udp_bind_hash; 10587c478bd9Sstevel@tonic-gate } else { 10597c478bd9Sstevel@tonic-gate udpnext->udp_ptpbhn = &udp->udp_bind_hash; 10607c478bd9Sstevel@tonic-gate } 10617c478bd9Sstevel@tonic-gate } 10627c478bd9Sstevel@tonic-gate udp->udp_bind_hash = udpnext; 10637c478bd9Sstevel@tonic-gate udp->udp_ptpbhn = udpp; 10647c478bd9Sstevel@tonic-gate udpp[0] = udp; 10657c478bd9Sstevel@tonic-gate } 10667c478bd9Sstevel@tonic-gate 10677c478bd9Sstevel@tonic-gate /* 10687c478bd9Sstevel@tonic-gate * This routine is called to handle each O_T_BIND_REQ/T_BIND_REQ message 10697c478bd9Sstevel@tonic-gate * passed to udp_wput. 10707c478bd9Sstevel@tonic-gate * It associates a port number and local address with the stream. 10717c478bd9Sstevel@tonic-gate * The O_T_BIND_REQ/T_BIND_REQ is passed downstream to ip with the UDP 10727c478bd9Sstevel@tonic-gate * protocol type (IPPROTO_UDP) placed in the message following the address. 10737c478bd9Sstevel@tonic-gate * A T_BIND_ACK message is passed upstream when ip acknowledges the request. 10747c478bd9Sstevel@tonic-gate * (Called as writer.) 10757c478bd9Sstevel@tonic-gate * 10767c478bd9Sstevel@tonic-gate * Note that UDP over IPv4 and IPv6 sockets can use the same port number 10777c478bd9Sstevel@tonic-gate * without setting SO_REUSEADDR. This is needed so that they 10787c478bd9Sstevel@tonic-gate * can be viewed as two independent transport protocols. 10797c478bd9Sstevel@tonic-gate * However, anonymouns ports are allocated from the same range to avoid 10807c478bd9Sstevel@tonic-gate * duplicating the udp_g_next_port_to_try. 10817c478bd9Sstevel@tonic-gate */ 10827c478bd9Sstevel@tonic-gate static void 10837c478bd9Sstevel@tonic-gate udp_bind(queue_t *q, mblk_t *mp) 10847c478bd9Sstevel@tonic-gate { 10857c478bd9Sstevel@tonic-gate sin_t *sin; 10867c478bd9Sstevel@tonic-gate sin6_t *sin6; 10877c478bd9Sstevel@tonic-gate mblk_t *mp1; 10887c478bd9Sstevel@tonic-gate in_port_t port; /* Host byte order */ 10897c478bd9Sstevel@tonic-gate in_port_t requested_port; /* Host byte order */ 10907c478bd9Sstevel@tonic-gate struct T_bind_req *tbr; 10917c478bd9Sstevel@tonic-gate int count; 10927c478bd9Sstevel@tonic-gate in6_addr_t v6src; 10937c478bd9Sstevel@tonic-gate boolean_t bind_to_req_port_only; 10947c478bd9Sstevel@tonic-gate int loopmax; 10957c478bd9Sstevel@tonic-gate udp_fanout_t *udpf; 10967c478bd9Sstevel@tonic-gate in_port_t lport; /* Network byte order */ 10977c478bd9Sstevel@tonic-gate zoneid_t zoneid; 1098ff550d0eSmasputra conn_t *connp; 1099ff550d0eSmasputra udp_t *udp; 11007c478bd9Sstevel@tonic-gate 1101ff550d0eSmasputra connp = Q_TO_CONN(q); 1102ff550d0eSmasputra udp = connp->conn_udp; 11037c478bd9Sstevel@tonic-gate if ((mp->b_wptr - mp->b_rptr) < sizeof (*tbr)) { 11047c478bd9Sstevel@tonic-gate (void) mi_strlog(q, 1, SL_ERROR|SL_TRACE, 11057c478bd9Sstevel@tonic-gate "udp_bind: bad req, len %u", 11067c478bd9Sstevel@tonic-gate (uint_t)(mp->b_wptr - mp->b_rptr)); 11077c478bd9Sstevel@tonic-gate udp_err_ack(q, mp, TPROTO, 0); 11087c478bd9Sstevel@tonic-gate return; 11097c478bd9Sstevel@tonic-gate } 1110ff550d0eSmasputra 11117c478bd9Sstevel@tonic-gate if (udp->udp_state != TS_UNBND) { 11127c478bd9Sstevel@tonic-gate (void) mi_strlog(q, 1, SL_ERROR|SL_TRACE, 11137c478bd9Sstevel@tonic-gate "udp_bind: bad state, %u", udp->udp_state); 11147c478bd9Sstevel@tonic-gate udp_err_ack(q, mp, TOUTSTATE, 0); 11157c478bd9Sstevel@tonic-gate return; 11167c478bd9Sstevel@tonic-gate } 11177c478bd9Sstevel@tonic-gate /* 11187c478bd9Sstevel@tonic-gate * Reallocate the message to make sure we have enough room for an 11197c478bd9Sstevel@tonic-gate * address and the protocol type. 11207c478bd9Sstevel@tonic-gate */ 11217c478bd9Sstevel@tonic-gate mp1 = reallocb(mp, sizeof (struct T_bind_ack) + sizeof (sin6_t) + 1, 1); 11227c478bd9Sstevel@tonic-gate if (!mp1) { 11237c478bd9Sstevel@tonic-gate udp_err_ack(q, mp, TSYSERR, ENOMEM); 11247c478bd9Sstevel@tonic-gate return; 11257c478bd9Sstevel@tonic-gate } 11267c478bd9Sstevel@tonic-gate 11277c478bd9Sstevel@tonic-gate mp = mp1; 11287c478bd9Sstevel@tonic-gate tbr = (struct T_bind_req *)mp->b_rptr; 11297c478bd9Sstevel@tonic-gate switch (tbr->ADDR_length) { 11307c478bd9Sstevel@tonic-gate case 0: /* Request for a generic port */ 11317c478bd9Sstevel@tonic-gate tbr->ADDR_offset = sizeof (struct T_bind_req); 11327c478bd9Sstevel@tonic-gate if (udp->udp_family == AF_INET) { 11337c478bd9Sstevel@tonic-gate tbr->ADDR_length = sizeof (sin_t); 11347c478bd9Sstevel@tonic-gate sin = (sin_t *)&tbr[1]; 11357c478bd9Sstevel@tonic-gate *sin = sin_null; 11367c478bd9Sstevel@tonic-gate sin->sin_family = AF_INET; 11377c478bd9Sstevel@tonic-gate mp->b_wptr = (uchar_t *)&sin[1]; 11387c478bd9Sstevel@tonic-gate } else { 11397c478bd9Sstevel@tonic-gate ASSERT(udp->udp_family == AF_INET6); 11407c478bd9Sstevel@tonic-gate tbr->ADDR_length = sizeof (sin6_t); 11417c478bd9Sstevel@tonic-gate sin6 = (sin6_t *)&tbr[1]; 11427c478bd9Sstevel@tonic-gate *sin6 = sin6_null; 11437c478bd9Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 11447c478bd9Sstevel@tonic-gate mp->b_wptr = (uchar_t *)&sin6[1]; 11457c478bd9Sstevel@tonic-gate } 11467c478bd9Sstevel@tonic-gate port = 0; 11477c478bd9Sstevel@tonic-gate break; 11487c478bd9Sstevel@tonic-gate 11497c478bd9Sstevel@tonic-gate case sizeof (sin_t): /* Complete IPv4 address */ 11507c478bd9Sstevel@tonic-gate sin = (sin_t *)mi_offset_param(mp, tbr->ADDR_offset, 11517c478bd9Sstevel@tonic-gate sizeof (sin_t)); 11527c478bd9Sstevel@tonic-gate if (sin == NULL || !OK_32PTR((char *)sin)) { 11537c478bd9Sstevel@tonic-gate udp_err_ack(q, mp, TSYSERR, EINVAL); 11547c478bd9Sstevel@tonic-gate return; 11557c478bd9Sstevel@tonic-gate } 11567c478bd9Sstevel@tonic-gate if (udp->udp_family != AF_INET || 11577c478bd9Sstevel@tonic-gate sin->sin_family != AF_INET) { 11587c478bd9Sstevel@tonic-gate udp_err_ack(q, mp, TSYSERR, EAFNOSUPPORT); 11597c478bd9Sstevel@tonic-gate return; 11607c478bd9Sstevel@tonic-gate } 11617c478bd9Sstevel@tonic-gate port = ntohs(sin->sin_port); 11627c478bd9Sstevel@tonic-gate break; 11637c478bd9Sstevel@tonic-gate 11647c478bd9Sstevel@tonic-gate case sizeof (sin6_t): /* complete IPv6 address */ 11657c478bd9Sstevel@tonic-gate sin6 = (sin6_t *)mi_offset_param(mp, tbr->ADDR_offset, 11667c478bd9Sstevel@tonic-gate sizeof (sin6_t)); 11677c478bd9Sstevel@tonic-gate if (sin6 == NULL || !OK_32PTR((char *)sin6)) { 11687c478bd9Sstevel@tonic-gate udp_err_ack(q, mp, TSYSERR, EINVAL); 11697c478bd9Sstevel@tonic-gate return; 11707c478bd9Sstevel@tonic-gate } 11717c478bd9Sstevel@tonic-gate if (udp->udp_family != AF_INET6 || 11727c478bd9Sstevel@tonic-gate sin6->sin6_family != AF_INET6) { 11737c478bd9Sstevel@tonic-gate udp_err_ack(q, mp, TSYSERR, EAFNOSUPPORT); 11747c478bd9Sstevel@tonic-gate return; 11757c478bd9Sstevel@tonic-gate } 11767c478bd9Sstevel@tonic-gate port = ntohs(sin6->sin6_port); 11777c478bd9Sstevel@tonic-gate break; 11787c478bd9Sstevel@tonic-gate 11797c478bd9Sstevel@tonic-gate default: /* Invalid request */ 11807c478bd9Sstevel@tonic-gate (void) mi_strlog(q, 1, SL_ERROR|SL_TRACE, 11817c478bd9Sstevel@tonic-gate "udp_bind: bad ADDR_length length %u", tbr->ADDR_length); 11827c478bd9Sstevel@tonic-gate udp_err_ack(q, mp, TBADADDR, 0); 11837c478bd9Sstevel@tonic-gate return; 11847c478bd9Sstevel@tonic-gate } 11857c478bd9Sstevel@tonic-gate 11867c478bd9Sstevel@tonic-gate requested_port = port; 11877c478bd9Sstevel@tonic-gate 11887c478bd9Sstevel@tonic-gate if (requested_port == 0 || tbr->PRIM_type == O_T_BIND_REQ) 11897c478bd9Sstevel@tonic-gate bind_to_req_port_only = B_FALSE; 11907c478bd9Sstevel@tonic-gate else /* T_BIND_REQ and requested_port != 0 */ 11917c478bd9Sstevel@tonic-gate bind_to_req_port_only = B_TRUE; 11927c478bd9Sstevel@tonic-gate 11937c478bd9Sstevel@tonic-gate if (requested_port == 0) { 11947c478bd9Sstevel@tonic-gate /* 11957c478bd9Sstevel@tonic-gate * If the application passed in zero for the port number, it 11967c478bd9Sstevel@tonic-gate * doesn't care which port number we bind to. Get one in the 11977c478bd9Sstevel@tonic-gate * valid range. 11987c478bd9Sstevel@tonic-gate */ 11997c478bd9Sstevel@tonic-gate if (udp->udp_anon_priv_bind) { 12007c478bd9Sstevel@tonic-gate port = udp_get_next_priv_port(); 12017c478bd9Sstevel@tonic-gate } else { 12027c478bd9Sstevel@tonic-gate port = udp_update_next_port(udp_g_next_port_to_try, 12037c478bd9Sstevel@tonic-gate B_TRUE); 12047c478bd9Sstevel@tonic-gate } 12057c478bd9Sstevel@tonic-gate } else { 12067c478bd9Sstevel@tonic-gate /* 12077c478bd9Sstevel@tonic-gate * If the port is in the well-known privileged range, 12087c478bd9Sstevel@tonic-gate * make sure the caller was privileged. 12097c478bd9Sstevel@tonic-gate */ 12107c478bd9Sstevel@tonic-gate int i; 12117c478bd9Sstevel@tonic-gate boolean_t priv = B_FALSE; 12127c478bd9Sstevel@tonic-gate 12137c478bd9Sstevel@tonic-gate if (port < udp_smallest_nonpriv_port) { 12147c478bd9Sstevel@tonic-gate priv = B_TRUE; 12157c478bd9Sstevel@tonic-gate } else { 12167c478bd9Sstevel@tonic-gate for (i = 0; i < udp_g_num_epriv_ports; i++) { 12177c478bd9Sstevel@tonic-gate if (port == udp_g_epriv_ports[i]) { 12187c478bd9Sstevel@tonic-gate priv = B_TRUE; 12197c478bd9Sstevel@tonic-gate break; 12207c478bd9Sstevel@tonic-gate } 12217c478bd9Sstevel@tonic-gate } 12227c478bd9Sstevel@tonic-gate } 12237c478bd9Sstevel@tonic-gate 12247c478bd9Sstevel@tonic-gate if (priv) { 1225ff550d0eSmasputra cred_t *cr = DB_CREDDEF(mp, connp->conn_cred); 12267c478bd9Sstevel@tonic-gate 12277c478bd9Sstevel@tonic-gate if (secpolicy_net_privaddr(cr, port) != 0) { 12287c478bd9Sstevel@tonic-gate udp_err_ack(q, mp, TACCES, 0); 12297c478bd9Sstevel@tonic-gate return; 12307c478bd9Sstevel@tonic-gate } 12317c478bd9Sstevel@tonic-gate } 12327c478bd9Sstevel@tonic-gate } 12337c478bd9Sstevel@tonic-gate 12347c478bd9Sstevel@tonic-gate /* 12357c478bd9Sstevel@tonic-gate * Copy the source address into our udp structure. This address 12367c478bd9Sstevel@tonic-gate * may still be zero; if so, IP will fill in the correct address 12377c478bd9Sstevel@tonic-gate * each time an outbound packet is passed to it. 12387c478bd9Sstevel@tonic-gate */ 12397c478bd9Sstevel@tonic-gate if (udp->udp_family == AF_INET) { 12407c478bd9Sstevel@tonic-gate ASSERT(sin != NULL); 12417c478bd9Sstevel@tonic-gate ASSERT(udp->udp_ipversion == IPV4_VERSION); 12427c478bd9Sstevel@tonic-gate udp->udp_max_hdr_len = IP_SIMPLE_HDR_LENGTH + UDPH_SIZE + 12437c478bd9Sstevel@tonic-gate udp->udp_ip_snd_options_len; 12447c478bd9Sstevel@tonic-gate IN6_IPADDR_TO_V4MAPPED(sin->sin_addr.s_addr, &v6src); 12457c478bd9Sstevel@tonic-gate } else { 12467c478bd9Sstevel@tonic-gate ASSERT(sin6 != NULL); 12477c478bd9Sstevel@tonic-gate v6src = sin6->sin6_addr; 12487c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_V4MAPPED(&v6src)) { 12497c478bd9Sstevel@tonic-gate udp->udp_ipversion = IPV4_VERSION; 12507c478bd9Sstevel@tonic-gate udp->udp_max_hdr_len = IP_SIMPLE_HDR_LENGTH + 12517c478bd9Sstevel@tonic-gate UDPH_SIZE + udp->udp_ip_snd_options_len; 12527c478bd9Sstevel@tonic-gate } else { 12537c478bd9Sstevel@tonic-gate udp->udp_ipversion = IPV6_VERSION; 12547c478bd9Sstevel@tonic-gate udp->udp_max_hdr_len = udp->udp_sticky_hdrs_len; 12557c478bd9Sstevel@tonic-gate } 12567c478bd9Sstevel@tonic-gate } 12577c478bd9Sstevel@tonic-gate 12587c478bd9Sstevel@tonic-gate /* 12597c478bd9Sstevel@tonic-gate * If udp_reuseaddr is not set, then we have to make sure that 12607c478bd9Sstevel@tonic-gate * the IP address and port number the application requested 12617c478bd9Sstevel@tonic-gate * (or we selected for the application) is not being used by 12627c478bd9Sstevel@tonic-gate * another stream. If another stream is already using the 12637c478bd9Sstevel@tonic-gate * requested IP address and port, the behavior depends on 12647c478bd9Sstevel@tonic-gate * "bind_to_req_port_only". If set the bind fails; otherwise we 12657c478bd9Sstevel@tonic-gate * search for any an unused port to bind to the the stream. 12667c478bd9Sstevel@tonic-gate * 12677c478bd9Sstevel@tonic-gate * As per the BSD semantics, as modified by the Deering multicast 12687c478bd9Sstevel@tonic-gate * changes, if udp_reuseaddr is set, then we allow multiple binds 12697c478bd9Sstevel@tonic-gate * to the same port independent of the local IP address. 12707c478bd9Sstevel@tonic-gate * 12717c478bd9Sstevel@tonic-gate * This is slightly different than in SunOS 4.X which did not 12727c478bd9Sstevel@tonic-gate * support IP multicast. Note that the change implemented by the 12737c478bd9Sstevel@tonic-gate * Deering multicast code effects all binds - not only binding 12747c478bd9Sstevel@tonic-gate * to IP multicast addresses. 12757c478bd9Sstevel@tonic-gate * 12767c478bd9Sstevel@tonic-gate * Note that when binding to port zero we ignore SO_REUSEADDR in 12777c478bd9Sstevel@tonic-gate * order to guarantee a unique port. 12787c478bd9Sstevel@tonic-gate */ 12797c478bd9Sstevel@tonic-gate 12807c478bd9Sstevel@tonic-gate count = 0; 12817c478bd9Sstevel@tonic-gate if (udp->udp_anon_priv_bind) { 12827c478bd9Sstevel@tonic-gate /* loopmax = (IPPORT_RESERVED-1) - udp_min_anonpriv_port + 1 */ 12837c478bd9Sstevel@tonic-gate loopmax = IPPORT_RESERVED - udp_min_anonpriv_port; 12847c478bd9Sstevel@tonic-gate } else { 12857c478bd9Sstevel@tonic-gate loopmax = udp_largest_anon_port - udp_smallest_anon_port + 1; 12867c478bd9Sstevel@tonic-gate } 12877c478bd9Sstevel@tonic-gate 1288ff550d0eSmasputra zoneid = connp->conn_zoneid; 12897c478bd9Sstevel@tonic-gate for (;;) { 12907c478bd9Sstevel@tonic-gate udp_t *udp1; 12917c478bd9Sstevel@tonic-gate boolean_t is_inaddr_any; 12927c478bd9Sstevel@tonic-gate boolean_t found_exclbind = B_FALSE; 12937c478bd9Sstevel@tonic-gate 12947c478bd9Sstevel@tonic-gate is_inaddr_any = V6_OR_V4_INADDR_ANY(v6src); 12957c478bd9Sstevel@tonic-gate /* 12967c478bd9Sstevel@tonic-gate * Walk through the list of udp streams bound to 12977c478bd9Sstevel@tonic-gate * requested port with the same IP address. 12987c478bd9Sstevel@tonic-gate */ 12997c478bd9Sstevel@tonic-gate lport = htons(port); 13007c478bd9Sstevel@tonic-gate udpf = &udp_bind_fanout[UDP_BIND_HASH(lport)]; 13017c478bd9Sstevel@tonic-gate mutex_enter(&udpf->uf_lock); 13027c478bd9Sstevel@tonic-gate for (udp1 = udpf->uf_udp; udp1 != NULL; 13037c478bd9Sstevel@tonic-gate udp1 = udp1->udp_bind_hash) { 13047c478bd9Sstevel@tonic-gate if (lport != udp1->udp_port || 1305ff550d0eSmasputra zoneid != udp1->udp_connp->conn_zoneid) 13067c478bd9Sstevel@tonic-gate continue; 13077c478bd9Sstevel@tonic-gate 13087c478bd9Sstevel@tonic-gate /* 13097c478bd9Sstevel@tonic-gate * If UDP_EXCLBIND is set for either the bound or 13107c478bd9Sstevel@tonic-gate * binding endpoint, the semantics of bind 13117c478bd9Sstevel@tonic-gate * is changed according to the following chart. 13127c478bd9Sstevel@tonic-gate * 13137c478bd9Sstevel@tonic-gate * spec = specified address (v4 or v6) 13147c478bd9Sstevel@tonic-gate * unspec = unspecified address (v4 or v6) 13157c478bd9Sstevel@tonic-gate * A = specified addresses are different for endpoints 13167c478bd9Sstevel@tonic-gate * 13177c478bd9Sstevel@tonic-gate * bound bind to allowed? 13187c478bd9Sstevel@tonic-gate * ------------------------------------- 13197c478bd9Sstevel@tonic-gate * unspec unspec no 13207c478bd9Sstevel@tonic-gate * unspec spec no 13217c478bd9Sstevel@tonic-gate * spec unspec no 13227c478bd9Sstevel@tonic-gate * spec spec yes if A 13237c478bd9Sstevel@tonic-gate */ 13247c478bd9Sstevel@tonic-gate if (udp1->udp_exclbind || udp->udp_exclbind) { 13257c478bd9Sstevel@tonic-gate if (V6_OR_V4_INADDR_ANY( 13267c478bd9Sstevel@tonic-gate udp1->udp_bound_v6src) || 13277c478bd9Sstevel@tonic-gate is_inaddr_any || 13287c478bd9Sstevel@tonic-gate IN6_ARE_ADDR_EQUAL(&udp1->udp_bound_v6src, 13297c478bd9Sstevel@tonic-gate &v6src)) { 13307c478bd9Sstevel@tonic-gate found_exclbind = B_TRUE; 13317c478bd9Sstevel@tonic-gate break; 13327c478bd9Sstevel@tonic-gate } 13337c478bd9Sstevel@tonic-gate continue; 13347c478bd9Sstevel@tonic-gate } 13357c478bd9Sstevel@tonic-gate 13367c478bd9Sstevel@tonic-gate /* 13377c478bd9Sstevel@tonic-gate * Check ipversion to allow IPv4 and IPv6 sockets to 1338*738d543bSdduvall * have disjoint port number spaces. 13397c478bd9Sstevel@tonic-gate */ 1340*738d543bSdduvall if (udp->udp_ipversion != udp1->udp_ipversion) 13417c478bd9Sstevel@tonic-gate continue; 13427c478bd9Sstevel@tonic-gate 13437c478bd9Sstevel@tonic-gate /* 13447c478bd9Sstevel@tonic-gate * No difference depending on SO_REUSEADDR. 13457c478bd9Sstevel@tonic-gate * 13467c478bd9Sstevel@tonic-gate * If existing port is bound to a 13477c478bd9Sstevel@tonic-gate * non-wildcard IP address and 13487c478bd9Sstevel@tonic-gate * the requesting stream is bound to 13497c478bd9Sstevel@tonic-gate * a distinct different IP addresses 13507c478bd9Sstevel@tonic-gate * (non-wildcard, also), keep going. 13517c478bd9Sstevel@tonic-gate */ 13527c478bd9Sstevel@tonic-gate if (!is_inaddr_any && 13537c478bd9Sstevel@tonic-gate !V6_OR_V4_INADDR_ANY(udp1->udp_bound_v6src) && 13547c478bd9Sstevel@tonic-gate !IN6_ARE_ADDR_EQUAL(&udp1->udp_bound_v6src, 13557c478bd9Sstevel@tonic-gate &v6src)) { 13567c478bd9Sstevel@tonic-gate continue; 13577c478bd9Sstevel@tonic-gate } 13587c478bd9Sstevel@tonic-gate break; 13597c478bd9Sstevel@tonic-gate } 13607c478bd9Sstevel@tonic-gate 13617c478bd9Sstevel@tonic-gate if (!found_exclbind && 13627c478bd9Sstevel@tonic-gate (udp->udp_reuseaddr && requested_port != 0)) { 13637c478bd9Sstevel@tonic-gate break; 13647c478bd9Sstevel@tonic-gate } 13657c478bd9Sstevel@tonic-gate 13667c478bd9Sstevel@tonic-gate if (udp1 == NULL) { 13677c478bd9Sstevel@tonic-gate /* 13687c478bd9Sstevel@tonic-gate * No other stream has this IP address 13697c478bd9Sstevel@tonic-gate * and port number. We can use it. 13707c478bd9Sstevel@tonic-gate */ 13717c478bd9Sstevel@tonic-gate break; 13727c478bd9Sstevel@tonic-gate } 13737c478bd9Sstevel@tonic-gate mutex_exit(&udpf->uf_lock); 13747c478bd9Sstevel@tonic-gate if (bind_to_req_port_only) { 13757c478bd9Sstevel@tonic-gate /* 13767c478bd9Sstevel@tonic-gate * We get here only when requested port 13777c478bd9Sstevel@tonic-gate * is bound (and only first of the for() 13787c478bd9Sstevel@tonic-gate * loop iteration). 13797c478bd9Sstevel@tonic-gate * 13807c478bd9Sstevel@tonic-gate * The semantics of this bind request 13817c478bd9Sstevel@tonic-gate * require it to fail so we return from 13827c478bd9Sstevel@tonic-gate * the routine (and exit the loop). 13837c478bd9Sstevel@tonic-gate * 13847c478bd9Sstevel@tonic-gate */ 13857c478bd9Sstevel@tonic-gate udp_err_ack(q, mp, TADDRBUSY, 0); 13867c478bd9Sstevel@tonic-gate return; 13877c478bd9Sstevel@tonic-gate } 13887c478bd9Sstevel@tonic-gate 13897c478bd9Sstevel@tonic-gate if (udp->udp_anon_priv_bind) { 13907c478bd9Sstevel@tonic-gate port = udp_get_next_priv_port(); 13917c478bd9Sstevel@tonic-gate } else { 13927c478bd9Sstevel@tonic-gate if ((count == 0) && (requested_port != 0)) { 13937c478bd9Sstevel@tonic-gate /* 13947c478bd9Sstevel@tonic-gate * If the application wants us to find 13957c478bd9Sstevel@tonic-gate * a port, get one to start with. Set 13967c478bd9Sstevel@tonic-gate * requested_port to 0, so that we will 13977c478bd9Sstevel@tonic-gate * update udp_g_next_port_to_try below. 13987c478bd9Sstevel@tonic-gate */ 13997c478bd9Sstevel@tonic-gate port = udp_update_next_port( 14007c478bd9Sstevel@tonic-gate udp_g_next_port_to_try, B_TRUE); 14017c478bd9Sstevel@tonic-gate requested_port = 0; 14027c478bd9Sstevel@tonic-gate } else { 14037c478bd9Sstevel@tonic-gate port = udp_update_next_port(port + 1, B_FALSE); 14047c478bd9Sstevel@tonic-gate } 14057c478bd9Sstevel@tonic-gate } 14067c478bd9Sstevel@tonic-gate 14077c478bd9Sstevel@tonic-gate if (++count >= loopmax) { 14087c478bd9Sstevel@tonic-gate /* 14097c478bd9Sstevel@tonic-gate * We've tried every possible port number and 14107c478bd9Sstevel@tonic-gate * there are none available, so send an error 14117c478bd9Sstevel@tonic-gate * to the user. 14127c478bd9Sstevel@tonic-gate */ 14137c478bd9Sstevel@tonic-gate udp_err_ack(q, mp, TNOADDR, 0); 14147c478bd9Sstevel@tonic-gate return; 14157c478bd9Sstevel@tonic-gate } 14167c478bd9Sstevel@tonic-gate } 14177c478bd9Sstevel@tonic-gate 14187c478bd9Sstevel@tonic-gate /* 14197c478bd9Sstevel@tonic-gate * Copy the source address into our udp structure. This address 14207c478bd9Sstevel@tonic-gate * may still be zero; if so, ip will fill in the correct address 14217c478bd9Sstevel@tonic-gate * each time an outbound packet is passed to it. 14227c478bd9Sstevel@tonic-gate * If we are binding to a broadcast or multicast address udp_rput 14237c478bd9Sstevel@tonic-gate * will clear the source address when it receives the T_BIND_ACK. 14247c478bd9Sstevel@tonic-gate */ 14257c478bd9Sstevel@tonic-gate udp->udp_v6src = udp->udp_bound_v6src = v6src; 14267c478bd9Sstevel@tonic-gate udp->udp_port = lport; 14277c478bd9Sstevel@tonic-gate /* 14287c478bd9Sstevel@tonic-gate * Now reset the the next anonymous port if the application requested 14297c478bd9Sstevel@tonic-gate * an anonymous port, or we handed out the next anonymous port. 14307c478bd9Sstevel@tonic-gate */ 14317c478bd9Sstevel@tonic-gate if ((requested_port == 0) && (!udp->udp_anon_priv_bind)) { 14327c478bd9Sstevel@tonic-gate udp_g_next_port_to_try = port + 1; 14337c478bd9Sstevel@tonic-gate } 14347c478bd9Sstevel@tonic-gate 14357c478bd9Sstevel@tonic-gate /* Initialize the O_T_BIND_REQ/T_BIND_REQ for ip. */ 14367c478bd9Sstevel@tonic-gate if (udp->udp_family == AF_INET) { 14377c478bd9Sstevel@tonic-gate sin->sin_port = udp->udp_port; 14387c478bd9Sstevel@tonic-gate } else { 14397c478bd9Sstevel@tonic-gate int error; 14407c478bd9Sstevel@tonic-gate 14417c478bd9Sstevel@tonic-gate sin6->sin6_port = udp->udp_port; 14427c478bd9Sstevel@tonic-gate /* Rebuild the header template */ 14437c478bd9Sstevel@tonic-gate error = udp_build_hdrs(q, udp); 14447c478bd9Sstevel@tonic-gate if (error != 0) { 14457c478bd9Sstevel@tonic-gate mutex_exit(&udpf->uf_lock); 14467c478bd9Sstevel@tonic-gate udp_err_ack(q, mp, TSYSERR, error); 14477c478bd9Sstevel@tonic-gate return; 14487c478bd9Sstevel@tonic-gate } 14497c478bd9Sstevel@tonic-gate } 14507c478bd9Sstevel@tonic-gate udp->udp_state = TS_IDLE; 14517c478bd9Sstevel@tonic-gate udp_bind_hash_insert(udpf, udp); 14527c478bd9Sstevel@tonic-gate mutex_exit(&udpf->uf_lock); 14537c478bd9Sstevel@tonic-gate 14547c478bd9Sstevel@tonic-gate if (cl_inet_bind) { 14557c478bd9Sstevel@tonic-gate /* 14567c478bd9Sstevel@tonic-gate * Running in cluster mode - register bind information 14577c478bd9Sstevel@tonic-gate */ 14587c478bd9Sstevel@tonic-gate if (udp->udp_ipversion == IPV4_VERSION) { 14597c478bd9Sstevel@tonic-gate (*cl_inet_bind)(IPPROTO_UDP, AF_INET, 14607c478bd9Sstevel@tonic-gate (uint8_t *)(&V4_PART_OF_V6(udp->udp_v6src)), 14617c478bd9Sstevel@tonic-gate (in_port_t)udp->udp_port); 14627c478bd9Sstevel@tonic-gate } else { 14637c478bd9Sstevel@tonic-gate (*cl_inet_bind)(IPPROTO_UDP, AF_INET6, 14647c478bd9Sstevel@tonic-gate (uint8_t *)&(udp->udp_v6src), 14657c478bd9Sstevel@tonic-gate (in_port_t)udp->udp_port); 14667c478bd9Sstevel@tonic-gate } 14677c478bd9Sstevel@tonic-gate 14687c478bd9Sstevel@tonic-gate } 14697c478bd9Sstevel@tonic-gate 14707c478bd9Sstevel@tonic-gate /* Pass the protocol number in the message following the address. */ 14717c478bd9Sstevel@tonic-gate *mp->b_wptr++ = IPPROTO_UDP; 14727c478bd9Sstevel@tonic-gate if (!V6_OR_V4_INADDR_ANY(udp->udp_v6src)) { 14737c478bd9Sstevel@tonic-gate /* 14747c478bd9Sstevel@tonic-gate * Append a request for an IRE if udp_v6src not 14757c478bd9Sstevel@tonic-gate * zero (IPv4 - INADDR_ANY, or IPv6 - all-zeroes address). 14767c478bd9Sstevel@tonic-gate */ 14777c478bd9Sstevel@tonic-gate mp->b_cont = allocb(sizeof (ire_t), BPRI_HI); 14787c478bd9Sstevel@tonic-gate if (!mp->b_cont) { 14797c478bd9Sstevel@tonic-gate udp_err_ack(q, mp, TSYSERR, ENOMEM); 14807c478bd9Sstevel@tonic-gate return; 14817c478bd9Sstevel@tonic-gate } 14827c478bd9Sstevel@tonic-gate mp->b_cont->b_wptr += sizeof (ire_t); 14837c478bd9Sstevel@tonic-gate mp->b_cont->b_datap->db_type = IRE_DB_REQ_TYPE; 14847c478bd9Sstevel@tonic-gate } 1485ff550d0eSmasputra if (udp->udp_family == AF_INET6) 1486ff550d0eSmasputra mp = ip_bind_v6(q, mp, connp, NULL); 1487ff550d0eSmasputra else 1488ff550d0eSmasputra mp = ip_bind_v4(q, mp, connp); 1489ff550d0eSmasputra 1490ff550d0eSmasputra if (mp != NULL) 1491ff550d0eSmasputra udp_rput_other(_RD(q), mp); 1492ff550d0eSmasputra else 1493ff550d0eSmasputra CONN_INC_REF(connp); 1494ff550d0eSmasputra } 1495ff550d0eSmasputra 1496ff550d0eSmasputra 1497ff550d0eSmasputra void 1498ff550d0eSmasputra udp_resume_bind(conn_t *connp, mblk_t *mp) 1499ff550d0eSmasputra { 1500ff550d0eSmasputra udp_enter(connp, mp, udp_resume_bind_cb, SQTAG_BIND_RETRY); 1501ff550d0eSmasputra } 1502ff550d0eSmasputra 1503ff550d0eSmasputra /* 1504ff550d0eSmasputra * This is called from ip_wput_nondata to resume a deferred UDP bind. 1505ff550d0eSmasputra */ 1506ff550d0eSmasputra /* ARGSUSED */ 1507ff550d0eSmasputra static void 1508ff550d0eSmasputra udp_resume_bind_cb(void *arg, mblk_t *mp, void *arg2) 1509ff550d0eSmasputra { 1510ff550d0eSmasputra conn_t *connp = arg; 1511ff550d0eSmasputra 1512ff550d0eSmasputra ASSERT(connp != NULL && IPCL_IS_UDP(connp)); 1513ff550d0eSmasputra 1514ff550d0eSmasputra udp_rput_other(connp->conn_rq, mp); 1515ff550d0eSmasputra 1516ff550d0eSmasputra CONN_OPER_PENDING_DONE(connp); 1517ff550d0eSmasputra udp_exit(connp); 15187c478bd9Sstevel@tonic-gate } 15197c478bd9Sstevel@tonic-gate 15207c478bd9Sstevel@tonic-gate /* 15217c478bd9Sstevel@tonic-gate * This routine handles each T_CONN_REQ message passed to udp. It 15227c478bd9Sstevel@tonic-gate * associates a default destination address with the stream. 15237c478bd9Sstevel@tonic-gate * 15247c478bd9Sstevel@tonic-gate * This routine sends down a T_BIND_REQ to IP with the following mblks: 15257c478bd9Sstevel@tonic-gate * T_BIND_REQ - specifying local and remote address/port 15267c478bd9Sstevel@tonic-gate * IRE_DB_REQ_TYPE - to get an IRE back containing ire_type and src 15277c478bd9Sstevel@tonic-gate * T_OK_ACK - for the T_CONN_REQ 15287c478bd9Sstevel@tonic-gate * T_CONN_CON - to keep the TPI user happy 15297c478bd9Sstevel@tonic-gate * 15307c478bd9Sstevel@tonic-gate * The connect completes in udp_rput. 15317c478bd9Sstevel@tonic-gate * When a T_BIND_ACK is received information is extracted from the IRE 15327c478bd9Sstevel@tonic-gate * and the two appended messages are sent to the TPI user. 15337c478bd9Sstevel@tonic-gate * Should udp_rput receive T_ERROR_ACK for the T_BIND_REQ it will convert 15347c478bd9Sstevel@tonic-gate * it to an error ack for the appropriate primitive. 15357c478bd9Sstevel@tonic-gate */ 15367c478bd9Sstevel@tonic-gate static void 15377c478bd9Sstevel@tonic-gate udp_connect(queue_t *q, mblk_t *mp) 15387c478bd9Sstevel@tonic-gate { 15397c478bd9Sstevel@tonic-gate sin6_t *sin6; 15407c478bd9Sstevel@tonic-gate sin_t *sin; 15417c478bd9Sstevel@tonic-gate struct T_conn_req *tcr; 15427c478bd9Sstevel@tonic-gate in6_addr_t v6dst; 15437c478bd9Sstevel@tonic-gate ipaddr_t v4dst; 15447c478bd9Sstevel@tonic-gate uint16_t dstport; 15457c478bd9Sstevel@tonic-gate uint32_t flowinfo; 15467c478bd9Sstevel@tonic-gate mblk_t *mp1, *mp2; 15477c478bd9Sstevel@tonic-gate udp_fanout_t *udpf; 1548ff550d0eSmasputra udp_t *udp, *udp1; 1549ff550d0eSmasputra 1550ff550d0eSmasputra udp = Q_TO_UDP(q); 15517c478bd9Sstevel@tonic-gate 15527c478bd9Sstevel@tonic-gate tcr = (struct T_conn_req *)mp->b_rptr; 15537c478bd9Sstevel@tonic-gate 15547c478bd9Sstevel@tonic-gate /* A bit of sanity checking */ 15557c478bd9Sstevel@tonic-gate if ((mp->b_wptr - mp->b_rptr) < sizeof (struct T_conn_req)) { 15567c478bd9Sstevel@tonic-gate udp_err_ack(q, mp, TPROTO, 0); 15577c478bd9Sstevel@tonic-gate return; 15587c478bd9Sstevel@tonic-gate } 15597c478bd9Sstevel@tonic-gate /* 15607c478bd9Sstevel@tonic-gate * This UDP must have bound to a port already before doing 15617c478bd9Sstevel@tonic-gate * a connect. 15627c478bd9Sstevel@tonic-gate */ 15637c478bd9Sstevel@tonic-gate if (udp->udp_state == TS_UNBND) { 15647c478bd9Sstevel@tonic-gate (void) mi_strlog(q, 1, SL_ERROR|SL_TRACE, 15657c478bd9Sstevel@tonic-gate "udp_connect: bad state, %u", udp->udp_state); 15667c478bd9Sstevel@tonic-gate udp_err_ack(q, mp, TOUTSTATE, 0); 15677c478bd9Sstevel@tonic-gate return; 15687c478bd9Sstevel@tonic-gate } 15697c478bd9Sstevel@tonic-gate ASSERT(udp->udp_port != 0 && udp->udp_ptpbhn != NULL); 15707c478bd9Sstevel@tonic-gate 15717c478bd9Sstevel@tonic-gate udpf = &udp_bind_fanout[UDP_BIND_HASH(udp->udp_port)]; 1572ff550d0eSmasputra 15737c478bd9Sstevel@tonic-gate if (udp->udp_state == TS_DATA_XFER) { 15747c478bd9Sstevel@tonic-gate /* Already connected - clear out state */ 15757c478bd9Sstevel@tonic-gate mutex_enter(&udpf->uf_lock); 15767c478bd9Sstevel@tonic-gate udp->udp_v6src = udp->udp_bound_v6src; 15777c478bd9Sstevel@tonic-gate udp->udp_state = TS_IDLE; 15787c478bd9Sstevel@tonic-gate mutex_exit(&udpf->uf_lock); 15797c478bd9Sstevel@tonic-gate } 15807c478bd9Sstevel@tonic-gate 15817c478bd9Sstevel@tonic-gate if (tcr->OPT_length != 0) { 15827c478bd9Sstevel@tonic-gate udp_err_ack(q, mp, TBADOPT, 0); 15837c478bd9Sstevel@tonic-gate return; 15847c478bd9Sstevel@tonic-gate } 15857c478bd9Sstevel@tonic-gate 15867c478bd9Sstevel@tonic-gate /* 15877c478bd9Sstevel@tonic-gate * Determine packet type based on type of address passed in 15887c478bd9Sstevel@tonic-gate * the request should contain an IPv4 or IPv6 address. 15897c478bd9Sstevel@tonic-gate * Make sure that address family matches the type of 15907c478bd9Sstevel@tonic-gate * family of the the address passed down 15917c478bd9Sstevel@tonic-gate */ 15927c478bd9Sstevel@tonic-gate switch (tcr->DEST_length) { 15937c478bd9Sstevel@tonic-gate default: 15947c478bd9Sstevel@tonic-gate udp_err_ack(q, mp, TBADADDR, 0); 15957c478bd9Sstevel@tonic-gate return; 15967c478bd9Sstevel@tonic-gate 15977c478bd9Sstevel@tonic-gate case sizeof (sin_t): 15987c478bd9Sstevel@tonic-gate sin = (sin_t *)mi_offset_param(mp, tcr->DEST_offset, 15997c478bd9Sstevel@tonic-gate sizeof (sin_t)); 16007c478bd9Sstevel@tonic-gate if (sin == NULL || !OK_32PTR((char *)sin)) { 16017c478bd9Sstevel@tonic-gate udp_err_ack(q, mp, TSYSERR, EINVAL); 16027c478bd9Sstevel@tonic-gate return; 16037c478bd9Sstevel@tonic-gate } 16047c478bd9Sstevel@tonic-gate if (udp->udp_family != AF_INET || 16057c478bd9Sstevel@tonic-gate sin->sin_family != AF_INET) { 16067c478bd9Sstevel@tonic-gate udp_err_ack(q, mp, TSYSERR, EAFNOSUPPORT); 16077c478bd9Sstevel@tonic-gate return; 16087c478bd9Sstevel@tonic-gate } 16097c478bd9Sstevel@tonic-gate v4dst = sin->sin_addr.s_addr; 16107c478bd9Sstevel@tonic-gate dstport = sin->sin_port; 16117c478bd9Sstevel@tonic-gate IN6_IPADDR_TO_V4MAPPED(v4dst, &v6dst); 16127c478bd9Sstevel@tonic-gate ASSERT(udp->udp_ipversion == IPV4_VERSION); 16137c478bd9Sstevel@tonic-gate udp->udp_max_hdr_len = IP_SIMPLE_HDR_LENGTH + UDPH_SIZE + 16147c478bd9Sstevel@tonic-gate udp->udp_ip_snd_options_len; 16157c478bd9Sstevel@tonic-gate break; 16167c478bd9Sstevel@tonic-gate 16177c478bd9Sstevel@tonic-gate case sizeof (sin6_t): 16187c478bd9Sstevel@tonic-gate sin6 = (sin6_t *)mi_offset_param(mp, tcr->DEST_offset, 16197c478bd9Sstevel@tonic-gate sizeof (sin6_t)); 16207c478bd9Sstevel@tonic-gate if (sin6 == NULL || !OK_32PTR((char *)sin6)) { 16217c478bd9Sstevel@tonic-gate udp_err_ack(q, mp, TSYSERR, EINVAL); 16227c478bd9Sstevel@tonic-gate return; 16237c478bd9Sstevel@tonic-gate } 16247c478bd9Sstevel@tonic-gate if (udp->udp_family != AF_INET6 || 16257c478bd9Sstevel@tonic-gate sin6->sin6_family != AF_INET6) { 16267c478bd9Sstevel@tonic-gate udp_err_ack(q, mp, TSYSERR, EAFNOSUPPORT); 16277c478bd9Sstevel@tonic-gate return; 16287c478bd9Sstevel@tonic-gate } 16297c478bd9Sstevel@tonic-gate v6dst = sin6->sin6_addr; 16307c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_V4MAPPED(&v6dst)) { 16317c478bd9Sstevel@tonic-gate IN6_V4MAPPED_TO_IPADDR(&v6dst, v4dst); 16327c478bd9Sstevel@tonic-gate udp->udp_ipversion = IPV4_VERSION; 16337c478bd9Sstevel@tonic-gate udp->udp_max_hdr_len = IP_SIMPLE_HDR_LENGTH + 16347c478bd9Sstevel@tonic-gate UDPH_SIZE + udp->udp_ip_snd_options_len; 16357c478bd9Sstevel@tonic-gate flowinfo = 0; 16367c478bd9Sstevel@tonic-gate } else { 16377c478bd9Sstevel@tonic-gate udp->udp_ipversion = IPV6_VERSION; 16387c478bd9Sstevel@tonic-gate udp->udp_max_hdr_len = udp->udp_sticky_hdrs_len; 16397c478bd9Sstevel@tonic-gate flowinfo = sin6->sin6_flowinfo; 16407c478bd9Sstevel@tonic-gate } 16417c478bd9Sstevel@tonic-gate dstport = sin6->sin6_port; 16427c478bd9Sstevel@tonic-gate break; 16437c478bd9Sstevel@tonic-gate } 16447c478bd9Sstevel@tonic-gate if (dstport == 0) { 16457c478bd9Sstevel@tonic-gate udp_err_ack(q, mp, TBADADDR, 0); 16467c478bd9Sstevel@tonic-gate return; 16477c478bd9Sstevel@tonic-gate } 16487c478bd9Sstevel@tonic-gate 16497c478bd9Sstevel@tonic-gate /* 16507c478bd9Sstevel@tonic-gate * Create a default IP header with no IP options. 16517c478bd9Sstevel@tonic-gate */ 16527c478bd9Sstevel@tonic-gate udp->udp_dstport = dstport; 16537c478bd9Sstevel@tonic-gate if (udp->udp_ipversion == IPV4_VERSION) { 16547c478bd9Sstevel@tonic-gate /* 16557c478bd9Sstevel@tonic-gate * Interpret a zero destination to mean loopback. 16567c478bd9Sstevel@tonic-gate * Update the T_CONN_REQ (sin/sin6) since it is used to 16577c478bd9Sstevel@tonic-gate * generate the T_CONN_CON. 16587c478bd9Sstevel@tonic-gate */ 16597c478bd9Sstevel@tonic-gate if (v4dst == INADDR_ANY) { 16607c478bd9Sstevel@tonic-gate v4dst = htonl(INADDR_LOOPBACK); 16617c478bd9Sstevel@tonic-gate IN6_IPADDR_TO_V4MAPPED(v4dst, &v6dst); 16627c478bd9Sstevel@tonic-gate if (udp->udp_family == AF_INET) { 16637c478bd9Sstevel@tonic-gate sin->sin_addr.s_addr = v4dst; 16647c478bd9Sstevel@tonic-gate } else { 16657c478bd9Sstevel@tonic-gate sin6->sin6_addr = v6dst; 16667c478bd9Sstevel@tonic-gate } 16677c478bd9Sstevel@tonic-gate } 16687c478bd9Sstevel@tonic-gate udp->udp_v6dst = v6dst; 16697c478bd9Sstevel@tonic-gate udp->udp_flowinfo = 0; 16707c478bd9Sstevel@tonic-gate 16717c478bd9Sstevel@tonic-gate /* 16727c478bd9Sstevel@tonic-gate * If the destination address is multicast and 16737c478bd9Sstevel@tonic-gate * an outgoing multicast interface has been set, 16747c478bd9Sstevel@tonic-gate * use the address of that interface as our 16757c478bd9Sstevel@tonic-gate * source address if no source address has been set. 16767c478bd9Sstevel@tonic-gate */ 16777c478bd9Sstevel@tonic-gate if (V4_PART_OF_V6(udp->udp_v6src) == INADDR_ANY && 16787c478bd9Sstevel@tonic-gate CLASSD(v4dst) && 16797c478bd9Sstevel@tonic-gate udp->udp_multicast_if_addr != INADDR_ANY) { 16807c478bd9Sstevel@tonic-gate IN6_IPADDR_TO_V4MAPPED(udp->udp_multicast_if_addr, 16817c478bd9Sstevel@tonic-gate &udp->udp_v6src); 16827c478bd9Sstevel@tonic-gate } 16837c478bd9Sstevel@tonic-gate } else { 16847c478bd9Sstevel@tonic-gate ASSERT(udp->udp_ipversion == IPV6_VERSION); 16857c478bd9Sstevel@tonic-gate /* 16867c478bd9Sstevel@tonic-gate * Interpret a zero destination to mean loopback. 16877c478bd9Sstevel@tonic-gate * Update the T_CONN_REQ (sin/sin6) since it is used to 16887c478bd9Sstevel@tonic-gate * generate the T_CONN_CON. 16897c478bd9Sstevel@tonic-gate */ 16907c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_UNSPECIFIED(&v6dst)) { 16917c478bd9Sstevel@tonic-gate v6dst = ipv6_loopback; 16927c478bd9Sstevel@tonic-gate sin6->sin6_addr = v6dst; 16937c478bd9Sstevel@tonic-gate } 16947c478bd9Sstevel@tonic-gate udp->udp_v6dst = v6dst; 16957c478bd9Sstevel@tonic-gate udp->udp_flowinfo = flowinfo; 16967c478bd9Sstevel@tonic-gate /* 16977c478bd9Sstevel@tonic-gate * If the destination address is multicast and 16987c478bd9Sstevel@tonic-gate * an outgoing multicast interface has been set, 16997c478bd9Sstevel@tonic-gate * then the ip bind logic will pick the correct source 17007c478bd9Sstevel@tonic-gate * address (i.e. matching the outgoing multicast interface). 17017c478bd9Sstevel@tonic-gate */ 17027c478bd9Sstevel@tonic-gate } 17037c478bd9Sstevel@tonic-gate 17047c478bd9Sstevel@tonic-gate /* 17057c478bd9Sstevel@tonic-gate * Verify that the src/port/dst/port is unique for all 17067c478bd9Sstevel@tonic-gate * connections in TS_DATA_XFER 17077c478bd9Sstevel@tonic-gate */ 17087c478bd9Sstevel@tonic-gate mutex_enter(&udpf->uf_lock); 17097c478bd9Sstevel@tonic-gate for (udp1 = udpf->uf_udp; udp1 != NULL; udp1 = udp1->udp_bind_hash) { 17107c478bd9Sstevel@tonic-gate if (udp1->udp_state != TS_DATA_XFER) 17117c478bd9Sstevel@tonic-gate continue; 17127c478bd9Sstevel@tonic-gate if (udp->udp_port != udp1->udp_port || 17137c478bd9Sstevel@tonic-gate udp->udp_ipversion != udp1->udp_ipversion || 17147c478bd9Sstevel@tonic-gate dstport != udp1->udp_dstport || 17157c478bd9Sstevel@tonic-gate !IN6_ARE_ADDR_EQUAL(&udp->udp_v6src, &udp1->udp_v6src) || 17167c478bd9Sstevel@tonic-gate !IN6_ARE_ADDR_EQUAL(&v6dst, &udp1->udp_v6dst)) 17177c478bd9Sstevel@tonic-gate continue; 17187c478bd9Sstevel@tonic-gate mutex_exit(&udpf->uf_lock); 17197c478bd9Sstevel@tonic-gate udp_err_ack(q, mp, TBADADDR, 0); 17207c478bd9Sstevel@tonic-gate return; 17217c478bd9Sstevel@tonic-gate } 17227c478bd9Sstevel@tonic-gate udp->udp_state = TS_DATA_XFER; 17237c478bd9Sstevel@tonic-gate mutex_exit(&udpf->uf_lock); 17247c478bd9Sstevel@tonic-gate 17257c478bd9Sstevel@tonic-gate /* 17267c478bd9Sstevel@tonic-gate * Send down bind to IP to verify that there is a route 17277c478bd9Sstevel@tonic-gate * and to determine the source address. 17287c478bd9Sstevel@tonic-gate * This will come back as T_BIND_ACK with an IRE_DB_TYPE in rput. 17297c478bd9Sstevel@tonic-gate */ 17307c478bd9Sstevel@tonic-gate if (udp->udp_family == AF_INET) 17317c478bd9Sstevel@tonic-gate mp1 = udp_ip_bind_mp(udp, O_T_BIND_REQ, sizeof (ipa_conn_t)); 17327c478bd9Sstevel@tonic-gate else 17337c478bd9Sstevel@tonic-gate mp1 = udp_ip_bind_mp(udp, O_T_BIND_REQ, sizeof (ipa6_conn_t)); 17347c478bd9Sstevel@tonic-gate if (mp1 == NULL) { 17357c478bd9Sstevel@tonic-gate udp_err_ack(q, mp, TSYSERR, ENOMEM); 17367c478bd9Sstevel@tonic-gate bind_failed: 17377c478bd9Sstevel@tonic-gate mutex_enter(&udpf->uf_lock); 17387c478bd9Sstevel@tonic-gate udp->udp_state = TS_IDLE; 17397c478bd9Sstevel@tonic-gate mutex_exit(&udpf->uf_lock); 17407c478bd9Sstevel@tonic-gate return; 17417c478bd9Sstevel@tonic-gate } 17427c478bd9Sstevel@tonic-gate 17437c478bd9Sstevel@tonic-gate /* 17447c478bd9Sstevel@tonic-gate * We also have to send a connection confirmation to 17457c478bd9Sstevel@tonic-gate * keep TLI happy. Prepare it for udp_rput. 17467c478bd9Sstevel@tonic-gate */ 17477c478bd9Sstevel@tonic-gate if (udp->udp_family == AF_INET) 17487c478bd9Sstevel@tonic-gate mp2 = mi_tpi_conn_con(NULL, (char *)sin, 17497c478bd9Sstevel@tonic-gate sizeof (*sin), NULL, 0); 17507c478bd9Sstevel@tonic-gate else 17517c478bd9Sstevel@tonic-gate mp2 = mi_tpi_conn_con(NULL, (char *)sin6, 17527c478bd9Sstevel@tonic-gate sizeof (*sin6), NULL, 0); 17537c478bd9Sstevel@tonic-gate if (mp2 == NULL) { 17547c478bd9Sstevel@tonic-gate freemsg(mp1); 17557c478bd9Sstevel@tonic-gate udp_err_ack(q, mp, TSYSERR, ENOMEM); 17567c478bd9Sstevel@tonic-gate goto bind_failed; 17577c478bd9Sstevel@tonic-gate } 17587c478bd9Sstevel@tonic-gate 17597c478bd9Sstevel@tonic-gate mp = mi_tpi_ok_ack_alloc(mp); 17607c478bd9Sstevel@tonic-gate if (mp == NULL) { 17617c478bd9Sstevel@tonic-gate /* Unable to reuse the T_CONN_REQ for the ack. */ 17627c478bd9Sstevel@tonic-gate freemsg(mp2); 17637c478bd9Sstevel@tonic-gate udp_err_ack_prim(q, mp1, T_CONN_REQ, TSYSERR, ENOMEM); 17647c478bd9Sstevel@tonic-gate goto bind_failed; 17657c478bd9Sstevel@tonic-gate } 17667c478bd9Sstevel@tonic-gate 17677c478bd9Sstevel@tonic-gate /* Hang onto the T_OK_ACK and T_CONN_CON for later. */ 17687c478bd9Sstevel@tonic-gate linkb(mp1, mp); 17697c478bd9Sstevel@tonic-gate linkb(mp1, mp2); 17707c478bd9Sstevel@tonic-gate 1771ff550d0eSmasputra if (udp->udp_family == AF_INET) 1772ff550d0eSmasputra mp1 = ip_bind_v4(q, mp1, udp->udp_connp); 1773ff550d0eSmasputra else 1774ff550d0eSmasputra mp1 = ip_bind_v6(q, mp1, udp->udp_connp, NULL); 1775ff550d0eSmasputra 1776ff550d0eSmasputra if (mp1 != NULL) 1777ff550d0eSmasputra udp_rput_other(_RD(q), mp1); 1778ff550d0eSmasputra else 1779ff550d0eSmasputra CONN_INC_REF(udp->udp_connp); 17807c478bd9Sstevel@tonic-gate } 17817c478bd9Sstevel@tonic-gate 17827c478bd9Sstevel@tonic-gate static int 17837c478bd9Sstevel@tonic-gate udp_close(queue_t *q) 17847c478bd9Sstevel@tonic-gate { 1785ff550d0eSmasputra conn_t *connp = Q_TO_CONN(UDP_WR(q)); 1786ff550d0eSmasputra udp_t *udp; 1787ff550d0eSmasputra queue_t *ip_rq = RD(UDP_WR(q)); 17887c478bd9Sstevel@tonic-gate 1789ff550d0eSmasputra ASSERT(connp != NULL && IPCL_IS_UDP(connp)); 1790ff550d0eSmasputra udp = connp->conn_udp; 1791ff550d0eSmasputra 1792ff550d0eSmasputra ip_quiesce_conn(connp); 1793ff550d0eSmasputra /* 1794ff550d0eSmasputra * Disable read-side synchronous stream 1795ff550d0eSmasputra * interface and drain any queued data. 1796ff550d0eSmasputra */ 1797ff550d0eSmasputra udp_rcv_drain(q, udp, B_TRUE); 1798ff550d0eSmasputra ASSERT(!udp->udp_direct_sockfs); 17997c478bd9Sstevel@tonic-gate 18007c478bd9Sstevel@tonic-gate qprocsoff(q); 18017c478bd9Sstevel@tonic-gate 1802ff550d0eSmasputra /* restore IP module's high and low water marks to default values */ 1803ff550d0eSmasputra ip_rq->q_hiwat = ip_rq->q_qinfo->qi_minfo->mi_hiwat; 1804ff550d0eSmasputra WR(ip_rq)->q_hiwat = WR(ip_rq)->q_qinfo->qi_minfo->mi_hiwat; 1805ff550d0eSmasputra WR(ip_rq)->q_lowat = WR(ip_rq)->q_qinfo->qi_minfo->mi_lowat; 1806ff550d0eSmasputra 1807ff550d0eSmasputra ASSERT(udp->udp_rcv_cnt == 0); 1808ff550d0eSmasputra ASSERT(udp->udp_rcv_msgcnt == 0); 1809ff550d0eSmasputra ASSERT(udp->udp_rcv_list_head == NULL); 1810ff550d0eSmasputra ASSERT(udp->udp_rcv_list_tail == NULL); 1811ff550d0eSmasputra 1812ff550d0eSmasputra /* connp is now single threaded. */ 1813ff550d0eSmasputra udp_close_free(connp); 1814ff550d0eSmasputra /* 1815ff550d0eSmasputra * Restore connp as an IP endpoint. We don't need 1816ff550d0eSmasputra * any locks since we are now single threaded 1817ff550d0eSmasputra */ 1818ff550d0eSmasputra connp->conn_flags &= ~IPCL_UDP; 1819ff550d0eSmasputra connp->conn_state_flags &= 1820ff550d0eSmasputra ~(CONN_CLOSING | CONN_CONDEMNED | CONN_QUIESCED); 1821ff550d0eSmasputra return (0); 1822ff550d0eSmasputra } 1823ff550d0eSmasputra 1824ff550d0eSmasputra /* 1825ff550d0eSmasputra * Called in the close path from IP (ip_quiesce_conn) to quiesce the conn 1826ff550d0eSmasputra */ 1827ff550d0eSmasputra void 1828ff550d0eSmasputra udp_quiesce_conn(conn_t *connp) 1829ff550d0eSmasputra { 1830ff550d0eSmasputra udp_t *udp = connp->conn_udp; 1831ff550d0eSmasputra 18327c478bd9Sstevel@tonic-gate if (cl_inet_unbind != NULL && udp->udp_state == TS_IDLE) { 18337c478bd9Sstevel@tonic-gate /* 18347c478bd9Sstevel@tonic-gate * Running in cluster mode - register unbind information 18357c478bd9Sstevel@tonic-gate */ 18367c478bd9Sstevel@tonic-gate if (udp->udp_ipversion == IPV4_VERSION) { 18377c478bd9Sstevel@tonic-gate (*cl_inet_unbind)(IPPROTO_UDP, AF_INET, 18387c478bd9Sstevel@tonic-gate (uint8_t *)(&(V4_PART_OF_V6(udp->udp_v6src))), 18397c478bd9Sstevel@tonic-gate (in_port_t)udp->udp_port); 18407c478bd9Sstevel@tonic-gate } else { 18417c478bd9Sstevel@tonic-gate (*cl_inet_unbind)(IPPROTO_UDP, AF_INET6, 18427c478bd9Sstevel@tonic-gate (uint8_t *)(&(udp->udp_v6src)), 18437c478bd9Sstevel@tonic-gate (in_port_t)udp->udp_port); 18447c478bd9Sstevel@tonic-gate } 18457c478bd9Sstevel@tonic-gate } 18467c478bd9Sstevel@tonic-gate 18477c478bd9Sstevel@tonic-gate udp_bind_hash_remove(udp, B_FALSE); 1848ff550d0eSmasputra 1849ff550d0eSmasputra mutex_enter(&connp->conn_lock); 1850ff550d0eSmasputra while (udp->udp_reader_count != 0 || udp->udp_squeue_count != 0 || 1851ff550d0eSmasputra udp->udp_mode != UDP_MT_HOT) { 1852ff550d0eSmasputra cv_wait(&connp->conn_cv, &connp->conn_lock); 1853ff550d0eSmasputra } 1854ff550d0eSmasputra mutex_exit(&connp->conn_lock); 1855ff550d0eSmasputra } 1856ff550d0eSmasputra 1857ff550d0eSmasputra void 1858ff550d0eSmasputra udp_close_free(conn_t *connp) 1859ff550d0eSmasputra { 1860ff550d0eSmasputra udp_t *udp = connp->conn_udp; 1861ff550d0eSmasputra 18627c478bd9Sstevel@tonic-gate /* If there are any options associated with the stream, free them. */ 1863ff550d0eSmasputra if (udp->udp_ip_snd_options) { 18647c478bd9Sstevel@tonic-gate mi_free((char *)udp->udp_ip_snd_options); 1865ff550d0eSmasputra udp->udp_ip_snd_options = NULL; 1866ff550d0eSmasputra } 18677c478bd9Sstevel@tonic-gate 1868ff550d0eSmasputra if (udp->udp_ip_rcv_options) { 18697c478bd9Sstevel@tonic-gate mi_free((char *)udp->udp_ip_rcv_options); 1870ff550d0eSmasputra udp->udp_ip_rcv_options = NULL; 1871ff550d0eSmasputra } 18727c478bd9Sstevel@tonic-gate 18737c478bd9Sstevel@tonic-gate /* Free memory associated with sticky options */ 18747c478bd9Sstevel@tonic-gate if (udp->udp_sticky_hdrs_len != 0) { 18757c478bd9Sstevel@tonic-gate kmem_free(udp->udp_sticky_hdrs, 18767c478bd9Sstevel@tonic-gate udp->udp_sticky_hdrs_len); 18777c478bd9Sstevel@tonic-gate udp->udp_sticky_hdrs = NULL; 18787c478bd9Sstevel@tonic-gate udp->udp_sticky_hdrs_len = 0; 18797c478bd9Sstevel@tonic-gate } 1880ff550d0eSmasputra 18817c478bd9Sstevel@tonic-gate if (udp->udp_sticky_ipp.ipp_fields & IPPF_HOPOPTS) { 18827c478bd9Sstevel@tonic-gate kmem_free(udp->udp_sticky_ipp.ipp_hopopts, 18837c478bd9Sstevel@tonic-gate udp->udp_sticky_ipp.ipp_hopoptslen); 1884ff550d0eSmasputra udp->udp_sticky_ipp.ipp_hopopts = NULL; 18857c478bd9Sstevel@tonic-gate } 18867c478bd9Sstevel@tonic-gate if (udp->udp_sticky_ipp.ipp_fields & IPPF_RTDSTOPTS) { 18877c478bd9Sstevel@tonic-gate kmem_free(udp->udp_sticky_ipp.ipp_rtdstopts, 18887c478bd9Sstevel@tonic-gate udp->udp_sticky_ipp.ipp_rtdstoptslen); 1889ff550d0eSmasputra udp->udp_sticky_ipp.ipp_rtdstopts = NULL; 18907c478bd9Sstevel@tonic-gate } 18917c478bd9Sstevel@tonic-gate if (udp->udp_sticky_ipp.ipp_fields & IPPF_RTHDR) { 18927c478bd9Sstevel@tonic-gate kmem_free(udp->udp_sticky_ipp.ipp_rthdr, 18937c478bd9Sstevel@tonic-gate udp->udp_sticky_ipp.ipp_rthdrlen); 1894ff550d0eSmasputra udp->udp_sticky_ipp.ipp_rthdr = NULL; 18957c478bd9Sstevel@tonic-gate } 18967c478bd9Sstevel@tonic-gate if (udp->udp_sticky_ipp.ipp_fields & IPPF_DSTOPTS) { 18977c478bd9Sstevel@tonic-gate kmem_free(udp->udp_sticky_ipp.ipp_dstopts, 18987c478bd9Sstevel@tonic-gate udp->udp_sticky_ipp.ipp_dstoptslen); 1899ff550d0eSmasputra udp->udp_sticky_ipp.ipp_dstopts = NULL; 19007c478bd9Sstevel@tonic-gate } 19017c478bd9Sstevel@tonic-gate udp->udp_sticky_ipp.ipp_fields &= 19027c478bd9Sstevel@tonic-gate ~(IPPF_HOPOPTS|IPPF_RTDSTOPTS|IPPF_RTHDR|IPPF_DSTOPTS); 19037c478bd9Sstevel@tonic-gate 1904ff550d0eSmasputra udp->udp_connp = NULL; 1905ff550d0eSmasputra connp->conn_udp = NULL; 1906ff550d0eSmasputra kmem_cache_free(udp_cache, udp); 19077c478bd9Sstevel@tonic-gate } 19087c478bd9Sstevel@tonic-gate 19097c478bd9Sstevel@tonic-gate /* 19107c478bd9Sstevel@tonic-gate * This routine handles each T_DISCON_REQ message passed to udp 19117c478bd9Sstevel@tonic-gate * as an indicating that UDP is no longer connected. This results 19127c478bd9Sstevel@tonic-gate * in sending a T_BIND_REQ to IP to restore the binding to just 19137c478bd9Sstevel@tonic-gate * the local address/port. 19147c478bd9Sstevel@tonic-gate * 19157c478bd9Sstevel@tonic-gate * This routine sends down a T_BIND_REQ to IP with the following mblks: 19167c478bd9Sstevel@tonic-gate * T_BIND_REQ - specifying just the local address/port 19177c478bd9Sstevel@tonic-gate * T_OK_ACK - for the T_DISCON_REQ 19187c478bd9Sstevel@tonic-gate * 19197c478bd9Sstevel@tonic-gate * The disconnect completes in udp_rput. 19207c478bd9Sstevel@tonic-gate * When a T_BIND_ACK is received the appended T_OK_ACK is sent to the TPI user. 19217c478bd9Sstevel@tonic-gate * Should udp_rput receive T_ERROR_ACK for the T_BIND_REQ it will convert 19227c478bd9Sstevel@tonic-gate * it to an error ack for the appropriate primitive. 19237c478bd9Sstevel@tonic-gate */ 19247c478bd9Sstevel@tonic-gate static void 19257c478bd9Sstevel@tonic-gate udp_disconnect(queue_t *q, mblk_t *mp) 19267c478bd9Sstevel@tonic-gate { 1927ff550d0eSmasputra udp_t *udp = Q_TO_UDP(q); 19287c478bd9Sstevel@tonic-gate mblk_t *mp1; 19297c478bd9Sstevel@tonic-gate udp_fanout_t *udpf; 19307c478bd9Sstevel@tonic-gate 19317c478bd9Sstevel@tonic-gate if (udp->udp_state != TS_DATA_XFER) { 19327c478bd9Sstevel@tonic-gate (void) mi_strlog(q, 1, SL_ERROR|SL_TRACE, 19337c478bd9Sstevel@tonic-gate "udp_disconnect: bad state, %u", udp->udp_state); 19347c478bd9Sstevel@tonic-gate udp_err_ack(q, mp, TOUTSTATE, 0); 19357c478bd9Sstevel@tonic-gate return; 19367c478bd9Sstevel@tonic-gate } 19377c478bd9Sstevel@tonic-gate udpf = &udp_bind_fanout[UDP_BIND_HASH(udp->udp_port)]; 19387c478bd9Sstevel@tonic-gate mutex_enter(&udpf->uf_lock); 19397c478bd9Sstevel@tonic-gate udp->udp_v6src = udp->udp_bound_v6src; 19407c478bd9Sstevel@tonic-gate udp->udp_state = TS_IDLE; 19417c478bd9Sstevel@tonic-gate mutex_exit(&udpf->uf_lock); 19427c478bd9Sstevel@tonic-gate 19437c478bd9Sstevel@tonic-gate /* 19447c478bd9Sstevel@tonic-gate * Send down bind to IP to remove the full binding and revert 19457c478bd9Sstevel@tonic-gate * to the local address binding. 19467c478bd9Sstevel@tonic-gate */ 19477c478bd9Sstevel@tonic-gate if (udp->udp_family == AF_INET) 19487c478bd9Sstevel@tonic-gate mp1 = udp_ip_bind_mp(udp, O_T_BIND_REQ, sizeof (sin_t)); 19497c478bd9Sstevel@tonic-gate else 19507c478bd9Sstevel@tonic-gate mp1 = udp_ip_bind_mp(udp, O_T_BIND_REQ, sizeof (sin6_t)); 19517c478bd9Sstevel@tonic-gate if (mp1 == NULL) { 19527c478bd9Sstevel@tonic-gate udp_err_ack(q, mp, TSYSERR, ENOMEM); 19537c478bd9Sstevel@tonic-gate return; 19547c478bd9Sstevel@tonic-gate } 19557c478bd9Sstevel@tonic-gate mp = mi_tpi_ok_ack_alloc(mp); 19567c478bd9Sstevel@tonic-gate if (mp == NULL) { 19577c478bd9Sstevel@tonic-gate /* Unable to reuse the T_DISCON_REQ for the ack. */ 19587c478bd9Sstevel@tonic-gate udp_err_ack_prim(q, mp1, T_DISCON_REQ, TSYSERR, ENOMEM); 19597c478bd9Sstevel@tonic-gate return; 19607c478bd9Sstevel@tonic-gate } 19617c478bd9Sstevel@tonic-gate 19627c478bd9Sstevel@tonic-gate if (udp->udp_family == AF_INET6) { 19637c478bd9Sstevel@tonic-gate int error; 19647c478bd9Sstevel@tonic-gate 19657c478bd9Sstevel@tonic-gate /* Rebuild the header template */ 19667c478bd9Sstevel@tonic-gate error = udp_build_hdrs(q, udp); 19677c478bd9Sstevel@tonic-gate if (error != 0) { 19687c478bd9Sstevel@tonic-gate udp_err_ack_prim(q, mp, T_DISCON_REQ, TSYSERR, error); 19697c478bd9Sstevel@tonic-gate freemsg(mp1); 19707c478bd9Sstevel@tonic-gate return; 19717c478bd9Sstevel@tonic-gate } 19727c478bd9Sstevel@tonic-gate } 19737c478bd9Sstevel@tonic-gate mutex_enter(&udpf->uf_lock); 19747c478bd9Sstevel@tonic-gate udp->udp_discon_pending = 1; 19757c478bd9Sstevel@tonic-gate mutex_exit(&udpf->uf_lock); 19767c478bd9Sstevel@tonic-gate 19777c478bd9Sstevel@tonic-gate /* Append the T_OK_ACK to the T_BIND_REQ for udp_rput */ 19787c478bd9Sstevel@tonic-gate linkb(mp1, mp); 1979ff550d0eSmasputra 1980ff550d0eSmasputra if (udp->udp_family == AF_INET6) 1981ff550d0eSmasputra mp1 = ip_bind_v6(q, mp1, udp->udp_connp, NULL); 1982ff550d0eSmasputra else 1983ff550d0eSmasputra mp1 = ip_bind_v4(q, mp1, udp->udp_connp); 1984ff550d0eSmasputra 1985ff550d0eSmasputra if (mp1 != NULL) 1986ff550d0eSmasputra udp_rput_other(_RD(q), mp1); 1987ff550d0eSmasputra else 1988ff550d0eSmasputra CONN_INC_REF(udp->udp_connp); 19897c478bd9Sstevel@tonic-gate } 19907c478bd9Sstevel@tonic-gate 19917c478bd9Sstevel@tonic-gate /* This routine creates a T_ERROR_ACK message and passes it upstream. */ 19927c478bd9Sstevel@tonic-gate static void 19937c478bd9Sstevel@tonic-gate udp_err_ack(queue_t *q, mblk_t *mp, t_scalar_t t_error, int sys_error) 19947c478bd9Sstevel@tonic-gate { 19957c478bd9Sstevel@tonic-gate if ((mp = mi_tpi_err_ack_alloc(mp, t_error, sys_error)) != NULL) 1996ff550d0eSmasputra putnext(UDP_RD(q), mp); 19977c478bd9Sstevel@tonic-gate } 19987c478bd9Sstevel@tonic-gate 19997c478bd9Sstevel@tonic-gate /* Shorthand to generate and send TPI error acks to our client */ 20007c478bd9Sstevel@tonic-gate static void 20017c478bd9Sstevel@tonic-gate udp_err_ack_prim(queue_t *q, mblk_t *mp, int primitive, t_scalar_t t_error, 20027c478bd9Sstevel@tonic-gate int sys_error) 20037c478bd9Sstevel@tonic-gate { 20047c478bd9Sstevel@tonic-gate struct T_error_ack *teackp; 20057c478bd9Sstevel@tonic-gate 20067c478bd9Sstevel@tonic-gate if ((mp = tpi_ack_alloc(mp, sizeof (struct T_error_ack), 20077c478bd9Sstevel@tonic-gate M_PCPROTO, T_ERROR_ACK)) != NULL) { 20087c478bd9Sstevel@tonic-gate teackp = (struct T_error_ack *)mp->b_rptr; 20097c478bd9Sstevel@tonic-gate teackp->ERROR_prim = primitive; 20107c478bd9Sstevel@tonic-gate teackp->TLI_error = t_error; 20117c478bd9Sstevel@tonic-gate teackp->UNIX_error = sys_error; 2012ff550d0eSmasputra putnext(UDP_RD(q), mp); 20137c478bd9Sstevel@tonic-gate } 20147c478bd9Sstevel@tonic-gate } 20157c478bd9Sstevel@tonic-gate 20167c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 20177c478bd9Sstevel@tonic-gate static int 20187c478bd9Sstevel@tonic-gate udp_extra_priv_ports_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *cr) 20197c478bd9Sstevel@tonic-gate { 20207c478bd9Sstevel@tonic-gate int i; 20217c478bd9Sstevel@tonic-gate 20227c478bd9Sstevel@tonic-gate for (i = 0; i < udp_g_num_epriv_ports; i++) { 20237c478bd9Sstevel@tonic-gate if (udp_g_epriv_ports[i] != 0) 20247c478bd9Sstevel@tonic-gate (void) mi_mpprintf(mp, "%d ", udp_g_epriv_ports[i]); 20257c478bd9Sstevel@tonic-gate } 20267c478bd9Sstevel@tonic-gate return (0); 20277c478bd9Sstevel@tonic-gate } 20287c478bd9Sstevel@tonic-gate 20297c478bd9Sstevel@tonic-gate /* ARGSUSED */ 20307c478bd9Sstevel@tonic-gate static int 20317c478bd9Sstevel@tonic-gate udp_extra_priv_ports_add(queue_t *q, mblk_t *mp, char *value, caddr_t cp, 20327c478bd9Sstevel@tonic-gate cred_t *cr) 20337c478bd9Sstevel@tonic-gate { 20347c478bd9Sstevel@tonic-gate long new_value; 20357c478bd9Sstevel@tonic-gate int i; 20367c478bd9Sstevel@tonic-gate 20377c478bd9Sstevel@tonic-gate /* 20387c478bd9Sstevel@tonic-gate * Fail the request if the new value does not lie within the 20397c478bd9Sstevel@tonic-gate * port number limits. 20407c478bd9Sstevel@tonic-gate */ 20417c478bd9Sstevel@tonic-gate if (ddi_strtol(value, NULL, 10, &new_value) != 0 || 20427c478bd9Sstevel@tonic-gate new_value <= 0 || new_value >= 65536) { 20437c478bd9Sstevel@tonic-gate return (EINVAL); 20447c478bd9Sstevel@tonic-gate } 20457c478bd9Sstevel@tonic-gate 20467c478bd9Sstevel@tonic-gate /* Check if the value is already in the list */ 20477c478bd9Sstevel@tonic-gate for (i = 0; i < udp_g_num_epriv_ports; i++) { 20487c478bd9Sstevel@tonic-gate if (new_value == udp_g_epriv_ports[i]) { 20497c478bd9Sstevel@tonic-gate return (EEXIST); 20507c478bd9Sstevel@tonic-gate } 20517c478bd9Sstevel@tonic-gate } 20527c478bd9Sstevel@tonic-gate /* Find an empty slot */ 20537c478bd9Sstevel@tonic-gate for (i = 0; i < udp_g_num_epriv_ports; i++) { 20547c478bd9Sstevel@tonic-gate if (udp_g_epriv_ports[i] == 0) 20557c478bd9Sstevel@tonic-gate break; 20567c478bd9Sstevel@tonic-gate } 20577c478bd9Sstevel@tonic-gate if (i == udp_g_num_epriv_ports) { 20587c478bd9Sstevel@tonic-gate return (EOVERFLOW); 20597c478bd9Sstevel@tonic-gate } 20607c478bd9Sstevel@tonic-gate 20617c478bd9Sstevel@tonic-gate /* Set the new value */ 20627c478bd9Sstevel@tonic-gate udp_g_epriv_ports[i] = (in_port_t)new_value; 20637c478bd9Sstevel@tonic-gate return (0); 20647c478bd9Sstevel@tonic-gate } 20657c478bd9Sstevel@tonic-gate 20667c478bd9Sstevel@tonic-gate /* ARGSUSED */ 20677c478bd9Sstevel@tonic-gate static int 20687c478bd9Sstevel@tonic-gate udp_extra_priv_ports_del(queue_t *q, mblk_t *mp, char *value, caddr_t cp, 20697c478bd9Sstevel@tonic-gate cred_t *cr) 20707c478bd9Sstevel@tonic-gate { 20717c478bd9Sstevel@tonic-gate long new_value; 20727c478bd9Sstevel@tonic-gate int i; 20737c478bd9Sstevel@tonic-gate 20747c478bd9Sstevel@tonic-gate /* 20757c478bd9Sstevel@tonic-gate * Fail the request if the new value does not lie within the 20767c478bd9Sstevel@tonic-gate * port number limits. 20777c478bd9Sstevel@tonic-gate */ 20787c478bd9Sstevel@tonic-gate if (ddi_strtol(value, NULL, 10, &new_value) != 0 || 20797c478bd9Sstevel@tonic-gate new_value <= 0 || new_value >= 65536) { 20807c478bd9Sstevel@tonic-gate return (EINVAL); 20817c478bd9Sstevel@tonic-gate } 20827c478bd9Sstevel@tonic-gate 20837c478bd9Sstevel@tonic-gate /* Check that the value is already in the list */ 20847c478bd9Sstevel@tonic-gate for (i = 0; i < udp_g_num_epriv_ports; i++) { 20857c478bd9Sstevel@tonic-gate if (udp_g_epriv_ports[i] == new_value) 20867c478bd9Sstevel@tonic-gate break; 20877c478bd9Sstevel@tonic-gate } 20887c478bd9Sstevel@tonic-gate if (i == udp_g_num_epriv_ports) { 20897c478bd9Sstevel@tonic-gate return (ESRCH); 20907c478bd9Sstevel@tonic-gate } 20917c478bd9Sstevel@tonic-gate 20927c478bd9Sstevel@tonic-gate /* Clear the value */ 20937c478bd9Sstevel@tonic-gate udp_g_epriv_ports[i] = 0; 20947c478bd9Sstevel@tonic-gate return (0); 20957c478bd9Sstevel@tonic-gate } 20967c478bd9Sstevel@tonic-gate 20977c478bd9Sstevel@tonic-gate /* At minimum we need 4 bytes of UDP header */ 20987c478bd9Sstevel@tonic-gate #define ICMP_MIN_UDP_HDR 4 20997c478bd9Sstevel@tonic-gate 21007c478bd9Sstevel@tonic-gate /* 21017c478bd9Sstevel@tonic-gate * udp_icmp_error is called by udp_rput to process ICMP msgs. passed up by IP. 21027c478bd9Sstevel@tonic-gate * Generates the appropriate T_UDERROR_IND for permanent (non-transient) errors. 21037c478bd9Sstevel@tonic-gate * Assumes that IP has pulled up everything up to and including the ICMP header. 21047c478bd9Sstevel@tonic-gate * An M_CTL could potentially come here from some other module (i.e. if UDP 21057c478bd9Sstevel@tonic-gate * is pushed on some module other than IP). Thus, if we find that the M_CTL 21067c478bd9Sstevel@tonic-gate * does not have enough ICMP information , following STREAMS conventions, 21077c478bd9Sstevel@tonic-gate * we send it upstream assuming it is an M_CTL we don't understand. 21087c478bd9Sstevel@tonic-gate */ 21097c478bd9Sstevel@tonic-gate static void 21107c478bd9Sstevel@tonic-gate udp_icmp_error(queue_t *q, mblk_t *mp) 21117c478bd9Sstevel@tonic-gate { 21127c478bd9Sstevel@tonic-gate icmph_t *icmph; 21137c478bd9Sstevel@tonic-gate ipha_t *ipha; 21147c478bd9Sstevel@tonic-gate int iph_hdr_length; 21157c478bd9Sstevel@tonic-gate udpha_t *udpha; 21167c478bd9Sstevel@tonic-gate sin_t sin; 21177c478bd9Sstevel@tonic-gate sin6_t sin6; 21187c478bd9Sstevel@tonic-gate mblk_t *mp1; 21197c478bd9Sstevel@tonic-gate int error = 0; 21207c478bd9Sstevel@tonic-gate size_t mp_size = MBLKL(mp); 2121ff550d0eSmasputra udp_t *udp = Q_TO_UDP(q); 21227c478bd9Sstevel@tonic-gate 21237c478bd9Sstevel@tonic-gate /* 21247c478bd9Sstevel@tonic-gate * Assume IP provides aligned packets - otherwise toss 21257c478bd9Sstevel@tonic-gate */ 21267c478bd9Sstevel@tonic-gate if (!OK_32PTR(mp->b_rptr)) { 21277c478bd9Sstevel@tonic-gate freemsg(mp); 21287c478bd9Sstevel@tonic-gate return; 21297c478bd9Sstevel@tonic-gate } 21307c478bd9Sstevel@tonic-gate 21317c478bd9Sstevel@tonic-gate /* 21327c478bd9Sstevel@tonic-gate * Verify that we have a complete IP header and the application has 21337c478bd9Sstevel@tonic-gate * asked for errors. If not, send it upstream. 21347c478bd9Sstevel@tonic-gate */ 21357c478bd9Sstevel@tonic-gate if (!udp->udp_dgram_errind || mp_size < sizeof (ipha_t)) { 21367c478bd9Sstevel@tonic-gate noticmpv4: 2137ff550d0eSmasputra putnext(UDP_RD(q), mp); 21387c478bd9Sstevel@tonic-gate return; 21397c478bd9Sstevel@tonic-gate } 21407c478bd9Sstevel@tonic-gate 21417c478bd9Sstevel@tonic-gate ipha = (ipha_t *)mp->b_rptr; 21427c478bd9Sstevel@tonic-gate /* 21437c478bd9Sstevel@tonic-gate * Verify IP version. Anything other than IPv4 or IPv6 packet is sent 21447c478bd9Sstevel@tonic-gate * upstream. ICMPv6 is handled in udp_icmp_error_ipv6. 21457c478bd9Sstevel@tonic-gate */ 21467c478bd9Sstevel@tonic-gate switch (IPH_HDR_VERSION(ipha)) { 21477c478bd9Sstevel@tonic-gate case IPV6_VERSION: 21487c478bd9Sstevel@tonic-gate udp_icmp_error_ipv6(q, mp); 21497c478bd9Sstevel@tonic-gate return; 21507c478bd9Sstevel@tonic-gate case IPV4_VERSION: 21517c478bd9Sstevel@tonic-gate break; 21527c478bd9Sstevel@tonic-gate default: 21537c478bd9Sstevel@tonic-gate goto noticmpv4; 21547c478bd9Sstevel@tonic-gate } 21557c478bd9Sstevel@tonic-gate 21567c478bd9Sstevel@tonic-gate /* Skip past the outer IP and ICMP headers */ 21577c478bd9Sstevel@tonic-gate iph_hdr_length = IPH_HDR_LENGTH(ipha); 21587c478bd9Sstevel@tonic-gate icmph = (icmph_t *)&mp->b_rptr[iph_hdr_length]; 21597c478bd9Sstevel@tonic-gate /* 21607c478bd9Sstevel@tonic-gate * If we don't have the correct outer IP header length or if the ULP 21617c478bd9Sstevel@tonic-gate * is not IPPROTO_ICMP or if we don't have a complete inner IP header 21627c478bd9Sstevel@tonic-gate * send the packet upstream. 21637c478bd9Sstevel@tonic-gate */ 21647c478bd9Sstevel@tonic-gate if (iph_hdr_length < sizeof (ipha_t) || 21657c478bd9Sstevel@tonic-gate ipha->ipha_protocol != IPPROTO_ICMP || 21667c478bd9Sstevel@tonic-gate (ipha_t *)&icmph[1] + 1 > (ipha_t *)mp->b_wptr) { 21677c478bd9Sstevel@tonic-gate goto noticmpv4; 21687c478bd9Sstevel@tonic-gate } 21697c478bd9Sstevel@tonic-gate ipha = (ipha_t *)&icmph[1]; 21707c478bd9Sstevel@tonic-gate 21717c478bd9Sstevel@tonic-gate /* Skip past the inner IP and find the ULP header */ 21727c478bd9Sstevel@tonic-gate iph_hdr_length = IPH_HDR_LENGTH(ipha); 21737c478bd9Sstevel@tonic-gate udpha = (udpha_t *)((char *)ipha + iph_hdr_length); 21747c478bd9Sstevel@tonic-gate /* 21757c478bd9Sstevel@tonic-gate * If we don't have the correct inner IP header length or if the ULP 21767c478bd9Sstevel@tonic-gate * is not IPPROTO_UDP or if we don't have at least ICMP_MIN_UDP_HDR 21777c478bd9Sstevel@tonic-gate * bytes of UDP header, send it upstream. 21787c478bd9Sstevel@tonic-gate */ 21797c478bd9Sstevel@tonic-gate if (iph_hdr_length < sizeof (ipha_t) || 21807c478bd9Sstevel@tonic-gate ipha->ipha_protocol != IPPROTO_UDP || 21817c478bd9Sstevel@tonic-gate (uchar_t *)udpha + ICMP_MIN_UDP_HDR > mp->b_wptr) { 21827c478bd9Sstevel@tonic-gate goto noticmpv4; 21837c478bd9Sstevel@tonic-gate } 21847c478bd9Sstevel@tonic-gate 21857c478bd9Sstevel@tonic-gate switch (icmph->icmph_type) { 21867c478bd9Sstevel@tonic-gate case ICMP_DEST_UNREACHABLE: 21877c478bd9Sstevel@tonic-gate switch (icmph->icmph_code) { 21887c478bd9Sstevel@tonic-gate case ICMP_FRAGMENTATION_NEEDED: 21897c478bd9Sstevel@tonic-gate /* 21907c478bd9Sstevel@tonic-gate * IP has already adjusted the path MTU. 21917c478bd9Sstevel@tonic-gate * XXX Somehow pass MTU indication to application? 21927c478bd9Sstevel@tonic-gate */ 21937c478bd9Sstevel@tonic-gate break; 21947c478bd9Sstevel@tonic-gate case ICMP_PORT_UNREACHABLE: 21957c478bd9Sstevel@tonic-gate case ICMP_PROTOCOL_UNREACHABLE: 21967c478bd9Sstevel@tonic-gate error = ECONNREFUSED; 21977c478bd9Sstevel@tonic-gate break; 21987c478bd9Sstevel@tonic-gate default: 21997c478bd9Sstevel@tonic-gate /* Transient errors */ 22007c478bd9Sstevel@tonic-gate break; 22017c478bd9Sstevel@tonic-gate } 22027c478bd9Sstevel@tonic-gate break; 22037c478bd9Sstevel@tonic-gate default: 22047c478bd9Sstevel@tonic-gate /* Transient errors */ 22057c478bd9Sstevel@tonic-gate break; 22067c478bd9Sstevel@tonic-gate } 22077c478bd9Sstevel@tonic-gate if (error == 0) { 22087c478bd9Sstevel@tonic-gate freemsg(mp); 22097c478bd9Sstevel@tonic-gate return; 22107c478bd9Sstevel@tonic-gate } 22117c478bd9Sstevel@tonic-gate 22127c478bd9Sstevel@tonic-gate switch (udp->udp_family) { 22137c478bd9Sstevel@tonic-gate case AF_INET: 22147c478bd9Sstevel@tonic-gate sin = sin_null; 22157c478bd9Sstevel@tonic-gate sin.sin_family = AF_INET; 22167c478bd9Sstevel@tonic-gate sin.sin_addr.s_addr = ipha->ipha_dst; 22177c478bd9Sstevel@tonic-gate sin.sin_port = udpha->uha_dst_port; 22187c478bd9Sstevel@tonic-gate mp1 = mi_tpi_uderror_ind((char *)&sin, sizeof (sin_t), NULL, 0, 22197c478bd9Sstevel@tonic-gate error); 22207c478bd9Sstevel@tonic-gate break; 22217c478bd9Sstevel@tonic-gate case AF_INET6: 22227c478bd9Sstevel@tonic-gate sin6 = sin6_null; 22237c478bd9Sstevel@tonic-gate sin6.sin6_family = AF_INET6; 22247c478bd9Sstevel@tonic-gate IN6_IPADDR_TO_V4MAPPED(ipha->ipha_dst, &sin6.sin6_addr); 22257c478bd9Sstevel@tonic-gate sin6.sin6_port = udpha->uha_dst_port; 22267c478bd9Sstevel@tonic-gate 22277c478bd9Sstevel@tonic-gate mp1 = mi_tpi_uderror_ind((char *)&sin6, sizeof (sin6_t), 22287c478bd9Sstevel@tonic-gate NULL, 0, error); 22297c478bd9Sstevel@tonic-gate break; 22307c478bd9Sstevel@tonic-gate } 22317c478bd9Sstevel@tonic-gate if (mp1) 2232ff550d0eSmasputra putnext(UDP_RD(q), mp1); 22337c478bd9Sstevel@tonic-gate freemsg(mp); 22347c478bd9Sstevel@tonic-gate } 22357c478bd9Sstevel@tonic-gate 22367c478bd9Sstevel@tonic-gate /* 22377c478bd9Sstevel@tonic-gate * udp_icmp_error_ipv6 is called by udp_icmp_error to process ICMP for IPv6. 22387c478bd9Sstevel@tonic-gate * Generates the appropriate T_UDERROR_IND for permanent (non-transient) errors. 22397c478bd9Sstevel@tonic-gate * Assumes that IP has pulled up all the extension headers as well as the 22407c478bd9Sstevel@tonic-gate * ICMPv6 header. 22417c478bd9Sstevel@tonic-gate * An M_CTL could potentially come here from some other module (i.e. if UDP 22427c478bd9Sstevel@tonic-gate * is pushed on some module other than IP). Thus, if we find that the M_CTL 22437c478bd9Sstevel@tonic-gate * does not have enough ICMP information , following STREAMS conventions, 22447c478bd9Sstevel@tonic-gate * we send it upstream assuming it is an M_CTL we don't understand. The reason 22457c478bd9Sstevel@tonic-gate * it might get here is if the non-ICMP M_CTL accidently has 6 in the version 22467c478bd9Sstevel@tonic-gate * field (when cast to ipha_t in udp_icmp_error). 22477c478bd9Sstevel@tonic-gate */ 22487c478bd9Sstevel@tonic-gate static void 22497c478bd9Sstevel@tonic-gate udp_icmp_error_ipv6(queue_t *q, mblk_t *mp) 22507c478bd9Sstevel@tonic-gate { 22517c478bd9Sstevel@tonic-gate icmp6_t *icmp6; 22527c478bd9Sstevel@tonic-gate ip6_t *ip6h, *outer_ip6h; 22537c478bd9Sstevel@tonic-gate uint16_t hdr_length; 22547c478bd9Sstevel@tonic-gate uint8_t *nexthdrp; 22557c478bd9Sstevel@tonic-gate udpha_t *udpha; 22567c478bd9Sstevel@tonic-gate sin6_t sin6; 22577c478bd9Sstevel@tonic-gate mblk_t *mp1; 22587c478bd9Sstevel@tonic-gate int error = 0; 22597c478bd9Sstevel@tonic-gate size_t mp_size = MBLKL(mp); 2260ff550d0eSmasputra udp_t *udp = Q_TO_UDP(q); 22617c478bd9Sstevel@tonic-gate 22627c478bd9Sstevel@tonic-gate /* 22637c478bd9Sstevel@tonic-gate * Verify that we have a complete IP header. If not, send it upstream. 22647c478bd9Sstevel@tonic-gate */ 22657c478bd9Sstevel@tonic-gate if (mp_size < sizeof (ip6_t)) { 22667c478bd9Sstevel@tonic-gate noticmpv6: 2267ff550d0eSmasputra putnext(UDP_RD(q), mp); 22687c478bd9Sstevel@tonic-gate return; 22697c478bd9Sstevel@tonic-gate } 22707c478bd9Sstevel@tonic-gate 22717c478bd9Sstevel@tonic-gate outer_ip6h = (ip6_t *)mp->b_rptr; 22727c478bd9Sstevel@tonic-gate /* 22737c478bd9Sstevel@tonic-gate * Verify this is an ICMPV6 packet, else send it upstream 22747c478bd9Sstevel@tonic-gate */ 22757c478bd9Sstevel@tonic-gate if (outer_ip6h->ip6_nxt == IPPROTO_ICMPV6) { 22767c478bd9Sstevel@tonic-gate hdr_length = IPV6_HDR_LEN; 22777c478bd9Sstevel@tonic-gate } else if (!ip_hdr_length_nexthdr_v6(mp, outer_ip6h, &hdr_length, 22787c478bd9Sstevel@tonic-gate &nexthdrp) || 22797c478bd9Sstevel@tonic-gate *nexthdrp != IPPROTO_ICMPV6) { 22807c478bd9Sstevel@tonic-gate goto noticmpv6; 22817c478bd9Sstevel@tonic-gate } 22827c478bd9Sstevel@tonic-gate icmp6 = (icmp6_t *)&mp->b_rptr[hdr_length]; 22837c478bd9Sstevel@tonic-gate ip6h = (ip6_t *)&icmp6[1]; 22847c478bd9Sstevel@tonic-gate /* 22857c478bd9Sstevel@tonic-gate * Verify we have a complete ICMP and inner IP header. 22867c478bd9Sstevel@tonic-gate */ 22877c478bd9Sstevel@tonic-gate if ((uchar_t *)&ip6h[1] > mp->b_wptr) 22887c478bd9Sstevel@tonic-gate goto noticmpv6; 22897c478bd9Sstevel@tonic-gate 22907c478bd9Sstevel@tonic-gate if (!ip_hdr_length_nexthdr_v6(mp, ip6h, &hdr_length, &nexthdrp)) 22917c478bd9Sstevel@tonic-gate goto noticmpv6; 22927c478bd9Sstevel@tonic-gate udpha = (udpha_t *)((char *)ip6h + hdr_length); 22937c478bd9Sstevel@tonic-gate /* 22947c478bd9Sstevel@tonic-gate * Validate inner header. If the ULP is not IPPROTO_UDP or if we don't 22957c478bd9Sstevel@tonic-gate * have at least ICMP_MIN_UDP_HDR bytes of UDP header send the 22967c478bd9Sstevel@tonic-gate * packet upstream. 22977c478bd9Sstevel@tonic-gate */ 22987c478bd9Sstevel@tonic-gate if ((*nexthdrp != IPPROTO_UDP) || 22997c478bd9Sstevel@tonic-gate ((uchar_t *)udpha + ICMP_MIN_UDP_HDR) > mp->b_wptr) { 23007c478bd9Sstevel@tonic-gate goto noticmpv6; 23017c478bd9Sstevel@tonic-gate } 23027c478bd9Sstevel@tonic-gate 23037c478bd9Sstevel@tonic-gate switch (icmp6->icmp6_type) { 23047c478bd9Sstevel@tonic-gate case ICMP6_DST_UNREACH: 23057c478bd9Sstevel@tonic-gate switch (icmp6->icmp6_code) { 23067c478bd9Sstevel@tonic-gate case ICMP6_DST_UNREACH_NOPORT: 23077c478bd9Sstevel@tonic-gate error = ECONNREFUSED; 23087c478bd9Sstevel@tonic-gate break; 23097c478bd9Sstevel@tonic-gate case ICMP6_DST_UNREACH_ADMIN: 23107c478bd9Sstevel@tonic-gate case ICMP6_DST_UNREACH_NOROUTE: 23117c478bd9Sstevel@tonic-gate case ICMP6_DST_UNREACH_BEYONDSCOPE: 23127c478bd9Sstevel@tonic-gate case ICMP6_DST_UNREACH_ADDR: 23137c478bd9Sstevel@tonic-gate /* Transient errors */ 23147c478bd9Sstevel@tonic-gate break; 23157c478bd9Sstevel@tonic-gate default: 23167c478bd9Sstevel@tonic-gate break; 23177c478bd9Sstevel@tonic-gate } 23187c478bd9Sstevel@tonic-gate break; 23197c478bd9Sstevel@tonic-gate case ICMP6_PACKET_TOO_BIG: { 23207c478bd9Sstevel@tonic-gate struct T_unitdata_ind *tudi; 23217c478bd9Sstevel@tonic-gate struct T_opthdr *toh; 23227c478bd9Sstevel@tonic-gate size_t udi_size; 23237c478bd9Sstevel@tonic-gate mblk_t *newmp; 23247c478bd9Sstevel@tonic-gate t_scalar_t opt_length = sizeof (struct T_opthdr) + 23257c478bd9Sstevel@tonic-gate sizeof (struct ip6_mtuinfo); 23267c478bd9Sstevel@tonic-gate sin6_t *sin6; 23277c478bd9Sstevel@tonic-gate struct ip6_mtuinfo *mtuinfo; 23287c478bd9Sstevel@tonic-gate 23297c478bd9Sstevel@tonic-gate /* 23307c478bd9Sstevel@tonic-gate * If the application has requested to receive path mtu 23317c478bd9Sstevel@tonic-gate * information, send up an empty message containing an 23327c478bd9Sstevel@tonic-gate * IPV6_PATHMTU ancillary data item. 23337c478bd9Sstevel@tonic-gate */ 23347c478bd9Sstevel@tonic-gate if (!udp->udp_ipv6_recvpathmtu) 23357c478bd9Sstevel@tonic-gate break; 23367c478bd9Sstevel@tonic-gate 23377c478bd9Sstevel@tonic-gate udi_size = sizeof (struct T_unitdata_ind) + sizeof (sin6_t) + 23387c478bd9Sstevel@tonic-gate opt_length; 23397c478bd9Sstevel@tonic-gate if ((newmp = allocb(udi_size, BPRI_MED)) == NULL) { 23407c478bd9Sstevel@tonic-gate BUMP_MIB(&udp_mib, udpInErrors); 23417c478bd9Sstevel@tonic-gate break; 23427c478bd9Sstevel@tonic-gate } 23437c478bd9Sstevel@tonic-gate 23447c478bd9Sstevel@tonic-gate /* 23457c478bd9Sstevel@tonic-gate * newmp->b_cont is left to NULL on purpose. This is an 23467c478bd9Sstevel@tonic-gate * empty message containing only ancillary data. 23477c478bd9Sstevel@tonic-gate */ 23487c478bd9Sstevel@tonic-gate newmp->b_datap->db_type = M_PROTO; 23497c478bd9Sstevel@tonic-gate tudi = (struct T_unitdata_ind *)newmp->b_rptr; 23507c478bd9Sstevel@tonic-gate newmp->b_wptr = (uchar_t *)tudi + udi_size; 23517c478bd9Sstevel@tonic-gate tudi->PRIM_type = T_UNITDATA_IND; 23527c478bd9Sstevel@tonic-gate tudi->SRC_length = sizeof (sin6_t); 23537c478bd9Sstevel@tonic-gate tudi->SRC_offset = sizeof (struct T_unitdata_ind); 23547c478bd9Sstevel@tonic-gate tudi->OPT_offset = tudi->SRC_offset + sizeof (sin6_t); 23557c478bd9Sstevel@tonic-gate tudi->OPT_length = opt_length; 23567c478bd9Sstevel@tonic-gate 23577c478bd9Sstevel@tonic-gate sin6 = (sin6_t *)&tudi[1]; 23587c478bd9Sstevel@tonic-gate bzero(sin6, sizeof (sin6_t)); 23597c478bd9Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 23607c478bd9Sstevel@tonic-gate sin6->sin6_addr = udp->udp_v6dst; 23617c478bd9Sstevel@tonic-gate 23627c478bd9Sstevel@tonic-gate toh = (struct T_opthdr *)&sin6[1]; 23637c478bd9Sstevel@tonic-gate toh->level = IPPROTO_IPV6; 23647c478bd9Sstevel@tonic-gate toh->name = IPV6_PATHMTU; 23657c478bd9Sstevel@tonic-gate toh->len = opt_length; 23667c478bd9Sstevel@tonic-gate toh->status = 0; 23677c478bd9Sstevel@tonic-gate 23687c478bd9Sstevel@tonic-gate mtuinfo = (struct ip6_mtuinfo *)&toh[1]; 23697c478bd9Sstevel@tonic-gate bzero(mtuinfo, sizeof (struct ip6_mtuinfo)); 23707c478bd9Sstevel@tonic-gate mtuinfo->ip6m_addr.sin6_family = AF_INET6; 23717c478bd9Sstevel@tonic-gate mtuinfo->ip6m_addr.sin6_addr = ip6h->ip6_dst; 23727c478bd9Sstevel@tonic-gate mtuinfo->ip6m_mtu = icmp6->icmp6_mtu; 23737c478bd9Sstevel@tonic-gate /* 23747c478bd9Sstevel@tonic-gate * We've consumed everything we need from the original 23757c478bd9Sstevel@tonic-gate * message. Free it, then send our empty message. 23767c478bd9Sstevel@tonic-gate */ 23777c478bd9Sstevel@tonic-gate freemsg(mp); 2378ff550d0eSmasputra putnext(UDP_RD(q), newmp); 23797c478bd9Sstevel@tonic-gate return; 23807c478bd9Sstevel@tonic-gate } 23817c478bd9Sstevel@tonic-gate case ICMP6_TIME_EXCEEDED: 23827c478bd9Sstevel@tonic-gate /* Transient errors */ 23837c478bd9Sstevel@tonic-gate break; 23847c478bd9Sstevel@tonic-gate case ICMP6_PARAM_PROB: 23857c478bd9Sstevel@tonic-gate /* If this corresponds to an ICMP_PROTOCOL_UNREACHABLE */ 23867c478bd9Sstevel@tonic-gate if (icmp6->icmp6_code == ICMP6_PARAMPROB_NEXTHEADER && 23877c478bd9Sstevel@tonic-gate (uchar_t *)ip6h + icmp6->icmp6_pptr == 23887c478bd9Sstevel@tonic-gate (uchar_t *)nexthdrp) { 23897c478bd9Sstevel@tonic-gate error = ECONNREFUSED; 23907c478bd9Sstevel@tonic-gate break; 23917c478bd9Sstevel@tonic-gate } 23927c478bd9Sstevel@tonic-gate break; 23937c478bd9Sstevel@tonic-gate } 23947c478bd9Sstevel@tonic-gate if (error == 0) { 23957c478bd9Sstevel@tonic-gate freemsg(mp); 23967c478bd9Sstevel@tonic-gate return; 23977c478bd9Sstevel@tonic-gate } 23987c478bd9Sstevel@tonic-gate 23997c478bd9Sstevel@tonic-gate sin6 = sin6_null; 24007c478bd9Sstevel@tonic-gate sin6.sin6_family = AF_INET6; 24017c478bd9Sstevel@tonic-gate sin6.sin6_addr = ip6h->ip6_dst; 24027c478bd9Sstevel@tonic-gate sin6.sin6_port = udpha->uha_dst_port; 24037c478bd9Sstevel@tonic-gate sin6.sin6_flowinfo = ip6h->ip6_vcf & ~IPV6_VERS_AND_FLOW_MASK; 24047c478bd9Sstevel@tonic-gate 24057c478bd9Sstevel@tonic-gate mp1 = mi_tpi_uderror_ind((char *)&sin6, sizeof (sin6_t), NULL, 0, 24067c478bd9Sstevel@tonic-gate error); 24077c478bd9Sstevel@tonic-gate if (mp1) 2408ff550d0eSmasputra putnext(UDP_RD(q), mp1); 24097c478bd9Sstevel@tonic-gate freemsg(mp); 24107c478bd9Sstevel@tonic-gate } 24117c478bd9Sstevel@tonic-gate 24127c478bd9Sstevel@tonic-gate /* 24137c478bd9Sstevel@tonic-gate * This routine responds to T_ADDR_REQ messages. It is called by udp_wput. 24147c478bd9Sstevel@tonic-gate * The local address is filled in if endpoint is bound. The remote address 24157c478bd9Sstevel@tonic-gate * is filled in if remote address has been precified ("connected endpoint") 24167c478bd9Sstevel@tonic-gate * (The concept of connected CLTS sockets is alien to published TPI 24177c478bd9Sstevel@tonic-gate * but we support it anyway). 24187c478bd9Sstevel@tonic-gate */ 24197c478bd9Sstevel@tonic-gate static void 24207c478bd9Sstevel@tonic-gate udp_addr_req(queue_t *q, mblk_t *mp) 24217c478bd9Sstevel@tonic-gate { 24227c478bd9Sstevel@tonic-gate sin_t *sin; 24237c478bd9Sstevel@tonic-gate sin6_t *sin6; 24247c478bd9Sstevel@tonic-gate mblk_t *ackmp; 24257c478bd9Sstevel@tonic-gate struct T_addr_ack *taa; 2426ff550d0eSmasputra udp_t *udp = Q_TO_UDP(q); 24277c478bd9Sstevel@tonic-gate 24287c478bd9Sstevel@tonic-gate /* Make it large enough for worst case */ 24297c478bd9Sstevel@tonic-gate ackmp = reallocb(mp, sizeof (struct T_addr_ack) + 24307c478bd9Sstevel@tonic-gate 2 * sizeof (sin6_t), 1); 24317c478bd9Sstevel@tonic-gate if (ackmp == NULL) { 24327c478bd9Sstevel@tonic-gate udp_err_ack(q, mp, TSYSERR, ENOMEM); 24337c478bd9Sstevel@tonic-gate return; 24347c478bd9Sstevel@tonic-gate } 24357c478bd9Sstevel@tonic-gate taa = (struct T_addr_ack *)ackmp->b_rptr; 24367c478bd9Sstevel@tonic-gate 24377c478bd9Sstevel@tonic-gate bzero(taa, sizeof (struct T_addr_ack)); 24387c478bd9Sstevel@tonic-gate ackmp->b_wptr = (uchar_t *)&taa[1]; 24397c478bd9Sstevel@tonic-gate 24407c478bd9Sstevel@tonic-gate taa->PRIM_type = T_ADDR_ACK; 24417c478bd9Sstevel@tonic-gate ackmp->b_datap->db_type = M_PCPROTO; 24427c478bd9Sstevel@tonic-gate /* 24437c478bd9Sstevel@tonic-gate * Note: Following code assumes 32 bit alignment of basic 24447c478bd9Sstevel@tonic-gate * data structures like sin_t and struct T_addr_ack. 24457c478bd9Sstevel@tonic-gate */ 24467c478bd9Sstevel@tonic-gate if (udp->udp_state != TS_UNBND) { 24477c478bd9Sstevel@tonic-gate /* 24487c478bd9Sstevel@tonic-gate * Fill in local address first 24497c478bd9Sstevel@tonic-gate */ 24507c478bd9Sstevel@tonic-gate taa->LOCADDR_offset = sizeof (*taa); 24517c478bd9Sstevel@tonic-gate if (udp->udp_family == AF_INET) { 24527c478bd9Sstevel@tonic-gate taa->LOCADDR_length = sizeof (sin_t); 24537c478bd9Sstevel@tonic-gate sin = (sin_t *)&taa[1]; 24547c478bd9Sstevel@tonic-gate /* Fill zeroes and then initialize non-zero fields */ 24557c478bd9Sstevel@tonic-gate *sin = sin_null; 24567c478bd9Sstevel@tonic-gate sin->sin_family = AF_INET; 24577c478bd9Sstevel@tonic-gate if (!IN6_IS_ADDR_V4MAPPED_ANY(&udp->udp_v6src) && 24587c478bd9Sstevel@tonic-gate !IN6_IS_ADDR_UNSPECIFIED(&udp->udp_v6src)) { 24597c478bd9Sstevel@tonic-gate IN6_V4MAPPED_TO_IPADDR(&udp->udp_v6src, 24607c478bd9Sstevel@tonic-gate sin->sin_addr.s_addr); 24617c478bd9Sstevel@tonic-gate } else { 24627c478bd9Sstevel@tonic-gate /* 24637c478bd9Sstevel@tonic-gate * INADDR_ANY 24647c478bd9Sstevel@tonic-gate * udp_v6src is not set, we might be bound to 24657c478bd9Sstevel@tonic-gate * broadcast/multicast. Use udp_bound_v6src as 24667c478bd9Sstevel@tonic-gate * local address instead (that could 24677c478bd9Sstevel@tonic-gate * also still be INADDR_ANY) 24687c478bd9Sstevel@tonic-gate */ 24697c478bd9Sstevel@tonic-gate IN6_V4MAPPED_TO_IPADDR(&udp->udp_bound_v6src, 24707c478bd9Sstevel@tonic-gate sin->sin_addr.s_addr); 24717c478bd9Sstevel@tonic-gate } 24727c478bd9Sstevel@tonic-gate sin->sin_port = udp->udp_port; 24737c478bd9Sstevel@tonic-gate ackmp->b_wptr = (uchar_t *)&sin[1]; 24747c478bd9Sstevel@tonic-gate if (udp->udp_state == TS_DATA_XFER) { 24757c478bd9Sstevel@tonic-gate /* 24767c478bd9Sstevel@tonic-gate * connected, fill remote address too 24777c478bd9Sstevel@tonic-gate */ 24787c478bd9Sstevel@tonic-gate taa->REMADDR_length = sizeof (sin_t); 24797c478bd9Sstevel@tonic-gate /* assumed 32-bit alignment */ 24807c478bd9Sstevel@tonic-gate taa->REMADDR_offset = taa->LOCADDR_offset + 24817c478bd9Sstevel@tonic-gate taa->LOCADDR_length; 24827c478bd9Sstevel@tonic-gate 24837c478bd9Sstevel@tonic-gate sin = (sin_t *)(ackmp->b_rptr + 24847c478bd9Sstevel@tonic-gate taa->REMADDR_offset); 24857c478bd9Sstevel@tonic-gate /* initialize */ 24867c478bd9Sstevel@tonic-gate *sin = sin_null; 24877c478bd9Sstevel@tonic-gate sin->sin_family = AF_INET; 24887c478bd9Sstevel@tonic-gate sin->sin_addr.s_addr = 24897c478bd9Sstevel@tonic-gate V4_PART_OF_V6(udp->udp_v6dst); 24907c478bd9Sstevel@tonic-gate sin->sin_port = udp->udp_dstport; 24917c478bd9Sstevel@tonic-gate ackmp->b_wptr = (uchar_t *)&sin[1]; 24927c478bd9Sstevel@tonic-gate } 24937c478bd9Sstevel@tonic-gate } else { 24947c478bd9Sstevel@tonic-gate taa->LOCADDR_length = sizeof (sin6_t); 24957c478bd9Sstevel@tonic-gate sin6 = (sin6_t *)&taa[1]; 24967c478bd9Sstevel@tonic-gate /* Fill zeroes and then initialize non-zero fields */ 24977c478bd9Sstevel@tonic-gate *sin6 = sin6_null; 24987c478bd9Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 24997c478bd9Sstevel@tonic-gate if (!IN6_IS_ADDR_UNSPECIFIED(&udp->udp_v6src)) { 25007c478bd9Sstevel@tonic-gate sin6->sin6_addr = udp->udp_v6src; 25017c478bd9Sstevel@tonic-gate } else { 25027c478bd9Sstevel@tonic-gate /* 25037c478bd9Sstevel@tonic-gate * UNSPECIFIED 25047c478bd9Sstevel@tonic-gate * udp_v6src is not set, we might be bound to 25057c478bd9Sstevel@tonic-gate * broadcast/multicast. Use udp_bound_v6src as 25067c478bd9Sstevel@tonic-gate * local address instead (that could 25077c478bd9Sstevel@tonic-gate * also still be UNSPECIFIED) 25087c478bd9Sstevel@tonic-gate */ 25097c478bd9Sstevel@tonic-gate sin6->sin6_addr = 25107c478bd9Sstevel@tonic-gate udp->udp_bound_v6src; 25117c478bd9Sstevel@tonic-gate } 25127c478bd9Sstevel@tonic-gate sin6->sin6_port = udp->udp_port; 25137c478bd9Sstevel@tonic-gate ackmp->b_wptr = (uchar_t *)&sin6[1]; 25147c478bd9Sstevel@tonic-gate if (udp->udp_state == TS_DATA_XFER) { 25157c478bd9Sstevel@tonic-gate /* 25167c478bd9Sstevel@tonic-gate * connected, fill remote address too 25177c478bd9Sstevel@tonic-gate */ 25187c478bd9Sstevel@tonic-gate taa->REMADDR_length = sizeof (sin6_t); 25197c478bd9Sstevel@tonic-gate /* assumed 32-bit alignment */ 25207c478bd9Sstevel@tonic-gate taa->REMADDR_offset = taa->LOCADDR_offset + 25217c478bd9Sstevel@tonic-gate taa->LOCADDR_length; 25227c478bd9Sstevel@tonic-gate 25237c478bd9Sstevel@tonic-gate sin6 = (sin6_t *)(ackmp->b_rptr + 25247c478bd9Sstevel@tonic-gate taa->REMADDR_offset); 25257c478bd9Sstevel@tonic-gate /* initialize */ 25267c478bd9Sstevel@tonic-gate *sin6 = sin6_null; 25277c478bd9Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 25287c478bd9Sstevel@tonic-gate sin6->sin6_addr = udp->udp_v6dst; 25297c478bd9Sstevel@tonic-gate sin6->sin6_port = udp->udp_dstport; 25307c478bd9Sstevel@tonic-gate ackmp->b_wptr = (uchar_t *)&sin6[1]; 25317c478bd9Sstevel@tonic-gate } 25327c478bd9Sstevel@tonic-gate ackmp->b_wptr = (uchar_t *)&sin6[1]; 25337c478bd9Sstevel@tonic-gate } 25347c478bd9Sstevel@tonic-gate } 25357c478bd9Sstevel@tonic-gate ASSERT(ackmp->b_wptr <= ackmp->b_datap->db_lim); 2536ff550d0eSmasputra putnext(UDP_RD(q), ackmp); 25377c478bd9Sstevel@tonic-gate } 25387c478bd9Sstevel@tonic-gate 25397c478bd9Sstevel@tonic-gate static void 25407c478bd9Sstevel@tonic-gate udp_copy_info(struct T_info_ack *tap, udp_t *udp) 25417c478bd9Sstevel@tonic-gate { 25427c478bd9Sstevel@tonic-gate if (udp->udp_family == AF_INET) { 25437c478bd9Sstevel@tonic-gate *tap = udp_g_t_info_ack_ipv4; 25447c478bd9Sstevel@tonic-gate } else { 25457c478bd9Sstevel@tonic-gate *tap = udp_g_t_info_ack_ipv6; 25467c478bd9Sstevel@tonic-gate } 25477c478bd9Sstevel@tonic-gate tap->CURRENT_state = udp->udp_state; 25487c478bd9Sstevel@tonic-gate tap->OPT_size = udp_max_optsize; 25497c478bd9Sstevel@tonic-gate } 25507c478bd9Sstevel@tonic-gate 25517c478bd9Sstevel@tonic-gate /* 25527c478bd9Sstevel@tonic-gate * This routine responds to T_CAPABILITY_REQ messages. It is called by 25537c478bd9Sstevel@tonic-gate * udp_wput. Much of the T_CAPABILITY_ACK information is copied from 25547c478bd9Sstevel@tonic-gate * udp_g_t_info_ack. The current state of the stream is copied from 25557c478bd9Sstevel@tonic-gate * udp_state. 25567c478bd9Sstevel@tonic-gate */ 25577c478bd9Sstevel@tonic-gate static void 25587c478bd9Sstevel@tonic-gate udp_capability_req(queue_t *q, mblk_t *mp) 25597c478bd9Sstevel@tonic-gate { 25607c478bd9Sstevel@tonic-gate t_uscalar_t cap_bits1; 25617c478bd9Sstevel@tonic-gate struct T_capability_ack *tcap; 2562ff550d0eSmasputra udp_t *udp = Q_TO_UDP(q); 25637c478bd9Sstevel@tonic-gate 25647c478bd9Sstevel@tonic-gate cap_bits1 = ((struct T_capability_req *)mp->b_rptr)->CAP_bits1; 25657c478bd9Sstevel@tonic-gate 25667c478bd9Sstevel@tonic-gate mp = tpi_ack_alloc(mp, sizeof (struct T_capability_ack), 25677c478bd9Sstevel@tonic-gate mp->b_datap->db_type, T_CAPABILITY_ACK); 25687c478bd9Sstevel@tonic-gate if (!mp) 25697c478bd9Sstevel@tonic-gate return; 25707c478bd9Sstevel@tonic-gate 25717c478bd9Sstevel@tonic-gate tcap = (struct T_capability_ack *)mp->b_rptr; 25727c478bd9Sstevel@tonic-gate tcap->CAP_bits1 = 0; 25737c478bd9Sstevel@tonic-gate 25747c478bd9Sstevel@tonic-gate if (cap_bits1 & TC1_INFO) { 25757c478bd9Sstevel@tonic-gate udp_copy_info(&tcap->INFO_ack, udp); 25767c478bd9Sstevel@tonic-gate tcap->CAP_bits1 |= TC1_INFO; 25777c478bd9Sstevel@tonic-gate } 25787c478bd9Sstevel@tonic-gate 2579ff550d0eSmasputra putnext(UDP_RD(q), mp); 25807c478bd9Sstevel@tonic-gate } 25817c478bd9Sstevel@tonic-gate 25827c478bd9Sstevel@tonic-gate /* 25837c478bd9Sstevel@tonic-gate * This routine responds to T_INFO_REQ messages. It is called by udp_wput. 25847c478bd9Sstevel@tonic-gate * Most of the T_INFO_ACK information is copied from udp_g_t_info_ack. 25857c478bd9Sstevel@tonic-gate * The current state of the stream is copied from udp_state. 25867c478bd9Sstevel@tonic-gate */ 25877c478bd9Sstevel@tonic-gate static void 25887c478bd9Sstevel@tonic-gate udp_info_req(queue_t *q, mblk_t *mp) 25897c478bd9Sstevel@tonic-gate { 2590ff550d0eSmasputra udp_t *udp = Q_TO_UDP(q); 25917c478bd9Sstevel@tonic-gate 25927c478bd9Sstevel@tonic-gate /* Create a T_INFO_ACK message. */ 25937c478bd9Sstevel@tonic-gate mp = tpi_ack_alloc(mp, sizeof (struct T_info_ack), M_PCPROTO, 25947c478bd9Sstevel@tonic-gate T_INFO_ACK); 25957c478bd9Sstevel@tonic-gate if (!mp) 25967c478bd9Sstevel@tonic-gate return; 25977c478bd9Sstevel@tonic-gate udp_copy_info((struct T_info_ack *)mp->b_rptr, udp); 2598ff550d0eSmasputra putnext(UDP_RD(q), mp); 25997c478bd9Sstevel@tonic-gate } 26007c478bd9Sstevel@tonic-gate 26017c478bd9Sstevel@tonic-gate /* 26027c478bd9Sstevel@tonic-gate * IP recognizes seven kinds of bind requests: 26037c478bd9Sstevel@tonic-gate * 26047c478bd9Sstevel@tonic-gate * - A zero-length address binds only to the protocol number. 26057c478bd9Sstevel@tonic-gate * 26067c478bd9Sstevel@tonic-gate * - A 4-byte address is treated as a request to 26077c478bd9Sstevel@tonic-gate * validate that the address is a valid local IPv4 26087c478bd9Sstevel@tonic-gate * address, appropriate for an application to bind to. 26097c478bd9Sstevel@tonic-gate * IP does the verification, but does not make any note 26107c478bd9Sstevel@tonic-gate * of the address at this time. 26117c478bd9Sstevel@tonic-gate * 26127c478bd9Sstevel@tonic-gate * - A 16-byte address contains is treated as a request 26137c478bd9Sstevel@tonic-gate * to validate a local IPv6 address, as the 4-byte 26147c478bd9Sstevel@tonic-gate * address case above. 26157c478bd9Sstevel@tonic-gate * 26167c478bd9Sstevel@tonic-gate * - A 16-byte sockaddr_in to validate the local IPv4 address and also 26177c478bd9Sstevel@tonic-gate * use it for the inbound fanout of packets. 26187c478bd9Sstevel@tonic-gate * 26197c478bd9Sstevel@tonic-gate * - A 24-byte sockaddr_in6 to validate the local IPv6 address and also 26207c478bd9Sstevel@tonic-gate * use it for the inbound fanout of packets. 26217c478bd9Sstevel@tonic-gate * 26227c478bd9Sstevel@tonic-gate * - A 12-byte address (ipa_conn_t) containing complete IPv4 fanout 26237c478bd9Sstevel@tonic-gate * information consisting of local and remote addresses 26247c478bd9Sstevel@tonic-gate * and ports. In this case, the addresses are both 26257c478bd9Sstevel@tonic-gate * validated as appropriate for this operation, and, if 26267c478bd9Sstevel@tonic-gate * so, the information is retained for use in the 26277c478bd9Sstevel@tonic-gate * inbound fanout. 26287c478bd9Sstevel@tonic-gate * 26297c478bd9Sstevel@tonic-gate * - A 36-byte address address (ipa6_conn_t) containing complete IPv6 26307c478bd9Sstevel@tonic-gate * fanout information, like the 12-byte case above. 26317c478bd9Sstevel@tonic-gate * 26327c478bd9Sstevel@tonic-gate * IP will also fill in the IRE request mblk with information 26337c478bd9Sstevel@tonic-gate * regarding our peer. In all cases, we notify IP of our protocol 26347c478bd9Sstevel@tonic-gate * type by appending a single protocol byte to the bind request. 26357c478bd9Sstevel@tonic-gate */ 26367c478bd9Sstevel@tonic-gate static mblk_t * 26377c478bd9Sstevel@tonic-gate udp_ip_bind_mp(udp_t *udp, t_scalar_t bind_prim, t_scalar_t addr_length) 26387c478bd9Sstevel@tonic-gate { 26397c478bd9Sstevel@tonic-gate char *cp; 26407c478bd9Sstevel@tonic-gate mblk_t *mp; 26417c478bd9Sstevel@tonic-gate struct T_bind_req *tbr; 26427c478bd9Sstevel@tonic-gate ipa_conn_t *ac; 26437c478bd9Sstevel@tonic-gate ipa6_conn_t *ac6; 26447c478bd9Sstevel@tonic-gate sin_t *sin; 26457c478bd9Sstevel@tonic-gate sin6_t *sin6; 26467c478bd9Sstevel@tonic-gate 26477c478bd9Sstevel@tonic-gate ASSERT(bind_prim == O_T_BIND_REQ || bind_prim == T_BIND_REQ); 26487c478bd9Sstevel@tonic-gate 26497c478bd9Sstevel@tonic-gate mp = allocb(sizeof (*tbr) + addr_length + 1, BPRI_HI); 26507c478bd9Sstevel@tonic-gate if (!mp) 26517c478bd9Sstevel@tonic-gate return (mp); 26527c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_PROTO; 26537c478bd9Sstevel@tonic-gate tbr = (struct T_bind_req *)mp->b_rptr; 26547c478bd9Sstevel@tonic-gate tbr->PRIM_type = bind_prim; 26557c478bd9Sstevel@tonic-gate tbr->ADDR_offset = sizeof (*tbr); 26567c478bd9Sstevel@tonic-gate tbr->CONIND_number = 0; 26577c478bd9Sstevel@tonic-gate tbr->ADDR_length = addr_length; 26587c478bd9Sstevel@tonic-gate cp = (char *)&tbr[1]; 26597c478bd9Sstevel@tonic-gate switch (addr_length) { 26607c478bd9Sstevel@tonic-gate case sizeof (ipa_conn_t): 26617c478bd9Sstevel@tonic-gate ASSERT(udp->udp_family == AF_INET); 26627c478bd9Sstevel@tonic-gate /* Append a request for an IRE */ 26637c478bd9Sstevel@tonic-gate mp->b_cont = allocb(sizeof (ire_t), BPRI_HI); 26647c478bd9Sstevel@tonic-gate if (!mp->b_cont) { 26657c478bd9Sstevel@tonic-gate freemsg(mp); 26667c478bd9Sstevel@tonic-gate return (NULL); 26677c478bd9Sstevel@tonic-gate } 26687c478bd9Sstevel@tonic-gate mp->b_cont->b_wptr += sizeof (ire_t); 26697c478bd9Sstevel@tonic-gate mp->b_cont->b_datap->db_type = IRE_DB_REQ_TYPE; 26707c478bd9Sstevel@tonic-gate 26717c478bd9Sstevel@tonic-gate /* cp known to be 32 bit aligned */ 26727c478bd9Sstevel@tonic-gate ac = (ipa_conn_t *)cp; 26737c478bd9Sstevel@tonic-gate ac->ac_laddr = V4_PART_OF_V6(udp->udp_v6src); 26747c478bd9Sstevel@tonic-gate ac->ac_faddr = V4_PART_OF_V6(udp->udp_v6dst); 26757c478bd9Sstevel@tonic-gate ac->ac_fport = udp->udp_dstport; 26767c478bd9Sstevel@tonic-gate ac->ac_lport = udp->udp_port; 26777c478bd9Sstevel@tonic-gate break; 26787c478bd9Sstevel@tonic-gate 26797c478bd9Sstevel@tonic-gate case sizeof (ipa6_conn_t): 26807c478bd9Sstevel@tonic-gate ASSERT(udp->udp_family == AF_INET6); 26817c478bd9Sstevel@tonic-gate /* Append a request for an IRE */ 26827c478bd9Sstevel@tonic-gate mp->b_cont = allocb(sizeof (ire_t), BPRI_HI); 26837c478bd9Sstevel@tonic-gate if (!mp->b_cont) { 26847c478bd9Sstevel@tonic-gate freemsg(mp); 26857c478bd9Sstevel@tonic-gate return (NULL); 26867c478bd9Sstevel@tonic-gate } 26877c478bd9Sstevel@tonic-gate mp->b_cont->b_wptr += sizeof (ire_t); 26887c478bd9Sstevel@tonic-gate mp->b_cont->b_datap->db_type = IRE_DB_REQ_TYPE; 26897c478bd9Sstevel@tonic-gate 26907c478bd9Sstevel@tonic-gate /* cp known to be 32 bit aligned */ 26917c478bd9Sstevel@tonic-gate ac6 = (ipa6_conn_t *)cp; 26927c478bd9Sstevel@tonic-gate ac6->ac6_laddr = udp->udp_v6src; 26937c478bd9Sstevel@tonic-gate ac6->ac6_faddr = udp->udp_v6dst; 26947c478bd9Sstevel@tonic-gate ac6->ac6_fport = udp->udp_dstport; 26957c478bd9Sstevel@tonic-gate ac6->ac6_lport = udp->udp_port; 26967c478bd9Sstevel@tonic-gate break; 26977c478bd9Sstevel@tonic-gate 26987c478bd9Sstevel@tonic-gate case sizeof (sin_t): 26997c478bd9Sstevel@tonic-gate ASSERT(udp->udp_family == AF_INET); 27007c478bd9Sstevel@tonic-gate /* Append a request for an IRE */ 27017c478bd9Sstevel@tonic-gate mp->b_cont = allocb(sizeof (ire_t), BPRI_HI); 27027c478bd9Sstevel@tonic-gate if (!mp->b_cont) { 27037c478bd9Sstevel@tonic-gate freemsg(mp); 27047c478bd9Sstevel@tonic-gate return (NULL); 27057c478bd9Sstevel@tonic-gate } 27067c478bd9Sstevel@tonic-gate mp->b_cont->b_wptr += sizeof (ire_t); 27077c478bd9Sstevel@tonic-gate mp->b_cont->b_datap->db_type = IRE_DB_REQ_TYPE; 27087c478bd9Sstevel@tonic-gate 27097c478bd9Sstevel@tonic-gate sin = (sin_t *)cp; 27107c478bd9Sstevel@tonic-gate *sin = sin_null; 27117c478bd9Sstevel@tonic-gate sin->sin_family = AF_INET; 27127c478bd9Sstevel@tonic-gate sin->sin_addr.s_addr = V4_PART_OF_V6(udp->udp_bound_v6src); 27137c478bd9Sstevel@tonic-gate sin->sin_port = udp->udp_port; 27147c478bd9Sstevel@tonic-gate break; 27157c478bd9Sstevel@tonic-gate 27167c478bd9Sstevel@tonic-gate case sizeof (sin6_t): 27177c478bd9Sstevel@tonic-gate ASSERT(udp->udp_family == AF_INET6); 27187c478bd9Sstevel@tonic-gate /* Append a request for an IRE */ 27197c478bd9Sstevel@tonic-gate mp->b_cont = allocb(sizeof (ire_t), BPRI_HI); 27207c478bd9Sstevel@tonic-gate if (!mp->b_cont) { 27217c478bd9Sstevel@tonic-gate freemsg(mp); 27227c478bd9Sstevel@tonic-gate return (NULL); 27237c478bd9Sstevel@tonic-gate } 27247c478bd9Sstevel@tonic-gate mp->b_cont->b_wptr += sizeof (ire_t); 27257c478bd9Sstevel@tonic-gate mp->b_cont->b_datap->db_type = IRE_DB_REQ_TYPE; 27267c478bd9Sstevel@tonic-gate 27277c478bd9Sstevel@tonic-gate sin6 = (sin6_t *)cp; 27287c478bd9Sstevel@tonic-gate *sin6 = sin6_null; 27297c478bd9Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 27307c478bd9Sstevel@tonic-gate sin6->sin6_addr = udp->udp_bound_v6src; 27317c478bd9Sstevel@tonic-gate sin6->sin6_port = udp->udp_port; 27327c478bd9Sstevel@tonic-gate break; 27337c478bd9Sstevel@tonic-gate } 27347c478bd9Sstevel@tonic-gate /* Add protocol number to end */ 27357c478bd9Sstevel@tonic-gate cp[addr_length] = (char)IPPROTO_UDP; 27367c478bd9Sstevel@tonic-gate mp->b_wptr = (uchar_t *)&cp[addr_length + 1]; 27377c478bd9Sstevel@tonic-gate return (mp); 27387c478bd9Sstevel@tonic-gate } 27397c478bd9Sstevel@tonic-gate 27407c478bd9Sstevel@tonic-gate /* 27417c478bd9Sstevel@tonic-gate * This is the open routine for udp. It allocates a udp_t structure for 27427c478bd9Sstevel@tonic-gate * the stream and, on the first open of the module, creates an ND table. 27437c478bd9Sstevel@tonic-gate */ 2744ff550d0eSmasputra /* ARGSUSED */ 27457c478bd9Sstevel@tonic-gate static int 27467c478bd9Sstevel@tonic-gate udp_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp) 27477c478bd9Sstevel@tonic-gate { 27487c478bd9Sstevel@tonic-gate int err; 27497c478bd9Sstevel@tonic-gate udp_t *udp; 2750ff550d0eSmasputra conn_t *connp; 2751ff550d0eSmasputra zoneid_t zoneid = getzoneid(); 2752ff550d0eSmasputra queue_t *ip_wq; 2753ff550d0eSmasputra char *name; 27547c478bd9Sstevel@tonic-gate 27557c478bd9Sstevel@tonic-gate TRACE_1(TR_FAC_UDP, TR_UDP_OPEN, "udp_open: q %p", q); 27567c478bd9Sstevel@tonic-gate 27577c478bd9Sstevel@tonic-gate /* If the stream is already open, return immediately. */ 27587c478bd9Sstevel@tonic-gate if (q->q_ptr != NULL) 27597c478bd9Sstevel@tonic-gate return (0); 27607c478bd9Sstevel@tonic-gate 27617c478bd9Sstevel@tonic-gate /* If this is not a push of udp as a module, fail. */ 27627c478bd9Sstevel@tonic-gate if (sflag != MODOPEN) 27637c478bd9Sstevel@tonic-gate return (EINVAL); 27647c478bd9Sstevel@tonic-gate 2765ff550d0eSmasputra q->q_hiwat = udp_recv_hiwat; 2766ff550d0eSmasputra WR(q)->q_hiwat = udp_xmit_hiwat; 2767ff550d0eSmasputra WR(q)->q_lowat = udp_xmit_lowat; 2768ff550d0eSmasputra 2769ff550d0eSmasputra /* Insert ourselves in the stream since we're about to walk q_next */ 2770ff550d0eSmasputra qprocson(q); 2771ff550d0eSmasputra 2772ff550d0eSmasputra udp = kmem_cache_alloc(udp_cache, KM_SLEEP); 2773ff550d0eSmasputra bzero(udp, sizeof (*udp)); 2774ff550d0eSmasputra 2775ff550d0eSmasputra /* 2776ff550d0eSmasputra * UDP is supported only as a module and it has to be pushed directly 2777ff550d0eSmasputra * above the device instance of IP. If UDP is pushed anywhere else 2778ff550d0eSmasputra * on a stream, it will support just T_SVR4_OPTMGMT_REQ for the 2779ff550d0eSmasputra * sake of MIB browsers and fail everything else. 2780ff550d0eSmasputra */ 2781ff550d0eSmasputra ip_wq = WR(q)->q_next; 2782ff550d0eSmasputra if (ip_wq->q_next != NULL || 2783ff550d0eSmasputra (name = ip_wq->q_qinfo->qi_minfo->mi_idname) == NULL || 2784ff550d0eSmasputra strcmp(name, IP_MOD_NAME) != 0 || 2785ff550d0eSmasputra ip_wq->q_qinfo->qi_minfo->mi_idnum != IP_MOD_ID) { 2786ff550d0eSmasputra /* Support just SNMP for MIB browsers */ 2787ff550d0eSmasputra connp = ipcl_conn_create(IPCL_IPCCONN, KM_SLEEP); 2788ff550d0eSmasputra connp->conn_rq = q; 2789ff550d0eSmasputra connp->conn_wq = WR(q); 2790ff550d0eSmasputra connp->conn_flags |= IPCL_UDPMOD; 2791ff550d0eSmasputra connp->conn_cred = credp; 2792ff550d0eSmasputra connp->conn_zoneid = zoneid; 2793ff550d0eSmasputra connp->conn_udp = udp; 2794ff550d0eSmasputra udp->udp_connp = connp; 2795ff550d0eSmasputra q->q_ptr = WR(q)->q_ptr = connp; 2796ff550d0eSmasputra crhold(credp); 2797ff550d0eSmasputra q->q_qinfo = &udp_snmp_rinit; 2798ff550d0eSmasputra WR(q)->q_qinfo = &udp_snmp_winit; 2799ff550d0eSmasputra return (0); 2800ff550d0eSmasputra } 2801ff550d0eSmasputra 28027c478bd9Sstevel@tonic-gate /* 2803ff550d0eSmasputra * Initialize the udp_t structure for this stream. 28047c478bd9Sstevel@tonic-gate */ 2805ff550d0eSmasputra q = RD(ip_wq); 2806ff550d0eSmasputra connp = Q_TO_CONN(q); 2807ff550d0eSmasputra mutex_enter(&connp->conn_lock); 2808ff550d0eSmasputra connp->conn_proto = IPPROTO_UDP; 2809ff550d0eSmasputra connp->conn_flags |= IPCL_UDP; 2810ff550d0eSmasputra connp->conn_sqp = IP_SQUEUE_GET(lbolt); 2811ff550d0eSmasputra connp->conn_udp = udp; 28127c478bd9Sstevel@tonic-gate 28137c478bd9Sstevel@tonic-gate /* Set the initial state of the stream and the privilege status. */ 2814ff550d0eSmasputra udp->udp_connp = connp; 28157c478bd9Sstevel@tonic-gate udp->udp_state = TS_UNBND; 2816ff550d0eSmasputra udp->udp_mode = UDP_MT_HOT; 28177c478bd9Sstevel@tonic-gate if (getmajor(*devp) == (major_t)UDP6_MAJ) { 28187c478bd9Sstevel@tonic-gate udp->udp_family = AF_INET6; 28197c478bd9Sstevel@tonic-gate udp->udp_ipversion = IPV6_VERSION; 28207c478bd9Sstevel@tonic-gate udp->udp_max_hdr_len = IPV6_HDR_LEN + UDPH_SIZE; 28217c478bd9Sstevel@tonic-gate udp->udp_ttl = udp_ipv6_hoplimit; 2822ff550d0eSmasputra connp->conn_af_isv6 = B_TRUE; 2823ff550d0eSmasputra connp->conn_flags |= IPCL_ISV6; 28247c478bd9Sstevel@tonic-gate } else { 28257c478bd9Sstevel@tonic-gate udp->udp_family = AF_INET; 28267c478bd9Sstevel@tonic-gate udp->udp_ipversion = IPV4_VERSION; 28277c478bd9Sstevel@tonic-gate udp->udp_max_hdr_len = IP_SIMPLE_HDR_LENGTH + UDPH_SIZE; 28287c478bd9Sstevel@tonic-gate udp->udp_ttl = udp_ipv4_ttl; 2829ff550d0eSmasputra connp->conn_af_isv6 = B_FALSE; 2830ff550d0eSmasputra connp->conn_flags &= ~IPCL_ISV6; 28317c478bd9Sstevel@tonic-gate } 28327c478bd9Sstevel@tonic-gate 28337c478bd9Sstevel@tonic-gate udp->udp_multicast_ttl = IP_DEFAULT_MULTICAST_TTL; 2834ff550d0eSmasputra connp->conn_multicast_loop = IP_DEFAULT_MULTICAST_LOOP; 2835ff550d0eSmasputra connp->conn_zoneid = zoneid; 28367c478bd9Sstevel@tonic-gate 2837ff550d0eSmasputra if (connp->conn_flags & IPCL_SOCKET) { 2838ff550d0eSmasputra udp->udp_issocket = B_TRUE; 2839ff550d0eSmasputra udp->udp_direct_sockfs = B_TRUE; 2840ff550d0eSmasputra } 2841ff550d0eSmasputra mutex_exit(&connp->conn_lock); 28427c478bd9Sstevel@tonic-gate 28437c478bd9Sstevel@tonic-gate /* 28447c478bd9Sstevel@tonic-gate * The transmit hiwat/lowat is only looked at on IP's queue. 2845ff550d0eSmasputra * Store in q_hiwat in order to return on SO_SNDBUF/SO_RCVBUF 28467c478bd9Sstevel@tonic-gate * getsockopts. 28477c478bd9Sstevel@tonic-gate */ 2848ff550d0eSmasputra q->q_hiwat = udp_recv_hiwat; 28497c478bd9Sstevel@tonic-gate WR(q)->q_hiwat = udp_xmit_hiwat; 28507c478bd9Sstevel@tonic-gate WR(q)->q_lowat = udp_xmit_lowat; 28517c478bd9Sstevel@tonic-gate 28527c478bd9Sstevel@tonic-gate if (udp->udp_family == AF_INET6) { 28537c478bd9Sstevel@tonic-gate /* Build initial header template for transmit */ 28547c478bd9Sstevel@tonic-gate if ((err = udp_build_hdrs(q, udp)) != 0) { 2855ff550d0eSmasputra qprocsoff(UDP_RD(q)); 2856ff550d0eSmasputra udp->udp_connp = NULL; 2857ff550d0eSmasputra connp->conn_udp = NULL; 2858ff550d0eSmasputra kmem_cache_free(udp_cache, udp); 2859ff550d0eSmasputra return (err); 28607c478bd9Sstevel@tonic-gate } 28617c478bd9Sstevel@tonic-gate } 28627c478bd9Sstevel@tonic-gate 2863ff550d0eSmasputra /* Set the Stream head write offset and high watermark. */ 2864ff550d0eSmasputra (void) mi_set_sth_wroff(UDP_RD(q), 2865ff550d0eSmasputra udp->udp_max_hdr_len + udp_wroff_extra); 2866ff550d0eSmasputra (void) mi_set_sth_hiwat(UDP_RD(q), udp_set_rcv_hiwat(udp, q->q_hiwat)); 28677c478bd9Sstevel@tonic-gate 2868d045b987Smasputra WR(UDP_RD(q))->q_qinfo = &udp_winit; 2869d045b987Smasputra 2870ff550d0eSmasputra return (0); 28717c478bd9Sstevel@tonic-gate } 28727c478bd9Sstevel@tonic-gate 28737c478bd9Sstevel@tonic-gate /* 28747c478bd9Sstevel@tonic-gate * Which UDP options OK to set through T_UNITDATA_REQ... 28757c478bd9Sstevel@tonic-gate */ 28767c478bd9Sstevel@tonic-gate /* ARGSUSED */ 28777c478bd9Sstevel@tonic-gate static boolean_t 28787c478bd9Sstevel@tonic-gate udp_opt_allow_udr_set(t_scalar_t level, t_scalar_t name) 28797c478bd9Sstevel@tonic-gate { 28807c478bd9Sstevel@tonic-gate return (B_TRUE); 28817c478bd9Sstevel@tonic-gate } 28827c478bd9Sstevel@tonic-gate 28837c478bd9Sstevel@tonic-gate /* 28847c478bd9Sstevel@tonic-gate * This routine gets default values of certain options whose default 28857c478bd9Sstevel@tonic-gate * values are maintained by protcol specific code 28867c478bd9Sstevel@tonic-gate */ 28877c478bd9Sstevel@tonic-gate /* ARGSUSED */ 28887c478bd9Sstevel@tonic-gate int 28897c478bd9Sstevel@tonic-gate udp_opt_default(queue_t *q, t_scalar_t level, t_scalar_t name, uchar_t *ptr) 28907c478bd9Sstevel@tonic-gate { 28917c478bd9Sstevel@tonic-gate int *i1 = (int *)ptr; 28927c478bd9Sstevel@tonic-gate 28937c478bd9Sstevel@tonic-gate switch (level) { 28947c478bd9Sstevel@tonic-gate case IPPROTO_IP: 28957c478bd9Sstevel@tonic-gate switch (name) { 28967c478bd9Sstevel@tonic-gate case IP_MULTICAST_TTL: 28977c478bd9Sstevel@tonic-gate *ptr = (uchar_t)IP_DEFAULT_MULTICAST_TTL; 28987c478bd9Sstevel@tonic-gate return (sizeof (uchar_t)); 28997c478bd9Sstevel@tonic-gate case IP_MULTICAST_LOOP: 29007c478bd9Sstevel@tonic-gate *ptr = (uchar_t)IP_DEFAULT_MULTICAST_LOOP; 29017c478bd9Sstevel@tonic-gate return (sizeof (uchar_t)); 29027c478bd9Sstevel@tonic-gate } 29037c478bd9Sstevel@tonic-gate break; 29047c478bd9Sstevel@tonic-gate case IPPROTO_IPV6: 29057c478bd9Sstevel@tonic-gate switch (name) { 29067c478bd9Sstevel@tonic-gate case IPV6_MULTICAST_HOPS: 29077c478bd9Sstevel@tonic-gate *i1 = IP_DEFAULT_MULTICAST_TTL; 29087c478bd9Sstevel@tonic-gate return (sizeof (int)); 29097c478bd9Sstevel@tonic-gate case IPV6_MULTICAST_LOOP: 29107c478bd9Sstevel@tonic-gate *i1 = IP_DEFAULT_MULTICAST_LOOP; 29117c478bd9Sstevel@tonic-gate return (sizeof (int)); 29127c478bd9Sstevel@tonic-gate case IPV6_UNICAST_HOPS: 29137c478bd9Sstevel@tonic-gate *i1 = udp_ipv6_hoplimit; 29147c478bd9Sstevel@tonic-gate return (sizeof (int)); 29157c478bd9Sstevel@tonic-gate } 29167c478bd9Sstevel@tonic-gate break; 29177c478bd9Sstevel@tonic-gate } 29187c478bd9Sstevel@tonic-gate return (-1); 29197c478bd9Sstevel@tonic-gate } 29207c478bd9Sstevel@tonic-gate 29217c478bd9Sstevel@tonic-gate /* 2922ff550d0eSmasputra * This routine retrieves the current status of socket options 2923ff550d0eSmasputra * and expects the caller to pass in the queue pointer of the 2924ff550d0eSmasputra * upper instance. It returns the size of the option retrieved. 29257c478bd9Sstevel@tonic-gate */ 29267c478bd9Sstevel@tonic-gate int 29277c478bd9Sstevel@tonic-gate udp_opt_get(queue_t *q, t_scalar_t level, t_scalar_t name, uchar_t *ptr) 29287c478bd9Sstevel@tonic-gate { 29297c478bd9Sstevel@tonic-gate int *i1 = (int *)ptr; 2930ff550d0eSmasputra conn_t *connp; 2931ff550d0eSmasputra udp_t *udp; 2932ff550d0eSmasputra ip6_pkt_t *ipp; 2933ff550d0eSmasputra 2934ff550d0eSmasputra q = UDP_WR(q); 2935ff550d0eSmasputra connp = Q_TO_CONN(q); 2936ff550d0eSmasputra udp = connp->conn_udp; 2937ff550d0eSmasputra ipp = &udp->udp_sticky_ipp; 29387c478bd9Sstevel@tonic-gate 29397c478bd9Sstevel@tonic-gate switch (level) { 29407c478bd9Sstevel@tonic-gate case SOL_SOCKET: 29417c478bd9Sstevel@tonic-gate switch (name) { 29427c478bd9Sstevel@tonic-gate case SO_DEBUG: 29437c478bd9Sstevel@tonic-gate *i1 = udp->udp_debug; 29447c478bd9Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 29457c478bd9Sstevel@tonic-gate case SO_REUSEADDR: 29467c478bd9Sstevel@tonic-gate *i1 = udp->udp_reuseaddr; 29477c478bd9Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 29487c478bd9Sstevel@tonic-gate case SO_TYPE: 29497c478bd9Sstevel@tonic-gate *i1 = SOCK_DGRAM; 29507c478bd9Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 29517c478bd9Sstevel@tonic-gate 29527c478bd9Sstevel@tonic-gate /* 29537c478bd9Sstevel@tonic-gate * The following three items are available here, 29547c478bd9Sstevel@tonic-gate * but are only meaningful to IP. 29557c478bd9Sstevel@tonic-gate */ 29567c478bd9Sstevel@tonic-gate case SO_DONTROUTE: 29577c478bd9Sstevel@tonic-gate *i1 = udp->udp_dontroute; 29587c478bd9Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 29597c478bd9Sstevel@tonic-gate case SO_USELOOPBACK: 29607c478bd9Sstevel@tonic-gate *i1 = udp->udp_useloopback; 29617c478bd9Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 29627c478bd9Sstevel@tonic-gate case SO_BROADCAST: 29637c478bd9Sstevel@tonic-gate *i1 = udp->udp_broadcast; 29647c478bd9Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 29657c478bd9Sstevel@tonic-gate 29667c478bd9Sstevel@tonic-gate case SO_SNDBUF: 29677c478bd9Sstevel@tonic-gate *i1 = q->q_hiwat; 29687c478bd9Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 29697c478bd9Sstevel@tonic-gate case SO_RCVBUF: 29707c478bd9Sstevel@tonic-gate *i1 = RD(q)->q_hiwat; 29717c478bd9Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 29727c478bd9Sstevel@tonic-gate case SO_DGRAM_ERRIND: 29737c478bd9Sstevel@tonic-gate *i1 = udp->udp_dgram_errind; 29747c478bd9Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 29757c478bd9Sstevel@tonic-gate case SO_RECVUCRED: 29767c478bd9Sstevel@tonic-gate *i1 = udp->udp_recvucred; 29777c478bd9Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 29787c478bd9Sstevel@tonic-gate default: 29797c478bd9Sstevel@tonic-gate return (-1); 29807c478bd9Sstevel@tonic-gate } 29817c478bd9Sstevel@tonic-gate break; 29827c478bd9Sstevel@tonic-gate case IPPROTO_IP: 29837c478bd9Sstevel@tonic-gate if (udp->udp_family != AF_INET) 29847c478bd9Sstevel@tonic-gate return (-1); 29857c478bd9Sstevel@tonic-gate switch (name) { 29867c478bd9Sstevel@tonic-gate case IP_OPTIONS: 29877c478bd9Sstevel@tonic-gate case T_IP_OPTIONS: 29887c478bd9Sstevel@tonic-gate if (udp->udp_ip_rcv_options_len) 29897c478bd9Sstevel@tonic-gate bcopy(udp->udp_ip_rcv_options, ptr, 29907c478bd9Sstevel@tonic-gate udp->udp_ip_rcv_options_len); 29917c478bd9Sstevel@tonic-gate return (udp->udp_ip_rcv_options_len); 29927c478bd9Sstevel@tonic-gate case IP_TOS: 29937c478bd9Sstevel@tonic-gate case T_IP_TOS: 29947c478bd9Sstevel@tonic-gate *i1 = (int)udp->udp_type_of_service; 29957c478bd9Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 29967c478bd9Sstevel@tonic-gate case IP_TTL: 29977c478bd9Sstevel@tonic-gate *i1 = (int)udp->udp_ttl; 29987c478bd9Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 299943d18f1cSpriyanka case IP_NEXTHOP: 300043d18f1cSpriyanka /* Handled at IP level */ 300143d18f1cSpriyanka return (-EINVAL); 30027c478bd9Sstevel@tonic-gate case IP_MULTICAST_IF: 30037c478bd9Sstevel@tonic-gate /* 0 address if not set */ 30047c478bd9Sstevel@tonic-gate *(ipaddr_t *)ptr = udp->udp_multicast_if_addr; 30057c478bd9Sstevel@tonic-gate return (sizeof (ipaddr_t)); 30067c478bd9Sstevel@tonic-gate case IP_MULTICAST_TTL: 30077c478bd9Sstevel@tonic-gate *(uchar_t *)ptr = udp->udp_multicast_ttl; 30087c478bd9Sstevel@tonic-gate return (sizeof (uchar_t)); 30097c478bd9Sstevel@tonic-gate case IP_MULTICAST_LOOP: 3010ff550d0eSmasputra *ptr = connp->conn_multicast_loop; 30117c478bd9Sstevel@tonic-gate return (sizeof (uint8_t)); 30127c478bd9Sstevel@tonic-gate case IP_RECVOPTS: 30137c478bd9Sstevel@tonic-gate *i1 = udp->udp_recvopts; 30147c478bd9Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 30157c478bd9Sstevel@tonic-gate case IP_RECVDSTADDR: 30167c478bd9Sstevel@tonic-gate *i1 = udp->udp_recvdstaddr; 30177c478bd9Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 30187c478bd9Sstevel@tonic-gate case IP_RECVIF: 30197c478bd9Sstevel@tonic-gate *i1 = udp->udp_recvif; 30207c478bd9Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 30217c478bd9Sstevel@tonic-gate case IP_RECVSLLA: 30227c478bd9Sstevel@tonic-gate *i1 = udp->udp_recvslla; 30237c478bd9Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 30247c478bd9Sstevel@tonic-gate case IP_RECVTTL: 30257c478bd9Sstevel@tonic-gate *i1 = udp->udp_recvttl; 30267c478bd9Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 30277c478bd9Sstevel@tonic-gate case IP_ADD_MEMBERSHIP: 30287c478bd9Sstevel@tonic-gate case IP_DROP_MEMBERSHIP: 30297c478bd9Sstevel@tonic-gate case IP_BLOCK_SOURCE: 30307c478bd9Sstevel@tonic-gate case IP_UNBLOCK_SOURCE: 30317c478bd9Sstevel@tonic-gate case IP_ADD_SOURCE_MEMBERSHIP: 30327c478bd9Sstevel@tonic-gate case IP_DROP_SOURCE_MEMBERSHIP: 30337c478bd9Sstevel@tonic-gate case MCAST_JOIN_GROUP: 30347c478bd9Sstevel@tonic-gate case MCAST_LEAVE_GROUP: 30357c478bd9Sstevel@tonic-gate case MCAST_BLOCK_SOURCE: 30367c478bd9Sstevel@tonic-gate case MCAST_UNBLOCK_SOURCE: 30377c478bd9Sstevel@tonic-gate case MCAST_JOIN_SOURCE_GROUP: 30387c478bd9Sstevel@tonic-gate case MCAST_LEAVE_SOURCE_GROUP: 30397c478bd9Sstevel@tonic-gate case IP_DONTFAILOVER_IF: 30407c478bd9Sstevel@tonic-gate /* cannot "get" the value for these */ 30417c478bd9Sstevel@tonic-gate return (-1); 30427c478bd9Sstevel@tonic-gate case IP_BOUND_IF: 30437c478bd9Sstevel@tonic-gate /* Zero if not set */ 30447c478bd9Sstevel@tonic-gate *i1 = udp->udp_bound_if; 30457c478bd9Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 30467c478bd9Sstevel@tonic-gate case IP_UNSPEC_SRC: 30477c478bd9Sstevel@tonic-gate *i1 = udp->udp_unspec_source; 30487c478bd9Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 30497c478bd9Sstevel@tonic-gate case IP_XMIT_IF: 30507c478bd9Sstevel@tonic-gate *i1 = udp->udp_xmit_if; 30517c478bd9Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 30527c478bd9Sstevel@tonic-gate default: 30537c478bd9Sstevel@tonic-gate return (-1); 30547c478bd9Sstevel@tonic-gate } 30557c478bd9Sstevel@tonic-gate break; 30567c478bd9Sstevel@tonic-gate case IPPROTO_IPV6: 30577c478bd9Sstevel@tonic-gate if (udp->udp_family != AF_INET6) 30587c478bd9Sstevel@tonic-gate return (-1); 30597c478bd9Sstevel@tonic-gate switch (name) { 30607c478bd9Sstevel@tonic-gate case IPV6_UNICAST_HOPS: 30617c478bd9Sstevel@tonic-gate *i1 = (unsigned int)udp->udp_ttl; 30627c478bd9Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 30637c478bd9Sstevel@tonic-gate case IPV6_MULTICAST_IF: 30647c478bd9Sstevel@tonic-gate /* 0 index if not set */ 30657c478bd9Sstevel@tonic-gate *i1 = udp->udp_multicast_if_index; 30667c478bd9Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 30677c478bd9Sstevel@tonic-gate case IPV6_MULTICAST_HOPS: 30687c478bd9Sstevel@tonic-gate *i1 = udp->udp_multicast_ttl; 30697c478bd9Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 30707c478bd9Sstevel@tonic-gate case IPV6_MULTICAST_LOOP: 3071ff550d0eSmasputra *i1 = connp->conn_multicast_loop; 30727c478bd9Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 30737c478bd9Sstevel@tonic-gate case IPV6_JOIN_GROUP: 30747c478bd9Sstevel@tonic-gate case IPV6_LEAVE_GROUP: 30757c478bd9Sstevel@tonic-gate case MCAST_JOIN_GROUP: 30767c478bd9Sstevel@tonic-gate case MCAST_LEAVE_GROUP: 30777c478bd9Sstevel@tonic-gate case MCAST_BLOCK_SOURCE: 30787c478bd9Sstevel@tonic-gate case MCAST_UNBLOCK_SOURCE: 30797c478bd9Sstevel@tonic-gate case MCAST_JOIN_SOURCE_GROUP: 30807c478bd9Sstevel@tonic-gate case MCAST_LEAVE_SOURCE_GROUP: 30817c478bd9Sstevel@tonic-gate /* cannot "get" the value for these */ 30827c478bd9Sstevel@tonic-gate return (-1); 30837c478bd9Sstevel@tonic-gate case IPV6_BOUND_IF: 30847c478bd9Sstevel@tonic-gate /* Zero if not set */ 30857c478bd9Sstevel@tonic-gate *i1 = udp->udp_bound_if; 30867c478bd9Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 30877c478bd9Sstevel@tonic-gate case IPV6_UNSPEC_SRC: 30887c478bd9Sstevel@tonic-gate *i1 = udp->udp_unspec_source; 30897c478bd9Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 30907c478bd9Sstevel@tonic-gate case IPV6_RECVPKTINFO: 30917c478bd9Sstevel@tonic-gate *i1 = udp->udp_ipv6_recvpktinfo; 30927c478bd9Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 30937c478bd9Sstevel@tonic-gate case IPV6_RECVTCLASS: 30947c478bd9Sstevel@tonic-gate *i1 = udp->udp_ipv6_recvtclass; 30957c478bd9Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 30967c478bd9Sstevel@tonic-gate case IPV6_RECVPATHMTU: 30977c478bd9Sstevel@tonic-gate *i1 = udp->udp_ipv6_recvpathmtu; 30987c478bd9Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 30997c478bd9Sstevel@tonic-gate case IPV6_RECVHOPLIMIT: 31007c478bd9Sstevel@tonic-gate *i1 = udp->udp_ipv6_recvhoplimit; 31017c478bd9Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 31027c478bd9Sstevel@tonic-gate case IPV6_RECVHOPOPTS: 31037c478bd9Sstevel@tonic-gate *i1 = udp->udp_ipv6_recvhopopts; 31047c478bd9Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 31057c478bd9Sstevel@tonic-gate case IPV6_RECVDSTOPTS: 31067c478bd9Sstevel@tonic-gate *i1 = udp->udp_ipv6_recvdstopts; 31077c478bd9Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 31087c478bd9Sstevel@tonic-gate case _OLD_IPV6_RECVDSTOPTS: 31097c478bd9Sstevel@tonic-gate *i1 = udp->udp_old_ipv6_recvdstopts; 31107c478bd9Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 31117c478bd9Sstevel@tonic-gate case IPV6_RECVRTHDRDSTOPTS: 31127c478bd9Sstevel@tonic-gate *i1 = udp->udp_ipv6_recvrthdrdstopts; 31137c478bd9Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 31147c478bd9Sstevel@tonic-gate case IPV6_RECVRTHDR: 31157c478bd9Sstevel@tonic-gate *i1 = udp->udp_ipv6_recvrthdr; 31167c478bd9Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 31177c478bd9Sstevel@tonic-gate case IPV6_PKTINFO: { 31187c478bd9Sstevel@tonic-gate /* XXX assumes that caller has room for max size! */ 31197c478bd9Sstevel@tonic-gate struct in6_pktinfo *pkti; 31207c478bd9Sstevel@tonic-gate 31217c478bd9Sstevel@tonic-gate pkti = (struct in6_pktinfo *)ptr; 31227c478bd9Sstevel@tonic-gate if (ipp->ipp_fields & IPPF_IFINDEX) 31237c478bd9Sstevel@tonic-gate pkti->ipi6_ifindex = ipp->ipp_ifindex; 31247c478bd9Sstevel@tonic-gate else 31257c478bd9Sstevel@tonic-gate pkti->ipi6_ifindex = 0; 31267c478bd9Sstevel@tonic-gate if (ipp->ipp_fields & IPPF_ADDR) 31277c478bd9Sstevel@tonic-gate pkti->ipi6_addr = ipp->ipp_addr; 31287c478bd9Sstevel@tonic-gate else 31297c478bd9Sstevel@tonic-gate pkti->ipi6_addr = ipv6_all_zeros; 31307c478bd9Sstevel@tonic-gate return (sizeof (struct in6_pktinfo)); 31317c478bd9Sstevel@tonic-gate } 31327c478bd9Sstevel@tonic-gate case IPV6_TCLASS: 31337c478bd9Sstevel@tonic-gate if (ipp->ipp_fields & IPPF_TCLASS) 31347c478bd9Sstevel@tonic-gate *i1 = ipp->ipp_tclass; 31357c478bd9Sstevel@tonic-gate else 31367c478bd9Sstevel@tonic-gate *i1 = IPV6_FLOW_TCLASS( 31377c478bd9Sstevel@tonic-gate IPV6_DEFAULT_VERS_AND_FLOW); 31387c478bd9Sstevel@tonic-gate break; /* goto sizeof (int) option return */ 31397c478bd9Sstevel@tonic-gate case IPV6_NEXTHOP: { 31407c478bd9Sstevel@tonic-gate sin6_t *sin6 = (sin6_t *)ptr; 31417c478bd9Sstevel@tonic-gate 31427c478bd9Sstevel@tonic-gate if (!(ipp->ipp_fields & IPPF_NEXTHOP)) 31437c478bd9Sstevel@tonic-gate return (0); 31447c478bd9Sstevel@tonic-gate *sin6 = sin6_null; 31457c478bd9Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 31467c478bd9Sstevel@tonic-gate sin6->sin6_addr = ipp->ipp_nexthop; 31477c478bd9Sstevel@tonic-gate return (sizeof (sin6_t)); 31487c478bd9Sstevel@tonic-gate } 31497c478bd9Sstevel@tonic-gate case IPV6_HOPOPTS: 31507c478bd9Sstevel@tonic-gate if (!(ipp->ipp_fields & IPPF_HOPOPTS)) 31517c478bd9Sstevel@tonic-gate return (0); 31527c478bd9Sstevel@tonic-gate bcopy(ipp->ipp_hopopts, ptr, ipp->ipp_hopoptslen); 31537c478bd9Sstevel@tonic-gate return (ipp->ipp_hopoptslen); 31547c478bd9Sstevel@tonic-gate case IPV6_RTHDRDSTOPTS: 31557c478bd9Sstevel@tonic-gate if (!(ipp->ipp_fields & IPPF_RTDSTOPTS)) 31567c478bd9Sstevel@tonic-gate return (0); 31577c478bd9Sstevel@tonic-gate bcopy(ipp->ipp_rtdstopts, ptr, ipp->ipp_rtdstoptslen); 31587c478bd9Sstevel@tonic-gate return (ipp->ipp_rtdstoptslen); 31597c478bd9Sstevel@tonic-gate case IPV6_RTHDR: 31607c478bd9Sstevel@tonic-gate if (!(ipp->ipp_fields & IPPF_RTHDR)) 31617c478bd9Sstevel@tonic-gate return (0); 31627c478bd9Sstevel@tonic-gate bcopy(ipp->ipp_rthdr, ptr, ipp->ipp_rthdrlen); 31637c478bd9Sstevel@tonic-gate return (ipp->ipp_rthdrlen); 31647c478bd9Sstevel@tonic-gate case IPV6_DSTOPTS: 31657c478bd9Sstevel@tonic-gate if (!(ipp->ipp_fields & IPPF_DSTOPTS)) 31667c478bd9Sstevel@tonic-gate return (0); 31677c478bd9Sstevel@tonic-gate bcopy(ipp->ipp_dstopts, ptr, ipp->ipp_dstoptslen); 31687c478bd9Sstevel@tonic-gate return (ipp->ipp_dstoptslen); 31697c478bd9Sstevel@tonic-gate case IPV6_PATHMTU: 31707c478bd9Sstevel@tonic-gate return (ip_fill_mtuinfo(&udp->udp_v6dst, 31717c478bd9Sstevel@tonic-gate udp->udp_dstport, (struct ip6_mtuinfo *)ptr)); 31727c478bd9Sstevel@tonic-gate default: 31737c478bd9Sstevel@tonic-gate return (-1); 31747c478bd9Sstevel@tonic-gate } 31757c478bd9Sstevel@tonic-gate break; 31767c478bd9Sstevel@tonic-gate case IPPROTO_UDP: 31777c478bd9Sstevel@tonic-gate switch (name) { 31787c478bd9Sstevel@tonic-gate case UDP_ANONPRIVBIND: 31797c478bd9Sstevel@tonic-gate *i1 = udp->udp_anon_priv_bind; 31807c478bd9Sstevel@tonic-gate break; 31817c478bd9Sstevel@tonic-gate case UDP_EXCLBIND: 31827c478bd9Sstevel@tonic-gate *i1 = udp->udp_exclbind ? UDP_EXCLBIND : 0; 31837c478bd9Sstevel@tonic-gate break; 31847c478bd9Sstevel@tonic-gate case UDP_RCVHDR: 31857c478bd9Sstevel@tonic-gate *i1 = udp->udp_rcvhdr ? 1 : 0; 31867c478bd9Sstevel@tonic-gate break; 31877c478bd9Sstevel@tonic-gate default: 31887c478bd9Sstevel@tonic-gate return (-1); 31897c478bd9Sstevel@tonic-gate } 31907c478bd9Sstevel@tonic-gate break; 31917c478bd9Sstevel@tonic-gate default: 31927c478bd9Sstevel@tonic-gate return (-1); 31937c478bd9Sstevel@tonic-gate } 31947c478bd9Sstevel@tonic-gate return (sizeof (int)); 31957c478bd9Sstevel@tonic-gate } 31967c478bd9Sstevel@tonic-gate 3197ff550d0eSmasputra /* 3198ff550d0eSmasputra * This routine sets socket options; it expects the caller 3199ff550d0eSmasputra * to pass in the queue pointer of the upper instance. 3200ff550d0eSmasputra */ 32017c478bd9Sstevel@tonic-gate /* ARGSUSED */ 32027c478bd9Sstevel@tonic-gate int 32037c478bd9Sstevel@tonic-gate udp_opt_set(queue_t *q, uint_t optset_context, int level, 32047c478bd9Sstevel@tonic-gate int name, uint_t inlen, uchar_t *invalp, uint_t *outlenp, 32057c478bd9Sstevel@tonic-gate uchar_t *outvalp, void *thisdg_attrs, cred_t *cr, mblk_t *mblk) 32067c478bd9Sstevel@tonic-gate { 32077c478bd9Sstevel@tonic-gate int *i1 = (int *)invalp; 32087c478bd9Sstevel@tonic-gate boolean_t onoff = (*i1 == 0) ? 0 : 1; 32097c478bd9Sstevel@tonic-gate boolean_t checkonly; 32107c478bd9Sstevel@tonic-gate int error; 3211ff550d0eSmasputra conn_t *connp; 3212ff550d0eSmasputra udp_t *udp; 3213ff550d0eSmasputra 3214ff550d0eSmasputra q = UDP_WR(q); 3215ff550d0eSmasputra connp = Q_TO_CONN(q); 3216ff550d0eSmasputra udp = connp->conn_udp; 32177c478bd9Sstevel@tonic-gate 32187c478bd9Sstevel@tonic-gate switch (optset_context) { 32197c478bd9Sstevel@tonic-gate case SETFN_OPTCOM_CHECKONLY: 32207c478bd9Sstevel@tonic-gate checkonly = B_TRUE; 32217c478bd9Sstevel@tonic-gate /* 32227c478bd9Sstevel@tonic-gate * Note: Implies T_CHECK semantics for T_OPTCOM_REQ 32237c478bd9Sstevel@tonic-gate * inlen != 0 implies value supplied and 32247c478bd9Sstevel@tonic-gate * we have to "pretend" to set it. 32257c478bd9Sstevel@tonic-gate * inlen == 0 implies that there is no 32267c478bd9Sstevel@tonic-gate * value part in T_CHECK request and just validation 32277c478bd9Sstevel@tonic-gate * done elsewhere should be enough, we just return here. 32287c478bd9Sstevel@tonic-gate */ 32297c478bd9Sstevel@tonic-gate if (inlen == 0) { 32307c478bd9Sstevel@tonic-gate *outlenp = 0; 32317c478bd9Sstevel@tonic-gate return (0); 32327c478bd9Sstevel@tonic-gate } 32337c478bd9Sstevel@tonic-gate break; 32347c478bd9Sstevel@tonic-gate case SETFN_OPTCOM_NEGOTIATE: 32357c478bd9Sstevel@tonic-gate checkonly = B_FALSE; 32367c478bd9Sstevel@tonic-gate break; 32377c478bd9Sstevel@tonic-gate case SETFN_UD_NEGOTIATE: 32387c478bd9Sstevel@tonic-gate case SETFN_CONN_NEGOTIATE: 32397c478bd9Sstevel@tonic-gate checkonly = B_FALSE; 32407c478bd9Sstevel@tonic-gate /* 32417c478bd9Sstevel@tonic-gate * Negotiating local and "association-related" options 32427c478bd9Sstevel@tonic-gate * through T_UNITDATA_REQ. 32437c478bd9Sstevel@tonic-gate * 32447c478bd9Sstevel@tonic-gate * Following routine can filter out ones we do not 32457c478bd9Sstevel@tonic-gate * want to be "set" this way. 32467c478bd9Sstevel@tonic-gate */ 32477c478bd9Sstevel@tonic-gate if (!udp_opt_allow_udr_set(level, name)) { 32487c478bd9Sstevel@tonic-gate *outlenp = 0; 32497c478bd9Sstevel@tonic-gate return (EINVAL); 32507c478bd9Sstevel@tonic-gate } 32517c478bd9Sstevel@tonic-gate break; 32527c478bd9Sstevel@tonic-gate default: 32537c478bd9Sstevel@tonic-gate /* 32547c478bd9Sstevel@tonic-gate * We should never get here 32557c478bd9Sstevel@tonic-gate */ 32567c478bd9Sstevel@tonic-gate *outlenp = 0; 32577c478bd9Sstevel@tonic-gate return (EINVAL); 32587c478bd9Sstevel@tonic-gate } 32597c478bd9Sstevel@tonic-gate 32607c478bd9Sstevel@tonic-gate ASSERT((optset_context != SETFN_OPTCOM_CHECKONLY) || 32617c478bd9Sstevel@tonic-gate (optset_context == SETFN_OPTCOM_CHECKONLY && inlen != 0)); 32627c478bd9Sstevel@tonic-gate 32637c478bd9Sstevel@tonic-gate /* 32647c478bd9Sstevel@tonic-gate * For fixed length options, no sanity check 32657c478bd9Sstevel@tonic-gate * of passed in length is done. It is assumed *_optcom_req() 32667c478bd9Sstevel@tonic-gate * routines do the right thing. 32677c478bd9Sstevel@tonic-gate */ 32687c478bd9Sstevel@tonic-gate 32697c478bd9Sstevel@tonic-gate switch (level) { 32707c478bd9Sstevel@tonic-gate case SOL_SOCKET: 32717c478bd9Sstevel@tonic-gate switch (name) { 32727c478bd9Sstevel@tonic-gate case SO_REUSEADDR: 32737c478bd9Sstevel@tonic-gate if (!checkonly) 32747c478bd9Sstevel@tonic-gate udp->udp_reuseaddr = onoff; 32757c478bd9Sstevel@tonic-gate break; 32767c478bd9Sstevel@tonic-gate case SO_DEBUG: 32777c478bd9Sstevel@tonic-gate if (!checkonly) 32787c478bd9Sstevel@tonic-gate udp->udp_debug = onoff; 32797c478bd9Sstevel@tonic-gate break; 32807c478bd9Sstevel@tonic-gate /* 32817c478bd9Sstevel@tonic-gate * The following three items are available here, 32827c478bd9Sstevel@tonic-gate * but are only meaningful to IP. 32837c478bd9Sstevel@tonic-gate */ 32847c478bd9Sstevel@tonic-gate case SO_DONTROUTE: 32857c478bd9Sstevel@tonic-gate if (!checkonly) 32867c478bd9Sstevel@tonic-gate udp->udp_dontroute = onoff; 32877c478bd9Sstevel@tonic-gate break; 32887c478bd9Sstevel@tonic-gate case SO_USELOOPBACK: 32897c478bd9Sstevel@tonic-gate if (!checkonly) 32907c478bd9Sstevel@tonic-gate udp->udp_useloopback = onoff; 32917c478bd9Sstevel@tonic-gate break; 32927c478bd9Sstevel@tonic-gate case SO_BROADCAST: 32937c478bd9Sstevel@tonic-gate if (!checkonly) 32947c478bd9Sstevel@tonic-gate udp->udp_broadcast = onoff; 32957c478bd9Sstevel@tonic-gate break; 32967c478bd9Sstevel@tonic-gate 32977c478bd9Sstevel@tonic-gate case SO_SNDBUF: 32987c478bd9Sstevel@tonic-gate if (*i1 > udp_max_buf) { 32997c478bd9Sstevel@tonic-gate *outlenp = 0; 33007c478bd9Sstevel@tonic-gate return (ENOBUFS); 33017c478bd9Sstevel@tonic-gate } 33027c478bd9Sstevel@tonic-gate if (!checkonly) { 33037c478bd9Sstevel@tonic-gate q->q_hiwat = *i1; 3304ff550d0eSmasputra WR(UDP_RD(q))->q_hiwat = *i1; 33057c478bd9Sstevel@tonic-gate } 33067c478bd9Sstevel@tonic-gate break; 33077c478bd9Sstevel@tonic-gate case SO_RCVBUF: 33087c478bd9Sstevel@tonic-gate if (*i1 > udp_max_buf) { 33097c478bd9Sstevel@tonic-gate *outlenp = 0; 33107c478bd9Sstevel@tonic-gate return (ENOBUFS); 33117c478bd9Sstevel@tonic-gate } 33127c478bd9Sstevel@tonic-gate if (!checkonly) { 33137c478bd9Sstevel@tonic-gate RD(q)->q_hiwat = *i1; 3314ff550d0eSmasputra UDP_RD(q)->q_hiwat = *i1; 3315ff550d0eSmasputra (void) mi_set_sth_hiwat(UDP_RD(q), 3316ff550d0eSmasputra udp_set_rcv_hiwat(udp, *i1)); 33177c478bd9Sstevel@tonic-gate } 33187c478bd9Sstevel@tonic-gate break; 33197c478bd9Sstevel@tonic-gate case SO_DGRAM_ERRIND: 33207c478bd9Sstevel@tonic-gate if (!checkonly) 33217c478bd9Sstevel@tonic-gate udp->udp_dgram_errind = onoff; 33227c478bd9Sstevel@tonic-gate break; 33237c478bd9Sstevel@tonic-gate case SO_RECVUCRED: 33247c478bd9Sstevel@tonic-gate if (!checkonly) 33257c478bd9Sstevel@tonic-gate udp->udp_recvucred = onoff; 33267c478bd9Sstevel@tonic-gate break; 33277c478bd9Sstevel@tonic-gate default: 33287c478bd9Sstevel@tonic-gate *outlenp = 0; 33297c478bd9Sstevel@tonic-gate return (EINVAL); 33307c478bd9Sstevel@tonic-gate } 33317c478bd9Sstevel@tonic-gate break; 33327c478bd9Sstevel@tonic-gate case IPPROTO_IP: 33337c478bd9Sstevel@tonic-gate if (udp->udp_family != AF_INET) { 33347c478bd9Sstevel@tonic-gate *outlenp = 0; 33357c478bd9Sstevel@tonic-gate return (ENOPROTOOPT); 33367c478bd9Sstevel@tonic-gate } 33377c478bd9Sstevel@tonic-gate switch (name) { 33387c478bd9Sstevel@tonic-gate case IP_OPTIONS: 33397c478bd9Sstevel@tonic-gate case T_IP_OPTIONS: 33407c478bd9Sstevel@tonic-gate /* Save options for use by IP. */ 33417c478bd9Sstevel@tonic-gate if (inlen & 0x3) { 33427c478bd9Sstevel@tonic-gate *outlenp = 0; 33437c478bd9Sstevel@tonic-gate return (EINVAL); 33447c478bd9Sstevel@tonic-gate } 33457c478bd9Sstevel@tonic-gate if (checkonly) 33467c478bd9Sstevel@tonic-gate break; 33477c478bd9Sstevel@tonic-gate 33487c478bd9Sstevel@tonic-gate if (udp->udp_ip_snd_options) { 33497c478bd9Sstevel@tonic-gate mi_free((char *)udp->udp_ip_snd_options); 33507c478bd9Sstevel@tonic-gate udp->udp_ip_snd_options_len = 0; 33517c478bd9Sstevel@tonic-gate udp->udp_ip_snd_options = NULL; 33527c478bd9Sstevel@tonic-gate } 33537c478bd9Sstevel@tonic-gate if (inlen) { 33547c478bd9Sstevel@tonic-gate udp->udp_ip_snd_options = 33557c478bd9Sstevel@tonic-gate (uchar_t *)mi_alloc(inlen, BPRI_HI); 33567c478bd9Sstevel@tonic-gate if (udp->udp_ip_snd_options) { 33577c478bd9Sstevel@tonic-gate bcopy(invalp, udp->udp_ip_snd_options, 33587c478bd9Sstevel@tonic-gate inlen); 33597c478bd9Sstevel@tonic-gate udp->udp_ip_snd_options_len = inlen; 33607c478bd9Sstevel@tonic-gate } 33617c478bd9Sstevel@tonic-gate } 33627c478bd9Sstevel@tonic-gate udp->udp_max_hdr_len = IP_SIMPLE_HDR_LENGTH + 33637c478bd9Sstevel@tonic-gate UDPH_SIZE + udp->udp_ip_snd_options_len; 33647c478bd9Sstevel@tonic-gate (void) mi_set_sth_wroff(RD(q), udp->udp_max_hdr_len + 33657c478bd9Sstevel@tonic-gate udp_wroff_extra); 33667c478bd9Sstevel@tonic-gate break; 33677c478bd9Sstevel@tonic-gate case IP_TTL: 33687c478bd9Sstevel@tonic-gate if (!checkonly) { 33697c478bd9Sstevel@tonic-gate udp->udp_ttl = (uchar_t)*i1; 33707c478bd9Sstevel@tonic-gate } 33717c478bd9Sstevel@tonic-gate break; 33727c478bd9Sstevel@tonic-gate case IP_TOS: 33737c478bd9Sstevel@tonic-gate case T_IP_TOS: 33747c478bd9Sstevel@tonic-gate if (!checkonly) { 33757c478bd9Sstevel@tonic-gate udp->udp_type_of_service = (uchar_t)*i1; 33767c478bd9Sstevel@tonic-gate } 33777c478bd9Sstevel@tonic-gate break; 33787c478bd9Sstevel@tonic-gate case IP_MULTICAST_IF: { 33797c478bd9Sstevel@tonic-gate /* 33807c478bd9Sstevel@tonic-gate * TODO should check OPTMGMT reply and undo this if 33817c478bd9Sstevel@tonic-gate * there is an error. 33827c478bd9Sstevel@tonic-gate */ 33837c478bd9Sstevel@tonic-gate struct in_addr *inap = (struct in_addr *)invalp; 33847c478bd9Sstevel@tonic-gate if (!checkonly) { 33857c478bd9Sstevel@tonic-gate udp->udp_multicast_if_addr = 33867c478bd9Sstevel@tonic-gate inap->s_addr; 33877c478bd9Sstevel@tonic-gate } 33887c478bd9Sstevel@tonic-gate break; 33897c478bd9Sstevel@tonic-gate } 33907c478bd9Sstevel@tonic-gate case IP_MULTICAST_TTL: 33917c478bd9Sstevel@tonic-gate if (!checkonly) 33927c478bd9Sstevel@tonic-gate udp->udp_multicast_ttl = *invalp; 33937c478bd9Sstevel@tonic-gate break; 33947c478bd9Sstevel@tonic-gate case IP_MULTICAST_LOOP: 33957c478bd9Sstevel@tonic-gate if (!checkonly) 3396ff550d0eSmasputra connp->conn_multicast_loop = *invalp; 33977c478bd9Sstevel@tonic-gate break; 33987c478bd9Sstevel@tonic-gate case IP_RECVOPTS: 33997c478bd9Sstevel@tonic-gate if (!checkonly) 34007c478bd9Sstevel@tonic-gate udp->udp_recvopts = onoff; 34017c478bd9Sstevel@tonic-gate break; 34027c478bd9Sstevel@tonic-gate case IP_RECVDSTADDR: 34037c478bd9Sstevel@tonic-gate if (!checkonly) 34047c478bd9Sstevel@tonic-gate udp->udp_recvdstaddr = onoff; 34057c478bd9Sstevel@tonic-gate break; 34067c478bd9Sstevel@tonic-gate case IP_RECVIF: 34077c478bd9Sstevel@tonic-gate if (!checkonly) 34087c478bd9Sstevel@tonic-gate udp->udp_recvif = onoff; 34097c478bd9Sstevel@tonic-gate break; 34107c478bd9Sstevel@tonic-gate case IP_RECVSLLA: 34117c478bd9Sstevel@tonic-gate if (!checkonly) 34127c478bd9Sstevel@tonic-gate udp->udp_recvslla = onoff; 34137c478bd9Sstevel@tonic-gate break; 34147c478bd9Sstevel@tonic-gate case IP_RECVTTL: 34157c478bd9Sstevel@tonic-gate if (!checkonly) 34167c478bd9Sstevel@tonic-gate udp->udp_recvttl = onoff; 34177c478bd9Sstevel@tonic-gate break; 34187c478bd9Sstevel@tonic-gate case IP_ADD_MEMBERSHIP: 34197c478bd9Sstevel@tonic-gate case IP_DROP_MEMBERSHIP: 34207c478bd9Sstevel@tonic-gate case IP_BLOCK_SOURCE: 34217c478bd9Sstevel@tonic-gate case IP_UNBLOCK_SOURCE: 34227c478bd9Sstevel@tonic-gate case IP_ADD_SOURCE_MEMBERSHIP: 34237c478bd9Sstevel@tonic-gate case IP_DROP_SOURCE_MEMBERSHIP: 34247c478bd9Sstevel@tonic-gate case MCAST_JOIN_GROUP: 34257c478bd9Sstevel@tonic-gate case MCAST_LEAVE_GROUP: 34267c478bd9Sstevel@tonic-gate case MCAST_BLOCK_SOURCE: 34277c478bd9Sstevel@tonic-gate case MCAST_UNBLOCK_SOURCE: 34287c478bd9Sstevel@tonic-gate case MCAST_JOIN_SOURCE_GROUP: 34297c478bd9Sstevel@tonic-gate case MCAST_LEAVE_SOURCE_GROUP: 34307c478bd9Sstevel@tonic-gate case IP_SEC_OPT: 343143d18f1cSpriyanka case IP_NEXTHOP: 34327c478bd9Sstevel@tonic-gate /* 34337c478bd9Sstevel@tonic-gate * "soft" error (negative) 34347c478bd9Sstevel@tonic-gate * option not handled at this level 34357c478bd9Sstevel@tonic-gate * Do not modify *outlenp. 34367c478bd9Sstevel@tonic-gate */ 34377c478bd9Sstevel@tonic-gate return (-EINVAL); 34387c478bd9Sstevel@tonic-gate case IP_BOUND_IF: 34397c478bd9Sstevel@tonic-gate if (!checkonly) 34407c478bd9Sstevel@tonic-gate udp->udp_bound_if = *i1; 34417c478bd9Sstevel@tonic-gate break; 34427c478bd9Sstevel@tonic-gate case IP_UNSPEC_SRC: 34437c478bd9Sstevel@tonic-gate if (!checkonly) 34447c478bd9Sstevel@tonic-gate udp->udp_unspec_source = onoff; 34457c478bd9Sstevel@tonic-gate break; 34467c478bd9Sstevel@tonic-gate case IP_XMIT_IF: 34477c478bd9Sstevel@tonic-gate if (!checkonly) 34487c478bd9Sstevel@tonic-gate udp->udp_xmit_if = *i1; 34497c478bd9Sstevel@tonic-gate break; 34507c478bd9Sstevel@tonic-gate default: 34517c478bd9Sstevel@tonic-gate *outlenp = 0; 34527c478bd9Sstevel@tonic-gate return (EINVAL); 34537c478bd9Sstevel@tonic-gate } 34547c478bd9Sstevel@tonic-gate break; 34557c478bd9Sstevel@tonic-gate case IPPROTO_IPV6: { 34567c478bd9Sstevel@tonic-gate ip6_pkt_t *ipp; 34577c478bd9Sstevel@tonic-gate boolean_t sticky; 34587c478bd9Sstevel@tonic-gate 34597c478bd9Sstevel@tonic-gate if (udp->udp_family != AF_INET6) { 34607c478bd9Sstevel@tonic-gate *outlenp = 0; 34617c478bd9Sstevel@tonic-gate return (ENOPROTOOPT); 34627c478bd9Sstevel@tonic-gate } 34637c478bd9Sstevel@tonic-gate /* 34647c478bd9Sstevel@tonic-gate * Deal with both sticky options and ancillary data 34657c478bd9Sstevel@tonic-gate */ 34667c478bd9Sstevel@tonic-gate if (thisdg_attrs == NULL) { 34677c478bd9Sstevel@tonic-gate /* sticky options, or none */ 34687c478bd9Sstevel@tonic-gate ipp = &udp->udp_sticky_ipp; 34697c478bd9Sstevel@tonic-gate sticky = B_TRUE; 34707c478bd9Sstevel@tonic-gate } else { 34717c478bd9Sstevel@tonic-gate /* ancillary data */ 34727c478bd9Sstevel@tonic-gate ipp = (ip6_pkt_t *)thisdg_attrs; 34737c478bd9Sstevel@tonic-gate sticky = B_FALSE; 34747c478bd9Sstevel@tonic-gate } 34757c478bd9Sstevel@tonic-gate 34767c478bd9Sstevel@tonic-gate switch (name) { 34777c478bd9Sstevel@tonic-gate case IPV6_MULTICAST_IF: 34787c478bd9Sstevel@tonic-gate if (!checkonly) 34797c478bd9Sstevel@tonic-gate udp->udp_multicast_if_index = *i1; 34807c478bd9Sstevel@tonic-gate break; 34817c478bd9Sstevel@tonic-gate case IPV6_UNICAST_HOPS: 34827c478bd9Sstevel@tonic-gate /* -1 means use default */ 34837c478bd9Sstevel@tonic-gate if (*i1 < -1 || *i1 > IPV6_MAX_HOPS) { 34847c478bd9Sstevel@tonic-gate *outlenp = 0; 34857c478bd9Sstevel@tonic-gate return (EINVAL); 34867c478bd9Sstevel@tonic-gate } 34877c478bd9Sstevel@tonic-gate if (!checkonly) { 34887c478bd9Sstevel@tonic-gate if (*i1 == -1) { 3489b3d0fa4fSseb udp->udp_ttl = ipp->ipp_unicast_hops = 34907c478bd9Sstevel@tonic-gate udp_ipv6_hoplimit; 3491b3d0fa4fSseb ipp->ipp_fields &= ~IPPF_UNICAST_HOPS; 34927c478bd9Sstevel@tonic-gate /* Pass modified value to IP. */ 34937c478bd9Sstevel@tonic-gate *i1 = udp->udp_ttl; 34947c478bd9Sstevel@tonic-gate } else { 3495b3d0fa4fSseb udp->udp_ttl = ipp->ipp_unicast_hops = 34967c478bd9Sstevel@tonic-gate (uint8_t)*i1; 3497b3d0fa4fSseb ipp->ipp_fields |= IPPF_UNICAST_HOPS; 34987c478bd9Sstevel@tonic-gate } 34997c478bd9Sstevel@tonic-gate /* Rebuild the header template */ 35007c478bd9Sstevel@tonic-gate error = udp_build_hdrs(q, udp); 35017c478bd9Sstevel@tonic-gate if (error != 0) { 35027c478bd9Sstevel@tonic-gate *outlenp = 0; 35037c478bd9Sstevel@tonic-gate return (error); 35047c478bd9Sstevel@tonic-gate } 35057c478bd9Sstevel@tonic-gate } 35067c478bd9Sstevel@tonic-gate break; 35077c478bd9Sstevel@tonic-gate case IPV6_MULTICAST_HOPS: 35087c478bd9Sstevel@tonic-gate /* -1 means use default */ 35097c478bd9Sstevel@tonic-gate if (*i1 < -1 || *i1 > IPV6_MAX_HOPS) { 35107c478bd9Sstevel@tonic-gate *outlenp = 0; 35117c478bd9Sstevel@tonic-gate return (EINVAL); 35127c478bd9Sstevel@tonic-gate } 35137c478bd9Sstevel@tonic-gate if (!checkonly) { 35147c478bd9Sstevel@tonic-gate if (*i1 == -1) { 35157c478bd9Sstevel@tonic-gate udp->udp_multicast_ttl = 3516b3d0fa4fSseb ipp->ipp_multicast_hops = 35177c478bd9Sstevel@tonic-gate IP_DEFAULT_MULTICAST_TTL; 3518b3d0fa4fSseb ipp->ipp_fields &= ~IPPF_MULTICAST_HOPS; 35197c478bd9Sstevel@tonic-gate /* Pass modified value to IP. */ 35207c478bd9Sstevel@tonic-gate *i1 = udp->udp_multicast_ttl; 35217c478bd9Sstevel@tonic-gate } else { 35227c478bd9Sstevel@tonic-gate udp->udp_multicast_ttl = 3523b3d0fa4fSseb ipp->ipp_multicast_hops = 35247c478bd9Sstevel@tonic-gate (uint8_t)*i1; 3525b3d0fa4fSseb ipp->ipp_fields |= IPPF_MULTICAST_HOPS; 35267c478bd9Sstevel@tonic-gate } 35277c478bd9Sstevel@tonic-gate } 35287c478bd9Sstevel@tonic-gate break; 35297c478bd9Sstevel@tonic-gate case IPV6_MULTICAST_LOOP: 35307c478bd9Sstevel@tonic-gate if (*i1 != 0 && *i1 != 1) { 35317c478bd9Sstevel@tonic-gate *outlenp = 0; 35327c478bd9Sstevel@tonic-gate return (EINVAL); 35337c478bd9Sstevel@tonic-gate } 35347c478bd9Sstevel@tonic-gate if (!checkonly) 3535ff550d0eSmasputra connp->conn_multicast_loop = *i1; 35367c478bd9Sstevel@tonic-gate break; 35377c478bd9Sstevel@tonic-gate case IPV6_JOIN_GROUP: 35387c478bd9Sstevel@tonic-gate case IPV6_LEAVE_GROUP: 35397c478bd9Sstevel@tonic-gate case MCAST_JOIN_GROUP: 35407c478bd9Sstevel@tonic-gate case MCAST_LEAVE_GROUP: 35417c478bd9Sstevel@tonic-gate case MCAST_BLOCK_SOURCE: 35427c478bd9Sstevel@tonic-gate case MCAST_UNBLOCK_SOURCE: 35437c478bd9Sstevel@tonic-gate case MCAST_JOIN_SOURCE_GROUP: 35447c478bd9Sstevel@tonic-gate case MCAST_LEAVE_SOURCE_GROUP: 35457c478bd9Sstevel@tonic-gate /* 35467c478bd9Sstevel@tonic-gate * "soft" error (negative) 35477c478bd9Sstevel@tonic-gate * option not handled at this level 35487c478bd9Sstevel@tonic-gate * Note: Do not modify *outlenp 35497c478bd9Sstevel@tonic-gate */ 35507c478bd9Sstevel@tonic-gate return (-EINVAL); 35517c478bd9Sstevel@tonic-gate case IPV6_BOUND_IF: 35527c478bd9Sstevel@tonic-gate if (!checkonly) 35537c478bd9Sstevel@tonic-gate udp->udp_bound_if = *i1; 35547c478bd9Sstevel@tonic-gate break; 35557c478bd9Sstevel@tonic-gate case IPV6_UNSPEC_SRC: 35567c478bd9Sstevel@tonic-gate if (!checkonly) 35577c478bd9Sstevel@tonic-gate udp->udp_unspec_source = onoff; 35587c478bd9Sstevel@tonic-gate break; 35597c478bd9Sstevel@tonic-gate /* 35607c478bd9Sstevel@tonic-gate * Set boolean switches for ancillary data delivery 35617c478bd9Sstevel@tonic-gate */ 35627c478bd9Sstevel@tonic-gate case IPV6_RECVPKTINFO: 35637c478bd9Sstevel@tonic-gate if (!checkonly) 35647c478bd9Sstevel@tonic-gate udp->udp_ipv6_recvpktinfo = onoff; 35657c478bd9Sstevel@tonic-gate break; 35667c478bd9Sstevel@tonic-gate case IPV6_RECVTCLASS: 35677c478bd9Sstevel@tonic-gate if (!checkonly) { 35687c478bd9Sstevel@tonic-gate udp->udp_ipv6_recvtclass = onoff; 35697c478bd9Sstevel@tonic-gate } 35707c478bd9Sstevel@tonic-gate break; 35717c478bd9Sstevel@tonic-gate case IPV6_RECVPATHMTU: 35727c478bd9Sstevel@tonic-gate if (!checkonly) { 35737c478bd9Sstevel@tonic-gate udp->udp_ipv6_recvpathmtu = onoff; 35747c478bd9Sstevel@tonic-gate } 35757c478bd9Sstevel@tonic-gate break; 35767c478bd9Sstevel@tonic-gate case IPV6_RECVHOPLIMIT: 35777c478bd9Sstevel@tonic-gate if (!checkonly) 35787c478bd9Sstevel@tonic-gate udp->udp_ipv6_recvhoplimit = onoff; 35797c478bd9Sstevel@tonic-gate break; 35807c478bd9Sstevel@tonic-gate case IPV6_RECVHOPOPTS: 35817c478bd9Sstevel@tonic-gate if (!checkonly) 35827c478bd9Sstevel@tonic-gate udp->udp_ipv6_recvhopopts = onoff; 35837c478bd9Sstevel@tonic-gate break; 35847c478bd9Sstevel@tonic-gate case IPV6_RECVDSTOPTS: 35857c478bd9Sstevel@tonic-gate if (!checkonly) 35867c478bd9Sstevel@tonic-gate udp->udp_ipv6_recvdstopts = onoff; 35877c478bd9Sstevel@tonic-gate break; 35887c478bd9Sstevel@tonic-gate case _OLD_IPV6_RECVDSTOPTS: 35897c478bd9Sstevel@tonic-gate if (!checkonly) 35907c478bd9Sstevel@tonic-gate udp->udp_old_ipv6_recvdstopts = onoff; 35917c478bd9Sstevel@tonic-gate break; 35927c478bd9Sstevel@tonic-gate case IPV6_RECVRTHDRDSTOPTS: 35937c478bd9Sstevel@tonic-gate if (!checkonly) 35947c478bd9Sstevel@tonic-gate udp->udp_ipv6_recvrthdrdstopts = onoff; 35957c478bd9Sstevel@tonic-gate break; 35967c478bd9Sstevel@tonic-gate case IPV6_RECVRTHDR: 35977c478bd9Sstevel@tonic-gate if (!checkonly) 35987c478bd9Sstevel@tonic-gate udp->udp_ipv6_recvrthdr = onoff; 35997c478bd9Sstevel@tonic-gate break; 36007c478bd9Sstevel@tonic-gate /* 36017c478bd9Sstevel@tonic-gate * Set sticky options or ancillary data. 36027c478bd9Sstevel@tonic-gate * If sticky options, (re)build any extension headers 36037c478bd9Sstevel@tonic-gate * that might be needed as a result. 36047c478bd9Sstevel@tonic-gate */ 36057c478bd9Sstevel@tonic-gate case IPV6_PKTINFO: 36067c478bd9Sstevel@tonic-gate /* 36077c478bd9Sstevel@tonic-gate * The source address and ifindex are verified 36087c478bd9Sstevel@tonic-gate * in ip_opt_set(). For ancillary data the 36097c478bd9Sstevel@tonic-gate * source address is checked in ip_wput_v6. 36107c478bd9Sstevel@tonic-gate */ 36117c478bd9Sstevel@tonic-gate if (inlen != 0 && inlen != sizeof (struct in6_pktinfo)) 36127c478bd9Sstevel@tonic-gate return (EINVAL); 36137c478bd9Sstevel@tonic-gate if (checkonly) 36147c478bd9Sstevel@tonic-gate break; 36157c478bd9Sstevel@tonic-gate 36167c478bd9Sstevel@tonic-gate if (inlen == 0) { 36177c478bd9Sstevel@tonic-gate ipp->ipp_fields &= ~(IPPF_IFINDEX|IPPF_ADDR); 36187c478bd9Sstevel@tonic-gate ipp->ipp_sticky_ignored |= 36197c478bd9Sstevel@tonic-gate (IPPF_IFINDEX|IPPF_ADDR); 36207c478bd9Sstevel@tonic-gate } else { 36217c478bd9Sstevel@tonic-gate struct in6_pktinfo *pkti; 36227c478bd9Sstevel@tonic-gate 36237c478bd9Sstevel@tonic-gate pkti = (struct in6_pktinfo *)invalp; 36247c478bd9Sstevel@tonic-gate ipp->ipp_ifindex = pkti->ipi6_ifindex; 36257c478bd9Sstevel@tonic-gate ipp->ipp_addr = pkti->ipi6_addr; 36267c478bd9Sstevel@tonic-gate if (ipp->ipp_ifindex != 0) 36277c478bd9Sstevel@tonic-gate ipp->ipp_fields |= IPPF_IFINDEX; 36287c478bd9Sstevel@tonic-gate else 36297c478bd9Sstevel@tonic-gate ipp->ipp_fields &= ~IPPF_IFINDEX; 36307c478bd9Sstevel@tonic-gate if (!IN6_IS_ADDR_UNSPECIFIED( 36317c478bd9Sstevel@tonic-gate &ipp->ipp_addr)) 36327c478bd9Sstevel@tonic-gate ipp->ipp_fields |= IPPF_ADDR; 36337c478bd9Sstevel@tonic-gate else 36347c478bd9Sstevel@tonic-gate ipp->ipp_fields &= ~IPPF_ADDR; 36357c478bd9Sstevel@tonic-gate } 36367c478bd9Sstevel@tonic-gate if (sticky) { 36377c478bd9Sstevel@tonic-gate error = udp_build_hdrs(q, udp); 36387c478bd9Sstevel@tonic-gate if (error != 0) 36397c478bd9Sstevel@tonic-gate return (error); 36407c478bd9Sstevel@tonic-gate } 36417c478bd9Sstevel@tonic-gate break; 36427c478bd9Sstevel@tonic-gate case IPV6_HOPLIMIT: 3643b3d0fa4fSseb if (sticky) 3644b3d0fa4fSseb return (EINVAL); 36457c478bd9Sstevel@tonic-gate if (inlen != 0 && inlen != sizeof (int)) 36467c478bd9Sstevel@tonic-gate return (EINVAL); 36477c478bd9Sstevel@tonic-gate if (checkonly) 36487c478bd9Sstevel@tonic-gate break; 36497c478bd9Sstevel@tonic-gate 36507c478bd9Sstevel@tonic-gate if (inlen == 0) { 36517c478bd9Sstevel@tonic-gate ipp->ipp_fields &= ~IPPF_HOPLIMIT; 36527c478bd9Sstevel@tonic-gate ipp->ipp_sticky_ignored |= IPPF_HOPLIMIT; 36537c478bd9Sstevel@tonic-gate } else { 36547c478bd9Sstevel@tonic-gate if (*i1 > 255 || *i1 < -1) 36557c478bd9Sstevel@tonic-gate return (EINVAL); 36567c478bd9Sstevel@tonic-gate if (*i1 == -1) 36577c478bd9Sstevel@tonic-gate ipp->ipp_hoplimit = udp_ipv6_hoplimit; 36587c478bd9Sstevel@tonic-gate else 36597c478bd9Sstevel@tonic-gate ipp->ipp_hoplimit = *i1; 36607c478bd9Sstevel@tonic-gate ipp->ipp_fields |= IPPF_HOPLIMIT; 36617c478bd9Sstevel@tonic-gate } 36627c478bd9Sstevel@tonic-gate break; 36637c478bd9Sstevel@tonic-gate case IPV6_TCLASS: 36647c478bd9Sstevel@tonic-gate if (inlen != 0 && inlen != sizeof (int)) 36657c478bd9Sstevel@tonic-gate return (EINVAL); 36667c478bd9Sstevel@tonic-gate if (checkonly) 36677c478bd9Sstevel@tonic-gate break; 36687c478bd9Sstevel@tonic-gate 36697c478bd9Sstevel@tonic-gate if (inlen == 0) { 36707c478bd9Sstevel@tonic-gate ipp->ipp_fields &= ~IPPF_TCLASS; 36717c478bd9Sstevel@tonic-gate ipp->ipp_sticky_ignored |= IPPF_TCLASS; 36727c478bd9Sstevel@tonic-gate } else { 36737c478bd9Sstevel@tonic-gate if (*i1 > 255 || *i1 < -1) 36747c478bd9Sstevel@tonic-gate return (EINVAL); 36757c478bd9Sstevel@tonic-gate if (*i1 == -1) 36767c478bd9Sstevel@tonic-gate ipp->ipp_tclass = 0; 36777c478bd9Sstevel@tonic-gate else 36787c478bd9Sstevel@tonic-gate ipp->ipp_tclass = *i1; 36797c478bd9Sstevel@tonic-gate ipp->ipp_fields |= IPPF_TCLASS; 36807c478bd9Sstevel@tonic-gate } 36817c478bd9Sstevel@tonic-gate if (sticky) { 36827c478bd9Sstevel@tonic-gate error = udp_build_hdrs(q, udp); 36837c478bd9Sstevel@tonic-gate if (error != 0) 36847c478bd9Sstevel@tonic-gate return (error); 36857c478bd9Sstevel@tonic-gate } 36867c478bd9Sstevel@tonic-gate break; 36877c478bd9Sstevel@tonic-gate case IPV6_NEXTHOP: 36887c478bd9Sstevel@tonic-gate /* 36897c478bd9Sstevel@tonic-gate * IP will verify that the nexthop is reachable 36907c478bd9Sstevel@tonic-gate * and fail for sticky options. 36917c478bd9Sstevel@tonic-gate */ 36927c478bd9Sstevel@tonic-gate if (inlen != 0 && inlen != sizeof (sin6_t)) 36937c478bd9Sstevel@tonic-gate return (EINVAL); 36947c478bd9Sstevel@tonic-gate if (checkonly) 36957c478bd9Sstevel@tonic-gate break; 36967c478bd9Sstevel@tonic-gate 36977c478bd9Sstevel@tonic-gate if (inlen == 0) { 36987c478bd9Sstevel@tonic-gate ipp->ipp_fields &= ~IPPF_NEXTHOP; 36997c478bd9Sstevel@tonic-gate ipp->ipp_sticky_ignored |= IPPF_NEXTHOP; 37007c478bd9Sstevel@tonic-gate } else { 37017c478bd9Sstevel@tonic-gate sin6_t *sin6 = (sin6_t *)invalp; 37027c478bd9Sstevel@tonic-gate 37037c478bd9Sstevel@tonic-gate if (sin6->sin6_family != AF_INET6) 37047c478bd9Sstevel@tonic-gate return (EAFNOSUPPORT); 37057c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_V4MAPPED( 37067c478bd9Sstevel@tonic-gate &sin6->sin6_addr)) 37077c478bd9Sstevel@tonic-gate return (EADDRNOTAVAIL); 37087c478bd9Sstevel@tonic-gate ipp->ipp_nexthop = sin6->sin6_addr; 37097c478bd9Sstevel@tonic-gate if (!IN6_IS_ADDR_UNSPECIFIED( 37107c478bd9Sstevel@tonic-gate &ipp->ipp_nexthop)) 37117c478bd9Sstevel@tonic-gate ipp->ipp_fields |= IPPF_NEXTHOP; 37127c478bd9Sstevel@tonic-gate else 37137c478bd9Sstevel@tonic-gate ipp->ipp_fields &= ~IPPF_NEXTHOP; 37147c478bd9Sstevel@tonic-gate } 37157c478bd9Sstevel@tonic-gate if (sticky) { 37167c478bd9Sstevel@tonic-gate error = udp_build_hdrs(q, udp); 37177c478bd9Sstevel@tonic-gate if (error != 0) 37187c478bd9Sstevel@tonic-gate return (error); 37197c478bd9Sstevel@tonic-gate } 37207c478bd9Sstevel@tonic-gate break; 37217c478bd9Sstevel@tonic-gate case IPV6_HOPOPTS: { 37227c478bd9Sstevel@tonic-gate ip6_hbh_t *hopts = (ip6_hbh_t *)invalp; 37237c478bd9Sstevel@tonic-gate /* 37247c478bd9Sstevel@tonic-gate * Sanity checks - minimum size, size a multiple of 37257c478bd9Sstevel@tonic-gate * eight bytes, and matching size passed in. 37267c478bd9Sstevel@tonic-gate */ 37277c478bd9Sstevel@tonic-gate if (inlen != 0 && 37287c478bd9Sstevel@tonic-gate inlen != (8 * (hopts->ip6h_len + 1))) 37297c478bd9Sstevel@tonic-gate return (EINVAL); 37307c478bd9Sstevel@tonic-gate 37317c478bd9Sstevel@tonic-gate if (checkonly) 37327c478bd9Sstevel@tonic-gate break; 37337c478bd9Sstevel@tonic-gate 37347c478bd9Sstevel@tonic-gate if (inlen == 0) { 37357c478bd9Sstevel@tonic-gate if (sticky && 37367c478bd9Sstevel@tonic-gate (ipp->ipp_fields & IPPF_HOPOPTS) != 0) { 37377c478bd9Sstevel@tonic-gate kmem_free(ipp->ipp_hopopts, 37387c478bd9Sstevel@tonic-gate ipp->ipp_hopoptslen); 37397c478bd9Sstevel@tonic-gate ipp->ipp_hopopts = NULL; 37407c478bd9Sstevel@tonic-gate ipp->ipp_hopoptslen = 0; 37417c478bd9Sstevel@tonic-gate } 37427c478bd9Sstevel@tonic-gate ipp->ipp_fields &= ~IPPF_HOPOPTS; 37437c478bd9Sstevel@tonic-gate ipp->ipp_sticky_ignored |= IPPF_HOPOPTS; 37447c478bd9Sstevel@tonic-gate } else { 37457c478bd9Sstevel@tonic-gate error = udp_pkt_set(invalp, inlen, sticky, 37467c478bd9Sstevel@tonic-gate (uchar_t **)&ipp->ipp_hopopts, 37477c478bd9Sstevel@tonic-gate &ipp->ipp_hopoptslen); 37487c478bd9Sstevel@tonic-gate if (error != 0) 37497c478bd9Sstevel@tonic-gate return (error); 37507c478bd9Sstevel@tonic-gate ipp->ipp_fields |= IPPF_HOPOPTS; 37517c478bd9Sstevel@tonic-gate } 37527c478bd9Sstevel@tonic-gate if (sticky) { 37537c478bd9Sstevel@tonic-gate error = udp_build_hdrs(q, udp); 37547c478bd9Sstevel@tonic-gate if (error != 0) 37557c478bd9Sstevel@tonic-gate return (error); 37567c478bd9Sstevel@tonic-gate } 37577c478bd9Sstevel@tonic-gate break; 37587c478bd9Sstevel@tonic-gate } 37597c478bd9Sstevel@tonic-gate case IPV6_RTHDRDSTOPTS: { 37607c478bd9Sstevel@tonic-gate ip6_dest_t *dopts = (ip6_dest_t *)invalp; 37617c478bd9Sstevel@tonic-gate 37627c478bd9Sstevel@tonic-gate /* 37637c478bd9Sstevel@tonic-gate * Sanity checks - minimum size, size a multiple of 37647c478bd9Sstevel@tonic-gate * eight bytes, and matching size passed in. 37657c478bd9Sstevel@tonic-gate */ 37667c478bd9Sstevel@tonic-gate if (inlen != 0 && 37677c478bd9Sstevel@tonic-gate inlen != (8 * (dopts->ip6d_len + 1))) 37687c478bd9Sstevel@tonic-gate return (EINVAL); 37697c478bd9Sstevel@tonic-gate 37707c478bd9Sstevel@tonic-gate if (checkonly) 37717c478bd9Sstevel@tonic-gate break; 37727c478bd9Sstevel@tonic-gate 37737c478bd9Sstevel@tonic-gate if (inlen == 0) { 37747c478bd9Sstevel@tonic-gate if (sticky && 37757c478bd9Sstevel@tonic-gate (ipp->ipp_fields & IPPF_RTDSTOPTS) != 0) { 37767c478bd9Sstevel@tonic-gate kmem_free(ipp->ipp_rtdstopts, 37777c478bd9Sstevel@tonic-gate ipp->ipp_rtdstoptslen); 37787c478bd9Sstevel@tonic-gate ipp->ipp_rtdstopts = NULL; 37797c478bd9Sstevel@tonic-gate ipp->ipp_rtdstoptslen = 0; 37807c478bd9Sstevel@tonic-gate } 3781ff550d0eSmasputra 37827c478bd9Sstevel@tonic-gate ipp->ipp_fields &= ~IPPF_RTDSTOPTS; 37837c478bd9Sstevel@tonic-gate ipp->ipp_sticky_ignored |= IPPF_RTDSTOPTS; 37847c478bd9Sstevel@tonic-gate } else { 37857c478bd9Sstevel@tonic-gate error = udp_pkt_set(invalp, inlen, sticky, 37867c478bd9Sstevel@tonic-gate (uchar_t **)&ipp->ipp_rtdstopts, 37877c478bd9Sstevel@tonic-gate &ipp->ipp_rtdstoptslen); 37887c478bd9Sstevel@tonic-gate if (error != 0) 37897c478bd9Sstevel@tonic-gate return (error); 37907c478bd9Sstevel@tonic-gate ipp->ipp_fields |= IPPF_RTDSTOPTS; 37917c478bd9Sstevel@tonic-gate } 37927c478bd9Sstevel@tonic-gate if (sticky) { 37937c478bd9Sstevel@tonic-gate error = udp_build_hdrs(q, udp); 37947c478bd9Sstevel@tonic-gate if (error != 0) 37957c478bd9Sstevel@tonic-gate return (error); 37967c478bd9Sstevel@tonic-gate } 37977c478bd9Sstevel@tonic-gate break; 37987c478bd9Sstevel@tonic-gate } 37997c478bd9Sstevel@tonic-gate case IPV6_DSTOPTS: { 38007c478bd9Sstevel@tonic-gate ip6_dest_t *dopts = (ip6_dest_t *)invalp; 38017c478bd9Sstevel@tonic-gate 38027c478bd9Sstevel@tonic-gate /* 38037c478bd9Sstevel@tonic-gate * Sanity checks - minimum size, size a multiple of 38047c478bd9Sstevel@tonic-gate * eight bytes, and matching size passed in. 38057c478bd9Sstevel@tonic-gate */ 38067c478bd9Sstevel@tonic-gate if (inlen != 0 && 38077c478bd9Sstevel@tonic-gate inlen != (8 * (dopts->ip6d_len + 1))) 38087c478bd9Sstevel@tonic-gate return (EINVAL); 38097c478bd9Sstevel@tonic-gate 38107c478bd9Sstevel@tonic-gate if (checkonly) 38117c478bd9Sstevel@tonic-gate break; 38127c478bd9Sstevel@tonic-gate 38137c478bd9Sstevel@tonic-gate if (inlen == 0) { 38147c478bd9Sstevel@tonic-gate if (sticky && 38157c478bd9Sstevel@tonic-gate (ipp->ipp_fields & IPPF_DSTOPTS) != 0) { 38167c478bd9Sstevel@tonic-gate kmem_free(ipp->ipp_dstopts, 38177c478bd9Sstevel@tonic-gate ipp->ipp_dstoptslen); 38187c478bd9Sstevel@tonic-gate ipp->ipp_dstopts = NULL; 38197c478bd9Sstevel@tonic-gate ipp->ipp_dstoptslen = 0; 38207c478bd9Sstevel@tonic-gate } 38217c478bd9Sstevel@tonic-gate ipp->ipp_fields &= ~IPPF_DSTOPTS; 38227c478bd9Sstevel@tonic-gate ipp->ipp_sticky_ignored |= IPPF_DSTOPTS; 38237c478bd9Sstevel@tonic-gate } else { 38247c478bd9Sstevel@tonic-gate error = udp_pkt_set(invalp, inlen, sticky, 38257c478bd9Sstevel@tonic-gate (uchar_t **)&ipp->ipp_dstopts, 38267c478bd9Sstevel@tonic-gate &ipp->ipp_dstoptslen); 38277c478bd9Sstevel@tonic-gate if (error != 0) 38287c478bd9Sstevel@tonic-gate return (error); 38297c478bd9Sstevel@tonic-gate ipp->ipp_fields |= IPPF_DSTOPTS; 38307c478bd9Sstevel@tonic-gate } 38317c478bd9Sstevel@tonic-gate if (sticky) { 38327c478bd9Sstevel@tonic-gate error = udp_build_hdrs(q, udp); 38337c478bd9Sstevel@tonic-gate if (error != 0) 38347c478bd9Sstevel@tonic-gate return (error); 38357c478bd9Sstevel@tonic-gate } 38367c478bd9Sstevel@tonic-gate break; 38377c478bd9Sstevel@tonic-gate } 38387c478bd9Sstevel@tonic-gate case IPV6_RTHDR: { 38397c478bd9Sstevel@tonic-gate ip6_rthdr_t *rt = (ip6_rthdr_t *)invalp; 38407c478bd9Sstevel@tonic-gate 38417c478bd9Sstevel@tonic-gate /* 38427c478bd9Sstevel@tonic-gate * Sanity checks - minimum size, size a multiple of 38437c478bd9Sstevel@tonic-gate * eight bytes, and matching size passed in. 38447c478bd9Sstevel@tonic-gate */ 38457c478bd9Sstevel@tonic-gate if (inlen != 0 && 38467c478bd9Sstevel@tonic-gate inlen != (8 * (rt->ip6r_len + 1))) 38477c478bd9Sstevel@tonic-gate return (EINVAL); 38487c478bd9Sstevel@tonic-gate 38497c478bd9Sstevel@tonic-gate if (checkonly) 38507c478bd9Sstevel@tonic-gate break; 38517c478bd9Sstevel@tonic-gate 38527c478bd9Sstevel@tonic-gate if (inlen == 0) { 38537c478bd9Sstevel@tonic-gate if (sticky && 38547c478bd9Sstevel@tonic-gate (ipp->ipp_fields & IPPF_RTHDR) != 0) { 38557c478bd9Sstevel@tonic-gate kmem_free(ipp->ipp_rthdr, 38567c478bd9Sstevel@tonic-gate ipp->ipp_rthdrlen); 38577c478bd9Sstevel@tonic-gate ipp->ipp_rthdr = NULL; 38587c478bd9Sstevel@tonic-gate ipp->ipp_rthdrlen = 0; 38597c478bd9Sstevel@tonic-gate } 38607c478bd9Sstevel@tonic-gate ipp->ipp_fields &= ~IPPF_RTHDR; 38617c478bd9Sstevel@tonic-gate ipp->ipp_sticky_ignored |= IPPF_RTHDR; 38627c478bd9Sstevel@tonic-gate } else { 38637c478bd9Sstevel@tonic-gate error = udp_pkt_set(invalp, inlen, sticky, 38647c478bd9Sstevel@tonic-gate (uchar_t **)&ipp->ipp_rthdr, 38657c478bd9Sstevel@tonic-gate &ipp->ipp_rthdrlen); 38667c478bd9Sstevel@tonic-gate if (error != 0) 38677c478bd9Sstevel@tonic-gate return (error); 38687c478bd9Sstevel@tonic-gate ipp->ipp_fields |= IPPF_RTHDR; 38697c478bd9Sstevel@tonic-gate } 38707c478bd9Sstevel@tonic-gate if (sticky) { 38717c478bd9Sstevel@tonic-gate error = udp_build_hdrs(q, udp); 38727c478bd9Sstevel@tonic-gate if (error != 0) 38737c478bd9Sstevel@tonic-gate return (error); 38747c478bd9Sstevel@tonic-gate } 38757c478bd9Sstevel@tonic-gate break; 38767c478bd9Sstevel@tonic-gate } 38777c478bd9Sstevel@tonic-gate 38787c478bd9Sstevel@tonic-gate case IPV6_DONTFRAG: 38797c478bd9Sstevel@tonic-gate if (checkonly) 38807c478bd9Sstevel@tonic-gate break; 38817c478bd9Sstevel@tonic-gate 38827c478bd9Sstevel@tonic-gate if (onoff) { 38837c478bd9Sstevel@tonic-gate ipp->ipp_fields |= IPPF_DONTFRAG; 38847c478bd9Sstevel@tonic-gate } else { 38857c478bd9Sstevel@tonic-gate ipp->ipp_fields &= ~IPPF_DONTFRAG; 38867c478bd9Sstevel@tonic-gate } 38877c478bd9Sstevel@tonic-gate break; 38887c478bd9Sstevel@tonic-gate 38897c478bd9Sstevel@tonic-gate case IPV6_USE_MIN_MTU: 38907c478bd9Sstevel@tonic-gate if (inlen != sizeof (int)) 38917c478bd9Sstevel@tonic-gate return (EINVAL); 38927c478bd9Sstevel@tonic-gate 38937c478bd9Sstevel@tonic-gate if (*i1 < -1 || *i1 > 1) 38947c478bd9Sstevel@tonic-gate return (EINVAL); 38957c478bd9Sstevel@tonic-gate 38967c478bd9Sstevel@tonic-gate if (checkonly) 38977c478bd9Sstevel@tonic-gate break; 38987c478bd9Sstevel@tonic-gate 38997c478bd9Sstevel@tonic-gate ipp->ipp_fields |= IPPF_USE_MIN_MTU; 39007c478bd9Sstevel@tonic-gate ipp->ipp_use_min_mtu = *i1; 39017c478bd9Sstevel@tonic-gate break; 39027c478bd9Sstevel@tonic-gate 39037c478bd9Sstevel@tonic-gate case IPV6_BOUND_PIF: 39047c478bd9Sstevel@tonic-gate case IPV6_SEC_OPT: 39057c478bd9Sstevel@tonic-gate case IPV6_DONTFAILOVER_IF: 39067c478bd9Sstevel@tonic-gate case IPV6_SRC_PREFERENCES: 39077c478bd9Sstevel@tonic-gate case IPV6_V6ONLY: 39087c478bd9Sstevel@tonic-gate /* Handled at the IP level */ 39097c478bd9Sstevel@tonic-gate return (-EINVAL); 39107c478bd9Sstevel@tonic-gate default: 39117c478bd9Sstevel@tonic-gate *outlenp = 0; 39127c478bd9Sstevel@tonic-gate return (EINVAL); 39137c478bd9Sstevel@tonic-gate } 39147c478bd9Sstevel@tonic-gate break; 39157c478bd9Sstevel@tonic-gate } /* end IPPROTO_IPV6 */ 39167c478bd9Sstevel@tonic-gate case IPPROTO_UDP: 39177c478bd9Sstevel@tonic-gate switch (name) { 39187c478bd9Sstevel@tonic-gate case UDP_ANONPRIVBIND: 39197c478bd9Sstevel@tonic-gate if ((error = secpolicy_net_privaddr(cr, 0)) != 0) { 39207c478bd9Sstevel@tonic-gate *outlenp = 0; 39217c478bd9Sstevel@tonic-gate return (error); 39227c478bd9Sstevel@tonic-gate } 39237c478bd9Sstevel@tonic-gate if (!checkonly) { 39247c478bd9Sstevel@tonic-gate udp->udp_anon_priv_bind = onoff; 39257c478bd9Sstevel@tonic-gate } 39267c478bd9Sstevel@tonic-gate break; 39277c478bd9Sstevel@tonic-gate case UDP_EXCLBIND: 39287c478bd9Sstevel@tonic-gate if (!checkonly) 39297c478bd9Sstevel@tonic-gate udp->udp_exclbind = onoff; 39307c478bd9Sstevel@tonic-gate break; 39317c478bd9Sstevel@tonic-gate case UDP_RCVHDR: 39327c478bd9Sstevel@tonic-gate if (!checkonly) 39337c478bd9Sstevel@tonic-gate udp->udp_rcvhdr = onoff; 39347c478bd9Sstevel@tonic-gate break; 39357c478bd9Sstevel@tonic-gate default: 39367c478bd9Sstevel@tonic-gate *outlenp = 0; 39377c478bd9Sstevel@tonic-gate return (EINVAL); 39387c478bd9Sstevel@tonic-gate } 39397c478bd9Sstevel@tonic-gate break; 39407c478bd9Sstevel@tonic-gate default: 39417c478bd9Sstevel@tonic-gate *outlenp = 0; 39427c478bd9Sstevel@tonic-gate return (EINVAL); 39437c478bd9Sstevel@tonic-gate } 39447c478bd9Sstevel@tonic-gate /* 39457c478bd9Sstevel@tonic-gate * Common case of OK return with outval same as inval. 39467c478bd9Sstevel@tonic-gate */ 39477c478bd9Sstevel@tonic-gate if (invalp != outvalp) { 39487c478bd9Sstevel@tonic-gate /* don't trust bcopy for identical src/dst */ 39497c478bd9Sstevel@tonic-gate (void) bcopy(invalp, outvalp, inlen); 39507c478bd9Sstevel@tonic-gate } 39517c478bd9Sstevel@tonic-gate *outlenp = inlen; 39527c478bd9Sstevel@tonic-gate return (0); 39537c478bd9Sstevel@tonic-gate } 39547c478bd9Sstevel@tonic-gate 39557c478bd9Sstevel@tonic-gate /* 39567c478bd9Sstevel@tonic-gate * Update udp_sticky_hdrs based on udp_sticky_ipp, udp_v6src, and udp_ttl. 39577c478bd9Sstevel@tonic-gate * The headers include ip6i_t (if needed), ip6_t, any sticky extension 39587c478bd9Sstevel@tonic-gate * headers, and the udp header. 39597c478bd9Sstevel@tonic-gate * Returns failure if can't allocate memory. 39607c478bd9Sstevel@tonic-gate */ 39617c478bd9Sstevel@tonic-gate static int 39627c478bd9Sstevel@tonic-gate udp_build_hdrs(queue_t *q, udp_t *udp) 39637c478bd9Sstevel@tonic-gate { 39647c478bd9Sstevel@tonic-gate uchar_t *hdrs; 39657c478bd9Sstevel@tonic-gate uint_t hdrs_len; 39667c478bd9Sstevel@tonic-gate ip6_t *ip6h; 39677c478bd9Sstevel@tonic-gate ip6i_t *ip6i; 39687c478bd9Sstevel@tonic-gate udpha_t *udpha; 39697c478bd9Sstevel@tonic-gate ip6_pkt_t *ipp = &udp->udp_sticky_ipp; 39707c478bd9Sstevel@tonic-gate 39717c478bd9Sstevel@tonic-gate hdrs_len = ip_total_hdrs_len_v6(ipp) + UDPH_SIZE; 39727c478bd9Sstevel@tonic-gate ASSERT(hdrs_len != 0); 39737c478bd9Sstevel@tonic-gate if (hdrs_len != udp->udp_sticky_hdrs_len) { 39747c478bd9Sstevel@tonic-gate /* Need to reallocate */ 39757c478bd9Sstevel@tonic-gate hdrs = kmem_alloc(hdrs_len, KM_NOSLEEP); 39767c478bd9Sstevel@tonic-gate if (hdrs == NULL) 39777c478bd9Sstevel@tonic-gate return (ENOMEM); 39787c478bd9Sstevel@tonic-gate 39797c478bd9Sstevel@tonic-gate if (udp->udp_sticky_hdrs_len != 0) { 39807c478bd9Sstevel@tonic-gate kmem_free(udp->udp_sticky_hdrs, 39817c478bd9Sstevel@tonic-gate udp->udp_sticky_hdrs_len); 39827c478bd9Sstevel@tonic-gate } 39837c478bd9Sstevel@tonic-gate udp->udp_sticky_hdrs = hdrs; 39847c478bd9Sstevel@tonic-gate udp->udp_sticky_hdrs_len = hdrs_len; 39857c478bd9Sstevel@tonic-gate } 39867c478bd9Sstevel@tonic-gate ip_build_hdrs_v6(udp->udp_sticky_hdrs, 39877c478bd9Sstevel@tonic-gate udp->udp_sticky_hdrs_len - UDPH_SIZE, ipp, IPPROTO_UDP); 39887c478bd9Sstevel@tonic-gate 39897c478bd9Sstevel@tonic-gate /* Set header fields not in ipp */ 39907c478bd9Sstevel@tonic-gate if (ipp->ipp_fields & IPPF_HAS_IP6I) { 39917c478bd9Sstevel@tonic-gate ip6i = (ip6i_t *)udp->udp_sticky_hdrs; 39927c478bd9Sstevel@tonic-gate ip6h = (ip6_t *)&ip6i[1]; 39937c478bd9Sstevel@tonic-gate } else { 39947c478bd9Sstevel@tonic-gate ip6h = (ip6_t *)udp->udp_sticky_hdrs; 39957c478bd9Sstevel@tonic-gate } 39967c478bd9Sstevel@tonic-gate 39977c478bd9Sstevel@tonic-gate if (!(ipp->ipp_fields & IPPF_ADDR)) 39987c478bd9Sstevel@tonic-gate ip6h->ip6_src = udp->udp_v6src; 39997c478bd9Sstevel@tonic-gate 40007c478bd9Sstevel@tonic-gate udpha = (udpha_t *)(udp->udp_sticky_hdrs + hdrs_len - UDPH_SIZE); 40017c478bd9Sstevel@tonic-gate udpha->uha_src_port = udp->udp_port; 40027c478bd9Sstevel@tonic-gate 40037c478bd9Sstevel@tonic-gate /* Try to get everything in a single mblk */ 40047c478bd9Sstevel@tonic-gate if (hdrs_len > udp->udp_max_hdr_len) { 40057c478bd9Sstevel@tonic-gate udp->udp_max_hdr_len = hdrs_len; 40067c478bd9Sstevel@tonic-gate (void) mi_set_sth_wroff(RD(q), udp->udp_max_hdr_len + 40077c478bd9Sstevel@tonic-gate udp_wroff_extra); 40087c478bd9Sstevel@tonic-gate } 40097c478bd9Sstevel@tonic-gate return (0); 40107c478bd9Sstevel@tonic-gate } 40117c478bd9Sstevel@tonic-gate 40127c478bd9Sstevel@tonic-gate /* 40137c478bd9Sstevel@tonic-gate * Set optbuf and optlen for the option. 40147c478bd9Sstevel@tonic-gate * If sticky is set allocate memory (if not already present). 40157c478bd9Sstevel@tonic-gate * Otherwise just point optbuf and optlen at invalp and inlen. 40167c478bd9Sstevel@tonic-gate * Returns failure if memory can not be allocated. 40177c478bd9Sstevel@tonic-gate */ 40187c478bd9Sstevel@tonic-gate static int 40197c478bd9Sstevel@tonic-gate udp_pkt_set(uchar_t *invalp, uint_t inlen, boolean_t sticky, 40207c478bd9Sstevel@tonic-gate uchar_t **optbufp, uint_t *optlenp) 40217c478bd9Sstevel@tonic-gate { 40227c478bd9Sstevel@tonic-gate uchar_t *optbuf; 40237c478bd9Sstevel@tonic-gate 40247c478bd9Sstevel@tonic-gate if (!sticky) { 40257c478bd9Sstevel@tonic-gate *optbufp = invalp; 40267c478bd9Sstevel@tonic-gate *optlenp = inlen; 40277c478bd9Sstevel@tonic-gate return (0); 40287c478bd9Sstevel@tonic-gate } 40297c478bd9Sstevel@tonic-gate if (inlen == *optlenp) { 40307c478bd9Sstevel@tonic-gate /* Unchanged length - no need to realocate */ 40317c478bd9Sstevel@tonic-gate bcopy(invalp, *optbufp, inlen); 40327c478bd9Sstevel@tonic-gate return (0); 40337c478bd9Sstevel@tonic-gate } 40347c478bd9Sstevel@tonic-gate if (inlen != 0) { 40357c478bd9Sstevel@tonic-gate /* Allocate new buffer before free */ 40367c478bd9Sstevel@tonic-gate optbuf = kmem_alloc(inlen, KM_NOSLEEP); 40377c478bd9Sstevel@tonic-gate if (optbuf == NULL) 40387c478bd9Sstevel@tonic-gate return (ENOMEM); 40397c478bd9Sstevel@tonic-gate } else { 40407c478bd9Sstevel@tonic-gate optbuf = NULL; 40417c478bd9Sstevel@tonic-gate } 40427c478bd9Sstevel@tonic-gate /* Free old buffer */ 40437c478bd9Sstevel@tonic-gate if (*optlenp != 0) 40447c478bd9Sstevel@tonic-gate kmem_free(*optbufp, *optlenp); 40457c478bd9Sstevel@tonic-gate 40467c478bd9Sstevel@tonic-gate bcopy(invalp, optbuf, inlen); 40477c478bd9Sstevel@tonic-gate *optbufp = optbuf; 40487c478bd9Sstevel@tonic-gate *optlenp = inlen; 40497c478bd9Sstevel@tonic-gate return (0); 40507c478bd9Sstevel@tonic-gate } 40517c478bd9Sstevel@tonic-gate 40527c478bd9Sstevel@tonic-gate /* 40537c478bd9Sstevel@tonic-gate * This routine retrieves the value of an ND variable in a udpparam_t 40547c478bd9Sstevel@tonic-gate * structure. It is called through nd_getset when a user reads the 40557c478bd9Sstevel@tonic-gate * variable. 40567c478bd9Sstevel@tonic-gate */ 40577c478bd9Sstevel@tonic-gate /* ARGSUSED */ 40587c478bd9Sstevel@tonic-gate static int 40597c478bd9Sstevel@tonic-gate udp_param_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *cr) 40607c478bd9Sstevel@tonic-gate { 40617c478bd9Sstevel@tonic-gate udpparam_t *udppa = (udpparam_t *)cp; 40627c478bd9Sstevel@tonic-gate 40637c478bd9Sstevel@tonic-gate (void) mi_mpprintf(mp, "%d", udppa->udp_param_value); 40647c478bd9Sstevel@tonic-gate return (0); 40657c478bd9Sstevel@tonic-gate } 40667c478bd9Sstevel@tonic-gate 40677c478bd9Sstevel@tonic-gate /* 40687c478bd9Sstevel@tonic-gate * Walk through the param array specified registering each element with the 40697c478bd9Sstevel@tonic-gate * named dispatch (ND) handler. 40707c478bd9Sstevel@tonic-gate */ 40717c478bd9Sstevel@tonic-gate static boolean_t 40727c478bd9Sstevel@tonic-gate udp_param_register(udpparam_t *udppa, int cnt) 40737c478bd9Sstevel@tonic-gate { 40747c478bd9Sstevel@tonic-gate for (; cnt-- > 0; udppa++) { 40757c478bd9Sstevel@tonic-gate if (udppa->udp_param_name && udppa->udp_param_name[0]) { 40767c478bd9Sstevel@tonic-gate if (!nd_load(&udp_g_nd, udppa->udp_param_name, 40777c478bd9Sstevel@tonic-gate udp_param_get, udp_param_set, 40787c478bd9Sstevel@tonic-gate (caddr_t)udppa)) { 40797c478bd9Sstevel@tonic-gate nd_free(&udp_g_nd); 40807c478bd9Sstevel@tonic-gate return (B_FALSE); 40817c478bd9Sstevel@tonic-gate } 40827c478bd9Sstevel@tonic-gate } 40837c478bd9Sstevel@tonic-gate } 40847c478bd9Sstevel@tonic-gate if (!nd_load(&udp_g_nd, "udp_extra_priv_ports", 40857c478bd9Sstevel@tonic-gate udp_extra_priv_ports_get, NULL, NULL)) { 40867c478bd9Sstevel@tonic-gate nd_free(&udp_g_nd); 40877c478bd9Sstevel@tonic-gate return (B_FALSE); 40887c478bd9Sstevel@tonic-gate } 40897c478bd9Sstevel@tonic-gate if (!nd_load(&udp_g_nd, "udp_extra_priv_ports_add", 40907c478bd9Sstevel@tonic-gate NULL, udp_extra_priv_ports_add, NULL)) { 40917c478bd9Sstevel@tonic-gate nd_free(&udp_g_nd); 40927c478bd9Sstevel@tonic-gate return (B_FALSE); 40937c478bd9Sstevel@tonic-gate } 40947c478bd9Sstevel@tonic-gate if (!nd_load(&udp_g_nd, "udp_extra_priv_ports_del", 40957c478bd9Sstevel@tonic-gate NULL, udp_extra_priv_ports_del, NULL)) { 40967c478bd9Sstevel@tonic-gate nd_free(&udp_g_nd); 40977c478bd9Sstevel@tonic-gate return (B_FALSE); 40987c478bd9Sstevel@tonic-gate } 40997c478bd9Sstevel@tonic-gate if (!nd_load(&udp_g_nd, "udp_status", udp_status_report, NULL, 41007c478bd9Sstevel@tonic-gate NULL)) { 41017c478bd9Sstevel@tonic-gate nd_free(&udp_g_nd); 41027c478bd9Sstevel@tonic-gate return (B_FALSE); 41037c478bd9Sstevel@tonic-gate } 41047c478bd9Sstevel@tonic-gate if (!nd_load(&udp_g_nd, "udp_bind_hash", udp_bind_hash_report, NULL, 41057c478bd9Sstevel@tonic-gate NULL)) { 41067c478bd9Sstevel@tonic-gate nd_free(&udp_g_nd); 41077c478bd9Sstevel@tonic-gate return (B_FALSE); 41087c478bd9Sstevel@tonic-gate } 41097c478bd9Sstevel@tonic-gate return (B_TRUE); 41107c478bd9Sstevel@tonic-gate } 41117c478bd9Sstevel@tonic-gate 41127c478bd9Sstevel@tonic-gate /* This routine sets an ND variable in a udpparam_t structure. */ 41137c478bd9Sstevel@tonic-gate /* ARGSUSED */ 41147c478bd9Sstevel@tonic-gate static int 41157c478bd9Sstevel@tonic-gate udp_param_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp, cred_t *cr) 41167c478bd9Sstevel@tonic-gate { 41177c478bd9Sstevel@tonic-gate long new_value; 41187c478bd9Sstevel@tonic-gate udpparam_t *udppa = (udpparam_t *)cp; 41197c478bd9Sstevel@tonic-gate 41207c478bd9Sstevel@tonic-gate /* 41217c478bd9Sstevel@tonic-gate * Fail the request if the new value does not lie within the 41227c478bd9Sstevel@tonic-gate * required bounds. 41237c478bd9Sstevel@tonic-gate */ 41247c478bd9Sstevel@tonic-gate if (ddi_strtol(value, NULL, 10, &new_value) != 0 || 41257c478bd9Sstevel@tonic-gate new_value < udppa->udp_param_min || 41267c478bd9Sstevel@tonic-gate new_value > udppa->udp_param_max) { 41277c478bd9Sstevel@tonic-gate return (EINVAL); 41287c478bd9Sstevel@tonic-gate } 41297c478bd9Sstevel@tonic-gate 41307c478bd9Sstevel@tonic-gate /* Set the new value */ 41317c478bd9Sstevel@tonic-gate udppa->udp_param_value = new_value; 41327c478bd9Sstevel@tonic-gate return (0); 41337c478bd9Sstevel@tonic-gate } 41347c478bd9Sstevel@tonic-gate 41357c478bd9Sstevel@tonic-gate static void 4136ff550d0eSmasputra udp_input(conn_t *connp, mblk_t *mp) 41377c478bd9Sstevel@tonic-gate { 41387c478bd9Sstevel@tonic-gate struct T_unitdata_ind *tudi; 4139ff550d0eSmasputra uchar_t *rptr; /* Pointer to IP header */ 4140ff550d0eSmasputra int hdr_length; /* Length of IP+UDP headers */ 41417c478bd9Sstevel@tonic-gate int udi_size; /* Size of T_unitdata_ind */ 4142ff550d0eSmasputra int mp_len; 41437c478bd9Sstevel@tonic-gate udp_t *udp; 41447c478bd9Sstevel@tonic-gate udpha_t *udpha; 41457c478bd9Sstevel@tonic-gate int ipversion; 41467c478bd9Sstevel@tonic-gate ip6_pkt_t ipp; 41477c478bd9Sstevel@tonic-gate ip6_t *ip6h; 41487c478bd9Sstevel@tonic-gate ip6i_t *ip6i; 41497c478bd9Sstevel@tonic-gate mblk_t *mp1; 41507c478bd9Sstevel@tonic-gate mblk_t *options_mp = NULL; 41517c478bd9Sstevel@tonic-gate in_pktinfo_t *pinfo = NULL; 41527c478bd9Sstevel@tonic-gate cred_t *cr = NULL; 4153ff550d0eSmasputra queue_t *q = connp->conn_rq; 41547c478bd9Sstevel@tonic-gate pid_t cpid; 41557c478bd9Sstevel@tonic-gate 41567c478bd9Sstevel@tonic-gate TRACE_2(TR_FAC_UDP, TR_UDP_RPUT_START, 41577c478bd9Sstevel@tonic-gate "udp_rput_start: q %p mp %p", q, mp); 41587c478bd9Sstevel@tonic-gate 4159ff550d0eSmasputra udp = connp->conn_udp; 41607c478bd9Sstevel@tonic-gate rptr = mp->b_rptr; 4161ff550d0eSmasputra ASSERT(DB_TYPE(mp) == M_DATA || DB_TYPE(mp) == M_CTL); 4162ff550d0eSmasputra ASSERT(OK_32PTR(rptr)); 41637c478bd9Sstevel@tonic-gate 4164ff550d0eSmasputra /* 4165ff550d0eSmasputra * IP should have prepended the options data in an M_CTL 4166ff550d0eSmasputra * Check M_CTL "type" to make sure are not here bcos of 4167ff550d0eSmasputra * a valid ICMP message 4168ff550d0eSmasputra */ 4169ff550d0eSmasputra if (DB_TYPE(mp) == M_CTL) { 4170ff550d0eSmasputra if (MBLKL(mp) == sizeof (in_pktinfo_t) && 4171ff550d0eSmasputra ((in_pktinfo_t *)mp->b_rptr)->in_pkt_ulp_type == 4172ff550d0eSmasputra IN_PKTINFO) { 41737c478bd9Sstevel@tonic-gate /* 4174ff550d0eSmasputra * IP_RECVIF or IP_RECVSLLA information has been 4175ff550d0eSmasputra * appended to the packet by IP. We need to 4176ff550d0eSmasputra * extract the mblk and adjust the rptr 41777c478bd9Sstevel@tonic-gate */ 4178ff550d0eSmasputra pinfo = (in_pktinfo_t *)mp->b_rptr; 4179ff550d0eSmasputra options_mp = mp; 4180ff550d0eSmasputra mp = mp->b_cont; 4181ff550d0eSmasputra rptr = mp->b_rptr; 4182ff550d0eSmasputra UDP_STAT(udp_in_pktinfo); 4183ff550d0eSmasputra } else { 4184ff550d0eSmasputra /* 4185ff550d0eSmasputra * ICMP messages. 4186ff550d0eSmasputra */ 4187ff550d0eSmasputra udp_icmp_error(q, mp); 4188ff550d0eSmasputra TRACE_2(TR_FAC_UDP, TR_UDP_RPUT_END, 4189ff550d0eSmasputra "udp_rput_end: q %p (%S)", q, "m_ctl"); 4190ff550d0eSmasputra return; 41917c478bd9Sstevel@tonic-gate } 41927c478bd9Sstevel@tonic-gate } 41937c478bd9Sstevel@tonic-gate 4194ff550d0eSmasputra mp_len = msgdsize(mp); 41957c478bd9Sstevel@tonic-gate /* 41967c478bd9Sstevel@tonic-gate * This is the inbound data path. 41977c478bd9Sstevel@tonic-gate * First, we check to make sure the IP version number is correct, 41987c478bd9Sstevel@tonic-gate * and then pull the IP and UDP headers into the first mblk. 41997c478bd9Sstevel@tonic-gate * Assume IP provides aligned packets - otherwise toss. 42007c478bd9Sstevel@tonic-gate * Also, check if we have a complete IP header. 42017c478bd9Sstevel@tonic-gate */ 42027c478bd9Sstevel@tonic-gate 42037c478bd9Sstevel@tonic-gate /* Initialize regardless if ipversion is IPv4 or IPv6 */ 42047c478bd9Sstevel@tonic-gate ipp.ipp_fields = 0; 42057c478bd9Sstevel@tonic-gate 42067c478bd9Sstevel@tonic-gate ipversion = IPH_HDR_VERSION(rptr); 42077c478bd9Sstevel@tonic-gate switch (ipversion) { 42087c478bd9Sstevel@tonic-gate case IPV4_VERSION: 4209ff550d0eSmasputra ASSERT(MBLKL(mp) >= sizeof (ipha_t)); 4210ff550d0eSmasputra ASSERT(((ipha_t *)rptr)->ipha_protocol == IPPROTO_UDP); 42117c478bd9Sstevel@tonic-gate hdr_length = IPH_HDR_LENGTH(rptr) + UDPH_SIZE; 42127c478bd9Sstevel@tonic-gate if ((hdr_length > IP_SIMPLE_HDR_LENGTH + UDPH_SIZE) || 42137c478bd9Sstevel@tonic-gate (udp->udp_ip_rcv_options_len)) { 42147c478bd9Sstevel@tonic-gate /* 42157c478bd9Sstevel@tonic-gate * Handle IPv4 packets with options outside of the 42167c478bd9Sstevel@tonic-gate * main data path. Not needed for AF_INET6 sockets 42177c478bd9Sstevel@tonic-gate * since they don't support a getsockopt of IP_OPTIONS. 42187c478bd9Sstevel@tonic-gate */ 42197c478bd9Sstevel@tonic-gate if (udp->udp_family == AF_INET6) 42207c478bd9Sstevel@tonic-gate break; 42217c478bd9Sstevel@tonic-gate /* 42227c478bd9Sstevel@tonic-gate * UDP length check performed for IPv4 packets with 42237c478bd9Sstevel@tonic-gate * options to check whether UDP length specified in 42247c478bd9Sstevel@tonic-gate * the header is the same as the physical length of 42257c478bd9Sstevel@tonic-gate * the packet. 42267c478bd9Sstevel@tonic-gate */ 42277c478bd9Sstevel@tonic-gate udpha = (udpha_t *)(rptr + (hdr_length - UDPH_SIZE)); 4228ff550d0eSmasputra if (mp_len != (ntohs(udpha->uha_length) + 42297c478bd9Sstevel@tonic-gate hdr_length - UDPH_SIZE)) { 42307c478bd9Sstevel@tonic-gate goto tossit; 42317c478bd9Sstevel@tonic-gate } 42327c478bd9Sstevel@tonic-gate /* 42337c478bd9Sstevel@tonic-gate * Handle the case where the packet has IP options 42347c478bd9Sstevel@tonic-gate * and the IP_RECVSLLA & IP_RECVIF are set 42357c478bd9Sstevel@tonic-gate */ 42367c478bd9Sstevel@tonic-gate if (pinfo != NULL) 42377c478bd9Sstevel@tonic-gate mp = options_mp; 4238ff550d0eSmasputra udp_become_writer(connp, mp, udp_rput_other_wrapper, 4239ff550d0eSmasputra SQTAG_UDP_INPUT); 42407c478bd9Sstevel@tonic-gate TRACE_2(TR_FAC_UDP, TR_UDP_RPUT_END, 42417c478bd9Sstevel@tonic-gate "udp_rput_end: q %p (%S)", q, "end"); 42427c478bd9Sstevel@tonic-gate return; 42437c478bd9Sstevel@tonic-gate } 42447c478bd9Sstevel@tonic-gate 42457c478bd9Sstevel@tonic-gate /* Handle IPV6_RECVHOPLIMIT. */ 4246ff550d0eSmasputra if ((udp->udp_family == AF_INET6) && (pinfo != NULL) && 4247ff550d0eSmasputra udp->udp_ipv6_recvpktinfo) { 42487c478bd9Sstevel@tonic-gate if (pinfo->in_pkt_flags & IPF_RECVIF) { 42497c478bd9Sstevel@tonic-gate ipp.ipp_fields |= IPPF_IFINDEX; 42507c478bd9Sstevel@tonic-gate ipp.ipp_ifindex = pinfo->in_pkt_ifindex; 42517c478bd9Sstevel@tonic-gate } 42527c478bd9Sstevel@tonic-gate } 42537c478bd9Sstevel@tonic-gate break; 42547c478bd9Sstevel@tonic-gate case IPV6_VERSION: 42557c478bd9Sstevel@tonic-gate /* 42567c478bd9Sstevel@tonic-gate * IPv6 packets can only be received by applications 42577c478bd9Sstevel@tonic-gate * that are prepared to receive IPv6 addresses. 42587c478bd9Sstevel@tonic-gate * The IP fanout must ensure this. 42597c478bd9Sstevel@tonic-gate */ 42607c478bd9Sstevel@tonic-gate ASSERT(udp->udp_family == AF_INET6); 42617c478bd9Sstevel@tonic-gate 42627c478bd9Sstevel@tonic-gate ip6h = (ip6_t *)rptr; 4263ff550d0eSmasputra ASSERT((uchar_t *)&ip6h[1] <= mp->b_wptr); 42647c478bd9Sstevel@tonic-gate 42657c478bd9Sstevel@tonic-gate if (ip6h->ip6_nxt != IPPROTO_UDP) { 42667c478bd9Sstevel@tonic-gate uint8_t nexthdrp; 42677c478bd9Sstevel@tonic-gate /* Look for ifindex information */ 42687c478bd9Sstevel@tonic-gate if (ip6h->ip6_nxt == IPPROTO_RAW) { 42697c478bd9Sstevel@tonic-gate ip6i = (ip6i_t *)ip6h; 42707c478bd9Sstevel@tonic-gate if ((uchar_t *)&ip6i[1] > mp->b_wptr) 42717c478bd9Sstevel@tonic-gate goto tossit; 42727c478bd9Sstevel@tonic-gate 42737c478bd9Sstevel@tonic-gate if (ip6i->ip6i_flags & IP6I_IFINDEX) { 42747c478bd9Sstevel@tonic-gate ASSERT(ip6i->ip6i_ifindex != 0); 42757c478bd9Sstevel@tonic-gate ipp.ipp_fields |= IPPF_IFINDEX; 42767c478bd9Sstevel@tonic-gate ipp.ipp_ifindex = ip6i->ip6i_ifindex; 42777c478bd9Sstevel@tonic-gate } 42787c478bd9Sstevel@tonic-gate rptr = (uchar_t *)&ip6i[1]; 42797c478bd9Sstevel@tonic-gate mp->b_rptr = rptr; 42807c478bd9Sstevel@tonic-gate if (rptr == mp->b_wptr) { 42817c478bd9Sstevel@tonic-gate mp1 = mp->b_cont; 42827c478bd9Sstevel@tonic-gate freeb(mp); 42837c478bd9Sstevel@tonic-gate mp = mp1; 42847c478bd9Sstevel@tonic-gate rptr = mp->b_rptr; 42857c478bd9Sstevel@tonic-gate } 42867c478bd9Sstevel@tonic-gate if (MBLKL(mp) < (IPV6_HDR_LEN + UDPH_SIZE)) 42877c478bd9Sstevel@tonic-gate goto tossit; 42887c478bd9Sstevel@tonic-gate ip6h = (ip6_t *)rptr; 4289ff550d0eSmasputra mp_len = msgdsize(mp); 42907c478bd9Sstevel@tonic-gate } 42917c478bd9Sstevel@tonic-gate /* 42927c478bd9Sstevel@tonic-gate * Find any potentially interesting extension headers 42937c478bd9Sstevel@tonic-gate * as well as the length of the IPv6 + extension 42947c478bd9Sstevel@tonic-gate * headers. 42957c478bd9Sstevel@tonic-gate */ 42967c478bd9Sstevel@tonic-gate hdr_length = ip_find_hdr_v6(mp, ip6h, &ipp, &nexthdrp) + 42977c478bd9Sstevel@tonic-gate UDPH_SIZE; 4298ff550d0eSmasputra ASSERT(nexthdrp == IPPROTO_UDP); 42997c478bd9Sstevel@tonic-gate } else { 43007c478bd9Sstevel@tonic-gate hdr_length = IPV6_HDR_LEN + UDPH_SIZE; 43017c478bd9Sstevel@tonic-gate ip6i = NULL; 43027c478bd9Sstevel@tonic-gate } 43037c478bd9Sstevel@tonic-gate break; 43047c478bd9Sstevel@tonic-gate default: 4305ff550d0eSmasputra ASSERT(0); 43067c478bd9Sstevel@tonic-gate } 43077c478bd9Sstevel@tonic-gate 43087c478bd9Sstevel@tonic-gate /* 43097c478bd9Sstevel@tonic-gate * IP inspected the UDP header thus all of it must be in the mblk. 43107c478bd9Sstevel@tonic-gate * UDP length check is performed for IPv6 packets and IPv4 packets 43117c478bd9Sstevel@tonic-gate * without options to check if the size of the packet as specified 43127c478bd9Sstevel@tonic-gate * by the header is the same as the physical size of the packet. 43137c478bd9Sstevel@tonic-gate */ 43147c478bd9Sstevel@tonic-gate udpha = (udpha_t *)(rptr + (hdr_length - UDPH_SIZE)); 43157c478bd9Sstevel@tonic-gate if ((MBLKL(mp) < hdr_length) || 4316ff550d0eSmasputra (mp_len != (ntohs(udpha->uha_length) + hdr_length - UDPH_SIZE))) { 43177c478bd9Sstevel@tonic-gate goto tossit; 43187c478bd9Sstevel@tonic-gate } 43197c478bd9Sstevel@tonic-gate 43207c478bd9Sstevel@tonic-gate /* Walk past the headers. */ 4321ff550d0eSmasputra if (!udp->udp_rcvhdr) { 43227c478bd9Sstevel@tonic-gate mp->b_rptr = rptr + hdr_length; 4323ff550d0eSmasputra mp_len -= hdr_length; 4324ff550d0eSmasputra } 43257c478bd9Sstevel@tonic-gate 43267c478bd9Sstevel@tonic-gate /* 43277c478bd9Sstevel@tonic-gate * This is the inbound data path. Packets are passed upstream as 43287c478bd9Sstevel@tonic-gate * T_UNITDATA_IND messages with full IP headers still attached. 43297c478bd9Sstevel@tonic-gate */ 43307c478bd9Sstevel@tonic-gate if (udp->udp_family == AF_INET) { 43317c478bd9Sstevel@tonic-gate sin_t *sin; 43327c478bd9Sstevel@tonic-gate 43337c478bd9Sstevel@tonic-gate ASSERT(IPH_HDR_VERSION((ipha_t *)rptr) == IPV4_VERSION); 43347c478bd9Sstevel@tonic-gate 43357c478bd9Sstevel@tonic-gate /* 43367c478bd9Sstevel@tonic-gate * Normally only send up the address. 43377c478bd9Sstevel@tonic-gate * If IP_RECVDSTADDR is set we include the destination IP 43387c478bd9Sstevel@tonic-gate * address as an option. With IP_RECVOPTS we include all 43397c478bd9Sstevel@tonic-gate * the IP options. Only ip_rput_other() handles packets 43407c478bd9Sstevel@tonic-gate * that contain IP options. 43417c478bd9Sstevel@tonic-gate */ 43427c478bd9Sstevel@tonic-gate udi_size = sizeof (struct T_unitdata_ind) + sizeof (sin_t); 43437c478bd9Sstevel@tonic-gate if (udp->udp_recvdstaddr) { 43447c478bd9Sstevel@tonic-gate udi_size += sizeof (struct T_opthdr) + 43457c478bd9Sstevel@tonic-gate sizeof (struct in_addr); 4346ff550d0eSmasputra UDP_STAT(udp_in_recvdstaddr); 43477c478bd9Sstevel@tonic-gate } 43487c478bd9Sstevel@tonic-gate 43497c478bd9Sstevel@tonic-gate /* 43507c478bd9Sstevel@tonic-gate * If the IP_RECVSLLA or the IP_RECVIF is set then allocate 43517c478bd9Sstevel@tonic-gate * space accordingly 43527c478bd9Sstevel@tonic-gate */ 43537c478bd9Sstevel@tonic-gate if (udp->udp_recvif && (pinfo != NULL) && 43547c478bd9Sstevel@tonic-gate (pinfo->in_pkt_flags & IPF_RECVIF)) { 4355ff550d0eSmasputra udi_size += sizeof (struct T_opthdr) + sizeof (uint_t); 4356ff550d0eSmasputra UDP_STAT(udp_in_recvif); 43577c478bd9Sstevel@tonic-gate } 43587c478bd9Sstevel@tonic-gate 43597c478bd9Sstevel@tonic-gate if (udp->udp_recvslla && (pinfo != NULL) && 43607c478bd9Sstevel@tonic-gate (pinfo->in_pkt_flags & IPF_RECVSLLA)) { 43617c478bd9Sstevel@tonic-gate udi_size += sizeof (struct T_opthdr) + 4362ff550d0eSmasputra sizeof (struct sockaddr_dl); 4363ff550d0eSmasputra UDP_STAT(udp_in_recvslla); 43647c478bd9Sstevel@tonic-gate } 43657c478bd9Sstevel@tonic-gate 43667c478bd9Sstevel@tonic-gate if (udp->udp_recvucred && (cr = DB_CRED(mp)) != NULL) { 43677c478bd9Sstevel@tonic-gate udi_size += sizeof (struct T_opthdr) + ucredsize; 43687c478bd9Sstevel@tonic-gate cpid = DB_CPID(mp); 4369ff550d0eSmasputra UDP_STAT(udp_in_recvucred); 43707c478bd9Sstevel@tonic-gate } 43717c478bd9Sstevel@tonic-gate /* 43727c478bd9Sstevel@tonic-gate * If IP_RECVTTL is set allocate the appropriate sized buffer 43737c478bd9Sstevel@tonic-gate */ 43747c478bd9Sstevel@tonic-gate if (udp->udp_recvttl) { 43757c478bd9Sstevel@tonic-gate udi_size += sizeof (struct T_opthdr) + sizeof (uint8_t); 4376ff550d0eSmasputra UDP_STAT(udp_in_recvttl); 43777c478bd9Sstevel@tonic-gate } 43787c478bd9Sstevel@tonic-gate 43797c478bd9Sstevel@tonic-gate ASSERT(IPH_HDR_LENGTH((ipha_t *)rptr) == IP_SIMPLE_HDR_LENGTH); 43807c478bd9Sstevel@tonic-gate 43817c478bd9Sstevel@tonic-gate /* Allocate a message block for the T_UNITDATA_IND structure. */ 43827c478bd9Sstevel@tonic-gate mp1 = allocb(udi_size, BPRI_MED); 43837c478bd9Sstevel@tonic-gate if (mp1 == NULL) { 43847c478bd9Sstevel@tonic-gate freemsg(mp); 43857c478bd9Sstevel@tonic-gate if (options_mp != NULL) 43867c478bd9Sstevel@tonic-gate freeb(options_mp); 43877c478bd9Sstevel@tonic-gate TRACE_2(TR_FAC_UDP, TR_UDP_RPUT_END, 43887c478bd9Sstevel@tonic-gate "udp_rput_end: q %p (%S)", q, "allocbfail"); 43897c478bd9Sstevel@tonic-gate BUMP_MIB(&udp_mib, udpInErrors); 43907c478bd9Sstevel@tonic-gate return; 43917c478bd9Sstevel@tonic-gate } 43927c478bd9Sstevel@tonic-gate mp1->b_cont = mp; 43937c478bd9Sstevel@tonic-gate mp = mp1; 43947c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_PROTO; 43957c478bd9Sstevel@tonic-gate tudi = (struct T_unitdata_ind *)mp->b_rptr; 43967c478bd9Sstevel@tonic-gate mp->b_wptr = (uchar_t *)tudi + udi_size; 43977c478bd9Sstevel@tonic-gate tudi->PRIM_type = T_UNITDATA_IND; 43987c478bd9Sstevel@tonic-gate tudi->SRC_length = sizeof (sin_t); 43997c478bd9Sstevel@tonic-gate tudi->SRC_offset = sizeof (struct T_unitdata_ind); 44007c478bd9Sstevel@tonic-gate tudi->OPT_offset = sizeof (struct T_unitdata_ind) + 44017c478bd9Sstevel@tonic-gate sizeof (sin_t); 44027c478bd9Sstevel@tonic-gate udi_size -= (sizeof (struct T_unitdata_ind) + sizeof (sin_t)); 44037c478bd9Sstevel@tonic-gate tudi->OPT_length = udi_size; 44047c478bd9Sstevel@tonic-gate sin = (sin_t *)&tudi[1]; 44057c478bd9Sstevel@tonic-gate sin->sin_addr.s_addr = ((ipha_t *)rptr)->ipha_src; 44067c478bd9Sstevel@tonic-gate sin->sin_port = udpha->uha_src_port; 44077c478bd9Sstevel@tonic-gate sin->sin_family = udp->udp_family; 44087c478bd9Sstevel@tonic-gate *(uint32_t *)&sin->sin_zero[0] = 0; 44097c478bd9Sstevel@tonic-gate *(uint32_t *)&sin->sin_zero[4] = 0; 44107c478bd9Sstevel@tonic-gate 44117c478bd9Sstevel@tonic-gate /* 44127c478bd9Sstevel@tonic-gate * Add options if IP_RECVDSTADDR, IP_RECVIF, IP_RECVSLLA or 44137c478bd9Sstevel@tonic-gate * IP_RECVTTL has been set. 44147c478bd9Sstevel@tonic-gate */ 44157c478bd9Sstevel@tonic-gate if (udi_size != 0) { 44167c478bd9Sstevel@tonic-gate /* 44177c478bd9Sstevel@tonic-gate * Copy in destination address before options to avoid 44187c478bd9Sstevel@tonic-gate * any padding issues. 44197c478bd9Sstevel@tonic-gate */ 44207c478bd9Sstevel@tonic-gate char *dstopt; 44217c478bd9Sstevel@tonic-gate 44227c478bd9Sstevel@tonic-gate dstopt = (char *)&sin[1]; 44237c478bd9Sstevel@tonic-gate if (udp->udp_recvdstaddr) { 44247c478bd9Sstevel@tonic-gate struct T_opthdr *toh; 44257c478bd9Sstevel@tonic-gate ipaddr_t *dstptr; 44267c478bd9Sstevel@tonic-gate 44277c478bd9Sstevel@tonic-gate toh = (struct T_opthdr *)dstopt; 44287c478bd9Sstevel@tonic-gate toh->level = IPPROTO_IP; 44297c478bd9Sstevel@tonic-gate toh->name = IP_RECVDSTADDR; 44307c478bd9Sstevel@tonic-gate toh->len = sizeof (struct T_opthdr) + 44317c478bd9Sstevel@tonic-gate sizeof (ipaddr_t); 44327c478bd9Sstevel@tonic-gate toh->status = 0; 44337c478bd9Sstevel@tonic-gate dstopt += sizeof (struct T_opthdr); 44347c478bd9Sstevel@tonic-gate dstptr = (ipaddr_t *)dstopt; 44357c478bd9Sstevel@tonic-gate *dstptr = ((ipha_t *)rptr)->ipha_dst; 44367c478bd9Sstevel@tonic-gate dstopt += sizeof (ipaddr_t); 44377c478bd9Sstevel@tonic-gate udi_size -= toh->len; 44387c478bd9Sstevel@tonic-gate } 44397c478bd9Sstevel@tonic-gate 44407c478bd9Sstevel@tonic-gate if (udp->udp_recvslla && (pinfo != NULL) && 44417c478bd9Sstevel@tonic-gate (pinfo->in_pkt_flags & IPF_RECVSLLA)) { 44427c478bd9Sstevel@tonic-gate 44437c478bd9Sstevel@tonic-gate struct T_opthdr *toh; 44447c478bd9Sstevel@tonic-gate struct sockaddr_dl *dstptr; 44457c478bd9Sstevel@tonic-gate 44467c478bd9Sstevel@tonic-gate toh = (struct T_opthdr *)dstopt; 44477c478bd9Sstevel@tonic-gate toh->level = IPPROTO_IP; 44487c478bd9Sstevel@tonic-gate toh->name = IP_RECVSLLA; 44497c478bd9Sstevel@tonic-gate toh->len = sizeof (struct T_opthdr) + 44507c478bd9Sstevel@tonic-gate sizeof (struct sockaddr_dl); 44517c478bd9Sstevel@tonic-gate toh->status = 0; 44527c478bd9Sstevel@tonic-gate dstopt += sizeof (struct T_opthdr); 44537c478bd9Sstevel@tonic-gate dstptr = (struct sockaddr_dl *)dstopt; 44547c478bd9Sstevel@tonic-gate bcopy(&pinfo->in_pkt_slla, dstptr, 44557c478bd9Sstevel@tonic-gate sizeof (struct sockaddr_dl)); 44567c478bd9Sstevel@tonic-gate dstopt += sizeof (struct sockaddr_dl); 44577c478bd9Sstevel@tonic-gate udi_size -= toh->len; 44587c478bd9Sstevel@tonic-gate } 44597c478bd9Sstevel@tonic-gate 44607c478bd9Sstevel@tonic-gate if (udp->udp_recvif && (pinfo != NULL) && 44617c478bd9Sstevel@tonic-gate (pinfo->in_pkt_flags & IPF_RECVIF)) { 44627c478bd9Sstevel@tonic-gate 44637c478bd9Sstevel@tonic-gate struct T_opthdr *toh; 44647c478bd9Sstevel@tonic-gate uint_t *dstptr; 44657c478bd9Sstevel@tonic-gate 44667c478bd9Sstevel@tonic-gate toh = (struct T_opthdr *)dstopt; 44677c478bd9Sstevel@tonic-gate toh->level = IPPROTO_IP; 44687c478bd9Sstevel@tonic-gate toh->name = IP_RECVIF; 44697c478bd9Sstevel@tonic-gate toh->len = sizeof (struct T_opthdr) + 44707c478bd9Sstevel@tonic-gate sizeof (uint_t); 44717c478bd9Sstevel@tonic-gate toh->status = 0; 44727c478bd9Sstevel@tonic-gate dstopt += sizeof (struct T_opthdr); 44737c478bd9Sstevel@tonic-gate dstptr = (uint_t *)dstopt; 44747c478bd9Sstevel@tonic-gate *dstptr = pinfo->in_pkt_ifindex; 44757c478bd9Sstevel@tonic-gate dstopt += sizeof (uint_t); 44767c478bd9Sstevel@tonic-gate udi_size -= toh->len; 44777c478bd9Sstevel@tonic-gate } 44787c478bd9Sstevel@tonic-gate 44797c478bd9Sstevel@tonic-gate if (cr != NULL) { 44807c478bd9Sstevel@tonic-gate struct T_opthdr *toh; 44817c478bd9Sstevel@tonic-gate 44827c478bd9Sstevel@tonic-gate toh = (struct T_opthdr *)dstopt; 44837c478bd9Sstevel@tonic-gate toh->level = SOL_SOCKET; 44847c478bd9Sstevel@tonic-gate toh->name = SCM_UCRED; 44857c478bd9Sstevel@tonic-gate toh->len = sizeof (struct T_opthdr) + ucredsize; 44867c478bd9Sstevel@tonic-gate toh->status = 0; 44877c478bd9Sstevel@tonic-gate (void) cred2ucred(cr, cpid, &toh[1]); 44887c478bd9Sstevel@tonic-gate dstopt += toh->len; 44897c478bd9Sstevel@tonic-gate udi_size -= toh->len; 44907c478bd9Sstevel@tonic-gate } 44917c478bd9Sstevel@tonic-gate 44927c478bd9Sstevel@tonic-gate if (udp->udp_recvttl) { 44937c478bd9Sstevel@tonic-gate struct T_opthdr *toh; 44947c478bd9Sstevel@tonic-gate uint8_t *dstptr; 44957c478bd9Sstevel@tonic-gate 44967c478bd9Sstevel@tonic-gate toh = (struct T_opthdr *)dstopt; 44977c478bd9Sstevel@tonic-gate toh->level = IPPROTO_IP; 44987c478bd9Sstevel@tonic-gate toh->name = IP_RECVTTL; 44997c478bd9Sstevel@tonic-gate toh->len = sizeof (struct T_opthdr) + 45007c478bd9Sstevel@tonic-gate sizeof (uint8_t); 45017c478bd9Sstevel@tonic-gate toh->status = 0; 45027c478bd9Sstevel@tonic-gate dstopt += sizeof (struct T_opthdr); 45037c478bd9Sstevel@tonic-gate dstptr = (uint8_t *)dstopt; 45047c478bd9Sstevel@tonic-gate *dstptr = ((ipha_t *)rptr)->ipha_ttl; 45057c478bd9Sstevel@tonic-gate dstopt += sizeof (uint8_t); 45067c478bd9Sstevel@tonic-gate udi_size -= toh->len; 45077c478bd9Sstevel@tonic-gate } 45087c478bd9Sstevel@tonic-gate 45097c478bd9Sstevel@tonic-gate /* Consumed all of allocated space */ 45107c478bd9Sstevel@tonic-gate ASSERT(udi_size == 0); 45117c478bd9Sstevel@tonic-gate } 45127c478bd9Sstevel@tonic-gate } else { 45137c478bd9Sstevel@tonic-gate sin6_t *sin6; 45147c478bd9Sstevel@tonic-gate 45157c478bd9Sstevel@tonic-gate /* 45167c478bd9Sstevel@tonic-gate * Handle both IPv4 and IPv6 packets for IPv6 sockets. 45177c478bd9Sstevel@tonic-gate * 45187c478bd9Sstevel@tonic-gate * Normally we only send up the address. If receiving of any 45197c478bd9Sstevel@tonic-gate * optional receive side information is enabled, we also send 45207c478bd9Sstevel@tonic-gate * that up as options. 45217c478bd9Sstevel@tonic-gate * [ Only udp_rput_other() handles packets that contain IP 45227c478bd9Sstevel@tonic-gate * options so code to account for does not appear immediately 45237c478bd9Sstevel@tonic-gate * below but elsewhere ] 45247c478bd9Sstevel@tonic-gate */ 45257c478bd9Sstevel@tonic-gate udi_size = sizeof (struct T_unitdata_ind) + sizeof (sin6_t); 45267c478bd9Sstevel@tonic-gate 45277c478bd9Sstevel@tonic-gate if (ipp.ipp_fields & (IPPF_HOPOPTS|IPPF_DSTOPTS|IPPF_RTDSTOPTS| 45287c478bd9Sstevel@tonic-gate IPPF_RTHDR|IPPF_IFINDEX)) { 45297c478bd9Sstevel@tonic-gate if (udp->udp_ipv6_recvhopopts && 45307c478bd9Sstevel@tonic-gate (ipp.ipp_fields & IPPF_HOPOPTS)) { 45317c478bd9Sstevel@tonic-gate udi_size += sizeof (struct T_opthdr) + 45327c478bd9Sstevel@tonic-gate ipp.ipp_hopoptslen; 4533ff550d0eSmasputra UDP_STAT(udp_in_recvhopopts); 45347c478bd9Sstevel@tonic-gate } 45357c478bd9Sstevel@tonic-gate if ((udp->udp_ipv6_recvdstopts || 45367c478bd9Sstevel@tonic-gate udp->udp_old_ipv6_recvdstopts) && 45377c478bd9Sstevel@tonic-gate (ipp.ipp_fields & IPPF_DSTOPTS)) { 45387c478bd9Sstevel@tonic-gate udi_size += sizeof (struct T_opthdr) + 45397c478bd9Sstevel@tonic-gate ipp.ipp_dstoptslen; 4540ff550d0eSmasputra UDP_STAT(udp_in_recvdstopts); 45417c478bd9Sstevel@tonic-gate } 45427c478bd9Sstevel@tonic-gate if (((udp->udp_ipv6_recvdstopts && 45437c478bd9Sstevel@tonic-gate udp->udp_ipv6_recvrthdr && 45447c478bd9Sstevel@tonic-gate (ipp.ipp_fields & IPPF_RTHDR)) || 45457c478bd9Sstevel@tonic-gate udp->udp_ipv6_recvrthdrdstopts) && 45467c478bd9Sstevel@tonic-gate (ipp.ipp_fields & IPPF_RTDSTOPTS)) { 45477c478bd9Sstevel@tonic-gate udi_size += sizeof (struct T_opthdr) + 45487c478bd9Sstevel@tonic-gate ipp.ipp_rtdstoptslen; 4549ff550d0eSmasputra UDP_STAT(udp_in_recvrtdstopts); 45507c478bd9Sstevel@tonic-gate } 45517c478bd9Sstevel@tonic-gate if (udp->udp_ipv6_recvrthdr && 45527c478bd9Sstevel@tonic-gate (ipp.ipp_fields & IPPF_RTHDR)) { 45537c478bd9Sstevel@tonic-gate udi_size += sizeof (struct T_opthdr) + 45547c478bd9Sstevel@tonic-gate ipp.ipp_rthdrlen; 4555ff550d0eSmasputra UDP_STAT(udp_in_recvrthdr); 45567c478bd9Sstevel@tonic-gate } 45577c478bd9Sstevel@tonic-gate if (udp->udp_ipv6_recvpktinfo && 45587c478bd9Sstevel@tonic-gate (ipp.ipp_fields & IPPF_IFINDEX)) { 45597c478bd9Sstevel@tonic-gate udi_size += sizeof (struct T_opthdr) + 45607c478bd9Sstevel@tonic-gate sizeof (struct in6_pktinfo); 4561ff550d0eSmasputra UDP_STAT(udp_in_recvpktinfo); 45627c478bd9Sstevel@tonic-gate } 45637c478bd9Sstevel@tonic-gate 45647c478bd9Sstevel@tonic-gate } 45657c478bd9Sstevel@tonic-gate if (udp->udp_recvucred && (cr = DB_CRED(mp)) != NULL) { 45667c478bd9Sstevel@tonic-gate udi_size += sizeof (struct T_opthdr) + ucredsize; 45677c478bd9Sstevel@tonic-gate cpid = DB_CPID(mp); 4568ff550d0eSmasputra UDP_STAT(udp_in_recvucred); 45697c478bd9Sstevel@tonic-gate } 45707c478bd9Sstevel@tonic-gate 4571ff550d0eSmasputra if (udp->udp_ipv6_recvhoplimit) { 45727c478bd9Sstevel@tonic-gate udi_size += sizeof (struct T_opthdr) + sizeof (int); 4573ff550d0eSmasputra UDP_STAT(udp_in_recvhoplimit); 4574ff550d0eSmasputra } 45757c478bd9Sstevel@tonic-gate 4576ff550d0eSmasputra if (udp->udp_ipv6_recvtclass) { 45777c478bd9Sstevel@tonic-gate udi_size += sizeof (struct T_opthdr) + sizeof (int); 4578ff550d0eSmasputra UDP_STAT(udp_in_recvtclass); 4579ff550d0eSmasputra } 45807c478bd9Sstevel@tonic-gate 45817c478bd9Sstevel@tonic-gate mp1 = allocb(udi_size, BPRI_MED); 45827c478bd9Sstevel@tonic-gate if (mp1 == NULL) { 45837c478bd9Sstevel@tonic-gate freemsg(mp); 45847c478bd9Sstevel@tonic-gate if (options_mp != NULL) 45857c478bd9Sstevel@tonic-gate freeb(options_mp); 45867c478bd9Sstevel@tonic-gate TRACE_2(TR_FAC_UDP, TR_UDP_RPUT_END, 45877c478bd9Sstevel@tonic-gate "udp_rput_end: q %p (%S)", q, "allocbfail"); 45887c478bd9Sstevel@tonic-gate BUMP_MIB(&udp_mib, udpInErrors); 45897c478bd9Sstevel@tonic-gate return; 45907c478bd9Sstevel@tonic-gate } 45917c478bd9Sstevel@tonic-gate mp1->b_cont = mp; 45927c478bd9Sstevel@tonic-gate mp = mp1; 45937c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_PROTO; 45947c478bd9Sstevel@tonic-gate tudi = (struct T_unitdata_ind *)mp->b_rptr; 45957c478bd9Sstevel@tonic-gate mp->b_wptr = (uchar_t *)tudi + udi_size; 45967c478bd9Sstevel@tonic-gate tudi->PRIM_type = T_UNITDATA_IND; 45977c478bd9Sstevel@tonic-gate tudi->SRC_length = sizeof (sin6_t); 45987c478bd9Sstevel@tonic-gate tudi->SRC_offset = sizeof (struct T_unitdata_ind); 45997c478bd9Sstevel@tonic-gate tudi->OPT_offset = sizeof (struct T_unitdata_ind) + 46007c478bd9Sstevel@tonic-gate sizeof (sin6_t); 46017c478bd9Sstevel@tonic-gate udi_size -= (sizeof (struct T_unitdata_ind) + sizeof (sin6_t)); 46027c478bd9Sstevel@tonic-gate tudi->OPT_length = udi_size; 46037c478bd9Sstevel@tonic-gate sin6 = (sin6_t *)&tudi[1]; 46047c478bd9Sstevel@tonic-gate if (ipversion == IPV4_VERSION) { 46057c478bd9Sstevel@tonic-gate in6_addr_t v6dst; 46067c478bd9Sstevel@tonic-gate 46077c478bd9Sstevel@tonic-gate IN6_IPADDR_TO_V4MAPPED(((ipha_t *)rptr)->ipha_src, 46087c478bd9Sstevel@tonic-gate &sin6->sin6_addr); 46097c478bd9Sstevel@tonic-gate IN6_IPADDR_TO_V4MAPPED(((ipha_t *)rptr)->ipha_dst, 46107c478bd9Sstevel@tonic-gate &v6dst); 46117c478bd9Sstevel@tonic-gate sin6->sin6_flowinfo = 0; 46127c478bd9Sstevel@tonic-gate sin6->sin6_scope_id = 0; 46137c478bd9Sstevel@tonic-gate sin6->__sin6_src_id = ip_srcid_find_addr(&v6dst, 4614ff550d0eSmasputra connp->conn_zoneid); 46157c478bd9Sstevel@tonic-gate } else { 46167c478bd9Sstevel@tonic-gate sin6->sin6_addr = ip6h->ip6_src; 46177c478bd9Sstevel@tonic-gate /* No sin6_flowinfo per API */ 46187c478bd9Sstevel@tonic-gate sin6->sin6_flowinfo = 0; 46197c478bd9Sstevel@tonic-gate /* For link-scope source pass up scope id */ 46207c478bd9Sstevel@tonic-gate if ((ipp.ipp_fields & IPPF_IFINDEX) && 46217c478bd9Sstevel@tonic-gate IN6_IS_ADDR_LINKSCOPE(&ip6h->ip6_src)) 46227c478bd9Sstevel@tonic-gate sin6->sin6_scope_id = ipp.ipp_ifindex; 46237c478bd9Sstevel@tonic-gate else 46247c478bd9Sstevel@tonic-gate sin6->sin6_scope_id = 0; 4625ff550d0eSmasputra sin6->__sin6_src_id = ip_srcid_find_addr( 4626ff550d0eSmasputra &ip6h->ip6_dst, connp->conn_zoneid); 46277c478bd9Sstevel@tonic-gate } 46287c478bd9Sstevel@tonic-gate sin6->sin6_port = udpha->uha_src_port; 46297c478bd9Sstevel@tonic-gate sin6->sin6_family = udp->udp_family; 46307c478bd9Sstevel@tonic-gate 46317c478bd9Sstevel@tonic-gate if (udi_size != 0) { 46327c478bd9Sstevel@tonic-gate uchar_t *dstopt; 46337c478bd9Sstevel@tonic-gate 46347c478bd9Sstevel@tonic-gate dstopt = (uchar_t *)&sin6[1]; 46357c478bd9Sstevel@tonic-gate if (udp->udp_ipv6_recvpktinfo && 46367c478bd9Sstevel@tonic-gate (ipp.ipp_fields & IPPF_IFINDEX)) { 46377c478bd9Sstevel@tonic-gate struct T_opthdr *toh; 46387c478bd9Sstevel@tonic-gate struct in6_pktinfo *pkti; 46397c478bd9Sstevel@tonic-gate 46407c478bd9Sstevel@tonic-gate toh = (struct T_opthdr *)dstopt; 46417c478bd9Sstevel@tonic-gate toh->level = IPPROTO_IPV6; 46427c478bd9Sstevel@tonic-gate toh->name = IPV6_PKTINFO; 46437c478bd9Sstevel@tonic-gate toh->len = sizeof (struct T_opthdr) + 46447c478bd9Sstevel@tonic-gate sizeof (*pkti); 46457c478bd9Sstevel@tonic-gate toh->status = 0; 46467c478bd9Sstevel@tonic-gate dstopt += sizeof (struct T_opthdr); 46477c478bd9Sstevel@tonic-gate pkti = (struct in6_pktinfo *)dstopt; 46487c478bd9Sstevel@tonic-gate if (ipversion == IPV6_VERSION) 46497c478bd9Sstevel@tonic-gate pkti->ipi6_addr = ip6h->ip6_dst; 46507c478bd9Sstevel@tonic-gate else 46517c478bd9Sstevel@tonic-gate IN6_IPADDR_TO_V4MAPPED( 46527c478bd9Sstevel@tonic-gate ((ipha_t *)rptr)->ipha_dst, 46537c478bd9Sstevel@tonic-gate &pkti->ipi6_addr); 46547c478bd9Sstevel@tonic-gate pkti->ipi6_ifindex = ipp.ipp_ifindex; 46557c478bd9Sstevel@tonic-gate dstopt += sizeof (*pkti); 46567c478bd9Sstevel@tonic-gate udi_size -= toh->len; 46577c478bd9Sstevel@tonic-gate } 46587c478bd9Sstevel@tonic-gate if (udp->udp_ipv6_recvhoplimit) { 46597c478bd9Sstevel@tonic-gate struct T_opthdr *toh; 46607c478bd9Sstevel@tonic-gate 46617c478bd9Sstevel@tonic-gate toh = (struct T_opthdr *)dstopt; 46627c478bd9Sstevel@tonic-gate toh->level = IPPROTO_IPV6; 46637c478bd9Sstevel@tonic-gate toh->name = IPV6_HOPLIMIT; 46647c478bd9Sstevel@tonic-gate toh->len = sizeof (struct T_opthdr) + 46657c478bd9Sstevel@tonic-gate sizeof (uint_t); 46667c478bd9Sstevel@tonic-gate toh->status = 0; 46677c478bd9Sstevel@tonic-gate dstopt += sizeof (struct T_opthdr); 46687c478bd9Sstevel@tonic-gate if (ipversion == IPV6_VERSION) 46697c478bd9Sstevel@tonic-gate *(uint_t *)dstopt = ip6h->ip6_hops; 46707c478bd9Sstevel@tonic-gate else 46717c478bd9Sstevel@tonic-gate *(uint_t *)dstopt = 46727c478bd9Sstevel@tonic-gate ((ipha_t *)rptr)->ipha_ttl; 46737c478bd9Sstevel@tonic-gate dstopt += sizeof (uint_t); 46747c478bd9Sstevel@tonic-gate udi_size -= toh->len; 46757c478bd9Sstevel@tonic-gate } 46767c478bd9Sstevel@tonic-gate if (udp->udp_ipv6_recvtclass) { 46777c478bd9Sstevel@tonic-gate struct T_opthdr *toh; 46787c478bd9Sstevel@tonic-gate 46797c478bd9Sstevel@tonic-gate toh = (struct T_opthdr *)dstopt; 46807c478bd9Sstevel@tonic-gate toh->level = IPPROTO_IPV6; 46817c478bd9Sstevel@tonic-gate toh->name = IPV6_TCLASS; 46827c478bd9Sstevel@tonic-gate toh->len = sizeof (struct T_opthdr) + 46837c478bd9Sstevel@tonic-gate sizeof (uint_t); 46847c478bd9Sstevel@tonic-gate toh->status = 0; 46857c478bd9Sstevel@tonic-gate dstopt += sizeof (struct T_opthdr); 46867c478bd9Sstevel@tonic-gate if (ipversion == IPV6_VERSION) { 46877c478bd9Sstevel@tonic-gate *(uint_t *)dstopt = 46887c478bd9Sstevel@tonic-gate IPV6_FLOW_TCLASS(ip6h->ip6_flow); 46897c478bd9Sstevel@tonic-gate } else { 46907c478bd9Sstevel@tonic-gate ipha_t *ipha = (ipha_t *)rptr; 46917c478bd9Sstevel@tonic-gate *(uint_t *)dstopt = 46927c478bd9Sstevel@tonic-gate ipha->ipha_type_of_service; 46937c478bd9Sstevel@tonic-gate } 46947c478bd9Sstevel@tonic-gate dstopt += sizeof (uint_t); 46957c478bd9Sstevel@tonic-gate udi_size -= toh->len; 46967c478bd9Sstevel@tonic-gate } 46977c478bd9Sstevel@tonic-gate if (udp->udp_ipv6_recvhopopts && 46987c478bd9Sstevel@tonic-gate (ipp.ipp_fields & IPPF_HOPOPTS)) { 46997c478bd9Sstevel@tonic-gate struct T_opthdr *toh; 47007c478bd9Sstevel@tonic-gate 47017c478bd9Sstevel@tonic-gate toh = (struct T_opthdr *)dstopt; 47027c478bd9Sstevel@tonic-gate toh->level = IPPROTO_IPV6; 47037c478bd9Sstevel@tonic-gate toh->name = IPV6_HOPOPTS; 47047c478bd9Sstevel@tonic-gate toh->len = sizeof (struct T_opthdr) + 47057c478bd9Sstevel@tonic-gate ipp.ipp_hopoptslen; 47067c478bd9Sstevel@tonic-gate toh->status = 0; 47077c478bd9Sstevel@tonic-gate dstopt += sizeof (struct T_opthdr); 47087c478bd9Sstevel@tonic-gate bcopy(ipp.ipp_hopopts, dstopt, 47097c478bd9Sstevel@tonic-gate ipp.ipp_hopoptslen); 47107c478bd9Sstevel@tonic-gate dstopt += ipp.ipp_hopoptslen; 47117c478bd9Sstevel@tonic-gate udi_size -= toh->len; 47127c478bd9Sstevel@tonic-gate } 47137c478bd9Sstevel@tonic-gate if (udp->udp_ipv6_recvdstopts && 47147c478bd9Sstevel@tonic-gate udp->udp_ipv6_recvrthdr && 47157c478bd9Sstevel@tonic-gate (ipp.ipp_fields & IPPF_RTHDR) && 47167c478bd9Sstevel@tonic-gate (ipp.ipp_fields & IPPF_RTDSTOPTS)) { 47177c478bd9Sstevel@tonic-gate struct T_opthdr *toh; 47187c478bd9Sstevel@tonic-gate 47197c478bd9Sstevel@tonic-gate toh = (struct T_opthdr *)dstopt; 47207c478bd9Sstevel@tonic-gate toh->level = IPPROTO_IPV6; 47217c478bd9Sstevel@tonic-gate toh->name = IPV6_DSTOPTS; 47227c478bd9Sstevel@tonic-gate toh->len = sizeof (struct T_opthdr) + 47237c478bd9Sstevel@tonic-gate ipp.ipp_rtdstoptslen; 47247c478bd9Sstevel@tonic-gate toh->status = 0; 47257c478bd9Sstevel@tonic-gate dstopt += sizeof (struct T_opthdr); 47267c478bd9Sstevel@tonic-gate bcopy(ipp.ipp_rtdstopts, dstopt, 47277c478bd9Sstevel@tonic-gate ipp.ipp_rtdstoptslen); 47287c478bd9Sstevel@tonic-gate dstopt += ipp.ipp_rtdstoptslen; 47297c478bd9Sstevel@tonic-gate udi_size -= toh->len; 47307c478bd9Sstevel@tonic-gate } 47317c478bd9Sstevel@tonic-gate if (udp->udp_ipv6_recvrthdr && 47327c478bd9Sstevel@tonic-gate (ipp.ipp_fields & IPPF_RTHDR)) { 47337c478bd9Sstevel@tonic-gate struct T_opthdr *toh; 47347c478bd9Sstevel@tonic-gate 47357c478bd9Sstevel@tonic-gate toh = (struct T_opthdr *)dstopt; 47367c478bd9Sstevel@tonic-gate toh->level = IPPROTO_IPV6; 47377c478bd9Sstevel@tonic-gate toh->name = IPV6_RTHDR; 47387c478bd9Sstevel@tonic-gate toh->len = sizeof (struct T_opthdr) + 47397c478bd9Sstevel@tonic-gate ipp.ipp_rthdrlen; 47407c478bd9Sstevel@tonic-gate toh->status = 0; 47417c478bd9Sstevel@tonic-gate dstopt += sizeof (struct T_opthdr); 47427c478bd9Sstevel@tonic-gate bcopy(ipp.ipp_rthdr, dstopt, ipp.ipp_rthdrlen); 47437c478bd9Sstevel@tonic-gate dstopt += ipp.ipp_rthdrlen; 47447c478bd9Sstevel@tonic-gate udi_size -= toh->len; 47457c478bd9Sstevel@tonic-gate } 47467c478bd9Sstevel@tonic-gate if (udp->udp_ipv6_recvdstopts && 47477c478bd9Sstevel@tonic-gate (ipp.ipp_fields & IPPF_DSTOPTS)) { 47487c478bd9Sstevel@tonic-gate struct T_opthdr *toh; 47497c478bd9Sstevel@tonic-gate 47507c478bd9Sstevel@tonic-gate toh = (struct T_opthdr *)dstopt; 47517c478bd9Sstevel@tonic-gate toh->level = IPPROTO_IPV6; 47527c478bd9Sstevel@tonic-gate toh->name = IPV6_DSTOPTS; 47537c478bd9Sstevel@tonic-gate toh->len = sizeof (struct T_opthdr) + 47547c478bd9Sstevel@tonic-gate ipp.ipp_dstoptslen; 47557c478bd9Sstevel@tonic-gate toh->status = 0; 47567c478bd9Sstevel@tonic-gate dstopt += sizeof (struct T_opthdr); 47577c478bd9Sstevel@tonic-gate bcopy(ipp.ipp_dstopts, dstopt, 47587c478bd9Sstevel@tonic-gate ipp.ipp_dstoptslen); 47597c478bd9Sstevel@tonic-gate dstopt += ipp.ipp_dstoptslen; 47607c478bd9Sstevel@tonic-gate udi_size -= toh->len; 47617c478bd9Sstevel@tonic-gate } 47627c478bd9Sstevel@tonic-gate 47637c478bd9Sstevel@tonic-gate if (cr != NULL) { 47647c478bd9Sstevel@tonic-gate struct T_opthdr *toh; 47657c478bd9Sstevel@tonic-gate 47667c478bd9Sstevel@tonic-gate toh = (struct T_opthdr *)dstopt; 47677c478bd9Sstevel@tonic-gate toh->level = SOL_SOCKET; 47687c478bd9Sstevel@tonic-gate toh->name = SCM_UCRED; 47697c478bd9Sstevel@tonic-gate toh->len = sizeof (struct T_opthdr) + ucredsize; 47707c478bd9Sstevel@tonic-gate toh->status = 0; 47717c478bd9Sstevel@tonic-gate (void) cred2ucred(cr, cpid, &toh[1]); 47727c478bd9Sstevel@tonic-gate dstopt += toh->len; 47737c478bd9Sstevel@tonic-gate udi_size -= toh->len; 47747c478bd9Sstevel@tonic-gate } 47757c478bd9Sstevel@tonic-gate /* Consumed all of allocated space */ 47767c478bd9Sstevel@tonic-gate ASSERT(udi_size == 0); 47777c478bd9Sstevel@tonic-gate } 47787c478bd9Sstevel@tonic-gate #undef sin6 47797c478bd9Sstevel@tonic-gate /* No IP_RECVDSTADDR for IPv6. */ 47807c478bd9Sstevel@tonic-gate } 47817c478bd9Sstevel@tonic-gate 47827c478bd9Sstevel@tonic-gate BUMP_MIB(&udp_mib, udpInDatagrams); 47837c478bd9Sstevel@tonic-gate TRACE_2(TR_FAC_UDP, TR_UDP_RPUT_END, 47847c478bd9Sstevel@tonic-gate "udp_rput_end: q %p (%S)", q, "end"); 47857c478bd9Sstevel@tonic-gate if (options_mp != NULL) 47867c478bd9Sstevel@tonic-gate freeb(options_mp); 4787ff550d0eSmasputra 4788ff550d0eSmasputra if (udp->udp_direct_sockfs) { 4789ff550d0eSmasputra /* 4790ff550d0eSmasputra * There is nothing above us except for the stream head; 4791ff550d0eSmasputra * use the read-side synchronous stream interface in 4792ff550d0eSmasputra * order to reduce the time spent in interrupt thread. 4793ff550d0eSmasputra */ 4794ff550d0eSmasputra ASSERT(udp->udp_issocket); 4795ff550d0eSmasputra udp_rcv_enqueue(UDP_RD(q), udp, mp, mp_len); 4796ff550d0eSmasputra } else { 4797ff550d0eSmasputra /* 4798ff550d0eSmasputra * Use regular STREAMS interface to pass data upstream 4799ff550d0eSmasputra * if this is not a socket endpoint, or if we have 4800ff550d0eSmasputra * switched over to the slow mode due to sockmod being 4801ff550d0eSmasputra * popped or a module being pushed on top of us. 4802ff550d0eSmasputra */ 4803ff550d0eSmasputra putnext(UDP_RD(q), mp); 4804ff550d0eSmasputra } 4805ff550d0eSmasputra return; 4806ff550d0eSmasputra 4807ff550d0eSmasputra tossit: 4808ff550d0eSmasputra freemsg(mp); 4809ff550d0eSmasputra if (options_mp != NULL) 4810ff550d0eSmasputra freeb(options_mp); 4811ff550d0eSmasputra BUMP_MIB(&udp_mib, udpInErrors); 4812ff550d0eSmasputra } 4813ff550d0eSmasputra 4814ff550d0eSmasputra void 4815ff550d0eSmasputra udp_conn_recv(conn_t *connp, mblk_t *mp) 4816ff550d0eSmasputra { 4817ff550d0eSmasputra _UDP_ENTER(connp, mp, udp_input_wrapper, SQTAG_UDP_FANOUT); 4818ff550d0eSmasputra } 4819ff550d0eSmasputra 4820ff550d0eSmasputra /* ARGSUSED */ 4821ff550d0eSmasputra static void 4822ff550d0eSmasputra udp_input_wrapper(void *arg, mblk_t *mp, void *arg2) 4823ff550d0eSmasputra { 4824ff550d0eSmasputra udp_input((conn_t *)arg, mp); 4825ff550d0eSmasputra _UDP_EXIT((conn_t *)arg); 48267c478bd9Sstevel@tonic-gate } 48277c478bd9Sstevel@tonic-gate 48287c478bd9Sstevel@tonic-gate /* 48297c478bd9Sstevel@tonic-gate * Process non-M_DATA messages as well as M_DATA messages that requires 48307c478bd9Sstevel@tonic-gate * modifications to udp_ip_rcv_options i.e. IPv4 packets with IP options. 48317c478bd9Sstevel@tonic-gate */ 48327c478bd9Sstevel@tonic-gate static void 48337c478bd9Sstevel@tonic-gate udp_rput_other(queue_t *q, mblk_t *mp) 48347c478bd9Sstevel@tonic-gate { 48357c478bd9Sstevel@tonic-gate struct T_unitdata_ind *tudi; 48367c478bd9Sstevel@tonic-gate mblk_t *mp1; 48377c478bd9Sstevel@tonic-gate uchar_t *rptr; 48387c478bd9Sstevel@tonic-gate uchar_t *new_rptr; 48397c478bd9Sstevel@tonic-gate int hdr_length; 48407c478bd9Sstevel@tonic-gate int udi_size; /* Size of T_unitdata_ind */ 48417c478bd9Sstevel@tonic-gate int opt_len; /* Length of IP options */ 48427c478bd9Sstevel@tonic-gate sin_t *sin; 48437c478bd9Sstevel@tonic-gate struct T_error_ack *tea; 48447c478bd9Sstevel@tonic-gate mblk_t *options_mp = NULL; 48457c478bd9Sstevel@tonic-gate in_pktinfo_t *pinfo; 48467c478bd9Sstevel@tonic-gate boolean_t recv_on = B_FALSE; 48477c478bd9Sstevel@tonic-gate cred_t *cr = NULL; 4848ff550d0eSmasputra udp_t *udp = Q_TO_UDP(q); 48497c478bd9Sstevel@tonic-gate pid_t cpid; 48507c478bd9Sstevel@tonic-gate 48517c478bd9Sstevel@tonic-gate TRACE_2(TR_FAC_UDP, TR_UDP_RPUT_START, 48527c478bd9Sstevel@tonic-gate "udp_rput_other: q %p mp %p", q, mp); 48537c478bd9Sstevel@tonic-gate 48547c478bd9Sstevel@tonic-gate ASSERT(OK_32PTR(mp->b_rptr)); 48557c478bd9Sstevel@tonic-gate rptr = mp->b_rptr; 48567c478bd9Sstevel@tonic-gate 48577c478bd9Sstevel@tonic-gate switch (mp->b_datap->db_type) { 48587c478bd9Sstevel@tonic-gate case M_CTL: 48597c478bd9Sstevel@tonic-gate /* 48607c478bd9Sstevel@tonic-gate * We are here only if IP_RECVSLLA and/or IP_RECVIF are set 48617c478bd9Sstevel@tonic-gate */ 48627c478bd9Sstevel@tonic-gate recv_on = B_TRUE; 48637c478bd9Sstevel@tonic-gate options_mp = mp; 48647c478bd9Sstevel@tonic-gate pinfo = (in_pktinfo_t *)options_mp->b_rptr; 48657c478bd9Sstevel@tonic-gate 48667c478bd9Sstevel@tonic-gate /* 48677c478bd9Sstevel@tonic-gate * The actual data is in mp->b_cont 48687c478bd9Sstevel@tonic-gate */ 48697c478bd9Sstevel@tonic-gate mp = mp->b_cont; 48707c478bd9Sstevel@tonic-gate ASSERT(OK_32PTR(mp->b_rptr)); 48717c478bd9Sstevel@tonic-gate rptr = mp->b_rptr; 48727c478bd9Sstevel@tonic-gate break; 48737c478bd9Sstevel@tonic-gate case M_DATA: 48747c478bd9Sstevel@tonic-gate /* 48757c478bd9Sstevel@tonic-gate * M_DATA messages contain IPv4 datagrams. They are handled 48767c478bd9Sstevel@tonic-gate * after this switch. 48777c478bd9Sstevel@tonic-gate */ 48787c478bd9Sstevel@tonic-gate break; 48797c478bd9Sstevel@tonic-gate case M_PROTO: 48807c478bd9Sstevel@tonic-gate case M_PCPROTO: 48817c478bd9Sstevel@tonic-gate /* M_PROTO messages contain some type of TPI message. */ 48827c478bd9Sstevel@tonic-gate ASSERT((uintptr_t)(mp->b_wptr - rptr) <= (uintptr_t)INT_MAX); 48837c478bd9Sstevel@tonic-gate if (mp->b_wptr - rptr < sizeof (t_scalar_t)) { 48847c478bd9Sstevel@tonic-gate freemsg(mp); 48857c478bd9Sstevel@tonic-gate TRACE_2(TR_FAC_UDP, TR_UDP_RPUT_END, 48867c478bd9Sstevel@tonic-gate "udp_rput_other_end: q %p (%S)", q, "protoshort"); 48877c478bd9Sstevel@tonic-gate return; 48887c478bd9Sstevel@tonic-gate } 48897c478bd9Sstevel@tonic-gate tea = (struct T_error_ack *)rptr; 48907c478bd9Sstevel@tonic-gate 48917c478bd9Sstevel@tonic-gate switch (tea->PRIM_type) { 48927c478bd9Sstevel@tonic-gate case T_ERROR_ACK: 48937c478bd9Sstevel@tonic-gate switch (tea->ERROR_prim) { 48947c478bd9Sstevel@tonic-gate case O_T_BIND_REQ: 48957c478bd9Sstevel@tonic-gate case T_BIND_REQ: { 48967c478bd9Sstevel@tonic-gate /* 48977c478bd9Sstevel@tonic-gate * If our O_T_BIND_REQ/T_BIND_REQ fails, 48987c478bd9Sstevel@tonic-gate * clear out the associated port and source 48997c478bd9Sstevel@tonic-gate * address before passing the message 49007c478bd9Sstevel@tonic-gate * upstream. If this was caused by a T_CONN_REQ 49017c478bd9Sstevel@tonic-gate * revert back to bound state. 49027c478bd9Sstevel@tonic-gate */ 49037c478bd9Sstevel@tonic-gate udp_fanout_t *udpf; 49047c478bd9Sstevel@tonic-gate 49057c478bd9Sstevel@tonic-gate udpf = &udp_bind_fanout[ 49067c478bd9Sstevel@tonic-gate UDP_BIND_HASH(udp->udp_port)]; 49077c478bd9Sstevel@tonic-gate mutex_enter(&udpf->uf_lock); 49087c478bd9Sstevel@tonic-gate if (udp->udp_state == TS_DATA_XFER) { 49097c478bd9Sstevel@tonic-gate /* Connect failed */ 49107c478bd9Sstevel@tonic-gate tea->ERROR_prim = T_CONN_REQ; 49117c478bd9Sstevel@tonic-gate /* Revert back to the bound source */ 49127c478bd9Sstevel@tonic-gate udp->udp_v6src = udp->udp_bound_v6src; 49137c478bd9Sstevel@tonic-gate udp->udp_state = TS_IDLE; 49147c478bd9Sstevel@tonic-gate mutex_exit(&udpf->uf_lock); 49157c478bd9Sstevel@tonic-gate if (udp->udp_family == AF_INET6) 49167c478bd9Sstevel@tonic-gate (void) udp_build_hdrs(q, udp); 49177c478bd9Sstevel@tonic-gate break; 49187c478bd9Sstevel@tonic-gate } 49197c478bd9Sstevel@tonic-gate 49207c478bd9Sstevel@tonic-gate if (udp->udp_discon_pending) { 49217c478bd9Sstevel@tonic-gate tea->ERROR_prim = T_DISCON_REQ; 49227c478bd9Sstevel@tonic-gate udp->udp_discon_pending = 0; 49237c478bd9Sstevel@tonic-gate } 49247c478bd9Sstevel@tonic-gate V6_SET_ZERO(udp->udp_v6src); 49257c478bd9Sstevel@tonic-gate V6_SET_ZERO(udp->udp_bound_v6src); 49267c478bd9Sstevel@tonic-gate udp->udp_state = TS_UNBND; 49277c478bd9Sstevel@tonic-gate udp_bind_hash_remove(udp, B_TRUE); 49287c478bd9Sstevel@tonic-gate udp->udp_port = 0; 49297c478bd9Sstevel@tonic-gate mutex_exit(&udpf->uf_lock); 49307c478bd9Sstevel@tonic-gate if (udp->udp_family == AF_INET6) 49317c478bd9Sstevel@tonic-gate (void) udp_build_hdrs(q, udp); 49327c478bd9Sstevel@tonic-gate break; 49337c478bd9Sstevel@tonic-gate } 49347c478bd9Sstevel@tonic-gate default: 49357c478bd9Sstevel@tonic-gate break; 49367c478bd9Sstevel@tonic-gate } 49377c478bd9Sstevel@tonic-gate break; 49387c478bd9Sstevel@tonic-gate case T_BIND_ACK: 49397c478bd9Sstevel@tonic-gate udp_rput_bind_ack(q, mp); 49407c478bd9Sstevel@tonic-gate return; 49417c478bd9Sstevel@tonic-gate 49427c478bd9Sstevel@tonic-gate case T_OPTMGMT_ACK: 49437c478bd9Sstevel@tonic-gate case T_OK_ACK: 49447c478bd9Sstevel@tonic-gate break; 49457c478bd9Sstevel@tonic-gate default: 49467c478bd9Sstevel@tonic-gate freemsg(mp); 49477c478bd9Sstevel@tonic-gate return; 49487c478bd9Sstevel@tonic-gate } 4949ff550d0eSmasputra putnext(UDP_RD(q), mp); 49507c478bd9Sstevel@tonic-gate return; 49517c478bd9Sstevel@tonic-gate } 49527c478bd9Sstevel@tonic-gate 49537c478bd9Sstevel@tonic-gate /* 49547c478bd9Sstevel@tonic-gate * This is the inbound data path. 49557c478bd9Sstevel@tonic-gate * First, we make sure the data contains both IP and UDP headers. 49567c478bd9Sstevel@tonic-gate * 49577c478bd9Sstevel@tonic-gate * This handle IPv4 packets for only AF_INET sockets. 49587c478bd9Sstevel@tonic-gate * AF_INET6 sockets can never access udp_ip_rcv_options thus there 49597c478bd9Sstevel@tonic-gate * is no need saving the options. 49607c478bd9Sstevel@tonic-gate */ 49617c478bd9Sstevel@tonic-gate ASSERT(IPH_HDR_VERSION((ipha_t *)rptr) == IPV4_VERSION); 49627c478bd9Sstevel@tonic-gate hdr_length = IPH_HDR_LENGTH(rptr) + UDPH_SIZE; 49637c478bd9Sstevel@tonic-gate if (mp->b_wptr - rptr < hdr_length) { 49647c478bd9Sstevel@tonic-gate if (!pullupmsg(mp, hdr_length)) { 49657c478bd9Sstevel@tonic-gate freemsg(mp); 49667c478bd9Sstevel@tonic-gate if (options_mp != NULL) 49677c478bd9Sstevel@tonic-gate freeb(options_mp); 49687c478bd9Sstevel@tonic-gate BUMP_MIB(&udp_mib, udpInErrors); 49697c478bd9Sstevel@tonic-gate TRACE_2(TR_FAC_UDP, TR_UDP_RPUT_END, 49707c478bd9Sstevel@tonic-gate "udp_rput_other_end: q %p (%S)", q, "hdrshort"); 49717c478bd9Sstevel@tonic-gate BUMP_MIB(&udp_mib, udpInErrors); 49727c478bd9Sstevel@tonic-gate return; 49737c478bd9Sstevel@tonic-gate } 49747c478bd9Sstevel@tonic-gate rptr = mp->b_rptr; 49757c478bd9Sstevel@tonic-gate } 49767c478bd9Sstevel@tonic-gate /* Walk past the headers. */ 49777c478bd9Sstevel@tonic-gate new_rptr = rptr + hdr_length; 49787c478bd9Sstevel@tonic-gate if (!udp->udp_rcvhdr) 49797c478bd9Sstevel@tonic-gate mp->b_rptr = new_rptr; 49807c478bd9Sstevel@tonic-gate 49817c478bd9Sstevel@tonic-gate /* Save the options if any */ 49827c478bd9Sstevel@tonic-gate opt_len = hdr_length - (IP_SIMPLE_HDR_LENGTH + UDPH_SIZE); 49837c478bd9Sstevel@tonic-gate if (opt_len > 0) { 49847c478bd9Sstevel@tonic-gate if (opt_len > udp->udp_ip_rcv_options_len) { 49857c478bd9Sstevel@tonic-gate if (udp->udp_ip_rcv_options_len) 49867c478bd9Sstevel@tonic-gate mi_free((char *)udp->udp_ip_rcv_options); 49877c478bd9Sstevel@tonic-gate udp->udp_ip_rcv_options_len = 0; 49887c478bd9Sstevel@tonic-gate udp->udp_ip_rcv_options = 49897c478bd9Sstevel@tonic-gate (uchar_t *)mi_alloc(opt_len, BPRI_HI); 49907c478bd9Sstevel@tonic-gate if (udp->udp_ip_rcv_options) 49917c478bd9Sstevel@tonic-gate udp->udp_ip_rcv_options_len = opt_len; 49927c478bd9Sstevel@tonic-gate } 49937c478bd9Sstevel@tonic-gate if (udp->udp_ip_rcv_options_len) { 49947c478bd9Sstevel@tonic-gate bcopy(rptr + IP_SIMPLE_HDR_LENGTH, 49957c478bd9Sstevel@tonic-gate udp->udp_ip_rcv_options, opt_len); 49967c478bd9Sstevel@tonic-gate /* Adjust length if we are resusing the space */ 49977c478bd9Sstevel@tonic-gate udp->udp_ip_rcv_options_len = opt_len; 49987c478bd9Sstevel@tonic-gate } 49997c478bd9Sstevel@tonic-gate } else if (udp->udp_ip_rcv_options_len) { 50007c478bd9Sstevel@tonic-gate mi_free((char *)udp->udp_ip_rcv_options); 50017c478bd9Sstevel@tonic-gate udp->udp_ip_rcv_options = NULL; 50027c478bd9Sstevel@tonic-gate udp->udp_ip_rcv_options_len = 0; 50037c478bd9Sstevel@tonic-gate } 50047c478bd9Sstevel@tonic-gate 50057c478bd9Sstevel@tonic-gate /* 50067c478bd9Sstevel@tonic-gate * Normally only send up the address. 50077c478bd9Sstevel@tonic-gate * If IP_RECVDSTADDR is set we include the destination IP 50087c478bd9Sstevel@tonic-gate * address as an option. With IP_RECVOPTS we include all 50097c478bd9Sstevel@tonic-gate * the IP options. 50107c478bd9Sstevel@tonic-gate */ 50117c478bd9Sstevel@tonic-gate udi_size = sizeof (struct T_unitdata_ind) + sizeof (sin_t); 50127c478bd9Sstevel@tonic-gate if (udp->udp_recvdstaddr) { 50137c478bd9Sstevel@tonic-gate udi_size += sizeof (struct T_opthdr) + sizeof (struct in_addr); 5014ff550d0eSmasputra UDP_STAT(udp_in_recvdstaddr); 50157c478bd9Sstevel@tonic-gate } 5016ff550d0eSmasputra if (udp->udp_recvopts && opt_len > 0) { 50177c478bd9Sstevel@tonic-gate udi_size += sizeof (struct T_opthdr) + opt_len; 5018ff550d0eSmasputra UDP_STAT(udp_in_recvopts); 5019ff550d0eSmasputra } 50207c478bd9Sstevel@tonic-gate 50217c478bd9Sstevel@tonic-gate /* 50227c478bd9Sstevel@tonic-gate * If the IP_RECVSLLA or the IP_RECVIF is set then allocate 50237c478bd9Sstevel@tonic-gate * space accordingly 50247c478bd9Sstevel@tonic-gate */ 50257c478bd9Sstevel@tonic-gate if (udp->udp_recvif && recv_on && 50267c478bd9Sstevel@tonic-gate (pinfo->in_pkt_flags & IPF_RECVIF)) { 5027ff550d0eSmasputra udi_size += sizeof (struct T_opthdr) + sizeof (uint_t); 5028ff550d0eSmasputra UDP_STAT(udp_in_recvif); 50297c478bd9Sstevel@tonic-gate } 50307c478bd9Sstevel@tonic-gate 50317c478bd9Sstevel@tonic-gate if (udp->udp_recvslla && recv_on && 50327c478bd9Sstevel@tonic-gate (pinfo->in_pkt_flags & IPF_RECVSLLA)) { 50337c478bd9Sstevel@tonic-gate udi_size += sizeof (struct T_opthdr) + 50347c478bd9Sstevel@tonic-gate sizeof (struct sockaddr_dl); 5035ff550d0eSmasputra UDP_STAT(udp_in_recvslla); 50367c478bd9Sstevel@tonic-gate } 50377c478bd9Sstevel@tonic-gate 50387c478bd9Sstevel@tonic-gate if (udp->udp_recvucred && (cr = DB_CRED(mp)) != NULL) { 50397c478bd9Sstevel@tonic-gate udi_size += sizeof (struct T_opthdr) + ucredsize; 50407c478bd9Sstevel@tonic-gate cpid = DB_CPID(mp); 5041ff550d0eSmasputra UDP_STAT(udp_in_recvucred); 50427c478bd9Sstevel@tonic-gate } 50437c478bd9Sstevel@tonic-gate /* 50447c478bd9Sstevel@tonic-gate * If IP_RECVTTL is set allocate the appropriate sized buffer 50457c478bd9Sstevel@tonic-gate */ 50467c478bd9Sstevel@tonic-gate if (udp->udp_recvttl) { 50477c478bd9Sstevel@tonic-gate udi_size += sizeof (struct T_opthdr) + sizeof (uint8_t); 5048ff550d0eSmasputra UDP_STAT(udp_in_recvttl); 50497c478bd9Sstevel@tonic-gate } 50507c478bd9Sstevel@tonic-gate 50517c478bd9Sstevel@tonic-gate /* Allocate a message block for the T_UNITDATA_IND structure. */ 50527c478bd9Sstevel@tonic-gate mp1 = allocb(udi_size, BPRI_MED); 50537c478bd9Sstevel@tonic-gate if (mp1 == NULL) { 50547c478bd9Sstevel@tonic-gate freemsg(mp); 50557c478bd9Sstevel@tonic-gate if (options_mp != NULL) 50567c478bd9Sstevel@tonic-gate freeb(options_mp); 50577c478bd9Sstevel@tonic-gate TRACE_2(TR_FAC_UDP, TR_UDP_RPUT_END, 50587c478bd9Sstevel@tonic-gate "udp_rput_other_end: q %p (%S)", q, "allocbfail"); 50597c478bd9Sstevel@tonic-gate BUMP_MIB(&udp_mib, udpInErrors); 50607c478bd9Sstevel@tonic-gate return; 50617c478bd9Sstevel@tonic-gate } 50627c478bd9Sstevel@tonic-gate mp1->b_cont = mp; 50637c478bd9Sstevel@tonic-gate mp = mp1; 50647c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_PROTO; 50657c478bd9Sstevel@tonic-gate tudi = (struct T_unitdata_ind *)mp->b_rptr; 50667c478bd9Sstevel@tonic-gate mp->b_wptr = (uchar_t *)tudi + udi_size; 50677c478bd9Sstevel@tonic-gate tudi->PRIM_type = T_UNITDATA_IND; 50687c478bd9Sstevel@tonic-gate tudi->SRC_length = sizeof (sin_t); 50697c478bd9Sstevel@tonic-gate tudi->SRC_offset = sizeof (struct T_unitdata_ind); 50707c478bd9Sstevel@tonic-gate tudi->OPT_offset = sizeof (struct T_unitdata_ind) + sizeof (sin_t); 50717c478bd9Sstevel@tonic-gate udi_size -= (sizeof (struct T_unitdata_ind) + sizeof (sin_t)); 50727c478bd9Sstevel@tonic-gate tudi->OPT_length = udi_size; 50737c478bd9Sstevel@tonic-gate 50747c478bd9Sstevel@tonic-gate sin = (sin_t *)&tudi[1]; 50757c478bd9Sstevel@tonic-gate sin->sin_addr.s_addr = ((ipha_t *)rptr)->ipha_src; 50767c478bd9Sstevel@tonic-gate sin->sin_port = ((in_port_t *) 50777c478bd9Sstevel@tonic-gate new_rptr)[-(UDPH_SIZE/sizeof (in_port_t))]; 50787c478bd9Sstevel@tonic-gate sin->sin_family = AF_INET; 50797c478bd9Sstevel@tonic-gate *(uint32_t *)&sin->sin_zero[0] = 0; 50807c478bd9Sstevel@tonic-gate *(uint32_t *)&sin->sin_zero[4] = 0; 50817c478bd9Sstevel@tonic-gate 50827c478bd9Sstevel@tonic-gate /* 50837c478bd9Sstevel@tonic-gate * Add options if IP_RECVDSTADDR, IP_RECVIF, IP_RECVSLLA or 50847c478bd9Sstevel@tonic-gate * IP_RECVTTL has been set. 50857c478bd9Sstevel@tonic-gate */ 50867c478bd9Sstevel@tonic-gate if (udi_size != 0) { 50877c478bd9Sstevel@tonic-gate /* 50887c478bd9Sstevel@tonic-gate * Copy in destination address before options to avoid any 50897c478bd9Sstevel@tonic-gate * padding issues. 50907c478bd9Sstevel@tonic-gate */ 50917c478bd9Sstevel@tonic-gate char *dstopt; 50927c478bd9Sstevel@tonic-gate 50937c478bd9Sstevel@tonic-gate dstopt = (char *)&sin[1]; 50947c478bd9Sstevel@tonic-gate if (udp->udp_recvdstaddr) { 50957c478bd9Sstevel@tonic-gate struct T_opthdr *toh; 50967c478bd9Sstevel@tonic-gate ipaddr_t *dstptr; 50977c478bd9Sstevel@tonic-gate 50987c478bd9Sstevel@tonic-gate toh = (struct T_opthdr *)dstopt; 50997c478bd9Sstevel@tonic-gate toh->level = IPPROTO_IP; 51007c478bd9Sstevel@tonic-gate toh->name = IP_RECVDSTADDR; 51017c478bd9Sstevel@tonic-gate toh->len = sizeof (struct T_opthdr) + sizeof (ipaddr_t); 51027c478bd9Sstevel@tonic-gate toh->status = 0; 51037c478bd9Sstevel@tonic-gate dstopt += sizeof (struct T_opthdr); 51047c478bd9Sstevel@tonic-gate dstptr = (ipaddr_t *)dstopt; 51057c478bd9Sstevel@tonic-gate *dstptr = (((ipaddr_t *)rptr)[4]); 51067c478bd9Sstevel@tonic-gate dstopt += sizeof (ipaddr_t); 51077c478bd9Sstevel@tonic-gate udi_size -= toh->len; 51087c478bd9Sstevel@tonic-gate } 51097c478bd9Sstevel@tonic-gate if (udp->udp_recvopts && udi_size != 0) { 51107c478bd9Sstevel@tonic-gate struct T_opthdr *toh; 51117c478bd9Sstevel@tonic-gate 51127c478bd9Sstevel@tonic-gate toh = (struct T_opthdr *)dstopt; 51137c478bd9Sstevel@tonic-gate toh->level = IPPROTO_IP; 51147c478bd9Sstevel@tonic-gate toh->name = IP_RECVOPTS; 51157c478bd9Sstevel@tonic-gate toh->len = sizeof (struct T_opthdr) + opt_len; 51167c478bd9Sstevel@tonic-gate toh->status = 0; 51177c478bd9Sstevel@tonic-gate dstopt += sizeof (struct T_opthdr); 51187c478bd9Sstevel@tonic-gate bcopy(rptr + IP_SIMPLE_HDR_LENGTH, dstopt, opt_len); 51197c478bd9Sstevel@tonic-gate dstopt += opt_len; 51207c478bd9Sstevel@tonic-gate udi_size -= toh->len; 51217c478bd9Sstevel@tonic-gate } 51227c478bd9Sstevel@tonic-gate 51237c478bd9Sstevel@tonic-gate if (udp->udp_recvslla && recv_on && 51247c478bd9Sstevel@tonic-gate (pinfo->in_pkt_flags & IPF_RECVSLLA)) { 51257c478bd9Sstevel@tonic-gate 51267c478bd9Sstevel@tonic-gate struct T_opthdr *toh; 51277c478bd9Sstevel@tonic-gate struct sockaddr_dl *dstptr; 51287c478bd9Sstevel@tonic-gate 51297c478bd9Sstevel@tonic-gate toh = (struct T_opthdr *)dstopt; 51307c478bd9Sstevel@tonic-gate toh->level = IPPROTO_IP; 51317c478bd9Sstevel@tonic-gate toh->name = IP_RECVSLLA; 51327c478bd9Sstevel@tonic-gate toh->len = sizeof (struct T_opthdr) + 51337c478bd9Sstevel@tonic-gate sizeof (struct sockaddr_dl); 51347c478bd9Sstevel@tonic-gate toh->status = 0; 51357c478bd9Sstevel@tonic-gate dstopt += sizeof (struct T_opthdr); 51367c478bd9Sstevel@tonic-gate dstptr = (struct sockaddr_dl *)dstopt; 51377c478bd9Sstevel@tonic-gate bcopy(&pinfo->in_pkt_slla, dstptr, 51387c478bd9Sstevel@tonic-gate sizeof (struct sockaddr_dl)); 51397c478bd9Sstevel@tonic-gate dstopt += sizeof (struct sockaddr_dl); 51407c478bd9Sstevel@tonic-gate udi_size -= toh->len; 51417c478bd9Sstevel@tonic-gate } 51427c478bd9Sstevel@tonic-gate 51437c478bd9Sstevel@tonic-gate if (udp->udp_recvif && recv_on && 51447c478bd9Sstevel@tonic-gate (pinfo->in_pkt_flags & IPF_RECVIF)) { 51457c478bd9Sstevel@tonic-gate 51467c478bd9Sstevel@tonic-gate struct T_opthdr *toh; 51477c478bd9Sstevel@tonic-gate uint_t *dstptr; 51487c478bd9Sstevel@tonic-gate 51497c478bd9Sstevel@tonic-gate toh = (struct T_opthdr *)dstopt; 51507c478bd9Sstevel@tonic-gate toh->level = IPPROTO_IP; 51517c478bd9Sstevel@tonic-gate toh->name = IP_RECVIF; 51527c478bd9Sstevel@tonic-gate toh->len = sizeof (struct T_opthdr) + 51537c478bd9Sstevel@tonic-gate sizeof (uint_t); 51547c478bd9Sstevel@tonic-gate toh->status = 0; 51557c478bd9Sstevel@tonic-gate dstopt += sizeof (struct T_opthdr); 51567c478bd9Sstevel@tonic-gate dstptr = (uint_t *)dstopt; 51577c478bd9Sstevel@tonic-gate *dstptr = pinfo->in_pkt_ifindex; 51587c478bd9Sstevel@tonic-gate dstopt += sizeof (uint_t); 51597c478bd9Sstevel@tonic-gate udi_size -= toh->len; 51607c478bd9Sstevel@tonic-gate } 51617c478bd9Sstevel@tonic-gate 51627c478bd9Sstevel@tonic-gate if (cr != NULL) { 51637c478bd9Sstevel@tonic-gate struct T_opthdr *toh; 51647c478bd9Sstevel@tonic-gate 51657c478bd9Sstevel@tonic-gate toh = (struct T_opthdr *)dstopt; 51667c478bd9Sstevel@tonic-gate toh->level = SOL_SOCKET; 51677c478bd9Sstevel@tonic-gate toh->name = SCM_UCRED; 51687c478bd9Sstevel@tonic-gate toh->len = sizeof (struct T_opthdr) + ucredsize; 51697c478bd9Sstevel@tonic-gate toh->status = 0; 51707c478bd9Sstevel@tonic-gate (void) cred2ucred(cr, cpid, &toh[1]); 51717c478bd9Sstevel@tonic-gate dstopt += toh->len; 51727c478bd9Sstevel@tonic-gate udi_size -= toh->len; 51737c478bd9Sstevel@tonic-gate } 51747c478bd9Sstevel@tonic-gate 51757c478bd9Sstevel@tonic-gate if (udp->udp_recvttl) { 51767c478bd9Sstevel@tonic-gate struct T_opthdr *toh; 51777c478bd9Sstevel@tonic-gate uint8_t *dstptr; 51787c478bd9Sstevel@tonic-gate 51797c478bd9Sstevel@tonic-gate toh = (struct T_opthdr *)dstopt; 51807c478bd9Sstevel@tonic-gate toh->level = IPPROTO_IP; 51817c478bd9Sstevel@tonic-gate toh->name = IP_RECVTTL; 51827c478bd9Sstevel@tonic-gate toh->len = sizeof (struct T_opthdr) + 51837c478bd9Sstevel@tonic-gate sizeof (uint8_t); 51847c478bd9Sstevel@tonic-gate toh->status = 0; 51857c478bd9Sstevel@tonic-gate dstopt += sizeof (struct T_opthdr); 51867c478bd9Sstevel@tonic-gate dstptr = (uint8_t *)dstopt; 51877c478bd9Sstevel@tonic-gate *dstptr = ((ipha_t *)rptr)->ipha_ttl; 51887c478bd9Sstevel@tonic-gate dstopt += sizeof (uint8_t); 51897c478bd9Sstevel@tonic-gate udi_size -= toh->len; 51907c478bd9Sstevel@tonic-gate } 51917c478bd9Sstevel@tonic-gate 51927c478bd9Sstevel@tonic-gate ASSERT(udi_size == 0); /* "Consumed" all of allocated space */ 51937c478bd9Sstevel@tonic-gate } 51947c478bd9Sstevel@tonic-gate BUMP_MIB(&udp_mib, udpInDatagrams); 51957c478bd9Sstevel@tonic-gate TRACE_2(TR_FAC_UDP, TR_UDP_RPUT_END, 51967c478bd9Sstevel@tonic-gate "udp_rput_other_end: q %p (%S)", q, "end"); 51977c478bd9Sstevel@tonic-gate if (options_mp != NULL) 51987c478bd9Sstevel@tonic-gate freeb(options_mp); 5199ff550d0eSmasputra 5200ff550d0eSmasputra if (udp->udp_direct_sockfs) { 5201ff550d0eSmasputra /* 5202ff550d0eSmasputra * There is nothing above us except for the stream head; 5203ff550d0eSmasputra * use the read-side synchronous stream interface in 5204ff550d0eSmasputra * order to reduce the time spent in interrupt thread. 5205ff550d0eSmasputra */ 5206ff550d0eSmasputra ASSERT(udp->udp_issocket); 5207ff550d0eSmasputra udp_rcv_enqueue(UDP_RD(q), udp, mp, msgdsize(mp)); 5208ff550d0eSmasputra } else { 5209ff550d0eSmasputra /* 5210ff550d0eSmasputra * Use regular STREAMS interface to pass data upstream 5211ff550d0eSmasputra * if this is not a socket endpoint, or if we have 5212ff550d0eSmasputra * switched over to the slow mode due to sockmod being 5213ff550d0eSmasputra * popped or a module being pushed on top of us. 5214ff550d0eSmasputra */ 5215ff550d0eSmasputra putnext(UDP_RD(q), mp); 5216ff550d0eSmasputra } 5217ff550d0eSmasputra } 5218ff550d0eSmasputra 5219ff550d0eSmasputra /* ARGSUSED */ 5220ff550d0eSmasputra static void 5221ff550d0eSmasputra udp_rput_other_wrapper(void *arg, mblk_t *mp, void *arg2) 5222ff550d0eSmasputra { 5223ff550d0eSmasputra conn_t *connp = arg; 5224ff550d0eSmasputra 5225ff550d0eSmasputra udp_rput_other(connp->conn_rq, mp); 5226ff550d0eSmasputra udp_exit(connp); 52277c478bd9Sstevel@tonic-gate } 52287c478bd9Sstevel@tonic-gate 52297c478bd9Sstevel@tonic-gate /* 52307c478bd9Sstevel@tonic-gate * Process a T_BIND_ACK 52317c478bd9Sstevel@tonic-gate */ 52327c478bd9Sstevel@tonic-gate static void 52337c478bd9Sstevel@tonic-gate udp_rput_bind_ack(queue_t *q, mblk_t *mp) 52347c478bd9Sstevel@tonic-gate { 5235ff550d0eSmasputra udp_t *udp = Q_TO_UDP(q); 52367c478bd9Sstevel@tonic-gate mblk_t *mp1; 52377c478bd9Sstevel@tonic-gate ire_t *ire; 52387c478bd9Sstevel@tonic-gate struct T_bind_ack *tba; 52397c478bd9Sstevel@tonic-gate uchar_t *addrp; 52407c478bd9Sstevel@tonic-gate ipa_conn_t *ac; 52417c478bd9Sstevel@tonic-gate ipa6_conn_t *ac6; 52427c478bd9Sstevel@tonic-gate 52437c478bd9Sstevel@tonic-gate if (udp->udp_discon_pending) 52447c478bd9Sstevel@tonic-gate udp->udp_discon_pending = 0; 52457c478bd9Sstevel@tonic-gate 52467c478bd9Sstevel@tonic-gate /* 52477c478bd9Sstevel@tonic-gate * If a broadcast/multicast address was bound set 52487c478bd9Sstevel@tonic-gate * the source address to 0. 52497c478bd9Sstevel@tonic-gate * This ensures no datagrams with broadcast address 52507c478bd9Sstevel@tonic-gate * as source address are emitted (which would violate 52517c478bd9Sstevel@tonic-gate * RFC1122 - Hosts requirements) 52527c478bd9Sstevel@tonic-gate * 52537c478bd9Sstevel@tonic-gate * Note that when connecting the returned IRE is 52547c478bd9Sstevel@tonic-gate * for the destination address and we only perform 52557c478bd9Sstevel@tonic-gate * the broadcast check for the source address (it 52567c478bd9Sstevel@tonic-gate * is OK to connect to a broadcast/multicast address.) 52577c478bd9Sstevel@tonic-gate */ 52587c478bd9Sstevel@tonic-gate mp1 = mp->b_cont; 52597c478bd9Sstevel@tonic-gate if (mp1 != NULL && mp1->b_datap->db_type == IRE_DB_TYPE) { 52607c478bd9Sstevel@tonic-gate ire = (ire_t *)mp1->b_rptr; 52617c478bd9Sstevel@tonic-gate 52627c478bd9Sstevel@tonic-gate /* 52637c478bd9Sstevel@tonic-gate * Note: we get IRE_BROADCAST for IPv6 to "mark" a multicast 52647c478bd9Sstevel@tonic-gate * local address. 52657c478bd9Sstevel@tonic-gate */ 52667c478bd9Sstevel@tonic-gate if (ire->ire_type == IRE_BROADCAST && 52677c478bd9Sstevel@tonic-gate udp->udp_state != TS_DATA_XFER) { 52687c478bd9Sstevel@tonic-gate /* This was just a local bind to a broadcast addr */ 52697c478bd9Sstevel@tonic-gate V6_SET_ZERO(udp->udp_v6src); 52707c478bd9Sstevel@tonic-gate if (udp->udp_family == AF_INET6) 52717c478bd9Sstevel@tonic-gate (void) udp_build_hdrs(q, udp); 52727c478bd9Sstevel@tonic-gate } else if (V6_OR_V4_INADDR_ANY(udp->udp_v6src)) { 52737c478bd9Sstevel@tonic-gate /* 52747c478bd9Sstevel@tonic-gate * Local address not yet set - pick it from the 52757c478bd9Sstevel@tonic-gate * T_bind_ack 52767c478bd9Sstevel@tonic-gate */ 52777c478bd9Sstevel@tonic-gate tba = (struct T_bind_ack *)mp->b_rptr; 52787c478bd9Sstevel@tonic-gate addrp = &mp->b_rptr[tba->ADDR_offset]; 52797c478bd9Sstevel@tonic-gate switch (udp->udp_family) { 52807c478bd9Sstevel@tonic-gate case AF_INET: 52817c478bd9Sstevel@tonic-gate if (tba->ADDR_length == sizeof (ipa_conn_t)) { 52827c478bd9Sstevel@tonic-gate ac = (ipa_conn_t *)addrp; 52837c478bd9Sstevel@tonic-gate } else { 52847c478bd9Sstevel@tonic-gate ASSERT(tba->ADDR_length == 52857c478bd9Sstevel@tonic-gate sizeof (ipa_conn_x_t)); 52867c478bd9Sstevel@tonic-gate ac = &((ipa_conn_x_t *)addrp)->acx_conn; 52877c478bd9Sstevel@tonic-gate } 52887c478bd9Sstevel@tonic-gate IN6_IPADDR_TO_V4MAPPED(ac->ac_laddr, 52897c478bd9Sstevel@tonic-gate &udp->udp_v6src); 52907c478bd9Sstevel@tonic-gate break; 52917c478bd9Sstevel@tonic-gate case AF_INET6: 52927c478bd9Sstevel@tonic-gate if (tba->ADDR_length == sizeof (ipa6_conn_t)) { 52937c478bd9Sstevel@tonic-gate ac6 = (ipa6_conn_t *)addrp; 52947c478bd9Sstevel@tonic-gate } else { 52957c478bd9Sstevel@tonic-gate ASSERT(tba->ADDR_length == 52967c478bd9Sstevel@tonic-gate sizeof (ipa6_conn_x_t)); 52977c478bd9Sstevel@tonic-gate ac6 = &((ipa6_conn_x_t *) 52987c478bd9Sstevel@tonic-gate addrp)->ac6x_conn; 52997c478bd9Sstevel@tonic-gate } 53007c478bd9Sstevel@tonic-gate udp->udp_v6src = ac6->ac6_laddr; 53017c478bd9Sstevel@tonic-gate (void) udp_build_hdrs(q, udp); 53027c478bd9Sstevel@tonic-gate break; 53037c478bd9Sstevel@tonic-gate } 53047c478bd9Sstevel@tonic-gate } 53057c478bd9Sstevel@tonic-gate mp1 = mp1->b_cont; 53067c478bd9Sstevel@tonic-gate } 53077c478bd9Sstevel@tonic-gate /* 53087c478bd9Sstevel@tonic-gate * Look for one or more appended ACK message added by 53097c478bd9Sstevel@tonic-gate * udp_connect or udp_disconnect. 53107c478bd9Sstevel@tonic-gate * If none found just send up the T_BIND_ACK. 53117c478bd9Sstevel@tonic-gate * udp_connect has appended a T_OK_ACK and a T_CONN_CON. 53127c478bd9Sstevel@tonic-gate * udp_disconnect has appended a T_OK_ACK. 53137c478bd9Sstevel@tonic-gate */ 53147c478bd9Sstevel@tonic-gate if (mp1 != NULL) { 53157c478bd9Sstevel@tonic-gate if (mp->b_cont == mp1) 53167c478bd9Sstevel@tonic-gate mp->b_cont = NULL; 53177c478bd9Sstevel@tonic-gate else { 53187c478bd9Sstevel@tonic-gate ASSERT(mp->b_cont->b_cont == mp1); 53197c478bd9Sstevel@tonic-gate mp->b_cont->b_cont = NULL; 53207c478bd9Sstevel@tonic-gate } 53217c478bd9Sstevel@tonic-gate freemsg(mp); 53227c478bd9Sstevel@tonic-gate mp = mp1; 53237c478bd9Sstevel@tonic-gate while (mp != NULL) { 53247c478bd9Sstevel@tonic-gate mp1 = mp->b_cont; 53257c478bd9Sstevel@tonic-gate mp->b_cont = NULL; 5326ff550d0eSmasputra putnext(UDP_RD(q), mp); 53277c478bd9Sstevel@tonic-gate mp = mp1; 53287c478bd9Sstevel@tonic-gate } 53297c478bd9Sstevel@tonic-gate return; 53307c478bd9Sstevel@tonic-gate } 53317c478bd9Sstevel@tonic-gate freemsg(mp->b_cont); 53327c478bd9Sstevel@tonic-gate mp->b_cont = NULL; 5333ff550d0eSmasputra putnext(UDP_RD(q), mp); 53347c478bd9Sstevel@tonic-gate } 53357c478bd9Sstevel@tonic-gate 53367c478bd9Sstevel@tonic-gate /* 53377c478bd9Sstevel@tonic-gate * return SNMP stuff in buffer in mpdata 53387c478bd9Sstevel@tonic-gate */ 5339ff550d0eSmasputra int 53407c478bd9Sstevel@tonic-gate udp_snmp_get(queue_t *q, mblk_t *mpctl) 53417c478bd9Sstevel@tonic-gate { 53427c478bd9Sstevel@tonic-gate mblk_t *mpdata; 53437c478bd9Sstevel@tonic-gate mblk_t *mp_conn_ctl; 53447c478bd9Sstevel@tonic-gate mblk_t *mp6_conn_ctl; 53457c478bd9Sstevel@tonic-gate mblk_t *mp_conn_data; 53467c478bd9Sstevel@tonic-gate mblk_t *mp6_conn_data; 53477c478bd9Sstevel@tonic-gate mblk_t *mp_conn_tail = NULL; 53487c478bd9Sstevel@tonic-gate mblk_t *mp6_conn_tail = NULL; 53497c478bd9Sstevel@tonic-gate struct opthdr *optp; 53507c478bd9Sstevel@tonic-gate mib2_udpEntry_t ude; 53517c478bd9Sstevel@tonic-gate mib2_udp6Entry_t ude6; 53527c478bd9Sstevel@tonic-gate int state; 53537c478bd9Sstevel@tonic-gate zoneid_t zoneid; 5354ff550d0eSmasputra int i; 5355ff550d0eSmasputra connf_t *connfp; 5356ff550d0eSmasputra conn_t *connp = Q_TO_CONN(q); 5357ff550d0eSmasputra udp_t *udp = connp->conn_udp; 53587c478bd9Sstevel@tonic-gate 53597c478bd9Sstevel@tonic-gate if (mpctl == NULL || 53607c478bd9Sstevel@tonic-gate (mpdata = mpctl->b_cont) == NULL || 53617c478bd9Sstevel@tonic-gate (mp_conn_ctl = copymsg(mpctl)) == NULL || 53627c478bd9Sstevel@tonic-gate (mp6_conn_ctl = copymsg(mpctl)) == NULL) { 53637c478bd9Sstevel@tonic-gate freemsg(mp_conn_ctl); 53647c478bd9Sstevel@tonic-gate return (0); 53657c478bd9Sstevel@tonic-gate } 53667c478bd9Sstevel@tonic-gate 53677c478bd9Sstevel@tonic-gate mp_conn_data = mp_conn_ctl->b_cont; 53687c478bd9Sstevel@tonic-gate mp6_conn_data = mp6_conn_ctl->b_cont; 53697c478bd9Sstevel@tonic-gate 5370ff550d0eSmasputra zoneid = connp->conn_zoneid; 53717c478bd9Sstevel@tonic-gate 53727c478bd9Sstevel@tonic-gate /* fixed length structure for IPv4 and IPv6 counters */ 53737c478bd9Sstevel@tonic-gate SET_MIB(udp_mib.udpEntrySize, sizeof (mib2_udpEntry_t)); 53747c478bd9Sstevel@tonic-gate SET_MIB(udp_mib.udp6EntrySize, sizeof (mib2_udp6Entry_t)); 53757c478bd9Sstevel@tonic-gate optp = (struct opthdr *)&mpctl->b_rptr[sizeof (struct T_optmgmt_ack)]; 53767c478bd9Sstevel@tonic-gate optp->level = MIB2_UDP; 53777c478bd9Sstevel@tonic-gate optp->name = 0; 53787c478bd9Sstevel@tonic-gate (void) snmp_append_data(mpdata, (char *)&udp_mib, sizeof (udp_mib)); 53797c478bd9Sstevel@tonic-gate optp->len = msgdsize(mpdata); 53807c478bd9Sstevel@tonic-gate qreply(q, mpctl); 53817c478bd9Sstevel@tonic-gate 5382ff550d0eSmasputra for (i = 0; i < CONN_G_HASH_SIZE; i++) { 5383ff550d0eSmasputra connfp = &ipcl_globalhash_fanout[i]; 5384ff550d0eSmasputra connp = NULL; 53857c478bd9Sstevel@tonic-gate 5386ff550d0eSmasputra while ((connp = ipcl_get_next_conn(connfp, connp, 5387ff550d0eSmasputra IPCL_UDP))) { 5388ff550d0eSmasputra udp = connp->conn_udp; 5389ff550d0eSmasputra if (zoneid != connp->conn_zoneid) 5390ff550d0eSmasputra continue; 53917c478bd9Sstevel@tonic-gate 5392ff550d0eSmasputra /* 5393ff550d0eSmasputra * Note that the port numbers are sent in 5394ff550d0eSmasputra * host byte order 5395ff550d0eSmasputra */ 53967c478bd9Sstevel@tonic-gate 5397ff550d0eSmasputra if (udp->udp_state == TS_UNBND) 5398ff550d0eSmasputra state = MIB2_UDP_unbound; 5399ff550d0eSmasputra else if (udp->udp_state == TS_IDLE) 5400ff550d0eSmasputra state = MIB2_UDP_idle; 5401ff550d0eSmasputra else if (udp->udp_state == TS_DATA_XFER) 5402ff550d0eSmasputra state = MIB2_UDP_connected; 5403ff550d0eSmasputra else 5404ff550d0eSmasputra state = MIB2_UDP_unknown; 54057c478bd9Sstevel@tonic-gate 5406ff550d0eSmasputra /* 5407ff550d0eSmasputra * Create an IPv4 table entry for IPv4 entries and also 5408ff550d0eSmasputra * any IPv6 entries which are bound to in6addr_any 5409ff550d0eSmasputra * (i.e. anything a IPv4 peer could connect/send to). 5410ff550d0eSmasputra */ 5411ff550d0eSmasputra if (udp->udp_ipversion == IPV4_VERSION || 5412ff550d0eSmasputra (udp->udp_state <= TS_IDLE && 5413ff550d0eSmasputra IN6_IS_ADDR_UNSPECIFIED(&udp->udp_v6src))) { 5414ff550d0eSmasputra ude.udpEntryInfo.ue_state = state; 54157c478bd9Sstevel@tonic-gate /* 5416ff550d0eSmasputra * If in6addr_any this will set it to 5417ff550d0eSmasputra * INADDR_ANY 54187c478bd9Sstevel@tonic-gate */ 5419ff550d0eSmasputra ude.udpLocalAddress = 5420ff550d0eSmasputra V4_PART_OF_V6(udp->udp_v6src); 5421ff550d0eSmasputra ude.udpLocalPort = ntohs(udp->udp_port); 5422ff550d0eSmasputra if (udp->udp_state == TS_DATA_XFER) { 5423ff550d0eSmasputra /* 5424ff550d0eSmasputra * Can potentially get here for 5425ff550d0eSmasputra * v6 socket if another process 5426ff550d0eSmasputra * (say, ping) has just done a 5427ff550d0eSmasputra * sendto(), changing the state 5428ff550d0eSmasputra * from the TS_IDLE above to 5429ff550d0eSmasputra * TS_DATA_XFER by the time we hit 5430ff550d0eSmasputra * this part of the code. 5431ff550d0eSmasputra */ 5432ff550d0eSmasputra ude.udpEntryInfo.ue_RemoteAddress = 5433ff550d0eSmasputra V4_PART_OF_V6(udp->udp_v6dst); 5434ff550d0eSmasputra ude.udpEntryInfo.ue_RemotePort = 5435ff550d0eSmasputra ntohs(udp->udp_dstport); 5436ff550d0eSmasputra } else { 5437ff550d0eSmasputra ude.udpEntryInfo.ue_RemoteAddress = 0; 5438ff550d0eSmasputra ude.udpEntryInfo.ue_RemotePort = 0; 5439ff550d0eSmasputra } 5440ff550d0eSmasputra (void) snmp_append_data2(mp_conn_data, 5441ff550d0eSmasputra &mp_conn_tail, (char *)&ude, sizeof (ude)); 54427c478bd9Sstevel@tonic-gate } 5443ff550d0eSmasputra if (udp->udp_ipversion == IPV6_VERSION) { 5444ff550d0eSmasputra ude6.udp6EntryInfo.ue_state = state; 5445ff550d0eSmasputra ude6.udp6LocalAddress = udp->udp_v6src; 5446ff550d0eSmasputra ude6.udp6LocalPort = ntohs(udp->udp_port); 5447ff550d0eSmasputra ude6.udp6IfIndex = udp->udp_bound_if; 5448ff550d0eSmasputra if (udp->udp_state == TS_DATA_XFER) { 5449ff550d0eSmasputra ude6.udp6EntryInfo.ue_RemoteAddress = 5450ff550d0eSmasputra udp->udp_v6dst; 5451ff550d0eSmasputra ude6.udp6EntryInfo.ue_RemotePort = 5452ff550d0eSmasputra ntohs(udp->udp_dstport); 5453ff550d0eSmasputra } else { 5454ff550d0eSmasputra ude6.udp6EntryInfo.ue_RemoteAddress = 5455ff550d0eSmasputra sin6_null.sin6_addr; 5456ff550d0eSmasputra ude6.udp6EntryInfo.ue_RemotePort = 0; 5457ff550d0eSmasputra } 5458ff550d0eSmasputra (void) snmp_append_data2(mp6_conn_data, 5459ff550d0eSmasputra &mp6_conn_tail, (char *)&ude6, 5460ff550d0eSmasputra sizeof (ude6)); 54617c478bd9Sstevel@tonic-gate } 54627c478bd9Sstevel@tonic-gate } 54637c478bd9Sstevel@tonic-gate } 54647c478bd9Sstevel@tonic-gate 54657c478bd9Sstevel@tonic-gate /* IPv4 UDP endpoints */ 54667c478bd9Sstevel@tonic-gate optp = (struct opthdr *)&mp_conn_ctl->b_rptr[ 54677c478bd9Sstevel@tonic-gate sizeof (struct T_optmgmt_ack)]; 54687c478bd9Sstevel@tonic-gate optp->level = MIB2_UDP; 54697c478bd9Sstevel@tonic-gate optp->name = MIB2_UDP_ENTRY; 54707c478bd9Sstevel@tonic-gate optp->len = msgdsize(mp_conn_data); 54717c478bd9Sstevel@tonic-gate qreply(q, mp_conn_ctl); 54727c478bd9Sstevel@tonic-gate 54737c478bd9Sstevel@tonic-gate /* IPv6 UDP endpoints */ 54747c478bd9Sstevel@tonic-gate optp = (struct opthdr *)&mp6_conn_ctl->b_rptr[ 54757c478bd9Sstevel@tonic-gate sizeof (struct T_optmgmt_ack)]; 54767c478bd9Sstevel@tonic-gate optp->level = MIB2_UDP6; 54777c478bd9Sstevel@tonic-gate optp->name = MIB2_UDP6_ENTRY; 54787c478bd9Sstevel@tonic-gate optp->len = msgdsize(mp6_conn_data); 54797c478bd9Sstevel@tonic-gate qreply(q, mp6_conn_ctl); 54807c478bd9Sstevel@tonic-gate 54817c478bd9Sstevel@tonic-gate return (1); 54827c478bd9Sstevel@tonic-gate } 54837c478bd9Sstevel@tonic-gate 54847c478bd9Sstevel@tonic-gate /* 54857c478bd9Sstevel@tonic-gate * Return 0 if invalid set request, 1 otherwise, including non-udp requests. 54867c478bd9Sstevel@tonic-gate * NOTE: Per MIB-II, UDP has no writable data. 54877c478bd9Sstevel@tonic-gate * TODO: If this ever actually tries to set anything, it needs to be 54887c478bd9Sstevel@tonic-gate * to do the appropriate locking. 54897c478bd9Sstevel@tonic-gate */ 54907c478bd9Sstevel@tonic-gate /* ARGSUSED */ 5491ff550d0eSmasputra int 54927c478bd9Sstevel@tonic-gate udp_snmp_set(queue_t *q, t_scalar_t level, t_scalar_t name, 54937c478bd9Sstevel@tonic-gate uchar_t *ptr, int len) 54947c478bd9Sstevel@tonic-gate { 54957c478bd9Sstevel@tonic-gate switch (level) { 54967c478bd9Sstevel@tonic-gate case MIB2_UDP: 54977c478bd9Sstevel@tonic-gate return (0); 54987c478bd9Sstevel@tonic-gate default: 54997c478bd9Sstevel@tonic-gate return (1); 55007c478bd9Sstevel@tonic-gate } 55017c478bd9Sstevel@tonic-gate } 55027c478bd9Sstevel@tonic-gate 55037c478bd9Sstevel@tonic-gate static void 55047c478bd9Sstevel@tonic-gate udp_report_item(mblk_t *mp, udp_t *udp) 55057c478bd9Sstevel@tonic-gate { 55067c478bd9Sstevel@tonic-gate char *state; 55077c478bd9Sstevel@tonic-gate char addrbuf1[INET6_ADDRSTRLEN]; 55087c478bd9Sstevel@tonic-gate char addrbuf2[INET6_ADDRSTRLEN]; 55097c478bd9Sstevel@tonic-gate uint_t print_len, buf_len; 55107c478bd9Sstevel@tonic-gate 55117c478bd9Sstevel@tonic-gate buf_len = mp->b_datap->db_lim - mp->b_wptr; 55127c478bd9Sstevel@tonic-gate ASSERT(buf_len >= 0); 55137c478bd9Sstevel@tonic-gate if (buf_len == 0) 55147c478bd9Sstevel@tonic-gate return; 55157c478bd9Sstevel@tonic-gate 55167c478bd9Sstevel@tonic-gate if (udp->udp_state == TS_UNBND) 55177c478bd9Sstevel@tonic-gate state = "UNBOUND"; 55187c478bd9Sstevel@tonic-gate else if (udp->udp_state == TS_IDLE) 55197c478bd9Sstevel@tonic-gate state = "IDLE"; 55207c478bd9Sstevel@tonic-gate else if (udp->udp_state == TS_DATA_XFER) 55217c478bd9Sstevel@tonic-gate state = "CONNECTED"; 55227c478bd9Sstevel@tonic-gate else 55237c478bd9Sstevel@tonic-gate state = "UnkState"; 55247c478bd9Sstevel@tonic-gate print_len = snprintf((char *)mp->b_wptr, buf_len, 55257c478bd9Sstevel@tonic-gate MI_COL_PTRFMT_STR "%4d %5u %s %s %5u %s\n", 5526ff550d0eSmasputra (void *)udp, udp->udp_connp->conn_zoneid, ntohs(udp->udp_port), 55277c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, &udp->udp_v6src, 55287c478bd9Sstevel@tonic-gate addrbuf1, sizeof (addrbuf1)), 55297c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, &udp->udp_v6dst, 55307c478bd9Sstevel@tonic-gate addrbuf2, sizeof (addrbuf2)), 55317c478bd9Sstevel@tonic-gate ntohs(udp->udp_dstport), state); 55327c478bd9Sstevel@tonic-gate if (print_len < buf_len) { 55337c478bd9Sstevel@tonic-gate mp->b_wptr += print_len; 55347c478bd9Sstevel@tonic-gate } else { 55357c478bd9Sstevel@tonic-gate mp->b_wptr += buf_len; 55367c478bd9Sstevel@tonic-gate } 55377c478bd9Sstevel@tonic-gate } 55387c478bd9Sstevel@tonic-gate 55397c478bd9Sstevel@tonic-gate /* Report for ndd "udp_status" */ 55407c478bd9Sstevel@tonic-gate /* ARGSUSED */ 55417c478bd9Sstevel@tonic-gate static int 55427c478bd9Sstevel@tonic-gate udp_status_report(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *cr) 55437c478bd9Sstevel@tonic-gate { 55447c478bd9Sstevel@tonic-gate zoneid_t zoneid; 5545ff550d0eSmasputra connf_t *connfp; 5546ff550d0eSmasputra conn_t *connp = Q_TO_CONN(q); 5547ff550d0eSmasputra udp_t *udp = connp->conn_udp; 5548ff550d0eSmasputra int i; 55497c478bd9Sstevel@tonic-gate 55507c478bd9Sstevel@tonic-gate /* 55517c478bd9Sstevel@tonic-gate * Because of the ndd constraint, at most we can have 64K buffer 55527c478bd9Sstevel@tonic-gate * to put in all UDP info. So to be more efficient, just 55537c478bd9Sstevel@tonic-gate * allocate a 64K buffer here, assuming we need that large buffer. 55547c478bd9Sstevel@tonic-gate * This may be a problem as any user can read udp_status. Therefore 55557c478bd9Sstevel@tonic-gate * we limit the rate of doing this using udp_ndd_get_info_interval. 55567c478bd9Sstevel@tonic-gate * This should be OK as normal users should not do this too often. 55577c478bd9Sstevel@tonic-gate */ 55587c478bd9Sstevel@tonic-gate if (cr == NULL || secpolicy_net_config(cr, B_TRUE) != 0) { 55597c478bd9Sstevel@tonic-gate if (ddi_get_lbolt() - udp_last_ndd_get_info_time < 55607c478bd9Sstevel@tonic-gate drv_usectohz(udp_ndd_get_info_interval * 1000)) { 55617c478bd9Sstevel@tonic-gate (void) mi_mpprintf(mp, NDD_TOO_QUICK_MSG); 55627c478bd9Sstevel@tonic-gate return (0); 55637c478bd9Sstevel@tonic-gate } 55647c478bd9Sstevel@tonic-gate } 55657c478bd9Sstevel@tonic-gate if ((mp->b_cont = allocb(ND_MAX_BUF_LEN, BPRI_HI)) == NULL) { 55667c478bd9Sstevel@tonic-gate /* The following may work even if we cannot get a large buf. */ 55677c478bd9Sstevel@tonic-gate (void) mi_mpprintf(mp, NDD_OUT_OF_BUF_MSG); 55687c478bd9Sstevel@tonic-gate return (0); 55697c478bd9Sstevel@tonic-gate } 55707c478bd9Sstevel@tonic-gate (void) mi_mpprintf(mp, 55717c478bd9Sstevel@tonic-gate "UDP " MI_COL_HDRPAD_STR 55727c478bd9Sstevel@tonic-gate /* 12345678[89ABCDEF] */ 55737c478bd9Sstevel@tonic-gate " zone lport src addr dest addr port state"); 55747c478bd9Sstevel@tonic-gate /* 1234 12345 xxx.xxx.xxx.xxx xxx.xxx.xxx.xxx 12345 UNBOUND */ 55757c478bd9Sstevel@tonic-gate 5576ff550d0eSmasputra zoneid = connp->conn_zoneid; 55777c478bd9Sstevel@tonic-gate 5578ff550d0eSmasputra for (i = 0; i < CONN_G_HASH_SIZE; i++) { 5579ff550d0eSmasputra connfp = &ipcl_globalhash_fanout[i]; 5580ff550d0eSmasputra connp = NULL; 55817c478bd9Sstevel@tonic-gate 5582ff550d0eSmasputra while ((connp = ipcl_get_next_conn(connfp, connp, 5583ff550d0eSmasputra IPCL_UDP))) { 5584ff550d0eSmasputra udp = connp->conn_udp; 5585ff550d0eSmasputra if (zoneid != GLOBAL_ZONEID && 5586ff550d0eSmasputra zoneid != connp->conn_zoneid) 5587ff550d0eSmasputra continue; 55887c478bd9Sstevel@tonic-gate 5589ff550d0eSmasputra udp_report_item(mp->b_cont, udp); 5590ff550d0eSmasputra } 55917c478bd9Sstevel@tonic-gate } 55927c478bd9Sstevel@tonic-gate udp_last_ndd_get_info_time = ddi_get_lbolt(); 55937c478bd9Sstevel@tonic-gate return (0); 55947c478bd9Sstevel@tonic-gate } 55957c478bd9Sstevel@tonic-gate 55967c478bd9Sstevel@tonic-gate /* 55977c478bd9Sstevel@tonic-gate * This routine creates a T_UDERROR_IND message and passes it upstream. 55987c478bd9Sstevel@tonic-gate * The address and options are copied from the T_UNITDATA_REQ message 55997c478bd9Sstevel@tonic-gate * passed in mp. This message is freed. 56007c478bd9Sstevel@tonic-gate */ 56017c478bd9Sstevel@tonic-gate static void 5602ff550d0eSmasputra udp_ud_err(queue_t *q, mblk_t *mp, uchar_t *destaddr, t_scalar_t destlen, 5603ff550d0eSmasputra t_scalar_t err) 56047c478bd9Sstevel@tonic-gate { 5605ff550d0eSmasputra struct T_unitdata_req *tudr; 56067c478bd9Sstevel@tonic-gate mblk_t *mp1; 5607ff550d0eSmasputra uchar_t *optaddr; 5608ff550d0eSmasputra t_scalar_t optlen; 56097c478bd9Sstevel@tonic-gate 5610ff550d0eSmasputra if (DB_TYPE(mp) == M_DATA) { 5611ff550d0eSmasputra ASSERT(destaddr != NULL && destlen != 0); 5612ff550d0eSmasputra optaddr = NULL; 5613ff550d0eSmasputra optlen = 0; 5614ff550d0eSmasputra } else { 5615ff550d0eSmasputra if ((mp->b_wptr < mp->b_rptr) || 5616ff550d0eSmasputra (MBLKL(mp)) < sizeof (struct T_unitdata_req)) { 5617ff550d0eSmasputra goto done; 5618ff550d0eSmasputra } 5619ff550d0eSmasputra tudr = (struct T_unitdata_req *)mp->b_rptr; 5620ff550d0eSmasputra destaddr = mp->b_rptr + tudr->DEST_offset; 5621ff550d0eSmasputra if (destaddr < mp->b_rptr || destaddr >= mp->b_wptr || 5622ff550d0eSmasputra destaddr + tudr->DEST_length < mp->b_rptr || 5623ff550d0eSmasputra destaddr + tudr->DEST_length > mp->b_wptr) { 5624ff550d0eSmasputra goto done; 5625ff550d0eSmasputra } 5626ff550d0eSmasputra optaddr = mp->b_rptr + tudr->OPT_offset; 5627ff550d0eSmasputra if (optaddr < mp->b_rptr || optaddr >= mp->b_wptr || 5628ff550d0eSmasputra optaddr + tudr->OPT_length < mp->b_rptr || 5629ff550d0eSmasputra optaddr + tudr->OPT_length > mp->b_wptr) { 5630ff550d0eSmasputra goto done; 5631ff550d0eSmasputra } 5632ff550d0eSmasputra destlen = tudr->DEST_length; 5633ff550d0eSmasputra optlen = tudr->OPT_length; 56347c478bd9Sstevel@tonic-gate } 5635ff550d0eSmasputra 5636ff550d0eSmasputra mp1 = mi_tpi_uderror_ind((char *)destaddr, destlen, 5637ff550d0eSmasputra (char *)optaddr, optlen, err); 5638ff550d0eSmasputra if (mp1 != NULL) 5639ff550d0eSmasputra putnext(UDP_RD(q), mp1); 56407c478bd9Sstevel@tonic-gate 56417c478bd9Sstevel@tonic-gate done: 56427c478bd9Sstevel@tonic-gate freemsg(mp); 56437c478bd9Sstevel@tonic-gate } 56447c478bd9Sstevel@tonic-gate 56457c478bd9Sstevel@tonic-gate /* 56467c478bd9Sstevel@tonic-gate * This routine removes a port number association from a stream. It 56477c478bd9Sstevel@tonic-gate * is called by udp_wput to handle T_UNBIND_REQ messages. 56487c478bd9Sstevel@tonic-gate */ 56497c478bd9Sstevel@tonic-gate static void 56507c478bd9Sstevel@tonic-gate udp_unbind(queue_t *q, mblk_t *mp) 56517c478bd9Sstevel@tonic-gate { 5652ff550d0eSmasputra udp_t *udp = Q_TO_UDP(q); 56537c478bd9Sstevel@tonic-gate 56547c478bd9Sstevel@tonic-gate /* If a bind has not been done, we can't unbind. */ 56557c478bd9Sstevel@tonic-gate if (udp->udp_state == TS_UNBND) { 56567c478bd9Sstevel@tonic-gate udp_err_ack(q, mp, TOUTSTATE, 0); 56577c478bd9Sstevel@tonic-gate return; 56587c478bd9Sstevel@tonic-gate } 56597c478bd9Sstevel@tonic-gate if (cl_inet_unbind != NULL) { 56607c478bd9Sstevel@tonic-gate /* 56617c478bd9Sstevel@tonic-gate * Running in cluster mode - register unbind information 56627c478bd9Sstevel@tonic-gate */ 56637c478bd9Sstevel@tonic-gate if (udp->udp_ipversion == IPV4_VERSION) { 56647c478bd9Sstevel@tonic-gate (*cl_inet_unbind)(IPPROTO_UDP, AF_INET, 56657c478bd9Sstevel@tonic-gate (uint8_t *)(&V4_PART_OF_V6(udp->udp_v6src)), 56667c478bd9Sstevel@tonic-gate (in_port_t)udp->udp_port); 56677c478bd9Sstevel@tonic-gate } else { 56687c478bd9Sstevel@tonic-gate (*cl_inet_unbind)(IPPROTO_UDP, AF_INET6, 56697c478bd9Sstevel@tonic-gate (uint8_t *)&(udp->udp_v6src), 56707c478bd9Sstevel@tonic-gate (in_port_t)udp->udp_port); 56717c478bd9Sstevel@tonic-gate } 56727c478bd9Sstevel@tonic-gate } 56737c478bd9Sstevel@tonic-gate 56747c478bd9Sstevel@tonic-gate udp_bind_hash_remove(udp, B_FALSE); 56757c478bd9Sstevel@tonic-gate V6_SET_ZERO(udp->udp_v6src); 56767c478bd9Sstevel@tonic-gate V6_SET_ZERO(udp->udp_bound_v6src); 56777c478bd9Sstevel@tonic-gate udp->udp_port = 0; 56787c478bd9Sstevel@tonic-gate udp->udp_state = TS_UNBND; 56797c478bd9Sstevel@tonic-gate 56807c478bd9Sstevel@tonic-gate if (udp->udp_family == AF_INET6) { 56817c478bd9Sstevel@tonic-gate int error; 56827c478bd9Sstevel@tonic-gate 56837c478bd9Sstevel@tonic-gate /* Rebuild the header template */ 56847c478bd9Sstevel@tonic-gate error = udp_build_hdrs(q, udp); 56857c478bd9Sstevel@tonic-gate if (error != 0) { 56867c478bd9Sstevel@tonic-gate udp_err_ack(q, mp, TSYSERR, error); 56877c478bd9Sstevel@tonic-gate return; 56887c478bd9Sstevel@tonic-gate } 56897c478bd9Sstevel@tonic-gate } 5690ff550d0eSmasputra /* 5691ff550d0eSmasputra * Pass the unbind to IP; T_UNBIND_REQ is larger than T_OK_ACK 5692ff550d0eSmasputra * and therefore ip_unbind must never return NULL. 5693ff550d0eSmasputra */ 5694ff550d0eSmasputra mp = ip_unbind(q, mp); 5695ff550d0eSmasputra ASSERT(mp != NULL); 5696ff550d0eSmasputra putnext(UDP_RD(q), mp); 56977c478bd9Sstevel@tonic-gate } 56987c478bd9Sstevel@tonic-gate 56997c478bd9Sstevel@tonic-gate /* 57007c478bd9Sstevel@tonic-gate * Don't let port fall into the privileged range. 57017c478bd9Sstevel@tonic-gate * Since the extra priviledged ports can be arbitrary we also 57027c478bd9Sstevel@tonic-gate * ensure that we exclude those from consideration. 57037c478bd9Sstevel@tonic-gate * udp_g_epriv_ports is not sorted thus we loop over it until 57047c478bd9Sstevel@tonic-gate * there are no changes. 57057c478bd9Sstevel@tonic-gate */ 57067c478bd9Sstevel@tonic-gate static in_port_t 57077c478bd9Sstevel@tonic-gate udp_update_next_port(in_port_t port, boolean_t random) 57087c478bd9Sstevel@tonic-gate { 57097c478bd9Sstevel@tonic-gate int i; 57107c478bd9Sstevel@tonic-gate 57117c478bd9Sstevel@tonic-gate if (random && udp_random_anon_port != 0) { 57127c478bd9Sstevel@tonic-gate (void) random_get_pseudo_bytes((uint8_t *)&port, 57137c478bd9Sstevel@tonic-gate sizeof (in_port_t)); 57147c478bd9Sstevel@tonic-gate /* 57157c478bd9Sstevel@tonic-gate * Unless changed by a sys admin, the smallest anon port 57167c478bd9Sstevel@tonic-gate * is 32768 and the largest anon port is 65535. It is 57177c478bd9Sstevel@tonic-gate * very likely (50%) for the random port to be smaller 57187c478bd9Sstevel@tonic-gate * than the smallest anon port. When that happens, 57197c478bd9Sstevel@tonic-gate * add port % (anon port range) to the smallest anon 57207c478bd9Sstevel@tonic-gate * port to get the random port. It should fall into the 57217c478bd9Sstevel@tonic-gate * valid anon port range. 57227c478bd9Sstevel@tonic-gate */ 57237c478bd9Sstevel@tonic-gate if (port < udp_smallest_anon_port) { 57247c478bd9Sstevel@tonic-gate port = udp_smallest_anon_port + 57257c478bd9Sstevel@tonic-gate port % (udp_largest_anon_port - 57267c478bd9Sstevel@tonic-gate udp_smallest_anon_port); 57277c478bd9Sstevel@tonic-gate } 57287c478bd9Sstevel@tonic-gate } 57297c478bd9Sstevel@tonic-gate 57307c478bd9Sstevel@tonic-gate retry: 57317c478bd9Sstevel@tonic-gate if (port < udp_smallest_anon_port || port > udp_largest_anon_port) 57327c478bd9Sstevel@tonic-gate port = udp_smallest_anon_port; 57337c478bd9Sstevel@tonic-gate 57347c478bd9Sstevel@tonic-gate if (port < udp_smallest_nonpriv_port) 57357c478bd9Sstevel@tonic-gate port = udp_smallest_nonpriv_port; 57367c478bd9Sstevel@tonic-gate 57377c478bd9Sstevel@tonic-gate for (i = 0; i < udp_g_num_epriv_ports; i++) { 57387c478bd9Sstevel@tonic-gate if (port == udp_g_epriv_ports[i]) { 57397c478bd9Sstevel@tonic-gate port++; 57407c478bd9Sstevel@tonic-gate /* 57417c478bd9Sstevel@tonic-gate * Make sure that the port is in the 57427c478bd9Sstevel@tonic-gate * valid range. 57437c478bd9Sstevel@tonic-gate */ 57447c478bd9Sstevel@tonic-gate goto retry; 57457c478bd9Sstevel@tonic-gate } 57467c478bd9Sstevel@tonic-gate } 57477c478bd9Sstevel@tonic-gate return (port); 57487c478bd9Sstevel@tonic-gate } 57497c478bd9Sstevel@tonic-gate 5750ff550d0eSmasputra static mblk_t * 5751ff550d0eSmasputra udp_output_v4(conn_t *connp, mblk_t *mp, ipaddr_t v4dst, uint16_t port, 5752ff550d0eSmasputra uint_t srcid, int *error) 57537c478bd9Sstevel@tonic-gate { 5754ff550d0eSmasputra udp_t *udp = connp->conn_udp; 5755ff550d0eSmasputra queue_t *q = connp->conn_wq; 5756ff550d0eSmasputra mblk_t *mp1 = (DB_TYPE(mp) == M_DATA ? mp : mp->b_cont); 5757ff550d0eSmasputra mblk_t *mp2; 5758ff550d0eSmasputra ipha_t *ipha; 5759ff550d0eSmasputra int ip_hdr_length; 5760ff550d0eSmasputra uint32_t ip_len; 5761ff550d0eSmasputra udpha_t *udpha; 57627c478bd9Sstevel@tonic-gate 5763ff550d0eSmasputra *error = 0; 57647c478bd9Sstevel@tonic-gate 5765ff550d0eSmasputra /* mp1 points to the M_DATA mblk carrying the packet */ 5766ff550d0eSmasputra ASSERT(mp1 != NULL && DB_TYPE(mp1) == M_DATA); 57677c478bd9Sstevel@tonic-gate 5768ff550d0eSmasputra /* Add an IP header */ 5769ff550d0eSmasputra ip_hdr_length = IP_SIMPLE_HDR_LENGTH + UDPH_SIZE + 5770ff550d0eSmasputra udp->udp_ip_snd_options_len; 5771ff550d0eSmasputra ipha = (ipha_t *)&mp1->b_rptr[-ip_hdr_length]; 5772ff550d0eSmasputra if (DB_REF(mp1) != 1 || (uchar_t *)ipha < DB_BASE(mp1) || 5773ff550d0eSmasputra !OK_32PTR(ipha)) { 5774ff550d0eSmasputra mp2 = allocb(ip_hdr_length + udp_wroff_extra, BPRI_LO); 5775ff550d0eSmasputra if (mp2 == NULL) { 5776ff550d0eSmasputra TRACE_2(TR_FAC_UDP, TR_UDP_WPUT_END, 5777ff550d0eSmasputra "udp_wput_end: q %p (%S)", q, "allocbfail2"); 5778ff550d0eSmasputra *error = ENOMEM; 5779ff550d0eSmasputra goto done; 5780ff550d0eSmasputra } 5781ff550d0eSmasputra mp2->b_wptr = DB_LIM(mp2); 5782ff550d0eSmasputra mp2->b_cont = mp1; 5783ff550d0eSmasputra mp1 = mp2; 5784ff550d0eSmasputra if (DB_TYPE(mp) != M_DATA) 5785ff550d0eSmasputra mp->b_cont = mp1; 5786ff550d0eSmasputra else 5787ff550d0eSmasputra mp = mp1; 57887c478bd9Sstevel@tonic-gate 5789ff550d0eSmasputra ipha = (ipha_t *)(mp1->b_wptr - ip_hdr_length); 57907c478bd9Sstevel@tonic-gate } 5791ff550d0eSmasputra ip_hdr_length -= UDPH_SIZE; 5792ff550d0eSmasputra #ifdef _BIG_ENDIAN 5793ff550d0eSmasputra /* Set version, header length, and tos */ 5794ff550d0eSmasputra *(uint16_t *)&ipha->ipha_version_and_hdr_length = 5795ff550d0eSmasputra ((((IP_VERSION << 4) | (ip_hdr_length>>2)) << 8) | 5796ff550d0eSmasputra udp->udp_type_of_service); 5797ff550d0eSmasputra /* Set ttl and protocol */ 5798ff550d0eSmasputra *(uint16_t *)&ipha->ipha_ttl = (udp->udp_ttl << 8) | IPPROTO_UDP; 5799ff550d0eSmasputra #else 5800ff550d0eSmasputra /* Set version, header length, and tos */ 5801ff550d0eSmasputra *(uint16_t *)&ipha->ipha_version_and_hdr_length = 5802ff550d0eSmasputra ((udp->udp_type_of_service << 8) | 5803ff550d0eSmasputra ((IP_VERSION << 4) | (ip_hdr_length>>2))); 5804ff550d0eSmasputra /* Set ttl and protocol */ 5805ff550d0eSmasputra *(uint16_t *)&ipha->ipha_ttl = (IPPROTO_UDP << 8) | udp->udp_ttl; 5806ff550d0eSmasputra #endif 5807ff550d0eSmasputra /* 5808ff550d0eSmasputra * Copy our address into the packet. If this is zero, 5809ff550d0eSmasputra * first look at __sin6_src_id for a hint. If we leave the source 5810ff550d0eSmasputra * as INADDR_ANY then ip will fill in the real source address. 5811ff550d0eSmasputra */ 5812ff550d0eSmasputra IN6_V4MAPPED_TO_IPADDR(&udp->udp_v6src, ipha->ipha_src); 5813ff550d0eSmasputra if (srcid != 0 && ipha->ipha_src == INADDR_ANY) { 5814ff550d0eSmasputra in6_addr_t v6src; 58157c478bd9Sstevel@tonic-gate 5816ff550d0eSmasputra ip_srcid_find_id(srcid, &v6src, connp->conn_zoneid); 5817ff550d0eSmasputra IN6_V4MAPPED_TO_IPADDR(&v6src, ipha->ipha_src); 58187c478bd9Sstevel@tonic-gate } 58197c478bd9Sstevel@tonic-gate 5820ff550d0eSmasputra ipha->ipha_fragment_offset_and_flags = 0; 5821ff550d0eSmasputra ipha->ipha_ident = 0; 58227c478bd9Sstevel@tonic-gate 5823ff550d0eSmasputra mp1->b_rptr = (uchar_t *)ipha; 58247c478bd9Sstevel@tonic-gate 58257c478bd9Sstevel@tonic-gate ASSERT((uintptr_t)(mp1->b_wptr - (uchar_t *)ipha) <= 58267c478bd9Sstevel@tonic-gate (uintptr_t)UINT_MAX); 58277c478bd9Sstevel@tonic-gate 58287c478bd9Sstevel@tonic-gate /* Determine length of packet */ 58297c478bd9Sstevel@tonic-gate ip_len = (uint32_t)(mp1->b_wptr - (uchar_t *)ipha); 5830ff550d0eSmasputra if ((mp2 = mp1->b_cont) != NULL) { 5831ff550d0eSmasputra do { 5832ff550d0eSmasputra ASSERT((uintptr_t)MBLKL(mp2) <= (uintptr_t)UINT_MAX); 5833ff550d0eSmasputra ip_len += (uint32_t)MBLKL(mp2); 5834ff550d0eSmasputra } while ((mp2 = mp2->b_cont) != NULL); 58357c478bd9Sstevel@tonic-gate } 58367c478bd9Sstevel@tonic-gate /* 58377c478bd9Sstevel@tonic-gate * If the size of the packet is greater than the maximum allowed by 58387c478bd9Sstevel@tonic-gate * ip, return an error. Passing this down could cause panics because 58397c478bd9Sstevel@tonic-gate * the size will have wrapped and be inconsistent with the msg size. 58407c478bd9Sstevel@tonic-gate */ 58417c478bd9Sstevel@tonic-gate if (ip_len > IP_MAXPACKET) { 58427c478bd9Sstevel@tonic-gate TRACE_2(TR_FAC_UDP, TR_UDP_WPUT_END, 58437c478bd9Sstevel@tonic-gate "udp_wput_end: q %p (%S)", q, "IP length exceeded"); 5844ff550d0eSmasputra *error = EMSGSIZE; 5845ff550d0eSmasputra goto done; 58467c478bd9Sstevel@tonic-gate } 58477c478bd9Sstevel@tonic-gate ipha->ipha_length = htons((uint16_t)ip_len); 58487c478bd9Sstevel@tonic-gate ip_len -= ip_hdr_length; 58497c478bd9Sstevel@tonic-gate ip_len = htons((uint16_t)ip_len); 58507c478bd9Sstevel@tonic-gate udpha = (udpha_t *)(((uchar_t *)ipha) + ip_hdr_length); 5851ff550d0eSmasputra 58527c478bd9Sstevel@tonic-gate /* 5853ff550d0eSmasputra * Copy in the destination address 58547c478bd9Sstevel@tonic-gate */ 58557c478bd9Sstevel@tonic-gate if (v4dst == INADDR_ANY) 58567c478bd9Sstevel@tonic-gate ipha->ipha_dst = htonl(INADDR_LOOPBACK); 58577c478bd9Sstevel@tonic-gate else 58587c478bd9Sstevel@tonic-gate ipha->ipha_dst = v4dst; 58597c478bd9Sstevel@tonic-gate 58607c478bd9Sstevel@tonic-gate /* 58617c478bd9Sstevel@tonic-gate * Set ttl based on IP_MULTICAST_TTL to match IPv6 logic. 58627c478bd9Sstevel@tonic-gate */ 58637c478bd9Sstevel@tonic-gate if (CLASSD(v4dst)) 58647c478bd9Sstevel@tonic-gate ipha->ipha_ttl = udp->udp_multicast_ttl; 58657c478bd9Sstevel@tonic-gate 58667c478bd9Sstevel@tonic-gate udpha->uha_dst_port = port; 58677c478bd9Sstevel@tonic-gate udpha->uha_src_port = udp->udp_port; 58687c478bd9Sstevel@tonic-gate 58697c478bd9Sstevel@tonic-gate if (ip_hdr_length > IP_SIMPLE_HDR_LENGTH) { 58707c478bd9Sstevel@tonic-gate uint32_t cksum; 58717c478bd9Sstevel@tonic-gate 58727c478bd9Sstevel@tonic-gate bcopy(udp->udp_ip_snd_options, &ipha[1], 58737c478bd9Sstevel@tonic-gate udp->udp_ip_snd_options_len); 58747c478bd9Sstevel@tonic-gate /* 58757c478bd9Sstevel@tonic-gate * Massage source route putting first source route in ipha_dst. 58767c478bd9Sstevel@tonic-gate * Ignore the destination in T_unitdata_req. 58777c478bd9Sstevel@tonic-gate * Create a checksum adjustment for a source route, if any. 58787c478bd9Sstevel@tonic-gate */ 58797c478bd9Sstevel@tonic-gate cksum = ip_massage_options(ipha); 58807c478bd9Sstevel@tonic-gate cksum = (cksum & 0xFFFF) + (cksum >> 16); 58817c478bd9Sstevel@tonic-gate cksum -= ((ipha->ipha_dst >> 16) & 0xFFFF) + 58827c478bd9Sstevel@tonic-gate (ipha->ipha_dst & 0xFFFF); 58837c478bd9Sstevel@tonic-gate if ((int)cksum < 0) 58847c478bd9Sstevel@tonic-gate cksum--; 58857c478bd9Sstevel@tonic-gate cksum = (cksum & 0xFFFF) + (cksum >> 16); 58867c478bd9Sstevel@tonic-gate /* 58877c478bd9Sstevel@tonic-gate * IP does the checksum if uha_checksum is non-zero, 58887c478bd9Sstevel@tonic-gate * We make it easy for IP to include our pseudo header 58897c478bd9Sstevel@tonic-gate * by putting our length in uha_checksum. 58907c478bd9Sstevel@tonic-gate */ 58917c478bd9Sstevel@tonic-gate cksum += ip_len; 58927c478bd9Sstevel@tonic-gate cksum = (cksum & 0xFFFF) + (cksum >> 16); 58937c478bd9Sstevel@tonic-gate /* There might be a carry. */ 58947c478bd9Sstevel@tonic-gate cksum = (cksum & 0xFFFF) + (cksum >> 16); 58957c478bd9Sstevel@tonic-gate #ifdef _LITTLE_ENDIAN 58967c478bd9Sstevel@tonic-gate if (udp_do_checksum) 58977c478bd9Sstevel@tonic-gate ip_len = (cksum << 16) | ip_len; 58987c478bd9Sstevel@tonic-gate #else 58997c478bd9Sstevel@tonic-gate if (udp_do_checksum) 59007c478bd9Sstevel@tonic-gate ip_len = (ip_len << 16) | cksum; 59017c478bd9Sstevel@tonic-gate else 59027c478bd9Sstevel@tonic-gate ip_len <<= 16; 59037c478bd9Sstevel@tonic-gate #endif 59047c478bd9Sstevel@tonic-gate } else { 59057c478bd9Sstevel@tonic-gate /* 59067c478bd9Sstevel@tonic-gate * IP does the checksum if uha_checksum is non-zero, 59077c478bd9Sstevel@tonic-gate * We make it easy for IP to include our pseudo header 59087c478bd9Sstevel@tonic-gate * by putting our length in uha_checksum. 59097c478bd9Sstevel@tonic-gate */ 59107c478bd9Sstevel@tonic-gate if (udp_do_checksum) 59117c478bd9Sstevel@tonic-gate ip_len |= (ip_len << 16); 59127c478bd9Sstevel@tonic-gate #ifndef _LITTLE_ENDIAN 59137c478bd9Sstevel@tonic-gate else 59147c478bd9Sstevel@tonic-gate ip_len <<= 16; 59157c478bd9Sstevel@tonic-gate #endif 59167c478bd9Sstevel@tonic-gate } 59177c478bd9Sstevel@tonic-gate /* Set UDP length and checksum */ 59187c478bd9Sstevel@tonic-gate *((uint32_t *)&udpha->uha_length) = ip_len; 59197c478bd9Sstevel@tonic-gate 5920ff550d0eSmasputra if (DB_TYPE(mp) != M_DATA) { 5921ff550d0eSmasputra ASSERT(mp != mp1); 5922ff550d0eSmasputra freeb(mp); 5923ff550d0eSmasputra } 5924ff550d0eSmasputra 5925ff550d0eSmasputra /* mp has been consumed and we'll return success */ 5926ff550d0eSmasputra ASSERT(*error == 0); 5927ff550d0eSmasputra mp = NULL; 59287c478bd9Sstevel@tonic-gate 59297c478bd9Sstevel@tonic-gate /* We're done. Pass the packet to ip. */ 59307c478bd9Sstevel@tonic-gate BUMP_MIB(&udp_mib, udpOutDatagrams); 59317c478bd9Sstevel@tonic-gate TRACE_2(TR_FAC_UDP, TR_UDP_WPUT_END, 59327c478bd9Sstevel@tonic-gate "udp_wput_end: q %p (%S)", q, "end"); 5933ff550d0eSmasputra 5934ff550d0eSmasputra if ((connp->conn_flags & IPCL_CHECK_POLICY) != 0 || 5935ff550d0eSmasputra CONN_OUTBOUND_POLICY_PRESENT(connp) || 5936ff550d0eSmasputra connp->conn_dontroute || connp->conn_xmit_if_ill != NULL || 5937ff550d0eSmasputra connp->conn_nofailover_ill != NULL || 5938ff550d0eSmasputra connp->conn_outgoing_ill != NULL || 5939ff550d0eSmasputra ipha->ipha_version_and_hdr_length != IP_SIMPLE_HDR_VERSION || 5940ff550d0eSmasputra IPP_ENABLED(IPP_LOCAL_OUT) || ip_g_mrouter != NULL) { 5941ff550d0eSmasputra UDP_STAT(udp_ip_send); 5942ff550d0eSmasputra ip_output(connp, mp1, connp->conn_wq, IP_WPUT); 5943ff550d0eSmasputra } else { 5944ff550d0eSmasputra udp_send_data(udp, connp->conn_wq, mp1, ipha); 5945ff550d0eSmasputra } 5946ff550d0eSmasputra 5947ff550d0eSmasputra done: 5948ff550d0eSmasputra if (*error != 0) { 5949ff550d0eSmasputra ASSERT(mp != NULL); 5950ff550d0eSmasputra BUMP_MIB(&udp_mib, udpOutErrors); 5951ff550d0eSmasputra } 5952ff550d0eSmasputra return (mp); 5953ff550d0eSmasputra } 5954ff550d0eSmasputra 5955ff550d0eSmasputra static void 5956ff550d0eSmasputra udp_send_data(udp_t *udp, queue_t *q, mblk_t *mp, ipha_t *ipha) 5957ff550d0eSmasputra { 5958ff550d0eSmasputra conn_t *connp = udp->udp_connp; 5959ff550d0eSmasputra ipaddr_t src, dst; 5960ff550d0eSmasputra ill_t *ill; 5961ff550d0eSmasputra ire_t *ire; 5962ff550d0eSmasputra ipif_t *ipif = NULL; 5963ff550d0eSmasputra mblk_t *ire_fp_mp; 5964ff550d0eSmasputra uint_t ire_fp_mp_len; 5965ff550d0eSmasputra uint16_t *up; 5966ff550d0eSmasputra uint32_t cksum, hcksum_txflags; 5967ff550d0eSmasputra queue_t *dev_q; 5968ff550d0eSmasputra boolean_t retry_caching; 5969ff550d0eSmasputra 5970ff550d0eSmasputra dst = ipha->ipha_dst; 5971ff550d0eSmasputra src = ipha->ipha_src; 5972ff550d0eSmasputra ASSERT(ipha->ipha_ident == 0); 5973ff550d0eSmasputra 5974ff550d0eSmasputra if (CLASSD(dst)) { 5975ff550d0eSmasputra int err; 5976ff550d0eSmasputra 5977ff550d0eSmasputra ipif = conn_get_held_ipif(connp, 5978ff550d0eSmasputra &connp->conn_multicast_ipif, &err); 5979ff550d0eSmasputra 5980ff550d0eSmasputra if (ipif == NULL || ipif->ipif_isv6 || 5981ff550d0eSmasputra (ipif->ipif_ill->ill_phyint->phyint_flags & 5982ff550d0eSmasputra PHYI_LOOPBACK)) { 5983ff550d0eSmasputra if (ipif != NULL) 5984ff550d0eSmasputra ipif_refrele(ipif); 5985ff550d0eSmasputra UDP_STAT(udp_ip_send); 5986ff550d0eSmasputra ip_output(connp, mp, q, IP_WPUT); 5987ff550d0eSmasputra return; 5988ff550d0eSmasputra } 5989ff550d0eSmasputra } 5990ff550d0eSmasputra 5991ff550d0eSmasputra retry_caching = B_FALSE; 5992ff550d0eSmasputra mutex_enter(&connp->conn_lock); 5993ff550d0eSmasputra ire = connp->conn_ire_cache; 5994ff550d0eSmasputra ASSERT(!(connp->conn_state_flags & CONN_INCIPIENT)); 5995ff550d0eSmasputra 5996ff550d0eSmasputra if (ire == NULL || ire->ire_addr != dst || 5997ff550d0eSmasputra (ire->ire_marks & IRE_MARK_CONDEMNED)) { 5998ff550d0eSmasputra retry_caching = B_TRUE; 5999ff550d0eSmasputra } else if (CLASSD(dst) && (ire->ire_type & IRE_CACHE)) { 6000ff550d0eSmasputra ill_t *stq_ill = (ill_t *)ire->ire_stq->q_ptr; 6001ff550d0eSmasputra 6002ff550d0eSmasputra ASSERT(ipif != NULL); 6003ff550d0eSmasputra if (stq_ill != ipif->ipif_ill && (stq_ill->ill_group == NULL || 6004ff550d0eSmasputra stq_ill->ill_group != ipif->ipif_ill->ill_group)) 6005ff550d0eSmasputra retry_caching = B_TRUE; 6006ff550d0eSmasputra } 6007ff550d0eSmasputra 6008ff550d0eSmasputra if (!retry_caching) { 6009ff550d0eSmasputra ASSERT(ire != NULL); 6010ff550d0eSmasputra IRE_REFHOLD(ire); 6011ff550d0eSmasputra mutex_exit(&connp->conn_lock); 6012ff550d0eSmasputra } else { 6013ff550d0eSmasputra boolean_t cached = B_FALSE; 6014ff550d0eSmasputra 6015ff550d0eSmasputra connp->conn_ire_cache = NULL; 6016ff550d0eSmasputra mutex_exit(&connp->conn_lock); 6017ff550d0eSmasputra 6018ff550d0eSmasputra /* Release the old ire */ 6019ff550d0eSmasputra if (ire != NULL) { 6020ff550d0eSmasputra IRE_REFRELE_NOTR(ire); 6021ff550d0eSmasputra ire = NULL; 6022ff550d0eSmasputra } 6023ff550d0eSmasputra 6024ff550d0eSmasputra if (CLASSD(dst)) { 6025ff550d0eSmasputra ASSERT(ipif != NULL); 6026ff550d0eSmasputra ire = ire_ctable_lookup(dst, 0, 0, ipif, 6027ff550d0eSmasputra connp->conn_zoneid, MATCH_IRE_ILL_GROUP); 6028ff550d0eSmasputra } else { 6029ff550d0eSmasputra ASSERT(ipif == NULL); 6030ff550d0eSmasputra ire = ire_cache_lookup(dst, connp->conn_zoneid); 6031ff550d0eSmasputra } 6032ff550d0eSmasputra 6033ff550d0eSmasputra if (ire == NULL) { 6034ff550d0eSmasputra if (ipif != NULL) 6035ff550d0eSmasputra ipif_refrele(ipif); 6036ff550d0eSmasputra UDP_STAT(udp_ire_null); 6037ff550d0eSmasputra ip_output(connp, mp, q, IP_WPUT); 6038ff550d0eSmasputra return; 6039ff550d0eSmasputra } 6040ff550d0eSmasputra IRE_REFHOLD_NOTR(ire); 6041ff550d0eSmasputra 6042ff550d0eSmasputra mutex_enter(&connp->conn_lock); 6043ff550d0eSmasputra if (!(connp->conn_state_flags & CONN_CLOSING) && 6044ff550d0eSmasputra connp->conn_ire_cache == NULL) { 6045ff550d0eSmasputra rw_enter(&ire->ire_bucket->irb_lock, RW_READER); 6046ff550d0eSmasputra if (!(ire->ire_marks & IRE_MARK_CONDEMNED)) { 6047ff550d0eSmasputra connp->conn_ire_cache = ire; 6048ff550d0eSmasputra cached = B_TRUE; 6049ff550d0eSmasputra } 6050ff550d0eSmasputra rw_exit(&ire->ire_bucket->irb_lock); 6051ff550d0eSmasputra } 6052ff550d0eSmasputra mutex_exit(&connp->conn_lock); 6053ff550d0eSmasputra 6054ff550d0eSmasputra /* 6055ff550d0eSmasputra * We can continue to use the ire but since it was not 6056ff550d0eSmasputra * cached, we should drop the extra reference. 6057ff550d0eSmasputra */ 6058ff550d0eSmasputra if (!cached) 6059ff550d0eSmasputra IRE_REFRELE_NOTR(ire); 6060ff550d0eSmasputra } 6061ff550d0eSmasputra ASSERT(ire != NULL && ire->ire_ipversion == IPV4_VERSION); 6062ff550d0eSmasputra ASSERT(!CLASSD(dst) || ipif != NULL); 6063ff550d0eSmasputra 6064ff550d0eSmasputra if ((ire->ire_type & (IRE_BROADCAST|IRE_LOCAL|IRE_LOOPBACK)) || 6065ff550d0eSmasputra (ire->ire_flags & RTF_MULTIRT) || ire->ire_stq == NULL || 6066ff550d0eSmasputra ire->ire_max_frag < ntohs(ipha->ipha_length) || 6067ff550d0eSmasputra (ire_fp_mp = ire->ire_fp_mp) == NULL || 606843d18f1cSpriyanka (connp->conn_nexthop_set) || 6069ff550d0eSmasputra (ire_fp_mp_len = MBLKL(ire_fp_mp)) > MBLKHEAD(mp)) { 6070ff550d0eSmasputra if (ipif != NULL) 6071ff550d0eSmasputra ipif_refrele(ipif); 6072ff550d0eSmasputra UDP_STAT(udp_ip_ire_send); 6073ff550d0eSmasputra IRE_REFRELE(ire); 6074ff550d0eSmasputra ip_output(connp, mp, q, IP_WPUT); 6075ff550d0eSmasputra return; 6076ff550d0eSmasputra } 6077ff550d0eSmasputra 6078ff550d0eSmasputra BUMP_MIB(&ip_mib, ipOutRequests); 6079ff550d0eSmasputra 6080ff550d0eSmasputra ill = ire_to_ill(ire); 6081ff550d0eSmasputra ASSERT(ill != NULL); 6082ff550d0eSmasputra 6083ff550d0eSmasputra dev_q = ire->ire_stq->q_next; 6084ff550d0eSmasputra ASSERT(dev_q != NULL); 6085ff550d0eSmasputra /* 6086ff550d0eSmasputra * If the service thread is already running, or if the driver 6087ff550d0eSmasputra * queue is currently flow-controlled, queue this packet. 6088ff550d0eSmasputra */ 6089ff550d0eSmasputra if ((q->q_first != NULL || connp->conn_draining) || 6090ff550d0eSmasputra ((dev_q->q_next || dev_q->q_first) && !canput(dev_q))) { 6091ff550d0eSmasputra if (ip_output_queue) { 6092ff550d0eSmasputra (void) putq(q, mp); 6093ff550d0eSmasputra } else { 6094ff550d0eSmasputra BUMP_MIB(&ip_mib, ipOutDiscards); 6095ff550d0eSmasputra freemsg(mp); 6096ff550d0eSmasputra } 6097ff550d0eSmasputra if (ipif != NULL) 6098ff550d0eSmasputra ipif_refrele(ipif); 6099ff550d0eSmasputra IRE_REFRELE(ire); 6100ff550d0eSmasputra return; 6101ff550d0eSmasputra } 6102ff550d0eSmasputra 6103ff550d0eSmasputra ipha->ipha_ident = (uint16_t)atomic_add_32_nv(&ire->ire_ident, 1); 6104ff550d0eSmasputra #ifndef _BIG_ENDIAN 6105ff550d0eSmasputra ipha->ipha_ident = (ipha->ipha_ident << 8) | (ipha->ipha_ident >> 8); 6106ff550d0eSmasputra #endif 6107ff550d0eSmasputra 6108ff550d0eSmasputra if (src == INADDR_ANY && !connp->conn_unspec_src) { 6109ff550d0eSmasputra if (CLASSD(dst) && !(ire->ire_flags & RTF_SETSRC)) 6110ff550d0eSmasputra src = ipha->ipha_src = ipif->ipif_src_addr; 6111ff550d0eSmasputra else 6112ff550d0eSmasputra src = ipha->ipha_src = ire->ire_src_addr; 6113ff550d0eSmasputra } 6114ff550d0eSmasputra 6115ff550d0eSmasputra if (ILL_HCKSUM_CAPABLE(ill) && dohwcksum) { 6116ff550d0eSmasputra ASSERT(ill->ill_hcksum_capab != NULL); 6117ff550d0eSmasputra hcksum_txflags = ill->ill_hcksum_capab->ill_hcksum_txflags; 6118ff550d0eSmasputra } else { 6119ff550d0eSmasputra hcksum_txflags = 0; 6120ff550d0eSmasputra } 6121ff550d0eSmasputra 6122ff550d0eSmasputra /* pseudo-header checksum (do it in parts for IP header checksum) */ 6123ff550d0eSmasputra cksum = (dst >> 16) + (dst & 0xFFFF) + (src >> 16) + (src & 0xFFFF); 6124ff550d0eSmasputra 6125ff550d0eSmasputra ASSERT(ipha->ipha_version_and_hdr_length == IP_SIMPLE_HDR_VERSION); 6126ff550d0eSmasputra up = IPH_UDPH_CHECKSUMP(ipha, IP_SIMPLE_HDR_LENGTH); 6127ff550d0eSmasputra if (*up != 0) { 6128ff550d0eSmasputra IP_CKSUM_XMIT_FAST(ire->ire_ipversion, hcksum_txflags, 6129ff550d0eSmasputra mp, ipha, up, IPPROTO_UDP, IP_SIMPLE_HDR_LENGTH, 6130ff550d0eSmasputra ntohs(ipha->ipha_length), cksum); 6131ff550d0eSmasputra 6132ff550d0eSmasputra /* Software checksum? */ 6133ff550d0eSmasputra if (DB_CKSUMFLAGS(mp) == 0) { 6134ff550d0eSmasputra UDP_STAT(udp_out_sw_cksum); 6135ff550d0eSmasputra UDP_STAT_UPDATE(udp_out_sw_cksum_bytes, 6136ff550d0eSmasputra ntohs(ipha->ipha_length) - IP_SIMPLE_HDR_LENGTH); 6137ff550d0eSmasputra } 6138ff550d0eSmasputra } 6139ff550d0eSmasputra 6140ff550d0eSmasputra ipha->ipha_fragment_offset_and_flags |= 6141ff550d0eSmasputra (uint32_t)htons(ire->ire_frag_flag); 6142ff550d0eSmasputra 6143ff550d0eSmasputra /* Calculate IP header checksum if hardware isn't capable */ 6144ff550d0eSmasputra if (!(DB_CKSUMFLAGS(mp) & HCK_IPV4_HDRCKSUM)) { 6145ff550d0eSmasputra IP_HDR_CKSUM(ipha, cksum, ((uint32_t *)ipha)[0], 6146ff550d0eSmasputra ((uint16_t *)ipha)[4]); 6147ff550d0eSmasputra } 6148ff550d0eSmasputra 6149ff550d0eSmasputra if (CLASSD(dst)) { 6150ff550d0eSmasputra ilm_t *ilm; 6151ff550d0eSmasputra 6152ff550d0eSmasputra ILM_WALKER_HOLD(ill); 6153ff550d0eSmasputra ilm = ilm_lookup_ill(ill, dst, ALL_ZONES); 6154ff550d0eSmasputra ILM_WALKER_RELE(ill); 6155ff550d0eSmasputra if (ilm != NULL) { 6156ff550d0eSmasputra ip_multicast_loopback(q, ill, mp, 6157ff550d0eSmasputra connp->conn_multicast_loop ? 0 : 6158ff550d0eSmasputra IP_FF_NO_MCAST_LOOP, connp->conn_zoneid); 6159ff550d0eSmasputra } 6160ff550d0eSmasputra 6161ff550d0eSmasputra /* If multicast TTL is 0 then we are done */ 6162ff550d0eSmasputra if (ipha->ipha_ttl == 0) { 6163ff550d0eSmasputra if (ipif != NULL) 6164ff550d0eSmasputra ipif_refrele(ipif); 6165ff550d0eSmasputra freemsg(mp); 6166ff550d0eSmasputra IRE_REFRELE(ire); 6167ff550d0eSmasputra return; 6168ff550d0eSmasputra } 6169ff550d0eSmasputra } 6170ff550d0eSmasputra 6171ff550d0eSmasputra ASSERT(DB_TYPE(ire_fp_mp) == M_DATA); 6172ff550d0eSmasputra mp->b_rptr = (uchar_t *)ipha - ire_fp_mp_len; 6173ff550d0eSmasputra bcopy(ire_fp_mp->b_rptr, mp->b_rptr, ire_fp_mp_len); 6174ff550d0eSmasputra 6175ff550d0eSmasputra UPDATE_OB_PKT_COUNT(ire); 6176ff550d0eSmasputra ire->ire_last_used_time = lbolt; 6177ff550d0eSmasputra 61784b46d1efSkrgopi if (ILL_DLS_CAPABLE(ill)) { 6179ff550d0eSmasputra /* 6180ff550d0eSmasputra * Send the packet directly to DLD, where it may be queued 6181ff550d0eSmasputra * depending on the availability of transmit resources at 6182ff550d0eSmasputra * the media layer. 6183ff550d0eSmasputra */ 61844b46d1efSkrgopi IP_DLS_ILL_TX(ill, mp); 6185ff550d0eSmasputra } else { 6186ff550d0eSmasputra putnext(ire->ire_stq, mp); 6187ff550d0eSmasputra } 6188ff550d0eSmasputra 6189ff550d0eSmasputra if (ipif != NULL) 6190ff550d0eSmasputra ipif_refrele(ipif); 6191ff550d0eSmasputra IRE_REFRELE(ire); 61927c478bd9Sstevel@tonic-gate } 61937c478bd9Sstevel@tonic-gate 61947c478bd9Sstevel@tonic-gate /* 6195ff550d0eSmasputra * This routine handles all messages passed downstream. It either 6196ff550d0eSmasputra * consumes the message or passes it downstream; it never queues a 6197ff550d0eSmasputra * a message. 61987c478bd9Sstevel@tonic-gate */ 61997c478bd9Sstevel@tonic-gate static void 6200ff550d0eSmasputra udp_output(conn_t *connp, mblk_t *mp, struct sockaddr *addr, socklen_t addrlen) 62017c478bd9Sstevel@tonic-gate { 6202ff550d0eSmasputra sin6_t *sin6; 6203ff550d0eSmasputra sin_t *sin; 6204ff550d0eSmasputra ipaddr_t v4dst; 6205ff550d0eSmasputra uint16_t port; 6206ff550d0eSmasputra uint_t srcid; 6207ff550d0eSmasputra queue_t *q = connp->conn_wq; 6208ff550d0eSmasputra udp_t *udp = connp->conn_udp; 6209ff550d0eSmasputra t_scalar_t optlen; 6210ff550d0eSmasputra int error = 0; 6211ff550d0eSmasputra struct sockaddr_storage ss; 62127c478bd9Sstevel@tonic-gate 6213ff550d0eSmasputra TRACE_2(TR_FAC_UDP, TR_UDP_WPUT_START, 6214ff550d0eSmasputra "udp_wput_start: connp %p mp %p", connp, mp); 6215ff550d0eSmasputra 6216ff550d0eSmasputra /* 6217ff550d0eSmasputra * We directly handle several cases here: T_UNITDATA_REQ message 6218ff550d0eSmasputra * coming down as M_PROTO/M_PCPROTO and M_DATA messages for both 6219ff550d0eSmasputra * connected and non-connected socket. The latter carries the 6220ff550d0eSmasputra * address structure along when this routine gets called. 6221ff550d0eSmasputra */ 6222ff550d0eSmasputra switch (DB_TYPE(mp)) { 6223ff550d0eSmasputra case M_DATA: 6224ff550d0eSmasputra if (!udp->udp_direct_sockfs || udp->udp_state != TS_DATA_XFER) { 6225ff550d0eSmasputra if (!udp->udp_direct_sockfs || 6226ff550d0eSmasputra addr == NULL || addrlen == 0) { 6227ff550d0eSmasputra /* Not connected; address is required */ 6228ff550d0eSmasputra BUMP_MIB(&udp_mib, udpOutErrors); 6229ff550d0eSmasputra UDP_STAT(udp_out_err_notconn); 6230ff550d0eSmasputra freemsg(mp); 6231ff550d0eSmasputra TRACE_2(TR_FAC_UDP, TR_UDP_WPUT_END, 6232ff550d0eSmasputra "udp_wput_end: connp %p (%S)", connp, 6233ff550d0eSmasputra "not-connected; address required"); 6234ff550d0eSmasputra return; 6235ff550d0eSmasputra } 6236ff550d0eSmasputra ASSERT(udp->udp_issocket); 6237ff550d0eSmasputra UDP_DBGSTAT(udp_data_notconn); 6238ff550d0eSmasputra /* Not connected; do some more checks below */ 6239ff550d0eSmasputra optlen = 0; 6240ff550d0eSmasputra break; 6241ff550d0eSmasputra } 6242ff550d0eSmasputra /* M_DATA for connected socket */ 6243ff550d0eSmasputra UDP_DBGSTAT(udp_data_conn); 6244ff550d0eSmasputra IN6_V4MAPPED_TO_IPADDR(&udp->udp_v6dst, v4dst); 6245ff550d0eSmasputra 6246ff550d0eSmasputra /* Initialize addr and addrlen as if they're passed in */ 6247ff550d0eSmasputra if (udp->udp_family == AF_INET) { 6248ff550d0eSmasputra sin = (sin_t *)&ss; 6249ff550d0eSmasputra sin->sin_family = AF_INET; 6250ff550d0eSmasputra sin->sin_port = udp->udp_dstport; 6251ff550d0eSmasputra sin->sin_addr.s_addr = v4dst; 6252ff550d0eSmasputra addr = (struct sockaddr *)sin; 6253ff550d0eSmasputra addrlen = sizeof (*sin); 6254ff550d0eSmasputra } else { 6255ff550d0eSmasputra sin6 = (sin6_t *)&ss; 6256ff550d0eSmasputra sin6->sin6_family = AF_INET6; 6257ff550d0eSmasputra sin6->sin6_port = udp->udp_dstport; 6258ff550d0eSmasputra sin6->sin6_flowinfo = udp->udp_flowinfo; 6259ff550d0eSmasputra sin6->sin6_addr = udp->udp_v6dst; 6260ff550d0eSmasputra sin6->sin6_scope_id = 0; 6261ff550d0eSmasputra sin6->__sin6_src_id = 0; 6262ff550d0eSmasputra addr = (struct sockaddr *)sin6; 6263ff550d0eSmasputra addrlen = sizeof (*sin6); 6264ff550d0eSmasputra } 6265ff550d0eSmasputra 6266ff550d0eSmasputra if (udp->udp_family == AF_INET || 6267ff550d0eSmasputra IN6_IS_ADDR_V4MAPPED(&udp->udp_v6dst)) { 6268ff550d0eSmasputra /* 6269ff550d0eSmasputra * Handle both AF_INET and AF_INET6; the latter 6270ff550d0eSmasputra * for IPV4 mapped destination addresses. Note 6271ff550d0eSmasputra * here that both addr and addrlen point to the 6272ff550d0eSmasputra * corresponding struct depending on the address 6273ff550d0eSmasputra * family of the socket. 6274ff550d0eSmasputra */ 6275ff550d0eSmasputra mp = udp_output_v4(connp, mp, v4dst, 6276ff550d0eSmasputra udp->udp_dstport, 0, &error); 6277ff550d0eSmasputra } else { 6278ff550d0eSmasputra mp = udp_output_v6(connp, mp, sin6, 0, &error); 6279ff550d0eSmasputra } 6280ff550d0eSmasputra if (error != 0) { 6281ff550d0eSmasputra ASSERT(addr != NULL && addrlen != 0); 6282ff550d0eSmasputra goto ud_error; 6283ff550d0eSmasputra } 6284ff550d0eSmasputra return; 6285ff550d0eSmasputra case M_PROTO: 6286ff550d0eSmasputra case M_PCPROTO: { 6287ff550d0eSmasputra struct T_unitdata_req *tudr; 6288ff550d0eSmasputra 6289ff550d0eSmasputra ASSERT((uintptr_t)MBLKL(mp) <= (uintptr_t)INT_MAX); 6290ff550d0eSmasputra tudr = (struct T_unitdata_req *)mp->b_rptr; 6291ff550d0eSmasputra 6292ff550d0eSmasputra /* Handle valid T_UNITDATA_REQ here */ 6293ff550d0eSmasputra if (MBLKL(mp) >= sizeof (*tudr) && 6294ff550d0eSmasputra ((t_primp_t)mp->b_rptr)->type == T_UNITDATA_REQ) { 6295ff550d0eSmasputra if (mp->b_cont == NULL) { 6296ff550d0eSmasputra TRACE_2(TR_FAC_UDP, TR_UDP_WPUT_END, 6297ff550d0eSmasputra "udp_wput_end: q %p (%S)", q, "badaddr"); 6298ff550d0eSmasputra error = EPROTO; 6299ff550d0eSmasputra goto ud_error; 6300ff550d0eSmasputra } 6301ff550d0eSmasputra 6302ff550d0eSmasputra if (!MBLKIN(mp, 0, tudr->DEST_offset + 6303ff550d0eSmasputra tudr->DEST_length)) { 6304ff550d0eSmasputra TRACE_2(TR_FAC_UDP, TR_UDP_WPUT_END, 6305ff550d0eSmasputra "udp_wput_end: q %p (%S)", q, "badaddr"); 6306ff550d0eSmasputra error = EADDRNOTAVAIL; 6307ff550d0eSmasputra goto ud_error; 6308ff550d0eSmasputra } 6309ff550d0eSmasputra /* 6310ff550d0eSmasputra * If a port has not been bound to the stream, fail. 6311ff550d0eSmasputra * This is not a problem when sockfs is directly 6312ff550d0eSmasputra * above us, because it will ensure that the socket 6313ff550d0eSmasputra * is first bound before allowing data to be sent. 6314ff550d0eSmasputra */ 6315ff550d0eSmasputra if (udp->udp_state == TS_UNBND) { 6316ff550d0eSmasputra TRACE_2(TR_FAC_UDP, TR_UDP_WPUT_END, 6317ff550d0eSmasputra "udp_wput_end: q %p (%S)", q, "outstate"); 6318ff550d0eSmasputra error = EPROTO; 6319ff550d0eSmasputra goto ud_error; 6320ff550d0eSmasputra } 6321ff550d0eSmasputra addr = (struct sockaddr *) 6322ff550d0eSmasputra &mp->b_rptr[tudr->DEST_offset]; 6323ff550d0eSmasputra addrlen = tudr->DEST_length; 6324ff550d0eSmasputra optlen = tudr->OPT_length; 6325ff550d0eSmasputra if (optlen != 0) 6326ff550d0eSmasputra UDP_STAT(udp_out_opt); 6327ff550d0eSmasputra break; 6328ff550d0eSmasputra } 6329ff550d0eSmasputra /* FALLTHRU */ 6330ff550d0eSmasputra } 6331ff550d0eSmasputra default: 6332ff550d0eSmasputra udp_become_writer(connp, mp, udp_wput_other_wrapper, 6333ff550d0eSmasputra SQTAG_UDP_OUTPUT); 6334ff550d0eSmasputra return; 6335ff550d0eSmasputra } 6336ff550d0eSmasputra ASSERT(addr != NULL); 6337ff550d0eSmasputra 6338ff550d0eSmasputra switch (udp->udp_family) { 6339ff550d0eSmasputra case AF_INET6: 6340ff550d0eSmasputra sin6 = (sin6_t *)addr; 6341ff550d0eSmasputra if (!OK_32PTR((char *)sin6) || addrlen != sizeof (sin6_t) || 6342ff550d0eSmasputra sin6->sin6_family != AF_INET6) { 6343ff550d0eSmasputra TRACE_2(TR_FAC_UDP, TR_UDP_WPUT_END, 6344ff550d0eSmasputra "udp_wput_end: q %p (%S)", q, "badaddr"); 6345ff550d0eSmasputra error = EADDRNOTAVAIL; 6346ff550d0eSmasputra goto ud_error; 6347ff550d0eSmasputra } 6348ff550d0eSmasputra 6349ff550d0eSmasputra if (!IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 6350ff550d0eSmasputra /* 6351ff550d0eSmasputra * Destination is a non-IPv4-compatible IPv6 address. 6352ff550d0eSmasputra * Send out an IPv6 format packet. 6353ff550d0eSmasputra */ 6354ff550d0eSmasputra mp = udp_output_v6(connp, mp, sin6, optlen, &error); 6355ff550d0eSmasputra if (error != 0) 6356ff550d0eSmasputra goto ud_error; 6357ff550d0eSmasputra 6358ff550d0eSmasputra TRACE_2(TR_FAC_UDP, TR_UDP_WPUT_END, 6359ff550d0eSmasputra "udp_wput_end: q %p (%S)", q, "udp_output_v6"); 6360ff550d0eSmasputra return; 6361ff550d0eSmasputra } 6362ff550d0eSmasputra /* 6363ff550d0eSmasputra * If the local address is not zero or a mapped address 6364ff550d0eSmasputra * return an error. It would be possible to send an IPv4 6365ff550d0eSmasputra * packet but the response would never make it back to the 6366ff550d0eSmasputra * application since it is bound to a non-mapped address. 6367ff550d0eSmasputra */ 6368ff550d0eSmasputra if (!IN6_IS_ADDR_V4MAPPED(&udp->udp_v6src) && 6369ff550d0eSmasputra !IN6_IS_ADDR_UNSPECIFIED(&udp->udp_v6src)) { 6370ff550d0eSmasputra TRACE_2(TR_FAC_UDP, TR_UDP_WPUT_END, 6371ff550d0eSmasputra "udp_wput_end: q %p (%S)", q, "badaddr"); 6372ff550d0eSmasputra error = EADDRNOTAVAIL; 6373ff550d0eSmasputra goto ud_error; 6374ff550d0eSmasputra } 6375ff550d0eSmasputra /* Send IPv4 packet without modifying udp_ipversion */ 6376ff550d0eSmasputra /* Extract port and ipaddr */ 6377ff550d0eSmasputra port = sin6->sin6_port; 6378ff550d0eSmasputra IN6_V4MAPPED_TO_IPADDR(&sin6->sin6_addr, v4dst); 6379ff550d0eSmasputra srcid = sin6->__sin6_src_id; 6380ff550d0eSmasputra break; 6381ff550d0eSmasputra 6382ff550d0eSmasputra case AF_INET: 6383ff550d0eSmasputra sin = (sin_t *)addr; 6384ff550d0eSmasputra if (!OK_32PTR((char *)sin) || addrlen != sizeof (sin_t) || 6385ff550d0eSmasputra sin->sin_family != AF_INET) { 6386ff550d0eSmasputra TRACE_2(TR_FAC_UDP, TR_UDP_WPUT_END, 6387ff550d0eSmasputra "udp_wput_end: q %p (%S)", q, "badaddr"); 6388ff550d0eSmasputra error = EADDRNOTAVAIL; 6389ff550d0eSmasputra goto ud_error; 6390ff550d0eSmasputra } 6391ff550d0eSmasputra /* Extract port and ipaddr */ 6392ff550d0eSmasputra port = sin->sin_port; 6393ff550d0eSmasputra v4dst = sin->sin_addr.s_addr; 6394ff550d0eSmasputra srcid = 0; 6395ff550d0eSmasputra break; 6396ff550d0eSmasputra } 6397ff550d0eSmasputra 6398ff550d0eSmasputra /* 6399ff550d0eSmasputra * If options passed in, feed it for verification and handling 6400ff550d0eSmasputra */ 6401ff550d0eSmasputra if (optlen != 0) { 6402ff550d0eSmasputra ASSERT(DB_TYPE(mp) != M_DATA); 6403ff550d0eSmasputra if (udp_unitdata_opt_process(q, mp, &error, NULL) < 0) { 6404ff550d0eSmasputra /* failure */ 6405ff550d0eSmasputra TRACE_2(TR_FAC_UDP, TR_UDP_WPUT_END, 6406ff550d0eSmasputra "udp_wput_end: q %p (%S)", q, 6407ff550d0eSmasputra "udp_unitdata_opt_process"); 6408ff550d0eSmasputra goto ud_error; 6409ff550d0eSmasputra } 6410ff550d0eSmasputra /* 6411ff550d0eSmasputra * Note: success in processing options. 6412ff550d0eSmasputra * mp option buffer represented by 6413ff550d0eSmasputra * OPT_length/offset now potentially modified 6414ff550d0eSmasputra * and contain option setting results 6415ff550d0eSmasputra */ 6416ff550d0eSmasputra } 6417ff550d0eSmasputra ASSERT(error == 0); 6418ff550d0eSmasputra mp = udp_output_v4(connp, mp, v4dst, port, srcid, &error); 6419ff550d0eSmasputra if (error != 0) { 6420ff550d0eSmasputra ud_error: 6421ff550d0eSmasputra UDP_STAT(udp_out_err_output); 6422ff550d0eSmasputra ASSERT(mp != NULL); 6423ff550d0eSmasputra /* mp is freed by the following routine */ 6424ff550d0eSmasputra udp_ud_err(q, mp, (uchar_t *)addr, (t_scalar_t)addrlen, 6425ff550d0eSmasputra (t_scalar_t)error); 6426ff550d0eSmasputra } 6427ff550d0eSmasputra } 6428ff550d0eSmasputra 6429ff550d0eSmasputra /* ARGSUSED */ 6430ff550d0eSmasputra static void 6431ff550d0eSmasputra udp_output_wrapper(void *arg, mblk_t *mp, void *arg2) 6432ff550d0eSmasputra { 6433ff550d0eSmasputra udp_output((conn_t *)arg, mp, NULL, 0); 6434ff550d0eSmasputra _UDP_EXIT((conn_t *)arg); 6435ff550d0eSmasputra } 6436ff550d0eSmasputra 6437ff550d0eSmasputra static void 6438ff550d0eSmasputra udp_wput(queue_t *q, mblk_t *mp) 6439ff550d0eSmasputra { 6440ff550d0eSmasputra _UDP_ENTER(Q_TO_CONN(UDP_WR(q)), mp, udp_output_wrapper, 6441ff550d0eSmasputra SQTAG_UDP_WPUT); 6442ff550d0eSmasputra } 6443ff550d0eSmasputra 6444ff550d0eSmasputra /* 6445ff550d0eSmasputra * Allocate and prepare a T_UNITDATA_REQ message. 6446ff550d0eSmasputra */ 6447ff550d0eSmasputra static mblk_t * 6448ff550d0eSmasputra udp_tudr_alloc(struct sockaddr *addr, socklen_t addrlen) 6449ff550d0eSmasputra { 6450ff550d0eSmasputra struct T_unitdata_req *tudr; 6451ff550d0eSmasputra mblk_t *mp; 6452ff550d0eSmasputra 6453ff550d0eSmasputra mp = allocb(sizeof (*tudr) + addrlen, BPRI_MED); 6454ff550d0eSmasputra if (mp != NULL) { 6455ff550d0eSmasputra mp->b_wptr += sizeof (*tudr) + addrlen; 6456ff550d0eSmasputra DB_TYPE(mp) = M_PROTO; 6457ff550d0eSmasputra 6458ff550d0eSmasputra tudr = (struct T_unitdata_req *)mp->b_rptr; 6459ff550d0eSmasputra tudr->PRIM_type = T_UNITDATA_REQ; 6460ff550d0eSmasputra tudr->DEST_length = addrlen; 6461ff550d0eSmasputra tudr->DEST_offset = (t_scalar_t)sizeof (*tudr); 6462ff550d0eSmasputra tudr->OPT_length = 0; 6463ff550d0eSmasputra tudr->OPT_offset = 0; 6464ff550d0eSmasputra bcopy(addr, tudr+1, addrlen); 6465ff550d0eSmasputra } 6466ff550d0eSmasputra return (mp); 6467ff550d0eSmasputra } 6468ff550d0eSmasputra 6469ff550d0eSmasputra /* 6470ff550d0eSmasputra * Entry point for sockfs when udp is in "direct sockfs" mode. This mode 6471ff550d0eSmasputra * is valid when we are directly beneath the stream head, and thus sockfs 6472ff550d0eSmasputra * is able to bypass STREAMS and directly call us, passing along the sockaddr 6473ff550d0eSmasputra * structure without the cumbersome T_UNITDATA_REQ interface. Note that 6474ff550d0eSmasputra * this is done for both connected and non-connected endpoint. 6475ff550d0eSmasputra */ 6476ff550d0eSmasputra void 6477ff550d0eSmasputra udp_wput_data(queue_t *q, mblk_t *mp, struct sockaddr *addr, socklen_t addrlen) 6478ff550d0eSmasputra { 6479ff550d0eSmasputra conn_t *connp; 6480ff550d0eSmasputra udp_t *udp; 6481ff550d0eSmasputra 6482ff550d0eSmasputra q = UDP_WR(q); 6483ff550d0eSmasputra connp = Q_TO_CONN(q); 6484ff550d0eSmasputra udp = connp->conn_udp; 6485ff550d0eSmasputra 6486ff550d0eSmasputra /* udpsockfs should only send down M_DATA for this entry point */ 6487ff550d0eSmasputra ASSERT(DB_TYPE(mp) == M_DATA); 6488ff550d0eSmasputra 6489ff550d0eSmasputra mutex_enter(&connp->conn_lock); 6490ff550d0eSmasputra UDP_MODE_ASSERTIONS(udp, UDP_ENTER); 6491ff550d0eSmasputra 6492ff550d0eSmasputra if (udp->udp_mode != UDP_MT_HOT) { 6493ff550d0eSmasputra /* 6494ff550d0eSmasputra * We can't enter this conn right away because another 6495ff550d0eSmasputra * thread is currently executing as writer; therefore we 6496ff550d0eSmasputra * need to deposit the message into the squeue to be 6497ff550d0eSmasputra * drained later. If a socket address is present, we 6498ff550d0eSmasputra * need to create a T_UNITDATA_REQ message as placeholder. 6499ff550d0eSmasputra */ 6500ff550d0eSmasputra if (addr != NULL && addrlen != 0) { 6501ff550d0eSmasputra mblk_t *tudr_mp = udp_tudr_alloc(addr, addrlen); 6502ff550d0eSmasputra 6503ff550d0eSmasputra if (tudr_mp == NULL) { 6504ff550d0eSmasputra mutex_exit(&connp->conn_lock); 6505ff550d0eSmasputra BUMP_MIB(&udp_mib, udpOutErrors); 6506ff550d0eSmasputra UDP_STAT(udp_out_err_tudr); 6507ff550d0eSmasputra freemsg(mp); 6508ff550d0eSmasputra return; 6509ff550d0eSmasputra } 6510ff550d0eSmasputra /* Tag the packet with T_UNITDATA_REQ */ 6511ff550d0eSmasputra tudr_mp->b_cont = mp; 6512ff550d0eSmasputra mp = tudr_mp; 6513ff550d0eSmasputra } 6514ff550d0eSmasputra mutex_exit(&connp->conn_lock); 6515ff550d0eSmasputra udp_enter(connp, mp, udp_output_wrapper, SQTAG_UDP_WPUT); 6516ff550d0eSmasputra return; 6517ff550d0eSmasputra } 6518ff550d0eSmasputra 6519ff550d0eSmasputra /* We can execute as reader right away. */ 6520ff550d0eSmasputra UDP_READERS_INCREF(udp); 6521ff550d0eSmasputra mutex_exit(&connp->conn_lock); 6522ff550d0eSmasputra 6523ff550d0eSmasputra udp_output(connp, mp, addr, addrlen); 6524ff550d0eSmasputra 6525ff550d0eSmasputra mutex_enter(&connp->conn_lock); 6526ff550d0eSmasputra UDP_MODE_ASSERTIONS(udp, UDP_EXIT); 6527ff550d0eSmasputra UDP_READERS_DECREF(udp); 6528ff550d0eSmasputra mutex_exit(&connp->conn_lock); 6529ff550d0eSmasputra } 6530ff550d0eSmasputra 6531ff550d0eSmasputra /* 6532ff550d0eSmasputra * udp_output_v6(): 6533ff550d0eSmasputra * Assumes that udp_wput did some sanity checking on the destination 6534ff550d0eSmasputra * address. 6535ff550d0eSmasputra */ 6536ff550d0eSmasputra static mblk_t * 6537ff550d0eSmasputra udp_output_v6(conn_t *connp, mblk_t *mp, sin6_t *sin6, t_scalar_t tudr_optlen, 6538ff550d0eSmasputra int *error) 6539ff550d0eSmasputra { 6540ff550d0eSmasputra ip6_t *ip6h; 6541ff550d0eSmasputra ip6i_t *ip6i; /* mp1->b_rptr even if no ip6i_t */ 6542ff550d0eSmasputra mblk_t *mp1 = (DB_TYPE(mp) == M_DATA ? mp : mp->b_cont); 6543ff550d0eSmasputra mblk_t *mp2; 6544ff550d0eSmasputra int udp_ip_hdr_len = IPV6_HDR_LEN + UDPH_SIZE; 6545ff550d0eSmasputra size_t ip_len; 6546ff550d0eSmasputra udpha_t *udph; 6547ff550d0eSmasputra udp_t *udp = connp->conn_udp; 6548ff550d0eSmasputra queue_t *q = connp->conn_wq; 6549ff550d0eSmasputra ip6_pkt_t ipp_s; /* For ancillary data options */ 6550ff550d0eSmasputra ip6_pkt_t *ipp = &ipp_s; 6551ff550d0eSmasputra ip6_pkt_t *tipp; /* temporary ipp */ 6552ff550d0eSmasputra uint32_t csum = 0; 6553ff550d0eSmasputra uint_t ignore = 0; 6554ff550d0eSmasputra uint_t option_exists = 0, is_sticky = 0; 6555ff550d0eSmasputra uint8_t *cp; 6556ff550d0eSmasputra uint8_t *nxthdr_ptr; 6557ff550d0eSmasputra 6558ff550d0eSmasputra *error = 0; 6559ff550d0eSmasputra 6560ff550d0eSmasputra /* mp1 points to the M_DATA mblk carrying the packet */ 6561ff550d0eSmasputra ASSERT(mp1 != NULL && DB_TYPE(mp1) == M_DATA); 6562ff550d0eSmasputra ASSERT(tudr_optlen == 0 || DB_TYPE(mp) != M_DATA); 65637c478bd9Sstevel@tonic-gate 65647c478bd9Sstevel@tonic-gate /* 65657c478bd9Sstevel@tonic-gate * If the local address is a mapped address return 65667c478bd9Sstevel@tonic-gate * an error. 65677c478bd9Sstevel@tonic-gate * It would be possible to send an IPv6 packet but the 65687c478bd9Sstevel@tonic-gate * response would never make it back to the application 65697c478bd9Sstevel@tonic-gate * since it is bound to a mapped address. 65707c478bd9Sstevel@tonic-gate */ 65717c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_V4MAPPED(&udp->udp_v6src)) { 6572ff550d0eSmasputra *error = EADDRNOTAVAIL; 6573ff550d0eSmasputra goto done; 65747c478bd9Sstevel@tonic-gate } 65757c478bd9Sstevel@tonic-gate 65767c478bd9Sstevel@tonic-gate ipp->ipp_fields = 0; 65777c478bd9Sstevel@tonic-gate ipp->ipp_sticky_ignored = 0; 65787c478bd9Sstevel@tonic-gate 65797c478bd9Sstevel@tonic-gate /* 65807c478bd9Sstevel@tonic-gate * If TPI options passed in, feed it for verification and handling 65817c478bd9Sstevel@tonic-gate */ 65827c478bd9Sstevel@tonic-gate if (tudr_optlen != 0) { 6583ff550d0eSmasputra if (udp_unitdata_opt_process(q, mp, error, (void *)ipp) < 0) { 65847c478bd9Sstevel@tonic-gate /* failure */ 6585ff550d0eSmasputra goto done; 65867c478bd9Sstevel@tonic-gate } 65877c478bd9Sstevel@tonic-gate ignore = ipp->ipp_sticky_ignored; 6588ff550d0eSmasputra ASSERT(*error == 0); 65897c478bd9Sstevel@tonic-gate } 65907c478bd9Sstevel@tonic-gate 65917c478bd9Sstevel@tonic-gate if (sin6->sin6_scope_id != 0 && 65927c478bd9Sstevel@tonic-gate IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { 65937c478bd9Sstevel@tonic-gate /* 65947c478bd9Sstevel@tonic-gate * IPPF_SCOPE_ID is special. It's neither a sticky 65957c478bd9Sstevel@tonic-gate * option nor ancillary data. It needs to be 65967c478bd9Sstevel@tonic-gate * explicitly set in options_exists. 65977c478bd9Sstevel@tonic-gate */ 65987c478bd9Sstevel@tonic-gate option_exists |= IPPF_SCOPE_ID; 65997c478bd9Sstevel@tonic-gate } 66007c478bd9Sstevel@tonic-gate 6601ff550d0eSmasputra if ((udp->udp_sticky_ipp.ipp_fields == 0) && (ipp->ipp_fields == 0)) { 66027c478bd9Sstevel@tonic-gate /* No sticky options nor ancillary data. */ 66037c478bd9Sstevel@tonic-gate goto no_options; 66047c478bd9Sstevel@tonic-gate } 66057c478bd9Sstevel@tonic-gate 66067c478bd9Sstevel@tonic-gate /* 66077c478bd9Sstevel@tonic-gate * Go through the options figuring out where each is going to 66087c478bd9Sstevel@tonic-gate * come from and build two masks. The first mask indicates if 66097c478bd9Sstevel@tonic-gate * the option exists at all. The second mask indicates if the 66107c478bd9Sstevel@tonic-gate * option is sticky or ancillary. 66117c478bd9Sstevel@tonic-gate */ 66127c478bd9Sstevel@tonic-gate if (!(ignore & IPPF_HOPOPTS)) { 66137c478bd9Sstevel@tonic-gate if (ipp->ipp_fields & IPPF_HOPOPTS) { 66147c478bd9Sstevel@tonic-gate option_exists |= IPPF_HOPOPTS; 66157c478bd9Sstevel@tonic-gate udp_ip_hdr_len += ipp->ipp_hopoptslen; 66167c478bd9Sstevel@tonic-gate } else if (udp->udp_sticky_ipp.ipp_fields & IPPF_HOPOPTS) { 66177c478bd9Sstevel@tonic-gate option_exists |= IPPF_HOPOPTS; 66187c478bd9Sstevel@tonic-gate is_sticky |= IPPF_HOPOPTS; 66197c478bd9Sstevel@tonic-gate udp_ip_hdr_len += udp->udp_sticky_ipp.ipp_hopoptslen; 66207c478bd9Sstevel@tonic-gate } 66217c478bd9Sstevel@tonic-gate } 66227c478bd9Sstevel@tonic-gate 66237c478bd9Sstevel@tonic-gate if (!(ignore & IPPF_RTHDR)) { 66247c478bd9Sstevel@tonic-gate if (ipp->ipp_fields & IPPF_RTHDR) { 66257c478bd9Sstevel@tonic-gate option_exists |= IPPF_RTHDR; 66267c478bd9Sstevel@tonic-gate udp_ip_hdr_len += ipp->ipp_rthdrlen; 66277c478bd9Sstevel@tonic-gate } else if (udp->udp_sticky_ipp.ipp_fields & IPPF_RTHDR) { 66287c478bd9Sstevel@tonic-gate option_exists |= IPPF_RTHDR; 66297c478bd9Sstevel@tonic-gate is_sticky |= IPPF_RTHDR; 66307c478bd9Sstevel@tonic-gate udp_ip_hdr_len += udp->udp_sticky_ipp.ipp_rthdrlen; 66317c478bd9Sstevel@tonic-gate } 66327c478bd9Sstevel@tonic-gate } 66337c478bd9Sstevel@tonic-gate 66347c478bd9Sstevel@tonic-gate if (!(ignore & IPPF_RTDSTOPTS) && (option_exists & IPPF_RTHDR)) { 66357c478bd9Sstevel@tonic-gate if (ipp->ipp_fields & IPPF_RTDSTOPTS) { 66367c478bd9Sstevel@tonic-gate option_exists |= IPPF_RTDSTOPTS; 66377c478bd9Sstevel@tonic-gate udp_ip_hdr_len += ipp->ipp_rtdstoptslen; 66387c478bd9Sstevel@tonic-gate } else if (udp->udp_sticky_ipp.ipp_fields & IPPF_RTDSTOPTS) { 66397c478bd9Sstevel@tonic-gate option_exists |= IPPF_RTDSTOPTS; 66407c478bd9Sstevel@tonic-gate is_sticky |= IPPF_RTDSTOPTS; 66417c478bd9Sstevel@tonic-gate udp_ip_hdr_len += udp->udp_sticky_ipp.ipp_rtdstoptslen; 66427c478bd9Sstevel@tonic-gate } 66437c478bd9Sstevel@tonic-gate } 66447c478bd9Sstevel@tonic-gate 66457c478bd9Sstevel@tonic-gate if (!(ignore & IPPF_DSTOPTS)) { 66467c478bd9Sstevel@tonic-gate if (ipp->ipp_fields & IPPF_DSTOPTS) { 66477c478bd9Sstevel@tonic-gate option_exists |= IPPF_DSTOPTS; 66487c478bd9Sstevel@tonic-gate udp_ip_hdr_len += ipp->ipp_dstoptslen; 66497c478bd9Sstevel@tonic-gate } else if (udp->udp_sticky_ipp.ipp_fields & IPPF_DSTOPTS) { 66507c478bd9Sstevel@tonic-gate option_exists |= IPPF_DSTOPTS; 66517c478bd9Sstevel@tonic-gate is_sticky |= IPPF_DSTOPTS; 66527c478bd9Sstevel@tonic-gate udp_ip_hdr_len += udp->udp_sticky_ipp.ipp_dstoptslen; 66537c478bd9Sstevel@tonic-gate } 66547c478bd9Sstevel@tonic-gate } 66557c478bd9Sstevel@tonic-gate 66567c478bd9Sstevel@tonic-gate if (!(ignore & IPPF_IFINDEX)) { 66577c478bd9Sstevel@tonic-gate if (ipp->ipp_fields & IPPF_IFINDEX) { 66587c478bd9Sstevel@tonic-gate option_exists |= IPPF_IFINDEX; 66597c478bd9Sstevel@tonic-gate } else if (udp->udp_sticky_ipp.ipp_fields & IPPF_IFINDEX) { 66607c478bd9Sstevel@tonic-gate option_exists |= IPPF_IFINDEX; 66617c478bd9Sstevel@tonic-gate is_sticky |= IPPF_IFINDEX; 66627c478bd9Sstevel@tonic-gate } 66637c478bd9Sstevel@tonic-gate } 66647c478bd9Sstevel@tonic-gate 66657c478bd9Sstevel@tonic-gate if (!(ignore & IPPF_ADDR)) { 66667c478bd9Sstevel@tonic-gate if (ipp->ipp_fields & IPPF_ADDR) { 66677c478bd9Sstevel@tonic-gate option_exists |= IPPF_ADDR; 66687c478bd9Sstevel@tonic-gate } else if (udp->udp_sticky_ipp.ipp_fields & IPPF_ADDR) { 66697c478bd9Sstevel@tonic-gate option_exists |= IPPF_ADDR; 66707c478bd9Sstevel@tonic-gate is_sticky |= IPPF_ADDR; 66717c478bd9Sstevel@tonic-gate } 66727c478bd9Sstevel@tonic-gate } 66737c478bd9Sstevel@tonic-gate 66747c478bd9Sstevel@tonic-gate if (!(ignore & IPPF_DONTFRAG)) { 66757c478bd9Sstevel@tonic-gate if (ipp->ipp_fields & IPPF_DONTFRAG) { 66767c478bd9Sstevel@tonic-gate option_exists |= IPPF_DONTFRAG; 66777c478bd9Sstevel@tonic-gate } else if (udp->udp_sticky_ipp.ipp_fields & IPPF_DONTFRAG) { 66787c478bd9Sstevel@tonic-gate option_exists |= IPPF_DONTFRAG; 66797c478bd9Sstevel@tonic-gate is_sticky |= IPPF_DONTFRAG; 66807c478bd9Sstevel@tonic-gate } 66817c478bd9Sstevel@tonic-gate } 66827c478bd9Sstevel@tonic-gate 66837c478bd9Sstevel@tonic-gate if (!(ignore & IPPF_USE_MIN_MTU)) { 66847c478bd9Sstevel@tonic-gate if (ipp->ipp_fields & IPPF_USE_MIN_MTU) { 66857c478bd9Sstevel@tonic-gate option_exists |= IPPF_USE_MIN_MTU; 6686ff550d0eSmasputra } else if (udp->udp_sticky_ipp.ipp_fields & 6687ff550d0eSmasputra IPPF_USE_MIN_MTU) { 66887c478bd9Sstevel@tonic-gate option_exists |= IPPF_USE_MIN_MTU; 66897c478bd9Sstevel@tonic-gate is_sticky |= IPPF_USE_MIN_MTU; 66907c478bd9Sstevel@tonic-gate } 66917c478bd9Sstevel@tonic-gate } 66927c478bd9Sstevel@tonic-gate 6693b3d0fa4fSseb if (!(ignore & IPPF_HOPLIMIT) && (ipp->ipp_fields & IPPF_HOPLIMIT)) 6694b3d0fa4fSseb option_exists |= IPPF_HOPLIMIT; 6695b3d0fa4fSseb /* IPV6_HOPLIMIT can never be sticky */ 6696b3d0fa4fSseb ASSERT(!(udp->udp_sticky_ipp.ipp_fields & IPPF_HOPLIMIT)); 6697b3d0fa4fSseb 6698b3d0fa4fSseb if (!(ignore & IPPF_UNICAST_HOPS) && 6699b3d0fa4fSseb (udp->udp_sticky_ipp.ipp_fields & IPPF_UNICAST_HOPS)) { 6700b3d0fa4fSseb option_exists |= IPPF_UNICAST_HOPS; 6701b3d0fa4fSseb is_sticky |= IPPF_UNICAST_HOPS; 6702b3d0fa4fSseb } 6703b3d0fa4fSseb 6704b3d0fa4fSseb if (!(ignore & IPPF_MULTICAST_HOPS) && 6705b3d0fa4fSseb (udp->udp_sticky_ipp.ipp_fields & IPPF_MULTICAST_HOPS)) { 6706b3d0fa4fSseb option_exists |= IPPF_MULTICAST_HOPS; 6707b3d0fa4fSseb is_sticky |= IPPF_MULTICAST_HOPS; 67087c478bd9Sstevel@tonic-gate } 67097c478bd9Sstevel@tonic-gate 67107c478bd9Sstevel@tonic-gate if (!(ignore & IPPF_TCLASS)) { 67117c478bd9Sstevel@tonic-gate if (ipp->ipp_fields & IPPF_TCLASS) { 67127c478bd9Sstevel@tonic-gate option_exists |= IPPF_TCLASS; 67137c478bd9Sstevel@tonic-gate } else if (udp->udp_sticky_ipp.ipp_fields & IPPF_TCLASS) { 67147c478bd9Sstevel@tonic-gate option_exists |= IPPF_TCLASS; 67157c478bd9Sstevel@tonic-gate is_sticky |= IPPF_TCLASS; 67167c478bd9Sstevel@tonic-gate } 67177c478bd9Sstevel@tonic-gate } 67187c478bd9Sstevel@tonic-gate 67197c478bd9Sstevel@tonic-gate no_options: 67207c478bd9Sstevel@tonic-gate 67217c478bd9Sstevel@tonic-gate /* 67227c478bd9Sstevel@tonic-gate * If any options carried in the ip6i_t were specified, we 67237c478bd9Sstevel@tonic-gate * need to account for the ip6i_t in the data we'll be sending 67247c478bd9Sstevel@tonic-gate * down. 67257c478bd9Sstevel@tonic-gate */ 67267c478bd9Sstevel@tonic-gate if (option_exists & IPPF_HAS_IP6I) 67277c478bd9Sstevel@tonic-gate udp_ip_hdr_len += sizeof (ip6i_t); 67287c478bd9Sstevel@tonic-gate 67297c478bd9Sstevel@tonic-gate /* check/fix buffer config, setup pointers into it */ 67307c478bd9Sstevel@tonic-gate ip6h = (ip6_t *)&mp1->b_rptr[-udp_ip_hdr_len]; 6731ff550d0eSmasputra if (DB_REF(mp1) != 1 || ((unsigned char *)ip6h < DB_BASE(mp1)) || 67327c478bd9Sstevel@tonic-gate !OK_32PTR(ip6h)) { 67337c478bd9Sstevel@tonic-gate /* Try to get everything in a single mblk next time */ 67347c478bd9Sstevel@tonic-gate if (udp_ip_hdr_len > udp->udp_max_hdr_len) { 67357c478bd9Sstevel@tonic-gate udp->udp_max_hdr_len = udp_ip_hdr_len; 6736ff550d0eSmasputra (void) mi_set_sth_wroff(UDP_RD(q), 67377c478bd9Sstevel@tonic-gate udp->udp_max_hdr_len + udp_wroff_extra); 67387c478bd9Sstevel@tonic-gate } 6739ff550d0eSmasputra mp2 = allocb(udp_ip_hdr_len + udp_wroff_extra, BPRI_LO); 6740ff550d0eSmasputra if (mp2 == NULL) { 6741ff550d0eSmasputra *error = ENOMEM; 6742ff550d0eSmasputra goto done; 67437c478bd9Sstevel@tonic-gate } 6744ff550d0eSmasputra mp2->b_wptr = DB_LIM(mp2); 6745ff550d0eSmasputra mp2->b_cont = mp1; 6746ff550d0eSmasputra mp1 = mp2; 6747ff550d0eSmasputra if (DB_TYPE(mp) != M_DATA) 6748ff550d0eSmasputra mp->b_cont = mp1; 6749ff550d0eSmasputra else 6750ff550d0eSmasputra mp = mp1; 6751ff550d0eSmasputra 67527c478bd9Sstevel@tonic-gate ip6h = (ip6_t *)(mp1->b_wptr - udp_ip_hdr_len); 67537c478bd9Sstevel@tonic-gate } 67547c478bd9Sstevel@tonic-gate mp1->b_rptr = (unsigned char *)ip6h; 67557c478bd9Sstevel@tonic-gate ip6i = (ip6i_t *)ip6h; 67567c478bd9Sstevel@tonic-gate 67577c478bd9Sstevel@tonic-gate #define ANCIL_OR_STICKY_PTR(f) ((is_sticky & f) ? &udp->udp_sticky_ipp : ipp) 67587c478bd9Sstevel@tonic-gate if (option_exists & IPPF_HAS_IP6I) { 67597c478bd9Sstevel@tonic-gate ip6h = (ip6_t *)&ip6i[1]; 67607c478bd9Sstevel@tonic-gate ip6i->ip6i_flags = 0; 67617c478bd9Sstevel@tonic-gate ip6i->ip6i_vcf = IPV6_DEFAULT_VERS_AND_FLOW; 67627c478bd9Sstevel@tonic-gate 67637c478bd9Sstevel@tonic-gate /* sin6_scope_id takes precendence over IPPF_IFINDEX */ 67647c478bd9Sstevel@tonic-gate if (option_exists & IPPF_SCOPE_ID) { 67657c478bd9Sstevel@tonic-gate ip6i->ip6i_flags |= IP6I_IFINDEX; 67667c478bd9Sstevel@tonic-gate ip6i->ip6i_ifindex = sin6->sin6_scope_id; 67677c478bd9Sstevel@tonic-gate } else if (option_exists & IPPF_IFINDEX) { 67687c478bd9Sstevel@tonic-gate tipp = ANCIL_OR_STICKY_PTR(IPPF_IFINDEX); 67697c478bd9Sstevel@tonic-gate ASSERT(tipp->ipp_ifindex != 0); 67707c478bd9Sstevel@tonic-gate ip6i->ip6i_flags |= IP6I_IFINDEX; 67717c478bd9Sstevel@tonic-gate ip6i->ip6i_ifindex = tipp->ipp_ifindex; 67727c478bd9Sstevel@tonic-gate } 67737c478bd9Sstevel@tonic-gate 67747c478bd9Sstevel@tonic-gate if (option_exists & IPPF_ADDR) { 67757c478bd9Sstevel@tonic-gate /* 67767c478bd9Sstevel@tonic-gate * Enable per-packet source address verification if 67777c478bd9Sstevel@tonic-gate * IPV6_PKTINFO specified the source address. 67787c478bd9Sstevel@tonic-gate * ip6_src is set in the transport's _wput function. 67797c478bd9Sstevel@tonic-gate */ 67807c478bd9Sstevel@tonic-gate ip6i->ip6i_flags |= IP6I_VERIFY_SRC; 67817c478bd9Sstevel@tonic-gate } 67827c478bd9Sstevel@tonic-gate 67837c478bd9Sstevel@tonic-gate if (option_exists & IPPF_DONTFRAG) { 67847c478bd9Sstevel@tonic-gate ip6i->ip6i_flags |= IP6I_DONTFRAG; 67857c478bd9Sstevel@tonic-gate } 67867c478bd9Sstevel@tonic-gate 67877c478bd9Sstevel@tonic-gate if (option_exists & IPPF_USE_MIN_MTU) { 67887c478bd9Sstevel@tonic-gate ip6i->ip6i_flags = IP6I_API_USE_MIN_MTU( 67897c478bd9Sstevel@tonic-gate ip6i->ip6i_flags, ipp->ipp_use_min_mtu); 67907c478bd9Sstevel@tonic-gate } 67917c478bd9Sstevel@tonic-gate 67927c478bd9Sstevel@tonic-gate if (option_exists & IPPF_NEXTHOP) { 67937c478bd9Sstevel@tonic-gate tipp = ANCIL_OR_STICKY_PTR(IPPF_NEXTHOP); 67947c478bd9Sstevel@tonic-gate ASSERT(!IN6_IS_ADDR_UNSPECIFIED(&tipp->ipp_nexthop)); 67957c478bd9Sstevel@tonic-gate ip6i->ip6i_flags |= IP6I_NEXTHOP; 67967c478bd9Sstevel@tonic-gate ip6i->ip6i_nexthop = tipp->ipp_nexthop; 67977c478bd9Sstevel@tonic-gate } 67987c478bd9Sstevel@tonic-gate 67997c478bd9Sstevel@tonic-gate /* 68007c478bd9Sstevel@tonic-gate * tell IP this is an ip6i_t private header 68017c478bd9Sstevel@tonic-gate */ 68027c478bd9Sstevel@tonic-gate ip6i->ip6i_nxt = IPPROTO_RAW; 68037c478bd9Sstevel@tonic-gate } 68047c478bd9Sstevel@tonic-gate 68057c478bd9Sstevel@tonic-gate /* Initialize IPv6 header */ 68067c478bd9Sstevel@tonic-gate ip6h->ip6_vcf = IPV6_DEFAULT_VERS_AND_FLOW; 68077c478bd9Sstevel@tonic-gate bzero(&ip6h->ip6_src, sizeof (ip6h->ip6_src)); 68087c478bd9Sstevel@tonic-gate 6809b3d0fa4fSseb /* Set the hoplimit of the outgoing packet. */ 68107c478bd9Sstevel@tonic-gate if (option_exists & IPPF_HOPLIMIT) { 6811b3d0fa4fSseb /* IPV6_HOPLIMIT ancillary data overrides all other settings. */ 6812b3d0fa4fSseb ip6h->ip6_hops = ipp->ipp_hoplimit; 68137c478bd9Sstevel@tonic-gate ip6i->ip6i_flags |= IP6I_HOPLIMIT; 6814b3d0fa4fSseb } else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { 6815b3d0fa4fSseb ip6h->ip6_hops = udp->udp_multicast_ttl; 6816b3d0fa4fSseb if (option_exists & IPPF_MULTICAST_HOPS) 6817b3d0fa4fSseb ip6i->ip6i_flags |= IP6I_HOPLIMIT; 68187c478bd9Sstevel@tonic-gate } else { 68197c478bd9Sstevel@tonic-gate ip6h->ip6_hops = udp->udp_ttl; 6820b3d0fa4fSseb if (option_exists & IPPF_UNICAST_HOPS) 6821b3d0fa4fSseb ip6i->ip6i_flags |= IP6I_HOPLIMIT; 68227c478bd9Sstevel@tonic-gate } 68237c478bd9Sstevel@tonic-gate 68247c478bd9Sstevel@tonic-gate if (option_exists & IPPF_ADDR) { 68257c478bd9Sstevel@tonic-gate tipp = ANCIL_OR_STICKY_PTR(IPPF_ADDR); 68267c478bd9Sstevel@tonic-gate ASSERT(!IN6_IS_ADDR_UNSPECIFIED(&tipp->ipp_addr)); 68277c478bd9Sstevel@tonic-gate ip6h->ip6_src = tipp->ipp_addr; 68287c478bd9Sstevel@tonic-gate } else { 68297c478bd9Sstevel@tonic-gate /* 68307c478bd9Sstevel@tonic-gate * The source address was not set using IPV6_PKTINFO. 68317c478bd9Sstevel@tonic-gate * First look at the bound source. 68327c478bd9Sstevel@tonic-gate * If unspecified fallback to __sin6_src_id. 68337c478bd9Sstevel@tonic-gate */ 68347c478bd9Sstevel@tonic-gate ip6h->ip6_src = udp->udp_v6src; 68357c478bd9Sstevel@tonic-gate if (sin6->__sin6_src_id != 0 && 68367c478bd9Sstevel@tonic-gate IN6_IS_ADDR_UNSPECIFIED(&ip6h->ip6_src)) { 68377c478bd9Sstevel@tonic-gate ip_srcid_find_id(sin6->__sin6_src_id, 6838ff550d0eSmasputra &ip6h->ip6_src, connp->conn_zoneid); 68397c478bd9Sstevel@tonic-gate } 68407c478bd9Sstevel@tonic-gate } 68417c478bd9Sstevel@tonic-gate 68427c478bd9Sstevel@tonic-gate nxthdr_ptr = (uint8_t *)&ip6h->ip6_nxt; 68437c478bd9Sstevel@tonic-gate cp = (uint8_t *)&ip6h[1]; 68447c478bd9Sstevel@tonic-gate 68457c478bd9Sstevel@tonic-gate /* 68467c478bd9Sstevel@tonic-gate * Here's where we have to start stringing together 68477c478bd9Sstevel@tonic-gate * any extension headers in the right order: 68487c478bd9Sstevel@tonic-gate * Hop-by-hop, destination, routing, and final destination opts. 68497c478bd9Sstevel@tonic-gate */ 68507c478bd9Sstevel@tonic-gate if (option_exists & IPPF_HOPOPTS) { 68517c478bd9Sstevel@tonic-gate /* Hop-by-hop options */ 68527c478bd9Sstevel@tonic-gate ip6_hbh_t *hbh = (ip6_hbh_t *)cp; 68537c478bd9Sstevel@tonic-gate tipp = ANCIL_OR_STICKY_PTR(IPPF_HOPOPTS); 68547c478bd9Sstevel@tonic-gate 68557c478bd9Sstevel@tonic-gate *nxthdr_ptr = IPPROTO_HOPOPTS; 68567c478bd9Sstevel@tonic-gate nxthdr_ptr = &hbh->ip6h_nxt; 68577c478bd9Sstevel@tonic-gate 68587c478bd9Sstevel@tonic-gate bcopy(tipp->ipp_hopopts, cp, tipp->ipp_hopoptslen); 68597c478bd9Sstevel@tonic-gate cp += tipp->ipp_hopoptslen; 68607c478bd9Sstevel@tonic-gate } 68617c478bd9Sstevel@tonic-gate /* 68627c478bd9Sstevel@tonic-gate * En-route destination options 68637c478bd9Sstevel@tonic-gate * Only do them if there's a routing header as well 68647c478bd9Sstevel@tonic-gate */ 68657c478bd9Sstevel@tonic-gate if (option_exists & IPPF_RTDSTOPTS) { 68667c478bd9Sstevel@tonic-gate ip6_dest_t *dst = (ip6_dest_t *)cp; 68677c478bd9Sstevel@tonic-gate tipp = ANCIL_OR_STICKY_PTR(IPPF_RTDSTOPTS); 68687c478bd9Sstevel@tonic-gate 68697c478bd9Sstevel@tonic-gate *nxthdr_ptr = IPPROTO_DSTOPTS; 68707c478bd9Sstevel@tonic-gate nxthdr_ptr = &dst->ip6d_nxt; 68717c478bd9Sstevel@tonic-gate 68727c478bd9Sstevel@tonic-gate bcopy(tipp->ipp_rtdstopts, cp, tipp->ipp_rtdstoptslen); 68737c478bd9Sstevel@tonic-gate cp += tipp->ipp_rtdstoptslen; 68747c478bd9Sstevel@tonic-gate } 68757c478bd9Sstevel@tonic-gate /* 68767c478bd9Sstevel@tonic-gate * Routing header next 68777c478bd9Sstevel@tonic-gate */ 68787c478bd9Sstevel@tonic-gate if (option_exists & IPPF_RTHDR) { 68797c478bd9Sstevel@tonic-gate ip6_rthdr_t *rt = (ip6_rthdr_t *)cp; 68807c478bd9Sstevel@tonic-gate tipp = ANCIL_OR_STICKY_PTR(IPPF_RTHDR); 68817c478bd9Sstevel@tonic-gate 68827c478bd9Sstevel@tonic-gate *nxthdr_ptr = IPPROTO_ROUTING; 68837c478bd9Sstevel@tonic-gate nxthdr_ptr = &rt->ip6r_nxt; 68847c478bd9Sstevel@tonic-gate 68857c478bd9Sstevel@tonic-gate bcopy(tipp->ipp_rthdr, cp, tipp->ipp_rthdrlen); 68867c478bd9Sstevel@tonic-gate cp += tipp->ipp_rthdrlen; 68877c478bd9Sstevel@tonic-gate } 68887c478bd9Sstevel@tonic-gate /* 68897c478bd9Sstevel@tonic-gate * Do ultimate destination options 68907c478bd9Sstevel@tonic-gate */ 68917c478bd9Sstevel@tonic-gate if (option_exists & IPPF_DSTOPTS) { 68927c478bd9Sstevel@tonic-gate ip6_dest_t *dest = (ip6_dest_t *)cp; 68937c478bd9Sstevel@tonic-gate tipp = ANCIL_OR_STICKY_PTR(IPPF_DSTOPTS); 68947c478bd9Sstevel@tonic-gate 68957c478bd9Sstevel@tonic-gate *nxthdr_ptr = IPPROTO_DSTOPTS; 68967c478bd9Sstevel@tonic-gate nxthdr_ptr = &dest->ip6d_nxt; 68977c478bd9Sstevel@tonic-gate 68987c478bd9Sstevel@tonic-gate bcopy(tipp->ipp_dstopts, cp, tipp->ipp_dstoptslen); 68997c478bd9Sstevel@tonic-gate cp += tipp->ipp_dstoptslen; 69007c478bd9Sstevel@tonic-gate } 69017c478bd9Sstevel@tonic-gate /* 69027c478bd9Sstevel@tonic-gate * Now set the last header pointer to the proto passed in 69037c478bd9Sstevel@tonic-gate */ 69047c478bd9Sstevel@tonic-gate ASSERT((int)(cp - (uint8_t *)ip6i) == (udp_ip_hdr_len - UDPH_SIZE)); 69057c478bd9Sstevel@tonic-gate *nxthdr_ptr = IPPROTO_UDP; 69067c478bd9Sstevel@tonic-gate 69077c478bd9Sstevel@tonic-gate /* Update UDP header */ 69087c478bd9Sstevel@tonic-gate udph = (udpha_t *)((uchar_t *)ip6i + udp_ip_hdr_len - UDPH_SIZE); 69097c478bd9Sstevel@tonic-gate udph->uha_dst_port = sin6->sin6_port; 69107c478bd9Sstevel@tonic-gate udph->uha_src_port = udp->udp_port; 69117c478bd9Sstevel@tonic-gate 69127c478bd9Sstevel@tonic-gate /* 69137c478bd9Sstevel@tonic-gate * Copy in the destination address 69147c478bd9Sstevel@tonic-gate */ 69157c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) 69167c478bd9Sstevel@tonic-gate ip6h->ip6_dst = ipv6_loopback; 69177c478bd9Sstevel@tonic-gate else 69187c478bd9Sstevel@tonic-gate ip6h->ip6_dst = sin6->sin6_addr; 69197c478bd9Sstevel@tonic-gate 69207c478bd9Sstevel@tonic-gate ip6h->ip6_vcf = 69217c478bd9Sstevel@tonic-gate (IPV6_DEFAULT_VERS_AND_FLOW & IPV6_VERS_AND_FLOW_MASK) | 69227c478bd9Sstevel@tonic-gate (sin6->sin6_flowinfo & ~IPV6_VERS_AND_FLOW_MASK); 69237c478bd9Sstevel@tonic-gate 69247c478bd9Sstevel@tonic-gate if (option_exists & IPPF_TCLASS) { 69257c478bd9Sstevel@tonic-gate tipp = ANCIL_OR_STICKY_PTR(IPPF_TCLASS); 69267c478bd9Sstevel@tonic-gate ip6h->ip6_vcf = IPV6_TCLASS_FLOW(ip6h->ip6_vcf, 69277c478bd9Sstevel@tonic-gate tipp->ipp_tclass); 69287c478bd9Sstevel@tonic-gate } 69297c478bd9Sstevel@tonic-gate 69307c478bd9Sstevel@tonic-gate if (option_exists & IPPF_RTHDR) { 69317c478bd9Sstevel@tonic-gate ip6_rthdr_t *rth; 69327c478bd9Sstevel@tonic-gate 69337c478bd9Sstevel@tonic-gate /* 69347c478bd9Sstevel@tonic-gate * Perform any processing needed for source routing. 69357c478bd9Sstevel@tonic-gate * We know that all extension headers will be in the same mblk 69367c478bd9Sstevel@tonic-gate * as the IPv6 header. 69377c478bd9Sstevel@tonic-gate */ 69387c478bd9Sstevel@tonic-gate rth = ip_find_rthdr_v6(ip6h, mp1->b_wptr); 69397c478bd9Sstevel@tonic-gate if (rth != NULL && rth->ip6r_segleft != 0) { 69407c478bd9Sstevel@tonic-gate if (rth->ip6r_type != IPV6_RTHDR_TYPE_0) { 69417c478bd9Sstevel@tonic-gate /* 69427c478bd9Sstevel@tonic-gate * Drop packet - only support Type 0 routing. 69437c478bd9Sstevel@tonic-gate * Notify the application as well. 69447c478bd9Sstevel@tonic-gate */ 6945ff550d0eSmasputra *error = EPROTO; 6946ff550d0eSmasputra goto done; 69477c478bd9Sstevel@tonic-gate } 69487c478bd9Sstevel@tonic-gate 69497c478bd9Sstevel@tonic-gate /* 69507c478bd9Sstevel@tonic-gate * rth->ip6r_len is twice the number of 69517c478bd9Sstevel@tonic-gate * addresses in the header. Thus it must be even. 69527c478bd9Sstevel@tonic-gate */ 69537c478bd9Sstevel@tonic-gate if (rth->ip6r_len & 0x1) { 6954ff550d0eSmasputra *error = EPROTO; 6955ff550d0eSmasputra goto done; 69567c478bd9Sstevel@tonic-gate } 69577c478bd9Sstevel@tonic-gate /* 69587c478bd9Sstevel@tonic-gate * Shuffle the routing header and ip6_dst 69597c478bd9Sstevel@tonic-gate * addresses, and get the checksum difference 69607c478bd9Sstevel@tonic-gate * between the first hop (in ip6_dst) and 69617c478bd9Sstevel@tonic-gate * the destination (in the last routing hdr entry). 69627c478bd9Sstevel@tonic-gate */ 69637c478bd9Sstevel@tonic-gate csum = ip_massage_options_v6(ip6h, rth); 69647c478bd9Sstevel@tonic-gate /* 69657c478bd9Sstevel@tonic-gate * Verify that the first hop isn't a mapped address. 69667c478bd9Sstevel@tonic-gate * Routers along the path need to do this verification 69677c478bd9Sstevel@tonic-gate * for subsequent hops. 69687c478bd9Sstevel@tonic-gate */ 69697c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_V4MAPPED(&ip6h->ip6_dst)) { 6970ff550d0eSmasputra *error = EADDRNOTAVAIL; 6971ff550d0eSmasputra goto done; 69727c478bd9Sstevel@tonic-gate } 69737c478bd9Sstevel@tonic-gate 69747c478bd9Sstevel@tonic-gate cp += (rth->ip6r_len + 1)*8; 69757c478bd9Sstevel@tonic-gate } 69767c478bd9Sstevel@tonic-gate } 69777c478bd9Sstevel@tonic-gate 69787c478bd9Sstevel@tonic-gate /* count up length of UDP packet */ 69797c478bd9Sstevel@tonic-gate ip_len = (mp1->b_wptr - (unsigned char *)ip6h) - IPV6_HDR_LEN; 6980ff550d0eSmasputra if ((mp2 = mp1->b_cont) != NULL) { 6981ff550d0eSmasputra do { 6982ff550d0eSmasputra ASSERT((uintptr_t)MBLKL(mp2) <= (uintptr_t)UINT_MAX); 6983ff550d0eSmasputra ip_len += (uint32_t)MBLKL(mp2); 6984ff550d0eSmasputra } while ((mp2 = mp2->b_cont) != NULL); 69857c478bd9Sstevel@tonic-gate } 69867c478bd9Sstevel@tonic-gate 69877c478bd9Sstevel@tonic-gate /* 69887c478bd9Sstevel@tonic-gate * If the size of the packet is greater than the maximum allowed by 69897c478bd9Sstevel@tonic-gate * ip, return an error. Passing this down could cause panics because 69907c478bd9Sstevel@tonic-gate * the size will have wrapped and be inconsistent with the msg size. 69917c478bd9Sstevel@tonic-gate */ 69927c478bd9Sstevel@tonic-gate if (ip_len > IP_MAXPACKET) { 6993ff550d0eSmasputra *error = EMSGSIZE; 6994ff550d0eSmasputra goto done; 69957c478bd9Sstevel@tonic-gate } 69967c478bd9Sstevel@tonic-gate 69977c478bd9Sstevel@tonic-gate /* Store the UDP length. Subtract length of extension hdrs */ 69987c478bd9Sstevel@tonic-gate udph->uha_length = htons(ip_len + IPV6_HDR_LEN - 69997c478bd9Sstevel@tonic-gate (int)((uchar_t *)udph - (uchar_t *)ip6h)); 70007c478bd9Sstevel@tonic-gate 70017c478bd9Sstevel@tonic-gate /* 70027c478bd9Sstevel@tonic-gate * We make it easy for IP to include our pseudo header 70037c478bd9Sstevel@tonic-gate * by putting our length in uh_checksum, modified (if 70047c478bd9Sstevel@tonic-gate * we have a routing header) by the checksum difference 70057c478bd9Sstevel@tonic-gate * between the ultimate destination and first hop addresses. 70067c478bd9Sstevel@tonic-gate * Note: UDP over IPv6 must always checksum the packet. 70077c478bd9Sstevel@tonic-gate */ 70087c478bd9Sstevel@tonic-gate csum += udph->uha_length; 70097c478bd9Sstevel@tonic-gate csum = (csum & 0xFFFF) + (csum >> 16); 70107c478bd9Sstevel@tonic-gate udph->uha_checksum = (uint16_t)csum; 70117c478bd9Sstevel@tonic-gate 70127c478bd9Sstevel@tonic-gate #ifdef _LITTLE_ENDIAN 70137c478bd9Sstevel@tonic-gate ip_len = htons(ip_len); 70147c478bd9Sstevel@tonic-gate #endif 70157c478bd9Sstevel@tonic-gate ip6h->ip6_plen = ip_len; 70167c478bd9Sstevel@tonic-gate 7017ff550d0eSmasputra if (DB_TYPE(mp) != M_DATA) { 7018ff550d0eSmasputra ASSERT(mp != mp1); 7019ff550d0eSmasputra freeb(mp); 7020ff550d0eSmasputra } 7021ff550d0eSmasputra 7022ff550d0eSmasputra /* mp has been consumed and we'll return success */ 7023ff550d0eSmasputra ASSERT(*error == 0); 7024ff550d0eSmasputra mp = NULL; 70257c478bd9Sstevel@tonic-gate 70267c478bd9Sstevel@tonic-gate /* We're done. Pass the packet to IP */ 70277c478bd9Sstevel@tonic-gate BUMP_MIB(&udp_mib, udpOutDatagrams); 7028ff550d0eSmasputra ip_output_v6(connp, mp1, q, IP_WPUT); 7029ff550d0eSmasputra 7030ff550d0eSmasputra done: 7031ff550d0eSmasputra if (*error != 0) { 7032ff550d0eSmasputra ASSERT(mp != NULL); 7033ff550d0eSmasputra BUMP_MIB(&udp_mib, udpOutErrors); 7034ff550d0eSmasputra } 7035ff550d0eSmasputra return (mp); 70367c478bd9Sstevel@tonic-gate } 70377c478bd9Sstevel@tonic-gate 70387c478bd9Sstevel@tonic-gate static void 70397c478bd9Sstevel@tonic-gate udp_wput_other(queue_t *q, mblk_t *mp) 70407c478bd9Sstevel@tonic-gate { 70417c478bd9Sstevel@tonic-gate uchar_t *rptr = mp->b_rptr; 70427c478bd9Sstevel@tonic-gate struct datab *db; 70437c478bd9Sstevel@tonic-gate struct iocblk *iocp; 70447c478bd9Sstevel@tonic-gate cred_t *cr; 7045ff550d0eSmasputra conn_t *connp = Q_TO_CONN(q); 7046ff550d0eSmasputra udp_t *udp = connp->conn_udp; 70477c478bd9Sstevel@tonic-gate 70487c478bd9Sstevel@tonic-gate TRACE_1(TR_FAC_UDP, TR_UDP_WPUT_OTHER_START, 70497c478bd9Sstevel@tonic-gate "udp_wput_other_start: q %p", q); 70507c478bd9Sstevel@tonic-gate 70517c478bd9Sstevel@tonic-gate db = mp->b_datap; 70527c478bd9Sstevel@tonic-gate 7053ff550d0eSmasputra cr = DB_CREDDEF(mp, connp->conn_cred); 70547c478bd9Sstevel@tonic-gate 70557c478bd9Sstevel@tonic-gate switch (db->db_type) { 70567c478bd9Sstevel@tonic-gate case M_PROTO: 70577c478bd9Sstevel@tonic-gate case M_PCPROTO: 70587c478bd9Sstevel@tonic-gate if (mp->b_wptr - rptr < sizeof (t_scalar_t)) { 70597c478bd9Sstevel@tonic-gate freemsg(mp); 70607c478bd9Sstevel@tonic-gate TRACE_2(TR_FAC_UDP, TR_UDP_WPUT_OTHER_END, 70617c478bd9Sstevel@tonic-gate "udp_wput_other_end: q %p (%S)", 70627c478bd9Sstevel@tonic-gate q, "protoshort"); 70637c478bd9Sstevel@tonic-gate return; 70647c478bd9Sstevel@tonic-gate } 7065ff550d0eSmasputra switch (((t_primp_t)rptr)->type) { 70667c478bd9Sstevel@tonic-gate case T_ADDR_REQ: 70677c478bd9Sstevel@tonic-gate udp_addr_req(q, mp); 70687c478bd9Sstevel@tonic-gate TRACE_2(TR_FAC_UDP, TR_UDP_WPUT_OTHER_END, 70697c478bd9Sstevel@tonic-gate "udp_wput_other_end: q %p (%S)", q, "addrreq"); 70707c478bd9Sstevel@tonic-gate return; 70717c478bd9Sstevel@tonic-gate case O_T_BIND_REQ: 70727c478bd9Sstevel@tonic-gate case T_BIND_REQ: 70737c478bd9Sstevel@tonic-gate udp_bind(q, mp); 70747c478bd9Sstevel@tonic-gate TRACE_2(TR_FAC_UDP, TR_UDP_WPUT_OTHER_END, 70757c478bd9Sstevel@tonic-gate "udp_wput_other_end: q %p (%S)", q, "bindreq"); 70767c478bd9Sstevel@tonic-gate return; 70777c478bd9Sstevel@tonic-gate case T_CONN_REQ: 70787c478bd9Sstevel@tonic-gate udp_connect(q, mp); 70797c478bd9Sstevel@tonic-gate TRACE_2(TR_FAC_UDP, TR_UDP_WPUT_OTHER_END, 70807c478bd9Sstevel@tonic-gate "udp_wput_other_end: q %p (%S)", q, "connreq"); 70817c478bd9Sstevel@tonic-gate return; 70827c478bd9Sstevel@tonic-gate case T_CAPABILITY_REQ: 70837c478bd9Sstevel@tonic-gate udp_capability_req(q, mp); 70847c478bd9Sstevel@tonic-gate TRACE_2(TR_FAC_UDP, TR_UDP_WPUT_OTHER_END, 70857c478bd9Sstevel@tonic-gate "udp_wput_other_end: q %p (%S)", q, "capabreq"); 70867c478bd9Sstevel@tonic-gate return; 70877c478bd9Sstevel@tonic-gate case T_INFO_REQ: 70887c478bd9Sstevel@tonic-gate udp_info_req(q, mp); 70897c478bd9Sstevel@tonic-gate TRACE_2(TR_FAC_UDP, TR_UDP_WPUT_OTHER_END, 70907c478bd9Sstevel@tonic-gate "udp_wput_other_end: q %p (%S)", q, "inforeq"); 70917c478bd9Sstevel@tonic-gate return; 70927c478bd9Sstevel@tonic-gate case T_UNITDATA_REQ: 70937c478bd9Sstevel@tonic-gate /* 70947c478bd9Sstevel@tonic-gate * If a T_UNITDATA_REQ gets here, the address must 70957c478bd9Sstevel@tonic-gate * be bad. Valid T_UNITDATA_REQs are handled 70967c478bd9Sstevel@tonic-gate * in udp_wput. 70977c478bd9Sstevel@tonic-gate */ 7098ff550d0eSmasputra udp_ud_err(q, mp, NULL, 0, EADDRNOTAVAIL); 70997c478bd9Sstevel@tonic-gate TRACE_2(TR_FAC_UDP, TR_UDP_WPUT_OTHER_END, 71007c478bd9Sstevel@tonic-gate "udp_wput_other_end: q %p (%S)", 71017c478bd9Sstevel@tonic-gate q, "unitdatareq"); 71027c478bd9Sstevel@tonic-gate return; 71037c478bd9Sstevel@tonic-gate case T_UNBIND_REQ: 71047c478bd9Sstevel@tonic-gate udp_unbind(q, mp); 71057c478bd9Sstevel@tonic-gate TRACE_2(TR_FAC_UDP, TR_UDP_WPUT_OTHER_END, 71067c478bd9Sstevel@tonic-gate "udp_wput_other_end: q %p (%S)", q, "unbindreq"); 71077c478bd9Sstevel@tonic-gate return; 71087c478bd9Sstevel@tonic-gate case T_SVR4_OPTMGMT_REQ: 71097c478bd9Sstevel@tonic-gate if (!snmpcom_req(q, mp, udp_snmp_set, udp_snmp_get, cr)) 7110ff550d0eSmasputra /* 7111ff550d0eSmasputra * Use upper queue for option processing in 7112ff550d0eSmasputra * case the request is not handled at this 7113ff550d0eSmasputra * level and needs to be passed down to IP. 7114ff550d0eSmasputra */ 7115ff550d0eSmasputra (void) svr4_optcom_req(_WR(UDP_RD(q)), 7116ff550d0eSmasputra mp, cr, &udp_opt_obj); 71177c478bd9Sstevel@tonic-gate TRACE_2(TR_FAC_UDP, TR_UDP_WPUT_OTHER_END, 71187c478bd9Sstevel@tonic-gate "udp_wput_other_end: q %p (%S)", 71197c478bd9Sstevel@tonic-gate q, "optmgmtreq"); 71207c478bd9Sstevel@tonic-gate return; 71217c478bd9Sstevel@tonic-gate 71227c478bd9Sstevel@tonic-gate case T_OPTMGMT_REQ: 7123ff550d0eSmasputra /* 7124ff550d0eSmasputra * Use upper queue for option processing in 7125ff550d0eSmasputra * case the request is not handled at this 7126ff550d0eSmasputra * level and needs to be passed down to IP. 7127ff550d0eSmasputra */ 7128ff550d0eSmasputra (void) tpi_optcom_req(_WR(UDP_RD(q)), 7129ff550d0eSmasputra mp, cr, &udp_opt_obj); 71307c478bd9Sstevel@tonic-gate TRACE_2(TR_FAC_UDP, TR_UDP_WPUT_OTHER_END, 71317c478bd9Sstevel@tonic-gate "udp_wput_other_end: q %p (%S)", 71327c478bd9Sstevel@tonic-gate q, "optmgmtreq"); 71337c478bd9Sstevel@tonic-gate return; 71347c478bd9Sstevel@tonic-gate 71357c478bd9Sstevel@tonic-gate case T_DISCON_REQ: 71367c478bd9Sstevel@tonic-gate udp_disconnect(q, mp); 71377c478bd9Sstevel@tonic-gate TRACE_2(TR_FAC_UDP, TR_UDP_WPUT_OTHER_END, 71387c478bd9Sstevel@tonic-gate "udp_wput_other_end: q %p (%S)", 71397c478bd9Sstevel@tonic-gate q, "disconreq"); 71407c478bd9Sstevel@tonic-gate return; 71417c478bd9Sstevel@tonic-gate 71427c478bd9Sstevel@tonic-gate /* The following TPI message is not supported by udp. */ 71437c478bd9Sstevel@tonic-gate case O_T_CONN_RES: 71447c478bd9Sstevel@tonic-gate case T_CONN_RES: 71457c478bd9Sstevel@tonic-gate udp_err_ack(q, mp, TNOTSUPPORT, 0); 71467c478bd9Sstevel@tonic-gate TRACE_2(TR_FAC_UDP, TR_UDP_WPUT_OTHER_END, 71477c478bd9Sstevel@tonic-gate "udp_wput_other_end: q %p (%S)", 71487c478bd9Sstevel@tonic-gate q, "connres/disconreq"); 71497c478bd9Sstevel@tonic-gate return; 71507c478bd9Sstevel@tonic-gate 71517c478bd9Sstevel@tonic-gate /* The following 3 TPI messages are illegal for udp. */ 71527c478bd9Sstevel@tonic-gate case T_DATA_REQ: 71537c478bd9Sstevel@tonic-gate case T_EXDATA_REQ: 71547c478bd9Sstevel@tonic-gate case T_ORDREL_REQ: 71557c478bd9Sstevel@tonic-gate udp_err_ack(q, mp, TNOTSUPPORT, 0); 71567c478bd9Sstevel@tonic-gate TRACE_2(TR_FAC_UDP, TR_UDP_WPUT_OTHER_END, 71577c478bd9Sstevel@tonic-gate "udp_wput_other_end: q %p (%S)", 71587c478bd9Sstevel@tonic-gate q, "data/exdata/ordrel"); 71597c478bd9Sstevel@tonic-gate return; 71607c478bd9Sstevel@tonic-gate default: 71617c478bd9Sstevel@tonic-gate break; 71627c478bd9Sstevel@tonic-gate } 71637c478bd9Sstevel@tonic-gate break; 71647c478bd9Sstevel@tonic-gate case M_FLUSH: 71657c478bd9Sstevel@tonic-gate if (*rptr & FLUSHW) 71667c478bd9Sstevel@tonic-gate flushq(q, FLUSHDATA); 71677c478bd9Sstevel@tonic-gate break; 71687c478bd9Sstevel@tonic-gate case M_IOCTL: 71697c478bd9Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr; 71707c478bd9Sstevel@tonic-gate switch (iocp->ioc_cmd) { 71717c478bd9Sstevel@tonic-gate case TI_GETPEERNAME: 71727c478bd9Sstevel@tonic-gate if (udp->udp_state != TS_DATA_XFER) { 71737c478bd9Sstevel@tonic-gate /* 71747c478bd9Sstevel@tonic-gate * If a default destination address has not 71757c478bd9Sstevel@tonic-gate * been associated with the stream, then we 71767c478bd9Sstevel@tonic-gate * don't know the peer's name. 71777c478bd9Sstevel@tonic-gate */ 71787c478bd9Sstevel@tonic-gate iocp->ioc_error = ENOTCONN; 71797c478bd9Sstevel@tonic-gate iocp->ioc_count = 0; 71807c478bd9Sstevel@tonic-gate mp->b_datap->db_type = M_IOCACK; 7181ff550d0eSmasputra putnext(UDP_RD(q), mp); 71827c478bd9Sstevel@tonic-gate TRACE_2(TR_FAC_UDP, TR_UDP_WPUT_OTHER_END, 71837c478bd9Sstevel@tonic-gate "udp_wput_other_end: q %p (%S)", 71847c478bd9Sstevel@tonic-gate q, "getpeername"); 71857c478bd9Sstevel@tonic-gate return; 71867c478bd9Sstevel@tonic-gate } 71877c478bd9Sstevel@tonic-gate /* FALLTHRU */ 71887c478bd9Sstevel@tonic-gate case TI_GETMYNAME: { 71897c478bd9Sstevel@tonic-gate /* 71907c478bd9Sstevel@tonic-gate * For TI_GETPEERNAME and TI_GETMYNAME, we first 71917c478bd9Sstevel@tonic-gate * need to copyin the user's strbuf structure. 71927c478bd9Sstevel@tonic-gate * Processing will continue in the M_IOCDATA case 71937c478bd9Sstevel@tonic-gate * below. 71947c478bd9Sstevel@tonic-gate */ 71957c478bd9Sstevel@tonic-gate mi_copyin(q, mp, NULL, 71967c478bd9Sstevel@tonic-gate SIZEOF_STRUCT(strbuf, iocp->ioc_flag)); 71977c478bd9Sstevel@tonic-gate TRACE_2(TR_FAC_UDP, TR_UDP_WPUT_OTHER_END, 71987c478bd9Sstevel@tonic-gate "udp_wput_other_end: q %p (%S)", 71997c478bd9Sstevel@tonic-gate q, "getmyname"); 72007c478bd9Sstevel@tonic-gate return; 72017c478bd9Sstevel@tonic-gate } 72027c478bd9Sstevel@tonic-gate case ND_SET: 72037c478bd9Sstevel@tonic-gate /* nd_getset performs the necessary checking */ 72047c478bd9Sstevel@tonic-gate case ND_GET: 72057c478bd9Sstevel@tonic-gate if (nd_getset(q, udp_g_nd, mp)) { 7206ff550d0eSmasputra putnext(UDP_RD(q), mp); 72077c478bd9Sstevel@tonic-gate TRACE_2(TR_FAC_UDP, TR_UDP_WPUT_OTHER_END, 72087c478bd9Sstevel@tonic-gate "udp_wput_other_end: q %p (%S)", 72097c478bd9Sstevel@tonic-gate q, "get"); 72107c478bd9Sstevel@tonic-gate return; 72117c478bd9Sstevel@tonic-gate } 72127c478bd9Sstevel@tonic-gate break; 7213ff550d0eSmasputra case _SIOCSOCKFALLBACK: 7214ff550d0eSmasputra /* 7215ff550d0eSmasputra * Either sockmod is about to be popped and the 7216ff550d0eSmasputra * socket would now be treated as a plain stream, 7217ff550d0eSmasputra * or a module is about to be pushed so we could 7218ff550d0eSmasputra * no longer use read-side synchronous stream. 7219ff550d0eSmasputra * Drain any queued data and disable direct sockfs 7220ff550d0eSmasputra * interface from now on. 7221ff550d0eSmasputra */ 7222ff550d0eSmasputra if (!udp->udp_issocket) { 7223ff550d0eSmasputra DB_TYPE(mp) = M_IOCNAK; 7224ff550d0eSmasputra iocp->ioc_error = EINVAL; 7225ff550d0eSmasputra } else { 7226ff550d0eSmasputra udp->udp_issocket = B_FALSE; 7227ff550d0eSmasputra if (udp->udp_direct_sockfs) { 7228ff550d0eSmasputra /* 7229ff550d0eSmasputra * Disable read-side synchronous 7230ff550d0eSmasputra * stream interface and drain any 7231ff550d0eSmasputra * queued data. 7232ff550d0eSmasputra */ 7233ff550d0eSmasputra udp_rcv_drain(UDP_RD(q), udp, 7234ff550d0eSmasputra B_FALSE); 7235ff550d0eSmasputra ASSERT(!udp->udp_direct_sockfs); 7236ff550d0eSmasputra UDP_STAT(udp_sock_fallback); 7237ff550d0eSmasputra } 7238ff550d0eSmasputra DB_TYPE(mp) = M_IOCACK; 7239ff550d0eSmasputra iocp->ioc_error = 0; 7240ff550d0eSmasputra } 7241ff550d0eSmasputra iocp->ioc_count = 0; 7242ff550d0eSmasputra iocp->ioc_rval = 0; 7243ff550d0eSmasputra putnext(UDP_RD(q), mp); 7244ff550d0eSmasputra return; 72457c478bd9Sstevel@tonic-gate default: 72467c478bd9Sstevel@tonic-gate break; 72477c478bd9Sstevel@tonic-gate } 72487c478bd9Sstevel@tonic-gate break; 72497c478bd9Sstevel@tonic-gate case M_IOCDATA: 72507c478bd9Sstevel@tonic-gate udp_wput_iocdata(q, mp); 72517c478bd9Sstevel@tonic-gate TRACE_2(TR_FAC_UDP, TR_UDP_WPUT_OTHER_END, 72527c478bd9Sstevel@tonic-gate "udp_wput_other_end: q %p (%S)", q, "iocdata"); 72537c478bd9Sstevel@tonic-gate return; 72547c478bd9Sstevel@tonic-gate default: 72557c478bd9Sstevel@tonic-gate /* Unrecognized messages are passed through without change. */ 72567c478bd9Sstevel@tonic-gate break; 72577c478bd9Sstevel@tonic-gate } 72587c478bd9Sstevel@tonic-gate TRACE_2(TR_FAC_UDP, TR_UDP_WPUT_OTHER_END, 72597c478bd9Sstevel@tonic-gate "udp_wput_other_end: q %p (%S)", q, "end"); 7260ff550d0eSmasputra ip_output(connp, mp, q, IP_WPUT); 7261ff550d0eSmasputra } 7262ff550d0eSmasputra 7263ff550d0eSmasputra /* ARGSUSED */ 7264ff550d0eSmasputra static void 7265ff550d0eSmasputra udp_wput_other_wrapper(void *arg, mblk_t *mp, void *arg2) 7266ff550d0eSmasputra { 7267ff550d0eSmasputra udp_wput_other(((conn_t *)arg)->conn_wq, mp); 7268ff550d0eSmasputra udp_exit((conn_t *)arg); 72697c478bd9Sstevel@tonic-gate } 72707c478bd9Sstevel@tonic-gate 72717c478bd9Sstevel@tonic-gate /* 72727c478bd9Sstevel@tonic-gate * udp_wput_iocdata is called by udp_wput_other to handle all M_IOCDATA 72737c478bd9Sstevel@tonic-gate * messages. 72747c478bd9Sstevel@tonic-gate */ 72757c478bd9Sstevel@tonic-gate static void 72767c478bd9Sstevel@tonic-gate udp_wput_iocdata(queue_t *q, mblk_t *mp) 72777c478bd9Sstevel@tonic-gate { 72787c478bd9Sstevel@tonic-gate mblk_t *mp1; 72797c478bd9Sstevel@tonic-gate STRUCT_HANDLE(strbuf, sb); 72807c478bd9Sstevel@tonic-gate uint16_t port; 72817c478bd9Sstevel@tonic-gate in6_addr_t v6addr; 72827c478bd9Sstevel@tonic-gate ipaddr_t v4addr; 72837c478bd9Sstevel@tonic-gate uint32_t flowinfo = 0; 72847c478bd9Sstevel@tonic-gate int addrlen; 7285ff550d0eSmasputra udp_t *udp = Q_TO_UDP(q); 72867c478bd9Sstevel@tonic-gate 72877c478bd9Sstevel@tonic-gate /* Make sure it is one of ours. */ 72887c478bd9Sstevel@tonic-gate switch (((struct iocblk *)mp->b_rptr)->ioc_cmd) { 72897c478bd9Sstevel@tonic-gate case TI_GETMYNAME: 72907c478bd9Sstevel@tonic-gate case TI_GETPEERNAME: 72917c478bd9Sstevel@tonic-gate break; 72927c478bd9Sstevel@tonic-gate default: 7293ff550d0eSmasputra ip_output(Q_TO_CONN(q), mp, q, IP_WPUT); 72947c478bd9Sstevel@tonic-gate return; 72957c478bd9Sstevel@tonic-gate } 7296ff550d0eSmasputra 7297ff550d0eSmasputra q = WR(UDP_RD(q)); 72987c478bd9Sstevel@tonic-gate switch (mi_copy_state(q, mp, &mp1)) { 72997c478bd9Sstevel@tonic-gate case -1: 73007c478bd9Sstevel@tonic-gate return; 73017c478bd9Sstevel@tonic-gate case MI_COPY_CASE(MI_COPY_IN, 1): 73027c478bd9Sstevel@tonic-gate break; 73037c478bd9Sstevel@tonic-gate case MI_COPY_CASE(MI_COPY_OUT, 1): 73047c478bd9Sstevel@tonic-gate /* 73057c478bd9Sstevel@tonic-gate * The address has been copied out, so now 73067c478bd9Sstevel@tonic-gate * copyout the strbuf. 73077c478bd9Sstevel@tonic-gate */ 73087c478bd9Sstevel@tonic-gate mi_copyout(q, mp); 73097c478bd9Sstevel@tonic-gate return; 73107c478bd9Sstevel@tonic-gate case MI_COPY_CASE(MI_COPY_OUT, 2): 73117c478bd9Sstevel@tonic-gate /* 73127c478bd9Sstevel@tonic-gate * The address and strbuf have been copied out. 73137c478bd9Sstevel@tonic-gate * We're done, so just acknowledge the original 73147c478bd9Sstevel@tonic-gate * M_IOCTL. 73157c478bd9Sstevel@tonic-gate */ 73167c478bd9Sstevel@tonic-gate mi_copy_done(q, mp, 0); 73177c478bd9Sstevel@tonic-gate return; 73187c478bd9Sstevel@tonic-gate default: 73197c478bd9Sstevel@tonic-gate /* 73207c478bd9Sstevel@tonic-gate * Something strange has happened, so acknowledge 73217c478bd9Sstevel@tonic-gate * the original M_IOCTL with an EPROTO error. 73227c478bd9Sstevel@tonic-gate */ 73237c478bd9Sstevel@tonic-gate mi_copy_done(q, mp, EPROTO); 73247c478bd9Sstevel@tonic-gate return; 73257c478bd9Sstevel@tonic-gate } 73267c478bd9Sstevel@tonic-gate 73277c478bd9Sstevel@tonic-gate /* 73287c478bd9Sstevel@tonic-gate * Now we have the strbuf structure for TI_GETMYNAME 73297c478bd9Sstevel@tonic-gate * and TI_GETPEERNAME. Next we copyout the requested 73307c478bd9Sstevel@tonic-gate * address and then we'll copyout the strbuf. 73317c478bd9Sstevel@tonic-gate */ 73327c478bd9Sstevel@tonic-gate STRUCT_SET_HANDLE(sb, ((struct iocblk *)mp->b_rptr)->ioc_flag, 73337c478bd9Sstevel@tonic-gate (void *)mp1->b_rptr); 73347c478bd9Sstevel@tonic-gate if (udp->udp_family == AF_INET) 73357c478bd9Sstevel@tonic-gate addrlen = sizeof (sin_t); 73367c478bd9Sstevel@tonic-gate else 73377c478bd9Sstevel@tonic-gate addrlen = sizeof (sin6_t); 73387c478bd9Sstevel@tonic-gate 73397c478bd9Sstevel@tonic-gate if (STRUCT_FGET(sb, maxlen) < addrlen) { 73407c478bd9Sstevel@tonic-gate mi_copy_done(q, mp, EINVAL); 73417c478bd9Sstevel@tonic-gate return; 73427c478bd9Sstevel@tonic-gate } 73437c478bd9Sstevel@tonic-gate switch (((struct iocblk *)mp->b_rptr)->ioc_cmd) { 73447c478bd9Sstevel@tonic-gate case TI_GETMYNAME: 73457c478bd9Sstevel@tonic-gate if (udp->udp_family == AF_INET) { 73467c478bd9Sstevel@tonic-gate ASSERT(udp->udp_ipversion == IPV4_VERSION); 73477c478bd9Sstevel@tonic-gate if (!IN6_IS_ADDR_V4MAPPED_ANY(&udp->udp_v6src) && 73487c478bd9Sstevel@tonic-gate !IN6_IS_ADDR_UNSPECIFIED(&udp->udp_v6src)) { 73497c478bd9Sstevel@tonic-gate v4addr = V4_PART_OF_V6(udp->udp_v6src); 73507c478bd9Sstevel@tonic-gate } else { 73517c478bd9Sstevel@tonic-gate /* 73527c478bd9Sstevel@tonic-gate * INADDR_ANY 73537c478bd9Sstevel@tonic-gate * udp_v6src is not set, we might be bound to 73547c478bd9Sstevel@tonic-gate * broadcast/multicast. Use udp_bound_v6src as 73557c478bd9Sstevel@tonic-gate * local address instead (that could 73567c478bd9Sstevel@tonic-gate * also still be INADDR_ANY) 73577c478bd9Sstevel@tonic-gate */ 73587c478bd9Sstevel@tonic-gate v4addr = V4_PART_OF_V6(udp->udp_bound_v6src); 73597c478bd9Sstevel@tonic-gate } 73607c478bd9Sstevel@tonic-gate } else { 73617c478bd9Sstevel@tonic-gate /* udp->udp_family == AF_INET6 */ 73627c478bd9Sstevel@tonic-gate if (!IN6_IS_ADDR_UNSPECIFIED(&udp->udp_v6src)) { 73637c478bd9Sstevel@tonic-gate v6addr = udp->udp_v6src; 73647c478bd9Sstevel@tonic-gate } else { 73657c478bd9Sstevel@tonic-gate /* 73667c478bd9Sstevel@tonic-gate * UNSPECIFIED 73677c478bd9Sstevel@tonic-gate * udp_v6src is not set, we might be bound to 73687c478bd9Sstevel@tonic-gate * broadcast/multicast. Use udp_bound_v6src as 73697c478bd9Sstevel@tonic-gate * local address instead (that could 73707c478bd9Sstevel@tonic-gate * also still be UNSPECIFIED) 73717c478bd9Sstevel@tonic-gate */ 73727c478bd9Sstevel@tonic-gate v6addr = udp->udp_bound_v6src; 73737c478bd9Sstevel@tonic-gate } 73747c478bd9Sstevel@tonic-gate } 73757c478bd9Sstevel@tonic-gate port = udp->udp_port; 73767c478bd9Sstevel@tonic-gate break; 73777c478bd9Sstevel@tonic-gate case TI_GETPEERNAME: 7378ff550d0eSmasputra if (udp->udp_state != TS_DATA_XFER) { 7379ff550d0eSmasputra mi_copy_done(q, mp, ENOTCONN); 7380ff550d0eSmasputra return; 7381ff550d0eSmasputra } 73827c478bd9Sstevel@tonic-gate if (udp->udp_family == AF_INET) { 73837c478bd9Sstevel@tonic-gate ASSERT(udp->udp_ipversion == IPV4_VERSION); 73847c478bd9Sstevel@tonic-gate v4addr = V4_PART_OF_V6(udp->udp_v6dst); 73857c478bd9Sstevel@tonic-gate } else { 73867c478bd9Sstevel@tonic-gate /* udp->udp_family == AF_INET6) */ 73877c478bd9Sstevel@tonic-gate v6addr = udp->udp_v6dst; 73887c478bd9Sstevel@tonic-gate flowinfo = udp->udp_flowinfo; 73897c478bd9Sstevel@tonic-gate } 73907c478bd9Sstevel@tonic-gate port = udp->udp_dstport; 73917c478bd9Sstevel@tonic-gate break; 73927c478bd9Sstevel@tonic-gate default: 73937c478bd9Sstevel@tonic-gate mi_copy_done(q, mp, EPROTO); 73947c478bd9Sstevel@tonic-gate return; 73957c478bd9Sstevel@tonic-gate } 73967c478bd9Sstevel@tonic-gate mp1 = mi_copyout_alloc(q, mp, STRUCT_FGETP(sb, buf), addrlen, B_TRUE); 73977c478bd9Sstevel@tonic-gate if (!mp1) 73987c478bd9Sstevel@tonic-gate return; 73997c478bd9Sstevel@tonic-gate 74007c478bd9Sstevel@tonic-gate if (udp->udp_family == AF_INET) { 74017c478bd9Sstevel@tonic-gate sin_t *sin; 74027c478bd9Sstevel@tonic-gate 74037c478bd9Sstevel@tonic-gate STRUCT_FSET(sb, len, (int)sizeof (sin_t)); 74047c478bd9Sstevel@tonic-gate sin = (sin_t *)mp1->b_rptr; 74057c478bd9Sstevel@tonic-gate mp1->b_wptr = (uchar_t *)&sin[1]; 74067c478bd9Sstevel@tonic-gate *sin = sin_null; 74077c478bd9Sstevel@tonic-gate sin->sin_family = AF_INET; 74087c478bd9Sstevel@tonic-gate sin->sin_addr.s_addr = v4addr; 74097c478bd9Sstevel@tonic-gate sin->sin_port = port; 74107c478bd9Sstevel@tonic-gate } else { 74117c478bd9Sstevel@tonic-gate /* udp->udp_family == AF_INET6 */ 74127c478bd9Sstevel@tonic-gate sin6_t *sin6; 74137c478bd9Sstevel@tonic-gate 74147c478bd9Sstevel@tonic-gate STRUCT_FSET(sb, len, (int)sizeof (sin6_t)); 74157c478bd9Sstevel@tonic-gate sin6 = (sin6_t *)mp1->b_rptr; 74167c478bd9Sstevel@tonic-gate mp1->b_wptr = (uchar_t *)&sin6[1]; 74177c478bd9Sstevel@tonic-gate *sin6 = sin6_null; 74187c478bd9Sstevel@tonic-gate sin6->sin6_family = AF_INET6; 74197c478bd9Sstevel@tonic-gate sin6->sin6_flowinfo = flowinfo; 74207c478bd9Sstevel@tonic-gate sin6->sin6_addr = v6addr; 74217c478bd9Sstevel@tonic-gate sin6->sin6_port = port; 74227c478bd9Sstevel@tonic-gate } 74237c478bd9Sstevel@tonic-gate /* Copy out the address */ 74247c478bd9Sstevel@tonic-gate mi_copyout(q, mp); 74257c478bd9Sstevel@tonic-gate } 74267c478bd9Sstevel@tonic-gate 74277c478bd9Sstevel@tonic-gate 74287c478bd9Sstevel@tonic-gate static int 74297c478bd9Sstevel@tonic-gate udp_unitdata_opt_process(queue_t *q, mblk_t *mp, int *errorp, 74307c478bd9Sstevel@tonic-gate void *thisdg_attrs) 74317c478bd9Sstevel@tonic-gate { 74327c478bd9Sstevel@tonic-gate struct T_unitdata_req *udreqp; 74337c478bd9Sstevel@tonic-gate int is_absreq_failure; 74347c478bd9Sstevel@tonic-gate cred_t *cr; 7435ff550d0eSmasputra conn_t *connp = Q_TO_CONN(q); 74367c478bd9Sstevel@tonic-gate 7437ff550d0eSmasputra ASSERT(((t_primp_t)mp->b_rptr)->type); 74387c478bd9Sstevel@tonic-gate 7439ff550d0eSmasputra cr = DB_CREDDEF(mp, connp->conn_cred); 74407c478bd9Sstevel@tonic-gate 74417c478bd9Sstevel@tonic-gate udreqp = (struct T_unitdata_req *)mp->b_rptr; 74427c478bd9Sstevel@tonic-gate *errorp = 0; 74437c478bd9Sstevel@tonic-gate 7444ff550d0eSmasputra /* 7445ff550d0eSmasputra * Use upper queue for option processing since the callback 7446ff550d0eSmasputra * routines expect to be called in UDP instance instead of IP. 7447ff550d0eSmasputra */ 7448ff550d0eSmasputra *errorp = tpi_optcom_buf(_WR(UDP_RD(q)), mp, &udreqp->OPT_length, 74497c478bd9Sstevel@tonic-gate udreqp->OPT_offset, cr, &udp_opt_obj, 74507c478bd9Sstevel@tonic-gate thisdg_attrs, &is_absreq_failure); 74517c478bd9Sstevel@tonic-gate 74527c478bd9Sstevel@tonic-gate if (*errorp != 0) { 74537c478bd9Sstevel@tonic-gate /* 74547c478bd9Sstevel@tonic-gate * Note: No special action needed in this 74557c478bd9Sstevel@tonic-gate * module for "is_absreq_failure" 74567c478bd9Sstevel@tonic-gate */ 74577c478bd9Sstevel@tonic-gate return (-1); /* failure */ 74587c478bd9Sstevel@tonic-gate } 74597c478bd9Sstevel@tonic-gate ASSERT(is_absreq_failure == 0); 74607c478bd9Sstevel@tonic-gate return (0); /* success */ 74617c478bd9Sstevel@tonic-gate } 74627c478bd9Sstevel@tonic-gate 74637c478bd9Sstevel@tonic-gate void 74647c478bd9Sstevel@tonic-gate udp_ddi_init(void) 74657c478bd9Sstevel@tonic-gate { 74667c478bd9Sstevel@tonic-gate int i; 74677c478bd9Sstevel@tonic-gate 74687c478bd9Sstevel@tonic-gate UDP6_MAJ = ddi_name_to_major(UDP6); 74697c478bd9Sstevel@tonic-gate 74707c478bd9Sstevel@tonic-gate udp_max_optsize = optcom_max_optsize(udp_opt_obj.odb_opt_des_arr, 74717c478bd9Sstevel@tonic-gate udp_opt_obj.odb_opt_arr_cnt); 74727c478bd9Sstevel@tonic-gate 74737c478bd9Sstevel@tonic-gate if (udp_bind_fanout_size & (udp_bind_fanout_size - 1)) { 74747c478bd9Sstevel@tonic-gate /* Not a power of two. Round up to nearest power of two */ 74757c478bd9Sstevel@tonic-gate for (i = 0; i < 31; i++) { 74767c478bd9Sstevel@tonic-gate if (udp_bind_fanout_size < (1 << i)) 74777c478bd9Sstevel@tonic-gate break; 74787c478bd9Sstevel@tonic-gate } 74797c478bd9Sstevel@tonic-gate udp_bind_fanout_size = 1 << i; 74807c478bd9Sstevel@tonic-gate } 74817c478bd9Sstevel@tonic-gate udp_bind_fanout = kmem_zalloc(udp_bind_fanout_size * 74827c478bd9Sstevel@tonic-gate sizeof (udp_fanout_t), KM_SLEEP); 74837c478bd9Sstevel@tonic-gate for (i = 0; i < udp_bind_fanout_size; i++) { 74847c478bd9Sstevel@tonic-gate mutex_init(&udp_bind_fanout[i].uf_lock, NULL, MUTEX_DEFAULT, 74857c478bd9Sstevel@tonic-gate NULL); 74867c478bd9Sstevel@tonic-gate } 74877c478bd9Sstevel@tonic-gate (void) udp_param_register(udp_param_arr, A_CNT(udp_param_arr)); 7488ff550d0eSmasputra 74897c478bd9Sstevel@tonic-gate udp_kstat_init(); 7490ff550d0eSmasputra 7491ff550d0eSmasputra udp_cache = kmem_cache_create("udp_cache", sizeof (udp_t), 7492ff550d0eSmasputra CACHE_ALIGN_SIZE, NULL, NULL, NULL, NULL, NULL, 0); 74937c478bd9Sstevel@tonic-gate } 74947c478bd9Sstevel@tonic-gate 74957c478bd9Sstevel@tonic-gate void 74967c478bd9Sstevel@tonic-gate udp_ddi_destroy(void) 74977c478bd9Sstevel@tonic-gate { 74987c478bd9Sstevel@tonic-gate int i; 74997c478bd9Sstevel@tonic-gate 75007c478bd9Sstevel@tonic-gate nd_free(&udp_g_nd); 75017c478bd9Sstevel@tonic-gate 75027c478bd9Sstevel@tonic-gate for (i = 0; i < udp_bind_fanout_size; i++) { 75037c478bd9Sstevel@tonic-gate mutex_destroy(&udp_bind_fanout[i].uf_lock); 75047c478bd9Sstevel@tonic-gate } 7505ff550d0eSmasputra 75067c478bd9Sstevel@tonic-gate kmem_free(udp_bind_fanout, udp_bind_fanout_size * 75077c478bd9Sstevel@tonic-gate sizeof (udp_fanout_t)); 7508ff550d0eSmasputra 75097c478bd9Sstevel@tonic-gate udp_kstat_fini(); 75107c478bd9Sstevel@tonic-gate 7511ff550d0eSmasputra kmem_cache_destroy(udp_cache); 75127c478bd9Sstevel@tonic-gate } 75137c478bd9Sstevel@tonic-gate 75147c478bd9Sstevel@tonic-gate static void 75157c478bd9Sstevel@tonic-gate udp_kstat_init(void) 75167c478bd9Sstevel@tonic-gate { 75177c478bd9Sstevel@tonic-gate udp_named_kstat_t template = { 75187c478bd9Sstevel@tonic-gate { "inDatagrams", KSTAT_DATA_UINT32, 0 }, 75197c478bd9Sstevel@tonic-gate { "inErrors", KSTAT_DATA_UINT32, 0 }, 75207c478bd9Sstevel@tonic-gate { "outDatagrams", KSTAT_DATA_UINT32, 0 }, 75217c478bd9Sstevel@tonic-gate { "entrySize", KSTAT_DATA_INT32, 0 }, 75227c478bd9Sstevel@tonic-gate { "entry6Size", KSTAT_DATA_INT32, 0 }, 75237c478bd9Sstevel@tonic-gate { "outErrors", KSTAT_DATA_UINT32, 0 }, 75247c478bd9Sstevel@tonic-gate }; 75257c478bd9Sstevel@tonic-gate 7526ff550d0eSmasputra udp_mibkp = kstat_create(UDP_MOD_NAME, 0, UDP_MOD_NAME, 7527ff550d0eSmasputra "mib2", KSTAT_TYPE_NAMED, NUM_OF_FIELDS(udp_named_kstat_t), 0); 7528ff550d0eSmasputra 75297c478bd9Sstevel@tonic-gate if (udp_mibkp == NULL) 75307c478bd9Sstevel@tonic-gate return; 75317c478bd9Sstevel@tonic-gate 75327c478bd9Sstevel@tonic-gate template.entrySize.value.ui32 = sizeof (mib2_udpEntry_t); 75337c478bd9Sstevel@tonic-gate template.entry6Size.value.ui32 = sizeof (mib2_udp6Entry_t); 75347c478bd9Sstevel@tonic-gate 75357c478bd9Sstevel@tonic-gate bcopy(&template, udp_mibkp->ks_data, sizeof (template)); 75367c478bd9Sstevel@tonic-gate 75377c478bd9Sstevel@tonic-gate udp_mibkp->ks_update = udp_kstat_update; 75387c478bd9Sstevel@tonic-gate 75397c478bd9Sstevel@tonic-gate kstat_install(udp_mibkp); 7540ff550d0eSmasputra 7541ff550d0eSmasputra if ((udp_ksp = kstat_create(UDP_MOD_NAME, 0, "udpstat", 7542ff550d0eSmasputra "net", KSTAT_TYPE_NAMED, 7543ff550d0eSmasputra sizeof (udp_statistics) / sizeof (kstat_named_t), 7544ff550d0eSmasputra KSTAT_FLAG_VIRTUAL)) != NULL) { 7545ff550d0eSmasputra udp_ksp->ks_data = &udp_statistics; 7546ff550d0eSmasputra kstat_install(udp_ksp); 7547ff550d0eSmasputra } 75487c478bd9Sstevel@tonic-gate } 75497c478bd9Sstevel@tonic-gate 75507c478bd9Sstevel@tonic-gate static void 75517c478bd9Sstevel@tonic-gate udp_kstat_fini(void) 75527c478bd9Sstevel@tonic-gate { 7553ff550d0eSmasputra if (udp_ksp != NULL) { 7554ff550d0eSmasputra kstat_delete(udp_ksp); 7555ff550d0eSmasputra udp_ksp = NULL; 7556ff550d0eSmasputra } 7557ff550d0eSmasputra if (udp_mibkp != NULL) { 75587c478bd9Sstevel@tonic-gate kstat_delete(udp_mibkp); 75597c478bd9Sstevel@tonic-gate udp_mibkp = NULL; 75607c478bd9Sstevel@tonic-gate } 75617c478bd9Sstevel@tonic-gate } 75627c478bd9Sstevel@tonic-gate 75637c478bd9Sstevel@tonic-gate static int 75647c478bd9Sstevel@tonic-gate udp_kstat_update(kstat_t *kp, int rw) 75657c478bd9Sstevel@tonic-gate { 75667c478bd9Sstevel@tonic-gate udp_named_kstat_t *udpkp; 75677c478bd9Sstevel@tonic-gate 75687c478bd9Sstevel@tonic-gate if ((kp == NULL) || (kp->ks_data == NULL)) 75697c478bd9Sstevel@tonic-gate return (EIO); 75707c478bd9Sstevel@tonic-gate 75717c478bd9Sstevel@tonic-gate if (rw == KSTAT_WRITE) 75727c478bd9Sstevel@tonic-gate return (EACCES); 75737c478bd9Sstevel@tonic-gate 75747c478bd9Sstevel@tonic-gate udpkp = (udp_named_kstat_t *)kp->ks_data; 75757c478bd9Sstevel@tonic-gate 75767c478bd9Sstevel@tonic-gate udpkp->inDatagrams.value.ui32 = udp_mib.udpInDatagrams; 75777c478bd9Sstevel@tonic-gate udpkp->inErrors.value.ui32 = udp_mib.udpInErrors; 75787c478bd9Sstevel@tonic-gate udpkp->outDatagrams.value.ui32 = udp_mib.udpOutDatagrams; 75797c478bd9Sstevel@tonic-gate udpkp->outErrors.value.ui32 = udp_mib.udpOutErrors; 75807c478bd9Sstevel@tonic-gate 75817c478bd9Sstevel@tonic-gate return (0); 75827c478bd9Sstevel@tonic-gate } 75837c478bd9Sstevel@tonic-gate 7584ff550d0eSmasputra /* ARGSUSED */ 7585ff550d0eSmasputra static void 7586ff550d0eSmasputra udp_rput(queue_t *q, mblk_t *mp) 7587ff550d0eSmasputra { 7588ff550d0eSmasputra /* 7589ff550d0eSmasputra * We get here whenever we do qreply() from IP, 7590ff550d0eSmasputra * i.e as part of handlings ioctls, etc. 7591ff550d0eSmasputra */ 7592ff550d0eSmasputra putnext(q, mp); 7593ff550d0eSmasputra } 7594ff550d0eSmasputra 7595ff550d0eSmasputra /* 7596ff550d0eSmasputra * Read-side synchronous stream info entry point, called as a 7597ff550d0eSmasputra * result of handling certain STREAMS ioctl operations. 7598ff550d0eSmasputra */ 7599ff550d0eSmasputra static int 7600ff550d0eSmasputra udp_rinfop(queue_t *q, infod_t *dp) 7601ff550d0eSmasputra { 7602ff550d0eSmasputra mblk_t *mp; 7603ff550d0eSmasputra uint_t cmd = dp->d_cmd; 7604ff550d0eSmasputra int res = 0; 7605ff550d0eSmasputra int error = 0; 7606ff550d0eSmasputra udp_t *udp = Q_TO_UDP(RD(UDP_WR(q))); 7607ff550d0eSmasputra struct stdata *stp = STREAM(q); 7608ff550d0eSmasputra 7609ff550d0eSmasputra mutex_enter(&udp->udp_drain_lock); 7610ff550d0eSmasputra /* If shutdown on read has happened, return nothing */ 7611ff550d0eSmasputra mutex_enter(&stp->sd_lock); 7612ff550d0eSmasputra if (stp->sd_flag & STREOF) { 7613ff550d0eSmasputra mutex_exit(&stp->sd_lock); 7614ff550d0eSmasputra goto done; 7615ff550d0eSmasputra } 7616ff550d0eSmasputra mutex_exit(&stp->sd_lock); 7617ff550d0eSmasputra 7618ff550d0eSmasputra if ((mp = udp->udp_rcv_list_head) == NULL) 7619ff550d0eSmasputra goto done; 7620ff550d0eSmasputra 7621ff550d0eSmasputra ASSERT(DB_TYPE(mp) != M_DATA && mp->b_cont != NULL); 7622ff550d0eSmasputra 7623ff550d0eSmasputra if (cmd & INFOD_COUNT) { 7624ff550d0eSmasputra /* 7625ff550d0eSmasputra * Return the number of messages. 7626ff550d0eSmasputra */ 7627ff550d0eSmasputra dp->d_count += udp->udp_rcv_msgcnt; 7628ff550d0eSmasputra res |= INFOD_COUNT; 7629ff550d0eSmasputra } 7630ff550d0eSmasputra if (cmd & INFOD_BYTES) { 7631ff550d0eSmasputra /* 7632ff550d0eSmasputra * Return size of all data messages. 7633ff550d0eSmasputra */ 7634ff550d0eSmasputra dp->d_bytes += udp->udp_rcv_cnt; 7635ff550d0eSmasputra res |= INFOD_BYTES; 7636ff550d0eSmasputra } 7637ff550d0eSmasputra if (cmd & INFOD_FIRSTBYTES) { 7638ff550d0eSmasputra /* 7639ff550d0eSmasputra * Return size of first data message. 7640ff550d0eSmasputra */ 7641ff550d0eSmasputra dp->d_bytes = msgdsize(mp); 7642ff550d0eSmasputra res |= INFOD_FIRSTBYTES; 7643ff550d0eSmasputra dp->d_cmd &= ~INFOD_FIRSTBYTES; 7644ff550d0eSmasputra } 7645ff550d0eSmasputra if (cmd & INFOD_COPYOUT) { 7646ff550d0eSmasputra mblk_t *mp1 = mp->b_cont; 7647ff550d0eSmasputra int n; 7648ff550d0eSmasputra /* 7649ff550d0eSmasputra * Return data contents of first message. 7650ff550d0eSmasputra */ 7651ff550d0eSmasputra ASSERT(DB_TYPE(mp1) == M_DATA); 7652ff550d0eSmasputra while (mp1 != NULL && dp->d_uiop->uio_resid > 0) { 7653ff550d0eSmasputra n = MIN(dp->d_uiop->uio_resid, MBLKL(mp1)); 7654ff550d0eSmasputra if (n != 0 && (error = uiomove((char *)mp1->b_rptr, n, 7655ff550d0eSmasputra UIO_READ, dp->d_uiop)) != 0) { 7656ff550d0eSmasputra goto done; 7657ff550d0eSmasputra } 7658ff550d0eSmasputra mp1 = mp1->b_cont; 7659ff550d0eSmasputra } 7660ff550d0eSmasputra res |= INFOD_COPYOUT; 7661ff550d0eSmasputra dp->d_cmd &= ~INFOD_COPYOUT; 7662ff550d0eSmasputra } 7663ff550d0eSmasputra done: 7664ff550d0eSmasputra mutex_exit(&udp->udp_drain_lock); 7665ff550d0eSmasputra 7666ff550d0eSmasputra dp->d_res |= res; 7667ff550d0eSmasputra 7668ff550d0eSmasputra return (error); 7669ff550d0eSmasputra } 7670ff550d0eSmasputra 7671ff550d0eSmasputra /* 7672ff550d0eSmasputra * Read-side synchronous stream entry point. This is called as a result 7673ff550d0eSmasputra * of recv/read operation done at sockfs, and is guaranteed to execute 7674ff550d0eSmasputra * outside of the interrupt thread context. It returns a single datagram 7675ff550d0eSmasputra * (b_cont chain of T_UNITDATA_IND plus data) to the upper layer. 7676ff550d0eSmasputra */ 7677ff550d0eSmasputra static int 7678ff550d0eSmasputra udp_rrw(queue_t *q, struiod_t *dp) 7679ff550d0eSmasputra { 7680ff550d0eSmasputra mblk_t *mp; 7681ff550d0eSmasputra udp_t *udp = Q_TO_UDP(_RD(UDP_WR(q))); 7682ff550d0eSmasputra 7683ff550d0eSmasputra /* We should never get here when we're in SNMP mode */ 7684ff550d0eSmasputra ASSERT(!(udp->udp_connp->conn_flags & IPCL_UDPMOD)); 7685ff550d0eSmasputra 7686ff550d0eSmasputra /* 7687ff550d0eSmasputra * Dequeue datagram from the head of the list and return 7688ff550d0eSmasputra * it to caller; also ensure that RSLEEP sd_wakeq flag is 7689ff550d0eSmasputra * set/cleared depending on whether or not there's data 7690ff550d0eSmasputra * remaining in the list. 7691ff550d0eSmasputra */ 7692ff550d0eSmasputra mutex_enter(&udp->udp_drain_lock); 7693ff550d0eSmasputra if (!udp->udp_direct_sockfs) { 7694ff550d0eSmasputra mutex_exit(&udp->udp_drain_lock); 7695ff550d0eSmasputra UDP_STAT(udp_rrw_busy); 7696ff550d0eSmasputra return (EBUSY); 7697ff550d0eSmasputra } 7698ff550d0eSmasputra if ((mp = udp->udp_rcv_list_head) != NULL) { 7699ff550d0eSmasputra uint_t size = msgdsize(mp); 7700ff550d0eSmasputra 7701ff550d0eSmasputra /* Last datagram in the list? */ 7702ff550d0eSmasputra if ((udp->udp_rcv_list_head = mp->b_next) == NULL) 7703ff550d0eSmasputra udp->udp_rcv_list_tail = NULL; 7704ff550d0eSmasputra mp->b_next = NULL; 7705ff550d0eSmasputra 7706ff550d0eSmasputra udp->udp_rcv_cnt -= size; 7707ff550d0eSmasputra udp->udp_rcv_msgcnt--; 7708ff550d0eSmasputra UDP_STAT(udp_rrw_msgcnt); 7709ff550d0eSmasputra 7710ff550d0eSmasputra /* No longer flow-controlling? */ 7711ff550d0eSmasputra if (udp->udp_rcv_cnt < udp->udp_rcv_hiwat && 7712ff550d0eSmasputra udp->udp_rcv_msgcnt < udp->udp_rcv_hiwat) 7713ff550d0eSmasputra udp->udp_drain_qfull = B_FALSE; 7714ff550d0eSmasputra } 7715ff550d0eSmasputra if (udp->udp_rcv_list_head == NULL) { 7716ff550d0eSmasputra /* 7717ff550d0eSmasputra * Either we just dequeued the last datagram or 7718ff550d0eSmasputra * we get here from sockfs and have nothing to 7719ff550d0eSmasputra * return; in this case clear RSLEEP. 7720ff550d0eSmasputra */ 7721ff550d0eSmasputra ASSERT(udp->udp_rcv_cnt == 0); 7722ff550d0eSmasputra ASSERT(udp->udp_rcv_msgcnt == 0); 7723ff550d0eSmasputra ASSERT(udp->udp_rcv_list_tail == NULL); 7724ff550d0eSmasputra STR_WAKEUP_CLEAR(STREAM(q)); 7725ff550d0eSmasputra } else { 7726ff550d0eSmasputra /* 7727ff550d0eSmasputra * More data follows; we need udp_rrw() to be 7728ff550d0eSmasputra * called in future to pick up the rest. 7729ff550d0eSmasputra */ 7730ff550d0eSmasputra STR_WAKEUP_SET(STREAM(q)); 7731ff550d0eSmasputra } 7732ff550d0eSmasputra mutex_exit(&udp->udp_drain_lock); 7733ff550d0eSmasputra dp->d_mp = mp; 7734ff550d0eSmasputra return (0); 7735ff550d0eSmasputra } 7736ff550d0eSmasputra 7737ff550d0eSmasputra /* 7738ff550d0eSmasputra * Enqueue a completely-built T_UNITDATA_IND message into the receive 7739ff550d0eSmasputra * list; this is typically executed within the interrupt thread context 7740ff550d0eSmasputra * and so we do things as quickly as possible. 7741ff550d0eSmasputra */ 7742ff550d0eSmasputra static void 7743ff550d0eSmasputra udp_rcv_enqueue(queue_t *q, udp_t *udp, mblk_t *mp, uint_t pkt_len) 7744ff550d0eSmasputra { 7745ff550d0eSmasputra ASSERT(q == RD(q)); 7746ff550d0eSmasputra ASSERT(pkt_len == msgdsize(mp)); 7747ff550d0eSmasputra ASSERT(mp->b_next == NULL && mp->b_cont != NULL); 7748ff550d0eSmasputra ASSERT(DB_TYPE(mp) == M_PROTO && DB_TYPE(mp->b_cont) == M_DATA); 7749ff550d0eSmasputra ASSERT(MBLKL(mp) >= sizeof (struct T_unitdata_ind)); 7750ff550d0eSmasputra 7751ff550d0eSmasputra mutex_enter(&udp->udp_drain_lock); 7752ff550d0eSmasputra /* 7753ff550d0eSmasputra * Wake up and signal the receiving app; it is okay to do this 7754ff550d0eSmasputra * before enqueueing the mp because we are holding the drain lock. 7755ff550d0eSmasputra * One of the advantages of synchronous stream is the ability for 7756ff550d0eSmasputra * us to find out when the application performs a read on the 7757ff550d0eSmasputra * socket by way of udp_rrw() entry point being called. We need 7758ff550d0eSmasputra * to generate SIGPOLL/SIGIO for each received data in the case 7759ff550d0eSmasputra * of asynchronous socket just as in the strrput() case. However, 7760ff550d0eSmasputra * we only wake the application up when necessary, i.e. during the 7761ff550d0eSmasputra * first enqueue. When udp_rrw() is called, we send up a single 7762ff550d0eSmasputra * datagram upstream and call STR_WAKEUP_SET() again when there 7763ff550d0eSmasputra * are still data remaining in our receive queue. 7764ff550d0eSmasputra */ 7765ff550d0eSmasputra if (udp->udp_rcv_list_head == NULL) { 7766ff550d0eSmasputra STR_WAKEUP_SET(STREAM(q)); 7767ff550d0eSmasputra udp->udp_rcv_list_head = mp; 7768ff550d0eSmasputra } else { 7769ff550d0eSmasputra udp->udp_rcv_list_tail->b_next = mp; 7770ff550d0eSmasputra } 7771ff550d0eSmasputra udp->udp_rcv_list_tail = mp; 7772ff550d0eSmasputra udp->udp_rcv_cnt += pkt_len; 7773ff550d0eSmasputra udp->udp_rcv_msgcnt++; 7774ff550d0eSmasputra 7775ff550d0eSmasputra /* Need to flow-control? */ 7776ff550d0eSmasputra if (udp->udp_rcv_cnt >= udp->udp_rcv_hiwat || 7777ff550d0eSmasputra udp->udp_rcv_msgcnt >= udp->udp_rcv_hiwat) 7778ff550d0eSmasputra udp->udp_drain_qfull = B_TRUE; 7779ff550d0eSmasputra 7780ff550d0eSmasputra /* Update poll events and send SIGPOLL/SIGIO if necessary */ 7781ff550d0eSmasputra STR_SENDSIG(STREAM(q)); 7782ff550d0eSmasputra mutex_exit(&udp->udp_drain_lock); 7783ff550d0eSmasputra } 7784ff550d0eSmasputra 7785ff550d0eSmasputra /* 7786ff550d0eSmasputra * Drain the contents of receive list to the module upstream; we do 7787ff550d0eSmasputra * this during close or when we fallback to the slow mode due to 7788ff550d0eSmasputra * sockmod being popped or a module being pushed on top of us. 7789ff550d0eSmasputra */ 7790ff550d0eSmasputra static void 7791ff550d0eSmasputra udp_rcv_drain(queue_t *q, udp_t *udp, boolean_t closing) 7792ff550d0eSmasputra { 7793ff550d0eSmasputra mblk_t *mp; 7794ff550d0eSmasputra 7795ff550d0eSmasputra ASSERT(q == RD(q)); 7796ff550d0eSmasputra 7797ff550d0eSmasputra mutex_enter(&udp->udp_drain_lock); 7798ff550d0eSmasputra /* 7799ff550d0eSmasputra * There is no race with a concurrent udp_input() sending 7800ff550d0eSmasputra * up packets using putnext() after we have cleared the 7801ff550d0eSmasputra * udp_direct_sockfs flag but before we have completed 7802ff550d0eSmasputra * sending up the packets in udp_rcv_list, since we are 7803ff550d0eSmasputra * either a writer or we have quiesced the conn. 7804ff550d0eSmasputra */ 7805ff550d0eSmasputra udp->udp_direct_sockfs = B_FALSE; 7806ff550d0eSmasputra mutex_exit(&udp->udp_drain_lock); 7807ff550d0eSmasputra 7808ff550d0eSmasputra if (udp->udp_rcv_list_head != NULL) 7809ff550d0eSmasputra UDP_STAT(udp_drain); 7810ff550d0eSmasputra 7811ff550d0eSmasputra /* 7812ff550d0eSmasputra * Send up everything via putnext(); note here that we 7813ff550d0eSmasputra * don't need the udp_drain_lock to protect us since 7814ff550d0eSmasputra * nothing can enter udp_rrw() and that we currently 7815ff550d0eSmasputra * have exclusive access to this udp. 7816ff550d0eSmasputra */ 7817ff550d0eSmasputra while ((mp = udp->udp_rcv_list_head) != NULL) { 7818ff550d0eSmasputra udp->udp_rcv_list_head = mp->b_next; 7819ff550d0eSmasputra mp->b_next = NULL; 7820ff550d0eSmasputra udp->udp_rcv_cnt -= msgdsize(mp); 7821ff550d0eSmasputra udp->udp_rcv_msgcnt--; 7822ff550d0eSmasputra if (closing) { 7823ff550d0eSmasputra freemsg(mp); 7824ff550d0eSmasputra } else { 7825ff550d0eSmasputra putnext(q, mp); 7826ff550d0eSmasputra } 7827ff550d0eSmasputra } 7828ff550d0eSmasputra ASSERT(udp->udp_rcv_cnt == 0); 7829ff550d0eSmasputra ASSERT(udp->udp_rcv_msgcnt == 0); 7830ff550d0eSmasputra ASSERT(udp->udp_rcv_list_head == NULL); 7831ff550d0eSmasputra udp->udp_rcv_list_tail = NULL; 7832ff550d0eSmasputra udp->udp_drain_qfull = B_FALSE; 7833ff550d0eSmasputra } 7834ff550d0eSmasputra 7835ff550d0eSmasputra static size_t 7836ff550d0eSmasputra udp_set_rcv_hiwat(udp_t *udp, size_t size) 7837ff550d0eSmasputra { 7838ff550d0eSmasputra /* We add a bit of extra buffering */ 7839ff550d0eSmasputra size += size >> 1; 7840ff550d0eSmasputra if (size > udp_max_buf) 7841ff550d0eSmasputra size = udp_max_buf; 7842ff550d0eSmasputra 7843ff550d0eSmasputra udp->udp_rcv_hiwat = size; 7844ff550d0eSmasputra return (size); 7845ff550d0eSmasputra } 7846ff550d0eSmasputra 78477c478bd9Sstevel@tonic-gate /* 78487c478bd9Sstevel@tonic-gate * Little helper for IPsec's NAT-T processing. 78497c478bd9Sstevel@tonic-gate */ 78507c478bd9Sstevel@tonic-gate boolean_t 78517c478bd9Sstevel@tonic-gate udp_compute_checksum(void) 78527c478bd9Sstevel@tonic-gate { 78537c478bd9Sstevel@tonic-gate return (udp_do_checksum); 78547c478bd9Sstevel@tonic-gate } 7855