1 /* This is a small demo of the NetX SNMP Agent on the high-performance NetX TCP/IP stack.
2 This demo relies on ThreadX and NetX to show simple SNMP GET/GETNEXT/SET requests on
3 the SNMP MIB-2 objects. */
4
5 #include "tx_api.h"
6 #include "nx_api.h"
7 #include "nxd_snmp.h"
8 #include "demo_snmp_helper.h"
9
10 #define DEMO_STACK_SIZE 4096
11 #define AGENT_PRIMARY_ADDRESS IP_ADDRESS(1,2,3,4)
12
13 /* Define the ThreadX and NetX object control blocks... */
14
15 TX_THREAD thread_0;
16 NX_PACKET_POOL pool_0;
17 NX_IP ip_0;
18 NX_SNMP_AGENT my_agent;
19
20
21 #ifdef FEATURE_NX_IPV6
22
23 /* Indicate if using IPv6 to communicate with SNMP servers. Note that
24 IPv6 must be enabled in the NetX Duo library first. Further, IPv6
25 and ICMPv6 services are enabled before starting the SNMP agent. */
26
27 /* #define USE_IPV6 */
28
29 #endif /* FEATURE_NX_IPV6 */
30
31 /* To use SNMPv3 features such as authentication and encryption, define NX_SNMP_DISABLE_V3. */
32
33 /* Define authentication and privacy keys. */
34
35 #ifdef AUTHENTICATION_REQUIRED
36 NX_SNMP_SECURITY_KEY my_authentication_key;
37 #endif
38
39 #ifdef PRIVACY_REQUIRED
40 NX_SNMP_SECURITY_KEY my_privacy_key;
41 #endif
42
43 /* Define an error counter variable. */
44 UINT error_counter = 0;
45
46 /* This binds a secondary interfaces to the primary IP network interface
47 if SNMP is required for required for that interface. */
48 /* #define MULTI_HOMED_DEVICE */
49
50 /* Define function prototypes. A generic ram driver is used in this demo. However to properly
51 run an SNMP agent demo, a real driver should be substituted. */
52
53 VOID thread_agent_entry(ULONG thread_input);
54 VOID _nx_ram_network_driver(NX_IP_DRIVER *driver_req_ptr);
55 UINT mib2_get_processing(NX_SNMP_AGENT *agent_ptr, UCHAR *object_requested, NX_SNMP_OBJECT_DATA *object_data);
56 UINT mib2_getnext_processing(NX_SNMP_AGENT *agent_ptr, UCHAR *object_requested, NX_SNMP_OBJECT_DATA *object_data);
57 UINT mib2_set_processing(NX_SNMP_AGENT *agent_ptr, UCHAR *object_requested, NX_SNMP_OBJECT_DATA *object_data);
58 UINT mib2_username_processing(NX_SNMP_AGENT *agent_ptr, UCHAR *username);
59 VOID mib2_variable_update(NX_IP *ip_ptr, NX_SNMP_AGENT *agent_ptr);
60
61
62 UCHAR context_engine_id[] = {0x80, 0x00, 0x0d, 0xfe, 0x03, 0x00, 0x11, 0x23, 0x23, 0x44, 0x55};
63 UINT context_engine_size = 11;
64 UCHAR context_name[] = {0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c};
65 UINT context_name_size = 7;
66
67 /* Define main entry point. */
68
main()69 int main()
70 {
71
72 /* Enter the ThreadX kernel. */
73 tx_kernel_enter();
74 }
75
76
77 /* Define what the initial system looks like. */
tx_application_define(void * first_unused_memory)78 void tx_application_define(void *first_unused_memory)
79 {
80
81 UCHAR *pointer;
82 UINT status;
83
84
85 /* Setup the working pointer. */
86 pointer = (UCHAR *) first_unused_memory;
87
88 status = tx_thread_create(&thread_0, "agent thread", thread_agent_entry, 0,
89 pointer, DEMO_STACK_SIZE,
90 4, 4, TX_NO_TIME_SLICE, TX_AUTO_START);
91 if (status != NX_SUCCESS)
92 {
93 return;
94 }
95
96 pointer = pointer + DEMO_STACK_SIZE;
97
98
99 /* Initialize the NetX system. */
100 nx_system_initialize();
101
102 /* Create packet pool. */
103 status = nx_packet_pool_create(&pool_0, "NetX Packet Pool 0", 2048, pointer, 20000);
104
105 if (status != NX_SUCCESS)
106 {
107 return;
108 }
109
110 pointer = pointer + 20000;
111
112 /* Create an IP instance. */
113 status = nx_ip_create(&ip_0, "SNMP Agent IP Instance", AGENT_PRIMARY_ADDRESS,
114 0xFFFFFF00UL, &pool_0, _nx_ram_network_driver,
115 pointer, 4096, 1);
116
117 if (status != NX_SUCCESS)
118 {
119 return;
120 }
121
122 pointer = pointer + 4096;
123
124 #ifndef NX_DISABLE_IPV4
125 /* Enable ARP and supply ARP cache memory for IP Instance 0. */
126 nx_arp_enable(&ip_0, (void *) pointer, 1024);
127 pointer = pointer + 1024;
128
129 /* Enable ICMP for ping. */
130 nx_icmp_enable(&ip_0);
131 #endif /* NX_DISABLE_IPV4 */
132
133 /* Enable UPD processing for IP instance. */
134 nx_udp_enable(&ip_0);
135
136 /* Create an SNMP agent instance. */
137 status = nx_snmp_agent_create(&my_agent, "SNMP Agent", &ip_0, pointer, 4096, &pool_0,
138 mib2_username_processing, mib2_get_processing, mib2_getnext_processing,
139 mib2_set_processing);
140
141 if (status != NX_SUCCESS)
142 {
143 return;
144 }
145
146 pointer = pointer + 4096;
147
148 #ifdef NX_SNMP_DISABLE_V3
149 status = nx_snmp_agent_context_engine_set(&my_agent, context_engine_id, context_engine_size);
150
151 if (status != NX_SUCCESS)
152 {
153 error_counter++;
154 }
155 #endif /* NX_SNMP_DISABLE_V3 */
156
157 return;
158 }
159
thread_agent_entry(ULONG thread_input)160 VOID thread_agent_entry(ULONG thread_input)
161 {
162
163 UINT status;
164 #ifdef USE_IPV6
165 UINT iface_index, address_index;
166 NXD_ADDRESS agent_ipv6_address;
167 #endif
168
169 NX_PARAMETER_NOT_USED(thread_input);
170
171 /* Allow NetX time to get initialized. */
172 tx_thread_sleep(NX_IP_PERIODIC_RATE);
173
174 #ifdef USE_IPV6
175
176 /* If using IPv6, enable IPv6 and ICMPv6 services and get IPv6 addresses
177 registered with NetX Dou. */
178
179 /* Enable IPv6 on the IP instance. */
180 status = nxd_ipv6_enable(&ip_0);
181
182 /* Check for enable errors. */
183 if (status)
184 {
185
186 error_counter++;
187 return;
188 }
189 /* Enable ICMPv6 on the IP instance. */
190 status = nxd_icmp_enable(&ip_0);
191
192 /* Check for enable errors. */
193 if (status)
194 {
195
196 error_counter++;
197 return;
198 }
199
200 agent_ipv6_address.nxd_ip_address.v6[3] = 0x101;
201 agent_ipv6_address.nxd_ip_address.v6[2] = 0x0;
202 agent_ipv6_address.nxd_ip_address.v6[1] = 0x0000f101;
203 agent_ipv6_address.nxd_ip_address.v6[0] = 0x20010db8;
204 agent_ipv6_address.nxd_ip_version = NX_IP_VERSION_V6;
205
206 /* Set the primary interface for our DNS IPv6 addresses. */
207 iface_index = 0;
208
209 /* This assumes we are using the primary network interface (index 0). */
210 status = nxd_ipv6_address_set(&ip_0, iface_index, NX_NULL, 10, &address_index);
211
212 /* Check for link local address set error. */
213 if (status)
214 {
215
216 error_counter++;
217 return;
218 }
219
220 /* Set the host global IP address. We are assuming a 64
221 bit prefix here but this can be any value (< 128). */
222 status = nxd_ipv6_address_set(&ip_0, iface_index, &agent_ipv6_address, 64, &address_index);
223
224 /* Check for global address set error. */
225 if (status)
226 {
227
228 error_counter++;
229 return;
230 }
231
232 /* Wait while NetX validates the link local and global address. */
233 tx_thread_sleep(5 * NX_IP_PERIODIC_RATE);
234 #endif
235
236 #ifdef AUTHENTICATION_REQUIRED
237
238 /* Create an authentication key. */
239 status = nx_snmp_agent_md5_key_create(&my_agent, (UCHAR *)"authpassword", &my_authentication_key);
240 if (status)
241 error_counter++;
242
243 /* Use the authentication key. */
244 status = nx_snmp_agent_authenticate_key_use(&my_agent, &my_authentication_key);
245 if (status)
246 error_counter++;
247
248 #endif
249
250 #ifdef PRIVACY_REQUIRED
251
252 /* Create a privacy key. */
253 status = nx_snmp_agent_md5_key_create(&my_agent, (UCHAR *)"privpassword", &my_privacy_key);
254 if (status)
255 error_counter++;
256
257 /* Use the privacy key. */
258 status = nx_snmp_agent_privacy_key_use(&my_agent, &my_privacy_key);
259 if (status)
260 error_counter++;
261 #endif
262
263 /* Start the SNMP instance. */
264 status = nx_snmp_agent_start(&my_agent);
265 if (status)
266 error_counter++;
267
268 }
269
270 /* Define the application's GET processing routine. */
271
mib2_get_processing(NX_SNMP_AGENT * agent_ptr,UCHAR * object_requested,NX_SNMP_OBJECT_DATA * object_data)272 UINT mib2_get_processing(NX_SNMP_AGENT *agent_ptr, UCHAR *object_requested, NX_SNMP_OBJECT_DATA *object_data)
273 {
274
275 UINT i;
276 UINT status;
277
278 NX_PARAMETER_NOT_USED(agent_ptr);
279
280
281 /* Loop through the sample MIB to see if we have information for the supplied variable. */
282 i = 0;
283 status = NX_SNMP_ERROR;
284 while (mib2_mib[i].object_name)
285 {
286
287 /* See if we have found the matching entry. */
288 status = nx_snmp_object_compare(object_requested, mib2_mib[i].object_name);
289
290 /* Was it found? */
291 if (status == NX_SUCCESS)
292 {
293
294 /* Yes it was found. */
295 break;
296 }
297
298 /* Move to the next index. */
299 i++;
300 }
301
302 /* Determine if a not found condition is present. */
303 if (status != NX_SUCCESS)
304 {
305
306
307 /* The object was not found - return an error. */
308 return(NX_SNMP_ERROR_NOSUCHNAME);
309 }
310
311 /* Determine if the entry has a get function. */
312 if (mib2_mib[i].object_get_callback)
313 {
314
315 /* Yes, call the get function. */
316 status = (mib2_mib[i].object_get_callback)(mib2_mib[i].object_value_ptr, object_data);
317 }
318 else
319 {
320
321
322 /* No get function, return no access. */
323 status = NX_SNMP_ERROR_NOACCESS;
324 }
325
326
327
328 /* Return the status. */
329 return(status);
330 }
331
332
333 /* Define the application's GETNEXT processing routine. */
334
mib2_getnext_processing(NX_SNMP_AGENT * agent_ptr,UCHAR * object_requested,NX_SNMP_OBJECT_DATA * object_data)335 UINT mib2_getnext_processing(NX_SNMP_AGENT *agent_ptr, UCHAR *object_requested, NX_SNMP_OBJECT_DATA *object_data)
336 {
337
338 UINT i;
339 UINT status;
340
341 NX_PARAMETER_NOT_USED(agent_ptr);
342
343
344
345 /* Loop through the sample MIB to see if we have information for the supplied variable. */
346 i = 0;
347 status = NX_SNMP_ERROR;
348 while (mib2_mib[i].object_name)
349 {
350
351 /* See if we have found the next entry. */
352 status = nx_snmp_object_compare(object_requested, mib2_mib[i].object_name);
353
354 /* Is the next entry the mib greater? */
355 if (status == NX_SNMP_NEXT_ENTRY)
356 {
357
358 /* Yes it was found. */
359 break;
360 }
361
362 /* Move to the next index. */
363 i++;
364 }
365
366 /* Determine if a not found condition is present. */
367 if (status != NX_SNMP_NEXT_ENTRY)
368 {
369
370
371 /* The object was not found - return an error. */
372 return(NX_SNMP_ERROR_NOSUCHNAME);
373 }
374
375
376 /* Copy the new name into the object. */
377 nx_snmp_object_copy(mib2_mib[i].object_name, object_requested);
378
379
380 /* Determine if the entry has a get function. */
381 if (mib2_mib[i].object_get_callback)
382 {
383
384 /* Yes, call the get function. */
385 status = (mib2_mib[i].object_get_callback)(mib2_mib[i].object_value_ptr, object_data);
386
387 /* Determine if the object data indicates an end-of-mib condition. */
388 if (object_data -> nx_snmp_object_data_type == NX_SNMP_END_OF_MIB_VIEW)
389 {
390
391 /* Copy the name supplied in the mib table. */
392 nx_snmp_object_copy(mib2_mib[i].object_value_ptr, object_requested);
393 }
394 }
395 else
396 {
397
398
399 /* No get function, return no access. */
400 status = NX_SNMP_ERROR_NOACCESS;
401 }
402
403
404
405 /* Return the status. */
406 return(status);
407 }
408
409
410 /* Define the application's SET processing routine. */
411
mib2_set_processing(NX_SNMP_AGENT * agent_ptr,UCHAR * object_requested,NX_SNMP_OBJECT_DATA * object_data)412 UINT mib2_set_processing(NX_SNMP_AGENT *agent_ptr, UCHAR *object_requested, NX_SNMP_OBJECT_DATA *object_data)
413 {
414
415 UINT i;
416 UINT status;
417
418 NX_PARAMETER_NOT_USED(agent_ptr);
419
420
421 /* Loop through the sample MIB to see if we have information for the supplied variable. */
422 i = 0;
423 status = NX_SNMP_ERROR;
424 while (mib2_mib[i].object_name)
425 {
426
427 /* See if we have found the matching entry. */
428 status = nx_snmp_object_compare(object_requested, mib2_mib[i].object_name);
429
430 /* Was it found? */
431 if (status == NX_SUCCESS)
432 {
433
434 /* Yes it was found. */
435 break;
436 }
437
438 /* Move to the next index. */
439 i++;
440 }
441
442 /* Determine if a not found condition is present. */
443 if (status != NX_SUCCESS)
444 {
445
446
447 /* The object was not found - return an error. */
448 return(NX_SNMP_ERROR_NOSUCHNAME);
449 }
450
451
452 /* Determine if the entry has a set function. */
453 if (mib2_mib[i].object_set_callback)
454 {
455
456 /* If the object data type is string. */
457 if (object_data -> nx_snmp_object_data_type == NX_SNMP_ANS1_OCTET_STRING)
458 {
459
460 /* Check the string length of the object value. */
461 if (object_data -> nx_snmp_object_octet_string_size > mib2_mib[i].length)
462 {
463 return(NX_SNMP_ERROR_TOOBIG);
464 }
465 }
466
467 /* Yes, call the set function. */
468 status = (mib2_mib[i].object_set_callback)(mib2_mib[i].object_value_ptr, object_data);
469 }
470 else
471 {
472
473
474 /* No get function, return no access. */
475 status = NX_SNMP_ERROR_NOACCESS;
476 }
477
478
479 /* Return the status. */
480 return(status);
481 }
482
483
484 /* Define the application's authentication routine. */
485
mib2_username_processing(NX_SNMP_AGENT * agent_ptr,UCHAR * username)486 UINT mib2_username_processing(NX_SNMP_AGENT *agent_ptr, UCHAR *username)
487 {
488
489 NX_PARAMETER_NOT_USED(agent_ptr);
490 NX_PARAMETER_NOT_USED(username);
491
492 /* Update MIB-2 objects. In this example, it is only the SNMP objects. */
493 mib2_variable_update(&ip_0, &my_agent);
494
495 /* No authentication is done, just return success! */
496 return(NX_SUCCESS);
497 }
498
499
500 /* Define the application's update routine. */
501
mib2_variable_update(NX_IP * ip_ptr,NX_SNMP_AGENT * agent_ptr)502 VOID mib2_variable_update(NX_IP *ip_ptr, NX_SNMP_AGENT *agent_ptr)
503 {
504
505 NX_PARAMETER_NOT_USED(ip_ptr);
506 NX_PARAMETER_NOT_USED(agent_ptr);
507
508 /* This section is for updating the snmp parameters defined in the MIB table definition files. */
509 }
510
511