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

Subversion Repositories openrisc

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

powered by: WebSVN 2.1.0

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