text: /*
   *  Linux kernel interface
   *
   */
  
  #include <net-snmp/agent/net-snmp-agent-includes.h>
  #include <net-snmp/net-snmp-config.h>
  #include <net-snmp/net-snmp-features.h>
  #include <net-snmp/net-snmp-includes.h>
  
  #if HAVE_STRING_H
  #include <string.h>
  #endif
  #include <sys/types.h>
  #if HAVE_SYS_PARAM_H
  #include <sys/param.h>
  #endif
  #include <errno.h>
  #include <stddef.h>
  
  #include "kernel_linux.h"
  
  struct ip_mib cached_ip_mib;
  struct ip6_mib cached_ip6_mib;
  struct icmp_mib cached_icmp_mib;
  struct icmp6_mib cached_icmp6_mib;
  struct icmp4_msg_mib cached_icmp4_msg_mib;
  struct tcp_mib cached_tcp_mib;
  struct udp_mib cached_udp_mib;
  struct udp6_mib cached_udp6_mib;
  
  struct stats_descr
  {
      const char* prefix;
      const char* col_name;
      void* var;
      unsigned int offset;
      unsigned int validity_offset;
  };
  
  static const struct stats_descr ipv4_snmp_stats[] = {
      {"Ip:", "Forwarding", &cached_ip_mib,
       offsetof(struct ip_mib, ipForwarding)},
      {"Ip:", "DefaultTTL", &cached_ip_mib,
       offsetof(struct ip_mib, ipDefaultTTL)},
      {"Ip:", "InReceives", &cached_ip_mib,
       offsetof(struct ip_mib, ipInReceives)},
      {"Ip:", "InHdrErrors", &cached_ip_mib,
       offsetof(struct ip_mib, ipInHdrErrors)},
      {"Ip:", "InAddrErrors", &cached_ip_mib,
       offsetof(struct ip_mib, ipInAddrErrors)},
      {"Ip:", "ForwDatagrams", &cached_ip_mib,
       offsetof(struct ip_mib, ipForwDatagrams)},
      {"Ip:", "InUnknownProtos", &cached_ip_mib,
       offsetof(struct ip_mib, ipInUnknownProtos)},
      {"Ip:", "InDiscards", &cached_ip_mib,
       offsetof(struct ip_mib, ipInDiscards)},
      {"Ip:", "InDelivers", &cached_ip_mib,
       offsetof(struct ip_mib, ipInDelivers)},
      {"Ip:", "OutRequests", &cached_ip_mib,
       offsetof(struct ip_mib, ipOutRequests)},
      {"Ip:", "OutDiscards", &cached_ip_mib,
       offsetof(struct ip_mib, ipOutDiscards)},
      {"Ip:", "OutNoRoutes", &cached_ip_mib,
       offsetof(struct ip_mib, ipOutNoRoutes)},
      {"Ip:", "ReasmTimeout", &cached_ip_mib,
       offsetof(struct ip_mib, ipReasmTimeout)},
      {"Ip:", "ReasmReqds", &cached_ip_mib,
       offsetof(struct ip_mib, ipReasmReqds)},
      {"Ip:", "ReasmOKs", &cached_ip_mib, offsetof(struct ip_mib, ipReasmOKs)},
      {"Ip:", "ReasmFails", &cached_ip_mib,
       offsetof(struct ip_mib, ipReasmFails)},
      {"Ip:", "FragOKs", &cached_ip_mib, offsetof(struct ip_mib, ipFragOKs)},
      {"Ip:", "FragFails", &cached_ip_mib, offsetof(struct ip_mib, ipFragFails)},
      {"Ip:", "FragCreates", &cached_ip_mib,
       offsetof(struct ip_mib, ipFragCreates)},
  
      {"Icmp:", "InMsgs", &cached_icmp_mib,
       offsetof(struct icmp_mib, icmpInMsgs)},
      {"Icmp:", "InErrors", &cached_icmp_mib,
       offsetof(struct icmp_mib, icmpInErrors)},
      {"Icmp:", "InDestUnreachs", &cached_icmp_mib,
       offsetof(struct icmp_mib, icmpInDestUnreachs)},
      {"Icmp:", "InTimeExcds", &cached_icmp_mib,
       offsetof(struct icmp_mib, icmpInTimeExcds)},
      {"Icmp:", "InParmProbs", &cached_icmp_mib,
       offsetof(struct icmp_mib, icmpInParmProbs)},
      {"Icmp:", "InSrcQuenchs", &cached_icmp_mib,
       offsetof(struct icmp_mib, icmpInSrcQuenchs)},
      {"Icmp:", "InRedirects", &cached_icmp_mib,
       offsetof(struct icmp_mib, icmpInRedirects)},
      {"Icmp:", "InEchos", &cached_icmp_mib,
       offsetof(struct icmp_mib, icmpInEchos)},
      {"Icmp:", "InEchoReps", &cached_icmp_mib,
       offsetof(struct icmp_mib, icmpInEchoReps)},
      {"Icmp:", "InTimestamps", &cached_icmp_mib,
       offsetof(struct icmp_mib, icmpInTimestamps)},
      {"Icmp:", "InTimestampReps", &cached_icmp_mib,
       offsetof(struct icmp_mib, icmpInTimestampReps)},
      {"Icmp:", "InAddrMasks", &cached_icmp_mib,
       offsetof(struct icmp_mib, icmpInAddrMasks)},
      {"Icmp:", "InAddrMaskReps", &cached_icmp_mib,
       offsetof(struct icmp_mib, icmpInAddrMaskReps)},
      {"Icmp:", "OutMsgs", &cached_icmp_mib,
       offsetof(struct icmp_mib, icmpOutMsgs)},
      {"Icmp:", "OutErrors", &cached_icmp_mib,
       offsetof(struct icmp_mib, icmpOutErrors)},
      {"Icmp:", "OutDestUnreachs", &cached_icmp_mib,
       offsetof(struct icmp_mib, icmpOutDestUnreachs)},
      {"Icmp:", "OutTimeExcds", &cached_icmp_mib,
       offsetof(struct icmp_mib, icmpOutTimeExcds)},
      {"Icmp:", "OutParmProbs", &cached_icmp_mib,
       offsetof(struct icmp_mib, icmpOutParmProbs)},
      {"Icmp:", "OutSrcQuenchs", &cached_icmp_mib,
       offsetof(struct icmp_mib, icmpOutSrcQuenchs)},
      {"Icmp:", "OutRedirects", &cached_icmp_mib,
       offsetof(struct icmp_mib, icmpOutRedirects)},
      {"Icmp:", "OutEchos", &cached_icmp_mib,
       offsetof(struct icmp_mib, icmpOutEchos)},
      {"Icmp:", "OutEchoReps", &cached_icmp_mib,
       offsetof(struct icmp_mib, icmpOutEchoReps)},
      {"Icmp:", "OutTimestamps", &cached_icmp_mib,
       offsetof(struct icmp_mib, icmpOutTimestamps)},
      {"Icmp:", "OutTimestampReps", &cached_icmp_mib,
       offsetof(struct icmp_mib, icmpOutTimestampReps)},
      {"Icmp:", "OutAddrMasks", &cached_icmp_mib,
       offsetof(struct icmp_mib, icmpOutAddrMasks)},
      {"Icmp:", "OutAddrMaskReps", &cached_icmp_mib,
       offsetof(struct icmp_mib, icmpOutAddrMaskReps)},
  
      {"Tcp:", "RtoAlgorithm", &cached_tcp_mib,
       offsetof(struct tcp_mib, tcpRtoAlgorithm)},
      {"Tcp:", "RtoMin", &cached_tcp_mib, offsetof(struct tcp_mib, tcpRtoMin)},
      {"Tcp:", "RtoMax", &cached_tcp_mib, offsetof(struct tcp_mib, tcpRtoMax)},
      {"Tcp:", "MaxConn", &cached_tcp_mib, offsetof(struct tcp_mib, tcpMaxConn)},
      {"Tcp:", "ActiveOpens", &cached_tcp_mib,
       offsetof(struct tcp_mib, tcpActiveOpens)},
      {"Tcp:", "PassiveOpens", &cached_tcp_mib,
       offsetof(struct tcp_mib, tcpPassiveOpens)},
      {"Tcp:", "AttemptFails", &cached_tcp_mib,
       offsetof(struct tcp_mib, tcpAttemptFails)},
      {"Tcp:", "EstabResets", &cached_tcp_mib,
       offsetof(struct tcp_mib, tcpEstabResets)},
      {"Tcp:", "CurrEstab", &cached_tcp_mib,
       offsetof(struct tcp_mib, tcpCurrEstab)},
      {"Tcp:", "InSegs", &cached_tcp_mib, offsetof(struct tcp_mib, tcpInSegs)},
      {"Tcp:", "OutSegs", &cached_tcp_mib, offsetof(struct tcp_mib, tcpOutSegs)},
      {"Tcp:", "RetransSegs", &cached_tcp_mib,
       offsetof(struct tcp_mib, tcpRetransSegs)},
      {"Tcp:", "InErrs", &cached_tcp_mib, offsetof(struct tcp_mib, tcpInErrs),
       offsetof(struct tcp_mib, tcpInErrsValid)},
      {"Tcp:", "OutRsts", &cached_tcp_mib, offsetof(struct tcp_mib, tcpOutRsts),
       offsetof(struct tcp_mib, tcpOutRstsValid)},
  
      {"Udp:", "InDatagrams", &cached_udp_mib,
       offsetof(struct udp_mib, udpInDatagrams)},
      {"Udp:", "NoPorts", &cached_udp_mib, offsetof(struct udp_mib, udpNoPorts)},
      {"Udp:", "InErrors", &cached_udp_mib,
       offsetof(struct udp_mib, udpInErrors)},
      {"Udp:", "OutDatagrams", &cached_udp_mib,
       offsetof(struct udp_mib, udpOutDatagrams)},
  };
  
  #define IP6_STATS_LINE "Ip6"
  #define ICMP6_STATS_LINE "Icmp6"
  #define UDP6_STATS_LINE "Udp6"
  
  #define IP6_STATS_PREFIX_LEN 3
  #define ICMP6_STATS_PREFIX_LEN 5
  #define UDP6_STATS_PREFIX_LEN 4
  
  netsnmp_feature_child_of(linux_ip6_stat_all, libnetsnmpmibs)
  
      netsnmp_feature_child_of(linux_read_ip6_stat, linux_ip6_stat_all)
  
          static int decode_icmp_msg(char* line, char* data,
                                     struct icmp4_msg_mib* msg)
  {
      char *token, *saveptr, *lineptr, *saveptr1, *dataptr, *delim = NULL;
      char line_cpy[1024];
      char data_cpy[1024];
      long index;
  
      if (data == NULL)
          return -1;
  
      /*
       * Since we are using strtok, there is a possiblity of the orginal data
       * getting modified. So we take a local copy for this purpose even though
       * its expensive.
       */
      strlcpy(line_cpy, line, sizeof(line_cpy));
      strlcpy(data_cpy, data, sizeof(data_cpy));
  
      lineptr = line_cpy;
      dataptr = data_cpy;
      saveptr1 = saveptr = NULL;
      while (1)
      {
          if (NULL == (token = strtok_r(lineptr, " ", &saveptr)))
              break;
          lineptr = NULL;
          errno = 0;
          if (0 == strncmp(strsep(&token, "e"), "OutTyp", 6))
          {
              index = strtol(token, &delim, 0);
              if (ERANGE == errno)
              {
                  continue;
              }
              else if (index > 255)
              {
                  continue;
              }
              else if (index < 0)
              {
                  continue;
              }
              if (NULL == (token = strtok_r(dataptr, " ", &saveptr1)))
                  break;
              dataptr = NULL;
              msg->vals[index].OutType = atoi(token);
          }
          else
          {
              index = strtol(token, &delim, 0);
              if (ERANGE == errno)
              {
                  continue;
              }
              else if (index > 255)
              {
                  continue;
              }
              else if (index < 0)
              {
                  continue;
              }
              if (NULL == (token = strtok_r(dataptr, " ", &saveptr1)))
                  break;
              dataptr = NULL;
              msg->vals[index].InType = atoi(token);
          }
      }
      return 0;
  }
  
  static int linux_read_mibII_stats(void)
  {
      FILE* in;
      char line[1024], data[1024], *linepos, *datapos, *pfx, *hdr, *v;
      const struct stats_descr* d;
      const struct stats_descr* const end =
          ipv4_snmp_stats + sizeof(ipv4_snmp_stats) / sizeof(ipv4_snmp_stats[0]);
      int ret = 0;
  
      in = fopen("/proc/net/snmp", "r");
      if (!in)
      {
          DEBUGMSGTL(("mibII/kernel_linux", "Unable to open /proc/net/snmp"));
          return -1;
      }
  
      while (fgets(line, sizeof(line), in) && fgets(data, sizeof(data), in))
      {
          if (!(pfx = strtok_r(line, " ", &linepos)))
              continue;
          if (!strtok_r(data, " ", &datapos))
              continue;
          if (strcmp(pfx, "IcmpMsg:") == 0)
          {
              decode_icmp_msg(linepos, datapos, &cached_icmp4_msg_mib);
          }
          else
          {
              while ((hdr = strtok_r(linepos, " \n", &linepos)) &&
                     (v = strtok_r(datapos, " \n", &datapos)))
              {
                  for (d = ipv4_snmp_stats; d < end; d++)
                  {
                      if (strcmp(d->prefix, pfx) == 0 &&
                          strcmp(d->col_name, hdr) == 0)
                      {
                          *(unsigned long*)(d->var + d->offset) = atol(v);
                          if (d->validity_offset != 0)
                          {
                              *(short*)(d->var + d->validity_offset) = 1;
                          }
                          break;
                      }
                  }
                  if (d == end)
                      DEBUGMSGTL(("mibII/kernel_linux", "Skipped %s %s %s\n", pfx,
                                  hdr, v));
              }
          }
      }
      fclose(in);
  
      /*
       * Tweak illegal values:
       *
       * valid values for ipForwarding are 1 == yup, 2 == nope
       * a 0 is forbidden, so patch:
       */
      if (!cached_ip_mib.ipForwarding)
          cached_ip_mib.ipForwarding = 2;
  
      /*
       * 0 is illegal for tcpRtoAlgorithm
       * so assume `other' algorithm:
       */
      if (!cached_tcp_mib.tcpRtoAlgorithm)
          cached_tcp_mib.tcpRtoAlgorithm = 1;
  
      return ret;
  }
  
  int linux_read_ip_stat(struct ip_mib* ipstat)
  {
      memset((char*)ipstat, (0), sizeof(*ipstat));
      if (linux_read_mibII_stats() == -1)
          return -1;
      memcpy((char*)ipstat, (char*)&cached_ip_mib, sizeof(*ipstat));
      return 0;
  }
  
  #ifndef NETSNMP_FEATURE_REMOVE_LINUX_READ_IP6_STAT
  int linux_read_ip6_stat(struct ip6_mib* ip6stat)
  {
  #ifdef NETSNMP_ENABLE_IPV6
      FILE* in;
      char line[1024];
      unsigned long stats;
      char* endp;
      int match;
  #endif
  
      memset((char*)ip6stat, (0), sizeof(*ip6stat));
  
  #ifdef NETSNMP_ENABLE_IPV6
      DEBUGMSGTL(
          ("mibII/kernel_linux/ip6stats", "Reading /proc/net/snmp6 stats\n"));
      if (NULL == (in = fopen("/proc/net/snmp6", "r")))
      {
          DEBUGMSGTL(("mibII/kernel_linux/ip6stats",
                      "Failed to open /proc/net/snmp6\n"));
          return -1;
      }
  
      while (NULL != fgets(line, sizeof(line), in))
      {
          if (0 != strncmp(line, IP6_STATS_LINE, IP6_STATS_PREFIX_LEN))
              continue;
  
          if (1 != sscanf(line, "%*s %lu", &stats))
              continue;
  
          endp = strchr(line, ' ');
          if (endp)
              *endp = '\0';
          DEBUGMSGTL(("mibII/kernel_linux/ip6stats", "Find tag: %s\n", line));
  
          match = 1;
          if (0 == strncmp(line + 3, "In", 2))
          { /* In */
              if (0 == strcmp(line + 5, "AddrErrors"))
              {
                  cached_ip6_mib.ip6InAddrErrors = stats;
              }
              else if (0 == strcmp(line + 5, "Delivers"))
              {
                  cached_ip6_mib.ip6InDelivers = stats;
              }
              else if (0 == strcmp(line + 5, "Discards"))
              {
                  cached_ip6_mib.ip6InDiscards = stats;
              }
              else if (0 == strcmp(line + 5, "HdrErrors"))
              {
                  cached_ip6_mib.ip6InHdrErrors = stats;
              }
              else if (0 == strcmp(line + 5, "McastPkts"))
              {
                  cached_ip6_mib.ip6InMcastPkts = stats;
              }
              else if (0 == strcmp(line + 5, "NoRoutes"))
              {
                  cached_ip6_mib.ip6InNoRoutes = stats;
              }
              else if (0 == strcmp(line + 5, "Receives"))
              {
                  cached_ip6_mib.ip6InReceives = stats;
              }
              else if (0 == strcmp(line + 5, "TruncatedPkts"))
              {
                  cached_ip6_mib.ip6InTruncatedPkts = stats;
              }
              else if (0 == strcmp(line + 5, "TooBigErrors"))
              {
                  cached_ip6_mib.ip6InTooBigErrors = stats;
              }
              else if (0 == strcmp(line + 5, "UnknownProtos"))
              {
                  cached_ip6_mib.ip6InUnknownProtos = stats;
              }
              else
              {
                  match = 0;
              }
          }
          else if (0 == strncmp(line + 3, "Out", 3))
          { /* Out */
              if (0 == strcmp(line + 6, "Discards"))
              {
                  cached_ip6_mib.ip6OutDiscards = stats;
              }
              else if (0 == strcmp(line + 6, "ForwDatagrams"))
              {
                  cached_ip6_mib.ip6OutForwDatagrams = stats;
              }
              else if (0 == strcmp(line + 6, "McastPkts"))
              {
                  cached_ip6_mib.ip6OutMcastPkts = stats;
              }
              else if (0 == strcmp(line + 6, "NoRoutes"))
              {
                  cached_ip6_mib.ip6OutNoRoutes = stats;
              }
              else if (0 == strcmp(line + 6, "Requests"))
              {
                  cached_ip6_mib.ip6OutRequests = stats;
              }
              else
              {
                  match = 0;
              }
          }
          else if (0 == strncmp(line + 3, "Reasm", 5))
          { /* Reasm */
              if (0 == strcmp(line + 8, "Fails"))
              {
                  cached_ip6_mib.ip6ReasmFails = stats;
              }
              else if (0 == strcmp(line + 8, "OKs"))
              {
                  cached_ip6_mib.ip6ReasmOKs = stats;
              }
              else if (0 == strcmp(line + 8, "Reqds"))
              {
                  cached_ip6_mib.ip6ReasmReqds = stats;
              }
              else if (0 == strcmp(line + 8, "Timeout"))
              {
                  cached_ip6_mib.ip6ReasmTimeout = stats;
              }
              else
              {
                  match = 0;
              }
          }
          else if (0 == strncmp(line + 3, "Frag", 4))
          { /* Frag */
              if (0 == strcmp(line + 7, "Creates"))
              {
                  cached_ip6_mib.ip6FragCreates = stats;
              }
              else if (0 == strcmp(line + 7, "Fails"))
              {
                  cached_ip6_mib.ip6FragFails = stats;
              }
              else if (0 == strcmp(line + 7, "OKs"))
              {
                  cached_ip6_mib.ip6FragOKs = stats;
              }
              else
              {
                  match = 0;
              }
          }
          else
          {
              match = 0;
          }
  
          if (!match)
              DEBUGMSGTL(("mibII/kernel_linux/ip6stats", "%s is an unknown tag\n",
                          line));
      }
  
      fclose(in);
  #endif
  
      memcpy((char*)ip6stat, (char*)&cached_ip6_mib, sizeof(*ip6stat));
      return 0;
  }
  #endif /* NETSNMP_FEATURE_REMOVE_LINUX_READ_IP6_STAT */
  
  int linux_read_icmp_msg_stat(struct icmp_mib* icmpstat,
                               struct icmp4_msg_mib* icmpmsgstat, int* flag)
  {
      int ret;
  
      memset(icmpstat, 0, sizeof(*icmpstat));
      memset(icmpmsgstat, 0, sizeof(*icmpmsgstat));
  
      if ((ret = linux_read_mibII_stats()) == -1)
      {
          return -1;
      }
      else if (ret)
      {
          memcpy(icmpmsgstat, &cached_icmp4_msg_mib, sizeof(*icmpmsgstat));
          *flag = 1; /* We have a valid icmpmsg */
      }
  
      memcpy(icmpstat, &cached_icmp_mib, sizeof(*icmpstat));
      return 0;
  }
  
  int linux_read_icmp_stat(struct icmp_mib* icmpstat)
  {
      memset((char*)icmpstat, (0), sizeof(*icmpstat));
      if (linux_read_mibII_stats() == -1)
          return -1;
      memcpy((char*)icmpstat, (char*)&cached_icmp_mib, sizeof(*icmpstat));
      return 0;
  }
  
  static int linux_read_icmp6_parse(struct icmp6_mib* icmp6stat,
                                    struct icmp6_msg_mib* icmp6msgstat,
                                    int* support)
  {
  #ifdef NETSNMP_ENABLE_IPV6
      FILE* in;
      char line[1024];
      char name[255];
      unsigned long stats;
      char *endp, *vals;
      int match;
  #endif
  
      memset(icmp6stat, 0, sizeof(*icmp6stat));
      if (NULL != icmp6msgstat)
          memset(icmp6msgstat, 0, sizeof(*icmp6msgstat));
  
  #ifdef NETSNMP_ENABLE_IPV6
      DEBUGMSGTL(
          ("mibII/kernel_linux/icmp6stats", "Reading /proc/net/snmp6 stats\n"));
      if (NULL == (in = fopen("/proc/net/snmp6", "r")))
      {
          DEBUGMSGTL(("mibII/kernel_linux/icmp6stats",
                      "Failed to open /proc/net/snmp6\n"));
          return -1;
      }
  
      while (NULL != fgets(line, sizeof(line), in))
      {
          if (0 != strncmp(line, ICMP6_STATS_LINE, ICMP6_STATS_PREFIX_LEN))
              continue;
  
          if (2 != sscanf(line, "%s %lu", name, &stats))
              continue;
  
          endp = strchr(line, ' ');
          if (endp)
              *endp = '\0';
          DEBUGMSGTL(("mibII/kernel_linux/icmp6stats", "Find tag: %s\n", line));
  
          vals = name;
          if (NULL != icmp6msgstat)
          {
              int type;
              if (0 == strncmp(name, "Icmp6OutType", 12))
              {
                  strsep(&vals, "e");
                  type = atoi(vals);
                  if (type < 0 || type > 255)
                      continue;
                  icmp6msgstat->vals[type].OutType = stats;
                  *support = 1;
                  continue;
              }
              else if (0 == strncmp(name, "Icmp6InType", 11))
              {
                  strsep(&vals, "e");
                  type = atoi(vals);
                  if (type < 0 || type > 255)
                      continue;
                  icmp6msgstat->vals[type].InType = stats;
                  *support = 1;
                  continue;
              }
          }
  
          match = 1;
          if (0 == strncmp(line + 5, "In", 2))
          { /* In */
              if (0 == strcmp(line + 7, "DestUnreachs"))
              {
                  cached_icmp6_mib.icmp6InDestUnreachs = stats;
              }
              else if (0 == strcmp(line + 7, "Echos"))
              {
                  cached_icmp6_mib.icmp6InEchos = stats;
              }
              else if (0 == strcmp(line + 7, "EchoReplies"))
              {
                  cached_icmp6_mib.icmp6InEchoReplies = stats;
              }
              else if (0 == strcmp(line + 7, "Errors"))
              {
                  cached_icmp6_mib.icmp6InErrors = stats;
              }
              else if (0 == strcmp(line + 7, "GroupMembQueries"))
              {
                  cached_icmp6_mib.icmp6InGroupMembQueries = stats;
              }
              else if (0 == strcmp(line + 7, "GroupMembReductions"))
              {
                  cached_icmp6_mib.icmp6InGroupMembReductions = stats;
              }
              else if (0 == strcmp(line + 7, "GroupMembResponses"))
              {
                  cached_icmp6_mib.icmp6InGroupMembResponses = stats;
              }
              else if (0 == strcmp(line + 7, "Msgs"))
              {
                  cached_icmp6_mib.icmp6InMsgs = stats;
              }
              else if (0 == strcmp(line + 7, "NeighborAdvertisements"))
              {
                  cached_icmp6_mib.icmp6InNeighborAdvertisements = stats;
              }
              else if (0 == strcmp(line + 7, "NeighborSolicits"))
              {
                  cached_icmp6_mib.icmp6InNeighborSolicits = stats;
              }
              else if (0 == strcmp(line + 7, "PktTooBigs"))
              {
                  cached_icmp6_mib.icmp6InPktTooBigs = stats;
              }
              else if (0 == strcmp(line + 7, "ParmProblems"))
              {
                  cached_icmp6_mib.icmp6InParmProblems = stats;
              }
              else if (0 == strcmp(line + 7, "Redirects"))
              {
                  cached_icmp6_mib.icmp6InRedirects = stats;
              }
              else if (0 == strcmp(line + 7, "RouterAdvertisements"))
              {
                  cached_icmp6_mib.icmp6InRouterAdvertisements = stats;
              }
              else if (0 == strcmp(line + 7, "RouterSolicits"))
              {
                  cached_icmp6_mib.icmp6InRouterSolicits = stats;
              }
              else if (0 == strcmp(line + 7, "TimeExcds"))
              {
                  cached_icmp6_mib.icmp6InTimeExcds = stats;
              }
              else
              {
                  match = 0;
              }
          }
          else if (0 == strncmp(line + 5, "Out", 3))
          { /* Out */
              if (0 == strcmp(line + 8, "DestUnreachs"))
              {
                  cached_icmp6_mib.icmp6OutDestUnreachs = stats;
              }
              else if (0 == strcmp(line + 8, "Echos"))
              {
                  cached_icmp6_mib.icmp6OutEchos = stats;
              }
              else if (0 == strcmp(line + 8, "EchoReplies"))
              {
                  cached_icmp6_mib.icmp6OutEchoReplies = stats;
              }
              else if (0 == strcmp(line + 8, "GroupMembReductions"))
              {
                  cached_icmp6_mib.icmp6OutGroupMembReductions = stats;
              }
              else if (0 == strcmp(line + 8, "GroupMembResponses"))
              {
                  cached_icmp6_mib.icmp6OutGroupMembResponses = stats;
              }
              else if (0 == strcmp(line + 8, "Msgs"))
              {
                  cached_icmp6_mib.icmp6OutMsgs = stats;
              }
              else if (0 == strcmp(line + 8, "NeighborAdvertisements"))
              {
                  cached_icmp6_mib.icmp6OutNeighborAdvertisements = stats;
              }
              else if (0 == strcmp(line + 8, "NeighborSolicits"))
              {
                  cached_icmp6_mib.icmp6OutNeighborSolicits = stats;
              }
              else if (0 == strcmp(line + 8, "PktTooBigs"))
              {
                  cached_icmp6_mib.icmp6OutPktTooBigs = stats;
              }
              else if (0 == strcmp(line + 8, "ParmProblems"))
              {
                  cached_icmp6_mib.icmp6OutParmProblems = stats;
              }
              else if (0 == strcmp(line + 8, "Redirects"))
              {
                  cached_icmp6_mib.icmp6OutRedirects = stats;
              }
              else if (0 == strcmp(line + 8, "RouterSolicits"))
              {
                  cached_icmp6_mib.icmp6OutRouterSolicits = stats;
              }
              else if (0 == strcmp(line + 8, "TimeExcds"))
              {
                  cached_icmp6_mib.icmp6OutTimeExcds = stats;
              }
              else
              {
                  match = 0;
              }
          }
          else
          {
              match = 0;
          }
          if (!match)
              DEBUGMSGTL(("mibII/kernel_linux/icmp6stats",
                          "%s is an unknown tag\n", line));
      }
  
      fclose(in);
  #endif
  
      memcpy((char*)icmp6stat, (char*)&cached_icmp6_mib, sizeof(*icmp6stat));
      return 0;
  }
  
  int linux_read_icmp6_msg_stat(struct icmp6_mib* icmp6stat,
                                struct icmp6_msg_mib* icmp6msgstat, int* support)
  {
      if (linux_read_icmp6_parse(icmp6stat, icmp6msgstat, support) < 0)
          return -1;
      else
          return 0;
  }
  
  int linux_read_icmp6_stat(struct icmp6_mib* icmp6stat)
  {
      if (linux_read_icmp6_parse(icmp6stat, NULL, NULL) < 0)
          return -1;
      else
          return 0;
  }
  
  int linux_read_tcp_stat(struct tcp_mib* tcpstat)
  {
      memset((char*)tcpstat, (0), sizeof(*tcpstat));
      if (linux_read_mibII_stats() == -1)
          return -1;
      memcpy((char*)tcpstat, (char*)&cached_tcp_mib, sizeof(*tcpstat));
      return 0;
  }
  
  int linux_read_udp_stat(struct udp_mib* udpstat)
  {
      memset((char*)udpstat, (0), sizeof(*udpstat));
      if (linux_read_mibII_stats() == -1)
          return -1;
  
  #ifdef NETSNMP_ENABLE_IPV6
      {
          struct udp6_mib udp6stat;
          memset(&udp6stat, 0, sizeof(udp6stat));
  
          if (linux_read_udp6_stat(&udp6stat) == 0)
          {
              cached_udp_mib.udpOutDatagrams += udp6stat.udp6OutDatagrams;
              cached_udp_mib.udpNoPorts += udp6stat.udp6NoPorts;
              cached_udp_mib.udpInDatagrams += udp6stat.udp6InDatagrams;
              cached_udp_mib.udpInErrors += udp6stat.udp6InErrors;
          }
      }
  #endif
      memcpy((char*)udpstat, (char*)&cached_udp_mib, sizeof(*udpstat));
      return 0;
  }
  
  int linux_read_udp6_stat(struct udp6_mib* udp6stat)
  {
  #ifdef NETSNMP_ENABLE_IPV6
      FILE* in;
      char line[1024];
      unsigned long stats;
      char* endp;
  #endif
  
      memset(udp6stat, 0, sizeof(*udp6stat));
  
  #ifdef NETSNMP_ENABLE_IPV6
      DEBUGMSGTL(
          ("mibII/kernel_linux/udp6stats", "Reading /proc/net/snmp6 stats\n"));
      if (NULL == (in = fopen("/proc/net/snmp6", "r")))
      {
          DEBUGMSGTL(("mibII/kernel_linux/udp6stats",
                      "Failed to open /proc/net/snmp6\n"));
          return -1;
      }
  
      while (NULL != fgets(line, sizeof(line), in))
      {
          if (0 != strncmp(line, UDP6_STATS_LINE, UDP6_STATS_PREFIX_LEN))
              continue;
  
          if (1 != sscanf(line, "%*s %lu", &stats))
              continue;
  
          endp = strchr(line, ' ');
          if (endp)
              *endp = '\0';
          DEBUGMSGTL(("mibII/kernel_linux/udp6stats", "Find tag: %s\n", line));
  
          if (0 == strcmp(line + 4, "OutDatagrams"))
          {
              cached_udp6_mib.udp6OutDatagrams = stats;
          }
          else if (0 == strcmp(line + 4, "NoPorts"))
          {
              cached_udp6_mib.udp6NoPorts = stats;
          }
          else if (0 == strcmp(line + 4, "InDatagrams"))
          {
              cached_udp6_mib.udp6InDatagrams = stats;
          }
          else if (0 == strcmp(line + 4, "InErrors"))
          {
              cached_udp6_mib.udp6InErrors = stats;
          }
          else
          {
              DEBUGMSGTL(("mibII/kernel_linux/udp6stats",
                          "%s is an unknown tag\n", line));
          }
      }
  
      fclose(in);
  #endif
  
      memcpy((char*)udp6stat, (char*)&cached_udp6_mib, sizeof(*udp6stat));
      return 0;
  }
  