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

Subversion Repositories openrisc

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

Go to most recent revision | 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() @todo: use reply value?? */
593
    en = msg_ps->ext_mib_node;
594
    en->set_value_a(request_id, &msg_ps->ext_object_def, 0, NULL);
595
 
596
    /** @todo use set_value_pc() if toobig */
597
    msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE;
598
    msg_ps->vb_idx += 1;
599
  }
600
 
601
  /* test all values before setting */
602
  while ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&
603
         (msg_ps->vb_idx < msg_ps->invb.count))
604
  {
605
    struct mib_node *mn;
606
    struct snmp_name_ptr np;
607
 
608
    if (msg_ps->vb_idx == 0)
609
    {
610
      msg_ps->vb_ptr = msg_ps->invb.head;
611
    }
612
    else
613
    {
614
      msg_ps->vb_ptr = msg_ps->vb_ptr->next;
615
    }
616
    /** test object identifier for .iso.org.dod.internet prefix */
617
    if (snmp_iso_prefix_tst(msg_ps->vb_ptr->ident_len,  msg_ps->vb_ptr->ident))
618
    {
619
      mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4,
620
                             msg_ps->vb_ptr->ident + 4, &np);
621
      if (mn != NULL)
622
      {
623
        if (mn->node_type == MIB_NODE_EX)
624
        {
625
          /* external object */
626
          struct mib_external_node *en = (struct mib_external_node*)mn;
627
 
628
          msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF;
629
          /* save en && args in msg_ps!! */
630
          msg_ps->ext_mib_node = en;
631
          msg_ps->ext_name_ptr = np;
632
 
633
          en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident);
634
        }
635
        else
636
        {
637
          /* internal object */
638
          struct obj_def object_def;
639
 
640
          msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF;
641
          mn->get_object_def(np.ident_len, np.ident, &object_def);
642
          if (object_def.instance != MIB_OBJECT_NONE)
643
          {
644
            mn = mn;
645
          }
646
          else
647
          {
648
            /* search failed, object id points to unknown object (nosuchname) */
649
            mn = NULL;
650
          }
651
          if (mn != NULL)
652
          {
653
            msg_ps->state = SNMP_MSG_INTERNAL_SET_TEST;
654
 
655
            if (object_def.access == MIB_OBJECT_READ_WRITE)
656
            {
657
              if ((object_def.asn_type == msg_ps->vb_ptr->value_type) &&
658
                  (mn->set_test(&object_def,msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value) != 0))
659
              {
660
                msg_ps->state = SNMP_MSG_SEARCH_OBJ;
661
                msg_ps->vb_idx += 1;
662
              }
663
              else
664
              {
665
                /* bad value */
666
                snmp_error_response(msg_ps,SNMP_ES_BADVALUE);
667
              }
668
            }
669
            else
670
            {
671
              /* object not available for set */
672
              snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
673
            }
674
          }
675
        }
676
      }
677
    }
678
    else
679
    {
680
      mn = NULL;
681
    }
682
    if (mn == NULL)
683
    {
684
      /* mn == NULL, noSuchName */
685
      snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
686
    }
687
  }
688
 
689
  if ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&
690
      (msg_ps->vb_idx == msg_ps->invb.count))
691
  {
692
    msg_ps->vb_idx = 0;
693
    msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE;
694
  }
695
 
696
  /* set all values "atomically" (be as "atomic" as possible) */
697
  while ((msg_ps->state == SNMP_MSG_INTERNAL_SET_VALUE) &&
698
         (msg_ps->vb_idx < msg_ps->invb.count))
699
  {
700
    struct mib_node *mn;
701
    struct snmp_name_ptr np;
702
 
703
    if (msg_ps->vb_idx == 0)
704
    {
705
      msg_ps->vb_ptr = msg_ps->invb.head;
706
    }
707
    else
708
    {
709
      msg_ps->vb_ptr = msg_ps->vb_ptr->next;
710
    }
711
    /* skip iso prefix test, was done previously while settesting() */
712
    mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4,
713
                           msg_ps->vb_ptr->ident + 4, &np);
714
    /* check if object is still available
715
       (e.g. external hot-plug thingy present?) */
716
    if (mn != NULL)
