OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [freertos-6.1.1/] [Demo/] [Common/] [ethernet/] [lwIP_132/] [src/] [core/] [snmp/] [msg_in.c] - Blame information for rev 606

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 606 jeremybenn
/**
2
 * @file
3
 * SNMP input message processing (RFC1157).
4
 */
5
 
6
/*
7
 * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
8
 * All rights reserved.
9
 *
10
 * Redistribution and use in source and binary forms, with or without modification,
11
 * are permitted provided that the following conditions are met:
12
 *
13
 * 1. Redistributions of source code must retain the above copyright notice,
14
 *    this list of conditions and the following disclaimer.
15
 * 2. Redistributions in binary form must reproduce the above copyright notice,
16
 *    this list of conditions and the following disclaimer in the documentation
17
 *    and/or other materials provided with the distribution.
18
 * 3. The name of the author may not be used to endorse or promote products
19
 *    derived from this software without specific prior written permission.
20
 *
21
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
22
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
24
 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
26
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
29
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
30
 * OF SUCH DAMAGE.
31
 *
32
 * Author: Christiaan Simons <christiaan.simons@axon.tv>
33
 */
34
 
35
#include "lwip/opt.h"
36
 
37
#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
38
 
39
#include "lwip/ip_addr.h"
40
#include "lwip/mem.h"
41
#include "lwip/udp.h"
42
#include "lwip/stats.h"
43
#include "lwip/snmp.h"
44
#include "lwip/snmp_asn1.h"
45
#include "lwip/snmp_msg.h"
46
#include "lwip/snmp_structs.h"
47
 
48
#include <string.h>
49
 
50
/* public (non-static) constants */
51
/** SNMP v1 == 0 */
52
const s32_t snmp_version = 0;
53
/** default SNMP community string */
54
const char snmp_publiccommunity[7] = "public";
55
 
56
/* statically allocated buffers for SNMP_CONCURRENT_REQUESTS */
57
struct snmp_msg_pstat msg_input_list[SNMP_CONCURRENT_REQUESTS];
58
/* UDP Protocol Control Block */
59
struct udp_pcb *snmp1_pcb;
60
 
61
static void snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port);
62
static err_t snmp_pdu_header_check(struct pbuf *p, u16_t ofs, u16_t pdu_len, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat);
63
static err_t snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat);
64
 
65
 
66
/**
67
 * Starts SNMP Agent.
68
 * Allocates UDP pcb and binds it to IP_ADDR_ANY port 161.
69
 */
70
void
71
snmp_init(void)
72
{
73
  struct snmp_msg_pstat *msg_ps;
74
  u8_t i;
75
 
76
  snmp1_pcb = udp_new();
77
  if (snmp1_pcb != NULL)
78
  {
79
    udp_recv(snmp1_pcb, snmp_recv, (void *)SNMP_IN_PORT);
80
    udp_bind(snmp1_pcb, IP_ADDR_ANY, SNMP_IN_PORT);
81
  }
82
  msg_ps = &msg_input_list[0];
83
  for (i=0; i<SNMP_CONCURRENT_REQUESTS; i++)
84
  {
85
    msg_ps->state = SNMP_MSG_EMPTY;
86
    msg_ps->error_index = 0;
87
    msg_ps->error_status = SNMP_ES_NOERROR;
88
    msg_ps++;
89
  }
90
  trap_msg.pcb = snmp1_pcb;
91
  /* The coldstart trap will only be output
92
     if our outgoing interface is up & configured  */
93
  snmp_coldstart_trap();
94
}
95
 
96
static void
97
snmp_error_response(struct snmp_msg_pstat *msg_ps, u8_t error)
98
{
99
  snmp_varbind_list_free(&msg_ps->outvb);
100
  msg_ps->outvb = msg_ps->invb;
101
  msg_ps->invb.head = NULL;
102
  msg_ps->invb.tail = NULL;
103
  msg_ps->invb.count = 0;
104
  msg_ps->error_status = error;
105
  msg_ps->error_index = 1 + msg_ps->vb_idx;
106
  snmp_send_response(msg_ps);
107
  snmp_varbind_list_free(&msg_ps->outvb);
108
  msg_ps->state = SNMP_MSG_EMPTY;
109
}
110
 
111
static void
112
snmp_ok_response(struct snmp_msg_pstat *msg_ps)
113
{
114
  err_t err_ret;
115
 
116
  err_ret = snmp_send_response(msg_ps);
117
  if (err_ret == ERR_MEM)
118
  {
119
    /* serious memory problem, can't return tooBig */
120
  }
121
  else
122
  {
123
    LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event = %"S32_F"\n",msg_ps->error_status));
124
  }
125
  /* free varbinds (if available) */
126
  snmp_varbind_list_free(&msg_ps->invb);
127
  snmp_varbind_list_free(&msg_ps->outvb);
128
  msg_ps->state = SNMP_MSG_EMPTY;
129
}
130
 
131
/**
132
 * Service an internal or external event for SNMP GET.
133
 *
134
 * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1)
135
 * @param msg_ps points to the assosicated message process state
136
 */
137
static void
138
snmp_msg_get_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
139
{
140
  LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_get_event: msg_ps->state==%"U16_F"\n",(u16_t)msg_ps->state));
141
 
142
  if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF)
143
  {
144
    struct mib_external_node *en;
145
    struct snmp_name_ptr np;
146
 
147
    /* get_object_def() answer*/
148
    en = msg_ps->ext_mib_node;
149
    np = msg_ps->ext_name_ptr;
150
 
151
    /* translate answer into a known lifeform */
152
    en->get_object_def_a(request_id, np.ident_len, np.ident, &msg_ps->ext_object_def);
153
    if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE)
154
    {
155
      msg_ps->state = SNMP_MSG_EXTERNAL_GET_VALUE;
156
      en->get_value_q(request_id, &msg_ps->ext_object_def);
157
    }
158
    else
159
    {
160
      en->get_object_def_pc(request_id, np.ident_len, np.ident);
161
      /* search failed, object id points to unknown object (nosuchname) */
162
      snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
163
    }
164
  }
165
  else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_VALUE)
