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