]>
git.ipfire.org Git - thirdparty/squid.git/blob - lib/snmplib/snmp_pdu.c
2 * Copyright (C) 1996-2014 The Squid Software Foundation and contributors
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
14 * RFC 1902: Structure of Management Information for SNMPv2
18 /**********************************************************************
20 * Copyright 1997 by Carnegie Mellon University
24 * Permission to use, copy, modify, and distribute this software and its
25 * documentation for any purpose and without fee is hereby granted,
26 * provided that the above copyright notice appear in all copies and that
27 * both that copyright notice and this permission notice appear in
28 * supporting documentation, and that the name of CMU not be
29 * used in advertising or publicity pertaining to distribution of the
30 * software without specific, written prior permission.
32 * CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
33 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
34 * CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
35 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
36 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
37 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
40 * Author: Ryan Troll <ryan+@andrew.cmu.edu>
42 **********************************************************************/
53 #include <sys/types.h>
59 #include <gnumalloc.h>
76 #include <sys/socket.h>
79 #include <netinet/in.h>
82 #include <arpa/inet.h>
93 #include "snmp_api_error.h"
94 #include "snmp_error.h"
97 #include "snmp_vars.h"
101 /* #define DEBUG_PDU 1 */
102 /* #define DEBUG_PDU_DECODE 1 */
103 /* #define DEBUG_PDU_ENCODE 1 */
105 #define ASN_PARSE_ERROR(x) { return(x); }
107 /**********************************************************************/
113 snmp_pdu_create(int command
) {
114 struct snmp_pdu
*pdu
;
117 snmplib_debug(8, "PDU: Creating\n");
120 pdu
= (struct snmp_pdu
*) xmalloc(sizeof(struct snmp_pdu
));
122 snmp_set_api_error(SNMPERR_OS_ERR
);
125 memset((char *) pdu
, '\0', sizeof(struct snmp_pdu
));
127 pdu
->command
= command
;
128 pdu
->errstat
= SNMP_DEFAULT_ERRSTAT
;
129 pdu
->errindex
= SNMP_DEFAULT_ERRINDEX
;
130 pdu
->address
.sin_addr
.s_addr
= SNMP_DEFAULT_ADDRESS
;
131 pdu
->enterprise
= NULL
;
132 pdu
->enterprise_length
= 0;
133 pdu
->variables
= NULL
;
136 snmplib_debug(8, "PDU: Created %x\n", (unsigned int) pdu
);
142 /**********************************************************************/
144 /* Clone an existing PDU.
147 snmp_pdu_clone(struct snmp_pdu
*Src
) {
148 struct snmp_pdu
*Dest
;
151 snmplib_debug(8, "PDU %x: Cloning\n", (unsigned int) Src
);
154 Dest
= (struct snmp_pdu
*) xmalloc(sizeof(struct snmp_pdu
));
156 snmp_set_api_error(SNMPERR_OS_ERR
);
159 memcpy((char *) Dest
, (char *) Src
, sizeof(struct snmp_pdu
));
162 snmplib_debug(8, "PDU %x: Created %x\n", (unsigned int) Src
, (unsigned int) Dest
);
167 /**********************************************************************/
170 * If there was an error in the input pdu, creates a clone of the pdu
171 * that includes all the variables except the one marked by the errindex.
172 * The command is set to the input command and the reqid, errstat, and
173 * errindex are set to default values.
174 * If the error status didn't indicate an error, the error index didn't
175 * indicate a variable, the pdu wasn't a get response message, or there
176 * would be no remaining variables, this function will return NULL.
177 * If everything was successful, a pointer to the fixed cloned pdu will
181 snmp_pdu_fix(struct snmp_pdu
*pdu
, int command
) {
182 return (snmp_fix_pdu(pdu
, command
));
186 snmp_fix_pdu(struct snmp_pdu
*pdu
, int command
) {
187 struct variable_list
*var
, *newvar
;
188 struct snmp_pdu
*newpdu
;
193 snmplib_debug(8, "PDU %x: Fixing. Err index is %d\n",
194 (unsigned int) pdu
, (unsigned int) pdu
->errindex
);
197 if (pdu
->command
!= SNMP_PDU_RESPONSE
||
198 pdu
->errstat
== SNMP_ERR_NOERROR
||
199 pdu
->errindex
<= 0) {
200 snmp_set_api_error(SNMPERR_UNABLE_TO_FIX
);
204 newpdu
= snmp_pdu_clone(pdu
);
208 newpdu
->variables
= 0;
209 newpdu
->command
= command
;
210 newpdu
->reqid
= SNMP_DEFAULT_REQID
;
211 newpdu
->errstat
= SNMP_DEFAULT_ERRSTAT
;
212 newpdu
->errindex
= SNMP_DEFAULT_ERRINDEX
;
214 /* Loop through the variables, removing whatever isn't necessary */
216 var
= pdu
->variables
;
219 /* skip first variable if necessary */
220 if (pdu
->errindex
== i
) {
221 var
= var
->next_variable
;
226 /* VAR is the first uncopied variable */
228 /* Clone this variable */
229 newpdu
->variables
= snmp_var_clone(var
);
230 if (newpdu
->variables
== NULL
) {
231 snmp_pdu_free(newpdu
);
236 newvar
= newpdu
->variables
;
238 /* VAR has been copied to NEWVAR. */
239 while (var
->next_variable
) {
241 /* Skip the item that was bad */
242 if (++i
== pdu
->errindex
) {
243 var
= var
->next_variable
;
247 newvar
->next_variable
= snmp_var_clone(var
->next_variable
);
248 if (newvar
->next_variable
== NULL
) {
249 snmp_pdu_free(newpdu
);
252 /* Move to the next one */
253 newvar
= newvar
->next_variable
;
254 var
= var
->next_variable
;
257 newvar
->next_variable
= NULL
;
259 /* If we didn't copy anything, free the new pdu. */
260 if (i
< pdu
->errindex
|| copied
== 0) {
261 snmp_free_pdu(newpdu
);
262 snmp_set_api_error(SNMPERR_UNABLE_TO_FIX
);
266 snmplib_debug(8, "PDU %x: Fixed PDU is %x\n",
267 (unsigned int) pdu
, (unsigned int) newpdu
);
272 /**********************************************************************/
275 snmp_pdu_free(struct snmp_pdu
*pdu
)
281 * Frees the pdu and any xmalloc'd data associated with it.
284 snmp_free_pdu(struct snmp_pdu
*pdu
)
286 struct variable_list
*vp
, *ovp
;
291 vp
= vp
->next_variable
;
296 xfree((char *) pdu
->enterprise
);
300 /**********************************************************************/
302 /* Encode this PDU into DestBuf.
304 * Returns a pointer to the next byte in the buffer (where the Variable
309 * RFC 1902: Structure of Management Information for SNMPv2
313 * request-id INTEGER32
314 * error-status INTEGER
315 * error-index INTEGER
321 * request-id INTEGER32
322 * non-repeaters INTEGER
323 * max-repetitions INTEGER
329 * RFC 1157: A Simple Network Management Protocol (SNMP)
334 * error-status INTEGER
335 * error-index INTEGER
341 * enterprise NetworkAddress
342 * generic-trap INTEGER
343 * specific-trap INTEGER
344 * time-stamp TIMETICKS
350 snmp_pdu_encode(u_char
* DestBuf
, int *DestBufLen
,
351 struct snmp_pdu
*PDU
)
356 snmplib_debug(8, "PDU: Encoding %d\n", PDU
->command
);
360 switch (PDU
->command
) {
362 /**********************************************************************/
369 bufp
= asn_build_objid(DestBuf
, DestBufLen
,
370 (u_char
) (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_OBJECT_ID
),
371 (oid
*) PDU
->enterprise
, PDU
->enterprise_length
);
376 bufp
= asn_build_string(bufp
, DestBufLen
,
377 (u_char
) (SMI_IPADDRESS
| ASN_PRIMITIVE
),
378 (u_char
*) & PDU
->agent_addr
.sin_addr
.s_addr
,
379 sizeof(PDU
->agent_addr
.sin_addr
.s_addr
));
384 bufp
= asn_build_int(bufp
, DestBufLen
,
385 (u_char
) (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
386 (int *) &PDU
->trap_type
, sizeof(PDU
->trap_type
));
391 bufp
= asn_build_int(bufp
, DestBufLen
,
392 (u_char
) (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
393 (int *) &PDU
->specific_type
,
394 sizeof(PDU
->specific_type
));
399 bufp
= asn_build_unsigned_int(bufp
, DestBufLen
,
400 (u_char
) (SMI_TIMETICKS
| ASN_PRIMITIVE
),
401 &PDU
->time
, sizeof(PDU
->time
));
407 /**********************************************************************/
409 case SNMP_PDU_GETBULK
:
411 /* SNMPv2 Bulk Request */
414 bufp
= asn_build_int(DestBuf
, DestBufLen
,
415 (u_char
) (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
416 &PDU
->reqid
, sizeof(PDU
->reqid
));
421 bufp
= asn_build_int(bufp
, DestBufLen
,
422 (u_char
) (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
424 sizeof(PDU
->non_repeaters
));
428 /* max-repetitions */
429 bufp
= asn_build_int(bufp
, DestBufLen
,
430 (u_char
) (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
431 &PDU
->max_repetitions
,
432 sizeof(PDU
->max_repetitions
));
437 /**********************************************************************/
441 /* Normal PDU Encoding */
445 snmplib_debug(8, "PDU: Request ID %d (0x%x)\n", PDU
->reqid
, DestBuf
);
447 bufp
= asn_build_int(DestBuf
, DestBufLen
,
448 (u_char
) (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
449 &PDU
->reqid
, sizeof(PDU
->reqid
));
455 snmplib_debug(8, "PDU: Error Status %d (0x%x)\n", PDU
->errstat
, bufp
);
457 bufp
= asn_build_int(bufp
, DestBufLen
,
458 (u_char
) (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
459 &PDU
->errstat
, sizeof(PDU
->errstat
));
465 snmplib_debug(8, "PDU: Error index %d (0x%x)\n", PDU
->errindex
, bufp
);
467 bufp
= asn_build_int(bufp
, DestBufLen
,
468 (u_char
) (ASN_UNIVERSAL
| ASN_PRIMITIVE
| ASN_INTEGER
),
469 &PDU
->errindex
, sizeof(PDU
->errindex
));
473 } /* End of encoding */
478 /**********************************************************************/
480 /* Decodes PDU from Packet into PDU.
482 * Returns a pointer to the next byte of the packet, which is where the
483 * Variable Bindings start.
486 snmp_pdu_decode(u_char
* Packet
, /* data */
487 int *Length
, /* &length */
488 struct snmp_pdu
* PDU
)
495 oid objid
[MAX_NAME_LEN
];
498 bufp
= asn_parse_header(Packet
, Length
, &PDUType
);
500 ASN_PARSE_ERROR(NULL
);
503 snmplib_debug(8, "PDU Type: %d\n", PDUType
);
506 PDU
->command
= PDUType
;
512 /* SNMPv1 Trap Message */
515 PDU
->enterprise_length
= MAX_NAME_LEN
;
516 bufp
= asn_parse_objid(bufp
, Length
,
517 &ASNType
, objid
, &PDU
->enterprise_length
);
519 ASN_PARSE_ERROR(NULL
);
521 PDU
->enterprise
= (oid
*) xmalloc(PDU
->enterprise_length
* sizeof(oid
));
522 if (PDU
->enterprise
== NULL
) {
523 snmp_set_api_error(SNMPERR_OS_ERR
);
526 memcpy((char *) PDU
->enterprise
, (char *) objid
,
527 PDU
->enterprise_length
* sizeof(oid
));
531 bufp
= asn_parse_string(bufp
, Length
,
533 (u_char
*) & PDU
->agent_addr
.sin_addr
.s_addr
,
536 ASN_PARSE_ERROR(NULL
);
539 bufp
= asn_parse_int(bufp
, Length
,
541 (int *) &PDU
->trap_type
,
542 sizeof(PDU
->trap_type
));
544 ASN_PARSE_ERROR(NULL
);
547 bufp
= asn_parse_int(bufp
, Length
,
549 (int *) &PDU
->specific_type
,
550 sizeof(PDU
->specific_type
));
552 ASN_PARSE_ERROR(NULL
);
555 bufp
= asn_parse_unsigned_int(bufp
, Length
,
557 &PDU
->time
, sizeof(PDU
->time
));
559 ASN_PARSE_ERROR(NULL
);
563 /**********************************************************************/
565 case SNMP_PDU_GETBULK
:
567 /* SNMPv2 Bulk Request */
570 bufp
= asn_parse_int(bufp
, Length
,
572 &PDU
->reqid
, sizeof(PDU
->reqid
));
574 ASN_PARSE_ERROR(NULL
);
577 bufp
= asn_parse_int(bufp
, Length
,
579 &PDU
->non_repeaters
, sizeof(PDU
->non_repeaters
));
581 ASN_PARSE_ERROR(NULL
);
583 /* max-repetitions */
584 bufp
= asn_parse_int(bufp
, Length
,
586 &PDU
->max_repetitions
, sizeof(PDU
->max_repetitions
));
588 ASN_PARSE_ERROR(NULL
);
591 /**********************************************************************/
595 /* Normal PDU Encoding */
598 bufp
= asn_parse_int(bufp
, Length
,
600 &PDU
->reqid
, sizeof(PDU
->reqid
));
602 ASN_PARSE_ERROR(NULL
);
605 snmplib_debug(8, "PDU Request ID: %d\n", PDU
->reqid
);
609 bufp
= asn_parse_int(bufp
, Length
,
611 &PDU
->errstat
, sizeof(PDU
->errstat
));
613 ASN_PARSE_ERROR(NULL
);
616 snmplib_debug(8, "PDU Error Status: %d\n", PDU
->errstat
);
620 bufp
= asn_parse_int(bufp
, Length
,
622 &PDU
->errindex
, sizeof(PDU
->errindex
));
624 ASN_PARSE_ERROR(NULL
);
627 snmplib_debug(8, "PDU Error Index: %d\n", PDU
->errindex
);
637 * Add a null variable with the requested name to the end of the list of
638 * variables for this pdu.
641 snmp_add_null_var(struct snmp_pdu
*pdu
, oid
* name
, int name_length
)
643 struct variable_list
*vars
;
644 struct variable_list
*ptr
;
646 vars
= snmp_var_new(name
, name_length
);
648 perror("snmp_add_null_var:xmalloc");
651 if (pdu
->variables
== NULL
) {
652 pdu
->variables
= vars
;
655 /* Insert at the end */
656 for (ptr
= pdu
->variables
;
658 ptr
= ptr
->next_variable
)
660 ptr
->next_variable
= vars
;