717
    {
718
      if (mn->node_type == MIB_NODE_EX)
719
      {
720
        /* external object */
721
        struct mib_external_node *en = (struct mib_external_node*)mn;
722
 
723
        msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF_S;
724
        /* save en && args in msg_ps!! */
725
        msg_ps->ext_mib_node = en;
726
        msg_ps->ext_name_ptr = np;
727
 
728
        en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident);
729
      }
730
      else
731
      {
732
        /* internal object */
733
        struct obj_def object_def;
734
 
735
        msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF_S;
736
        mn->get_object_def(np.ident_len, np.ident, &object_def);
737
        msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE;
738
        mn->set_value(&object_def,msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value);
739
        msg_ps->vb_idx += 1;
740
      }
741
    }
742
  }
743
  if ((msg_ps->state == SNMP_MSG_INTERNAL_SET_VALUE) &&
744
      (msg_ps->vb_idx == msg_ps->invb.count))
745
  {
746
    /* simply echo the input if we can set it
747
       @todo do we need to return the actual value?
748
       e.g. if value is silently modified or behaves sticky? */
749
    msg_ps->outvb = msg_ps->invb;
750
    msg_ps->invb.head = NULL;
751
    msg_ps->invb.tail = NULL;
752
    msg_ps->invb.count = 0;
753
    snmp_ok_response(msg_ps);
754
  }
755
}
756
 
757
 
758
/**
759
 * Handle one internal or external event.
760
 * Called for one async event. (recv external/private answer)
761
 *
762
 * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1)
763
 */
764
void
765
snmp_msg_event(u8_t request_id)
766
{
767
  struct snmp_msg_pstat *msg_ps;
768
 
769
  if (request_id < SNMP_CONCURRENT_REQUESTS)
770
  {
771
    msg_ps = &msg_input_list[request_id];
772
    if (msg_ps->rt == SNMP_ASN1_PDU_GET_NEXT_REQ)
773
    {
774
      snmp_msg_getnext_event(request_id, msg_ps);
775
    }
776
    else if (msg_ps->rt == SNMP_ASN1_PDU_GET_REQ)
777
    {
778
      snmp_msg_get_event(request_id, msg_ps);
779
    }
780
    else if(msg_ps->rt == SNMP_ASN1_PDU_SET_REQ)
781
    {
782
      snmp_msg_set_event(request_id, msg_ps);
783
    }
784
  }
785
}
786
 
787
 
