rds_opt.c revision 8348:4137e18bfaf0
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26#include <sys/ib/clients/rds/rds.h>
27#include <inet/proto_set.h>
28
29#define	rds_max_buf 2097152
30opdes_t rds_opt_arr[] = {
31
32{ SO_TYPE,	SOL_SOCKET, OA_R, OA_R, OP_NP, OP_PASSNEXT, sizeof (int), 0 },
33{ SO_SNDBUF,	SOL_SOCKET, OA_RW, OA_RW, OP_NP, OP_PASSNEXT, sizeof (int), 0 },
34{ SO_RCVBUF,	SOL_SOCKET, OA_RW, OA_RW, OP_NP, OP_PASSNEXT, sizeof (int), 0 },
35};
36
37/* ARGSUSED */
38int
39rds_opt_default(queue_t *q, t_scalar_t level, t_scalar_t name, uchar_t *ptr)
40{
41	/* no default value processed by protocol specific code currently */
42	return (-1);
43}
44
45/*
46 * This routine retrieves the current status of socket options.
47 * It returns the size of the option retrieved.
48 */
49int
50rds_opt_get(queue_t *q, t_scalar_t level, t_scalar_t name, uchar_t *ptr)
51{
52	int	*i1 = (int *)(uintptr_t)ptr;
53
54	switch (level) {
55	case SOL_SOCKET:
56		switch (name) {
57		case SO_TYPE:
58			*i1 = SOCK_DGRAM;
59			break;	/* goto sizeof (int) option return */
60
61		case SO_SNDBUF:
62			*i1 = q->q_hiwat;
63			break;	/* goto sizeof (int) option return */
64		case SO_RCVBUF:
65			*i1 = RD(q)->q_hiwat;
66			break;	/* goto sizeof (int) option return */
67		default:
68			return (-1);
69		}
70		break;
71	default:
72		return (-1);
73	}
74	return (sizeof (int));
75}
76
77/* This routine sets socket options. */
78/* ARGSUSED */
79int
80rds_opt_set(queue_t *q, uint_t optset_context, int level,
81    int name, uint_t inlen, uchar_t *invalp, uint_t *outlenp,
82    uchar_t *outvalp, void *thisdg_attrs, cred_t *cr, mblk_t *mblk)
83{
84	int	*i1 = (int *)(uintptr_t)invalp;
85	boolean_t checkonly;
86
87	switch (optset_context) {
88	case SETFN_OPTCOM_CHECKONLY:
89		checkonly = B_TRUE;
90		/*
91		 * Note: Implies T_CHECK semantics for T_OPTCOM_REQ
92		 * inlen != 0 implies value supplied and
93		 * 	we have to "pretend" to set it.
94		 * inlen == 0 implies that there is no
95		 * 	value part in T_CHECK request and just validation
96		 * done elsewhere should be enough, we just return here.
97		 */
98		if (inlen == 0) {
99			*outlenp = 0;
100			return (0);
101		}
102		break;
103	case SETFN_OPTCOM_NEGOTIATE:
104		checkonly = B_FALSE;
105		break;
106	default:
107		/*
108		 * We should never get here
109		 */
110		*outlenp = 0;
111		return (EINVAL);
112	}
113
114	ASSERT((optset_context != SETFN_OPTCOM_CHECKONLY) ||
115	    (optset_context == SETFN_OPTCOM_CHECKONLY && inlen != 0));
116
117	/*
118	 * For fixed length options, no sanity check
119	 * of passed in length is done. It is assumed *_optcom_req()
120	 * routines do the right thing.
121	 */
122
123	switch (level) {
124	case SOL_SOCKET:
125		switch (name) {
126
127		case SO_SNDBUF:
128			if (*i1 > rds_max_buf) {
129				*outlenp = 0;
130				return (ENOBUFS);
131			}
132			if (!checkonly) {
133				q->q_hiwat = *i1;
134				q->q_next->q_hiwat = *i1;
135			}
136			break;
137		case SO_RCVBUF:
138			if (*i1 > rds_max_buf) {
139				*outlenp = 0;
140				return (ENOBUFS);
141			}
142			if (!checkonly) {
143				RD(q)->q_hiwat = *i1;
144				(void) proto_set_rx_hiwat(RD(q), NULL, *i1);
145			}
146			break;
147		default:
148			*outlenp = 0;
149			return (EINVAL);
150		}
151		break;
152	default:
153		*outlenp = 0;
154		return (EINVAL);
155	}
156	/*
157	 * Common case of OK return with outval same as inval.
158	 */
159	if (invalp != outvalp) {
160		/* don't trust bcopy for identical src/dst */
161		(void) bcopy(invalp, outvalp, inlen);
162	}
163	*outlenp = inlen;
164	return (0);
165}
166
167uint_t rds_max_optsize; /* initialized when RDS driver is loaded */
168
169#define	RDS_VALID_LEVELS_CNT	A_CNT(rds_valid_levels_arr)
170
171#define	RDS_OPT_ARR_CNT		A_CNT(rds_opt_arr)
172
173
174optlevel_t rds_valid_levels_arr[] = {
175	SOL_SOCKET,
176};
177
178/*
179 * Initialize option database object for RDS
180 *
181 * This object represents database of options to search passed to
182 * {sock,tpi}optcom_req() interface routine to take care of option
183 * management and associated methods.
184 */
185
186optdb_obj_t rds_opt_obj = {
187	rds_opt_default,	/* RDS default value function pointer */
188	rds_opt_get,		/* RDS get function pointer */
189	rds_opt_set,		/* RDS set function pointer */
190	B_TRUE,			/* RDS is tpi provider */
191	RDS_OPT_ARR_CNT,	/* RDS option database count of entries */
192	rds_opt_arr,		/* RDS option database */
193	RDS_VALID_LEVELS_CNT,	/* RDS valid level count of entries */
194	rds_valid_levels_arr	/* RDS valid level array */
195};
196