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 /* commclt.c
27  */
28 
29 #include <irda.h>
30 #include <comm.h>
31 
32 /**********************************************************************
33  * Constants
34  **********************************************************************/
35 
36 static const char id_client[]="comm client";
37 
38 /**********************************************************************
39  * Data structures
40  **********************************************************************/
41 
42 typedef struct Port {
43   int id;
44   int lsap;
45   int st;
46   int pt;
47 } Port;
48 
49 typedef struct COMMClientPrivate {
50   COMMClient comm;
51   LAP* lap;
52   int state;
53 #define STATE_GET_LSAPS               1
54 #define STATE_GET_PARAMETERS          2
55 #define STATE_LIVE                    3
56 #define STATE_CLOSED                  0
57   IASClient* ias;
58   Connection* con;
59   int stMask;
60   int ptMask;
61 #define NPORTS                        10
62   Port ports[NPORTS];
63 
64   /* Communication state */
65   int serviceType;
66   bool isDCE;
67   int dce;
68   int dte;
69 
70 } COMMClientPrivate;
71 
72 /**********************************************************************
73  * Internal functions
74  **********************************************************************/
75 
parseControl(COMMClientPrivate * commp,const u_char * buf,int len)76 static int parseControl(COMMClientPrivate* commp, const u_char* buf, int len)
77 {
78   int i,len1;
79 
80   if(len<1) return 0;
81   len1=buf[0]+1;
82   if(len1>len) return -1;
83   i=1;
84   while(i+1<len1) {
85     int pi=buf[i];
86     int pl=buf[i+1];
87     int pv=pl<=4 ? getBEVariable(buf+i+2,pl) : 0;
88     if(i+2+pl>len1) return -1;
89 
90     switch(pi) {
91     case PI_SERVICE_TYPE:
92       if(commp->comm.debug&COMM_DEBUG_INFO) birda_log("service type %x\n",pv);
93       break;
94     case PI_PORT_TYPE:
95       if(commp->comm.debug&COMM_DEBUG_INFO) birda_log("port type %x\n",pv);
96       break;
97     case PI_FIXED_PORT_NAME:
98       if(commp->comm.debug&COMM_DEBUG_INFO) birda_log("fixed port name %.*s\n",pl,buf+i+2);
99       break;
100     case PI_DATA_RATE:
101       if(commp->comm.debug&COMM_DEBUG_INFO) birda_log("data rate %d\n",pv);
102       break;
103     case PI_DATA_FORMAT:
104       if(commp->comm.debug&COMM_DEBUG_INFO) birda_log("data format %x\n",pv);
105       break;
106     case PI_FLOW_CONTROL:
107       if(commp->comm.debug&COMM_DEBUG_INFO) birda_log("flow control %x\n",pv);
108       break;
109     case PI_XON_XOFF:
110       if(commp->comm.debug&COMM_DEBUG_INFO) birda_log("xon/xoff %x\n",pv);
111       break;
112     case PI_ENQ_ACK:
113       if(commp->comm.debug&COMM_DEBUG_INFO) birda_log("enq/ack %x\n",pv);
114       break;
115     case PI_DTE:
116       if(commp->comm.debug&COMM_DEBUG_INFO) birda_log("DTE %x\n",pv);
117       commp->dte=pv&(COMM_DTR|COMM_RTS);
118       break;
119     case PI_DCE:
120       if(commp->comm.debug&COMM_DEBUG_INFO) birda_log("DCE %x\n",pv);
121       commp->dce&=pv&(COMM_CTS|COMM_DSR|COMM_RI|COMM_CD);
122       break;
123     case PI_POLL_LINE_SETTINGS:
124       birda_log("poll line settings is NYI\n");
125     default:
126       if(commp->comm.debug&COMM_DEBUG_INFO) birda_log("pi=%x pl=%d\n",pi,pl);
127       break;
128     }
129 
130     i+=2+pl;
131   }
132   if(i!=len1) return -1;
133   return len1;
134 }
135 
checkParameters(COMMClientPrivate * commp)136 static void checkParameters(COMMClientPrivate* commp)
137 {
138   for(;;) {
139     int i,id,type=iasCltResType(commp->ias);
140 
141     if(type==IAS_NONE) break;
142     if(type!=IAS_OCTETS) continue;
143 
144     id=iasCltResId(commp->ias);
145 
146     for(i=0;i<NPORTS;i++) {
147       if(commp->ports[i].id==id) {
148 	u_char* p=iasCltResPtr(commp->ias);
149 	int n=iasCltResLength(commp->ias);
150 	commp->ports[i].st=getBEParameter(PI_SERVICE_TYPE,0,p,n);
151 	commp->ports[i].pt=getBEParameter(PI_PORT_TYPE,COMM_PT_SERIAL|COMM_PT_PARALLEL,p,n);
152 	break;
153       }
154     }
155     iasCltResNext(commp->ias);
156   }
157 }
158 
checkLsaps(COMMClientPrivate * commp)159 static void checkLsaps(COMMClientPrivate* commp)
160 {
161   int i=0;
162 
163   while(i<NPORTS) {
164     int type=iasCltResType(commp->ias);
165 
166     if(type==IAS_NONE) break;
167     if(type!=IAS_INT) continue;
168 
169     commp->ports[i].id=iasCltResId(commp->ias);
170     commp->ports[i].lsap=iasCltResInt(commp->ias);
171 
172     i++;
173     iasCltResNext(commp->ias);
174   }
175   while(i<NPORTS) commp->ports[i++].lsap=0;
176 }
177 
connData(Connection * con,void * buf0,int len)178 static void connData(Connection* con, void* buf0, int len)
179 {
180   u_char* buf=(u_char*)buf0;
181   COMMClientPrivate* commp=(COMMClientPrivate*)con->handle;
182   COMMClient* comm=&commp->comm;
183   int len1=parseControl(commp,buf,len);
184 
185   if(len1>=0 && len1<len && comm->data) comm->data(comm,buf+len1,len-len1);
186 }
187 
connStatus(Connection * con,int event,void * buf,int len)188 static void connStatus(Connection* con, int event, void* buf, int len)
189 {
190   COMMClient* comm=(COMMClient*)con->handle;
191   switch(event) {
192   case CONN_OPENED:
193     if(comm->status) comm->status(comm,COMM_CONNECTED);
194     if(len>0) connData(con,buf,len);
195     break;
196   case CONN_CLOSED:
197     if(comm->status) comm->status(comm,COMM_DISCONNECTED);
198     break;
199   }
200 }
201 
choosePort(COMMClientPrivate * commp)202 static void choosePort(COMMClientPrivate* commp)
203 {
204   u_char buf[32];
205   int i,len;
206 
207   for(i=0;i<NPORTS;i++) {
208     int lsap=commp->ports[i].lsap;
209     int pt=commp->ports[i].pt&commp->ptMask;
210     int st=commp->ports[i].st&commp->stMask;
211 
212     if(!lsap || !pt || !st) continue;
213 
214     if (st&COMM_ST_CENTRONICS) {
215       birda_log("centronics protocol is NYI\n");
216     } else if(st&COMM_ST_9WIRE) {
217       if(commp->comm.debug&COMM_DEBUG_INFO) birda_log("using 9 wire protocol\n");
218 
219       commp->serviceType=COMM_ST_9WIRE;
220 
221       buf[0]=9;
222       buf[1]=PI_SERVICE_TYPE;
223       buf[2]=1;
224       buf[3]=COMM_ST_9WIRE;
225       buf[4]=PI_FLOW_CONTROL;
226       buf[5]=1;
227       buf[6]=0;
228       buf[7]=commp->isDCE ? PI_DCE : PI_DTE;
229       buf[8]=1;
230       buf[9]=commp->isDCE ? commp->dce : commp->dte;
231       len=10;
232 
233       /* Send later: PI_DATA_RATE, PI_DATA_FORMAT
234        * Ignore: PI_XON_XOFF, PI_ENQ_ACK
235        */
236     } else if(st&COMM_ST_3WIRE) {
237       birda_log("3 wire protocol is NYI\n");
238       /* Send: PI_SERVICE_TYPE, PI_FLOW_CONTROL, PI_XON_XOFF, PI_ENQ_ACK */
239     } else if(st&COMM_ST_3WIRE_RAW) {
240       birda_log("3 wire raw protocol is NYI\n");
241     }
242 
243     commp->state=STATE_LIVE;
244     commp->con=lapNewConnection(commp->lap,lsap,LM_TINY_TP,buf,len);
245     commp->con->handle=commp;
246     commp->con->status=connStatus;
247     commp->con->data=connData;
248     return;
249   }
250 
251   birda_log("failed to match ports, NYI\n");
252 }
253 
iasStatus(IASClient * ic,int event)254 static void iasStatus(IASClient* ic, int event)
255 {
256   COMMClientPrivate* commp=(COMMClientPrivate*)ic->handle;
257 
258   switch(event) {
259   case IAS_QUERY_COMPLETE:
260     switch(commp->state) {
261     case STATE_GET_LSAPS:
262       checkLsaps(commp);
263       if(!iasCltGetValueByClass(commp->ias,"IrDA:IrCOMM","Parameters")) {
264 	birda_log("fail2\n");
265       }
266       commp->state=STATE_GET_PARAMETERS;
267       break;
268     case STATE_GET_PARAMETERS:
269       checkParameters(commp);
270       iasCltClose(commp->ias);
271       commp->ias=0;
272       choosePort(commp);
273       break;
274     }
275     break;
276   case IAS_QUERY_FAILED:
277     birda_log("ias query failed is NYI\n");
278     break;
279   }
280 }
281 
282 /**********************************************************************
283  * External functions
284  **********************************************************************/
285 
commCltWrite(COMMClient * comm,const void * buf0,int len)286 void commCltWrite(COMMClient* comm, const void* buf0, int len)
287 {
288   u_char* buf=(u_char*)buf0;
289   COMMClientPrivate* commp=(COMMClientPrivate*)comm;
290   int k=connGetSendDataSize(commp->con);
291   int n,i=0;
292   u_char cbuf[1];
293 
294   cbuf[0]=0;
295 
296   while((n=len-i)>0) {
297     if(commp->serviceType!=COMM_ST_3WIRE_RAW) {
298       if(n>=k) n=k-1;
299       connWrite2(commp->con,cbuf,1,buf+i,n);
300     } else {
301       if(n>k) n=k;
302       connWrite(commp->con,buf+i,n);
303     }
304     i+=n;
305   }
306 }
307 
commCltSetParams(COMMClient * comm,int dataRate,int dataFormat)308 void commCltSetParams(COMMClient* comm, int dataRate, int dataFormat)
309 {
310   COMMClientPrivate* commp=(COMMClientPrivate*)comm;
311 
312   if(commp->serviceType!=COMM_ST_3WIRE_RAW) {
313     u_char cbuf[10];
314 
315     cbuf[0]=9;
316     cbuf[1]=PI_DATA_RATE;
317     cbuf[2]=4;
318     putBELong(cbuf+3,dataRate);
319     cbuf[7]=PI_DATA_FORMAT;
320     cbuf[8]=1;
321     cbuf[9]=dataFormat;
322 
323     connWrite(commp->con,cbuf,10);
324   }
325 }
326 
commCltSetDTE(COMMClient * comm,int dte)327 void commCltSetDTE(COMMClient* comm, int dte)
328 {
329   COMMClientPrivate* commp=(COMMClientPrivate*)comm;
330   int delta;
331 
332   dte&=COMM_DTR|COMM_RTS;
333   delta=(commp->dte^dte)>>2;
334 
335   if(commp->serviceType!=COMM_ST_3WIRE_RAW && delta) {
336     u_char cbuf[4];
337 
338     cbuf[0]=3;
339     cbuf[1]=PI_DTE;
340     cbuf[2]=1;
341     cbuf[3]=delta|dte;
342     connWrite(commp->con,cbuf,4);
343 
344     commp->dte=dte;
345   }
346 }
347 
commCltSetDCE(COMMClient * comm,int dce)348 void commCltSetDCE(COMMClient* comm, int dce)
349 {
350   COMMClientPrivate* commp=(COMMClientPrivate*)comm;
351   int delta;
352 
353   dce&=COMM_CTS|COMM_DSR|COMM_RI|COMM_CD;
354   delta=(commp->dce^dce)>>4;
355 
356   if(commp->serviceType!=COMM_ST_3WIRE_RAW && delta) {
357     u_char cbuf[4];
358 
359     cbuf[0]=3;
360     cbuf[1]=PI_DCE;
361     cbuf[2]=1;
362     cbuf[3]=delta|dce;
363     connWrite(commp->con,cbuf,4);
364 
365     commp->dce=dce;
366   }
367 }
368 
commCltClose(COMMClient * comm)369 void commCltClose(COMMClient* comm)
370 {
371   COMMClientPrivate* commp=(COMMClientPrivate*)comm;
372 
373   if(commp->ias) iasCltClose(commp->ias);
374   if(commp->con) connClose(commp->con);
375   freeMem(commp);
376 }
377 
createCOMMClient(LAP * lap,int serviceMask,int portMask,bool isDCE)378 COMMClient* createCOMMClient(LAP* lap, int serviceMask, int portMask, bool isDCE)
379 {
380   COMMClientPrivate* commp;
381   IASClient* ias=createIASClient(lap);
382   if(!ias) return 0;
383 
384   commp=allocMem(id_client,sizeof(COMMClientPrivate));
385   commp->comm.handle=0;
386   commp->comm.status=0;
387   commp->lap=lap;
388   commp->stMask=serviceMask;
389   commp->ptMask=portMask;
390   commp->state=STATE_GET_LSAPS;
391   commp->ias=ias;
392   commp->ias->handle=commp;
393   commp->ias->status=iasStatus;
394   commp->con=0;
395   commp->isDCE=isDCE;
396   commp->dce=COMM_CTS|COMM_DSR|COMM_RI|COMM_CD;
397   commp->dte=COMM_DTR|COMM_RTS;
398 
399   iasCltGetValueByClass(commp->ias,"IrDA:IrCOMM","IrDA:TinyTP:LsapSel");
400 
401   return &commp->comm;
402 }
403