166
  {
167
    struct mib_external_node *en;
168
    struct snmp_varbind *vb;
169
 
170
    /* get_value() answer */
171
    en = msg_ps->ext_mib_node;
172
 
173
    /* allocate output varbind */
174
    vb = (struct snmp_varbind *)mem_malloc(sizeof(struct snmp_varbind));
175
    LWIP_ASSERT("vb != NULL",vb != NULL);
176
    if (vb != NULL)
177
    {
178
      vb->next = NULL;
179
      vb->prev = NULL;
180
 
181
      /* move name from invb to outvb */
182
      vb->ident = msg_ps->vb_ptr->ident;
183
      vb->ident_len = msg_ps->vb_ptr->ident_len;
184
      /* ensure this memory is refereced once only */
185
      msg_ps->vb_ptr->ident = NULL;
186
      msg_ps->vb_ptr->ident_len = 0;
187
 
188
      vb->value_type = msg_ps->ext_object_def.asn_type;
189
      vb->value_len =  msg_ps->ext_object_def.v_len;
190
      if (vb->value_len > 0)
191
      {
192
        vb->value = mem_malloc(vb->value_len);
193
        LWIP_ASSERT("vb->value != NULL",vb->value != NULL);
194
        if (vb->value != NULL)
195
        {
196
          en->get_value_a(request_id, &msg_ps->ext_object_def, vb->value_len, vb->value);
197
          snmp_varbind_tail_add(&msg_ps->outvb, vb);
198
          /* search again (if vb_idx < msg_ps->invb.count) */
199
          msg_ps->state = SNMP_MSG_SEARCH_OBJ;
200
          msg_ps->vb_idx += 1;
201
        }
202
        else
203
        {
204
          en->get_value_pc(request_id, &msg_ps->ext_object_def);
205
          LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: no variable space\n"));
206
          msg_ps->vb_ptr->ident = vb->ident;
207
          msg_ps->vb_ptr->ident_len = vb->ident_len;
208
          mem_free(vb);
209
          snmp_error_response(msg_ps,SNMP_ES_TOOBIG);
210
        }
211
      }
212
      else
213
      {
214
        /* vb->value_len == 0, empty value (e.g. empty string) */
215
        en->get_value_a(request_id, &msg_ps->ext_object_def, 0, NULL);
216
        vb->value = NULL;
217
        snmp_varbind_tail_add(&msg_ps->outvb, vb);
218
        /* search again (if vb_idx < msg_ps->invb.count) */
219
        msg_ps->state = SNMP_MSG_SEARCH_OBJ;
220
        msg_ps->vb_idx += 1;
221
      }
222
    }
223
    else
224
    {
225
      en->get_value_pc(request_id, &msg_ps->ext_object_def);
226
      LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: no outvb space\n"));
227
      snmp_error_response(msg_ps,SNMP_ES_TOOBIG);
228
    }
229
  }
230
 
231
  while ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&
232
         (msg_ps->vb_idx < msg_ps->invb.count))
233
  {
234
    struct mib_node *mn;
235
    struct snmp_name_ptr np;
236
 
237
    if (msg_ps->vb_idx == 0)
238
    {
239
      msg_ps->vb_ptr = msg_ps->invb.head;
240
    }
241
    else
242
    {
243
      msg_ps->vb_ptr = msg_ps->vb_ptr->next;
244
    }
245
    /** test object identifier for .iso.org.dod.internet prefix */
246
    if (snmp_iso_prefix_tst(msg_ps->vb_ptr->ident_len,  msg_ps->vb_ptr->ident))
247
    {
248
      mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4,
249
                             msg_ps->vb_ptr->ident + 4, &np);
250
      if (mn != NULL)
251
      {
252
        if (mn->node_type == MIB_NODE_EX)
253
        {
254
          /* external object */
255
          struct mib_external_node *en = (struct mib_external_node*)mn;
256
 
257
          msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF;
258
          /* save en && args in msg_ps!! */
259
          msg_ps->ext_mib_node = en;
260
          msg_ps->ext_name_ptr = np;
261
 
262
          en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident);
263
        }
264
        else
265
        {
266
          /* internal object */
267
          struct obj_def object_def;
268
 
269
          msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF;
270
          mn->get_object_def(np.ident_len, np.ident, &object_def);
271
          if (object_def.instance != MIB_OBJECT_NONE)
272
          {
273
            mn = mn;
274
          }
275
          else
276
          {
277
            /* search failed, object id points to unknown object (nosuchname) */
278
            mn =  NULL;
279
          }
280
          if (mn != NULL)
281
          {
282
            struct snmp_varbind *vb;
283
 
284
            msg_ps->state = SNMP_MSG_INTERNAL_GET_VALUE;
285
            /* allocate output varbind */
286
            vb = (struct snmp_varbind *)mem_malloc(sizeof(struct snmp_varbind));
287
            LWIP_ASSERT("vb != NULL",vb != NULL);
288
            if (vb != NULL)
289
            {
290
              vb->next = NULL;
291
              vb->prev = NULL;
292
 
293
              /* move name from invb to outvb */
294
              vb->ident = msg_ps->vb_ptr->ident;
295
              vb->ident_len = msg_ps->vb_ptr->ident_len;
296
              /* ensure this memory is refereced once only */
297
              msg_ps->vb_ptr->ident = NULL;
298
              msg_ps->vb_ptr->ident_len = 0;
299
 
300
              vb->value_type = object_def.asn_type;
301
              vb->value_len = object_def.v_len;
302
              if (vb->value_len > 0)
303
              {
304
                vb->value = mem_malloc(vb->value_len);
305
                LWIP_ASSERT("vb->value != NULL",vb->value != NULL);
306
                if (vb->value != NULL)
307
                {
308
                  mn->get_value(&object_def, vb->value_len, vb->value);
309
                  snmp_varbind_tail_add(&msg_ps->outvb, vb);
310
                  msg_ps->state = SNMP_MSG_SEARCH_OBJ;
311
                  msg_ps->vb_idx += 1;
312
                }
313
                else
314
                {
315
                  LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: couldn't allocate variable space\n"));
316
                  msg_ps->vb_ptr->ident = vb->ident;
317
                  msg_ps->vb_ptr->ident_len = vb->ident_len;
318
                  mem_free(vb);
319
                  snmp_error_response(msg_ps,SNMP_ES_TOOBIG);
320
                }
321
              }
322
              else
323
              {
324
                /* vb->value_len == 0, empty value (e.g. empty string) */
325
                vb->value = NULL;
326
                snmp_varbind_tail_add(&msg_ps->outvb, vb);
327
                msg_ps->state = SNMP_MSG_SEARCH_OBJ;
328
                msg_ps->vb_idx += 1;
329
              }
330
            }
331
            else
332
            {
333
              LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: couldn't allocate outvb space\n"));
334
              snmp_error_response(msg_ps,SNMP_ES_TOOBIG);
335
            }
336
          }
337
        }
338
      }
