]> git.decadent.org.uk Git - ap-utils.git/blob - lib/snmp.c
f688c55d9242a473a203cc4b39985b630ecb35de
[ap-utils.git] / lib / snmp.c
1 /*
2  *      snmp.c from Access Point SNMP Utils for Linux
3  *      basic snmp packets assembly/disassembly and send/receive functions
4  *
5  * Copyright (c) 2002 Roman Festchook <roma at polesye dot net>
6  *
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.
10  *
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.
15  *
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
19  *
20  */
21 #include <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <signal.h>
25 #include <setjmp.h>
26 #include <sys/types.h>
27 #include <netinet/in.h>
28 #include <sys/socket.h>
29 #include <arpa/inet.h>
30 #include "ap-utils.h"
31
32 #define RETRIES 5
33
34 sigjmp_buf position;
35
36 extern char *community;
37 extern short ap_type;
38 extern int sockfd;
39 extern struct in_addr ap_ip;
40 int retries;
41 char *buf = NULL;
42
43 static void alarm_handler()
44 {
45     retries--;
46     siglongjmp(position, 1);
47 }
48
49 int ber(char *message, varbind * varbindlist, int num, int type)
50 {
51
52     char pdu1[1024], pdu[1024], *list = pdu1;
53     int len_var = 0, lenp, len_tmp, len = 0, community_len =
54         strlen(community), i;
55     char snmp_ver[] = { 0x02, 0x01, 0x00 };
56     const char req_id[] = { 0x02, 0x01 }, err[] = {
57     0x02, 0x01, 0x00};
58
59     for (i = 0; i < num; i++) {
60         *(pdu1 + len++) = ASN_HEADER;
61         len_tmp =
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;
66         }
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;
78     }
79
80     len_var = len;
81
82     lenp = 0;
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;
88     }
89     *(pdu + lenp++) = len_tmp % 256;
90
91     memcpy(pdu + lenp, req_id, sizeof(req_id));
92     lenp += sizeof(req_id);
93     *(pdu + lenp++) =
94         (1 + (int) (255.0 * rand() / (RAND_MAX + 1.0))) & 0xFF;
95     memcpy(pdu + lenp, err, sizeof(err));
96     lenp += sizeof(err);
97     memcpy(pdu + lenp, err, sizeof(err));
98     lenp += sizeof(err);
99     *(pdu + lenp++) = ASN_HEADER;
100     len_tmp = len_var;
101     if (!(ap_type == NWN && type == SET)) {
102         *(pdu + lenp++) = 0x82;
103         *(pdu + lenp++) = (len_tmp - (len_tmp % 256)) / 256;
104     }
105     *(pdu + lenp++) = len_tmp % 256;
106     memcpy(pdu + lenp, list, len_var);
107     lenp += len_var;
108
109     *message = ASN_HEADER;
110     len = 1;
111
112     i = lenp + community_len + 5;
113     if (!(ap_type == NWN && type == SET)) {
114         *(message + len++) = 0x82;
115         *(message + len++) = (i - (i % 256)) / 256;
116     }
117     *(message + len++) = i % 256;
118
119     memcpy(message + len, snmp_ver, 3);
120     len += 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);
126     len += lenp;
127
128     return len;
129 }
130
131 int snmp(varbind * varbindlist, int num, int type)
132 {
133     unsigned char message[1024], *start;
134     unsigned int num_reply;
135     int len;
136     struct sockaddr_in server;
137
138     if (num == 0)
139         return 1;
140
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;
145
146     signal(SIGALRM, alarm_handler);
147     retries = RETRIES;
148     sigsetjmp(position, 1);
149     if (!retries) {
150         return 0;
151     }
152
153     alarm(1);
154     len = ber(message, varbindlist, num, type);
155     if (sendto(sockfd, message, len, 0, (struct sockaddr *) &server, SIZE)
156         == -1) {
157         alarm(0);
158         return 0;
159     }
160     if ((len = recv(sockfd, message, 1024, 0)) == -1) {
161         alarm(0);
162         return 0;
163     }
164     alarm(0);
165
166     if (buf)
167         free(buf);
168     buf = (char *) malloc(len);
169     memcpy(buf, message, len);
170
171     start = buf;
172     num_reply = 0;
173     if (*start != ASN_HEADER) {
174         return 0;
175     }
176
177     if (start[1] & 0x80) {
178         start += (start[1] & 0x7F) + 2;
179         len -= ((start[1] & 0x7F) + 2);
180     } else {
181         start += 2;
182         len -= 2;
183     }
184
185     len -= *(start + 4) + 5;
186     start += *(start + 4) + 5;
187
188     if (*(start) != RESPONSE) {
189         return 0;
190     }
191
192
193
194     if (start[1] & 0x80) {
195         start += (start[1] & 0x7F) + 2;
196         len -= ((start[1] & 0x7F) + 2);
197     } else {
198         start += 2;
199         len -= 2;
200     }
201
202     if (*(start + 5))
203         return -*(start + 8);
204
205     start += 9;
206     len -= 9;
207     if (*(start) != ASN_HEADER) {
208         return 0;
209     }
210
211
212     if (start[1] & 0x80) {
213         start += (start[1] & 0x7F) + 2;
214         len -= ((start[1] & 0x7F) + 2);
215     } else {
216         start += 2;
217         len -= 2;
218     }
219     while (len) {
220         if (*(start) != ASN_HEADER) {
221             return num_reply;
222         }
223         if (start[1] & 0x80) {
224             start += (start[1] & 0x7F) + 2;
225             len -= ((start[1] & 0x7F) + 2);
226         } else {
227             start += 2;
228             len -= 2;
229         }
230
231
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);
239 */
240         varbindlist[num_reply].oid = start + 2;
241         len -= *(start + 1) + 2;
242         start += *(start + 1) + 2;
243         varbindlist[num_reply].type = *(start);
244
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);
249         } else {
250             varbindlist[num_reply].len_val = start[1];
251             start += 2;
252             len -= 2;
253         }
254
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);
261 */
262         varbindlist[num_reply].value = start;
263         len -= varbindlist[num_reply].len_val;
264         start += varbindlist[num_reply].len_val;
265         num_reply++;
266     }
267
268     return num_reply;
269 }