788
/* lwIP UDP receive callback function */
789
static void
790
snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port)
791
{
792
  struct udp_hdr *udphdr;
793
 
794
  /* suppress unused argument warning */
795
  LWIP_UNUSED_ARG(arg);
796
  /* peek in the UDP header (goto IP payload) */
797
  if(pbuf_header(p, UDP_HLEN)){
798
    LWIP_ASSERT("Can't move to UDP header", 0);
799
    pbuf_free(p);
800
    return;
801
  }
802
  udphdr = p->payload;
803
 
804
  /* check if datagram is really directed at us (including broadcast requests) */
805
  if ((pcb == snmp1_pcb) && (ntohs(udphdr->dest) == SNMP_IN_PORT))
806
  {
807
    struct snmp_msg_pstat *msg_ps;
808
    u8_t req_idx;
809
 
810
    /* traverse input message process list, look for SNMP_MSG_EMPTY */
811
    msg_ps = &msg_input_list[0];
812
    req_idx = 0;
813
    while ((req_idx<SNMP_CONCURRENT_REQUESTS) && (msg_ps->state != SNMP_MSG_EMPTY))
814
    {
815
      req_idx++;
816
      msg_ps++;
817
    }
818
    if (req_idx != SNMP_CONCURRENT_REQUESTS)
819
    {
820
      err_t err_ret;
821
      u16_t payload_len;
822
      u16_t payload_ofs;
823
      u16_t varbind_ofs = 0;
824
 
825
      /* accepting request */
826
      snmp_inc_snmpinpkts();
827
      /* record used 'protocol control block' */
828
      msg_ps->pcb = pcb;
829
      /* source address (network order) */
830
      msg_ps->sip = *addr;
831
      /* source port (host order (lwIP oddity)) */
832
      msg_ps->sp = port;
833
      /* read UDP payload length from UDP header */
834
      payload_len = ntohs(udphdr->len) - UDP_HLEN;
835
 
836
      /* adjust to UDP payload */
837
      payload_ofs = UDP_HLEN;
838
 
839
      /* check total length, version, community, pdu type */
840
      err_ret = snmp_pdu_header_check(p, payload_ofs, payload_len, &varbind_ofs, msg_ps);
841
      if (((msg_ps->rt == SNMP_ASN1_PDU_GET_REQ) ||
842
           (msg_ps->rt == SNMP_ASN1_PDU_GET_NEXT_REQ) ||
843
           (msg_ps->rt == SNMP_ASN1_PDU_SET_REQ)) &&
844
          ((msg_ps->error_status == SNMP_ES_NOERROR) &&
845
           (msg_ps->error_index == 0)) )
846
      {
847
        /* Only accept requests and requests without error (be robust) */
848
        err_ret = err_ret;
849
      }
850
      else
851
      {
852
        /* Reject response and trap headers or error requests as input! */
853
        err_ret = ERR_ARG;
854
      }
855
      if (err_ret == ERR_OK)
856
      {
857
        LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv ok, community %s\n", msg_ps->community));
858
 
859
        /* Builds a list of variable bindings. Copy the varbinds from the pbuf
860
          chain to glue them when these are divided over two or more pbuf's. */
861
        err_ret = snmp_pdu_dec_varbindlist(p, varbind_ofs, &varbind_ofs, msg_ps);
862
        if ((err_ret == ERR_OK) && (msg_ps->invb.count > 0))
863
        {
864
          /* we've decoded the incoming message, release input msg now */
865
          pbuf_free(p);
866
 
867
          msg_ps->error_status = SNMP_ES_NOERROR;
868
          msg_ps->error_index = 0;
869
          /* find object for each variable binding */
870
          msg_ps->state = SNMP_MSG_SEARCH_OBJ;
871
          /* first variable binding from list to inspect */
872
          msg_ps->vb_idx = 0;
873
 
874
          LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv varbind cnt=%"U16_F"\n",(u16_t)msg_ps->invb.count));
875
 
876
          /* handle input event and as much objects as possible in one go */
877
          snmp_msg_event(req_idx);
878
        }
879
        else
880
        {
881
          /* varbind-list decode failed, or varbind list empty.
882
             drop request silently, do not return error!
883
             (errors are only returned for a specific varbind failure) */
884
          pbuf_free(p);
885
          LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_dec_varbindlist() failed\n"));
886
        }
887
      }
888
      else
889
      {
890
        /* header check failed
891
           drop request silently, do not return error! */
892
        pbuf_free(p);
893
        LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_header_check() failed\n"));
894
      }
895
    }
896
    else
897
    {
898
      /* exceeding number of concurrent requests */
899
      pbuf_free(p);
900
    }
901
  }
902
  else
903
  {
904
    /* datagram not for us */
905
    pbuf_free(p);
906
  }
907
}
908
 
909
/**
910
 * Checks and decodes incoming SNMP message header, logs header errors.
911
 *
912
 * @param p points to pbuf chain of SNMP message (UDP payload)
913
 * @param ofs points to first octet of SNMP message
914
 * @param pdu_len the length of the UDP payload
915
 * @param ofs_ret returns the ofset of the variable bindings
916
 * @param m_stat points to the current message request state return
917
 * @return
918
 * - ERR_OK SNMP header is sane and accepted
919
 * - ERR_ARG SNMP header is either malformed or rejected
920
 */
921
static err_t
922
snmp_pdu_header_check(struct pbuf *p, u16_t ofs, u16_t pdu_len, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat)
923
{
924
  err_t derr;
925
  u16_t len, ofs_base;
926
  u8_t  len_octets;
927
  u8_t  type;
928
  s32_t version;
929
 
930
  ofs_base = ofs;
931
  snmp_asn1_dec_type(p, ofs, &type);
932
  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
933
  if ((derr != ERR_OK) ||
934
      (pdu_len != (1 + len_octets + len)) ||
935
      (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)))
936
  {
937
    snmp_inc_snmpinasnparseerrs();
938
    return ERR_ARG;
939
  }
940
  ofs += (1 + len_octets);
941
  snmp_asn1_dec_type(p, ofs, &type);
942
  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
943
  if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))
944
  {
945
    /* can't decode or no integer (version) */
946
    snmp_inc_snmpinasnparseerrs();
947
    return ERR_ARG;
948
  }
949
  derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &version);
950
  if (derr != ERR_OK)