339
    }
340
    else
341
    {
342
      mn = NULL;
343
    }
344
    if (mn == NULL)
345
    {
346
      /* mn == NULL, noSuchName */
347
      snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
348
    }
349
  }
350
  if ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&
351
      (msg_ps->vb_idx == msg_ps->invb.count))
352
  {
353
    snmp_ok_response(msg_ps);
354
  }
355
}
356
 
357
/**
358
 * Service an internal or external event for SNMP GETNEXT.
359
 *
360
 * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1)
361
 * @param msg_ps points to the assosicated message process state
362
 */
363
static void
364
snmp_msg_getnext_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
365
{
366
  LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_getnext_event: msg_ps->state==%"U16_F"\n",(u16_t)msg_ps->state));
367
 
368
  if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF)
369
  {
370
    struct mib_external_node *en;
371
 
372
    /* get_object_def() answer*/
373
    en = msg_ps->ext_mib_node;
374
 
375
    /* translate answer into a known lifeform */
376
    en->get_object_def_a(request_id, 1, &msg_ps->ext_oid.id[msg_ps->ext_oid.len - 1], &msg_ps->ext_object_def);
377
    if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE)
378
    {
379
      msg_ps->state = SNMP_MSG_EXTERNAL_GET_VALUE;
380
      en->get_value_q(request_id, &msg_ps->ext_object_def);
381
    }
382
    else
383
    {
384
      en->get_object_def_pc(request_id, 1, &msg_ps->ext_oid.id[msg_ps->ext_oid.len - 1]);
385
      /* search failed, object id points to unknown object (nosuchname) */
386
      snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
387
    }
388
  }
389
  else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_VALUE)
390
  {
391
    struct mib_external_node *en;
392
    struct snmp_varbind *vb;
393
 
394
    /* get_value() answer */
395
    en = msg_ps->ext_mib_node;
396
 
397
    vb = snmp_varbind_alloc(&msg_ps->ext_oid,
398
                            msg_ps->ext_object_def.asn_type,
399
                            msg_ps->ext_object_def.v_len);
400
    if (vb != NULL)
401
    {
402
      en->get_value_a(request_id, &msg_ps->ext_object_def, vb->value_len, vb->value);
403
      snmp_varbind_tail_add(&msg_ps->outvb, vb);
404
      msg_ps->state = SNMP_MSG_SEARCH_OBJ;
405
      msg_ps->vb_idx += 1;
406
    }
407
    else
408
    {
409
      en->get_value_pc(request_id, &msg_ps->ext_object_def);
410
      LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_getnext_event: couldn't allocate outvb space\n"));
411
      snmp_error_response(msg_ps,SNMP_ES_TOOBIG);
412
    }
413
  }
414
 
415
  while ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&
416
         (msg_ps->vb_idx < msg_ps->invb.count))
417
  {
418
    struct mib_node *mn;
419
    struct snmp_obj_id oid;
420
 
421
    if (msg_ps->vb_idx == 0)
422
    {
423
      msg_ps->vb_ptr = msg_ps->invb.head;
424
    }
425
    else
426
    {
427
      msg_ps->vb_ptr = msg_ps->vb_ptr->next;
428
    }
429
    if (snmp_iso_prefix_expand(msg_ps->vb_ptr->ident_len, msg_ps->vb_ptr->ident, &oid))
430
    {
431
      if (msg_ps->vb_ptr->ident_len > 3)
432
      {
433
        /* can offset ident_len and ident */
434
        mn = snmp_expand_tree((struct mib_node*)&internet,
435
                              msg_ps->vb_ptr->ident_len - 4,
436
                              msg_ps->vb_ptr->ident + 4, &oid);
437
      }
438
      else
439
      {
440
        /* can't offset ident_len -4, ident + 4 */
441
        mn = snmp_expand_tree((struct mib_node*)&internet, 0, NULL, &oid);
442
      }
443
    }
444
    else
445
    {
446
      mn = NULL;
447
    }
448
    if (mn != NULL)
449
    {
450
      if (mn->node_type == MIB_NODE_EX)
451
      {
452
        /* external object */
453
        struct mib_external_node *en = (struct mib_external_node*)mn;
454
 
455
        msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF;
456
        /* save en && args in msg_ps!! */
457
        msg_ps->ext_mib_node = en;
458
        msg_ps->ext_oid = oid;
459
 
460
        en->get_object_def_q(en->addr_inf, request_id, 1, &oid.id[oid.len - 1]);
461
      }
462
      else
463
      {
464
        /* internal object */
465
        struct obj_def object_def;
466
        struct snmp_varbind *vb;
467
 
468
        msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF;
469
        mn->get_object_def(1, &oid.id[oid.len - 1], &object_def);
470
 
471
        vb = snmp_varbind_alloc(&oid, object_def.asn_type, object_def.v_len);
472
        if (vb != NULL)
473
        {
474
          msg_ps->state = SNMP_MSG_INTERNAL_GET_VALUE;
475
          mn->get_value(&object_def, object_def.v_len, vb->value);
476
          snmp_varbind_tail_add(&msg_ps->outvb, vb);
477
          msg_ps->state = SNMP_MSG_SEARCH_OBJ;
478
          msg_ps->vb_idx += 1;
479
        }
480
        else
481
        {
482
          LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv couldn't allocate outvb space\n"));
483
          snmp_error_response(msg_ps,SNMP_ES_TOOBIG);
484
        }
485
      }
486
    }
487
    if (mn == NULL)
488
    {
489
      /* mn == NULL, noSuchName */
490
      snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
491
    }
492
  }
493
  if ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&
494
      (msg_ps->vb_idx == msg_ps->invb.count))
495
  {
496
    snmp_ok_response(msg_ps);
497
  }
498
}
499
 
500
/**
501
 * Service an internal or external event for SNMP SET.
502
 *
503
 * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1)
504
 * @param msg_ps points to the assosicated message process state
505
 */
506
static void
507
snmp_msg_set_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
508
{
509
  LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_set_event: msg_ps->state==%"U16_F"\n",(u16_t)msg_ps->state));
510
 
511
  if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF)
512
  {
513
    struct mib_external_node *en;
514
    struct snmp_name_ptr np;
515
 
516
    /* get_object_def() answer*/
517
    en = msg_ps->ext_mib_node;
518
    np = msg_ps->ext_name_ptr;
519
 
520
    /* translate answer into a known lifeform */
521
    en->get_object_def_a(request_id, np.ident_len, np.ident, &msg_ps->ext_object_def);
522
    if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE)
