1 /*
2  * Copyright (c) 2001 Tommy Bohlin <tommy@gatespace.com>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 /* iassrv.c
27  *
28  * Limitations:
29  *  - Only GetValueByClass supported
30  */
31 
32 #include <irda.h>
33 #include <ias.h>
34 
35 #include <string.h>
36 
37 /**********************************************************************
38  * Constants
39  **********************************************************************/
40 
41 static const char id_server[]="ias server";
42 static const char id_object[]="ias object";
43 static const char id_attribute[]="ias attribute";
44 static const char id_connection[]="ias server connection";
45 static const char id_inbuf[]="ias server inbuf";
46 static const char id_outbuf[]="ias server outbuf";
47 
48 #define IrLMP_VERSION            0x01
49 #define IAS_SUPPORT              0x00
50 #define LM_MUX_SUPPORT           0x00
51 
52 static const u_char irLMPSupport[] = { IrLMP_VERSION, IAS_SUPPORT, LM_MUX_SUPPORT };
53 
54 /**********************************************************************
55  * Data structures
56  **********************************************************************/
57 
58 typedef struct String {
59   int length;
60   char chars[60];  /* Longest class and attribute names according to spec */
61 } String;
62 
63 typedef struct AttributePrivate {
64   Attribute attr;
65   struct AttributePrivate* next;
66   struct AttributePrivate* selnext;
67   struct ObjectPrivate* obj;
68   String name;
69   int type;
70   union {
71     int i;
72     struct {
73       u_short length;
74       u_char charset;
75       u_char bytes[1];
76     } s;
77   } value;
78 } AttributePrivate;
79 
80 typedef struct ObjectPrivate {
81   Object object;
82   struct ObjectPrivate* next;
83   struct IASServerPrivate* ias;
84   u_short id;
85   String class;
86   AttributePrivate* attrs;
87 } ObjectPrivate;
88 
89 typedef struct IASServerPrivate {
90   IASServer ias;
91   LSAP* lsap;
92   ObjectPrivate* objects;
93   struct IASConnection* connections;
94 } IASServerPrivate;
95 
96 typedef struct IASConnection {
97   struct IASConnection* next;
98   IASServerPrivate* ias;
99 
100   int op;
101 
102   int outOfs;
103   int outLength;
104   int outMax;
105   u_char* outBuf;
106 
107   int inLength;
108   int inMax;
109   u_char* inBuf;
110 } IASConnection;
111 
112 /**********************************************************************
113  * Internal functions
114  **********************************************************************/
115 
cmpString(String * s1,String * s2)116 static int cmpString(String* s1, String* s2)
117 {
118   int d=s1->length-s2->length;
119   int len=d<0 ? s1->length : s2->length;
120   return memcmp(s1->chars,s2->chars,len) || d;
121 }
122 
getString(String * s,u_char * buf,int * ip,int len)123 static int getString(String* s, u_char* buf, int* ip, int len)
124 {
125   int i=*ip;
126 
127   if(i>=len) return 0;
128   s->length=buf[i++];
129   if(i+s->length>len) return 0;
130   if(s->length>sizeof s->chars) return 0;
131   memcpy(s->chars,buf+i,len);
132   i+=s->length;
133   *ip=i;
134   return 1;
135 }
136 
sendACK(Connection * con,int op)137 static void sendACK(Connection* con, int op)
138 {
139   u_char hdr[1];
140 
141   hdr[0]=op|IAS_ACK|IAS_LAST;
142   connWrite(con,hdr,1);
143 }
144 
sendUnsupported(Connection * con,int op)145 static void sendUnsupported(Connection* con, int op)
146 {
147   u_char hdr[2];
148 
149   hdr[0]=op|IAS_LAST;
150   hdr[1]=IAS_UNSUPPORTED;
151   connWrite(con,hdr,2);
152 }
153 
reserveReply(IASConnection * iasc,int n)154 static u_char* reserveReply(IASConnection* iasc, int n)
155 {
156   u_char* p;
157 
158   while(iasc->outLength+n>iasc->outMax) {
159     iasc->outMax*=2;
160     iasc->outBuf=growMem(iasc->outBuf,iasc->outMax);
161   }
162   p=iasc->outBuf+iasc->outLength;
163   iasc->outLength+=n;
164   return p;
165 }
166 
getValueByClass(IASConnection * ic,u_char * buf,int len)167 static void getValueByClass(IASConnection* ic, u_char* buf, int len)
168 {
169   String class;
170   String attr;
171   int i;
172   bool classFound=FALSE;
173   int nFound=0;
174   AttributePrivate* selected=0;
175   ObjectPrivate* op;
176   AttributePrivate* ap;
177 
178   /* Dissect arguments */
179   i=0;
180   if(!getString(&class,buf,&i,len)) {
181     *reserveReply(ic,1)=IAS_NO_CLASS;
182     return;
183   }
184   if(!getString(&attr,buf,&i,len)) {
185     *reserveReply(ic,1)=IAS_NO_ATTR;
186     return;
187   }
188 
189   /* Filter out reply set */
190   if(ic->ias) {
191     for(op=ic->ias->objects;op;op=op->next) {
192       if(cmpString(&class,&op->class)) continue;
193       classFound=TRUE;
194       for(ap=op->attrs;ap;ap=ap->next) {
195 	if(cmpString(&attr,&ap->name)) continue;
196 	ap->selnext=selected;
197 	selected=ap;
198 	nFound++;
199       }
200     }
201   }
202 
203   if(ic->ias->ias.debug&IAS_DEBUG_INFO)
204     birda_log("GetValueByClass %.*s %.*s\n",class.length,class.chars,attr.length,attr.chars);
205 
206   /* Format reply */
207 
208   if(nFound) {
209     *reserveReply(ic,1)=IAS_SUCCESS;
210     putBEShort(reserveReply(ic,2),nFound);
211 
212     for(ap=selected;ap;ap=ap->selnext) {
213       putBEShort(reserveReply(ic,2),ap->obj->id);
214       *reserveReply(ic,1)=ap->type;
215       if(ic->ias->ias.debug&IAS_DEBUG_INFO) birda_log(" -> %d ",ap->obj->id);
216       usleep(50000);		/* XXX LA: this seems to improve ircomm */
217       switch(ap->type) {
218       case IAS_INTEGER:
219 	putBELong(reserveReply(ic,4),ap->value.i);
220 	if(ic->ias->ias.debug&IAS_DEBUG_INFO) birda_log("%d\n",ap->value.i);
221 	break;
222       case IAS_OCTETS:
223 	i=ap->value.s.length;
224 	putBEShort(reserveReply(ic,2),i);
225 	memcpy(reserveReply(ic,i),ap->value.s.bytes,i);
226 	showBytes(ap->value.s.bytes,i);
227 	if(ic->ias->ias.debug&IAS_DEBUG_INFO) birda_log("\n");
228 	break;
229       case IAS_STRING:
230 	i=ap->value.s.length;
231 	*reserveReply(ic,1)=ap->value.s.charset;
232 	*reserveReply(ic,1)=i;
233 	memcpy(reserveReply(ic,i),ap->value.s.bytes,i);
234 	if(ic->ias->ias.debug&IAS_DEBUG_INFO) birda_log("%.*s\n",i,ap->value.s.bytes);
235 	break;
236       default:
237 	if(ic->ias->ias.debug&IAS_DEBUG_INFO) birda_log("[missing]\n");
238 	break;
239       }
240     }
241   } else {
242     *reserveReply(ic,1)=classFound ? IAS_NO_ATTR : IAS_NO_CLASS;
243   }
244 }
245 
sendChunk(Connection * con,IASConnection * iasc)246 static void sendChunk(Connection* con, IASConnection* iasc)
247 {
248   int n=iasc->outLength-iasc->outOfs;
249   int k=connGetSendDataSize(con)-1;
250   u_char hdr[1];
251 
252   if(k>n) k=n;
253   hdr[0]=iasc->op;
254   if(k==n) hdr[0]|=IAS_LAST;
255   connWrite2(con,hdr,1,iasc->outBuf,k);
256   iasc->outOfs+=k;
257 }
258 
makeAttribute(Object * obj,const char * name,int extra)259 static AttributePrivate* makeAttribute(Object* obj, const char* name, int extra)
260 {
261   ObjectPrivate* objp=(ObjectPrivate*)obj;
262   AttributePrivate* attr;
263   int len=strlen(name);
264 
265   if(len>sizeof attr->name.chars) return 0;
266   for(attr=objp->attrs;attr;attr=attr->next) {
267     if(attr->name.length==len &&
268        !memcmp(attr->name.chars,name,len)) return 0;
269   }
270 
271   attr=allocMem(id_attribute,sizeof(AttributePrivate)+extra);
272   attr->obj=objp;
273   attr->name.length=len;
274   memcpy(attr->name.chars,name,len);
275 
276   attr->next=objp->attrs;
277   objp->attrs=attr;
278 
279   return attr;
280 }
281 
status(Connection * con,int event,void * buf,int len)282 static void status(Connection* con, int event, void* buf, int len)
283 {
284   int flags;
285   IASConnection* ic=(IASConnection*)con->handle;
286 
287   if(event==CONN_CLOSED) {
288     if(ic->ias) {
289       IASConnection** ih=&ic->ias->connections;
290       IASConnection* i;
291 
292       while((i=*ih)) {
293 	if(i==ic) {
294 	  *ih=i->next;
295 	  break;
296 	} else {
297 	  ih=&i->next;
298 	}
299       }
300     }
301 
302     if(ic->outBuf) freeMem(ic->outBuf);
303     if(ic->inBuf) freeMem(ic->inBuf);
304     flags = ic->ias->ias.debug&IAS_DEBUG_INFO;
305     freeMem(ic);
306     connClose(con);
307     if(flags) birda_log("ias closed\n");
308   }
309 }
310 
data(Connection * con,void * buf0,int len)311 static void data(Connection* con, void* buf0, int len)
312 {
313   u_char* buf=(u_char*)buf0;
314   IASConnection* iasc=(IASConnection*)con->handle;
315   u_char op;
316 
317   /* Just ignore null input, OK? */
318   if(len<1) return;
319 
320   op=buf[0]&~(IAS_LAST|IAS_ACK);
321   if(op!=iasc->op) {
322     iasc->op=op;
323     iasc->outLength=0;
324     iasc->inLength=0;
325   }
326 
327   if(buf[0]&IAS_ACK) {
328     if(iasc->outOfs<iasc->outLength) sendChunk(con,iasc);
329   } else {
330     iasc->outOfs=0;
331     iasc->outLength=0;
332 
333     while(iasc->inMax<iasc->inLength+len-1) {
334       iasc->inMax*=2;
335       iasc->inBuf=growMem(iasc->inBuf,iasc->inMax);
336     }
337 
338     memcpy(iasc->inBuf+iasc->inLength,buf+1,len-1);
339     iasc->inLength+=len-1;
340 
341     if(buf[0]&IAS_LAST) {
342       switch(op) {
343       case OP_GetValueByClass:
344 	getValueByClass(iasc,buf+1,len-1);
345 	sendChunk(con,iasc);
346 	break;
347       default:
348 	birda_log("opcode %x not supported\n",op);
349 	sendUnsupported(con,op);
350 	break;
351       }
352       iasc->inLength=0;
353     } else {
354       sendACK(con,op);
355     }
356   }
357 }
358 
accept(LSAP * lsap,Connection * con,void * buf0,int len)359 static bool accept(LSAP* lsap, Connection* con, void* buf0, int len)
360 {
361   IASConnection* iasc=allocMem(id_connection,sizeof(IASConnection));
362   IASServerPrivate* iasp=(IASServerPrivate*)lsap->handle;
363 
364   iasc->ias=iasp;
365   iasc->inLength=0;
366   iasc->inMax=256;
367   iasc->inBuf=allocMem(id_inbuf,iasc->inMax);
368   iasc->outOfs=0;
369   iasc->outLength=0;
370   iasc->outMax=256;
371   iasc->outBuf=allocMem(id_outbuf,iasc->outMax);
372 
373   iasc->next=iasp->connections;
374   iasp->connections=iasc;
375 
376   con->handle=iasc;
377   con->status=status;
378   con->data=data;
379 
380   if(iasc->ias->ias.debug&IAS_DEBUG_INFO) birda_log("ias accept\n");
381   return TRUE;
382 }
383 
384 /**********************************************************************
385  * External functions
386  **********************************************************************/
387 
iasAttrDelete(Attribute * attr)388 void iasAttrDelete(Attribute* attr)
389 {
390   AttributePrivate* attrp=(AttributePrivate*)attr;
391   AttributePrivate** ah=&attrp->obj->attrs;
392   AttributePrivate* a;
393 
394   while((a=*ah)) {
395     if(a==attrp) {
396       *ah=a->next;
397       break;
398     } else {
399       ah=&a->next;
400     }
401   }
402 
403   freeMem(attrp);
404 }
405 
iasObjNewInteger(Object * obj,const char * name,int value)406 Attribute* iasObjNewInteger(Object* obj, const char* name, int value)
407 {
408   AttributePrivate* attr=makeAttribute(obj,name,0);
409 
410   if(attr) {
411     attr->type=IAS_INTEGER;
412     attr->value.i=value;
413   }
414   return &attr->attr;
415 }
416 
iasObjNewString(Object * obj,const char * name,int charset,const char * value,int length)417 Attribute* iasObjNewString(Object* obj, const char* name, int charset, const char* value, int length)
418 {
419   AttributePrivate* attr;
420 
421   if(length<0 || length>255) return 0;
422   attr=makeAttribute(obj,name,length);
423   if(attr) {
424     attr->type=IAS_STRING;
425     attr->value.s.charset=charset;
426     attr->value.s.length=length;
427     memcpy(attr->value.s.bytes,value,length);
428   }
429   return &attr->attr;
430 }
431 
iasObjNewOctets(Object * obj,const char * name,const void * value0,int length)432 Attribute* iasObjNewOctets(Object* obj, const char* name, const void* value0, int length)
433 {
434   u_char* value=(u_char*)value0;
435   AttributePrivate* attr;
436 
437   if(length<0 || length>1024) return 0;
438   attr=makeAttribute(obj,name,length);
439   if(attr) {
440     attr->type=IAS_OCTETS;
441     attr->value.s.length=length;
442     memcpy(attr->value.s.bytes,value,length);
443   }
444   return &attr->attr;
445 }
446 
iasObjDelete(Object * obj)447 void iasObjDelete(Object* obj)
448 {
449   ObjectPrivate* objp=(ObjectPrivate*)obj;
450   ObjectPrivate** oh=&objp->ias->objects;
451   ObjectPrivate* o;
452   AttributePrivate* attr;
453 
454   while((o=*oh)) {
455     if(o==objp) {
456       *oh=o->next;
457       break;
458     } else {
459       oh=&o->next;
460     }
461   }
462 
463   for(attr=objp->attrs;attr;) {
464     AttributePrivate* a1=attr;
465     attr=attr->next;
466     freeMem(a1);
467   }
468 
469   freeMem(objp);
470 }
471 
iasSrvNewObject(IASServer * ias,const char * class)472 Object* iasSrvNewObject(IASServer* ias, const char* class)
473 {
474   IASServerPrivate* iasp=(IASServerPrivate*)ias;
475   ObjectPrivate* op;
476   int len=strlen(class);
477   u_short id;
478 
479   if(len>sizeof op->class.chars) return 0;
480 
481   for(id=0;;id++) {
482     for(op=iasp->objects;op;op=op->next) if(op->id==id) break;
483     if(!op) break;
484   }
485 
486   op=allocMem(id_object,sizeof(ObjectPrivate));
487   op->attrs=0;
488   op->ias=iasp;
489   op->id=id;
490   op->class.length=len;
491   memcpy(op->class.chars,class,len);
492 
493   op->next=iasp->objects;
494   iasp->objects=op;
495 
496   return &op->object;
497 }
498 
iasSrvClose(IASServer * ias)499 void iasSrvClose(IASServer* ias)
500 {
501   IASServerPrivate* iasp=(IASServerPrivate*)ias;
502   ObjectPrivate* obj;
503   IASConnection* iasc;
504 
505   lsapClose(iasp->lsap);
506   for(iasc=iasp->connections;iasc;iasc=iasc->next) iasc->ias=0;
507 
508   for(obj=iasp->objects;obj;) {
509     ObjectPrivate* o1=obj;
510     AttributePrivate* attr;
511     for(attr=obj->attrs;attr;) {
512       AttributePrivate* a1=attr;
513       attr=attr->next;
514       freeMem(a1);
515     }
516     obj=obj->next;
517     freeMem(o1);
518   }
519 
520   freeMem(iasp);
521 }
522 
createIASServer(LAP * lap,int charset,const char * name,int len)523 IASServer* createIASServer(LAP* lap, int charset, const char* name, int len)
524 {
525   IASServerPrivate* iasp=allocMem(id_server,sizeof(IASServerPrivate));
526   IASServer* ias=&iasp->ias;
527   Object* obj;
528 
529   iasp->objects=0;
530   iasp->connections=0;
531 
532   iasp->lsap=lapNewLSAP(lap,0);
533   iasp->lsap->handle=iasp;
534   iasp->lsap->accept=accept;
535 
536   if(lsapGetSelector(iasp->lsap)!=IAS_LSAPSEL) {
537     birda_log("IAS wasn't registered first: wrong LSAP selector\n");
538   }
539 
540   obj=iasSrvNewObject(ias,"Device");
541 
542   iasObjNewString(obj, "DeviceName", charset, name, len);
543   iasObjNewOctets(obj, "IrLMPSupport", irLMPSupport, sizeof irLMPSupport);
544 
545   return ias;
546 }
547