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