523
    {
524
      msg_ps->state = SNMP_MSG_EXTERNAL_SET_TEST;
525
      en->set_test_q(request_id, &msg_ps->ext_object_def);
526
    }
527
    else
528
    {
529
      en->get_object_def_pc(request_id, np.ident_len, np.ident);
530
      /* search failed, object id points to unknown object (nosuchname) */
531
      snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
532
    }
533
  }
534
  else if (msg_ps->state == SNMP_MSG_EXTERNAL_SET_TEST)
535
  {
536
    struct mib_external_node *en;
537
 
538
    /* set_test() answer*/
539
    en = msg_ps->ext_mib_node;
540
 
541
    if (msg_ps->ext_object_def.access == MIB_OBJECT_READ_WRITE)
542
    {
543
       if ((msg_ps->ext_object_def.asn_type == msg_ps->vb_ptr->value_type) &&
544
           (en->set_test_a(request_id,&msg_ps->ext_object_def,
545
                           msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value) != 0))
546
      {
547
        msg_ps->state = SNMP_MSG_SEARCH_OBJ;
548
        msg_ps->vb_idx += 1;
549
      }
550
      else
551
      {
552
        en->set_test_pc(request_id,&msg_ps->ext_object_def);
553
        /* bad value */
554
        snmp_error_response(msg_ps,SNMP_ES_BADVALUE);
555
      }
556
    }
557
    else
558
    {
559
      en->set_test_pc(request_id,&msg_ps->ext_object_def);
560
      /* object not available for set */
561
      snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
562
    }
563
  }
564
  else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF_S)
565
  {
566
    struct mib_external_node *en;
567
    struct snmp_name_ptr np;
568
 
569
    /* get_object_def() answer*/
570
    en = msg_ps->ext_mib_node;
571
    np = msg_ps->ext_name_ptr;
572
 
573
    /* translate answer into a known lifeform */
574
    en->get_object_def_a(request_id, np.ident_len, np.ident, &msg_ps->ext_object_def);
575
    if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE)
576
    {
577
      msg_ps->state = SNMP_MSG_EXTERNAL_SET_VALUE;
578
      en->set_value_q(request_id, &msg_ps->ext_object_def,
579
                      msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value);
580
    }
581
    else
582
    {
583
      en->get_object_def_pc(request_id, np.ident_len, np.ident);
584
      /* set_value failed, object has disappeared for some odd reason?? */
585
      snmp_error_response(msg_ps,SNMP_ES_GENERROR);
586
    }
587
  }
588
  else if (msg_ps->state == SNMP_MSG_EXTERNAL_SET_VALUE)
589
  {
590
    struct mib_external_node *en;
591
 
592
    /** set_value_a() */
593
    en = msg_ps->ext_mib_node;
594
    en->set_value_a(request_id, &msg_ps->ext_object_def,
595
      msg_ps->vb_ptr->value_len, msg_ps->vb_ptr->value);
596
 
597
    /** @todo use set_value_pc() if toobig */
598
    msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE;
599
    msg_ps->vb_idx += 1;
600
  }
601
 
602
  /* test all values before setting */
603
  while ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&
604
         (msg_ps->vb_idx < msg_ps->invb.count))
605
  {
606
    struct mib_node *mn;
607
    struct snmp_name_ptr np;
608
 
609
    if (msg_ps->vb_idx == 0)
610
    {
611
      msg_ps->vb_ptr = msg_ps->invb.head;
612
    }
613
    else
614
    {
615
      msg_ps->vb_ptr = msg_ps->vb_ptr->next;
616
    }
617
    /** test object identifier for .iso.org.dod.internet prefix */
618
    if (snmp_iso_prefix_tst(msg_ps->vb_ptr->ident_len,  msg_ps->vb_ptr->ident))
619
    {
620
      mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4,
621
                             msg_ps->vb_ptr->ident + 4, &np);
622
      if (mn != NULL)
623
      {
624
        if (mn->node_type == MIB_NODE_EX)
625
        {
626
          /* external object */
627
          struct mib_external_node *en = (struct mib_external_node*)mn;
628
 
629
          msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF;
630
          /* save en && args in msg_ps!! */
631
          msg_ps->ext_mib_node = en;
632
          msg_ps->ext_name_ptr = np;
633
 
634
          en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident);
635
        }
636
        else
637
        {
638
          /* internal object */
639
          struct obj_def object_def;
640
 
641
          msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF;
642
          mn->get_object_def(np.ident_len, np.ident, &object_def);
643
          if (object_def.instance != MIB_OBJECT_NONE)
644
          {
645
            mn = mn;
646
          }
647
          else
648
          {
649
            /* search failed, object id points to unknown object (nosuchname) */
650
            mn = NULL;
651
          }
652
          if (mn != NULL)
653
          {
654
            msg_ps->state = SNMP_MSG_INTERNAL_SET_TEST;
655
 
656
            if (object_def.access == MIB_OBJECT_READ_WRITE)
657
            {
658
              if ((object_def.asn_type == msg_ps->vb_ptr->value_type) &&
659
                  (mn->set_test(&object_def,msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value) != 0))
660
              {
661
                msg_ps->state = SNMP_MSG_SEARCH_OBJ;
662
                msg_ps->vb_idx += 1;
663
              }
664
              else
665
              {
666
                /* bad value */
667
                snmp_error_response(msg_ps,SNMP_ES_BADVALUE);
668
              }
669
            }
670
            else
671
            {
672
              /* object not available for set */
673
              snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
674
            }
675
          }
676
        }
677
      }
678
    }
679
    else
680
    {
681
      mn = NULL;
682
    }
683
    if (mn == NULL)
684
    {
685
      /* mn == NULL, noSuchName */
686
      snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
687
    }
688
  }
689
 
690
  if ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&
691
      (msg_ps->vb_idx == msg_ps->invb.count))
692
  {
693
    msg_ps->vb_idx = 0;
694
    msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE;
695
  }
696
 
697
  /* set all values "atomically" (be as "atomic" as possible) */
698
  while ((msg_ps->state == SNMP_MSG_INTERNAL_SET_VALUE) &&
699
         (msg_ps->vb_idx < msg_ps->invb.count))
700
  {
701
    struct mib_node *mn;
702
    struct snmp_name_ptr np;
703
 
704
    if (msg_ps->vb_idx == 0)
705
    {
706
      msg_ps->vb_ptr = msg_ps->invb.head;
707
    }
708
    else
709
    {
710
      msg_ps->vb_ptr = msg_ps->vb_ptr->next;
711
    }
712
    /* skip iso prefix test, was done previously while settesting() */
713
    mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4,
714
                           msg_ps->vb_ptr->ident + 4, &np);
