Commit 2b473c25 authored by Adam Wujek's avatar Adam Wujek 💬

lib/snmp: Add SET to SNMP

Signed-off-by: Adam Wujek's avatarAdam Wujek <adam.wujek@cern.ch>
parent 0591af06
...@@ -141,6 +141,13 @@ config SNMP ...@@ -141,6 +141,13 @@ config SNMP
default y default y
boolean "Mini SNMP responder" boolean "Mini SNMP responder"
config SNMP_SET
depends on SNMP
default y
boolean "Add SET support to the Mini SNMP responder"
help
This option enables support for SET requests for Mini SNMP responder
config SNMP_SYSTEM_NAME config SNMP_SYSTEM_NAME
depends on SNMP depends on SNMP
default "wrc-3.0" default "wrc-3.0"
......
...@@ -47,11 +47,18 @@ ...@@ -47,11 +47,18 @@
#define SNMP_GET 0xA0 #define SNMP_GET 0xA0
#define SNMP_GET_NEXT 0xA1 #define SNMP_GET_NEXT 0xA1
#define SNMP_GET_RESPONSE 0xA2 #define SNMP_GET_RESPONSE 0xA2
#define SNMP_SET 0xA3
#define SNMP_V1 0 #define SNMP_V1 0
#define SNMP_V2c 1 #define SNMP_V2c 1
#define SNMP_V_MAX 1 /* Maximum supported version */ #define SNMP_V_MAX 1 /* Maximum supported version */
#ifdef CONFIG_SNMP_SET
#define SNMP_SET_ENABLED 1
#else
#define SNMP_SET_ENABLED 0
#endif
struct snmp_oid { struct snmp_oid {
uint8_t *oid_match; uint8_t *oid_match;
int (*fill)(uint8_t *buf, struct snmp_oid *obj); int (*fill)(uint8_t *buf, struct snmp_oid *obj);
...@@ -173,6 +180,53 @@ static int fill_int32_saturate_pp(uint8_t *buf, struct snmp_oid *obj) { ...@@ -173,6 +180,53 @@ static int fill_int32_saturate_pp(uint8_t *buf, struct snmp_oid *obj) {
*(void **)obj->p + obj->offset); *(void **)obj->p + obj->offset);
} }
static int set_value(uint8_t *set_buff, struct snmp_oid *obj, void *p)
{
uint8_t asn_incoming = set_buff[0];
uint8_t asn_expected = obj->asn;
uint8_t len = set_buff[1];
uint8_t *oid_data = set_buff + 2;
uint32_t tmp_u32;
if (asn_incoming != asn_expected) { /* wrong asn */
snmp_verbose("%s: wrong asn 0x%02x, expected 0x%02x\n",
__func__, asn_incoming, asn_expected);
return -1;
}
switch(asn_incoming){
case ASN_INTEGER:
tmp_u32 = 0;
memcpy(&tmp_u32, oid_data, len);
tmp_u32 = ntohl(tmp_u32);
/* move data when shorter than 4 bytes */
tmp_u32 = tmp_u32 >> ((4 - len) * 8);
*(uint32_t *)p = tmp_u32;
snmp_verbose("%s: 0x%08x 0x%08x len %d\n", __func__,
*(uint32_t*)p, tmp_u32, len);
break;
case ASN_OCTET_STR: /* TODO: check the string size */
memcpy(p, oid_data, len);
*(char*)(p + len) = '\0';
snmp_verbose("%s: %s len %d\n", __func__, (char*)p, len);
break;
default:
break;
}
return len + 2;
}
static int set_pp(uint8_t *buf, struct snmp_oid *obj)
{
/* calculate pointer, treat obj-> as void ** */
return set_value(buf, obj, *(void **)obj->p + obj->offset);
}
static int set_p(uint8_t *buf, struct snmp_oid *obj)
{
/* calculate pointer, treat obj-> as void * */
return set_value(buf, obj, obj->p + obj->offset);
}
static uint8_t oid_name[] = {0x2B,0x06,0x01,0x02,0x01,0x01,0x05,0x00}; static uint8_t oid_name[] = {0x2B,0x06,0x01,0x02,0x01,0x01,0x05,0x00};
static uint8_t oid_tics[] = {0x2B,0x06,0x01,0x02,0x01,0x19,0x01,0x01,0x00}; static uint8_t oid_tics[] = {0x2B,0x06,0x01,0x02,0x01,0x19,0x01,0x01,0x00};
static uint8_t oid_date[] = {0x2B,0x06,0x01,0x02,0x01,0x19,0x01,0x02,0x00}; static uint8_t oid_date[] = {0x2B,0x06,0x01,0x02,0x01,0x19,0x01,0x02,0x00};
...@@ -244,6 +298,18 @@ static struct snmp_oid oid_array[] = { ...@@ -244,6 +298,18 @@ static struct snmp_oid oid_array[] = {
{ 0, } { 0, }
}; };
static struct snmp_oid oid_array_set[] = {
OID_FIELD_VAR( oid_name, set_p, ASN_OCTET_STR, &snmp_system_name),
OID_FIELD_VAR( oid_wrsPtpMode, set_p, ASN_INTEGER, &ptp_mode),
OID_FIELD_STRUCT(oid_wrsPtpDeltaTxM, set_pp, ASN_INTEGER, struct wr_servo_state, &wr_s_state, delta_tx_m),
OID_FIELD_STRUCT(oid_wrsPtpDeltaRxM, set_pp, ASN_INTEGER, struct wr_servo_state, &wr_s_state, delta_rx_m),
OID_FIELD_STRUCT(oid_wrsPtpDeltaTxS, set_pp, ASN_INTEGER, struct wr_servo_state, &wr_s_state, delta_tx_s),
OID_FIELD_STRUCT(oid_wrsPtpDeltaRxS, set_pp, ASN_INTEGER, struct wr_servo_state, &wr_s_state, delta_rx_s),
{ 0 }
};
/* /*
* Perverse... snmpwalk does getnext anyways. * Perverse... snmpwalk does getnext anyways.
* *
...@@ -347,6 +413,7 @@ static uint8_t snmp_prepare_error(uint8_t *buf, uint8_t error) ...@@ -347,6 +413,7 @@ static uint8_t snmp_prepare_error(uint8_t *buf, uint8_t error)
return ret_size; return ret_size;
} }
/* And, now, work out your generic frame responder... */ /* And, now, work out your generic frame responder... */
static int snmp_respond(uint8_t *buf) static int snmp_respond(uint8_t *buf)
{ {
...@@ -354,8 +421,10 @@ static int snmp_respond(uint8_t *buf) ...@@ -354,8 +421,10 @@ static int snmp_respond(uint8_t *buf)
uint8_t *newbuf; uint8_t *newbuf;
uint8_t *new_oid;; uint8_t *new_oid;;
int i; int i;
uint8_t len; int8_t len;
uint8_t snmp_mode; uint8_t snmp_mode_get = 0;
uint8_t snmp_mode_get_next = 0;
uint8_t snmp_mode_set = 0;
uint8_t incoming_oid_len; uint8_t incoming_oid_len;
int8_t cmp_result; int8_t cmp_result;
for (i = 0; i < sizeof(match_array); i++) { for (i = 0; i < sizeof(match_array); i++) {
...@@ -372,10 +441,16 @@ static int snmp_respond(uint8_t *buf) ...@@ -372,10 +441,16 @@ static int snmp_respond(uint8_t *buf)
SNMP_ERR_GENERR); SNMP_ERR_GENERR);
continue; continue;
case BYTE_PDU: case BYTE_PDU:
if (buf[i] != SNMP_GET && buf[i] != SNMP_GET_NEXT) snmp_mode_get = (SNMP_GET == buf[i]);
snmp_mode_get_next = (SNMP_GET_NEXT == buf[i]);
snmp_mode_set = SNMP_SET_ENABLED &&
(SNMP_SET == buf[i]);
if (!(snmp_mode_get
|| snmp_mode_get_next
|| snmp_mode_set))
return snmp_prepare_error(buf, return snmp_prepare_error(buf,
SNMP_ERR_GENERR); SNMP_ERR_GENERR);
snmp_mode = buf[i];
break; break;
default: default:
if (buf[i] != match_array[i]) if (buf[i] != match_array[i])
...@@ -389,8 +464,13 @@ static int snmp_respond(uint8_t *buf) ...@@ -389,8 +464,13 @@ static int snmp_respond(uint8_t *buf)
new_oid = buf + i; new_oid = buf + i;
/* save size of incoming oid */ /* save size of incoming oid */
incoming_oid_len = buf[i - 1]; incoming_oid_len = buf[i - 1];
for (oid = oid_array; oid->oid_len; oid++) { if (snmp_mode_set) {
if (snmp_mode == SNMP_GET && oid = oid_array_set;
} else {
oid = oid_array;
}
for (; oid->oid_len; oid++) {
if (snmp_mode_get &&
oid->oid_len != incoming_oid_len) { oid->oid_len != incoming_oid_len) {
/* for SNMP_GET, we need equal lengths */ /* for SNMP_GET, we need equal lengths */
continue; continue;
...@@ -398,14 +478,15 @@ static int snmp_respond(uint8_t *buf) ...@@ -398,14 +478,15 @@ static int snmp_respond(uint8_t *buf)
cmp_result = memcmp(oid->oid_match, new_oid, cmp_result = memcmp(oid->oid_match, new_oid,
min(oid->oid_len, incoming_oid_len)); min(oid->oid_len, incoming_oid_len));
if (snmp_mode == SNMP_GET) { if (snmp_mode_get || snmp_mode_set) {
/* we need exact match for SNMP_GET */ /* we need exact match for SNMP_GET */
if (cmp_result == 0) { if (cmp_result == 0) {
snmp_verbose("%s: exact match for GET\n", snmp_verbose("%s: exact match for %s\n",
__func__); __func__,
snmp_mode_set ? "SET" : "GET");
break; break;
} }
} else if (snmp_mode == SNMP_GET_NEXT) { } else if (snmp_mode_get_next) {
if (cmp_result > 0) { /* current OID is after the one if (cmp_result > 0) { /* current OID is after the one
* that is requested, so use it * that is requested, so use it
*/ */
...@@ -433,7 +514,7 @@ static int snmp_respond(uint8_t *buf) ...@@ -433,7 +514,7 @@ static int snmp_respond(uint8_t *buf)
/* also for last GET_NEXT element */ /* also for last GET_NEXT element */
return snmp_prepare_error(buf, SNMP_ERR_NOSUCHNAME); return snmp_prepare_error(buf, SNMP_ERR_NOSUCHNAME);
} }
if (snmp_mode == SNMP_GET_NEXT) { if (snmp_mode_get_next) {
/* copy new OID */ /* copy new OID */
memcpy(new_oid, oid->oid_match, oid->oid_len); memcpy(new_oid, oid->oid_match, oid->oid_len);
/* update OID len, since it might be different */ /* update OID len, since it might be different */
...@@ -444,8 +525,24 @@ static int snmp_respond(uint8_t *buf) ...@@ -444,8 +525,24 @@ static int snmp_respond(uint8_t *buf)
snmp_verbose(" calling %p\n", oid->fill); snmp_verbose(" calling %p\n", oid->fill);
/* Phew.... we matched the OID, so let's call the filler */ /* Phew.... we matched the OID, so let's call the filler */
newbuf += oid->oid_len; newbuf += oid->oid_len;
len = oid->fill(newbuf, oid); if (SNMP_SET_ENABLED && snmp_mode_set) {
newbuf += len; uint8_t community_len;
len = oid->fill(newbuf, oid);
if (len < 0)
return snmp_prepare_error(buf,
SNMP_ERR_BADVALUE);
/* After set, perform get */
community_len = buf[BYTE_COMMUNITY_LEN_i];
/* If community_len is too long, it will return malformed
* packet, but at least something useful for debugging */
community_len = min(community_len, MAX_COMMUNITY_LEN);
buf[BYTE_PDU_i + community_len] = SNMP_GET;
/* recursive call of snmp_respond */
return snmp_respond(buf);
} else {
len = oid->fill(newbuf, oid);
newbuf += len;
}
/* now fix all size fields and change PDU */ /* now fix all size fields and change PDU */
for (i = 0; i < sizeof(match_array); i++) { for (i = 0; i < sizeof(match_array); i++) {
int remain = newbuf - buf - i - 1; int remain = newbuf - buf - i - 1;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment