This patch intruduces the supported ds described in PTPBASE_MIB. The
rest of the unsupported ds are not covered. These ds needs to be added
in ptp4l to begin with.

Signed-off-by: Anders Selhammer <anders.selham...@est.tech>
---
 makefile        |   6 +-
 ptpbase_mib.c   | 898 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 snmp4lptp_mib.h |   3 +
 3 files changed, 904 insertions(+), 3 deletions(-)
 create mode 100644 ptpbase_mib.c

diff --git a/makefile b/makefile
index 6995e70..3f21001 100644
--- a/makefile
+++ b/makefile
@@ -40,7 +40,7 @@ version := $(shell $(srcdir)/version.sh $(srcdir))
 VPATH  = $(srcdir)
 
 ifneq (,$(findstring -DHAVE_NET_SNMP,$(snmpflg)))
-PRG    += snmp4lptp
+PRG    += snmp4lptp ptpbase_mib.o
 OBJECTS        += snmp4lptp.o
 snmplib        := $(shell net-snmp-config --netsnmp-agent-libs)
 endif
@@ -68,8 +68,8 @@ hwstamp_ctl: hwstamp_ctl.o version.o
 
 phc_ctl: phc_ctl.o phc.o sk.o util.o clockadj.o sysoff.o print.o version.o
 
-snmp4lptp: config.o hash.o msg.o pmc_common.o print.o raw.o sk.o \
- snmp4lptp.o tlv.o transport.o udp.o udp6.o uds.o util.o
+snmp4lptp: config.o hash.o msg.o pmc_common.o print.o ptpbase_mib.o raw.o \
+ sk.o snmp4lptp.o tlv.o transport.o udp.o udp6.o uds.o util.o
        $(CC) $^ $(LDFLAGS) $(LOADLIBES) $(LDLIBS) $(snmplib) -o $@
 
 snmp4lptp.o: snmp4lptp.c