715
    /* check if object is still available
716
       (e.g. external hot-plug thingy present?) */
717
    if (mn != NULL)
718
    {
719
      if (mn->node_type == MIB_NODE_EX)
720
      {
721
        /* external object */
722
        struct mib_external_node *en = (struct mib_external_node*)mn;
723
 
724
        msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF_S;
725
        /* save en && args in msg_ps!! */
726
        msg_ps->ext_mib_node = en;
727
        msg_ps->ext_name_ptr = np;
728
 
729
        en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident);
730
      }
731
      else
732
      {
733
        /* internal object */
734
        struct obj_def object_def;
735
 
736
        msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF_S;
737
        mn->get_object_def(np.ident_len, np.ident, &object_def);
738
        msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE;
739
        mn->set_value(&object_def,msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value);
740
        msg_ps->vb_idx += 1;
741
      }
742
    }
743
  }
744
  if ((msg_ps->state == SNMP_MSG_INTERNAL_SET_VALUE) &&
745
      (msg_ps->vb_idx == msg_ps->invb.count))
746
  {
747
    /* simply echo the input if we can set it
748
       @todo do we need to return the actual value?
749
       e.g. if value is silently modified or behaves sticky? */
750
    msg_ps->outvb = msg_ps->invb;
751
    msg_ps->invb.head = NULL;
752
    msg_ps->invb.tail = NULL;
753
    msg_ps->invb.count = 0;
754
    snmp_ok_response(msg_ps);
755
  }
756
}
757
 
758
 
759
/**
760
 * Handle one internal or external event.
761
 * Called for one async event. (recv external/private answer)
762
 *
763
 * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1)
764
 */
765
void
766
snmp_msg_event(u8_t request_id)
767
{
768
  struct snmp_msg_pstat *msg_ps;
769
 
770
  if (request_id < SNMP_CONCURRENT_REQUESTS)
771
  {
772
    msg_ps = &msg_input_list[request_id];
773
    if (msg_ps->rt == SNMP_ASN1_PDU_GET_NEXT_REQ)
774
    {
775
      snmp_msg_getnext_event(request_id, msg_ps);
776
    }
777
    else if (msg_ps->rt == SNMP_ASN1_PDU_GET_REQ)
778
    {
779
      snmp_msg_get_event(request_id, msg_ps);
780
    }
781
    else if(msg_ps->rt == SNMP_ASN1_PDU_SET_REQ)
782
    {
783
      snmp_msg_set_event(request_id, msg_ps);
784
    }
785
  }
786
}
787
 
788
 
789
/* lwIP UDP receive callback function */
790
static void
791
snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port)
792
{
793
  struct udp_hdr *udphdr;
794
 
795
  /* suppress unused argument warning */
796
  LWIP_UNUSED_ARG(arg);
797
  /* peek in the UDP header (goto IP payload) */
798
  if(pbuf_header(p, UDP_HLEN)){
799
    LWIP_ASSERT("Can't move to UDP header", 0);
800
    pbuf_free(p);
801
    return;
802
  }
803
  udphdr = p->payload;
804
 
805
  /* check if datagram is really directed at us (including broadcast requests) */
806
  if ((pcb == snmp1_pcb) && (ntohs(udphdr->dest) == SNMP_IN_PORT))
807
  {
808
    struct snmp_msg_pstat *msg_ps;
809
    u8_t req_idx;
810
 
811
    /* traverse input message process list, look for SNMP_MSG_EMPTY */
812
    msg_ps = &msg_input_list[0];
813
    req_idx = 0;
814
    while ((req_idx<SNMP_CONCURRENT_REQUESTS) && (msg_ps->state != SNMP_MSG_EMPTY))
815
    {
816
      req_idx++;
817
      msg_ps++;
818
    }
819
    if (req_idx != SNMP_CONCURRENT_REQUESTS)
820
    {
821
      err_t err_ret;
822
      u16_t payload_len;
823
      u16_t payload_ofs;
824
      u16_t varbind_ofs = 0;
825
 
826
      /* accepting request */
827
      snmp_inc_snmpinpkts();
828
      /* record used 'protocol control block' */
829
      msg_ps->pcb = pcb;
830
      /* source address (network order) */
831
      msg_ps->sip = *addr;
832
      /* source port (host order (lwIP oddity)) */
833
      msg_ps->sp = port;
834
      /* read UDP payload length from UDP header */
835
      payload_len = ntohs(udphdr->len) - UDP_HLEN;
836
 
837
      /* adjust to UDP payload */
838
      payload_ofs = UDP_HLEN;
839
 
840
      /* check total length, version, community, pdu type */
841
      err_ret = snmp_pdu_header_check(p, payload_ofs, payload_len, &varbind_ofs, msg_ps);
842
      if (((msg_ps->rt == SNMP_ASN1_PDU_GET_REQ) ||
843
           (msg_ps->rt == SNMP_ASN1_PDU_GET_NEXT_REQ) ||
844
           (msg_ps->rt == SNMP_ASN1_PDU_SET_REQ)) &&
845
          ((msg_ps->error_status == SNMP_ES_NOERROR) &&
846
           (msg_ps->error_index == 0)) )
847
      {
848
        /* Only accept requests and requests without error (be robust) */
849
        err_ret = err_ret;
850
      }
851
      else
852
      {
853
        /* Reject response and trap headers or error requests as input! */
854
        err_ret = ERR_ARG;
855
      }
856
      if (err_ret == ERR_OK)
857
      {
858
        LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv ok, community %s\n", msg_ps->community));
859
 
860
        /* Builds a list of variable bindings. Copy the varbinds from the pbuf
861
          chain to glue them when these are divided over two or more pbuf's. */
862
        err_ret = snmp_pdu_dec_varbindlist(p, varbind_ofs, &varbind_ofs, msg_ps);
863
        if ((err_ret == ERR_OK) && (msg_ps->invb.count > 0))
864
        {
865
          /* we've decoded the incoming message, release input msg now */
866
          pbuf_free(p);
867
 
868
          msg_ps->error_status = SNMP_ES_NOERROR;
869
          msg_ps->error_index = 0;
870
          /* find object for each variable binding */
871
          msg_ps->state = SNMP_MSG_SEARCH_OBJ;
872
          /* first variable binding from list to inspect */
873
          msg_ps->vb_idx = 0;
874
 
875
          LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv varbind cnt=%"U16_F"\n",(u16_t)msg_ps->invb.count));
876
 
877
          /* handle input event and as much objects as possible in one go */
878
          snmp_msg_event(req_idx);
879
        }
880
        else
881
        {
882
          /* varbind-list decode failed, or varbind list empty.
883
             drop request silently, do not return error!
884
             (errors are only returned for a specific varbind failure) */
885
          pbuf_free(p);
886
          LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_dec_varbindlist() failed\n"));
887
        }
888
      }
889
      else
890
      {
891
        /* header check failed
892
           drop request silently, do not return error! */
893
        pbuf_free(p);
894
        LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_header_check() failed\n"));
895
      }
896
    }
897
    else
898
    {
899
      /* exceeding number of concurrent requests */
900
      pbuf_free(p);
901
    }
902
  }
903
  else
904
  {
905
    /* datagram not for us */
906
    pbuf_free(p);
907
  }
908
}
909
 