951
  {
952
    /* can't decode */
953
    snmp_inc_snmpinasnparseerrs();
954
    return ERR_ARG;
955
  }
956
  if (version != 0)
957
  {
958
    /* not version 1 */
959
    snmp_inc_snmpinbadversions();
960
    return ERR_ARG;
961
  }
962
  ofs += (1 + len_octets + len);
963
  snmp_asn1_dec_type(p, ofs, &type);
964
  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
965
  if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR)))
966
  {
967
    /* can't decode or no octet string (community) */
968
    snmp_inc_snmpinasnparseerrs();
969
    return ERR_ARG;
970
  }
971
  derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, SNMP_COMMUNITY_STR_LEN, m_stat->community);
972
  if (derr != ERR_OK)
973
  {
974
    snmp_inc_snmpinasnparseerrs();
975
    return ERR_ARG;
976
  }
977
  /* add zero terminator */
978
  len = ((len < (SNMP_COMMUNITY_STR_LEN))?(len):(SNMP_COMMUNITY_STR_LEN));
979
  m_stat->community[len] = 0;
980
  m_stat->com_strlen = len;
981
  if (strncmp(snmp_publiccommunity, (const char*)m_stat->community, SNMP_COMMUNITY_STR_LEN) != 0)
982
  {
983
    /** @todo: move this if we need to check more names */
984
    snmp_inc_snmpinbadcommunitynames();
985
    snmp_authfail_trap();
986
    return ERR_ARG;
987
  }
988
  ofs += (1 + len_octets + len);
989
  snmp_asn1_dec_type(p, ofs, &type);
990
  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
991
  if (derr != ERR_OK)
992
  {
993
    snmp_inc_snmpinasnparseerrs();
994
    return ERR_ARG;
995
  }
996
  switch(type)
997
  {
998
    case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_REQ):
999
      /* GetRequest PDU */
1000
      snmp_inc_snmpingetrequests();
1001
      derr = ERR_OK;
1002
      break;
1003
    case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_NEXT_REQ):
1004
      /* GetNextRequest PDU */
1005
      snmp_inc_snmpingetnexts();
1006
      derr = ERR_OK;
1007
      break;
1008
    case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_RESP):
1009
      /* GetResponse PDU */
1010
      snmp_inc_snmpingetresponses();
1011
      derr = ERR_ARG;
1012
      break;
1013
    case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_SET_REQ):
1014
      /* SetRequest PDU */
1015
      snmp_inc_snmpinsetrequests();
1016
      derr = ERR_OK;
1017
      break;
1018
    case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_TRAP):
1019
      /* Trap PDU */
1020
      snmp_inc_snmpintraps();
1021
      derr = ERR_ARG;
1022
      break;
1023
    default:
1024
      snmp_inc_snmpinasnparseerrs();
1025
      derr = ERR_ARG;
1026
      break;
1027
  }
1028
  if (derr != ERR_OK)
1029
  {
1030
    /* unsupported input PDU for this agent (no parse error) */
1031
    return ERR_ARG;
1032
  }
1033
  m_stat->rt = type & 0x1F;
1034
  ofs += (1 + len_octets);
1035
  if (len != (pdu_len - (ofs - ofs_base)))
1036
  {
1037
    /* decoded PDU length does not equal actual payload length */
1038
    snmp_inc_snmpinasnparseerrs();
1039
    return ERR_ARG;
1040
  }
1041
  snmp_asn1_dec_type(p, ofs, &type);
1042
  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
1043
  if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))
1044
  {
1045
    /* can't decode or no integer (request ID) */
1046
    snmp_inc_snmpinasnparseerrs();
1047
    return ERR_ARG;
1048
  }
1049
  derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->rid);
1050
  if (derr != ERR_OK)
1051
  {
1052
    /* can't decode */
1053
    snmp_inc_snmpinasnparseerrs();
1054
    return ERR_ARG;
1055
  }
1056
  ofs += (1 + len_octets + len);
1057
  snmp_asn1_dec_type(p, ofs, &type);
1058
  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
1059
  if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))
1060
  {
1061
    /* can't decode or no integer (error-status) */
1062
    snmp_inc_snmpinasnparseerrs();
1063
    return ERR_ARG;
1064
  }
1065
  /* must be noError (0) for incoming requests.
1066
     log errors for mib-2 completeness and for debug purposes */
