4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <sys/types.h>
27 #include <inet/common.h>
28 #include <sys/stream.h>
29 #include <sys/stropts.h>
30 #include <sys/strsun.h>
31 #include <sys/sysmacros.h>
32 #include <sys/stropts.h>
33 #include <sys/strsubr.h>
34 #include <sys/tpicommon.h>
35 #include <sys/socket_proto.h>
36 #include <sys/policy.h>
37 #include <inet/optcom.h>
38 #include <inet/ipclassifier.h>
41 proto_set_rx_hiwat(queue_t
*q
, conn_t
*connp
, size_t size
)
44 if (connp
!= NULL
&& IPCL_IS_NONSTR(connp
)) {
45 struct sock_proto_props sopp
;
47 sopp
.sopp_flags
= SOCKOPT_RCVHIWAT
;
48 sopp
.sopp_rxhiwat
= size
;
49 (*connp
->conn_upcalls
->su_set_proto_props
)
50 (connp
->conn_upper_handle
, &sopp
);
53 struct stroptions
*stropt
;
55 if (!(mp
= allocb(sizeof (*stropt
), BPRI_LO
)))
57 mp
->b_datap
->db_type
= M_SETOPTS
;
58 mp
->b_wptr
+= sizeof (*stropt
);
59 stropt
= (struct stroptions
*)mp
->b_rptr
;
60 stropt
->so_flags
= SO_HIWAT
;
61 stropt
->so_hiwat
= size
;
68 proto_set_rx_lowat(queue_t
*q
, conn_t
*connp
, size_t size
)
71 if (connp
!= NULL
&& IPCL_IS_NONSTR(connp
)) {
72 struct sock_proto_props sopp
;
74 sopp
.sopp_flags
= SOCKOPT_RCVLOWAT
;
75 sopp
.sopp_rxlowat
= size
;
76 (*connp
->conn_upcalls
->su_set_proto_props
)
77 (connp
->conn_upper_handle
, &sopp
);
80 struct stroptions
*stropt
;
82 if (!(mp
= allocb(sizeof (*stropt
), BPRI_LO
)))
84 mp
->b_datap
->db_type
= M_SETOPTS
;
85 mp
->b_wptr
+= sizeof (*stropt
);
86 stropt
= (struct stroptions
*)mp
->b_rptr
;
87 stropt
->so_flags
= SO_LOWAT
;
88 stropt
->so_lowat
= size
;
95 * Set maximum packet size. This is the maximum amount of data the protocol
96 * wants to be given at any time, Larger data needs to be broken in multiples
97 * of maximum packet size and given to the protocol one at a time.
100 proto_set_maxpsz(queue_t
*q
, conn_t
*connp
, size_t size
)
102 if (connp
!= NULL
&& IPCL_IS_NONSTR(connp
)) {
103 struct sock_proto_props sopp
;
105 sopp
.sopp_flags
= SOCKOPT_MAXPSZ
;
106 sopp
.sopp_maxpsz
= size
;
107 (*connp
->conn_upcalls
->su_set_proto_props
)
108 (connp
->conn_upper_handle
, &sopp
);
116 * At this point change of a queue parameter is not allowed
117 * when a multiplexor is sitting on top.
119 if (stp
== NULL
|| stp
->sd_flag
& STPLEX
)
122 claimstr(stp
->sd_wrq
);
123 wq
= stp
->sd_wrq
->q_next
;
125 (void) strqset(wq
, QMAXPSZ
, 0, size
);
126 releasestr(stp
->sd_wrq
);
133 proto_set_tx_maxblk(queue_t
*q
, conn_t
*connp
, ssize_t size
)
135 if (connp
!= NULL
&& IPCL_IS_NONSTR(connp
)) {
136 struct sock_proto_props sopp
;
138 sopp
.sopp_flags
= SOCKOPT_MAXBLK
;
139 sopp
.sopp_maxblk
= size
;
140 (*connp
->conn_upcalls
->su_set_proto_props
)
141 (connp
->conn_upper_handle
, &sopp
);
144 struct stroptions
*stropt
;
146 if (!(mp
= allocb(sizeof (*stropt
), BPRI_LO
)))
148 mp
->b_datap
->db_type
= M_SETOPTS
;
149 mp
->b_wptr
+= sizeof (*stropt
);
150 stropt
= (struct stroptions
*)mp
->b_rptr
;
151 stropt
->so_flags
= SO_MAXBLK
;
152 stropt
->so_maxblk
= size
;
159 proto_set_tx_copyopt(queue_t
*q
, conn_t
*connp
, int copyopt
)
161 if (connp
!= NULL
&& IPCL_IS_NONSTR(connp
)) {
162 struct sock_proto_props sopp
;
164 sopp
.sopp_flags
= SOCKOPT_ZCOPY
;
165 sopp
.sopp_zcopyflag
= (ushort_t
)copyopt
;
166 (*connp
->conn_upcalls
->su_set_proto_props
)
167 (connp
->conn_upper_handle
, &sopp
);
170 struct stroptions
*stropt
;
172 if (!(mp
= allocb(sizeof (*stropt
), BPRI_LO
)))
174 mp
->b_datap
->db_type
= M_SETOPTS
;
175 mp
->b_wptr
+= sizeof (*stropt
);
176 stropt
= (struct stroptions
*)mp
->b_rptr
;
177 stropt
->so_flags
= SO_COPYOPT
;
178 stropt
->so_copyopt
= (ushort_t
)copyopt
;
185 proto_set_tx_wroff(queue_t
*q
, conn_t
*connp
, size_t size
)
187 if (connp
!= NULL
&& IPCL_IS_NONSTR(connp
)) {
188 struct sock_proto_props sopp
;
190 sopp
.sopp_flags
= SOCKOPT_WROFF
;
191 sopp
.sopp_wroff
= size
;
193 /* XXX workaround for CR6757374 */
194 if (connp
->conn_upper_handle
!= NULL
)
195 (*connp
->conn_upcalls
->su_set_proto_props
)
196 (connp
->conn_upper_handle
, &sopp
);
200 struct stroptions
*stropt
;
201 if (!(mp
= allocb(sizeof (*stropt
), BPRI_LO
)))
203 mp
->b_datap
->db_type
= M_SETOPTS
;
204 mp
->b_wptr
+= sizeof (*stropt
);
205 stropt
= (struct stroptions
*)mp
->b_rptr
;
206 stropt
->so_flags
= SO_WROFF
;
207 stropt
->so_wroff
= (ushort_t
)size
;
214 * set OOBINLINE processing on the socket
217 proto_set_rx_oob_opt(conn_t
*connp
, boolean_t onoff
)
219 struct sock_proto_props sopp
;
221 ASSERT(IPCL_IS_NONSTR(connp
));
223 sopp
.sopp_flags
= SOCKOPT_OOBINLINE
;
224 sopp
.sopp_oobinline
= onoff
;
225 (*connp
->conn_upcalls
->su_set_proto_props
)
226 (connp
->conn_upper_handle
, &sopp
);
230 * Translate a TLI(/XTI) error into a system error as best we can.
232 static const int tli_errs
[] = {
234 EADDRNOTAVAIL
, /* TBADADDR */
235 ENOPROTOOPT
, /* TBADOPT */
238 EADDRNOTAVAIL
, /* TNOADDR */
239 EPROTO
, /* TOUTSTATE */
240 ECONNABORTED
, /* TBADSEQ */
241 0, /* TSYSERR - will never get */
242 EPROTO
, /* TLOOK - should never be sent by transport */
243 EMSGSIZE
, /* TBADDATA */
244 EMSGSIZE
, /* TBUFOVFLW */
246 EWOULDBLOCK
, /* TNODATA */
248 EPROTO
, /* TNOUDERR */
249 EINVAL
, /* TBADFLAG */
251 EOPNOTSUPP
, /* TNOTSUPPORT */
252 EPROTO
, /* TSTATECHNG */
253 /* following represent error namespace expansion with XTI */
254 EPROTO
, /* TNOSTRUCTYPE - never sent by transport */
255 EPROTO
, /* TBADNAME - never sent by transport */
256 EPROTO
, /* TBADQLEN - never sent by transport */
257 EADDRINUSE
, /* TADDRBUSY */
259 EBADF
, /* TPROVMISMATCH */
260 EBADF
, /* TRESQLEN */
261 EBADF
, /* TRESADDR */
262 EPROTO
, /* TQFULL - never sent by transport */
267 proto_tlitosyserr(int terr
)
269 ASSERT(terr
!= TSYSERR
);
270 if (terr
>= (sizeof (tli_errs
) / sizeof (tli_errs
[0])))
273 return (tli_errs
[terr
]);
277 * Verify that address is suitable for connect/sendmsg and is aligned properly
278 * Since this is a generic function we do not test for port being zero
279 * as some protocols like icmp do not require a port
282 proto_verify_ip_addr(int family
, const struct sockaddr
*name
, socklen_t namelen
)
285 if (name
== NULL
|| !OK_32PTR((char *)name
))
290 if (name
->sa_family
!= AF_INET
) {
291 return (EAFNOSUPPORT
);
294 if (namelen
!= (socklen_t
)sizeof (struct sockaddr_in
)) {
300 struct sockaddr_in6
*sin6
;
303 if (name
->sa_family
!= AF_INET6
) {
304 return (EAFNOSUPPORT
);
306 if (namelen
!= (socklen_t
)sizeof (struct sockaddr_in6
)) {
310 /* Verify that apps don't forget to clear sin6_scope_id etc */
311 sin6
= (struct sockaddr_in6
*)name
;
312 if (sin6
->sin6_scope_id
!= 0 &&
313 !IN6_IS_ADDR_LINKSCOPE(&sin6
->sin6_addr
)) {
314 zcmn_err(getzoneid(), CE_WARN
,
315 "connect/send* with uninitialized sin6_scope_id "
316 "(%d) on socket. Pid = %d\n",
317 (int)sin6
->sin6_scope_id
, (int)curproc
->p_pid
);
330 * Do a lookup of the options in the array.
331 * Rerurn NULL if there isn't a match.
334 proto_opt_lookup(t_uscalar_t level
, t_uscalar_t name
, opdes_t
*opt_arr
,
339 for (optd
= opt_arr
; optd
< &opt_arr
[opt_arr_cnt
];
341 if (level
== (uint_t
)optd
->opdes_level
&&
342 name
== (uint_t
)optd
->opdes_name
)
349 * Do a lookup of the options in the array and do permission and length checking
350 * Returns zero if there is no error (note: for non-tpi-providers not being able
351 * to find the option is not an error). TPI errors are returned as negative
352 * numbers and errnos as positive numbers.
353 * If max_len is set we update it based on the max length of the option.
356 proto_opt_check(int level
, int name
, int len
, t_uscalar_t
*max_len
,
357 opdes_t
*opt_arr
, uint_t opt_arr_cnt
, boolean_t negotiate
, boolean_t check
,
362 /* Find the option in the opt_arr. */
363 optd
= proto_opt_lookup(level
, name
, opt_arr
, opt_arr_cnt
);
367 /* Additional checks dependent on operation. */
369 /* Cannot be true at the same time */
370 ASSERT(check
== B_FALSE
);
372 if (!OA_WRITE_OR_EXECUTE(optd
, cr
)) {
373 /* can't negotiate option */
374 if (!(OA_MATCHED_PRIV(optd
, cr
)) &&
375 OA_WX_ANYPRIV(optd
)) {
377 * not privileged but privilege
378 * will help negotiate option.
386 * Verify size for options
387 * Note: For retaining compatibility with historical
388 * behavior, variable lengths options will have their
389 * length verified in the setfn() processing.
390 * In order to be compatible with SunOS 4.X we return
391 * EINVAL errors for bad lengths.
393 if (!(optd
->opdes_props
& OP_VARLEN
)) {
394 /* fixed length - size must match */
395 if (len
!= optd
->opdes_size
) {
401 if (!OA_RWX_ANYPRIV(optd
))
402 /* any of "rwx" permission but not none */
406 * XXX Since T_CURRENT was not there in TLI and the
407 * official TLI inspired TPI standard, getsockopt()
408 * API uses T_CHECK (for T_CURRENT semantics)
409 * Thus T_CHECK includes the T_CURRENT semantics due to that
412 if (!OA_READ_PERMISSION(optd
, cr
)) {
413 /* can't read option value */
414 if (!(OA_MATCHED_PRIV(optd
, cr
)) &&
415 OA_R_ANYPRIV(optd
)) {
417 * not privileged but privilege
418 * will help in reading option value.
427 *max_len
= optd
->opdes_size
;
429 /* We liked it. Keep going. */