910
/**
911
 * Checks and decodes incoming SNMP message header, logs header errors.
912
 *
913
 * @param p points to pbuf chain of SNMP message (UDP payload)
914
 * @param ofs points to first octet of SNMP message
915
 * @param pdu_len the length of the UDP payload
916
 * @param ofs_ret returns the ofset of the variable bindings
917
 * @param m_stat points to the current message request state return
918
 * @return
919
 * - ERR_OK SNMP header is sane and accepted
920
 * - ERR_ARG SNMP header is either malformed or rejected
921
 */
922
static err_t
923
snmp_pdu_header_check(struct pbuf *p, u16_t ofs, u16_t pdu_len, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat)
924
{
925
  err_t derr;
926
  u16_t len, ofs_base;
927
  u8_t  len_octets;
928
  u8_t  type;
929
  s32_t version;
930
 
931
  ofs_base = ofs;
932
  snmp_asn1_dec_type(p, ofs, &type);
933
  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
934
  if ((derr != ERR_OK) ||
935
      (pdu_len != (1 + len_octets + len)) ||
936
      (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)))
937
  {
938
    snmp_inc_snmpinasnparseerrs();
939
    return ERR_ARG;
940
  }
941
  ofs += (1 + len_octets);
942
  snmp_asn1_dec_type(p, ofs, &type);
943
  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
944
  if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))
945
  {
946
    /* can't decode or no integer (version) */
947
    snmp_inc_snmpinasnparseerrs();
948
    return ERR_ARG;
949
  }
950
  derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &version);
951
  if (derr != ERR_OK)
952
  {
953
    /* can't decode */
954
    snmp_inc_snmpinasnparseerrs();
955
    return ERR_ARG;
956
  }
957
  if (version != 0)
958
  {
959
    /* not version 1 */
960
    snmp_inc_snmpinbadversions();
961
    return ERR_ARG;
962
  }
963
  ofs += (1 + len_octets + len);
964
  snmp_asn1_dec_type(p, ofs, &type);
965
  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
966
  if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR)))
967
  {
968
    /* can't decode or no octet string (community) */
969
    snmp_inc_snmpinasnparseerrs();
970
    return ERR_ARG;
971
  }
972
  derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, SNMP_COMMUNITY_STR_LEN, m_stat->community);
973
  if (derr != ERR_OK)
974
  {
975
    snmp_inc_snmpinasnparseerrs();
976
    return ERR_ARG;
977
  }
978
  /* add zero terminator */
979
  len = ((len < (SNMP_COMMUNITY_STR_LEN))?(len):(SNMP_COMMUNITY_STR_LEN));
980
  m_stat->community[len] = 0;
981
  m_stat->com_strlen = len;
982
  if (strncmp(snmp_publiccommunity, (const char*)m_stat->community, SNMP_COMMUNITY_STR_LEN) != 0)
983
  {
984
    /** @todo: move this if we need to check more names */
985
    snmp_inc_snmpinbadcommunitynames();
986
    snmp_authfail_trap();
987
    return ERR_ARG;
988
  }
989
  ofs += (1 + len_octets + len);
990
  snmp_asn1_dec_type(p, ofs, &type);
991
  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
992
  if (derr != ERR_OK)
993
  {
994
    snmp_inc_snmpinasnparseerrs();
995
    return ERR_ARG;
996
  }
997
  switch(type)
998
  {
999
    case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_REQ):
1000
      /* GetRequest PDU */
1001
      snmp_inc_snmpingetrequests();
1002
      derr = ERR_OK;
1003
      break;
1004
    case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_NEXT_REQ):
1005
      /* GetNextRequest PDU */
1006
      snmp_inc_snmpingetnexts();
1007
      derr = ERR_OK;
1008
      break;
1009
    case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_RESP):
1010
      /* GetResponse PDU */
1011
      snmp_inc_snmpingetresponses();
1012
      derr = ERR_ARG;
1013
      break;
1014
    case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_SET_REQ):
1015
      /* SetRequest PDU */
1016
      snmp_inc_snmpinsetrequests();
1017
      derr = ERR_OK;
1018
      break;
1019
    case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_TRAP):
1020
      /* Trap PDU */
1021
      snmp_inc_snmpintraps();
1022
      derr = ERR_ARG;
1023
      break;
1024
    default:
1025
      snmp_inc_snmpinasnparseerrs();
1026
      derr = ERR_ARG;
1027
      break;
1028
  }
1029
  if (derr != ERR_OK)
1030
  {
1031
    /* unsupported input PDU for this agent (no parse error) */
1032
    return ERR_ARG;
1033
  }
1034
  m_stat->rt = type & 0x1F;
1035
  ofs += (1 + len_octets);
1036
  if (len != (pdu_len - (ofs - ofs_base)))
1037
  {
1038
    /* decoded PDU length does not equal actual payload length */
1039
    snmp_inc_snmpinasnparseerrs();
1040
    return ERR_ARG;
1041
  }
1042
  snmp_asn1_dec_type(p, ofs, &type);
1043
  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
1044
  if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))
1045
  {
1046
    /* can't decode or no integer (request ID) */
1047
    snmp_inc_snmpinasnparseerrs();
1048
    return ERR_ARG;
1049
  }
1050
  derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->rid);
1051
  if (derr != ERR_OK)
1052
  {
1053
    /* can't decode */
1054
    snmp_inc_snmpinasnparseerrs();
1055
    return ERR_ARG;
1056
  }
1057
  ofs += (1 + len_octets + len);
1058
  snmp_asn1_dec_type(p, ofs, &type);
1059
  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
1060
  if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))