1067
  derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->error_status);
1068
  if (derr != ERR_OK)
1069
  {
1070
    /* can't decode */
1071
    snmp_inc_snmpinasnparseerrs();
1072
    return ERR_ARG;
1073
  }
1074
  switch (m_stat->error_status)
1075
  {
1076
    case SNMP_ES_TOOBIG:
1077
      snmp_inc_snmpintoobigs();
1078
      break;
1079
    case SNMP_ES_NOSUCHNAME:
1080
      snmp_inc_snmpinnosuchnames();
1081
      break;
1082
    case SNMP_ES_BADVALUE:
1083
      snmp_inc_snmpinbadvalues();
1084
      break;
1085
    case SNMP_ES_READONLY:
1086
      snmp_inc_snmpinreadonlys();
1087
      break;
1088
    case SNMP_ES_GENERROR:
1089
      snmp_inc_snmpingenerrs();
1090
      break;
1091
  }
1092
  ofs += (1 + len_octets + len);
1093
  snmp_asn1_dec_type(p, ofs, &type);
1094
  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
1095
  if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))
1096
  {
1097
    /* can't decode or no integer (error-index) */
1098
    snmp_inc_snmpinasnparseerrs();
1099
    return ERR_ARG;
1100
  }
1101
  /* must be 0 for incoming requests.
1102
     decode anyway to catch bad integers (and dirty tricks) */
1103
  derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->error_index);
1104
  if (derr != ERR_OK)
1105
  {
1106
    /* can't decode */
1107
    snmp_inc_snmpinasnparseerrs();
1108
    return ERR_ARG;
1109
  }
1110
  ofs += (1 + len_octets + len);
1111
  *ofs_ret = ofs;
1112
  return ERR_OK;
1113
}
1114
 
1115
static err_t
1116
snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat)
1117
{
1118
  err_t derr;
1119
  u16_t len, vb_len;
1120
  u8_t  len_octets;
1121
  u8_t type;
1122
 
1123
  /* variable binding list */
1124
  snmp_asn1_dec_type(p, ofs, &type);
1125
  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &vb_len);
1126
  if ((derr != ERR_OK) ||
1127
      (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)))
1128
  {
1129
    snmp_inc_snmpinasnparseerrs();
1130
    return ERR_ARG;
1131
  }
1132
  ofs += (1 + len_octets);
1133
 
1134
  /* start with empty list */
1135
  m_stat->invb.count = 0;
1136
  m_stat->invb.head = NULL;
1137
  m_stat->invb.tail = NULL;
1138
 
1139
  while (vb_len > 0)
1140
  {
1141
    struct snmp_obj_id oid, oid_value;
1142
    struct snmp_varbind *vb;
1143
 
1144
    snmp_asn1_dec_type(p, ofs, &type);
1145
    derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
1146
    if ((derr != ERR_OK) ||
1147
        (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)) ||
1148
        (len <= 0) || (len > vb_len))
1149
    {
1150
      snmp_inc_snmpinasnparseerrs();
1151
      /* free varbinds (if available) */
1152
      snmp_varbind_list_free(&m_stat->invb);
1153
      return ERR_ARG;
1154
    }
1155
    ofs += (1 + len_octets);
1156
    vb_len -= (1 + len_octets);
1157
 
1158
    snmp_asn1_dec_type(p, ofs, &type);
1159
    derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
1160
    if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID)))
1161
    {
1162
      /* can't decode object name length */
1163
      snmp_inc_snmpinasnparseerrs();
1164
      /* free varbinds (if available) */
1165
      snmp_varbind_list_free(&m_stat->invb);
1166
      return ERR_ARG;
1167
    }
1168
    derr = snmp_asn1_dec_oid(p, ofs + 1 + len_octets, len, &oid);
1169
    if (derr != ERR_OK)
1170
    {
1171
      /* can't decode object name */
1172
      snmp_inc_snmpinasnparseerrs();
1173
      /* free varbinds (if available) */
1174
      snmp_varbind_list_free(&m_stat->invb);
1175
      return ERR_ARG;
1176
    }
1177
    ofs += (1 + len_octets + len);
1178
    vb_len -= (1 + len_octets + len);
1179
 
1180
    snmp_asn1_dec_type(p, ofs, &type);
1181
    derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
1182
    if (derr != ERR_OK)
