2 * snmp.c from Access Point SNMP Utils for Linux
3 * basic snmp packets assembly/disassembly and send/receive functions
5 * Copyright (c) 2002 Roman Festchook <roma at polesye dot net>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License Version 2 from
9 * June 1991 as published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #include <sys/types.h>
27 #include <netinet/in.h>
28 #include <sys/socket.h>
29 #include <arpa/inet.h>
36 extern char *community;
39 extern struct in_addr ap_ip;
43 static void alarm_handler()
46 siglongjmp(position, 1);
49 int ber(char *message, varbind * varbindlist, int num, int type)
52 char pdu1[1024], pdu[1024], *list = pdu1;
53 int len_var = 0, lenp, len_tmp, len = 0, community_len =
55 char snmp_ver[] = { 0x02, 0x01, 0x00 };
56 const char req_id[] = { 0x02, 0x01 }, err[] = {
59 for (i = 0; i < num; i++) {
60 *(pdu1 + len++) = ASN_HEADER;
62 (varbindlist + i)->len_oid + (varbindlist + i)->len_val + 4;
63 if (!(ap_type == NWN && type == SET)) {
64 *(pdu1 + len++) = 0x82;
65 *(pdu1 + len++) = (len_tmp - (len_tmp % 256)) / 256;
67 *(pdu1 + len++) = len_tmp % 256;
68 *(pdu1 + len++) = OID_VALUE;
69 *(pdu1 + len++) = (varbindlist + i)->len_oid;
70 memcpy(pdu1 + len, (varbindlist + i)->oid,
71 (varbindlist + i)->len_oid);
72 len += (varbindlist + i)->len_oid;
73 *(pdu1 + len++) = (varbindlist + i)->type;
74 *(pdu1 + len++) = (varbindlist + i)->len_val;
75 memcpy(pdu1 + len, (varbindlist + i)->value,
76 (varbindlist + i)->len_val);
77 len += (varbindlist + i)->len_val;
83 len_tmp = len_var + ((ap_type == NWN && type == SET) ? 11 : 13);
84 *(pdu + lenp++) = type;
85 if (!(ap_type == NWN && type == SET)) {
86 *(pdu + lenp++) = 0x82;
87 *(pdu + lenp++) = (len_tmp - (len_tmp % 256)) / 256;
89 *(pdu + lenp++) = len_tmp % 256;
91 memcpy(pdu + lenp, req_id, sizeof(req_id));
92 lenp += sizeof(req_id);
94 (1 + (int) (255.0 * rand() / (RAND_MAX + 1.0))) & 0xFF;
95 memcpy(pdu + lenp, err, sizeof(err));
97 memcpy(pdu + lenp, err, sizeof(err));
99 *(pdu + lenp++) = ASN_HEADER;
101 if (!(ap_type == NWN && type == SET)) {
102 *(pdu + lenp++) = 0x82;
103 *(pdu + lenp++) = (len_tmp - (len_tmp % 256)) / 256;
105 *(pdu + lenp++) = len_tmp % 256;
106 memcpy(pdu + lenp, list, len_var);
109 *message = ASN_HEADER;
112 i = lenp + community_len + 5;
113 if (!(ap_type == NWN && type == SET)) {
114 *(message + len++) = 0x82;
115 *(message + len++) = (i - (i % 256)) / 256;
117 *(message + len++) = i % 256;
119 memcpy(message + len, snmp_ver, 3);
121 *(message + len++) = STRING_VALUE;
122 *(message + len++) = community_len & 0xFF;
123 memcpy(message + len, community, community_len);
124 len += community_len;
125 memcpy(message + len, pdu, lenp);
131 int snmp(varbind * varbindlist, int num, int type)
133 unsigned char message[1024], *start;
134 unsigned int num_reply;
136 struct sockaddr_in server;
141 memset(&server, 0, sizeof server);
142 server.sin_family = AF_INET;
143 server.sin_port = htons(161);
144 server.sin_addr.s_addr = ap_ip.s_addr;
146 signal(SIGALRM, alarm_handler);
148 sigsetjmp(position, 1);
154 len = ber(message, varbindlist, num, type);
155 if (sendto(sockfd, message, len, 0, (struct sockaddr *) &server, SIZE)
160 if ((len = recv(sockfd, message, 1024, 0)) == -1) {
168 buf = (char *) malloc(len);
169 memcpy(buf, message, len);
173 if (*start != ASN_HEADER) {
177 if (start[1] & 0x80) {
178 start += (start[1] & 0x7F) + 2;
179 len -= ((start[1] & 0x7F) + 2);
185 len -= *(start + 4) + 5;
186 start += *(start + 4) + 5;
188 if (*(start) != RESPONSE) {
194 if (start[1] & 0x80) {
195 start += (start[1] & 0x7F) + 2;
196 len -= ((start[1] & 0x7F) + 2);
203 return -*(start + 8);
207 if (*(start) != ASN_HEADER) {
212 if (start[1] & 0x80) {
213 start += (start[1] & 0x7F) + 2;
214 len -= ((start[1] & 0x7F) + 2);
220 if (*(start) != ASN_HEADER) {
223 if (start[1] & 0x80) {
224 start += (start[1] & 0x7F) + 2;
225 len -= ((start[1] & 0x7F) + 2);
232 varbindlist[num_reply].len_oid = start[1];
233 /* if(varbindlist[num_reply].oid)
234 free(varbindlist[num_reply].oid);
235 varbindlist[num_reply].oid =
236 (char *) malloc(varbindlist[num_reply].len_oid);
237 memcpy(varbindlist[num_reply].oid, start + 2,
238 varbindlist[num_reply].len_oid);
240 varbindlist[num_reply].oid = start + 2;
241 len -= *(start + 1) + 2;
242 start += *(start + 1) + 2;
243 varbindlist[num_reply].type = *(start);
245 if (start[1] & 0x80) {
246 varbindlist[num_reply].len_val = start[2];
247 start += (start[1] & 0x7F) + 2;
248 len -= ((start[1] & 0x7F) + 2);
250 varbindlist[num_reply].len_val = start[1];
255 /* if(varbindlist[num_reply].value)
256 free(varbindlist[num_reply].value);
257 varbindlist[num_reply].value =
258 (char *) malloc(varbindlist[num_reply].len_val);
259 memcpy(varbindlist[num_reply].value, start,
260 varbindlist[num_reply].len_val);
262 varbindlist[num_reply].value = start;
263 len -= varbindlist[num_reply].len_val;
264 start += varbindlist[num_reply].len_val;