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 /* mux.c
27  *
28  * Limitations:
29  *  - LM exclusive mode not supported
30  */
31 
32 #include <irda.h>
33 #include <lapmux.h>
34 
35 #include <string.h>
36 
37 /**********************************************************************
38  * Constants
39  **********************************************************************/
40 
41 static const char id_mux_lsap[]="mux lsap";
42 static const char id_mux_connection[]="mux connection";
43 static const char id_mux_sarbuffer[]="mux sar buffer";
44 static const char id_mux_sendbuf[]="mux sendbuf";
45 
46 #define LM_CONTROL               0x80
47 
48 #define LM_CONNECT               0x01
49 #define LM_CONNECT_CONFIRM       0x81
50 #define LM_DISCONNECT            0x02
51 #define LM_ACCESSMODE            0x03
52 #define LM_ACCESSMODE_CONFIRM    0x83
53 
54 #define LM_UNSUPPORTED           0xff
55 
56 #define REASON_USER              0x01
57 #define REASON_LINK_MANAGEMENT   0x05
58 #define REASON_DISCONNECTED      0x06
59 #define REASON_NO_PEER           0x08
60 #define REASON_UNSPECIFIED       0xff
61 
62 #define LSAP_UNCONNECTED         0x70
63 
64 #define TTP_P                    0x80
65 #define TTP_M                    0x80
66 
67 #define PI_MAXSDUSIZE            1
68 
69 #define INITIAL_CREDITS          1       /* Is this the level we want? */
70 
71 /**********************************************************************
72  * Internal functions
73  **********************************************************************/
74 
makeSendBuf(int length)75 static SendBuf* makeSendBuf(int length)
76 {
77   SendBuf* s=allocMem(id_mux_sendbuf,sizeof(SendBuf)+length-1);
78   s->length=length;
79   return s;
80 }
81 
sendDisconnect(LAPPrivate * lapp,int dlsap,int slsap,int reason)82 static void sendDisconnect(LAPPrivate* lapp, int dlsap, int slsap, int reason)
83 {
84   SendBuf* sb=makeSendBuf(6);
85 
86   sb->buf[2]=dlsap|LM_CONTROL;
87   sb->buf[3]=slsap;
88   sb->buf[4]=LM_DISCONNECT;
89   sb->buf[5]=reason;
90   /* User data is not supported */
91   lapAppendSendBuffer(lapp,sb);
92 }
93 
sendConnect(LAPPrivate * lapp,int dlsap,int slsap,bool ttp,int credits,const u_char * buf,int len)94 static void sendConnect(LAPPrivate* lapp, int dlsap, int slsap,
95 			bool ttp, int credits, const u_char* buf, int len)
96 {
97   SendBuf* sb;
98 
99   sb=makeSendBuf((ttp ? 7 : 6)+len);
100   sb->buf[2]=dlsap|LM_CONTROL;
101   sb->buf[3]=slsap;
102   sb->buf[4]=LM_CONNECT;
103   sb->buf[5]=0;
104   if(ttp) sb->buf[6]=credits;
105   memcpy(sb->buf+(ttp ? 7 : 6),buf,len);
106   lapAppendSendBuffer(lapp,sb);
107 }
108 
sendConnectConfirm(LAPPrivate * lapp,int dlsap,int slsap,bool ttp,int credits)109 static void sendConnectConfirm(LAPPrivate* lapp, int dlsap, int slsap,
110 			       bool ttp, int credits)
111 {
112   SendBuf* sb;
113 
114   sb=makeSendBuf(ttp ? 7 : 6);
115   sb->buf[2]=dlsap|LM_CONTROL;
116   sb->buf[3]=slsap;
117   sb->buf[4]=LM_CONNECT_CONFIRM;
118   sb->buf[5]=0;
119   if(ttp) sb->buf[6]=credits;
120   /* User data not supported */
121   lapAppendSendBuffer(lapp,sb);
122 }
123 
sendAccessModeDeny(LAPPrivate * lapp,int dlsap,int slsap)124 static void sendAccessModeDeny(LAPPrivate* lapp, int dlsap, int slsap)
125 {
126   SendBuf* sb=makeSendBuf(6);
127 
128   sb->buf[2]=dlsap|LM_CONTROL;
129   sb->buf[3]=slsap;
130   sb->buf[4]=LM_ACCESSMODE_CONFIRM;
131   sb->buf[5]=LM_UNSUPPORTED;
132   lapAppendSendBuffer(lapp,sb);
133 }
134 
disableConnection(ConnectionPrivate * conp)135 static void disableConnection(ConnectionPrivate* conp)
136 {
137   if((conp->flags&(CST_OPEN|CST_OPENING)) &&
138      !(conp->flags&(CST_NOTIFIED))) {
139     conp->flags|=CST_NOTIFIED;
140     sendDisconnect(conp->lap,conp->remoteSel,conp->localSel,REASON_USER);
141   }
142 
143   if(conp->sarBuffer) {
144     freeMem(conp->sarBuffer);
145     conp->sarBuffer=0;
146   }
147 
148   while(conp->sendHead) {
149     SendBuf* sb=conp->sendHead;
150     conp->sendHead=sb->next;
151     freeMem(sb);
152   }
153 
154   if(conp->flags&(CST_OPENING|CST_OPEN)) {
155     conp->flags&=~(CST_OPENING|CST_OPEN);
156     if(conp->con.status) conp->con.status(&conp->con,CONN_CLOSED,0,0);
157   }
158 }
159 
freeConnection(ConnectionPrivate * conp)160 static void freeConnection(ConnectionPrivate* conp)
161 {
162   LAPPrivate* lapp=conp->lap;
163   ConnectionPrivate** ch=&lapp->connections;
164   ConnectionPrivate* c;
165 
166   while((c=*ch)) {
167     if(c==conp) {
168       *ch=c->next;
169       break;
170     } else {
171       ch=&c->next;
172     }
173   }
174 
175   if(lapp->nextConn==conp) lapp->nextConn=0;
176   freeMem(conp);
177 }
178 
parseTTPConnect(ConnectionPrivate * c,const u_char * buf,int len)179 static int parseTTPConnect(ConnectionPrivate* c, const u_char* buf, int len)
180 {
181   int len1;
182 
183   if(len<1) return -1;
184   c->sendCredits=buf[0]&~TTP_P;
185   if(buf[0]&TTP_P) {
186     if(len<2) return -1;
187     len1=buf[1]+2;
188     if(len1>len) return -1;
189     c->sendSduSize=0x7fffffff&getBEParameter(PI_MAXSDUSIZE,0,buf+2,len1-2);
190     return len1;
191   } else {
192     return 1;
193   }
194 }
195 
lsapControl(LAPPrivate * lapp,int dlsap,int slsap,int op,ConnectionPrivate * con,u_char * buf,int len)196 static void lsapControl(LAPPrivate* lapp, int dlsap, int slsap, int op,
197 			ConnectionPrivate* con, u_char* buf, int len)
198 {
199   int i;
200 
201   switch(op) {
202   case LM_CONNECT:
203     if(con) {
204       /* Reply to this? */
205       birda_log("Attempted connect to existing connection\n");
206     } else {
207       LSAPPrivate* lsapp=lapp->lsaps;
208       while(lsapp && lsapp->lsapSel!=dlsap) lsapp=lsapp->next;
209       if(lsapp) {
210 	con=allocMem(id_mux_connection,sizeof(ConnectionPrivate));
211 	con->con.handle=0;
212 	con->con.status=0;
213 	con->con.data=0;
214 	con->lap=lapp;
215 	con->localSel=dlsap;
216 	con->remoteSel=slsap;
217 	con->flags=(lsapp->flags&CST_USER_FLAGS)|CST_OPEN;
218 	con->sendSduSize=0;
219 	con->recvSduSize=0;
220 	con->sarLength=0;
221 	con->sarBuffer=0;
222 	con->sendHead=0;
223 
224 	con->sendCredits=0;
225 	con->recvCredits=0;
226 	con->wantedRecvCredits=0;
227 	con->sendDataSize=lapp->sendParams.dataSize-2; /* LM header bytes */
228 	con->recvDataSize=lapp->recvDataSize-2;        /* LM header bytes */
229 
230 	if(con->flags&LM_TINY_TP) {
231 	  con->recvDataSize--;
232 	  con->sendDataSize--;
233 	  con->recvCredits=1;
234 	  con->wantedRecvCredits=INITIAL_CREDITS;
235 	}
236 
237 	i=lsapp->flags&LM_TINY_TP ? parseTTPConnect(con,buf,len) : 0;
238 	if(i>=0 &&
239 	   lsapp->lsap.accept &&
240 	   lsapp->lsap.accept(&lsapp->lsap,&con->con,buf+i,len-i)) {
241 	  if(con->recvSduSize) con->sarBuffer=allocMem(id_mux_sarbuffer,con->recvSduSize);
242 	  con->next=lapp->connections;
243 	  lapp->connections=con;
244 
245 	  /* SAR not enabled in the return direction */
246 	  sendConnectConfirm(lapp,slsap,dlsap,con->flags&LM_TINY_TP,con->recvCredits);
247 	} else {
248 	  freeMem(con);
249 	  sendDisconnect(lapp,slsap,dlsap,REASON_UNSPECIFIED);
250 	}
251       } else {
252 	birda_log("No such LSAP: %d\n",dlsap);
253 	sendDisconnect(lapp,slsap,dlsap,REASON_NO_PEER);
254       }
255     }
256     break;
257   case LM_CONNECT_CONFIRM:
258     if(con->flags&CST_OPENING) {
259       i=(con->flags&LM_TINY_TP) ? parseTTPConnect(con,buf,len) : 0;
260       if(i>=0) {
261 	con->flags=(con->flags&~CST_OPENING)|CST_OPEN;
262 	if(con->recvSduSize) con->sarBuffer=allocMem(id_mux_sarbuffer,con->recvSduSize);
263 	if(con->con.status) con->con.status(&con->con,CONN_OPENED,buf+i,len-i);
264       } else {
265 	birda_log("failed to exchanged ttp settings\n");
266 	con->flags&=CST_OPENING;
267 	/* Do anything more? */
268       }
269     }
270     break;
271   case LM_DISCONNECT:
272     if(con) {
273       con->flags|=CST_NOTIFIED;
274       disableConnection(con);
275     }
276     break;
277   }
278 }
279 
unconnData(LAPPrivate * lapp,u_char * buf,int len)280 static void unconnData(LAPPrivate* lapp, u_char* buf, int len)
281 {
282   birda_log("Unconnected LSAP data:\n");
283   showBytes(buf,len);
284 }
285 
286 /**********************************************************************
287  * Called by lap.c
288  **********************************************************************/
289 
lmDisableConnections(LAPPrivate * lapp)290 void lmDisableConnections(LAPPrivate* lapp)
291 {
292   ConnectionPrivate* c;
293 
294   for(c=lapp->connections;c;c=c->next) disableConnection(c);
295 }
296 
lmFreeConnections(LAPPrivate * lapp)297 void lmFreeConnections(LAPPrivate* lapp)
298 {
299   while(lapp->connections) freeConnection(lapp->connections);
300 }
301 
lmMoveConnectionBuffers(LAPPrivate * lapp,int wanted)302 void lmMoveConnectionBuffers(LAPPrivate* lapp, int wanted)
303 {
304   if(lapp->connections) {
305     int flag;
306     ConnectionPrivate* c;
307 
308     if(!lapp->nextConn) lapp->nextConn=lapp->connections;
309     for(flag=0,c=lapp->nextConn;lapp->sendCount<wanted;) {
310       if(c->flags&CST_OPEN) {
311 	int delta=c->wantedRecvCredits-c->recvCredits;
312 	SendBuf* s=c->sendHead;
313 	if(s) {
314 	  c->sendHead=s->next;
315 	} else if(delta>0) {
316 	  s=makeSendBuf(5);
317 	  s->buf[2]=c->remoteSel;
318 	  s->buf[3]=c->localSel;
319 	  s->buf[4]=0;
320 	}
321 	if(delta>0) {
322 	  if(delta>127) delta=127;
323 	  s->buf[4]=(s->buf[4]&TTP_M)|delta;
324 	  c->recvCredits+=delta;
325 	}
326 	if(s) {
327 	  lapAppendSendBuffer(lapp,s);
328 	  flag=1;
329 	}
330       }
331       c=c->next ? c->next : lapp->connections;
332       if(c==lapp->nextConn) {
333 	if(!flag) return;
334 	flag=0;
335       }
336     }
337   }
338 }
339 
lmData(LAPPrivate * lapp,u_char * buf,int len,int expedited)340 void lmData(LAPPrivate* lapp, u_char* buf, int len, int expedited)
341 {
342   int cmd,dlsap,slsap,opcode;
343   ConnectionPrivate* conp;
344 
345   if(len<2) return;
346   cmd=LM_CONTROL&buf[0];
347   dlsap=~LM_CONTROL&buf[0];
348   slsap=~LM_CONTROL&buf[1];
349 
350   if(dlsap>=LSAP_UNCONNECTED || slsap>=LSAP_UNCONNECTED) {
351     if(!cmd && dlsap==LSAP_UNCONNECTED && slsap==LSAP_UNCONNECTED)
352       unconnData(lapp,buf+2,len-2);
353     return;
354   }
355 
356   for(conp=lapp->connections;conp;conp=conp->next)
357     if((conp->flags&(CST_OPENING|CST_OPEN)) &&
358        conp->localSel==dlsap &&
359        conp->remoteSel==slsap) break;
360 
361   /* NB: Should we also discard expedited data? */
362 
363   if(cmd) {
364     if(len<3 || expedited) return;
365     opcode=buf[2];
366 
367     switch(opcode) {
368     case LM_CONNECT_CONFIRM:
369     case LM_CONNECT:
370     case LM_DISCONNECT:
371       lsapControl(lapp,dlsap,slsap,opcode,conp,buf+4,len-4);
372       break;
373     case LM_ACCESSMODE:
374       sendAccessModeDeny(lapp,slsap,dlsap);
375       break;
376     case LM_ACCESSMODE_CONFIRM:
377       break;
378     }
379   } else if(!conp) {
380     sendDisconnect(lapp,slsap,dlsap,REASON_DISCONNECTED);
381   } else if(len>2) {
382     if(!(conp->flags&LM_TINY_TP)) {
383       if(conp->con.data) conp->con.data(&conp->con,buf+2,len-2);
384     } else {
385       if(conp->flags&CST_OPEN) {
386 	conp->sendCredits+=buf[2]&~TTP_M;
387 	if(len>3) {
388 	  if(conp->recvCredits>0) conp->recvCredits--;
389 	  if(!conp->recvSduSize) {
390 	    if(conp->con.data) conp->con.data(&conp->con,buf+3,len-3);
391 	  } else if(conp->sarLength+len-3>conp->recvSduSize) {
392 	    sendDisconnect(conp->lap,conp->remoteSel,conp->localSel,REASON_LINK_MANAGEMENT);
393 	    disableConnection(conp);
394 	    birda_log("SDU is too long, closing the connection\n");
395 	  } else if(buf[2]&TTP_M) {
396 	    memcpy(conp->sarBuffer+conp->sarLength,buf+3,len-3);
397 	    conp->sarLength+=len-3;
398 	  } else if(conp->sarLength) {
399 	    memcpy(conp->sarBuffer+conp->sarLength,buf+3,len-3);
400 	    conp->sarLength+=len-3;
401 	    if(conp->con.data) conp->con.data(&conp->con,conp->sarBuffer,conp->sarLength);
402 	    conp->sarLength=0;
403 	  } else {
404 	    if(conp->con.data) conp->con.data(&conp->con,buf+3,len-3);
405 	  }
406 	}
407       }
408     }
409   }
410 }
411 
lmUnitData(LAPPrivate * lapp,u_char * buf,int len)412 void lmUnitData(LAPPrivate* lapp, u_char* buf, int len)
413 {
414   if(len>=2 && buf[0]==LSAP_UNCONNECTED && (~LM_CONTROL&buf[1])==LSAP_UNCONNECTED)
415     unconnData(lapp,buf+2,len-2);
416 }
417 
418 /**********************************************************************
419  * External functions
420  **********************************************************************/
421 
422 
lapNewLSAP(LAP * lap,int flags)423 LSAP* lapNewLSAP(LAP* lap, int flags)
424 {
425   LAPPrivate* lapp=(LAPPrivate*)lap;
426   LSAPPrivate* lsapp;
427   ConnectionPrivate* c;
428   u_char sel=0;
429 
430   for(sel=0;sel<LSAP_UNCONNECTED;sel++) {
431     for(lsapp=lapp->lsaps; lsapp && lsapp->lsapSel!=sel; lsapp=lsapp->next);
432     if(lsapp) continue;
433     for(c=lapp->connections;
434 	c && !(c->flags&(CST_OPENING|CST_OPEN)) && c->localSel!=sel;
435 	c=c->next);
436     if(!c) break;
437   }
438   if(sel==LSAP_UNCONNECTED) return 0;
439 
440   lsapp=allocMem(id_mux_lsap,sizeof(LSAPPrivate));
441   lsapp->lsap.handle=0;
442   lsapp->lsap.accept=0;
443   lsapp->lsapSel=sel;
444   lsapp->flags=flags;
445   lsapp->lap=lapp;
446 
447   lsapp->next=lapp->lsaps;
448   lapp->lsaps=lsapp;
449 
450   return &lsapp->lsap;
451 }
452 
lsapGetSelector(LSAP * lsap)453 u_char lsapGetSelector(LSAP* lsap)
454 {
455   return ((LSAPPrivate*)lsap)->lsapSel;
456 }
457 
lsapClose(LSAP * lsap)458 void lsapClose(LSAP* lsap)
459 {
460   LSAPPrivate* lsapp=(LSAPPrivate*)lsap;
461   LSAPPrivate* l;
462   LSAPPrivate** lh=&lsapp->lap->lsaps;
463 
464   while((l=*lh)) {
465     if(l==lsapp) {
466       *lh=l->next;
467       freeMem(l);
468       return;
469     } else {
470       lh=&l->next;
471     }
472   }
473 }
474 
lapNewConnection(LAP * lap,int rlsap,int flags,const void * buf0,int len)475 Connection* lapNewConnection(LAP* lap, int rlsap, int flags, const void* buf0, int len)
476 {
477   const u_char* buf=(u_char*)buf0;
478   LAPPrivate* lapp=(LAPPrivate*)lap;
479   LSAPPrivate* l;
480   ConnectionPrivate* c;
481   u_char llsap=0;
482 
483   if(!(lapp->state&STATE_CONNECTED)) return 0;
484 
485   for(llsap=0;llsap<LSAP_UNCONNECTED;llsap++) {
486     for(l=lapp->lsaps; l && l->lsapSel!=llsap; l=l->next);
487     if(l) continue;
488     for(c=lapp->connections;
489 	c && (!(c->flags&(CST_OPENING|CST_OPEN)) ||
490 	      c->localSel!=llsap || c->remoteSel!=rlsap);
491 	c=c->next);
492     if(!c) break;
493   }
494   if(llsap==LSAP_UNCONNECTED) return 0;
495 
496   c=allocMem(id_mux_connection,sizeof(ConnectionPrivate));
497   c->con.handle=0;
498   c->con.status=0;
499   c->con.data=0;
500   c->lap=lapp;
501   c->localSel=llsap;
502   c->remoteSel=rlsap;
503   c->flags=(flags&CST_USER_FLAGS)|CST_OPENING;
504   c->sendSduSize=0;
505   c->recvSduSize=0;
506   c->sarLength=0;
507   c->sarBuffer=0;
508   c->sendHead=0;
509 
510   c->sendCredits=0;
511   c->recvCredits=0;
512   c->wantedRecvCredits=0;
513   c->sendDataSize=lapp->sendParams.dataSize-2; /* LM header bytes */
514   c->recvDataSize=lapp->recvDataSize-2;        /* LM header bytes */
515 
516   if(c->flags&LM_TINY_TP) {
517     c->sendDataSize--;
518     c->recvDataSize--;
519     c->recvCredits=1;
520     c->wantedRecvCredits=INITIAL_CREDITS;
521   }
522 
523   c->next=lapp->connections;
524   lapp->connections=c;
525 
526   sendConnect(lapp,rlsap,llsap,c->flags&LM_TINY_TP,c->recvCredits,buf,len);
527 
528   return &c->con;
529 }
530 
connClose(Connection * con)531 void connClose(Connection* con)
532 {
533   ConnectionPrivate* conp=(ConnectionPrivate*)con;
534 
535   conp->con.status=0;
536   disableConnection(conp);
537   freeConnection(conp);
538 }
539 
connGetSendDataSize(Connection * con)540 int connGetSendDataSize(Connection* con)
541 {
542   ConnectionPrivate* conp=(ConnectionPrivate*)con;
543   return conp->sendSduSize ? conp->sendSduSize : conp->sendDataSize;
544 }
545 
connGetRecvDataSize(Connection * con)546 int connGetRecvDataSize(Connection* con)
547 {
548   ConnectionPrivate* conp=(ConnectionPrivate*)con;
549   return conp->recvSduSize ? conp->recvSduSize : conp->recvDataSize;
550 }
551 
connWrite(Connection * con,const void * buf0,int len)552 bool connWrite(Connection* con, const void* buf0, int len)
553 {
554   u_char* buf=(u_char*)buf0;
555   ConnectionPrivate* conp=(ConnectionPrivate*)con;
556   int ttp=conp->flags&LM_TINY_TP ? 1 : 0;
557 
558   if(!(conp->flags&(CST_OPENING|CST_OPEN))) return FALSE;
559 
560   if(len>(conp->sendSduSize ? conp->sendSduSize : conp->sendDataSize)) {
561     birda_log("Packet is too large, discarding\n");
562     return FALSE;
563   }
564 
565   while(len>0) {
566     int len1=len<conp->sendDataSize ? len : conp->sendDataSize;
567     SendBuf* sb=makeSendBuf(len1+4+ttp);
568     sb->buf[2]=conp->remoteSel;
569     sb->buf[3]=conp->localSel;
570     if(ttp) sb->buf[4]=len1<len ? TTP_M : 0;
571     memcpy(sb->buf+4+ttp,buf,len1);
572     if(conp->sendHead) conp->sendTail->next=sb;
573     else               conp->sendHead=sb;
574     conp->sendTail=sb;
575     sb->next=0;
576     buf+=len1;
577     len-=len1;
578   }
579 
580   return TRUE;
581 }
582 
connWrite2(Connection * con,const void * buf10,int len1,const void * buf20,int len2)583 bool connWrite2(Connection* con, const void* buf10, int len1, const void* buf20, int len2)
584 {
585   u_char* buf1=(u_char*)buf10;
586   u_char* buf2=(u_char*)buf20;
587   ConnectionPrivate* conp=(ConnectionPrivate*)con;
588   int ttp=conp->flags&LM_TINY_TP ? 1 : 0;
589 
590   if(!(conp->flags&(CST_OPENING|CST_OPEN))) return FALSE;
591 
592   if(len1+len2>(conp->sendSduSize ? conp->sendSduSize : conp->sendDataSize)) {
593     birda_log("Packet is too large, discarding\n");
594     return FALSE;
595   }
596 
597   while(len1+len2>0) {
598     int len1x=len1<conp->sendDataSize ? len1 : conp->sendDataSize;
599     int len2x=len2<conp->sendDataSize-len1x ? len2 : conp->sendDataSize-len1x;
600     SendBuf* sb=makeSendBuf(len1x+len2x+4+ttp);
601     sb->buf[2]=conp->remoteSel;
602     sb->buf[3]=conp->localSel;
603     if(ttp) sb->buf[4]=len2x<len2 ? TTP_M : 0;
604     memcpy(sb->buf+4+ttp,buf1,len1x);
605     memcpy(sb->buf+4+ttp+len1x,buf2,len2x);
606     if(conp->sendHead) conp->sendTail->next=sb;
607     else               conp->sendHead=sb;
608     conp->sendTail=sb;
609     sb->next=0;
610     buf1+=len1x;
611     len1-=len1x;
612     buf2+=len2x;
613     len2-=len2x;
614   }
615 
616   return TRUE;
617 }
618