e1a720b34d1bf413bb9c3cf5738837a9f065fc42
[bcm963xx.git] / userapps / opensource / net-snmp / agent / mibgroup / mibII / system_mib.c
1 /*
2  *  System MIB group implementation - system.c
3  *
4  */
5
6 #include <net-snmp/net-snmp-config.h>
7
8 #if HAVE_STDLIB_H
9 #include <stdlib.h>
10 #endif
11 #ifdef HAVE_UNISTD_H
12 #include <unistd.h>
13 #endif
14 #if HAVE_STRING_H
15 #include <string.h>
16 #else
17 #include <strings.h>
18 #endif
19 #include <sys/types.h>
20 #if HAVE_WINSOCK_H
21 #include <winsock.h>
22 #endif
23
24 #ifdef HAVE_SYS_TIME_H
25 #include <sys/time.h>
26 #endif
27
28 #include <ctype.h>
29 #if HAVE_UTSNAME_H
30 #include <utsname.h>
31 #else
32 #if HAVE_SYS_UTSNAME_H
33 #include <sys/utsname.h>
34 #endif
35 #endif
36 #if HAVE_NETINET_IN_H
37 #include <netinet/in.h>
38 #endif
39
40 #if HAVE_DMALLOC_H
41 #include <dmalloc.h>
42 #endif
43
44 #ifdef BRCM_SNMP_INFO
45 #include "version.h"
46 #endif
47
48 #include <signal.h>   // need for SIGUSR1
49 #include <net-snmp/net-snmp-includes.h>
50 #include <net-snmp/agent/net-snmp-agent-includes.h>
51
52 #include "util_funcs.h"
53 #include "system_mib.h"
54 #include "struct.h"
55
56 #ifdef SNMP_SYSOR_MIB
57 #include "sysORTable.h"
58 #endif
59
60         /*********************
61          *
62          *  Kernel & interface information,
63          *   and internal forward declarations
64          *
65          *********************/
66 #define DEFAULT_SYSTEM_MIB 1,3,6,1,4,1,3646,100,7,OSTYPE
67
68 #define SYS_STRING_LEN  256
69 char            version_descr[SYS_STRING_LEN] = VERS_DESC;
70 char            sysContact[SYS_STRING_LEN] = SYS_CONTACT;
71 char            sysName[SYS_STRING_LEN] = SYS_NAME;
72 char            sysLocation[SYS_STRING_LEN] = SYS_LOC;
73 oid             sysObjectID[MAX_OID_LEN];
74 int             sysObjectIDLength;
75 //oid             version_sysoid[] = { SYSTEM_MIB };
76 oid             version_sysoid[] = { DEFAULT_SYSTEM_MIB };
77
78 char            oldversion_descr[SYS_STRING_LEN];
79 char            oldsysContact[SYS_STRING_LEN];
80 char            oldsysName[SYS_STRING_LEN];
81 char            oldsysLocation[SYS_STRING_LEN];
82
83 int             sysServices = 72;
84 int             sysServicesConfiged = 0;
85
86 extern oid      version_id[];
87 extern int      version_id_len;
88
89 static int      sysContactSet = 0, sysLocationSet = 0, sysNameSet = 0;
90
91 WriteMethod     writeSystem;
92 int             header_system(struct variable *, oid *, size_t *, int,
93                               size_t *, WriteMethod **);
94
95         /*********************
96          *
97          *  snmpd.conf config parsing
98          *
99          *********************/
100
101 void
102 system_parse_config_sysdescr(const char *token, char *cptr)
103 {
104     char            tmpbuf[1024];
105
106     if (strlen(cptr) >= sizeof(version_descr)) {
107         snprintf(tmpbuf,
108                  sizeof(tmpbuf),
109                  "sysdescr token too long (must be < %d):\n\t%s",
110                  sizeof(version_descr),
111                  cptr);
112         config_perror(tmpbuf);
113     } else if (strcmp(cptr, "\"\"") == 0) {
114         version_descr[0] = '\0';
115     } else {
116         strcpy(version_descr, cptr);
117     }
118 }
119
120 void
121 system_parse_config_sysloc(const char *token, char *cptr)
122 {
123     char            tmpbuf[1024];
124
125     if (strlen(cptr) >= sizeof(sysLocation)) {
126         snprintf(tmpbuf, 1024,
127                  "syslocation token too long (must be < %d):\n\t%s",
128                  sizeof(sysLocation), cptr);
129         config_perror(tmpbuf);
130     }
131
132     if (strcmp(token, "psyslocation") == 0) {
133         if (sysLocationSet < 0) {
134             /*
135              * This is bogus (and shouldn't happen anyway) -- the sysLocation
136              * is already configured read-only.  
137              */
138             snmp_log(LOG_WARNING,
139                      "ignoring attempted override of read-only sysLocation.0\n");
140             return;
141         } else {
142             sysLocationSet++;
143         }
144     } else {
145         if (sysLocationSet > 0) {
146             /*
147              * This is bogus (and shouldn't happen anyway) -- we already read a
148              * persistent value of sysLocation, which we should ignore in
149              * favour of this one.  
150              */
151             snmp_log(LOG_WARNING,
152                      "ignoring attempted override of read-only sysLocation.0\n");
153             /*
154              * Fall through and copy in this value.  
155              */
156         }
157         sysLocationSet = -1;
158     }
159
160     if (strcmp(cptr, "\"\"") == 0) {
161         sysLocation[0] = '\0';
162     } else if (strlen(cptr) < sizeof(sysLocation)) {
163         strcpy(sysLocation, cptr);
164     }
165 }
166
167 void
168 system_parse_config_syscon(const char *token, char *cptr)
169 {
170     char            tmpbuf[1024];
171
172     if (strlen(cptr) >= sizeof(sysContact)) {
173         snprintf(tmpbuf, 1024,
174                  "syscontact token too long (must be < %d):\n\t%s",
175                  sizeof(sysContact), cptr);
176         config_perror(tmpbuf);
177     }
178
179     if (strcmp(token, "psyscontact") == 0) {
180         if (sysContactSet < 0) {
181             /*
182              * This is bogus (and shouldn't happen anyway) -- the sysContact
183              * is already configured read-only.  
184              */
185             snmp_log(LOG_WARNING,
186                      "ignoring attempted override of read-only sysContact.0\n");
187             return;
188         } else {
189             sysContactSet++;
190         }
191     } else {
192         if (sysContactSet > 0) {
193             /*
194              * This is bogus (and shouldn't happen anyway) -- we already read a
195              * persistent value of sysContact, which we should ignore in favour
196              * of this one.  
197              */
198             snmp_log(LOG_WARNING,
199                      "ignoring attempted override of read-only sysContact.0\n");
200             /*
201              * Fall through and copy in this value.  
202              */
203         }
204         sysContactSet = -1;
205     }
206
207     if (strcmp(cptr, "\"\"") == 0) {
208         sysContact[0] = '\0';
209     } else if (strlen(cptr) < sizeof(sysContact)) {
210         strcpy(sysContact, cptr);
211     }
212 }
213
214 void
215 system_parse_config_sysname(const char *token, char *cptr)
216 {
217     char            tmpbuf[1024];
218
219     if (strlen(cptr) >= sizeof(sysName)) {
220         snprintf(tmpbuf, 1024,
221                  "sysname token too long (must be < %d):\n\t%s",
222                  sizeof(sysName), cptr);
223         config_perror(tmpbuf);
224     }
225
226     if (strcmp(token, "psysname") == 0) {
227         if (sysNameSet < 0) {
228             /*
229              * This is bogus (and shouldn't happen anyway) -- the sysName
230              * is already configured read-only.  
231              */
232             snmp_log(LOG_WARNING,
233                      "ignoring attempted override of read-only sysName.0\n");
234             return;
235         } else {
236             sysNameSet++;
237         }
238     } else {
239         if (sysNameSet > 0) {
240             /*
241              * This is bogus (and shouldn't happen anyway) -- we already read a
242              * persistent value of sysName, which we should ignore in favour
243              * of this one.  
244              */
245             snmp_log(LOG_WARNING,
246                      "ignoring attempted override of read-only sysName.0\n");
247             /*
248              * Fall through and copy in this value.  
249              */
250         }
251         sysNameSet = -1;
252     }
253
254     if (strcmp(cptr, "\"\"") == 0) {
255         sysName[0] = '\0';
256     } else if (strlen(cptr) < sizeof(sysName)) {
257         strcpy(sysName, cptr);
258     }
259 }
260
261 void
262 system_parse_config_sysServices(const char *token, char *cptr)
263 {
264     sysServices = atoi(cptr);
265     sysServicesConfiged = 1;
266 }
267
268 #ifdef BRCM_SNMP_SUPPORT
269 void system_parse_config_sysObjectID(const char *token, char *cptr)
270 {
271     char tmpbuf[1024];
272
273     sysObjectIDLength = MAX_OID_LEN;
274     if (!read_objid(cptr, sysObjectID, &sysObjectIDLength)) {
275         snprintf(tmpbuf,
276                  sizeof(tmpbuf),
277                  "sysobjectid token not a parsable OID:\n\t%s",
278                  cptr);
279         config_perror(tmpbuf);
280         memcpy(sysObjectID, version_sysoid, sizeof(version_sysoid));
281         sysObjectIDLength = OID_LENGTH(version_sysoid);
282     }
283 }
284 #endif /* BRCM_SNMP_SUPPORT */
285
286         /*********************
287          *
288          *  Initialisation & common implementation functions
289          *
290          *********************/
291
292 /*
293  * define the structure we're going to ask the agent to register our
294  * information at 
295  */
296 struct variable1 system_variables[] = {
297     {VERSION_DESCR, ASN_OCTET_STR, RONLY, var_system, 1, {1}},
298     {VERSIONID, ASN_OBJECT_ID, RONLY, var_system, 1, {2}},
299     {UPTIME, ASN_TIMETICKS, RONLY, var_system, 1, {3}},
300 #ifdef SNMP_SET
301     {SYSCONTACT, ASN_OCTET_STR, RWRITE, var_system, 1, {4}},
302     {SYSTEMNAME, ASN_OCTET_STR, RWRITE, var_system, 1, {5}},
303     {SYSLOCATION, ASN_OCTET_STR, RWRITE, var_system, 1, {6}},
304 #else
305     {SYSCONTACT, ASN_OCTET_STR, RONLY, var_system, 1, {4}},
306     {SYSTEMNAME, ASN_OCTET_STR, RONLY, var_system, 1, {5}},
307     {SYSLOCATION, ASN_OCTET_STR, RONLY, var_system, 1, {6}},
308 #endif /* SNMP_SET */
309 #ifdef SNMP_SYSOR_MIB
310     {SYSSERVICES, ASN_INTEGER, RONLY, var_system, 1, {7}},
311     {SYSORLASTCHANGE, ASN_TIMETICKS, RONLY, var_system, 1, {8}}
312 #else
313     {SYSSERVICES, ASN_INTEGER, RONLY, var_system, 1, {7}}
314 #endif
315 };
316 /*
317  * Define the OID pointer to the top of the mib tree that we're
318  * registering underneath
319  */
320 oid             system_variables_oid[] = { SNMP_OID_MIB2, 1 };
321 oid             system_module_oid[] = { SNMP_OID_SNMPMODULES, 1 };
322 int             system_module_oid_len =
323     sizeof(system_module_oid) / sizeof(oid);
324 int             system_module_count = 0;
325
326 static int
327 system_store(int a, int b, void *c, void *d)
328 {
329     int  pid = 0;
330     char line[SNMP_MAXBUF_SMALL];
331     FILE *fs = fopen("/var/run/httpd_pid", "r");
332
333     if (sysLocationSet > 0) {
334         snprintf(line, SNMP_MAXBUF_SMALL, "psyslocation %s", sysLocation);
335         snmpd_store_config(line);
336     }
337     if (sysContactSet > 0) {
338         snprintf(line, SNMP_MAXBUF_SMALL, "psyscontact %s", sysContact);
339         snmpd_store_config(line);
340     }
341     if (sysNameSet > 0) {
342         snprintf(line, SNMP_MAXBUF_SMALL, "psysname %s", sysName);
343         snmpd_store_config(line);
344     }
345
346     // send SIGUSR1 to httpd for storing SNMP set to PSI
347     if ( fs != NULL ) {
348        if ( fgets(line, SNMP_MAXBUF_SMALL - 1, fs) != NULL ) {
349           pid = atoi(line);
350           if ( pid > 0 )
351              kill(pid, SIGUSR1);
352        }
353        fclose(fs);
354     }
355
356     return 0;
357 }
358
359 void
360 init_system_mib(void)
361 {
362 #ifdef BRCM_SNMP_INFO
363   //sprintf(version_descr, "Broadcom Bcm963xx Software Version %s", ODM_VERSION);
364   sprintf(version_descr, "BCM96348-based ADSL Router");
365 #else
366 #ifdef HAVE_UNAME
367     struct utsname  utsName;
368
369     uname(&utsName);
370     snprintf(version_descr, sizeof(version_descr),
371             "%s %s %s %s %s", utsName.sysname,
372             utsName.nodename, utsName.release, utsName.version,
373             utsName.machine);
374     version_descr[ sizeof(version_descr)-1 ] = 0;
375 #else
376 #if HAVE_EXECV
377     struct extensible extmp;
378
379     /*
380      * set default values of system stuff 
381      */
382     sprintf(extmp.command, "%s -a", UNAMEPROG);
383     /*
384      * setup defaults 
385      */
386     extmp.type = EXECPROC;
387     extmp.next = NULL;
388     exec_command(&extmp);
389     strncpy(version_descr, extmp.output, sizeof(version_descr));
390     version_descr[sizeof(version_descr) - 1] = 0;
391     version_descr[strlen(version_descr) - 1] = 0;       /* chomp new line */
392 #else
393     strcpy(version_descr, "unknown");
394 #endif
395 #endif
396 #endif /* BRCM_SNMP_INFO */
397
398 #ifdef BRCM_SNMP_INFO
399     strncpy(sysName,"Broadcom",sizeof(sysName));
400 #else
401 #ifdef HAVE_GETHOSTNAME
402     gethostname(sysName, sizeof(sysName));
403 #else
404 #ifdef HAVE_UNAME
405     strncpy(sysName, utsName.nodename, sizeof(sysName));
406 #else
407 #if HAVE_EXECV
408     sprintf(extmp.command, "%s -n", UNAMEPROG);
409     /*
410      * setup defaults 
411      */
412     extmp.type = EXECPROC;
413     extmp.next = NULL;
414     exec_command(&extmp);
415     strncpy(sysName, extmp.output, sizeof(sysName));
416     sysName[strlen(sysName) - 1] = 0;   /* chomp new line */
417 #else
418     strcpy(sysName, "unknown");
419 #endif                          /* HAVE_EXECV */
420 #endif                          /* HAVE_UNAME */
421 #endif                          /* HAVE_GETHOSTNAME */
422
423 #endif /* BRCM_SNMP_INFO */
424
425     /* default sysObjectID */
426     memcpy(sysObjectID, version_sysoid, sizeof(version_sysoid));
427     sysObjectIDLength = OID_LENGTH(version_sysoid);
428
429     /*
430      * register ourselves with the agent to handle our mib tree 
431      */
432     REGISTER_MIB("mibII/system", system_variables, variable1,
433                  system_variables_oid);
434
435 #ifdef SNMP_SYSOR_MIB
436     if (++system_module_count == 3)
437         REGISTER_SYSOR_ENTRY(system_module_oid,
438                              "The MIB module for SNMPv2 entities");
439 #endif
440
441     sysContactSet = sysLocationSet = sysNameSet = 0;
442
443     /*
444      * register our config handlers 
445      */
446     snmpd_register_config_handler("sysdescr",
447                                   system_parse_config_sysdescr, NULL,
448                                   "description");
449     snmpd_register_config_handler("syslocation",
450                                   system_parse_config_sysloc, NULL,
451                                   "location");
452     snmpd_register_config_handler("syscontact", system_parse_config_syscon,
453                                   NULL, "contact-name");
454     snmpd_register_config_handler("sysname", system_parse_config_sysname,
455                                   NULL, "node-name");
456     snmpd_register_config_handler("psyslocation",
457                                   system_parse_config_sysloc, NULL, NULL);
458     snmpd_register_config_handler("psyscontact",
459                                   system_parse_config_syscon, NULL, NULL);
460     snmpd_register_config_handler("psysname", system_parse_config_sysname,
461                                   NULL, NULL);
462     snmpd_register_config_handler("sysservices",
463                                   system_parse_config_sysServices, NULL,
464                                   "NUMBER");
465 #ifdef BRCM_SNMP_SUPPORT
466     snmpd_register_config_handler("sysobjectid",
467                                   system_parse_config_sysObjectID, NULL,
468                                   "OID");
469 #endif
470     snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_STORE_DATA,
471                            system_store, NULL);
472
473 }
474
475
476         /*********************
477          *
478          *  System specific implementation functions
479          *
480          *********************/
481
482 #ifdef SNMP_SYSOR_MIB
483 #ifdef USING_MIBII_SYSORTABLE_MODULE
484 extern struct timeval sysOR_lastchange;
485 #endif
486 #endif /* SNMP_SYSOR_MIB */
487
488 u_char         *
489 var_system(struct variable *vp,
490            oid * name,
491            size_t * length,
492            int exact, size_t * var_len, WriteMethod ** write_method)
493 {
494     static u_long   ulret;
495
496     if (header_generic(vp, name, length, exact, var_len, write_method) ==
497         MATCH_FAILED)
498         return NULL;
499
500     switch (vp->magic) {
501     case VERSION_DESCR:
502         *var_len = strlen(version_descr);
503         return (u_char *) version_descr;
504     case VERSIONID:
505         *var_len = sysObjectIDLength * sizeof(sysObjectID[0]);
506         return (u_char *)sysObjectID;
507     case UPTIME:
508         ulret = netsnmp_get_agent_uptime();
509         return ((u_char *) & ulret);
510     case SYSCONTACT:
511         *var_len = strlen(sysContact);
512 #ifdef SNMP_SET
513         *write_method = writeSystem;
514 #else
515         *write_method = NULL;
516 #endif
517         return (u_char *) sysContact;
518     case SYSTEMNAME:
519         *var_len = strlen(sysName);
520 #ifdef SNMP_SET
521         *write_method = writeSystem;
522 #else
523         *write_method = NULL;
524 #endif
525         return (u_char *) sysName;
526     case SYSLOCATION:
527         *var_len = strlen(sysLocation);
528 #ifdef SNMP_SET
529         *write_method = writeSystem;
530 #else
531         *write_method = NULL;
532 #endif
533         return (u_char *) sysLocation;
534     case SYSSERVICES:
535 #if NO_DUMMY_VALUES
536         if (!sysServicesConfiged)
537             return NULL;
538 #endif
539         long_return = sysServices;
540         return (u_char *) & long_return;
541
542 #ifdef SNMP_SYSOR_MIB
543 #ifdef USING_MIBII_SYSORTABLE_MODULE
544     case SYSORLASTCHANGE:
545         ulret = netsnmp_timeval_uptime(&sysOR_lastchange);
546         return ((u_char *) & ulret);
547 #endif
548 #endif /* SNMP_SYSOR_MIB */
549     default:
550         DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_system\n",
551                     vp->magic));
552     }
553     return NULL;
554 }
555
556
557 #ifdef SNMP_SET
558 int
559 writeSystem(int action,
560             u_char * var_val,
561             u_char var_val_type,
562             size_t var_val_len,
563             u_char * statP, oid * name, size_t name_len)
564 {
565     u_char         *cp;
566     char           *buf = NULL, *oldbuf = NULL;
567     int             count, *setvar = NULL;
568
569     switch ((char) name[7]) {
570     case SYSCONTACT:
571         buf = sysContact;
572         oldbuf = oldsysContact;
573         setvar = &sysContactSet;
574         break;
575     case SYSTEMNAME:
576         buf = sysName;
577         oldbuf = oldsysName;
578         setvar = &sysNameSet;
579         break;
580     case SYSLOCATION:
581         buf = sysLocation;
582         oldbuf = oldsysLocation;
583         setvar = &sysLocationSet;
584         break;
585     default:
586         return SNMP_ERR_GENERR; /* ??? */
587     }
588
589     switch (action) {
590     case RESERVE1:             /* Check values for acceptability */
591         if (var_val_type != ASN_OCTET_STR) {
592             snmp_log(LOG_ERR, "not string\n");
593             return SNMP_ERR_WRONGTYPE;
594         }
595         if (var_val_len > sizeof(sysLocation) - 1) {
596             snmp_log(LOG_ERR, "bad length\n");
597             return SNMP_ERR_WRONGLENGTH;
598         }
599
600         for (cp = var_val, count = 0; count < (int) var_val_len;
601              count++, cp++) {
602             if (!isprint(*cp)) {
603                 snmp_log(LOG_ERR, "not print %x\n", *cp);
604                 return SNMP_ERR_WRONGVALUE;
605             }
606         }
607         if (setvar != NULL && *setvar < 0) {
608             /*
609              * The object is set in a read-only configuration file.  
610              */
611             return SNMP_ERR_NOTWRITABLE;
612         }
613         break;
614
615     case RESERVE2:             /* Allocate memory and similar resources */
616
617         /*
618          * Using static strings, so nothing needs to be done 
619          */
620         break;
621
622     case ACTION:               /* Perform the SET action (if reversible) */
623
624         /*
625          * Save the old value, in case of UNDO 
626          */
627         strcpy(oldbuf, buf);
628         memcpy(buf, var_val, var_val_len);
629         buf[var_val_len] = 0;
630         break;
631
632     case UNDO:                 /* Reverse the SET action and free resources */
633
634         strcpy(buf, oldbuf);
635         oldbuf[0] = 0;
636         break;
637
638     case COMMIT:
639         if (setvar != NULL) {
640             *setvar = 1;
641         }
642         snmp_save_persistent(netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_APPTYPE));
643         (void) snmp_call_callbacks(SNMP_CALLBACK_LIBRARY,
644                                    SNMP_CALLBACK_STORE_DATA, NULL);
645         snmp_clean_persistent(netsnmp_ds_get_string
646                               (NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_APPTYPE));
647
648     case FREE:                 /* Free any resources allocated */
649
650         /*
651          * No resources have been allocated, but "empty" the 'oldbuf' 
652          */
653         oldbuf[0] = 0;
654         break;
655     }
656     return SNMP_ERR_NOERROR;
657 }                               /* end of writeSystem */
658 #endif /* SNMP_SET */
659
660         /*********************
661          *
662          *  Internal implementation functions - None
663          *
664          *********************/