/* * Copyright (c) 2001 Tommy Bohlin * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* commsrv.c * * 2do: * obj2=iasSrvNewObject(ias,"IrLPT"); * iasObjNewInteger(obj2,"IrDA:IrLMP:LsapSel", ...); * lap->flags|=HINT_PRINTER; * HINT_MODEM? * HINT_FAX? * HINT_TELEPHONY? */ #include #include /********************************************************************** * Constants **********************************************************************/ static const char id_server[]="comm server"; static const char id_port[]="comm port"; static const u_char commParameters[] = { PI_SERVICE_TYPE, 1, COMM_ST_3WIRE|COMM_ST_9WIRE|COMM_ST_CENTRONICS, PI_PORT_TYPE, 1, COMM_PT_SERIAL|COMM_PT_PARALLEL }; /********************************************************************** * Data structures **********************************************************************/ typedef struct COMMPortPrivate { COMMPort port; struct COMMPortPrivate* next; struct COMMServerPrivate* server; LSAP* lsap; int type; Connection* con; Object* iasObject; } COMMPortPrivate; typedef struct COMMServerPrivate { COMMServer comm; LAP* lap; IASServer* ias; COMMPortPrivate* ports; } COMMServerPrivate; /********************************************************************** * Internal functions **********************************************************************/ static int parseControl(COMMPortPrivate* cpp, const u_char* buf, int len) { int i,len1; if(len<1) return 0; len1=buf[0]+1; if(len1>len) { if(cpp->server->comm.debug&COMM_DEBUG_INFO) birda_log("comm control data longer than packet"); return -1; } i=1; while(i+1len1) { if(cpp->server->comm.debug&COMM_DEBUG_INFO) birda_log("comm control entry too long"); return -1; } switch(pi) { case PI_SERVICE_TYPE: cpp->type=pv; if(cpp->server->comm.debug&COMM_DEBUG_INFO) birda_log("service type %x\n",pv); break; case PI_PORT_TYPE: if(cpp->server->comm.debug&COMM_DEBUG_INFO) birda_log("port type %x\n",pv); break; case PI_FIXED_PORT_NAME: if(cpp->server->comm.debug&COMM_DEBUG_INFO) birda_log("fixed port name %.*s\n",pl,buf+i+2); break; case PI_DATA_RATE: if(cpp->server->comm.debug&COMM_DEBUG_INFO) birda_log("data rate %d\n",pv); break; case PI_DATA_FORMAT: if(cpp->server->comm.debug&COMM_DEBUG_INFO) birda_log("data format %x\n",pv); break; case PI_FLOW_CONTROL: if(cpp->server->comm.debug&COMM_DEBUG_INFO) birda_log("flow control %x\n",pv); break; case PI_XON_XOFF: if(cpp->server->comm.debug&COMM_DEBUG_INFO) birda_log("xon/xoff %x\n",pv); break; case PI_ENQ_ACK: if(cpp->server->comm.debug&COMM_DEBUG_INFO) birda_log("enq/ack %x\n",pv); break; case PI_DTE: if(cpp->server->comm.debug&COMM_DEBUG_INFO) birda_log("DTE %x\n",pv); break; case PI_DCE: if(cpp->server->comm.debug&COMM_DEBUG_INFO) birda_log("DCE %x\n",pv); break; case PI_POLL_LINE_SETTINGS: birda_log("poll line settings is NYI\n"); default: if(cpp->server->comm.debug&COMM_DEBUG_INFO) birda_log("pi=%x pl=%d\n",pi,pl); break; } i+=2+pl; } if(i!=len1) { if(cpp->server->comm.debug&COMM_DEBUG_INFO) birda_log("trailing garbage in comm control data"); return -1; } return len1; } static void commData(Connection* con, void* buf0, int len) { u_char* buf=(u_char*)buf0; COMMPortPrivate* cpp=(COMMPortPrivate*)con->handle; int len1=parseControl(cpp,buf,len); if(len1>=0) { if(cpp->port.data) cpp->port.data(cpp->port.handle,buf+len1,len-len1); } else { birda_log("bad comm control data\n"); } } static void commStatus(Connection* con, int event, void* buf, int len) { COMMPortPrivate* cpp=(COMMPortPrivate*)con->handle; if(event==CONN_CLOSED) { if(cpp->server->comm.debug&COMM_DEBUG_INFO) birda_log("comm connection closed\n"); cpp->con=0; connClose(con); } } static bool accept(LSAP* lsap, Connection* con, void* buf, int len) { COMMPortPrivate* cpp=(COMMPortPrivate*)lsap->handle; if(cpp->con) { birda_log("port already open\n"); return FALSE; } cpp->type=0; if(parseControl(cpp,buf,len)<0) { birda_log("bad comm connection request\n"); return FALSE; } if(!(cpp->type&(COMM_ST_3WIRE|COMM_ST_9WIRE))) { birda_log("port type does not match\n"); return FALSE; } if(cpp->port.status) (cpp->port.status)(&cpp->port, COMM_CONNECTED); if(cpp->server->comm.debug&COMM_DEBUG_INFO) birda_log("comm connection accepted\n"); con->handle=cpp; con->status=commStatus; con->data=commData; cpp->con=con; return TRUE; } /********************************************************************** * External functions **********************************************************************/ void commPortWrite(COMMPort* cp, const void* buf0, int len) { u_char* buf=(u_char*)buf0; COMMPortPrivate* cpp=(COMMPortPrivate*)cp; int k=connGetSendDataSize(cpp->con); int n,i=0; u_char cbuf[1]; cbuf[0]=0; while((n=len-i)>0) { if(cpp->type!=COMM_ST_3WIRE_RAW) { if(n>=k) n=k-1; connWrite2(cpp->con,cbuf,1,buf+i,n); } else { if(n>k) n=k; connWrite(cpp->con,buf+i,n); } i+=n; } } void commPortClose(COMMPort* cp) { COMMPortPrivate* cpp=(COMMPortPrivate*)cp; COMMPortPrivate** ch=&cpp->server->ports; COMMPortPrivate* c; while((c=*ch)) { if(c==cpp) { *ch=c->next; break; } else { ch=&c->next; } } /* ### NYI * kill the current connection ... * Unregister from IAS * lsapClose(comp->lsap); * iasObjDelete(comp->iasObject); */ birda_log("commPortClose is NYI\n"); freeMem(cpp); } COMMPort* commSrvNewPort(COMMServer* cs) { COMMServerPrivate* csp=(COMMServerPrivate*)cs; COMMPortPrivate* cpp=allocMem(id_port,sizeof(COMMPortPrivate)); cpp->port.debug=0; cpp->port.handle=0; cpp->port.status=0; cpp->port.data=0; cpp->server=csp; cpp->next=csp->ports; csp->ports=cpp; cpp->lsap=lapNewLSAP(csp->lap,LM_TINY_TP); cpp->lsap->handle=cpp; cpp->lsap->accept=accept; cpp->con=0; cpp->iasObject=iasSrvNewObject(csp->ias,"IrDA:IrCOMM"); iasObjNewInteger(cpp->iasObject,"IrDA:TinyTP:LsapSel",lsapGetSelector(cpp->lsap)); iasObjNewOctets(cpp->iasObject,"Parameters",commParameters,sizeof commParameters); iasObjNewString(cpp->iasObject,"IrDA:IrLMP:InstanceName",CHARSET_ASCII,"com1",4); return &cpp->port; } void commSrvClose(COMMServer* comm) { COMMServerPrivate* commp=(COMMServerPrivate*)comm; while(commp->ports) commPortClose(&commp->ports->port); freeMem(commp); } COMMServer* createCOMMServer(LAP* lap, IASServer* ias) { COMMServerPrivate* commp=allocMem(id_server,sizeof(COMMServerPrivate)); commp->comm.debug=0; commp->lap=lap; commp->ias=ias; commp->ports=0; lap->flags|=HINT_IRCOMM; return &commp->comm; }