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 (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
24 /* Copyright (c) 1990 Mentat Inc. */
27 * This file contains common code for handling Options Management requests
31 #include <sys/types.h>
32 #include <sys/stream.h>
33 #include <sys/stropts.h>
34 #include <sys/errno.h>
35 #define _SUN_TPI_VERSION 2
36 #include <sys/tihdr.h>
38 #include <sys/cmn_err.h>
39 #include <sys/policy.h>
41 #include <sys/socket.h>
42 #include <netinet/in.h>
44 #include <inet/common.h>
46 #include <inet/mib2.h>
47 #include <inet/optcom.h>
48 #include <inet/snmpcom.h>
51 #include <sys/brand.h>
53 #define DEFAULT_LENGTH sizeof (long)
54 #define DATA_MBLK_SIZE 1024
55 #define TOAHDR_SIZE (sizeof (struct T_optmgmt_ack) +\
56 sizeof (struct opthdr))
58 /* SNMP Option Request Structure */
59 typedef struct sor_s
{
61 int sor_code
; /* MIB2 index value */
66 * Validation Table for set requests.
68 static sor_t req_arr
[] = {
69 { MIB2_IP
, 1, sizeof (int) },
70 { MIB2_IP
, 2, sizeof (int) },
71 { MIB2_IP
, 21, sizeof (mib2_ipRouteEntry_t
) },
72 { MIB2_IP
, 22, sizeof (mib2_ipNetToMediaEntry_t
)},
73 { MIB2_TCP
, 13, sizeof (mib2_tcpConnEntry_t
) }
77 * Binary compatibility to what used to be T_CURRENT in older releases.
78 * Unfortunately, the binary chosen for it was different and used by
79 * T_PARTSUCCESS in the new name space. However T_PARTSUCESS is only
80 * anticiapted in new T_OPTMGM_REQ (and not O_T_OPTMGMT_REQ messages).
81 * Only a test for TBADFLAG which uses one of the MIB option levels
82 * may have trouble with this provision for binary compatibility.
84 #define OLD_T_CURRENT 0x100 /* same value as T_PARTSUCCESS */
87 * MIB info returned in data part of M_PROTO msg. All info for a single
88 * request is appended in a chain of mblk's off of the M_PROTO T_OPTMGMT_ACK
92 snmp_append_data(mblk_t
*mpdata
, char *blob
, int len
)
97 while (mpdata
->b_cont
)
98 mpdata
= mpdata
->b_cont
;
99 if (mpdata
->b_wptr
+ len
>= mpdata
->b_datap
->db_lim
) {
100 mpdata
->b_cont
= allocb(DATA_MBLK_SIZE
, BPRI_HI
);
101 mpdata
= mpdata
->b_cont
;
105 bcopy(blob
, (char *)mpdata
->b_wptr
, len
);
106 mpdata
->b_wptr
+= len
;
111 * Need a form which avoids O(n^2) behavior locating the end of the
112 * chain every time. This is it.
115 snmp_append_data2(mblk_t
*mpdata
, mblk_t
**last_mpp
, char *blob
, int len
)
120 if (*last_mpp
== NULL
) {
121 while (mpdata
->b_cont
)
122 mpdata
= mpdata
->b_cont
;
125 if ((*last_mpp
)->b_wptr
+ len
>= (*last_mpp
)->b_datap
->db_lim
) {
126 (*last_mpp
)->b_cont
= allocb(DATA_MBLK_SIZE
, BPRI_HI
);
127 *last_mpp
= (*last_mpp
)->b_cont
;
131 bcopy(blob
, (char *)(*last_mpp
)->b_wptr
, len
);
132 (*last_mpp
)->b_wptr
+= len
;
137 * SNMP requests are issued using putmsg() on a stream containing all
138 * relevant modules. The ctl part contains a O_T_OPTMGMT_REQ message,
139 * and the data part is NULL
140 * to process this msg. If snmpcom_req() returns FALSE, then the module
141 * will try optcom_req to see if its some sort of SOCKET or IP option.
142 * snmpcom_req returns TRUE whenever the first option is recognized as
143 * an SNMP request, even if a bad one.
145 * "get" is done by a single O_T_OPTMGMT_REQ with MGMT_flags set to T_CURRENT.
146 * All modules respond with one or msg's about what they know. Responses
147 * are in T_OPTMGMT_ACK format. The opthdr level/name fields identify what
148 * is begin returned, the len field how big it is (in bytes). The info
149 * itself is in the data portion of the msg. Fixed length info returned
150 * in one msg; each table in a separate msg.
152 * setfn() returns 1 if things ok, 0 if set request invalid or otherwise
155 * If the passed q is at the bottom of the module chain (q_next == NULL,
156 * a ctl msg with req->name, level, len all zero is sent upstream. This
157 * is and EOD flag to the caller.
160 * - The msg type is M_PROTO, not M_PCPROTO!!! This is by design,
161 * since multiple messages will be sent to stream head and we want
162 * them queued for reading, not discarded.
163 * - All requests which match a table entry are sent to all get/set functions
164 * of each module. The functions must simply ignore requests not meant
165 * for them: getfn() returns 0, setfn() returns 1.
168 snmpcom_req(queue_t
*q
, mblk_t
*mp
, pfi_t setfn
, pfi_t getfn
, cred_t
*credp
)
172 struct opthdr
*next_req
;
173 struct opthdr
*req_end
;
174 struct opthdr
*req_start
;
176 struct T_optmgmt_req
*tor
= (struct T_optmgmt_req
*)mp
->b_rptr
;
177 struct T_optmgmt_ack
*toa
;
178 boolean_t legacy_req
;
180 if (mp
->b_cont
) { /* don't deal with multiple mblk's */
182 mp
->b_cont
= (mblk_t
*)0;
183 optcom_err_ack(q
, mp
, TSYSERR
, EBADMSG
);
186 if ((mp
->b_wptr
- mp
->b_rptr
) < sizeof (struct T_optmgmt_req
) ||
187 !(req_start
= (struct opthdr
*)mi_offset_param(mp
,
188 tor
->OPT_offset
, tor
->OPT_length
)))
190 if (! __TPI_OPT_ISALIGNED(req_start
))
194 * if first option not in the MIB2 or EXPER range, return false so
195 * optcom_req can scope things out. Otherwise it's passed to each
196 * calling module to process or ignore as it sees fit.
198 if ((!(req_start
->level
>= MIB2_RANGE_START
&&
199 req_start
->level
<= MIB2_RANGE_END
)) &&
200 (!(req_start
->level
>= EXPER_RANGE_START
&&
201 req_start
->level
<= EXPER_RANGE_END
)))
204 switch (tor
->MGMT_flags
) {
207 if (secpolicy_ip_config(credp
, B_FALSE
) != 0) {
208 optcom_err_ack(q
, mp
, TACCES
, 0);
211 req_end
= (struct opthdr
*)((uchar_t
*)req_start
+
213 for (req
= req_start
; req
< req_end
; req
= next_req
) {
215 (struct opthdr
*)((uchar_t
*)&req
[1] +
216 _TPI_ALIGN_OPT(req
->len
));
217 if (next_req
> req_end
)
219 for (sreq
= req_arr
; sreq
< A_END(req_arr
); sreq
++) {
220 if (req
->level
== sreq
->sor_group
&&
221 req
->name
== sreq
->sor_code
)
224 if (sreq
>= A_END(req_arr
))
226 if (!(*setfn
)(q
, req
->level
, req
->name
,
227 (uchar_t
*)&req
[1], req
->len
))
230 if (q
->q_next
!= NULL
)
238 mpctl
= allocb(TOAHDR_SIZE
, BPRI_MED
);
240 optcom_err_ack(q
, mp
, TSYSERR
, ENOMEM
);
243 mpctl
->b_cont
= allocb(DATA_MBLK_SIZE
, BPRI_MED
);
244 if (!mpctl
->b_cont
) {
246 optcom_err_ack(q
, mp
, TSYSERR
, ENOMEM
);
249 mpctl
->b_datap
->db_type
= M_PROTO
;
250 mpctl
->b_wptr
+= TOAHDR_SIZE
;
251 toa
= (struct T_optmgmt_ack
*)mpctl
->b_rptr
;
252 toa
->PRIM_type
= T_OPTMGMT_ACK
;
253 toa
->OPT_offset
= sizeof (struct T_optmgmt_ack
);
254 toa
->OPT_length
= sizeof (struct opthdr
);
255 toa
->MGMT_flags
= T_SUCCESS
;
257 * If the current process is running inside a solaris10-
258 * branded zone and len is 0 then it's a request for
261 if (PROC_IS_BRANDED(curproc
) &&
262 (strcmp(curproc
->p_brand
->b_name
, "solaris10") == 0) &&
263 (req_start
->len
== 0))
266 legacy_req
= B_FALSE
;
267 if (!(*getfn
)(q
, mpctl
, req_start
->level
, legacy_req
))
270 * all data for this module has now been sent upstream. If
271 * this is bottom module of stream, send up an EOD ctl msg,
272 * otherwise pass onto the next guy for processing.
274 if (q
->q_next
!= NULL
) {
282 mpctl
= reallocb(mp
, TOAHDR_SIZE
, 1);
284 optcom_err_ack(q
, mp
, TSYSERR
, ENOMEM
);
287 mpctl
->b_datap
->db_type
= M_PROTO
;
288 mpctl
->b_wptr
= mpctl
->b_rptr
+ TOAHDR_SIZE
;
289 toa
= (struct T_optmgmt_ack
*)mpctl
->b_rptr
;
290 toa
->PRIM_type
= T_OPTMGMT_ACK
;
291 toa
->OPT_offset
= sizeof (struct T_optmgmt_ack
);
292 toa
->OPT_length
= sizeof (struct opthdr
);
293 toa
->MGMT_flags
= T_SUCCESS
;
294 req
= (struct opthdr
*)&toa
[1];
302 optcom_err_ack(q
, mp
, TBADFLAG
, 0);
307 printf("snmpcom bad_req1\n");
310 printf("snmpcom bad_req2\n");
313 printf("snmpcom bad_req3\n");
316 printf("snmpcom bad_req4\n");
319 optcom_err_ack(q
, mp
, TBADOPT
, 0);