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>
37 extern char *community;
40 extern struct in_addr ap_ip;
44 static void alarm_handler()
47 siglongjmp(position, 1);
51 unsigned int ber_decode_uint(unsigned char *bevp, int len)
56 out = (out << 7) | (*bevp & (*bevp & 0x80 ? 0x7f : 0xff));
64 int ber(char *message, varbind * varbindlist, int num, int type)
67 char pdu1[1024], pdu[1024], *list = pdu1;
68 int len_var = 0, lenp, len_tmp, len = 0, community_len =
70 char snmp_ver[] = { 0x02, 0x01, 0x00 };
71 const char req_id[] = { 0x02, 0x01 }, err[] = {
74 for (i = 0; i < num; i++) {
75 *(pdu1 + len++) = ASN_HEADER;
77 (varbindlist + i)->len_oid + (varbindlist + i)->len_val + 4;
78 if (!(ap_type == NWN && type == SET)) {
79 *(pdu1 + len++) = 0x82;
80 *(pdu1 + len++) = (len_tmp - (len_tmp % 256)) / 256;
82 *(pdu1 + len++) = len_tmp % 256;
83 *(pdu1 + len++) = OID_VALUE;
84 *(pdu1 + len++) = (varbindlist + i)->len_oid;
85 memcpy(pdu1 + len, (varbindlist + i)->oid,
86 (varbindlist + i)->len_oid);
87 len += (varbindlist + i)->len_oid;
88 *(pdu1 + len++) = (varbindlist + i)->type;
89 *(pdu1 + len++) = (varbindlist + i)->len_val;
90 memcpy(pdu1 + len, (varbindlist + i)->value,
91 (varbindlist + i)->len_val);
92 len += (varbindlist + i)->len_val;
98 len_tmp = len_var + ((ap_type == NWN && type == SET) ? 11 : 13);
99 *(pdu + lenp++) = type;
100 if (!(ap_type == NWN && type == SET)) {
101 *(pdu + lenp++) = 0x82;
102 *(pdu + lenp++) = (len_tmp - (len_tmp % 256)) / 256;
104 *(pdu + lenp++) = len_tmp % 256;
106 memcpy(pdu + lenp, req_id, sizeof(req_id));
107 lenp += sizeof(req_id);
109 (1 + (int) (255.0 * rand() / (RAND_MAX + 1.0))) & 0xFF;
110 memcpy(pdu + lenp, err, sizeof(err));
112 memcpy(pdu + lenp, err, sizeof(err));
114 *(pdu + lenp++) = ASN_HEADER;
116 if (!(ap_type == NWN && type == SET)) {
117 *(pdu + lenp++) = 0x82;
118 *(pdu + lenp++) = (len_tmp - (len_tmp % 256)) / 256;
120 *(pdu + lenp++) = len_tmp % 256;
121 memcpy(pdu + lenp, list, len_var);
124 *message = ASN_HEADER;
127 i = lenp + community_len + 5;
128 if (!(ap_type == NWN && type == SET)) {
129 *(message + len++) = 0x82;
130 *(message + len++) = (i - (i % 256)) / 256;
132 *(message + len++) = i % 256;
134 memcpy(message + len, snmp_ver, 3);
136 *(message + len++) = STRING_VALUE;
137 *(message + len++) = community_len & 0xFF;
138 memcpy(message + len, community, community_len);
139 len += community_len;
140 memcpy(message + len, pdu, lenp);
146 int snmp(varbind * varbindlist, int num, int type)
148 unsigned char message[1024], *start;
149 unsigned int num_reply;
151 struct sockaddr_in server;
156 memset(&server, 0, sizeof server);
157 server.sin_family = AF_INET;
158 server.sin_port = htons(161);
159 server.sin_addr.s_addr = ap_ip.s_addr;
161 signal(SIGALRM, alarm_handler);
163 sigsetjmp(position, 1);
169 len = ber(message, varbindlist, num, type);
170 if (sendto(sockfd, message, len, 0, (struct sockaddr *) &server, SIZE)
175 if ((len = recv(sockfd, message, 1024, 0)) == -1) {
183 buf = (char *) malloc(len);
184 memcpy(buf, message, len);
188 if (*start != ASN_HEADER) {
192 if (start[1] & 0x80) {
193 start += (start[1] & 0x7F) + 2;
194 len -= ((start[1] & 0x7F) + 2);
200 len -= *(start + 4) + 5;
201 start += *(start + 4) + 5;
203 if (*(start) != RESPONSE) {
209 if (start[1] & 0x80) {
210 start += (start[1] & 0x7F) + 2;
211 len -= ((start[1] & 0x7F) + 2);
218 return -*(start + 8);
222 if (*(start) != ASN_HEADER) {
227 if (start[1] & 0x80) {
228 start += (start[1] & 0x7F) + 2;
229 len -= ((start[1] & 0x7F) + 2);
235 if (*(start) != ASN_HEADER) {
238 if (start[1] & 0x80) {
239 start += (start[1] & 0x7F) + 2;
240 len -= ((start[1] & 0x7F) + 2);
247 varbindlist[num_reply].len_oid = start[1];
248 /* if(varbindlist[num_reply].oid)
249 free(varbindlist[num_reply].oid);
250 varbindlist[num_reply].oid =
251 (char *) malloc(varbindlist[num_reply].len_oid);
252 memcpy(varbindlist[num_reply].oid, start + 2,
253 varbindlist[num_reply].len_oid);
255 varbindlist[num_reply].oid = start + 2;
256 len -= *(start + 1) + 2;
257 start += *(start + 1) + 2;
258 varbindlist[num_reply].type = *(start);
260 if (start[1] & 0x80) {
261 varbindlist[num_reply].len_val = start[2];
262 start += (start[1] & 0x7F) + 2;
263 len -= ((start[1] & 0x7F) + 2);
265 varbindlist[num_reply].len_val = start[1];
270 /* if(varbindlist[num_reply].value)
271 free(varbindlist[num_reply].value);
272 varbindlist[num_reply].value =
273 (char *) malloc(varbindlist[num_reply].len_val);
274 memcpy(varbindlist[num_reply].value, start,
275 varbindlist[num_reply].len_val);
277 varbindlist[num_reply].value = start;
278 len -= varbindlist[num_reply].len_val;
279 start += varbindlist[num_reply].len_val;