2 * snmp.c from Access Point SNMP Utils for Linux
3 * basic snmp packets assembly/disassembly and send/receive functions
5 * Copyright (c) Roman Festchook <roma at polesye dot net>
6 * Jan Rafaj <jr-aputils at cedric dot unob dot cz>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License Version 2 from
10 * June 1991 as published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include <sys/types.h>
28 #include <netinet/in.h>
29 #include <sys/socket.h>
30 #include <arpa/inet.h>
35 extern char *community;
38 extern struct in_addr ap_ip;
40 int snmp_retries = 5, retries;
43 static void alarm_handler()
46 siglongjmp(position, 1);
50 unsigned int ber_decode_uint(unsigned char *bevp, int len)
55 out = (out << 7) | (*bevp & (*bevp & 0x80 ? 0x7f : 0xff));
63 int ber(char *message, varbind * varbindlist, int num, int type)
66 char pdu1[1024], pdu[1024], *list = pdu1;
67 int len_var = 0, lenp, len_tmp, len = 0, community_len =
69 char snmp_ver[] = { 0x02, 0x01, 0x00 };
70 const char req_id[] = { 0x02, 0x01 }, err[] = {
73 for (i = 0; i < num; i++) {
74 *(pdu1 + len++) = ASN_HEADER;
76 (varbindlist + i)->len_oid + (varbindlist + i)->len_val + 4;
77 if (!(ap_type == NWN && type == SET)) {
78 *(pdu1 + len++) = 0x82;
79 *(pdu1 + len++) = (len_tmp - (len_tmp % 256)) / 256;
81 *(pdu1 + len++) = len_tmp % 256;
82 *(pdu1 + len++) = OID_VALUE;
83 *(pdu1 + len++) = (varbindlist + i)->len_oid;
84 memcpy(pdu1 + len, (varbindlist + i)->oid,
85 (varbindlist + i)->len_oid);
86 len += (varbindlist + i)->len_oid;
87 *(pdu1 + len++) = (varbindlist + i)->type;
88 *(pdu1 + len++) = (varbindlist + i)->len_val;
89 memcpy(pdu1 + len, (varbindlist + i)->value,
90 (varbindlist + i)->len_val);
91 len += (varbindlist + i)->len_val;
97 len_tmp = len_var + ((ap_type == NWN && type == SET) ? 11 : 13);
98 *(pdu + lenp++) = type;
99 if (!(ap_type == NWN && type == SET)) {
100 *(pdu + lenp++) = 0x82;
101 *(pdu + lenp++) = (len_tmp - (len_tmp % 256)) / 256;
103 *(pdu + lenp++) = len_tmp % 256;
105 memcpy(pdu + lenp, req_id, sizeof(req_id));
106 lenp += sizeof(req_id);
108 (1 + (int) (255.0 * rand() / (RAND_MAX + 1.0))) & 0xFF;
109 memcpy(pdu + lenp, err, sizeof(err));
111 memcpy(pdu + lenp, err, sizeof(err));
113 *(pdu + lenp++) = ASN_HEADER;
115 if (!(ap_type == NWN && type == SET)) {
116 *(pdu + lenp++) = 0x82;
117 *(pdu + lenp++) = (len_tmp - (len_tmp % 256)) / 256;
119 *(pdu + lenp++) = len_tmp % 256;
120 memcpy(pdu + lenp, list, len_var);
123 *message = ASN_HEADER;
126 i = lenp + community_len + 5;
127 if (!(ap_type == NWN && type == SET)) {
128 *(message + len++) = 0x82;
129 *(message + len++) = (i - (i % 256)) / 256;
131 *(message + len++) = i % 256;
133 memcpy(message + len, snmp_ver, 3);
135 *(message + len++) = STRING_VALUE;
136 *(message + len++) = community_len & 0xFF;
137 memcpy(message + len, community, community_len);
138 len += community_len;
139 memcpy(message + len, pdu, lenp);
145 int snmp(varbind * varbindlist, int num, int type)
147 unsigned char message[1024], *start;
148 unsigned int num_reply;
150 struct sockaddr_in server;
155 memset(&server, 0, sizeof server);
156 server.sin_family = AF_INET;
157 server.sin_port = htons(161);
158 server.sin_addr.s_addr = ap_ip.s_addr;
160 signal(SIGALRM, alarm_handler);
161 retries = snmp_retries;
162 sigsetjmp(position, 1);
168 len = ber(message, varbindlist, num, type);
169 if (sendto(sockfd, message, len, 0, (struct sockaddr *) &server, SIZE)
174 if ((len = recv(sockfd, message, 1024, 0)) == -1) {
182 buf = (char *) malloc(len);
183 memcpy(buf, message, len);
187 if (*start != ASN_HEADER) {
191 if (start[1] & 0x80) {
192 start += (start[1] & 0x7F) + 2;
193 len -= ((start[1] & 0x7F) + 2);
199 len -= *(start + 4) + 5;
200 start += *(start + 4) + 5;
202 if (*(start) != RESPONSE) {
208 if (start[1] & 0x80) {
209 start += (start[1] & 0x7F) + 2;
210 len -= ((start[1] & 0x7F) + 2);
217 return -*(start + 8);
221 if (*(start) != ASN_HEADER) {
226 if (start[1] & 0x80) {
227 start += (start[1] & 0x7F) + 2;
228 len -= ((start[1] & 0x7F) + 2);
234 if (*(start) != ASN_HEADER) {
237 if (start[1] & 0x80) {
238 start += (start[1] & 0x7F) + 2;
239 len -= ((start[1] & 0x7F) + 2);
246 varbindlist[num_reply].len_oid = start[1];
247 /* if(varbindlist[num_reply].oid)
248 free(varbindlist[num_reply].oid);
249 varbindlist[num_reply].oid =
250 (char *) malloc(varbindlist[num_reply].len_oid);
251 memcpy(varbindlist[num_reply].oid, start + 2,
252 varbindlist[num_reply].len_oid);
254 varbindlist[num_reply].oid = start + 2;
255 len -= *(start + 1) + 2;
256 start += *(start + 1) + 2;
257 varbindlist[num_reply].type = *(start);
259 if (start[1] & 0x80) {
260 varbindlist[num_reply].len_val = start[2];
261 start += (start[1] & 0x7F) + 2;
262 len -= ((start[1] & 0x7F) + 2);
264 varbindlist[num_reply].len_val = start[1];
269 /* if(varbindlist[num_reply].value)
270 free(varbindlist[num_reply].value);
271 varbindlist[num_reply].value =
272 (char *) malloc(varbindlist[num_reply].len_val);
273 memcpy(varbindlist[num_reply].value, start,
274 varbindlist[num_reply].len_val);
276 varbindlist[num_reply].value = start;
277 len -= varbindlist[num_reply].len_val;
278 start += varbindlist[num_reply].len_val;