1183
    {
1184
      /* can't decode object value length */
1185
      snmp_inc_snmpinasnparseerrs();
1186
      /* free varbinds (if available) */
1187
      snmp_varbind_list_free(&m_stat->invb);
1188
      return ERR_ARG;
1189
    }
1190
 
1191
    switch (type)
1192
    {
1193
      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG):
1194
        vb = snmp_varbind_alloc(&oid, type, sizeof(s32_t));
1195
        if (vb != NULL)
1196
        {
1197
          s32_t *vptr = vb->value;
1198
 
1199
          derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, vptr);
1200
          snmp_varbind_tail_add(&m_stat->invb, vb);
1201
        }
1202
        else
1203
        {
1204
          derr = ERR_ARG;
1205
        }
1206
        break;
1207
      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER):
1208
      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE):
1209
      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS):
1210
        vb = snmp_varbind_alloc(&oid, type, sizeof(u32_t));
1211
        if (vb != NULL)
1212
        {
1213
          u32_t *vptr = vb->value;
1214
 
1215
          derr = snmp_asn1_dec_u32t(p, ofs + 1 + len_octets, len, vptr);
1216
          snmp_varbind_tail_add(&m_stat->invb, vb);
1217
        }
1218
        else
1219
        {
1220
          derr = ERR_ARG;
1221
        }
1222
        break;
1223
      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR):
1224
      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_OPAQUE):
1225
        vb = snmp_varbind_alloc(&oid, type, len);
1226
        if (vb != NULL)
1227
        {
1228
          derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, vb->value_len, vb->value);
1229
          snmp_varbind_tail_add(&m_stat->invb, vb);
1230
        }
1231
        else
1232
        {
1233
          derr = ERR_ARG;
1234
        }
1235
        break;
1236
      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_NUL):
1237
        vb = snmp_varbind_alloc(&oid, type, 0);
1238
        if (vb != NULL)
1239
        {
1240
          snmp_varbind_tail_add(&m_stat->invb, vb);
1241
          derr = ERR_OK;
1242
        }
1243
        else
1244
        {
1245
          derr = ERR_ARG;
1246
        }
1247
        break;
1248
      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID):
1249
        derr = snmp_asn1_dec_oid(p, ofs + 1 + len_octets, len, &oid_value);
1250
        if (derr == ERR_OK)
1251
        {
1252
          vb = snmp_varbind_alloc(&oid, type, oid_value.len * sizeof(s32_t));
1253
          if (vb != NULL)
1254
          {
1255
            u8_t i = oid_value.len;
1256
            s32_t *vptr = vb->value;
1257
 
1258
            while(i > 0)
1259
            {
1260
              i--;
1261
              vptr[i] = oid_value.id[i];
1262
            }
1263
            snmp_varbind_tail_add(&m_stat->invb, vb);
1264
            derr = ERR_OK;
1265
          }
1266
          else
1267
          {
1268
            derr = ERR_ARG;
1269
          }
1270
        }
1271
        break;
1272
      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR):
1273
        if (len == 4)
1274
        {
1275
          /* must be exactly 4 octets! */
1276
          vb = snmp_varbind_alloc(&oid, type, 4);
1277
          if (vb != NULL)
1278
          {
1279
            derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, vb->value_len, vb->value);
1280
            snmp_varbind_tail_add(&m_stat->invb, vb);
1281
          }
1282
          else
1283
          {
1284
            derr = ERR_ARG;
1285
          }
1286
        }
1287
        else
1288
        {
1289
          derr = ERR_ARG;
1290
        }
1291
        break;
1292
      default:
1293
        derr = ERR_ARG;
1294
        break;
1295
    }
1296
    if (derr != ERR_OK)
1297
    {
1298
      snmp_inc_snmpinasnparseerrs();
1299
      /* free varbinds (if available) */
1300
      snmp_varbind_list_free(&m_stat->invb);
1301
      return ERR_ARG;
1302
    }
1303
    ofs += (1 + len_octets + len);
1304
    vb_len -= (1 + len_octets + len);
1305
  }
1306
 
1307
  if (m_stat->rt == SNMP_ASN1_PDU_SET_REQ)
1308
  {
1309
    snmp_add_snmpintotalsetvars(m_stat->invb.count);
1310
  }
1311
  else