1061
  {
1062
    /* can't decode or no integer (error-status) */
1063
    snmp_inc_snmpinasnparseerrs();
1064
    return ERR_ARG;
1065
  }
1066
  /* must be noError (0) for incoming requests.
1067
     log errors for mib-2 completeness and for debug purposes */
1068
  derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->error_status);
1069
  if (derr != ERR_OK)
1070
  {
1071
    /* can't decode */
1072
    snmp_inc_snmpinasnparseerrs();
1073
    return ERR_ARG;
1074
  }
1075
  switch (m_stat->error_status)
1076
  {
1077
    case SNMP_ES_TOOBIG:
1078
      snmp_inc_snmpintoobigs();
1079
      break;
1080
    case SNMP_ES_NOSUCHNAME:
1081
      snmp_inc_snmpinnosuchnames();
1082
      break;
1083
    case SNMP_ES_BADVALUE:
1084
      snmp_inc_snmpinbadvalues();
1085
      break;
1086
    case SNMP_ES_READONLY:
1087
      snmp_inc_snmpinreadonlys();
1088
      break;
1089
    case SNMP_ES_GENERROR:
1090
      snmp_inc_snmpingenerrs();
1091
      break;
1092
  }
1093
  ofs += (1 + len_octets + len);
1094
  snmp_asn1_dec_type(p, ofs, &type);
1095
  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
1096
  if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))
1097
  {
1098
    /* can't decode or no integer (error-index) */
1099
    snmp_inc_snmpinasnparseerrs();
1100
    return ERR_ARG;
1101
  }
1102
  /* must be 0 for incoming requests.
1103
     decode anyway to catch bad integers (and dirty tricks) */
1104
  derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->error_index);
1105
  if (derr != ERR_OK)
1106
  {
1107
    /* can't decode */
1108
    snmp_inc_snmpinasnparseerrs();
1109
    return ERR_ARG;
1110
  }
1111
  ofs += (1 + len_octets + len);
1112
  *ofs_ret = ofs;
1113
  return ERR_OK;
1114
}
1115
 
1116
static err_t
1117
snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat)
1118
{
1119
  err_t derr;
1120
  u16_t len, vb_len;
1121
  u8_t  len_octets;
1122
  u8_t type;
1123
 
1124
  /* variable binding list */
1125
  snmp_asn1_dec_type(p, ofs, &type);
1126
  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &vb_len);
1127
  if ((derr != ERR_OK) ||
1128
      (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)))
1129
  {
1130
    snmp_inc_snmpinasnparseerrs();
1131
    return ERR_ARG;
1132
  }
1133
  ofs += (1 + len_octets);
1134
 
1135
  /* start with empty list */
1136
  m_stat->invb.count = 0;
1137
  m_stat->invb.head = NULL;
1138
  m_stat->invb.tail = NULL;
1139
 
1140
  while (vb_len > 0)
1141
  {
1142
    struct snmp_obj_id oid, oid_value;
1143
    struct snmp_varbind *vb;
1144
 
1145
    snmp_asn1_dec_type(p, ofs, &type);
1146
    derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
1147
    if ((derr != ERR_OK) ||
1148
        (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)) ||
1149
        (len == 0) || (len > vb_len))
1150
    {
1151
      snmp_inc_snmpinasnparseerrs();
1152
      /* free varbinds (if available) */
1153
      snmp_varbind_list_free(&m_stat->invb);
1154
      return ERR_ARG;
1155
    }
1156
    ofs += (1 + len_octets);
1157
    vb_len -= (1 + len_octets);
1158
 
1159
    snmp_asn1_dec_type(p, ofs, &type);
1160
    derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
1161
    if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID)))
1162
    {
1163
      /* can't decode object name length */
1164
      snmp_inc_snmpinasnparseerrs();
1165
      /* free varbinds (if available) */
1166
      snmp_varbind_list_free(&m_stat->invb);
1167
      return ERR_ARG;
1168
    }
1169
    derr = snmp_asn1_dec_oid(p, ofs + 1 + len_octets, len, &oid);
1170
    if (derr != ERR_OK)
1171
    {
1172
      /* can't decode object name */
1173
      snmp_inc_snmpinasnparseerrs();
1174
      /* free varbinds (if available) */
1175
      snmp_varbind_list_free(&m_stat->invb);
1176
      return ERR_ARG;
1177
    }
1178
    ofs += (1 + len_octets + len);
1179
    vb_len -= (1 + len_octets + len);
1180
 
1181
    snmp_asn1_dec_type(p, ofs, &type);
1182
    derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
1183
    if (derr != ERR_OK)
1184
    {
1185
      /* can't decode object value length */
1186
      snmp_inc_snmpinasnparseerrs();
1187
      /* free varbinds (if available) */
1188
      snmp_varbind_list_free(&m_stat->invb);
1189
      return ERR_ARG;
1190
    }
1191
 
1192
    switch (type)
1193
    {
1194
      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG):
1195
        vb = snmp_varbind_alloc(&oid, type, sizeof(s32_t));
1196
        if (vb != NULL)
1197
        {
1198
          s32_t *vptr = vb->value;
1199
 
1200
          derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, vptr);
1201
          snmp_varbind_tail_add(&m_stat->invb, vb);
1202
        }
1203
        else
1204
        {
1205
          derr = ERR_ARG;
1206
        }
1207
        break;
1208
      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER):
1209
      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE):
1210
      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS):
1211
        vb = snmp_varbind_alloc(&oid, type, sizeof(u32_t));
1212
        if (vb != NULL)
1213
        {
1214
          u32_t *vptr = vb->value;
1215
 
1216
          derr = snmp_asn1_dec_u32t(p, ofs + 1 + len_octets, len, vptr);
1217
          snmp_varbind_tail_add(&m_stat->invb, vb);
1218
        }
1219
        else
1220
        {
1221
          derr = ERR_ARG;
1222
        }
1223
        break;
1224
      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR):
1225
      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_OPAQUE):
1226
        vb = snmp_varbind_alloc(&oid, type, len);
1227
        if (vb != NULL)
1228
        {
1229
          derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, vb->value_len, vb->value);
1230
          snmp_varbind_tail_add(&m_stat->invb, vb);
1231
        }
1232
        else
1233
        {
1234
          derr = ERR_ARG;
1235
        }
1236
        break;
1237
      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_NUL):
1238
        vb = snmp_varbind_alloc(&oid, type, 0);
1239
        if (vb != NULL)
1240
        {
1241
          snmp_varbind_tail_add(&m_stat->invb, vb);
1242
          derr = ERR_OK;
1243
        }
