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 (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright (c) 1990 Mentat Inc.
24 */
25
26 #include <sys/ib/clients/rds/rds.h>
27 #include <inet/proto_set.h>
28
29 #define rds_max_buf 2097152
30 opdes_t rds_opt_arr[] = {
31
32 { SO_TYPE, SOL_SOCKET, OA_R, OA_R, OP_NP, 0, sizeof (int), 0 },
33 { SO_SNDBUF, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
34 { SO_RCVBUF, SOL_SOCKET, OA_RW, OA_RW, OP_NP, 0, sizeof (int), 0 },
35 };
36
37 /* ARGSUSED */
38 int
rds_opt_default(queue_t * q,t_scalar_t level,t_scalar_t name,uchar_t * ptr)39 rds_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 */
49 int
rds_opt_get(queue_t * q,t_scalar_t level,t_scalar_t name,uchar_t * ptr)50 rds_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 */
79 int
rds_opt_set(queue_t * q,uint_t optset_context,int level,int name,uint_t inlen,uchar_t * invalp,uint_t * outlenp,uchar_t * outvalp,void * thisdg_attrs,cred_t * cr)80 rds_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)
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 }
135 break;
136 case SO_RCVBUF:
137 if (*i1 > rds_max_buf) {
138 *outlenp = 0;
139 return (ENOBUFS);
140 }
141 if (!checkonly) {
142 RD(q)->q_hiwat = *i1;
143 (void) proto_set_rx_hiwat(RD(q), NULL, *i1);
144 }
145 break;
146 default:
147 *outlenp = 0;
148 return (EINVAL);
149 }
150 break;
151 default:
152 *outlenp = 0;
153 return (EINVAL);
154 }
155 /*
156 * Common case of OK return with outval same as inval.
157 */
158 if (invalp != outvalp) {
159 /* don't trust bcopy for identical src/dst */
160 (void) bcopy(invalp, outvalp, inlen);
161 }
162 *outlenp = inlen;
163 return (0);
164 }
165
166 uint_t rds_max_optsize; /* initialized when RDS driver is loaded */
167
168 #define RDS_VALID_LEVELS_CNT A_CNT(rds_valid_levels_arr)
169
170 #define RDS_OPT_ARR_CNT A_CNT(rds_opt_arr)
171
172
173 optlevel_t rds_valid_levels_arr[] = {
174 SOL_SOCKET,
175 };
176
177 /*
178 * Initialize option database object for RDS
179 *
180 * This object represents database of options to search passed to
181 * {sock,tpi}optcom_req() interface routine to take care of option
182 * management and associated methods.
183 */
184
185 optdb_obj_t rds_opt_obj = {
186 rds_opt_default, /* RDS default value function pointer */
187 rds_opt_get, /* RDS get function pointer */
188 rds_opt_set, /* RDS set function pointer */
189 RDS_OPT_ARR_CNT, /* RDS option database count of entries */
190 rds_opt_arr, /* RDS option database */
191 RDS_VALID_LEVELS_CNT, /* RDS valid level count of entries */
192 rds_valid_levels_arr /* RDS valid level array */
193 };
194