1
/*****************************************************************************\
3
pml.c - get/set pml api for hpmud
5
The get/set pml commands are a high level interface to hpmud. This hpmud system
6
interface sits on top of the hpmud core interface. The system interface does
7
not use the hpmud memory map file system.
9
(c) 2004-2007 Copyright Hewlett-Packard Development Company, LP
11
Permission is hereby granted, free of charge, to any person obtaining a copy
12
of this software and associated documentation files (the "Software"), to deal
13
in the Software without restriction, including without limitation the rights
14
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
15
of the Software, and to permit persons to whom the Software is furnished to do
16
so, subject to the following conditions:
18
The above copyright notice and this permission notice shall be included in all
19
copies or substantial portions of the Software.
21
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
23
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
24
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
25
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28
\*****************************************************************************/
39
#ifdef HAVE_LIBNETSNMP
41
#include <ucd-snmp/ucd-snmp-config.h>
42
#include <ucd-snmp/ucd-snmp-includes.h>
44
#include <net-snmp/net-snmp-config.h>
45
#include <net-snmp/net-snmp-includes.h>
47
static const char *SnmpPort[] = { "","public.1","public.2","public.3" };
50
static int PmlOidToHex(const char *szoid, unsigned char *oid, int oidSize)
58
val = strtol(szoid, &tail, 10);
64
BUG("invalid oid size: oid=%s\n", szoid);
67
oid[i++] = (unsigned char)val;
72
val = strtol(tail+1, &tail, 10);
79
/* Convert ascii snmp oid to pml hex oid. */
80
static int SnmpToPml(const char *snmp_oid, unsigned char *oid, int oidSize)
82
static const char hp_pml_mib_prefix[] = "1.3.6.1.4.1.11.2.3.9.4.2";
83
static const char standard_printer_mib_prefix[] = "1.3.6.1.2.1.43";
84
static const char host_resource_mib_prefix[] = "1.3.6.1.2.1.25";
87
if (strncmp(snmp_oid, hp_pml_mib_prefix, sizeof(hp_pml_mib_prefix)-1) == 0)
89
/* Strip out snmp prefix and convert to hex. */
91
len += PmlOidToHex(&snmp_oid[sizeof(hp_pml_mib_prefix)], &oid[0], oidSize);
92
len--; /* remove trailing zero in pml mib */
94
else if (strncmp(snmp_oid, standard_printer_mib_prefix, sizeof(standard_printer_mib_prefix)-1) == 0)
96
/* Replace snmp prefix with 2 and convert to hex. */
99
len += PmlOidToHex(&snmp_oid[sizeof(standard_printer_mib_prefix)], &oid[1], oidSize);
101
else if (strncmp(snmp_oid, host_resource_mib_prefix, sizeof(host_resource_mib_prefix)-1) == 0)
103
/* Replace snmp prefix with 3 and convert to hex. */
106
len += PmlOidToHex(&snmp_oid[sizeof(host_resource_mib_prefix)], &oid[1], oidSize);
109
BUG("SnmpToPml failed snmp oid=%s\n", snmp_oid);
114
#ifdef HAVE_LIBNETSNMP
116
static int SnmpErrorToPml(int snmp_error)
122
case SNMP_ERR_NOERROR:
125
case SNMP_ERR_TOOBIG:
126
err = PML_EV_ERROR_BUFFER_OVERFLOW;
128
case SNMP_ERR_NOSUCHNAME:
129
err = PML_EV_ERROR_UNKNOWN_OBJECT_IDENTIFIER;
131
case SNMP_ERR_BADVALUE:
132
err = PML_EV_ERROR_INVALID_OR_UNSUPPORTED_VALUE;
134
case SNMP_ERR_READONLY:
135
err = PML_EV_ERROR_OBJECT_DOES_NOT_SUPPORT_REQUESTED_ACTION;
137
case SNMP_ERR_GENERR:
139
err = PML_EV_ERROR_UNKNOWN_REQUEST;
146
static int SetSnmp(const char *ip, int port, const char *szoid, int type, void *buffer, unsigned int size, int *pml_result, int *result)
148
struct snmp_session session, *ss=NULL;
149
struct snmp_pdu *pdu=NULL;
150
struct snmp_pdu *response=NULL;
151
oid anOID[MAX_OID_LEN];
152
size_t anOID_len = MAX_OID_LEN;
153
unsigned int i, len=0;
156
*result = HPMUD_R_IO_ERROR;
157
*pml_result = PML_EV_ERROR_UNKNOWN_REQUEST;
159
init_snmp("snmpapp");
161
snmp_sess_init(&session ); /* set up defaults */
162
session.peername = (char *)ip;
163
session.version = SNMP_VERSION_1;
164
session.community = (unsigned char *)SnmpPort[port];
165
session.community_len = strlen((const char *)session.community);
166
ss = snmp_open(&session); /* establish the session */
170
pdu = snmp_pdu_create(SNMP_MSG_SET);
171
read_objid(szoid, anOID, &anOID_len);
175
case PML_DT_ENUMERATION:
176
case PML_DT_SIGNED_INTEGER:
177
/* Convert PML big-endian to SNMP little-endian byte stream. */
178
for(i=0, val=0; i<size && i<sizeof(val); i++)
179
val = ((val << 8) | ((unsigned char *)buffer)[i]);
180
snmp_pdu_add_variable(pdu, anOID, anOID_len, ASN_INTEGER, (unsigned char *)&val, sizeof(val));
185
case PML_DT_NULL_VALUE:
186
case PML_DT_COLLECTION:
188
snmp_pdu_add_variable(pdu, anOID, anOID_len, ASN_OCTET_STR, buffer, size);
193
/* Send the request and get response. */
194
if (snmp_synch_response(ss, pdu, &response) != STAT_SUCCESS)
197
if (response->errstat == SNMP_ERR_NOERROR)
202
*pml_result = SnmpErrorToPml(response->errstat);
203
*result = HPMUD_R_OK;
206
if (response != NULL)
207
snmp_free_pdu(response);
213
int __attribute__ ((visibility ("hidden"))) GetSnmp(const char *ip, int port, const char *szoid, void *buffer, unsigned int size, int *type, int *pml_result, int *result)
215
struct snmp_session session, *ss=NULL;
216
struct snmp_pdu *pdu=NULL;
217
struct snmp_pdu *response=NULL;
218
unsigned int i, len=0;
219
oid anOID[MAX_OID_LEN];
220
size_t anOID_len = MAX_OID_LEN;
221
struct variable_list *vars;
223
unsigned char tmp[sizeof(uint32_t)];
225
*result = HPMUD_R_IO_ERROR;
226
*type = PML_DT_NULL_VALUE;
227
*pml_result = PML_EV_ERROR_UNKNOWN_REQUEST;
229
init_snmp("snmpapp");
231
snmp_sess_init(&session ); /* set up defaults */
232
session.peername = (char *)ip;
233
session.version = SNMP_VERSION_1;
234
session.community = (unsigned char *)SnmpPort[port];
235
session.community_len = strlen((const char *)session.community);
237
session.timeout = 1000000; /* 1 second */
238
ss = snmp_open(&session); /* establish the session */
242
pdu = snmp_pdu_create(SNMP_MSG_GET);
243
read_objid(szoid, anOID, &anOID_len);
244
snmp_add_null_var(pdu, anOID, anOID_len);
246
/* Send the request and get response. */
247
if (snmp_synch_response(ss, pdu, &response) != STAT_SUCCESS)
250
if (response->errstat == SNMP_ERR_NOERROR)
252
vars = response->variables;
256
*type = PML_DT_SIGNED_INTEGER;
258
/* Convert SNMP little-endian to PML big-endian byte stream. */
259
len = (sizeof(uint32_t) < size) ? sizeof(uint32_t) : size;
260
val = *vars->val.integer;
263
tmp[i-1] = val & 0xff;
267
/* Remove any in-significant bytes. */
268
for (; tmp[i]==0 && i<len; i++)
272
memcpy(buffer, tmp+i, len);
275
*type = PML_DT_NULL_VALUE;
278
*type = PML_DT_STRING;
279
len = (vars->val_len < size) ? vars->val_len : size;
280
memcpy(buffer, vars->val.string, len);
283
BUG("unable to GetSnmp: data type=%d\n", vars->type);
289
*pml_result = SnmpErrorToPml(response->errstat);
290
*result = HPMUD_R_OK;
293
if (response != NULL)
294
snmp_free_pdu(response);
302
int __attribute__ ((visibility ("hidden"))) SetSnmp(const char *ip, int port, const char *szoid, int type, void *buffer, unsigned int size, int *pml_result, int *result)
304
BUG("no JetDirect support enabled\n");
308
int __attribute__ ((visibility ("hidden"))) GetSnmp(const char *ip, int port, const char *szoid, void *buffer, unsigned int size, int *type, int *pml_result, int *result)
310
BUG("no JetDirect support enabled\n");
314
#endif /* HAVE_LIBSNMP */
316
/* Set a PML object in the hp device. */
317
enum HPMUD_RESULT hpmud_set_pml(HPMUD_DEVICE device, HPMUD_CHANNEL channel, const char *snmp_oid, int type, void *data, int data_size, int *pml_result)
319
unsigned char message[HPMUD_BUFFER_SIZE];
320
unsigned char oid[HPMUD_LINE_SIZE];
321
char ip[HPMUD_LINE_SIZE], *psz, *tail;
322
unsigned char *p=message;
323
int len, dLen, result, reply, status, port;
324
struct hpmud_dstat ds;
325
enum HPMUD_RESULT stat = HPMUD_R_IO_ERROR;
327
DBG("[%d] hpmud_set_pml() dd=%d cd=%d oid=%s type=%d data=%p size=%d\n", getpid(), device, channel, snmp_oid, type, data, data_size);
329
if ((result = hpmud_get_dstat(device, &ds)) != HPMUD_R_OK)
335
if (strcasestr(ds.uri, "net/") != NULL)
337
/* Process pml via snmp. */
339
hpmud_get_uri_datalink(ds.uri, ip, sizeof(ip));
341
if ((psz = strstr(ds.uri, "port=")) != NULL)
342
port = strtol(psz+5, &tail, 10);
346
SetSnmp(ip, port, snmp_oid, type, data, data_size, &status, &result);
347
if (result != HPMUD_R_OK)
349
BUG("SetPml failed ret=%d\n", result);
356
/* Process pml via local transport. */
358
/* Convert snmp ascii oid to pml hex oid. */
359
dLen = SnmpToPml(snmp_oid, oid, sizeof(oid));
361
*p++ = PML_SET_REQUEST;
362
*p++ = PML_DT_OBJECT_IDENTIFIER;
363
*p++ = dLen; /* assume oid length is < 10 bits */
364
memcpy(p, oid, dLen);
367
*p |= data_size >> 8; /* assume data length is 10 bits */
368
*(p+1) = data_size & 0xff;
370
memcpy(p, data, data_size);
372
result = hpmud_write_channel(device, channel, message, dLen+data_size+3+2, HPMUD_EXCEPTION_SEC_TIMEOUT, &len);
373
if (result != HPMUD_R_OK)
375
BUG("SetPml channel_write failed ret=%d\n", result);
380
result = hpmud_read_channel(device, channel, message, sizeof(message), HPMUD_EXCEPTION_SEC_TIMEOUT, &len);
381
if (result != HPMUD_R_OK || len == 0)
383
BUG("SetPml channel_read failed ret=%d len=%d\n", result, len);
388
reply = *p++; /* read command reply */
389
status = *p++; /* read execution outcome */
391
if (reply != (PML_SET_REQUEST | 0x80) && status & 0x80)
393
BUG("SetPml failed reply=%x outcome=%x\n", reply, status);
399
*pml_result = status;
402
DBG("set_pml result pmlresult=%x\n", status);
408
/* Get a PML object from the hp device. */
409
enum HPMUD_RESULT hpmud_get_pml(HPMUD_DEVICE device, HPMUD_CHANNEL channel, const char *snmp_oid, void *buf, int buf_size, int *bytes_read, int *type, int *pml_result)
411
unsigned char message[HPMUD_BUFFER_SIZE];
412
unsigned char oid[HPMUD_LINE_SIZE];
413
char ip[HPMUD_LINE_SIZE], *psz, *tail;
414
unsigned char *p=message;
415
int len, dLen, result, reply, status, dt, port;
416
struct hpmud_dstat ds;
417
enum HPMUD_RESULT stat = HPMUD_R_IO_ERROR;
419
DBG("[%d] hpmud_get_pml() dd=%d cd=%d oid=%s data=%p size=%d\n", getpid(), device, channel, snmp_oid, buf, buf_size);
421
if ((result = hpmud_get_dstat(device, &ds)) != HPMUD_R_OK)
427
if (strcasestr(ds.uri, "net/") != NULL)
429
/* Process pml via snmp. */
431
hpmud_get_uri_datalink(ds.uri, ip, sizeof(ip));
433
if ((psz = strstr(ds.uri, "port=")) != NULL)
434
port = strtol(psz+5, &tail, 10);
438
dLen = GetSnmp(ip, port, snmp_oid, message, sizeof(message), &dt, &status, &result);
439
if (result != HPMUD_R_OK)
441
BUG("GetPml failed ret=%d\n", result);
449
/* Process pml via local transport. */
451
/* Convert snmp ascii oid to pml hex oid. */
452
dLen = SnmpToPml(snmp_oid, oid, sizeof(oid));
454
*p++ = PML_GET_REQUEST;
455
*p++ = PML_DT_OBJECT_IDENTIFIER;
456
*p++ = dLen; /* assume oid length is < 10 bits */
457
memcpy(p, oid, dLen);
458
result = hpmud_write_channel(device, channel, message, dLen+3, HPMUD_EXCEPTION_SEC_TIMEOUT, &len);
459
if (result != HPMUD_R_OK)
461
BUG("GetPml channel_write failed ret=%d\n", result);
466
result = hpmud_read_channel(device, channel, message, sizeof(message), HPMUD_EXCEPTION_SEC_TIMEOUT, &len);
467
if (result != HPMUD_R_OK || len == 0)
469
BUG("GetPml channel_read failed ret=%d len=%d\n", result, len);
474
reply = *p++; /* read command reply */
475
status = *p++; /* read execution outcome */
477
if (reply != (PML_GET_REQUEST | 0x80) && status & 0x80)
479
BUG("GetPml failed reply=%x outcome=%x\n", reply, status);
484
dt = *p++; /* read data type */
486
if (dt == PML_DT_ERROR_CODE)
488
/* Ok, but invalid data type requested, get new data type. */
489
p += 2; /* eat length and err code */
490
dt = *p++; /* read data type */
493
if (dt != PML_DT_OBJECT_IDENTIFIER)
495
BUG("GetPml failed data type=%x\n", dt);
499
dLen = *p++; /* read oid length */
500
p += dLen; /* eat oid */
502
dt = *p; /* read data type. */
503
dLen = ((*p & 0x3) << 8 | *(p+1)); /* read 10 bit len from 2 byte field */
504
p += 2; /* eat type and length */
507
memcpy(buf, p, dLen);
510
*pml_result = status;
513
DBG("get_pml result len=%d datatype=%x pmlresult=%x\n", dLen, dt, status);