1 /*****************************************************************************
3 * ntpSnmpSubAgentObject.c
5 * This file provides the callback functions for net-snmp and registers the
6 * serviced MIB objects with the master agent.
8 * Each object has its own callback function that is called by the
9 * master agent process whenever someone queries the corresponding MIB
12 * At the moment this triggers a full send/receive procedure for each
13 * queried MIB object, one of the things that are still on my todo list:
14 * a caching mechanism that reduces the number of requests sent to the
17 ****************************************************************************/
23 /* general purpose buffer length definition */
24 #define NTPQ_BUFLEN 2048
26 char ntpvalue[NTPQ_BUFLEN];
29 /*****************************************************************************
31 * ntpsnmpd_parse_string
33 * This function will parse a given NULL terminated string and cut it
34 * into a fieldname and a value part (using the '=' as the delimiter.
35 * The fieldname will be converted to uppercase and all whitespace
36 * characters are removed from it.
37 * The value part is stripped, e.g. all whitespace characters are removed
38 * from the beginning and end of the string.
39 * If the value is started and ended with quotes ("), they will be removed
40 * and everything between the quotes is left untouched (including
43 * server host name = hello world!
44 * will result in a field string "SERVERHOSTNAME" and a value
46 * My first Parameter = " is this! "
47 * results in a field string "MYFIRSTPARAMETER" and a value " is this! "
48 ****************************************************************************
50 * string const char * The source string to parse.
51 * NOTE: must be NULL terminated!
52 * field char * The buffer for the field name.
53 * fieldsize size_t The size of the field buffer.
54 * value char * The buffer for the value.
55 * valuesize size_t The size of the value buffer.
58 * size_t length of value string
59 ****************************************************************************/
62 ntpsnmpd_parse_string(
76 /* we need at least one byte to work with to simplify */
77 if (fieldsize < 1 || valuesize < 1)
80 str_cnt = strlen(string);
82 /* Parsing the field name */
85 for (i = 0; loop && i <= str_cnt; i++) {
100 field[j++] = toupper(string[i]);
104 j = min(j, fieldsize - 1);
107 /* Now parsing the value */
110 for (val_cnt = 0; i < str_cnt; i++) {
111 if (string[i] > 0x0D && string[i] != ' ')
112 val_cnt = min(j + 1, valuesize - 1);
114 if (value[0] != '\0' ||
115 (string[i] > 0x0D && string[i] != ' ')) {
117 value[j++] = string[i];
120 value[val_cnt] = '\0';
122 if (value[0] == '"') {
124 strlcpy(value, &value[1], valuesize);
125 if (val_cnt > 0 && value[val_cnt - 1] == '"') {
127 value[val_cnt] = '\0';
135 /*****************************************************************************
137 * ntpsnmpd_cut_string
139 * This function will parse a given NULL terminated string and cut it
140 * into fields using the specified delimiter character.
141 * It will then copy the requested field into a destination buffer
143 * ntpsnmpd_cut_string(read:my:lips:fool, RESULT, ':', 2, sizeof(RESULT))
144 * will copy "lips" to RESULT.
145 ****************************************************************************
147 * src const char * The name of the source string variable
148 * NOTE: must be NULL terminated!
149 * dest char * The name of the string which takes the
150 * requested field content
151 * delim char The delimiter character
152 * fieldnumber int The number of the required field
153 * (start counting with 0)
154 * maxsize size_t The maximum size of dest
157 * size_t length of resulting dest string
158 ****************************************************************************/
177 str_cnt = strlen(string);
179 memset(dest, 0, maxsize);
181 /* Parsing the field name */
182 for (i = 0, l = 0; i < str_cnt && l <= fieldnumber; i++) {
183 if (string[i] == delim)
184 l++; /* next field */
185 else if (l == fieldnumber && j < maxsize)
186 dest[j++] = string[i];
188 j = min(j, maxsize - 1);
195 /*****************************************************************************
199 * This function retrieves the value for a given variable, currently
200 * this only supports sysvars. It starts a full mode 6 send/receive/parse
201 * iteration and needs to be optimized, e.g. by using a caching mechanism
203 ****************************************************************************
205 * variable char* The name of the required variable
206 * rbuffer char* The buffer where the value goes
207 * maxlength int Max. number of bytes for resultbuf
210 * u_int number of chars that have been copied to
212 ****************************************************************************/
216 const char * variable,
222 char sv_data[NTPQ_BUFLEN];
224 memset(sv_data, 0, sizeof(sv_data));
225 sv_len = ntpq_read_sysvars(sv_data, sizeof(sv_data));
230 return ntpq_getvar(sv_data, sv_len, variable, value,
235 /*****************************************************************************
237 * The get_xxx functions
239 * The following function calls are callback functions that will be
240 * used by the master agent process to retrieve a value for a requested
243 ****************************************************************************/
246 int get_ntpEntSoftwareName (netsnmp_mib_handler *handler,
247 netsnmp_handler_registration *reginfo,
248 netsnmp_agent_request_info *reqinfo,
249 netsnmp_request_info *requests)
251 char ntp_softwarename[NTPQ_BUFLEN];
253 memset (ntp_softwarename, 0, NTPQ_BUFLEN);
255 switch (reqinfo->mode) {
258 if ( read_ntp_value("product", ntpvalue, NTPQ_BUFLEN) )
260 snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,
265 else if ( read_ntp_value("version", ntpvalue, NTPQ_BUFLEN) )
267 ntpsnmpd_cut_string(ntpvalue, ntp_softwarename, ' ', 0, sizeof(ntp_softwarename)-1);
268 snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,
269 (u_char *)ntp_softwarename,
270 strlen(ntp_softwarename)
273 snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,
284 /* If we cannot get the information we need, we will return a generic error to the SNMP client */
285 return SNMP_ERR_GENERR;
288 return SNMP_ERR_NOERROR;
292 int get_ntpEntSoftwareVersion (netsnmp_mib_handler *handler,
293 netsnmp_handler_registration *reginfo,
294 netsnmp_agent_request_info *reqinfo,
295 netsnmp_request_info *requests)
298 switch (reqinfo->mode) {
302 if ( read_ntp_value("version", ntpvalue, NTPQ_BUFLEN) )
304 snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,
309 snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,
320 /* If we cannot get the information we need, we will return a generic error to the SNMP client */
321 return SNMP_ERR_GENERR;
324 return SNMP_ERR_NOERROR;
328 int get_ntpEntSoftwareVendor (netsnmp_mib_handler *handler,
329 netsnmp_handler_registration *reginfo,
330 netsnmp_agent_request_info *reqinfo,
331 netsnmp_request_info *requests)
334 switch (reqinfo->mode) {
338 if ( read_ntp_value("vendor", ntpvalue, NTPQ_BUFLEN) )
340 snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,
345 snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,
353 /* If we cannot get the information we need, we will return a generic error to the SNMP client */
354 return SNMP_ERR_GENERR;
357 return SNMP_ERR_NOERROR;
361 int get_ntpEntSystemType (netsnmp_mib_handler *handler,
362 netsnmp_handler_registration *reginfo,
363 netsnmp_agent_request_info *reqinfo,
364 netsnmp_request_info *requests)
367 switch (reqinfo->mode) {
371 if ( read_ntp_value("systemtype", ntpvalue, NTPQ_BUFLEN) )
373 snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,
379 if ( read_ntp_value("system", ntpvalue, NTPQ_BUFLEN) )
381 snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,
386 snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,
397 /* If we cannot get the information we need, we will return a generic error to the SNMP client */
398 return SNMP_ERR_GENERR;
401 return SNMP_ERR_NOERROR;
406 * ntpEntTimeResolution
407 * "The time resolution in integer format, where the resolution
408 * is represented as divisions of a second, e.g., a value of 1000
409 * translates to 1.0 ms."
411 * ntpEntTimeResolution is a challenge for ntpd, as the resolution is
412 * not known nor exposed by ntpd, only the measured precision (time to
415 * Logically the resolution must be at least the precision, so report
416 * it as our best approximation of resolution until/unless ntpd provides
420 get_ntpEntTimeResolution(
421 netsnmp_mib_handler * handler,
422 netsnmp_handler_registration * reginfo,
423 netsnmp_agent_request_info * reqinfo,
424 netsnmp_request_info * requests
430 switch (reqinfo->mode) {
433 if (!read_ntp_value("precision", ntpvalue,
435 return SNMP_ERR_GENERR;
436 if (1 != sscanf(ntpvalue, "%d", &precision))
437 return SNMP_ERR_GENERR;
439 return SNMP_ERR_GENERR;
440 precision = max(precision, -31);
441 resolution = 1 << -precision;
442 snmp_set_var_typed_value(
450 return SNMP_ERR_GENERR;
453 return SNMP_ERR_NOERROR;
458 * ntpEntTimePrecision
459 * "The entity's precision in integer format, shows the precision.
460 * A value of -5 would mean 2^-5 = 31.25 ms."
463 get_ntpEntTimePrecision(
464 netsnmp_mib_handler * handler,
465 netsnmp_handler_registration * reginfo,
466 netsnmp_agent_request_info * reqinfo,
467 netsnmp_request_info * requests
473 switch (reqinfo->mode) {
476 if (!read_ntp_value("precision", ntpvalue,
478 return SNMP_ERR_GENERR;
479 if (1 != sscanf(ntpvalue, "%d", &precision))
480 return SNMP_ERR_GENERR;
481 precision32 = (int32)precision;
482 snmp_set_var_typed_value(
485 (void *)&precision32,
486 sizeof(precision32));
490 return SNMP_ERR_GENERR;
493 return SNMP_ERR_NOERROR;
497 int get_ntpEntTimeDistance (netsnmp_mib_handler *handler,
498 netsnmp_handler_registration *reginfo,
499 netsnmp_agent_request_info *reqinfo,
500 netsnmp_request_info *requests)
502 switch (reqinfo->mode) {
506 if ( read_ntp_value("rootdelay", ntpvalue, NTPQ_BUFLEN) )
508 snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,
513 snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,
524 /* If we cannot get the information we need, we will return a generic error to the SNMP client */
525 return SNMP_ERR_GENERR;
528 return SNMP_ERR_NOERROR;
534 * Initialize sub agent
538 init_ntpSnmpSubagentObject(void)
540 /* Register all MIB objects with the agentx master */
541 NTP_OID_RO( ntpEntSoftwareName, 1, 1, 1, 0);
542 NTP_OID_RO( ntpEntSoftwareVersion, 1, 1, 2, 0);
543 NTP_OID_RO( ntpEntSoftwareVendor, 1, 1, 3, 0);
544 NTP_OID_RO( ntpEntSystemType, 1, 1, 4, 0);
545 NTP_OID_RO( ntpEntTimeResolution, 1, 1, 5, 0);
546 NTP_OID_RO( ntpEntTimePrecision, 1, 1, 6, 0);
547 NTP_OID_RO( ntpEntTimeDistance, 1, 1, 7, 0);