1312
  {
1313
    snmp_add_snmpintotalreqvars(m_stat->invb.count);
1314
  }
1315
 
1316
  *ofs_ret = ofs;
1317
  return ERR_OK;
1318
}
1319
 
1320
struct snmp_varbind*
1321
snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u8_t len)
1322
{
1323
  struct snmp_varbind *vb;
1324
 
1325
  vb = (struct snmp_varbind *)mem_malloc(sizeof(struct snmp_varbind));
1326
  LWIP_ASSERT("vb != NULL",vb != NULL);
1327
  if (vb != NULL)
1328
  {
1329
    u8_t i;
1330
 
1331
    vb->next = NULL;
1332
    vb->prev = NULL;
1333
    i = oid->len;
1334
    vb->ident_len = i;
1335
    if (i > 0)
1336
    {
1337
      /* allocate array of s32_t for our object identifier */
1338
      vb->ident = (s32_t*)mem_malloc(sizeof(s32_t) * i);
1339
      LWIP_ASSERT("vb->ident != NULL",vb->ident != NULL);
1340
      if (vb->ident == NULL)
1341
      {
1342
        mem_free(vb);
1343
        return NULL;
1344
      }
1345
      while(i > 0)
1346
      {
1347
        i--;
1348
        vb->ident[i] = oid->id[i];
1349
      }
1350
    }
1351
    else
1352
    {
1353
      /* i == 0, pass zero length object identifier */
1354
      vb->ident = NULL;
1355
    }
1356
    vb->value_type = type;
1357
    vb->value_len = len;
1358
    if (len > 0)
1359
    {
1360
      /* allocate raw bytes for our object value */
1361
      vb->value = mem_malloc(len);
1362
      LWIP_ASSERT("vb->value != NULL",vb->value != NULL);
1363
      if (vb->value == NULL)
1364
      {
1365
        if (vb->ident != NULL)
1366
        {
1367
          mem_free(vb->ident);
1368
        }
1369
        mem_free(vb);
1370
        return NULL;
1371
      }
1372
    }
1373
    else
1374
    {
1375
      /* ASN1_NUL type, or zero length ASN1_OC_STR */
1376
      vb->value = NULL;
1377
    }
1378
  }
1379
  return vb;
1380
}
1381
 
1382
void
1383
snmp_varbind_free(struct snmp_varbind *vb)
1384
{
1385
  if (vb->value != NULL )
1386
  {
1387
    mem_free(vb->value);
1388
  }
1389
  if (vb->ident != NULL )
1390
  {
1391
    mem_free(vb->ident);
1392
  }
1393
  mem_free(vb);
1394
}
1395
 
1396
void
1397
snmp_varbind_list_free(struct snmp_varbind_root *root)
1398
{
1399
  struct snmp_varbind *vb, *prev;
1400
 
1401
  vb = root->tail;
1402
  while ( vb != NULL )
1403
  {
1404
    prev = vb->prev;
1405
    snmp_varbind_free(vb);
1406
    vb = prev;
1407
  }
1408
  root->count = 0;
1409
  root->head = NULL;
1410
  root->tail = NULL;
1411
}
1412
 
1413
void
1414
snmp_varbind_tail_add(struct snmp_varbind_root *root, struct snmp_varbind *vb)
1415
{
1416
  if (root->count == 0)
1417
  {
1418
    /* add first varbind to list */
1419
    root->head = vb;
1420
    root->tail = vb;
1421
  }
1422
  else
1423
  {
1424
    /* add nth varbind to list tail */
1425
    root->tail->next = vb;
1426
    vb->prev = root->tail;
1427
    root->tail = vb;
1428
  }
1429
  root->count += 1;
1430
}
1431
 
1432
struct snmp_varbind*
1433
snmp_varbind_tail_remove(struct snmp_varbind_root *root)
1434
{
1435
  struct snmp_varbind* vb;
1436
 
1437
  if (root->count > 0)
1438
  {
1439
    /* remove tail varbind */
1440
    vb = root->tail;
1441
    root->tail = vb->prev;
1442
    vb->prev->next = NULL;
1443
    root->count -= 1;
1444
  }
1445
  else
1446
  {
1447
    /* nothing to remove */
1448
    vb = NULL;
1449
  }
1450
  return vb;
1451
}
1452
 
1453
#endif /* LWIP_SNMP */

powered by: WebSVN 2.1.0

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