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);