diff --git a/ptpbase_mib.c b/ptpbase_mib.c
new file mode 100644
index 0000000..cd39274
--- /dev/null
+++ b/ptpbase_mib.c
@@ -0,0 +1,898 @@
+/**
+ * @file ptpbase_mib.c
+ * @brief Implements PTPv2 Management Information Base (RFC 8173)
+ * @note Copyright (C) 2018 Anders Selhammer <anders.selham...@est.tech>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+
+#include "clock.h"
+#include "ds.h"
+#include "pdt.h"
+#include "print.h"
+#include "snmp4lptp_mib.h"
+#include "tlv.h"
+#include "tmv.h"
+
+/*
+ * ptp base oid values
+ */
+#define SNMP_OID_PTPBASE_MIB                  1, 3, 6, 1, 2, 1, 241
+#define SNMP_OID_PTPBASE_OBJ_CLOCKINFO        SNMP_OID_PTPBASE_MIB, 1, 2
+#define SNMP_OID_PTPBASE_CLOCK_CDS            SNMP_OID_PTPBASE_OBJ_CLOCKINFO, 1
+#define SNMP_OID_PTPBASE_CLOCK_PDS            SNMP_OID_PTPBASE_OBJ_CLOCKINFO, 2
+#define SNMP_OID_PTPBASE_CLOCK_DDS            SNMP_OID_PTPBASE_OBJ_CLOCKINFO, 3
+#define SNMP_OID_PTPBASE_CLOCK_TDS            SNMP_OID_PTPBASE_OBJ_CLOCKINFO, 5
+#define SNMP_OID_PTPBASE_PORT_DS              SNMP_OID_PTPBASE_OBJ_CLOCKINFO, 8
+
+/*
+ * column number definitions for tables
+ */
+
+#define COLUMN_CURRENTDS_STEPSREMOVED                           4
+#define COLUMN_CURRENTDS_OFFSETFROMMASTER                       5
+#define COLUMN_CURRENTDS_MEANPATHDELAY                          6
+#define COLUMN_CDS_MIN COLUMN_CURRENTDS_STEPSREMOVED
+#define COLUMN_CDS_MAX COLUMN_CURRENTDS_MEANPATHDELAY
+
+#define COLUMN_PARENTDS_PARENTPORTIDENTITY                      4
+#define COLUMN_PARENTDS_PARENTSTATS                             5
+#define COLUMN_PARENTDS_OFFSET                                  6
+#define COLUMN_PARENTDS_CLOCKPHCHRATE                           7
+#define COLUMN_PARENTDS_GMCLOCKIDENTITY                         8
+#define COLUMN_PARENTDS_GMCLOCKPRIORITY1                        9
+#define COLUMN_PARENTDS_GMCLOCKPRIORITY2                        10
+#define COLUMN_PARENTDS_GMCLOCKQUALITYCLASS                     11
+#define COLUMN_PARENTDS_GMCLOCKQUALITYACCURACY                  12
+#define COLUMN_PARENTDS_GMCLOCKQUALITYOFFSET                    13
+#define COLUMN_PDS_MIN COLUMN_PARENTDS_PARENTPORTIDENTITY
+#define COLUMN_PDS_MAX COLUMN_PARENTDS_GMCLOCKQUALITYOFFSET
+
+#define COLUMN_DEFAULTDS_TWOSTEPFLAG                            4
+#define COLUMN_DEFAULTDS_CLOCKIDENTITY                          5
+#define COLUMN_DEFAULTDS_PRIORITY1                              6
+#define COLUMN_DEFAULTDS_PRIORITY2                              7
+#define COLUMN_DEFAULTDS_SLAVEONLY                              8
+#define COLUMN_DEFAULTDS_QUALITYCLASS                           9
+#define COLUMN_DEFAULTDS_QUALITYACCURACY                        10
+#define COLUMN_DEFAULTDS_QUALITYOFFSET                          11
+#define COLUMN_DDS_MIN COLUMN_DEFAULTDS_TWOSTEPFLAG
+#define COLUMN_DDS_MAX COLUMN_DEFAULTDS_QUALITYOFFSET
+
+#define COLUMN_TIMEPROPERTIESDS_CURRENTUTCOFFSETVALID           4
+#define COLUMN_TIMEPROPERTIESDS_CURRENTUTCOFFSET                5
+#define COLUMN_TIMEPROPERTIESDS_LEAP59                          6
+#define COLUMN_TIMEPROPERTIESDS_LEAP61                          7
+#define COLUMN_TIMEPROPERTIESDS_TIMETRACEABLE                   8
+#define COLUMN_TIMEPROPERTIESDS_FREQTRACEABLE                   9
+#define COLUMN_TIMEPROPERTIESDS_PTPTIMESCALE                    10
+#define COLUMN_TIMEPROPERTIESDS_SOURCE                          11
+#define COLUMN_TDS_MIN COLUMN_TIMEPROPERTIESDS_CURRENTUTCOFFSETVALID
+#define COLUMN_TDS_MAX COLUMN_TIMEPROPERTIESDS_SOURCE
+
+#define COLUMN_PORTDS_NAME                                      5
+#define COLUMN_PORTDS_PORTIDENTITY                              6
+#define COLUMN_PORTDS_LOGANNOUNCEMENTINTERVAL                   7
+#define COLUMN_PORTDS_ANNOUNCERCTTIMEOUT                        8
+#define COLUMN_PORTDS_LOGSYNCINTERVAL                           9
+#define COLUMN_PORTDS_MINDELAYREQINTERVAL                       10
+#define COLUMN_PORTDS_PEERDELAYREQINTERVAL                      11
+#define COLUMN_PORTDS_DELAYMECH                                 12
+#define COLUMN_PORTDS_PEERMEANPATHDELAY                         13
+#define COLUMN_PORTDS_GRANTDURATION                             14
+#define COLUMN_PORTDS_PTPVERSION                                15
+#define COLUMN_PORTDS_MIN COLUMN_PORTDS_NAME
+#define COLUMN_PORTDS_MAX COLUMN_PORTDS_PTPVERSION
+
+/*
+ * other internal defines and types
+ */
+#define CMD_MAX_LEN 255
+
+enum ptp_clock_type {
+        ordinaryClock = 1,
+        boundaryClock,
+        transparentClock
+};
+
+struct ds_idx {
+       u_long             domain;
+       long               clock_type;
+       u_long             instance;
+       int                valid;
+};
+
+struct ds_data {
+       struct ds_idx      idxs;
+       int                id;
+       unsigned int       tmo;
+       struct ptp_message *cur;
+       TAILQ_HEAD(msg_head, ptp_message) msg;
+};
+
+struct mydata {
+       int                id;
+       int                multiple;
+       struct ds_data     *data;
+};
+
+
+/*
+ * function declarations
+ */
+
+static void reset_ds_data(struct ds_data *data)
+{
+       struct ptp_message *tmp;
+       data->id = 0;
+       if (data->tmo) {
+               snmp_alarm_unregister(data->tmo);
+               data->tmo = 0;
+       }
+       while ((tmp = TAILQ_FIRST(&data->msg)) != NULL) {
+               TAILQ_REMOVE(&data->msg, tmp, list);
+               msg_put(tmp);
+       }
+}
+
+static void ds_cb(unsigned int clientreg, void *clientarg)
+{
+       struct ds_data *data = (struct ds_data *)clientarg;
+
+       if (data->tmo != clientreg) {
+               pr_err("Received unregistered timer");
+               return;
+       }
+       data->idxs.valid = 0;
+       reset_ds_data(data);
+}
+
+static int get_command(char *cmd, int id)
+{
+       switch (id) {
+       case TLV_DEFAULT_DATA_SET:
+               snprintf(cmd, CMD_MAX_LEN, "GET DEFAULT_DATA_SET");
+               break;
+       case TLV_CURRENT_DATA_SET:
+               snprintf(cmd, CMD_MAX_LEN, "GET CURRENT_DATA_SET");
+               break;
+       case TLV_PARENT_DATA_SET:
+               snprintf(cmd, CMD_MAX_LEN, "GET PARENT_DATA_SET");
+               break;
+       case TLV_TIME_PROPERTIES_DATA_SET:
+               snprintf(cmd, CMD_MAX_LEN, "GET TIME_PROPERTIES_DATA_SET");
+               break;
+       case TLV_PORT_DATA_SET:
+               snprintf(cmd, CMD_MAX_LEN, "GET PORT_DATA_SET");
+               break;
+       default:
+               return SNMP_ERR_GENERR;
+       }
+
+       return SNMP_ERR_NOERROR;
+}
+
+static int get_mgmt_data(struct ptp_message *msg,
+                        struct management_tlv **mgt)
+{
+       struct TLV *tlv;
+       int action;
+
+       if (msg_type(msg) != MANAGEMENT) {
+               pr_err("msg type not MANAGEMENT");
+               return SNMP_ERR_GENERR;
+       }
+
+       action = management_action(msg);
+       if (action < GET || action > ACKNOWLEDGE) {
+               pr_err("incorrect action");
+               return SNMP_ERR_GENERR;
+       }
+
+       if (msg_tlv_count(msg) != 1) {
+               pr_err("incorrect tlv count");
+               return SNMP_ERR_GENERR;
+       }
+
+       tlv = (struct TLV *) msg->management.suffix;
+       if (tlv->type == TLV_MANAGEMENT) {
+               ;
+       } else if (tlv->type == TLV_MANAGEMENT_ERROR_STATUS) {
+               pr_err("MANAGEMENT_ERROR_STATUS");
+               return SNMP_ERR_GENERR;
+       } else {
+               pr_err("unknown-tlv");
+               return SNMP_ERR_GENERR;
+       }
+
+       *mgt = (struct management_tlv *) msg->management.suffix;
+       if ((*mgt)->length == 2 && (*mgt)->id != TLV_NULL_MANAGEMENT) {
+               pr_err("empty-tlv");
+               return SNMP_ERR_GENERR;
+       }
+
+       return SNMP_ERR_NOERROR;
+}
+
+static unsigned int get_port_ds_portnum(struct ptp_message *msg)
+{
+       struct management_tlv *mgt;
+       struct portDS *ds;
+
+       mgt = (struct management_tlv *) msg->management.suffix;
+       ds = (struct portDS *) mgt->data;
+
+       return ds->portIdentity.portNumber;
+}
+
+static int add_ds_table_indexes(netsnmp_table_registration_info *tinfo, int id)
+{
+       switch (id) {
+       case TLV_CURRENT_DATA_SET:
+       case TLV_PARENT_DATA_SET:
+       case TLV_DEFAULT_DATA_SET:
+       case TLV_TIME_PROPERTIES_DATA_SET:
+               netsnmp_table_helper_add_indexes(tinfo,
+                                                ASN_UNSIGNED,
+                                                ASN_INTEGER,
+                                                ASN_UNSIGNED,
+                                                0);
+               break;
+       case TLV_PORT_DATA_SET:
+               netsnmp_table_helper_add_indexes(tinfo,
+                                                ASN_UNSIGNED,
+                                                ASN_INTEGER,
+                                                ASN_UNSIGNED,
+                                                ASN_UNSIGNED,
+                                                0);
+               break;
+       default:
+               return SNMP_ERR_GENERR;
+       }
+       return SNMP_ERR_NOERROR;
+}
+
+static void set_ds_table_indexes(netsnmp_variable_list *idx, struct ds_data 
*data)
+{
+       switch (data->id) {
+       case TLV_CURRENT_DATA_SET:
+       case TLV_PARENT_DATA_SET:
+       case TLV_DEFAULT_DATA_SET:
+       case TLV_TIME_PROPERTIES_DATA_SET:
+               snmp_set_var_typed_integer(idx, ASN_UNSIGNED,
+                                          data->idxs.domain);
+               idx = idx->next_variable;
+               snmp_set_var_typed_integer(idx, ASN_INTEGER,
+                                          data->idxs.clock_type);
+               idx = idx->next_variable;
+               snmp_set_var_typed_integer(idx, ASN_UNSIGNED,
+                                          data->idxs.instance);
+               break;
+       case TLV_PORT_DATA_SET:
+               snmp_set_var_typed_integer(idx, ASN_UNSIGNED,
+                                          data->idxs.domain);
+               idx = idx->next_variable;
+               snmp_set_var_typed_integer(idx, ASN_INTEGER,
+                                          data->idxs.clock_type);
+               idx = idx->next_variable;
+               snmp_set_var_typed_integer(idx, ASN_UNSIGNED,
+                                          data->idxs.instance);
+               idx = idx->next_variable;
+               snmp_set_var_typed_integer(idx, ASN_UNSIGNED,
+                                          get_port_ds_portnum(data->cur));
+               break;
+       default:
+               pr_err("unimplemented id");
+       }
+}
+
+static int update_ds_idxs(struct ds_idx *idxs)
+{
+       struct management_tlv *mgt = NULL;
+       struct tlv_extra *extra = NULL;
+       int err = SNMP_ERR_NOERROR;
+       struct ptp_message *msg;
+
+       msg = snmp4lptp_run_pmc("GET CLOCK_DESCRIPTION");
+       if (!msg) {
+               return SNMP_ERR_GENERR;
+       }
+
+       if (get_mgmt_data(msg, &mgt)) {
+               err = SNMP_ERR_GENERR;
+               goto out;
+       }
+       if (mgt->id != TLV_CLOCK_DESCRIPTION) {
+               err = SNMP_ERR_GENERR;
+               goto out;
+       }
+
+       extra = TAILQ_FIRST(&msg->tlv_list);
+       switch (align16(extra->cd.clockType)) {
+       case CLOCK_TYPE_ORDINARY:
+               idxs->clock_type = ordinaryClock;
+               break;
+       case CLOCK_TYPE_BOUNDARY:
+               idxs->clock_type = boundaryClock;
+               break;
+       case CLOCK_TYPE_P2P:
+       case CLOCK_TYPE_E2E:
+               idxs->clock_type = transparentClock;
+               break;
+       default:
+               err = SNMP_ERR_GENERR;
+               goto out;
+       }
+
+       idxs->domain = snmp4lptp_get_domain();
+       idxs->instance = 0;
+       idxs->valid = 1;
+
+out:
+       msg_put(msg);
+       while ((msg = snmp4lptp_run_pmc(NULL))) {
+               msg_put(msg);
+       }
+
+       return err;
+}
+
+static int store_ds_msg(struct ds_data *data, struct ptp_message *msg)
+{
+       struct management_tlv *mgt = NULL;
+
+       if (get_mgmt_data(msg, &mgt)) {
+               return SNMP_ERR_GENERR;
+       }
+
+       data->id = mgt->id;
+       TAILQ_INSERT_TAIL(&data->msg, msg, list);
+
+       return SNMP_ERR_NOERROR;
+}
+
+static int update_ds_data(char *cmd, struct ds_data *data, int multiple_rsp)
+{
+       struct ptp_message *msg;
+
+       msg = snmp4lptp_run_pmc(cmd);
+       if (!msg) {
+               return SNMP_ERR_GENERR;
+       }
+       do {
+               if (store_ds_msg(data, msg)) {
+                       msg_put(msg);
+                       return SNMP_ERR_GENERR;
+               }
+       } while (multiple_rsp && (msg = snmp4lptp_run_pmc(NULL)));
+
+       return SNMP_ERR_NOERROR;
+}
+
+static netsnmp_variable_list *get_next_data_point(void **my_loop_context,
+                                                 void **my_data_context,
+                                                 netsnmp_variable_list
+                                                 *put_index_data,
+                                                 netsnmp_iterator_info
+                                                 *mydata)
+{
+       struct ds_data *data;
+
+       data = (struct ds_data *)*my_loop_context;
+       if (!data->cur) {
+               return NULL;
+       }
+
+       set_ds_table_indexes(put_index_data, data);
+
+       *my_data_context = (void *) data->cur;
+       data->cur = TAILQ_NEXT(data->cur, list);
+
+       return put_index_data;
+}
+
+static netsnmp_variable_list *get_first_data_point(void **my_loop_context,
+                                                  void **my_data_context,
+                                                  netsnmp_variable_list
+                                                  *put_index_data,
+                                                  netsnmp_iterator_info
+                                                  *mydata)
+{
+       struct mydata *my_data;
+       char cmd[CMD_MAX_LEN];
+
+       my_data = (struct mydata*)mydata->myvoid;
+       if (!my_data->data->idxs.valid) {
+               if (update_ds_idxs(&my_data->data->idxs)) {
+                       return NULL;
+               }
+       }
+       if (my_data->data->id != my_data->id) {
+               reset_ds_data(my_data->data);
+               my_data->data->tmo =
+                       snmp_alarm_register(1, 0, ds_cb, my_data->data);
+               if (get_command(cmd, my_data->id)) {
+                       return NULL;
+               }
+               if (update_ds_data(cmd, my_data->data, my_data->multiple)) {
+                       return NULL;
+               }
+       }
+
+       my_data->data->cur = TAILQ_FIRST(&my_data->data->msg);
+       *my_loop_context = my_data->data;
+
+       return get_next_data_point(my_loop_context, my_data_context,
+                                  put_index_data, mydata);
+}
+
+static int set_cds_return_values(unsigned int column,
+                                struct management_tlv *mgt,
+                                netsnmp_request_info *request)
+{
+       struct currentDS *ds = (struct currentDS *) mgt->data;
+
+       switch (column) {
+       case COLUMN_CURRENTDS_STEPSREMOVED:
+               snmp_set_var_typed_integer(request->requestvb,
+                                          ASN_UNSIGNED,
+                                          ds->stepsRemoved);
+               break;
+       case COLUMN_CURRENTDS_OFFSETFROMMASTER:
+               snmp_set_var_typed_value(request->requestvb,
+                                        ASN_OCTET_STR,
+                                        &ds->offsetFromMaster, 
sizeof(ds->offsetFromMaster));
+               break;
+       case COLUMN_CURRENTDS_MEANPATHDELAY:
+               snmp_set_var_typed_value(request->requestvb,
+                                        ASN_OCTET_STR,
+                                        &ds->meanPathDelay, 
sizeof(ds->meanPathDelay));
+               break;
+       default:
+               return SNMP_ERR_GENERR;
+       }
+
+       return SNMP_ERR_NOERROR;
+}
+
+static int set_pds_return_values(unsigned int column,
+                                struct management_tlv *mgt,
+                                netsnmp_request_info *request)
+{
+       struct parentDS *ds = (struct parentDS *) mgt->data;
+
+       switch (column) {
+       case COLUMN_PARENTDS_PARENTPORTIDENTITY:
+               snmp_set_var_typed_value(request->requestvb,
+                                        ASN_OCTET_STR,
+                                        &ds->parentPortIdentity, 
sizeof(ds->parentPortIdentity));
+               break;
+       case COLUMN_PARENTDS_PARENTSTATS:
+               snmp_set_var_typed_integer(request->requestvb,
+                                          ASN_INTEGER,
+                                          ds->parentStats);
+               break;
+       case COLUMN_PARENTDS_OFFSET:
+               snmp_set_var_typed_integer(request->requestvb,
+                                          ASN_INTEGER,
+                                          
ds->observedParentOffsetScaledLogVariance);
+               break;
+       case COLUMN_PARENTDS_CLOCKPHCHRATE:
+               snmp_set_var_typed_integer(request->requestvb,
+                                          ASN_INTEGER,
+                                          
ds->observedParentClockPhaseChangeRate);
+               break;
+       case COLUMN_PARENTDS_GMCLOCKIDENTITY:
+               snmp_set_var_typed_value(request->requestvb,
+                                        ASN_OCTET_STR,
+                                        &ds->grandmasterIdentity, 
sizeof(ds->grandmasterIdentity));
+               break;
+       case COLUMN_PARENTDS_GMCLOCKPRIORITY1:
+               snmp_set_var_typed_integer(request->requestvb,
+                                          ASN_UNSIGNED,
+                                          ds->grandmasterPriority1);
+               break;
+       case COLUMN_PARENTDS_GMCLOCKPRIORITY2:
+               snmp_set_var_typed_integer(request->requestvb,
+                                          ASN_UNSIGNED,
+                                          ds->grandmasterPriority2);
+               break;
+       case COLUMN_PARENTDS_GMCLOCKQUALITYCLASS:
+               snmp_set_var_typed_integer(request->requestvb,
+                                          ASN_INTEGER,
+                                          
ds->grandmasterClockQuality.clockClass);
+               break;
+       case COLUMN_PARENTDS_GMCLOCKQUALITYACCURACY:
+               snmp_set_var_typed_integer(request->requestvb,
+                                          ASN_INTEGER,
+                                          
ds->grandmasterClockQuality.clockAccuracy);
+               break;
+       case COLUMN_PARENTDS_GMCLOCKQUALITYOFFSET:
+               snmp_set_var_typed_integer(request->requestvb,
+                                          ASN_UNSIGNED,
+                                          
ds->grandmasterClockQuality.offsetScaledLogVariance);
+               break;
+       default:
+               return SNMP_ERR_GENERR;
+       }
+
+       return SNMP_ERR_NOERROR;
+}
+
+static int set_dds_return_values(unsigned int column,
+                                struct management_tlv *mgt,
+                                netsnmp_request_info *request) {
+       struct defaultDS *ds = (struct defaultDS *) mgt->data;
+
+       switch (column) {
+       case COLUMN_DEFAULTDS_TWOSTEPFLAG:
+               snmp_set_var_typed_integer(request->requestvb,
+                                          ASN_INTEGER,
+                                          ds->flags & DDS_TWO_STEP_FLAG ? 1 : 
0);
+               break;
+       case COLUMN_DEFAULTDS_CLOCKIDENTITY:
+               snmp_set_var_typed_value(request->requestvb,
+                                        ASN_OCTET_STR,
+                                        &ds->clockIdentity, 
sizeof(ds->clockIdentity));
+               break;
+       case COLUMN_DEFAULTDS_PRIORITY1:
+               snmp_set_var_typed_integer(request->requestvb,
+                                          ASN_UNSIGNED,
+                                          ds->priority1);
+               break;
+       case COLUMN_DEFAULTDS_PRIORITY2:
+               snmp_set_var_typed_integer(request->requestvb,
+                                          ASN_UNSIGNED,
+                                          ds->priority2);
+               break;
+       case COLUMN_DEFAULTDS_SLAVEONLY:
+               snmp_set_var_typed_integer(request->requestvb,
+                                          ASN_INTEGER,
+                                          ds->flags & DDS_SLAVE_ONLY ? 1 : 0);
+               break;
+       case COLUMN_DEFAULTDS_QUALITYCLASS:
+               snmp_set_var_typed_integer(request->requestvb,
+                                          ASN_INTEGER,
+                                          ds->clockQuality.
+                                          clockClass);
+               break;
+       case COLUMN_DEFAULTDS_QUALITYACCURACY:
+               snmp_set_var_typed_integer(request->requestvb,
+                                          ASN_INTEGER,
+                                          ds->clockQuality.
+                                          clockAccuracy);
+               break;
+       case COLUMN_DEFAULTDS_QUALITYOFFSET:
+               snmp_set_var_typed_integer(request->requestvb,
+                                          ASN_INTEGER,
+                                          ds->clockQuality.
+                                          offsetScaledLogVariance);
+               break;
+       default:
+               return SNMP_ERR_GENERR;
+       }
+
+       return SNMP_ERR_NOERROR;
+}
+
+static int set_tds_return_values(unsigned int column,
+                                struct management_tlv *mgt,
+                                netsnmp_request_info *request)
+{
+       struct timePropertiesDS *ds = (struct timePropertiesDS *) mgt->data;
+
+       switch (column) {
+       case COLUMN_TIMEPROPERTIESDS_CURRENTUTCOFFSETVALID:
+               snmp_set_var_typed_integer(request->requestvb,
+                                          ASN_INTEGER,
+                                          ds->flags & UTC_OFF_VALID ? 1 : 0);
+               break;
+       case COLUMN_TIMEPROPERTIESDS_CURRENTUTCOFFSET:
+               snmp_set_var_typed_integer(request->requestvb,
+                                          ASN_INTEGER,
+                                          ds->currentUtcOffset);
+               break;
+       case COLUMN_TIMEPROPERTIESDS_LEAP59:
+               snmp_set_var_typed_integer(request->requestvb,
+                                          ASN_INTEGER,
+                                          ds->flags & LEAP_59 ? 1 : 0);
+               break;
+       case COLUMN_TIMEPROPERTIESDS_LEAP61:
+               snmp_set_var_typed_integer(request->requestvb,
+                                          ASN_INTEGER,
+                                          ds->flags & LEAP_61 ? 1 : 0);
+               break;
+       case COLUMN_TIMEPROPERTIESDS_TIMETRACEABLE:
+               snmp_set_var_typed_integer(request->requestvb,
+                                          ASN_INTEGER,
+                                          ds->flags & TIME_TRACEABLE ? 1 : 0);
+               break;
+       case COLUMN_TIMEPROPERTIESDS_FREQTRACEABLE:
+               snmp_set_var_typed_integer(request->requestvb,
+                                          ASN_INTEGER,
+                                          ds->flags & FREQ_TRACEABLE ? 1 : 0);
+               break;
+       case COLUMN_TIMEPROPERTIESDS_PTPTIMESCALE:
+               snmp_set_var_typed_integer(request->requestvb,
+                                          ASN_INTEGER,
+                                          ds->flags & PTP_TIMESCALE ? 1 : 0);
+               break;
+       case COLUMN_TIMEPROPERTIESDS_SOURCE:
+               snmp_set_var_typed_integer(request->requestvb,
+                                          ASN_INTEGER,
+                                          ds->timeSource);
+               break;
+       default:
+               return SNMP_ERR_GENERR;
+       }
+
+       return SNMP_ERR_NOERROR;
+}
+
+static int set_port_ds_return_values(unsigned int column,
+                                    struct management_tlv *mgt,
+                                    netsnmp_request_info *request)
+{
+       struct portDS *ds = (struct portDS *) mgt->data;
+
+       switch (column) {
+       case COLUMN_PORTDS_NAME:
+               snmp_set_var_typed_value(request->requestvb,
+                                        ASN_OCTET_STR,
+                                        "PORTNAME", 8);
+               break;
+       case COLUMN_PORTDS_PORTIDENTITY:
+               snmp_set_var_typed_value(request->requestvb,
+                                        ASN_OCTET_STR,
+                                        &ds->portIdentity, 
sizeof(ds->portIdentity));
+               break;
+       case COLUMN_PORTDS_LOGANNOUNCEMENTINTERVAL:
+               snmp_set_var_typed_integer(request->requestvb,
+                                          ASN_INTEGER,
+                                          ds->logAnnounceInterval);
+               break;
+       case COLUMN_PORTDS_ANNOUNCERCTTIMEOUT:
+               snmp_set_var_typed_integer(request->requestvb,
+                                          ASN_INTEGER,
+                                          ds->announceReceiptTimeout);
+               break;
+       case COLUMN_PORTDS_LOGSYNCINTERVAL:
+               snmp_set_var_typed_integer(request->requestvb,
+                                          ASN_INTEGER,
+                                          ds->logSyncInterval);
+               break;
+       case COLUMN_PORTDS_MINDELAYREQINTERVAL:
+               snmp_set_var_typed_integer(request->requestvb,
+                                          ASN_INTEGER,
+                                          ds->logMinDelayReqInterval);
+               break;
+       case COLUMN_PORTDS_PEERDELAYREQINTERVAL:
+               snmp_set_var_typed_integer(request->requestvb,
+                                          ASN_INTEGER,
+                                          ds->logMinPdelayReqInterval);
+               break;
+       case COLUMN_PORTDS_DELAYMECH:
+               snmp_set_var_typed_integer(request->requestvb,
+                                          ASN_INTEGER,
+                                          ds->delayMechanism);
+               break;
+       case COLUMN_PORTDS_PEERMEANPATHDELAY:
+               snmp_set_var_typed_value(request->requestvb,
+                                        ASN_OCTET_STR,
+                                        &ds->peerMeanPathDelay, 
sizeof(ds->peerMeanPathDelay));
+               break;
+       case COLUMN_PORTDS_GRANTDURATION:
+               snmp_set_var_typed_integer(request->requestvb,
+                                          ASN_UNSIGNED,
+                                          0xFFFF);
+               break;
+       case COLUMN_PORTDS_PTPVERSION:
+               snmp_set_var_typed_integer(request->requestvb,
+                                          ASN_UNSIGNED,
+                                          ds->versionNumber);
+               break;
+       default:
+               return SNMP_ERR_GENERR;
+       }
+
+       return SNMP_ERR_NOERROR;
+}
+
+static int ds_handler(netsnmp_mib_handler *handler,
+                     netsnmp_handler_registration *reginfo,
+                     netsnmp_agent_request_info *reqinfo,
+                     netsnmp_request_info *requests)
+{
+       netsnmp_table_request_info *table_info;
+       netsnmp_request_info *request;
+       struct management_tlv *mgt;
+       struct ptp_message *msg;
+
+       if (reqinfo->mode != MODE_GET) {
+               return SNMP_ERR_NOERROR;
+       }
+
+       /*
+        * Read-support (also covers GetNext requests)
+        */
+       for (request = requests; request; request = request->next) {
+               msg = (struct ptp_message *)
+                       netsnmp_extract_iterator_context(request);
+               table_info = netsnmp_extract_table_info(request);
+               if (!table_info->colnum || !msg) {
+                       netsnmp_set_request_error(reqinfo, request,
+                                                 SNMP_NOSUCHINSTANCE);
+                       continue;
+               }
+               mgt = (struct management_tlv *) msg->management.suffix;
+               switch (mgt->id) {
+               case TLV_CURRENT_DATA_SET:
+                       if (set_cds_return_values(table_info->colnum,
+                                                 mgt, request)) {
+                               netsnmp_set_request_error(reqinfo, request,
+                                                         SNMP_NOSUCHOBJECT);
+                       }
+                       break;
+               case TLV_PARENT_DATA_SET:
+                       if (set_pds_return_values(table_info->colnum,
+                                                 mgt, request)) {
+                               netsnmp_set_request_error(reqinfo, request,
+                                                         SNMP_NOSUCHOBJECT);
+                       }
+                       break;
+               case TLV_DEFAULT_DATA_SET:
+                       if (set_dds_return_values(table_info->colnum,
+                                                 mgt, request)) {
+                               netsnmp_set_request_error(reqinfo, request,
+                                                         SNMP_NOSUCHOBJECT);
+                       }
+                       break;
+               case TLV_TIME_PROPERTIES_DATA_SET:
+                       if (set_tds_return_values(table_info->colnum,
+                                                 mgt, request)) {
+                               netsnmp_set_request_error(reqinfo, request,
+                                                         SNMP_NOSUCHOBJECT);
+                       }
+                       break;
+               case TLV_PORT_DATA_SET:
+                       if (set_port_ds_return_values(table_info->colnum,
+                                                     mgt, request)) {
+                               netsnmp_set_request_error(reqinfo, request,
+                                                         SNMP_NOSUCHOBJECT);
+                       }
+                       break;
+               }
+       }
+
+       return SNMP_ERR_NOERROR;
+}
+
+static int init_ds_table(const char *ds_name,
+                        const oid *ds_oid,
+                        const size_t ds_oid_len,
+                        unsigned int min_column,
+                        unsigned int max_column,
+                        struct mydata *mydata)
+{
+       netsnmp_table_registration_info *tinfo;
+       netsnmp_handler_registration *reg;
+       netsnmp_iterator_info *iinfo;
+
+       tinfo = SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info);
+       if (add_ds_table_indexes(tinfo, mydata->id)) {
+               pr_err("Failed to add indexes for id: %d", mydata->id);
+               return SNMP_ERR_GENERR;
+       }
+       tinfo->min_column = min_column;
+       tinfo->max_column = max_column;
+
+       reg = netsnmp_create_handler_registration(ds_name,
+                                                 ds_handler,
+                                                 ds_oid,
+                                                 ds_oid_len,
+                                                 HANDLER_CAN_RONLY);
+
+       iinfo = SNMP_MALLOC_TYPEDEF(netsnmp_iterator_info);
+       iinfo->get_first_data_point = get_first_data_point;
+       iinfo->get_next_data_point = get_next_data_point;
+       iinfo->table_reginfo = tinfo;
+       iinfo->flags |= NETSNMP_ITERATOR_FLAG_SORTED;
+       iinfo->myvoid = mydata;
+
+       netsnmp_register_table_iterator(reg, iinfo);
+
+       return SNMP_ERR_NOERROR;
+}
+
+int init_ptpbase_mib(void *data_void)
+{
+       static struct mydata cds_mydata = {TLV_CURRENT_DATA_SET};
+       static struct mydata pds_mydata = {TLV_PARENT_DATA_SET};
+       static struct mydata dds_mydata = {TLV_DEFAULT_DATA_SET};
+       static struct mydata tds_mydata = {TLV_TIME_PROPERTIES_DATA_SET};
+       static struct mydata port_mydata = {TLV_PORT_DATA_SET, 1};
+       const oid clock_cds_oid[] = {SNMP_OID_PTPBASE_CLOCK_CDS};
+       const oid clock_pds_oid[] = {SNMP_OID_PTPBASE_CLOCK_PDS};
+       const oid clock_dds_oid[] = {SNMP_OID_PTPBASE_CLOCK_DDS};
+       const oid clock_tds_oid[] = {SNMP_OID_PTPBASE_CLOCK_TDS};
+       const oid port_ds_oid[]   = {SNMP_OID_PTPBASE_PORT_DS};
+       struct ds_data *data;
+
+       data = SNMP_MALLOC_TYPEDEF(struct ds_data);
+       if (!data) {
+               pr_err("Failed to malloc memory");
+               goto err;
+       }
+       cds_mydata.data = pds_mydata.data = dds_mydata.data =
+               tds_mydata.data = port_mydata.data = data;
+
+       if (init_ds_table("clock_cds", clock_cds_oid,
+                         OID_LENGTH(clock_cds_oid),
+                         COLUMN_CDS_MIN, COLUMN_CDS_MAX,
+                         &cds_mydata)) {
+               pr_err("Failed to initialize clock_current_ds");
+               goto err_free;
+       }
+       if (init_ds_table("clock_pds", clock_pds_oid,
+                         OID_LENGTH(clock_pds_oid),
+                         COLUMN_PDS_MIN, COLUMN_PDS_MAX,
+                         &pds_mydata)) {
+               pr_err("Failed to initialize clock_current_ds");
+               goto err_free;
+       }
+       if (init_ds_table("clock_dds", clock_dds_oid,
+                         OID_LENGTH(clock_dds_oid),
+                         COLUMN_DDS_MIN, COLUMN_DDS_MAX,
+                         &dds_mydata)) {
+               pr_err("Failed to initialize clock_current_ds");
+               goto err_free;
+       }
+       if (init_ds_table("clock_tds", clock_tds_oid,
+                         OID_LENGTH(clock_tds_oid),
+                         COLUMN_TDS_MIN, COLUMN_TDS_MAX,
+                         &tds_mydata)) {
+               pr_err("Failed to initialize clock_current_ds");
+               goto err_free;
+       }
+       if (init_ds_table("port_ds", port_ds_oid,
+                         OID_LENGTH(port_ds_oid),
+                         COLUMN_PORTDS_MIN, COLUMN_PORTDS_MAX,
+                         &port_mydata)) {
+               pr_err("Failed to initialize port_ds");
+               goto err_free;
+       }
+
+       TAILQ_INIT(&data->msg);
+       data_void = (void *)data;
+
+       return SNMP_ERR_NOERROR;
+
+err_free:
+       SNMP_FREE(data);
+err:
+       data = data_void = NULL;
+
+       return SNMP_ERR_GENERR;
+}
+
+void free_ptpbase_mib(void *data_void)
+{
+       struct ds_data *data = (struct ds_data *)data_void;
+       reset_ds_data(data);
+       SNMP_FREE(data);
+}
diff --git a/snmp4lptp_mib.h b/snmp4lptp_mib.h
index af449ce..5079e6c 100644
--- a/snmp4lptp_mib.h
+++ b/snmp4lptp_mib.h
@@ -28,4 +28,7 @@
 struct ptp_message* snmp4lptp_run_pmc(char *cmd);
 uint8_t snmp4lptp_get_domain();
 
+int init_ptpbase_mib(void *data_void);
+void free_ptpbase_mib(void *data_void);
+
 #endif /* HAVE_SNMP4LPTP_MIB_H */
-- 
1.8.3.1



_______________________________________________
Linuxptp-devel mailing list
Linuxptp-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linuxptp-devel

Reply via email to