1244
        else
1245
        {
1246
          derr = ERR_ARG;
1247
        }
1248
        break;
1249
      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID):
1250
        derr = snmp_asn1_dec_oid(p, ofs + 1 + len_octets, len, &oid_value);
1251
        if (derr == ERR_OK)
1252
        {
1253
          vb = snmp_varbind_alloc(&oid, type, oid_value.len * sizeof(s32_t));
1254
          if (vb != NULL)
1255
          {
1256
            u8_t i = oid_value.len;
1257
            s32_t *vptr = vb->value;
1258
 
1259
            while(i > 0)
1260
            {
1261
              i--;
1262
              vptr[i] = oid_value.id[i];
1263
            }
1264
            snmp_varbind_tail_add(&m_stat->invb, vb);
1265
            derr = ERR_OK;
1266
          }
1267
          else
1268
          {
1269
            derr = ERR_ARG;
1270
          }
1271
        }
1272
        break;
1273
      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR):
1274
        if (len == 4)
1275
        {
1276
          /* must be exactly 4 octets! */
1277
          vb = snmp_varbind_alloc(&oid, type, 4);
1278
          if (vb != NULL)
1279
          {
1280
            derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, vb->value_len, vb->value);
1281
            snmp_varbind_tail_add(&m_stat->invb, vb);
1282
          }
1283
          else
1284
          {
1285
            derr = ERR_ARG;
1286
          }
1287
        }
1288
        else
1289
        {
1290
          derr = ERR_ARG;
1291
        }
1292
        break;
1293
      default:
1294
        derr = ERR_ARG;
1295
        break;
1296
    }
1297
    if (derr != ERR_OK)
1298
    {
1299
      snmp_inc_snmpinasnparseerrs();
1300
      /* free varbinds (if available) */
1301
      snmp_varbind_list_free(&m_stat->invb);
1302
      return ERR_ARG;
1303
    }
1304
    ofs += (1 + len_octets + len);
1305
    vb_len -= (1 + len_octets + len);
1306
  }
1307
 
1308
  if (m_stat->rt == SNMP_ASN1_PDU_SET_REQ)
1309
  {
1310
    snmp_add_snmpintotalsetvars(m_stat->invb.count);
1311
  }
1312
  else
1313
  {
1314
    snmp_add_snmpintotalreqvars(m_stat->invb.count);
1315
  }
1316
 
1317
  *ofs_ret = ofs;
1318
  return ERR_OK;
1319
}
1320
 
1321
struct snmp_varbind*
1322
snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u8_t len)
1323
{
1324
  struct snmp_varbind *vb;
1325
 
1326
  vb = (struct snmp_varbind *)mem_malloc(sizeof(struct snmp_varbind));
1327
  LWIP_ASSERT("vb != NULL",vb != NULL);
1328
  if (vb != NULL)
1329
  {
1330
    u8_t i;
1331
 
1332
    vb->next = NULL;
1333
    vb->prev = NULL;
1334
    i = oid->len;
1335
    vb->ident_len = i;
1336
    if (i > 0)
1337
    {
1338
      /* allocate array of s32_t for our object identifier */
1339
      vb->ident = (s32_t*)mem_malloc(sizeof(s32_t) * i);
1340
      LWIP_ASSERT("vb->ident != NULL",vb->ident != NULL);
1341
      if (vb->ident == NULL)
1342
      {
1343
        mem_free(vb);
1344
        return NULL;
1345
      }
1346
      while(i > 0)
1347
      {
1348
        i--;
1349
        vb->ident[i] = oid->id[i];
1350
      }
1351
    }
1352
    else
1353
    {
1354
      /* i == 0, pass zero length object identifier */
1355
      vb->ident = NULL;
1356
    }
1357
    vb->value_type = type;
1358
    vb->value_len = len;
1359
    if (len > 0)
1360
    {
1361
      /* allocate raw bytes for our object value */
1362
      vb->value = mem_malloc(len);
1363
      LWIP_ASSERT("vb->value != NULL",vb->value != NULL);
1364
      if (vb->value == NULL)
1365
      {
1366
        if (vb->ident != NULL)
1367
        {
1368
          mem_free(vb->ident);
1369
        }
1370
        mem_free(vb);
1371
        return NULL;
1372
      }
1373
    }
1374
    else
1375
    {
1376
      /* ASN1_NUL type, or zero length ASN1_OC_STR */
1377
      vb->value = NULL;
1378
    }
1379
  }
1380
  return vb;
1381
}
1382
 
1383
void
1384
snmp_varbind_free(struct snmp_varbind *vb)
1385
{
1386
  if (vb->value != NULL )
1387
  {
1388
    mem_free(vb->value);
1389
  }
1390
  if (vb->ident != NULL )
1391
  {
1392
    mem_free(vb->ident);
1393
  }
1394
  mem_free(vb);
1395
}
1396
 
1397
void
1398
snmp_varbind_list_free(struct snmp_varbind_root *root)
1399
{
1400
  struct snmp_varbind *vb, *prev;
1401
 
1402
  vb = root->tail;
1403
  while ( vb != NULL )
1404
  {
1405
    prev = vb->prev;
1406
    snmp_varbind_free(vb);
1407
    vb = prev;
1408
  }
1409
  root->count = 0;
1410
  root->head = NULL;
1411
  root->tail = NULL;
1412
}
1413
 
1414
void
1415
snmp_varbind_tail_add(struct snmp_varbind_root *root, struct snmp_varbind *vb)
1416
{
1417
  if (root->count == 0)
1418
  {
1419
    /* add first varbind to list */
1420
    root->head = vb;
1421
    root->tail = vb;
1422
  }
1423
  else
1424
  {
1425
    /* add nth varbind to list tail */
1426
    root->tail->next = vb;
1427
    vb->prev = root->tail;
1428
    root->tail = vb;
1429
  }
1430
  root->count += 1;
1431
}
1432
 
1433
struct snmp_varbind*
1434
snmp_varbind_tail_remove(struct snmp_varbind_root *root)
1435
{
1436
  struct snmp_varbind* vb;
1437
 
1438
  if (root->count > 0)
1439
  {
1440
    /* remove tail varbind */
1441
    vb = root->tail;
1442
    root->tail = vb->prev;
1443
    vb->prev->next = NULL;
1444
    root->count -= 1;
1445
  }
1446
  else
1447
  {
1448
    /* nothing to remove */
1449
    vb = NULL;
1450
  }
1451
  return vb;
1452
}
1453
 
1454
#endif /* LWIP_SNMP */

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.