Tizen 2.1 base
[platform/upstream/hplip.git] / io / hpmud / pml.c
1 /*****************************************************************************\
2
3   pml.c - get/set pml api for hpmud
4
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.
8  
9   (c) 2004-2007 Copyright Hewlett-Packard Development Company, LP
10
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:
17
18   The above copyright notice and this permission notice shall be included in all
19   copies or substantial portions of the Software.
20
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.
27
28 \*****************************************************************************/
29
30 #ifndef _GNU_SOURCE
31 #define _GNU_SOURCE
32 #endif
33
34 #include <stdlib.h>
35 #include <string.h>
36 #include "hpmud.h"
37 #include "hpmudi.h"
38
39 #ifdef HAVE_LIBNETSNMP
40 #ifdef HAVE_UCDSNMP
41 #include <ucd-snmp/ucd-snmp-config.h>
42 #include <ucd-snmp/ucd-snmp-includes.h>
43 #else
44 #include <net-snmp/net-snmp-config.h>
45 #include <net-snmp/net-snmp-includes.h>
46 #endif
47 static const char *SnmpPort[] = { "","public.1","public.2","public.3" };
48 #endif
49
50 static int PmlOidToHex(const char *szoid, unsigned char *oid, int oidSize)
51 {
52    char *tail;
53    int i=0, val;
54
55    if (szoid[0] == 0)
56       goto bugout;
57
58    val = strtol(szoid, &tail, 10);
59
60    while (i < oidSize)
61    {
62       if (val > 128)
63       {
64          BUG("invalid oid size: oid=%s\n", szoid);
65          goto bugout;
66       }
67       oid[i++] = (unsigned char)val;
68
69       if (*tail == 0)
70          break;         /* done */
71
72       val = strtol(tail+1, &tail, 10);
73    }
74
75 bugout:
76    return i;
77 }
78
79 /* Convert ascii snmp oid to pml hex oid. */
80 static int SnmpToPml(const char *snmp_oid, unsigned char *oid, int oidSize)
81 {
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";
85    int len=0;
86
87    if (strncmp(snmp_oid, hp_pml_mib_prefix, sizeof(hp_pml_mib_prefix)-1) == 0)
88    {
89       /* Strip out snmp prefix and convert to hex. */
90       len = 0;
91       len += PmlOidToHex(&snmp_oid[sizeof(hp_pml_mib_prefix)], &oid[0], oidSize);
92       len--; /* remove trailing zero in pml mib */
93    }
94    else if   (strncmp(snmp_oid, standard_printer_mib_prefix, sizeof(standard_printer_mib_prefix)-1) == 0)
95    {
96       /* Replace snmp prefix with 2 and convert to hex. */
97       len = 1;
98       oid[0] = 0x2;
99       len += PmlOidToHex(&snmp_oid[sizeof(standard_printer_mib_prefix)], &oid[1], oidSize);  
100    }
101    else if   (strncmp(snmp_oid, host_resource_mib_prefix, sizeof(host_resource_mib_prefix)-1) == 0)
102    {
103       /* Replace snmp prefix with 3 and convert to hex. */
104       len = 1;
105       oid[0] = 0x3;
106       len += PmlOidToHex(&snmp_oid[sizeof(host_resource_mib_prefix)], &oid[1], oidSize);
107    }
108    else
109       BUG("SnmpToPml failed snmp oid=%s\n", snmp_oid);
110
111    return len;
112 }
113
114 #ifdef HAVE_LIBNETSNMP
115
116 static int SnmpErrorToPml(int snmp_error)
117 {
118    int err;
119
120    switch (snmp_error)
121    {
122       case SNMP_ERR_NOERROR:
123          err = PML_EV_OK;
124          break;
125       case SNMP_ERR_TOOBIG:
126          err = PML_EV_ERROR_BUFFER_OVERFLOW;
127          break;
128       case SNMP_ERR_NOSUCHNAME:
129          err = PML_EV_ERROR_UNKNOWN_OBJECT_IDENTIFIER;
130          break;
131       case SNMP_ERR_BADVALUE:
132          err = PML_EV_ERROR_INVALID_OR_UNSUPPORTED_VALUE;
133          break;
134       case SNMP_ERR_READONLY:
135          err = PML_EV_ERROR_OBJECT_DOES_NOT_SUPPORT_REQUESTED_ACTION;
136          break;
137       case SNMP_ERR_GENERR:
138       default:
139          err = PML_EV_ERROR_UNKNOWN_REQUEST;
140          break;
141    }
142
143    return err;
144 }
145
146 static int SetSnmp(const char *ip, int port, const char *szoid, int type, void *buffer, unsigned int size, int *pml_result, int *result)
147 {
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;
154    uint32_t val;
155
156    *result = HPMUD_R_IO_ERROR;
157    *pml_result = PML_EV_ERROR_UNKNOWN_REQUEST;
158
159    init_snmp("snmpapp");
160
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 */
167    if (ss == NULL)
168       goto bugout;
169
170    pdu = snmp_pdu_create(SNMP_MSG_SET);
171    read_objid(szoid, anOID, &anOID_len);
172
173    switch (type)
174    {
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));
181          break;
182       case PML_DT_REAL:
183       case PML_DT_STRING:
184       case PML_DT_BINARY:
185       case PML_DT_NULL_VALUE:
186       case PML_DT_COLLECTION:
187       default:
188          snmp_pdu_add_variable(pdu, anOID, anOID_len, ASN_OCTET_STR, buffer, size);
189          break;
190    }
191
192   
193    /* Send the request and get response. */
194    if (snmp_synch_response(ss, pdu, &response) != STAT_SUCCESS)
195       goto bugout;
196
197    if (response->errstat == SNMP_ERR_NOERROR) 
198    {
199       len = size;
200    }
201
202    *pml_result = SnmpErrorToPml(response->errstat);
203    *result = HPMUD_R_OK;
204
205 bugout:
206    if (response != NULL)
207       snmp_free_pdu(response);
208    if (ss != NULL)
209       snmp_close(ss);
210    return len;
211 }
212
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)
214 {
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;
222    uint32_t val;
223    unsigned char tmp[sizeof(uint32_t)];
224
225    *result = HPMUD_R_IO_ERROR;
226    *type = PML_DT_NULL_VALUE;
227    *pml_result = PML_EV_ERROR_UNKNOWN_REQUEST;
228
229    init_snmp("snmpapp");
230
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);
236    session.retries = 2;
237    session.timeout = 1000000;         /* 1 second */
238    ss = snmp_open(&session);                     /* establish the session */
239    if (ss == NULL)
240       goto bugout;
241
242    pdu = snmp_pdu_create(SNMP_MSG_GET);
243    read_objid(szoid, anOID, &anOID_len);
244    snmp_add_null_var(pdu, anOID, anOID_len);
245   
246    /* Send the request and get response. */
247    if (snmp_synch_response(ss, pdu, &response) != STAT_SUCCESS)
248       goto bugout;
249
250    if (response->errstat == SNMP_ERR_NOERROR) 
251    {
252       vars = response->variables;
253       switch (vars->type)
254       {
255          case ASN_INTEGER:
256             *type = PML_DT_SIGNED_INTEGER;
257
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;
261             for(i=len; i>0; i--)
262             {
263                tmp[i-1] = val & 0xff;
264                val >>= 8;
265             }
266
267             /* Remove any in-significant bytes. */
268             for (; tmp[i]==0 && i<len; i++)
269                ;
270             len -= i;
271
272             memcpy(buffer, tmp+i, len);
273             break;
274          case ASN_NULL:
275             *type = PML_DT_NULL_VALUE;
276             break;
277          case ASN_OCTET_STR:
278             *type = PML_DT_STRING;
279             len = (vars->val_len < size) ? vars->val_len : size;
280             memcpy(buffer, vars->val.string, len);
281             break;
282          default:
283             BUG("unable to GetSnmp: data type=%d\n", vars->type);
284             goto bugout;
285             break;
286       }
287    }
288
289    *pml_result = SnmpErrorToPml(response->errstat);
290    *result = HPMUD_R_OK;
291
292 bugout:
293    if (response != NULL)
294       snmp_free_pdu(response);
295    if (ss != NULL)
296       snmp_close(ss);
297    return len;
298 }
299
300 #else
301
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)
303 {
304    BUG("no JetDirect support enabled\n");
305    return 0;
306 }
307
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)
309 {
310    BUG("no JetDirect support enabled\n");
311    return 0;
312 }
313
314 #endif /* HAVE_LIBSNMP */
315
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)
318 {
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;
326
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);
328
329    if ((result = hpmud_get_dstat(device, &ds)) != HPMUD_R_OK)
330    {
331       stat = result;
332       goto bugout;
333    }
334
335    if (strcasestr(ds.uri, "net/") != NULL)
336    {
337       /* Process pml via snmp. */
338
339       hpmud_get_uri_datalink(ds.uri, ip, sizeof(ip));
340
341       if ((psz = strstr(ds.uri, "port=")) != NULL)
342          port = strtol(psz+5, &tail, 10);
343       else
344          port = 1;
345
346       SetSnmp(ip, port, snmp_oid, type, data, data_size, &status, &result);
347       if (result != HPMUD_R_OK)
348       {
349          BUG("SetPml failed ret=%d\n", result);
350          stat = result;
351          goto bugout;       
352       }
353    }       
354    else
355    {
356       /* Process pml via local transport. */
357
358       /* Convert snmp ascii oid to pml hex oid. */
359       dLen = SnmpToPml(snmp_oid, oid, sizeof(oid));
360    
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);
365       p+=dLen;
366       *p = type;
367       *p |= data_size >> 8;                   /* assume data length is 10 bits */
368       *(p+1) = data_size & 0xff;    
369       p += 2; 
370       memcpy(p, data, data_size);
371
372       result = hpmud_write_channel(device, channel, message, dLen+data_size+3+2, HPMUD_EXCEPTION_SEC_TIMEOUT, &len);  
373       if (result != HPMUD_R_OK)
374       {
375          BUG("SetPml channel_write failed ret=%d\n", result);
376          stat = result;
377          goto bugout;       
378       }    
379
380       result = hpmud_read_channel(device, channel, message, sizeof(message), HPMUD_EXCEPTION_SEC_TIMEOUT, &len);
381       if (result != HPMUD_R_OK || len == 0)
382       {
383          BUG("SetPml channel_read failed ret=%d len=%d\n", result, len);
384          goto bugout;       
385       }    
386
387       p = message;
388       reply = *p++;       /* read command reply */
389       status = *p++;      /* read execution outcome */
390
391       if (reply != (PML_SET_REQUEST | 0x80) && status & 0x80)
392       {
393          BUG("SetPml failed reply=%x outcome=%x\n", reply, status);
394          DBG_DUMP(p, len-2);
395          goto bugout;       
396       }   
397    }
398    
399    *pml_result = status;
400    stat = HPMUD_R_OK;
401
402    DBG("set_pml result pmlresult=%x\n", status);
403
404 bugout:
405    return stat;
406 }
407
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)
410 {
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;
418
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);
420
421    if ((result = hpmud_get_dstat(device, &ds)) != HPMUD_R_OK)
422    {
423       stat = result;
424       goto bugout;
425    }
426
427    if (strcasestr(ds.uri, "net/") != NULL)
428    {
429       /* Process pml via snmp. */
430
431       hpmud_get_uri_datalink(ds.uri, ip, sizeof(ip));
432
433       if ((psz = strstr(ds.uri, "port=")) != NULL)
434          port = strtol(psz+5, &tail, 10);
435       else
436          port = 1;
437
438       dLen = GetSnmp(ip, port, snmp_oid, message, sizeof(message), &dt, &status, &result);
439       if (result != HPMUD_R_OK)
440       {
441          BUG("GetPml failed ret=%d\n", result);
442          stat = result;
443          goto bugout;       
444       }
445       p = message;    
446    }       
447    else
448    {
449       /* Process pml via local transport. */
450
451       /* Convert snmp ascii oid to pml hex oid. */
452       dLen = SnmpToPml(snmp_oid, oid, sizeof(oid));
453    
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)
460       {
461          BUG("GetPml channel_write failed ret=%d\n", result);
462          stat = result;
463          goto bugout;       
464       }    
465
466       result = hpmud_read_channel(device, channel, message, sizeof(message), HPMUD_EXCEPTION_SEC_TIMEOUT, &len);
467       if (result != HPMUD_R_OK || len == 0)
468       {
469          BUG("GetPml channel_read failed ret=%d len=%d\n", result, len);
470          goto bugout;       
471       }    
472
473       p = message;
474       reply = *p++;       /* read command reply */
475       status = *p++;      /* read execution outcome */
476
477       if (reply != (PML_GET_REQUEST | 0x80) && status & 0x80)
478       {
479          BUG("GetPml failed reply=%x outcome=%x\n", reply, status);
480          DBG_DUMP(p, len-2);
481          goto bugout;       
482       }   
483
484       dt = *p++;       /* read data type */
485
486       if (dt == PML_DT_ERROR_CODE)
487       {
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 */
491       } 
492
493       if (dt != PML_DT_OBJECT_IDENTIFIER)
494       {
495          BUG("GetPml failed data type=%x\n", dt);
496          goto bugout;       
497       }   
498
499       dLen = *p++;     /* read oid length */
500       p += dLen;       /* eat oid */
501
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 */
505    }
506    
507    memcpy(buf, p, dLen);
508    *bytes_read = dLen; 
509    *type = dt;
510    *pml_result = status;
511    stat = HPMUD_R_OK;
512
513    DBG("get_pml result len=%d datatype=%x pmlresult=%x\n", dLen, dt, status);
514    DBG_DUMP(buf, dLen);
515
516 bugout:
517    return stat;
518 }
519
520