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 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 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 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 };