xref: /illumos-gate/usr/src/uts/common/io/ib/clients/rds/rds_opt.c (revision b86efd96f8acd85ddaa930a2f0c1d664237e4aaf)
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 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <sys/ib/clients/rds/rds.h>
29 #include <inet/mi.h>
30 
31 #define	rds_max_buf 2097152
32 opdes_t rds_opt_arr[] = {
33 
34 { SO_TYPE,	SOL_SOCKET, OA_R, OA_R, OP_NP, OP_PASSNEXT, sizeof (int), 0 },
35 { SO_SNDBUF,	SOL_SOCKET, OA_RW, OA_RW, OP_NP, OP_PASSNEXT, sizeof (int), 0 },
36 { SO_RCVBUF,	SOL_SOCKET, OA_RW, OA_RW, OP_NP, OP_PASSNEXT, sizeof (int), 0 },
37 };
38 
39 /* ARGSUSED */
40 int
41 rds_opt_default(queue_t *q, t_scalar_t level, t_scalar_t name, uchar_t *ptr)
42 {
43 	/* no default value processed by protocol specific code currently */
44 	return (-1);
45 }
46 
47 /*
48  * This routine retrieves the current status of socket options.
49  * It returns the size of the option retrieved.
50  */
51 int
52 rds_opt_get(queue_t *q, t_scalar_t level, t_scalar_t name, uchar_t *ptr)
53 {
54 	int	*i1 = (int *)(uintptr_t)ptr;
55 
56 	switch (level) {
57 	case SOL_SOCKET:
58 		switch (name) {
59 		case SO_TYPE:
60 			*i1 = SOCK_DGRAM;
61 			break;	/* goto sizeof (int) option return */
62 
63 		case SO_SNDBUF:
64 			*i1 = q->q_hiwat;
65 			break;	/* goto sizeof (int) option return */
66 		case SO_RCVBUF:
67 			*i1 = RD(q)->q_hiwat;
68 			break;	/* goto sizeof (int) option return */
69 		default:
70 			return (-1);
71 		}
72 		break;
73 	default:
74 		return (-1);
75 	}
76 	return (sizeof (int));
77 }
78 
79 /* This routine sets socket options. */
80 /* ARGSUSED */
81 int
82 rds_opt_set(queue_t *q, uint_t optset_context, int level,
83     int name, uint_t inlen, uchar_t *invalp, uint_t *outlenp,
84     uchar_t *outvalp, void *thisdg_attrs, cred_t *cr, mblk_t *mblk)
85 {
86 	int	*i1 = (int *)(uintptr_t)invalp;
87 	boolean_t checkonly;
88 
89 	switch (optset_context) {
90 	case SETFN_OPTCOM_CHECKONLY:
91 		checkonly = B_TRUE;
92 		/*
93 		 * Note: Implies T_CHECK semantics for T_OPTCOM_REQ
94 		 * inlen != 0 implies value supplied and
95 		 * 	we have to "pretend" to set it.
96 		 * inlen == 0 implies that there is no
97 		 * 	value part in T_CHECK request and just validation
98 		 * done elsewhere should be enough, we just return here.
99 		 */
100 		if (inlen == 0) {
101 			*outlenp = 0;
102 			return (0);
103 		}
104 		break;
105 	case SETFN_OPTCOM_NEGOTIATE:
106 		checkonly = B_FALSE;
107 		break;
108 	default:
109 		/*
110 		 * We should never get here
111 		 */
112 		*outlenp = 0;
113 		return (EINVAL);
114 	}
115 
116 	ASSERT((optset_context != SETFN_OPTCOM_CHECKONLY) ||
117 	    (optset_context == SETFN_OPTCOM_CHECKONLY && inlen != 0));
118 
119 	/*
120 	 * For fixed length options, no sanity check
121 	 * of passed in length is done. It is assumed *_optcom_req()
122 	 * routines do the right thing.
123 	 */
124 
125 	switch (level) {
126 	case SOL_SOCKET:
127 		switch (name) {
128 
129 		case SO_SNDBUF:
130 			if (*i1 > rds_max_buf) {
131 				*outlenp = 0;
132 				return (ENOBUFS);
133 			}
134 			if (!checkonly) {
135 				q->q_hiwat = *i1;
136 				q->q_next->q_hiwat = *i1;
137 			}
138 			break;
139 		case SO_RCVBUF:
140 			if (*i1 > rds_max_buf) {
141 				*outlenp = 0;
142 				return (ENOBUFS);
143 			}
144 			if (!checkonly) {
145 				RD(q)->q_hiwat = *i1;
146 				(void) mi_set_sth_hiwat(RD(q), *i1);
147 			}
148 			break;
149 		default:
150 			*outlenp = 0;
151 			return (EINVAL);
152 		}
153 		break;
154 	default:
155 		*outlenp = 0;
156 		return (EINVAL);
157 	}
158 	/*
159 	 * Common case of OK return with outval same as inval.
160 	 */
161 	if (invalp != outvalp) {
162 		/* don't trust bcopy for identical src/dst */
163 		(void) bcopy(invalp, outvalp, inlen);
164 	}
165 	*outlenp = inlen;
166 	return (0);
167 }
168 
169 uint_t rds_max_optsize; /* initialized when RDS driver is loaded */
170 
171 #define	RDS_VALID_LEVELS_CNT	A_CNT(rds_valid_levels_arr)
172 
173 #define	RDS_OPT_ARR_CNT		A_CNT(rds_opt_arr)
174 
175 
176 optlevel_t rds_valid_levels_arr[] = {
177 	SOL_SOCKET,
178 };
179 
180 /*
181  * Initialize option database object for RDS
182  *
183  * This object represents database of options to search passed to
184  * {sock,tpi}optcom_req() interface routine to take care of option
185  * management and associated methods.
186  */
187 
188 optdb_obj_t rds_opt_obj = {
189 	rds_opt_default,	/* RDS default value function pointer */
190 	rds_opt_get,		/* RDS get function pointer */
191 	rds_opt_set,		/* RDS set function pointer */
192 	B_TRUE,			/* RDS is tpi provider */
193 	RDS_OPT_ARR_CNT,	/* RDS option database count of entries */
194 	rds_opt_arr,		/* RDS option database */
195 	RDS_VALID_LEVELS_CNT,	/* RDS valid level count of entries */
196 	rds_valid_levels_arr	/* RDS valid level array */
197 };
198