Exemple #1
0
static snmp_err_t
do_sync(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance, snmp_threadsync_called_fn fn)
{
  const struct snmp_threadsync_node *threadsync_node = (const struct snmp_threadsync_node*)(const void*)instance->node;
  struct threadsync_data *call_data = &threadsync_node->instance->data;

  if (threadsync_node->node.node.oid != threadsync_node->target->node.oid) {
    LWIP_DEBUGF(SNMP_DEBUG, ("Sync node OID does not match target node OID"));
    return SNMP_ERR_NOSUCHINSTANCE;
  }

  memset(&call_data->proxy_instance, 0, sizeof(call_data->proxy_instance));

  instance->reference.ptr = call_data;
  snmp_oid_assign(&call_data->proxy_instance.instance_oid, instance->instance_oid.id, instance->instance_oid.len);

  call_data->proxy_instance.node = &threadsync_node->target->node;
  call_data->threadsync_node     = threadsync_node;

  call_data->arg1.root_oid       = root_oid;
  call_data->arg2.root_oid_len   = root_oid_len;
  call_synced_function(call_data, fn);

  if (call_data->retval.err == SNMP_ERR_NOERROR) {
    instance->access           = call_data->proxy_instance.access;
    instance->asn1_type        = call_data->proxy_instance.asn1_type;
    instance->release_instance = threadsync_release_instance;
    instance->get_value        = (call_data->proxy_instance.get_value != NULL)? threadsync_get_value : NULL;
    instance->set_value        = (call_data->proxy_instance.set_value != NULL)? threadsync_set_value : NULL;
    instance->set_test         = (call_data->proxy_instance.set_test != NULL)?  threadsync_set_test  : NULL;
    snmp_oid_assign(&instance->instance_oid, call_data->proxy_instance.instance_oid.id, call_data->proxy_instance.instance_oid.len);
  }

  return call_data->retval.err;
}
Exemple #2
0
static snmp_err_t
ip_AddrTable_get_next_cell_instance_and_value(const u32_t* column, struct snmp_obj_id* row_oid, union snmp_variant_value* value, u32_t* value_len)
{
  struct netif *netif;
  struct snmp_next_oid_state state;
  u32_t result_temp[LWIP_ARRAYSIZE(ip_AddrTable_oid_ranges)];

  /* init struct to search next oid */
  snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(ip_AddrTable_oid_ranges));

  /* iterate over all possible OIDs to find the next one */
  netif = netif_list;
  while (netif != NULL) {
    u32_t test_oid[LWIP_ARRAYSIZE(ip_AddrTable_oid_ranges)];
    snmp_ip4_to_oid(netif_ip4_addr(netif), &test_oid[0]);

    /* check generated OID: is it a candidate for the next one? */
    snmp_next_oid_check(&state, test_oid, LWIP_ARRAYSIZE(ip_AddrTable_oid_ranges), netif);

    netif = netif->next;
  }

  /* did we find a next one? */
  if (state.status == SNMP_NEXT_OID_STATUS_SUCCESS) {
    snmp_oid_assign(row_oid, state.next_oid, state.next_oid_len);
    /* fill in object properties */
    return ip_AddrTable_get_cell_value_core((struct netif*)state.reference, column, value, value_len);
  }

  /* not found */
  return SNMP_ERR_NOSUCHINSTANCE;
}
Exemple #3
0
static snmp_err_t
sensor_table_get_next_cell_instance(const u32_t* column, struct snmp_obj_id* row_oid, struct snmp_node_instance* cell_instance)
{
  size_t i;
  struct snmp_next_oid_state state;
  u32_t result_temp[LWIP_ARRAYSIZE(sensor_table_oid_ranges)];

  LWIP_UNUSED_ARG(column);
  
  /* init struct to search next oid */
  snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(sensor_table_oid_ranges));

  /* iterate over all possible OIDs to find the next one */
  for(i=0; i<LWIP_ARRAYSIZE(sensors); i++) {
    if(sensors[i].num != 0) {
      u32_t test_oid[LWIP_ARRAYSIZE(sensor_table_oid_ranges)];

      test_oid[0] = sensors[i].num;

      /* check generated OID: is it a candidate for the next one? */
      snmp_next_oid_check(&state, test_oid, LWIP_ARRAYSIZE(sensor_table_oid_ranges), (void*)i);
    }
  }

  /* did we find a next one? */
  if(state.status == SNMP_NEXT_OID_STATUS_SUCCESS) {
    snmp_oid_assign(row_oid, state.next_oid, state.next_oid_len);
    /* store sensor index for subsequent operations (get/test/set) */
    cell_instance->reference.u32 = LWIP_CONST_CAST(u32_t, state.reference);
    return SNMP_ERR_NOERROR;
  }

  /* not found */
  return SNMP_ERR_NOSUCHINSTANCE;
}
static snmp_err_t
interfaces_Table_get_next_cell_instance(const u32_t* column, struct snmp_obj_id* row_oid, struct snmp_node_instance* cell_instance)
{
  struct netif *netif;
  struct snmp_next_oid_state state;
  u32_t result_temp[LWIP_ARRAYSIZE(interfaces_Table_oid_ranges)];

  LWIP_UNUSED_ARG(column);
  
  /* init struct to search next oid */
  snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(interfaces_Table_oid_ranges));

  /* iterate over all possible OIDs to find the next one */
  netif = netif_list;
  while (netif != NULL) {
    u32_t test_oid[LWIP_ARRAYSIZE(interfaces_Table_oid_ranges)];
    test_oid[0] = netif_to_num(netif);

    /* check generated OID: is it a candidate for the next one? */
    snmp_next_oid_check(&state, test_oid, LWIP_ARRAYSIZE(interfaces_Table_oid_ranges), netif);

    netif = netif->next;
  }

  /* did we find a next one? */
  if(state.status == SNMP_NEXT_OID_STATUS_SUCCESS) {
    snmp_oid_assign(row_oid, state.next_oid, state.next_oid_len);
    /* store netif pointer for subsequent operations (get/test/set) */
    cell_instance->reference.ptr = /* (struct netif*) */state.reference;
    return SNMP_ERR_NOERROR;
  }

  /* not found */
  return SNMP_ERR_NOSUCHINSTANCE;
}
static snmp_err_t
tcp_ConnTable_get_next_cell_instance_and_value(const u32_t* column, struct snmp_obj_id* row_oid, union snmp_variant_value* value, u32_t* value_len)
{
  u8_t i;
  struct tcp_pcb *pcb;
  struct snmp_next_oid_state state;
  u32_t result_temp[LWIP_ARRAYSIZE(tcp_ConnTable_oid_ranges)];

  /* init struct to search next oid */
  snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(tcp_ConnTable_oid_ranges));

  /* iterate over all possible OIDs to find the next one */
  for (i = 0; i < LWIP_ARRAYSIZE(tcp_pcb_lists); i++) {
    pcb = *tcp_pcb_lists[i];
    while (pcb != NULL) {
      u32_t test_oid[LWIP_ARRAYSIZE(tcp_ConnTable_oid_ranges)];

      if (IP_IS_V4_VAL(pcb->local_ip)) {
        snmp_ip4_to_oid(ip_2_ip4(&pcb->local_ip), &test_oid[0]);
        test_oid[4] = pcb->local_port;

        /* PCBs in state LISTEN are not connected and have no remote_ip or remote_port */
        if (pcb->state == LISTEN) {
          snmp_ip4_to_oid(IP4_ADDR_ANY, &test_oid[5]);
          test_oid[9] = 0;
        } else {
          if (IP_IS_V6_VAL(pcb->remote_ip)) { /* should never happen */
            continue;
          }
          snmp_ip4_to_oid(ip_2_ip4(&pcb->remote_ip), &test_oid[5]);
          test_oid[9] = pcb->remote_port;
        }

        /* check generated OID: is it a candidate for the next one? */
        snmp_next_oid_check(&state, test_oid, LWIP_ARRAYSIZE(tcp_ConnTable_oid_ranges), pcb);
      }

      pcb = pcb->next;
    }
  }

  /* did we find a next one? */
  if (state.status == SNMP_NEXT_OID_STATUS_SUCCESS) {
    snmp_oid_assign(row_oid, state.next_oid, state.next_oid_len);
    /* fill in object properties */
    return tcp_ConnTable_get_cell_value_core((struct tcp_pcb*)state.reference, column, value, value_len);
  }

  /* not found */
  return SNMP_ERR_NOSUCHINSTANCE;
}
static snmp_err_t 
udp_endpointTable_get_next_cell_instance_and_value(const u32_t* column, struct snmp_obj_id* row_oid, union snmp_variant_value* value, u32_t* value_len)
{
  struct udp_pcb *pcb;
  struct snmp_next_oid_state state;
  /* 1x udpEndpointLocalAddressType  + 1x OID len + 16x udpEndpointLocalAddress  + 1x udpEndpointLocalPort  +
   * 1x udpEndpointRemoteAddressType + 1x OID len + 16x udpEndpointRemoteAddress + 1x udpEndpointRemotePort +
   * 1x udpEndpointInstance = 39
   */
  u32_t  result_temp[39];

  LWIP_UNUSED_ARG(value_len);

  /* init struct to search next oid */
  snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(result_temp));

  /* iterate over all possible OIDs to find the next one */
  pcb = udp_pcbs;
  while (pcb != NULL) {
    u32_t test_oid[LWIP_ARRAYSIZE(result_temp)];
    u8_t idx = 0;

    /* udpEndpointLocalAddressType + udpEndpointLocalAddress + udpEndpointLocalPort */
    idx += snmp_ip_port_to_oid(&pcb->local_ip, pcb->local_port, &test_oid[idx]);

    /* udpEndpointRemoteAddressType + udpEndpointRemoteAddress + udpEndpointRemotePort */
    idx += snmp_ip_port_to_oid(&pcb->remote_ip, pcb->remote_port, &test_oid[idx]);

    test_oid[idx] = 0; /* udpEndpointInstance */    
    idx++;
    
    /* check generated OID: is it a candidate for the next one? */
    snmp_next_oid_check(&state, test_oid, idx, NULL);
    
    pcb = pcb->next;
  }

  /* did we find a next one? */
  if(state.status == SNMP_NEXT_OID_STATUS_SUCCESS) {
    snmp_oid_assign(row_oid, state.next_oid, state.next_oid_len);
    /* fill in object properties */
    return udp_endpointTable_get_cell_value_core(column, value);
  } else {
    /* not found */
    return SNMP_ERR_NOSUCHINSTANCE;
  }
}
static snmp_err_t
tcp_ConnectionTable_get_next_cell_instance_and_value(const u32_t* column, struct snmp_obj_id* row_oid, union snmp_variant_value* value, u32_t* value_len)
{
  struct tcp_pcb *pcb;
  struct snmp_next_oid_state state;
  /* 1x tcpConnectionLocalAddressType + 1x OID len + 16x tcpConnectionLocalAddress  + 1x tcpConnectionLocalPort
   * 1x tcpConnectionRemAddressType   + 1x OID len + 16x tcpConnectionRemAddress    + 1x tcpConnectionRemPort */
  u32_t  result_temp[38];
  u8_t i;
  struct tcp_pcb ** const tcp_pcb_nonlisten_lists[] = {&tcp_bound_pcbs, &tcp_active_pcbs, &tcp_tw_pcbs};

  LWIP_UNUSED_ARG(value_len);

  /* init struct to search next oid */
  snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(result_temp));

  /* iterate over all possible OIDs to find the next one */
  for (i = 0; i < LWIP_ARRAYSIZE(tcp_pcb_nonlisten_lists); i++) {
    pcb = *tcp_pcb_nonlisten_lists[i];

    while (pcb != NULL) {
      u8_t idx = 0;
      u32_t test_oid[LWIP_ARRAYSIZE(result_temp)];

      /* tcpConnectionLocalAddressType + tcpConnectionLocalAddress + tcpConnectionLocalPort */
      idx += snmp_ip_port_to_oid(&pcb->local_ip, pcb->local_port, &test_oid[idx]);

      /* tcpConnectionRemAddressType + tcpConnectionRemAddress + tcpConnectionRemPort */
      idx += snmp_ip_port_to_oid(&pcb->remote_ip, pcb->remote_port, &test_oid[idx]);

      /* check generated OID: is it a candidate for the next one? */
      snmp_next_oid_check(&state, test_oid, idx, pcb);

      pcb = pcb->next;
    }
  }

  /* did we find a next one? */
  if (state.status == SNMP_NEXT_OID_STATUS_SUCCESS) {
    snmp_oid_assign(row_oid, state.next_oid, state.next_oid_len);
    /* fill in object properties */
    return tcp_ConnectionTable_get_cell_value_core(column, (struct tcp_pcb*)state.reference, value);
  } else {
    /* not found */
    return SNMP_ERR_NOSUCHINSTANCE;
  }
}
static snmp_err_t
ip_NetToMediaTable_get_next_cell_instance_and_value(const u32_t* column, struct snmp_obj_id* row_oid, union snmp_variant_value* value, u32_t* value_len)
{
  u8_t i;
  struct snmp_next_oid_state state;
  u32_t result_temp[LWIP_ARRAYSIZE(ip_NetToMediaTable_oid_ranges)];

  /* init struct to search next oid */
  snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(ip_NetToMediaTable_oid_ranges));

  /* iterate over all possible OIDs to find the next one */
  for (i=0; i<ARP_TABLE_SIZE; i++) {
    ip4_addr_t *ip;
    struct netif *netif;
    struct eth_addr *ethaddr;

    if (etharp_get_entry(i, &ip, &netif, &ethaddr)) {
      u32_t test_oid[LWIP_ARRAYSIZE(ip_NetToMediaTable_oid_ranges)];

      test_oid[0] = netif_to_num(netif);
      snmp_ip4_to_oid(ip, &test_oid[1]);

      /* check generated OID: is it a candidate for the next one? */
      snmp_next_oid_check(&state, test_oid, LWIP_ARRAYSIZE(ip_NetToMediaTable_oid_ranges), (void*)(size_t)i);
    }
  }

  /* did we find a next one? */
  if (state.status == SNMP_NEXT_OID_STATUS_SUCCESS) {
    snmp_oid_assign(row_oid, state.next_oid, state.next_oid_len);
    /* fill in object properties */
    return ip_NetToMediaTable_get_cell_value_core((u8_t)(size_t)state.reference, column, value, value_len);
  }

  /* not found */
  return SNMP_ERR_NOSUCHINSTANCE;
}
static snmp_err_t 
udp_Table_get_next_cell_instance_and_value(const u32_t* column, struct snmp_obj_id* row_oid, union snmp_variant_value* value, u32_t* value_len)
{
  struct udp_pcb *pcb;
  struct snmp_next_oid_state state;
  u32_t  result_temp[LWIP_ARRAYSIZE(udp_Table_oid_ranges)];

  /* init struct to search next oid */
  snmp_next_oid_init(&state, row_oid->id, row_oid->len, result_temp, LWIP_ARRAYSIZE(udp_Table_oid_ranges));

  /* iterate over all possible OIDs to find the next one */
  pcb = udp_pcbs;
  while (pcb != NULL) {
    u32_t test_oid[LWIP_ARRAYSIZE(udp_Table_oid_ranges)];

    if(IP_IS_V4_VAL(pcb->local_ip)) {
      snmp_ip4_to_oid(ip_2_ip4(&pcb->local_ip), &test_oid[0]);
      test_oid[4] = pcb->local_port;

      /* check generated OID: is it a candidate for the next one? */
      snmp_next_oid_check(&state, test_oid, LWIP_ARRAYSIZE(udp_Table_oid_ranges), pcb);
    }
    
    pcb = pcb->next;
  }

  /* did we find a next one? */
  if(state.status == SNMP_NEXT_OID_STATUS_SUCCESS) {
    snmp_oid_assign(row_oid, state.next_oid, state.next_oid_len);
    /* fill in object properties */
    return udp_Table_get_cell_value_core((struct udp_pcb*)state.reference, column, value, value_len);
  } else {
    /* not found */
    return SNMP_ERR_NOSUCHINSTANCE;
  }
}
Exemple #10
0
static void 
snmp_process_varbind(struct snmp_request *request, struct snmp_varbind *vb, u8_t get_next)
{
  err_t err;
  struct snmp_node_instance node_instance;
  memset(&node_instance, 0, sizeof(node_instance));

  if (get_next) {
    struct snmp_obj_id result_oid;
    request->error_status = snmp_get_next_node_instance_from_oid(vb->oid.id, vb->oid.len, snmp_msg_getnext_validate_node_inst, request,  &result_oid, &node_instance);

    if (request->error_status == SNMP_ERR_NOERROR) {
      snmp_oid_assign(&vb->oid, result_oid.id, result_oid.len);
    }
  } else {
    request->error_status = snmp_get_node_instance_from_oid(vb->oid.id, vb->oid.len, &node_instance);

    if (request->error_status == SNMP_ERR_NOERROR) {
      /* use 'getnext_validate' method for validation to avoid code duplication (some checks have to be executed here) */
      request->error_status = snmp_msg_getnext_validate_node_inst(&node_instance, request);

      if (request->error_status != SNMP_ERR_NOERROR) {
        if (node_instance.release_instance != NULL) {
          node_instance.release_instance(&node_instance);
        }
      }
    }
  }

  if (request->error_status != SNMP_ERR_NOERROR)
  {
    if (request->error_status >= SNMP_VARBIND_EXCEPTION_OFFSET) {
      if (request->version == SNMP_VERSION_2c) {
        /* in SNMP v2c a varbind related exception is stored in varbind and not in frame header */
        vb->type = (SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_CLASS_CONTEXT | (request->error_status & SNMP_VARBIND_EXCEPTION_MASK));
        vb->value_len = 0;

        err = snmp_append_outbound_varbind(request, vb);
        if (err == ERR_OK) {
          /* we stored the exception in varbind -> go on */
          request->error_status = SNMP_ERR_NOERROR;
        } else if (err == ERR_BUF) {
          request->error_status = SNMP_ERR_TOOBIG;
        } else {
          request->error_status = SNMP_ERR_GENERROR;
        }
      }
    } else {
      /* according to RFC 1157/1905, all other errors only return genError */
      request->error_status = SNMP_ERR_GENERROR;
    }
  } else {
    vb->type = node_instance.asn1_type;
    vb->value_len = node_instance.get_value(&node_instance, vb->value);
    LWIP_ASSERT("SNMP_MAX_VALUE_SIZE is configured too low", (vb->value_len & ~SNMP_GET_VALUE_RAW_DATA) <= SNMP_MAX_VALUE_SIZE);

    err = snmp_append_outbound_varbind(request, vb);
    if (err == ERR_BUF) {
      request->error_status = SNMP_ERR_TOOBIG;
    } else if (err != ERR_OK) {
      request->error_status = SNMP_ERR_GENERROR;
    }

    if (node_instance.release_instance != NULL) {
      node_instance.release_instance(&node_instance);
    }
  }
}
Exemple #11
0
snmp_err_t snmp_table_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance)
{
  const struct snmp_table_node* table_node = (const struct snmp_table_node*)instance->node;
  const struct snmp_table_col_def* col_def;
  struct snmp_obj_id row_oid;
  u32_t column = 0;
  snmp_err_t result;

  LWIP_UNUSED_ARG(root_oid);
  LWIP_UNUSED_ARG(root_oid_len);

  /* check that first part of id is 0 or 1, referencing fixed row entry */
  if ((instance->instance_oid.len > 0) && (instance->instance_oid.id[0] > 1))
  {
    return SNMP_ERR_NOSUCHINSTANCE;
  }
  if (instance->instance_oid.len > 1)
  {
    column = instance->instance_oid.id[1];
  }
  if (instance->instance_oid.len > 2)
  {
    snmp_oid_assign(&row_oid, &(instance->instance_oid.id[2]), instance->instance_oid.len - 2);
  }
  else
  {
    row_oid.len = 0;
  }

  instance->get_value    = table_node->get_value;
  instance->set_test     = table_node->set_test;
  instance->set_value    = table_node->set_value;

  /* resolve column and value */
  do
  {
    u16_t i;
    const struct snmp_table_col_def* next_col_def = NULL;
    col_def = table_node->columns;

    for (i=0; i<table_node->column_count; i++)
    {
      if (col_def->index == column)
      {
        next_col_def = col_def;
        break;
      }
      else if ((col_def->index > column) && ((next_col_def == NULL) || (col_def->index < next_col_def->index)))
      {
        next_col_def = col_def;
      }
      col_def++;
    }

    if (next_col_def == NULL)
    {
      /* no further column found */
      return SNMP_ERR_NOSUCHINSTANCE;
    }

    instance->asn1_type          = next_col_def->asn1_type;
    instance->access             = next_col_def->access;

    result = table_node->get_next_cell_instance(
      &next_col_def->index,
      &row_oid,
      instance);

    if (result == SNMP_ERR_NOERROR)
    {
      col_def = next_col_def;
      break;
    }

    row_oid.len = 0; /* reset row_oid because we switch to next column and start with the first entry there */
    column = next_col_def->index + 1;
  }
  while (1);

  /* build resulting oid */
  instance->instance_oid.len   = 2;
  instance->instance_oid.id[0] = 1;
  instance->instance_oid.id[1] = col_def->index;
  snmp_oid_append(&instance->instance_oid, row_oid.id, row_oid.len);

  return SNMP_ERR_NOERROR;
}
Exemple #12
0
snmp_err_t snmp_table_simple_get_next_instance(const u32_t *root_oid, u8_t root_oid_len, struct snmp_node_instance* instance)
{
  const struct snmp_table_simple_node* table_node = (const struct snmp_table_simple_node*)instance->node;
  const struct snmp_table_simple_col_def* col_def;
  struct snmp_obj_id row_oid;
  u32_t column = 0;
  snmp_err_t result;

  LWIP_UNUSED_ARG(root_oid);
  LWIP_UNUSED_ARG(root_oid_len);

  /* check that first part of id is 0 or 1, referencing fixed row entry */
  if ((instance->instance_oid.len > 0) && (instance->instance_oid.id[0] > 1))
  {
    return SNMP_ERR_NOSUCHINSTANCE;
  }
  if (instance->instance_oid.len > 1)
  {
    column = instance->instance_oid.id[1];
  }
  if (instance->instance_oid.len > 2)
  {
    snmp_oid_assign(&row_oid, &(instance->instance_oid.id[2]), instance->instance_oid.len - 2);
  }
  else
  {
    row_oid.len = 0;
  }

  /* resolve column and value */
  do
  {
    u32_t i;
    const struct snmp_table_simple_col_def* next_col_def = NULL;
    col_def = table_node->columns;

    for (i=0; i<table_node->column_count; i++)
    {
      if (col_def->index == column)
      {
        next_col_def = col_def;
        break;
      }
      else if ((col_def->index > column) && ((next_col_def == NULL) || (col_def->index < next_col_def->index)))
      {
        next_col_def = col_def;
      }
      col_def++;
    }

    if (next_col_def == NULL)
    {
      /* no further column found */
      return SNMP_ERR_NOSUCHINSTANCE;
    }

    result = table_node->get_next_cell_instance_and_value(
      &next_col_def->index,
      &row_oid,
      &instance->reference,
      &instance->reference_len);

    if (result == SNMP_ERR_NOERROR)
    {
      col_def = next_col_def;
      break;
    }

    row_oid.len = 0; /* reset row_oid because we switch to next column and start with the first entry there */
    column = next_col_def->index + 1;
  }
  while (1);

  instance->asn1_type = col_def->asn1_type;
  instance->access    = SNMP_NODE_INSTANCE_READ_ONLY;
  instance->set_test  = NULL;
  instance->set_value = NULL;

  switch (col_def->data_type)
  {
    case SNMP_VARIANT_VALUE_TYPE_U32: instance->get_value = snmp_table_extract_value_from_u32ref; break;
    case SNMP_VARIANT_VALUE_TYPE_S32: instance->get_value = snmp_table_extract_value_from_s32ref; break;
    case SNMP_VARIANT_VALUE_TYPE_PTR: /* fall through */
    case SNMP_VARIANT_VALUE_TYPE_CONST_PTR: instance->get_value = snmp_table_extract_value_from_refconstptr; break;
    default:
      LWIP_DEBUGF(SNMP_DEBUG, ("snmp_table_simple_get_instance(): unknown column data_type: %d\n", col_def->data_type));
      return SNMP_ERR_GENERROR;
  }

  /* build resulting oid */
  instance->instance_oid.len   = 2;
  instance->instance_oid.id[0] = 1;
  instance->instance_oid.id[1] = col_def->index;
  snmp_oid_append(&instance->instance_oid, row_oid.id, row_oid.len);

  return SNMP_ERR_NOERROR;
}