PageRenderTime 162ms CodeModel.GetById 2ms app.highlight 114ms RepoModel.GetById 11ms app.codeStats 1ms

/bridge/bridge.c

https://github.com/xrg/misdnuser
C | 957 lines | 771 code | 93 blank | 93 comment | 102 complexity | 7efb38afdbc41f1c54af2cc6cd5d774e MD5 | raw file
  1/*****************************************************************************\
  2**                                                                           **
  3** isdnbridge                                                                **
  4**                                                                           **
  5**---------------------------------------------------------------------------**
  6** Copyright: Andreas Eversberg  (GPL)                                       **
  7**                                                                           **
  8** user space utility to bridge two mISDN ports.                             **
  9**                                                                           **
 10\*****************************************************************************/ 
 11
 12
 13#include <stdio.h>
 14#include <signal.h>
 15#include <string.h>
 16#include <stdlib.h>
 17#include <unistd.h>
 18//#include <poll.h>
 19#include <errno.h>
 20//#include <sys/ioctl.h>
 21#include <sys/types.h>
 22#include <sys/stat.h>
 23#include <fcntl.h>
 24#include <mISDNlib.h>
 25
 26#define ISDN_PID_L4_B_USER 0x440000ff
 27
 28/* used for udevice */
 29int entity = 0;
 30
 31/* the device handler and port list */
 32int mISDNdevice = -1;
 33int portcount = 0; /* counts all open ports for finding pair */
 34
 35/* quit flag */
 36int quit = 0;
 37
 38/* option stuff */
 39int nooutput = 0;
 40int traffic = 0;
 41int debug = 0;
 42
 43pid_t dsp_pid = 0;
 44
 45/* mISDN port structure list */
 46struct mISDNport {
 47	struct mISDNport *next, *prev;
 48	int count; /* port count */
 49	int portnum; /* port number */
 50	int l1link; /* if l1 is available (only works with nt-mode) */
 51	time_t l1establish; /* time until establishing after link failure */
 52	int ntmode; /* is TRUE if port is nt mode */
 53	int pri; /* is TRUE if port is a primary rate interface */
 54	int upper_id; /* id to transfer data down */
 55	int lower_id; /* id to transfer data up */
 56	int d_stid;
 57	int b_num; /* number of ports */
 58	int b_stid[256];
 59	int b_addr[256];
 60	int b_state[256]; /* state 0 = IDLE */
 61	unsigned char que_frm[2048]; /* queue while layer 1 is down */
 62	int que_len;
 63};
 64
 65struct mISDNport *mISDNport_first = NULL;
 66
 67enum { B_STATE_IDLE, B_STATE_ACTIVATING, B_STATE_ACTIVE, B_STATE_DEACTIVATING };
 68
 69/*
 70 * show state
 71 */
 72static void show_state(struct mISDNport *m1)
 73{
 74	struct mISDNport *m2 = m1;
 75
 76	if (nooutput)
 77		return;
 78	
 79	if (m1->count & 1)
 80		m1 = m1->prev;
 81	else
 82		m2 = m2->next;
 83
 84	printf("Port %2d %s  <->  Port %2d %s\n", m1->portnum, (m1->l1link)?"ACTIVE":"inactive", m2->portnum, (m2->l1link)?"ACTIVE":"inactive");
 85}
 86/*
 87 * show traffic
 88 */
 89static void show_traffic(struct mISDNport *m1, unsigned char *data, int len)
 90{
 91	struct mISDNport *m2 = m1;
 92	int right, i;
 93
 94	if (nooutput)
 95		return;
 96	
 97	if (m1->count & 1)
 98	{
 99		m1 = m1->prev;
100		right = 0;
101	} else
102	{
103		m2 = m2->next;
104		right = 1;
105	}
106
107	printf("Port %2d  %s  Port %2d :", m1->portnum, right?"-->":"<--", m2->portnum);
108	i = 0;
109	while(i < len)
110	{
111		printf(" %02x", data[i]);
112		i++;
113	}
114	printf("\n");
115}
116
117/*
118 * debug output
119 */
120#define PDEBUG(fmt, arg...) _printdebug(__FUNCTION__, __LINE__, fmt, ## arg)
121static void _printdebug(const char *function, int line, const char *fmt, ...)
122{
123	char buffer[4096];
124	va_list args;
125
126	if (!debug || nooutput)
127		return;
128
129	va_start(args,fmt);
130	vsnprintf(buffer, sizeof(buffer)-1, fmt, args);
131	buffer[sizeof(buffer)-1]=0;
132	va_end(args);
133
134	printf("%s, line %d: %s", function, line, buffer);
135}
136
137/*
138 * signal handler to interrupt main loop
139 */
140static void sighandler(int sigset)
141{
142	if (sigset == SIGHUP)
143		return;
144	if (sigset == SIGPIPE)
145		return;
146	fprintf(stderr, "Signal received: %d\n", sigset);
147	if (!quit)
148		quit = 1;
149
150}
151
152
153/*
154 * send control information to the channel (dsp-module)
155 */
156static void ph_control(unsigned long b_addr, int c1, int c2)
157{
158	unsigned char buffer[mISDN_HEADER_LEN+sizeof(int)+sizeof(int)];
159	iframe_t *ctrl = (iframe_t *)buffer; 
160	unsigned long *d = (unsigned long *)&ctrl->data.p;
161
162	ctrl->prim = PH_CONTROL | REQUEST;
163	ctrl->addr = b_addr | FLG_MSG_DOWN;
164	ctrl->dinfo = 0;
165	ctrl->len = sizeof(unsigned long)*2;
166	*d++ = c1;
167	*d++ = c2;
168	mISDN_write(mISDNdevice, ctrl, mISDN_HEADER_LEN+ctrl->len, TIMEOUT_1SEC);
169}
170
171void ph_control_block(unsigned long b_addr, int c1, void *c2, int c2_len)
172{
173	unsigned char buffer[mISDN_HEADER_LEN+sizeof(int)+c2_len];
174	iframe_t *ctrl = (iframe_t *)buffer;
175	unsigned long *d = (unsigned long *)&ctrl->data.p;
176
177	ctrl->prim = PH_CONTROL | REQUEST;
178	ctrl->addr = b_addr | FLG_MSG_DOWN;
179	ctrl->dinfo = 0;
180	ctrl->len = sizeof(unsigned long)*2;
181	*d++ = c1;
182	memcpy(d, c2, c2_len);
183	mISDN_write(mISDNdevice, ctrl, mISDN_HEADER_LEN+ctrl->len, TIMEOUT_1SEC);
184}
185
186
187/*
188 * activate / deactivate bchannel
189 */
190static void bchannel_activate(struct mISDNport *mISDNport, int i)
191{
192	iframe_t act;
193
194	/* we must activate if we are deactivated */
195	if (mISDNport->b_state[i] == B_STATE_IDLE)
196	{
197		/* activate bchannel */
198		PDEBUG("activating bchannel (index %d), because currently idle (address 0x%x).\n", i, mISDNport->b_addr[i]);
199		act.prim = DL_ESTABLISH | REQUEST; 
200		act.addr = mISDNport->b_addr[i] | FLG_MSG_DOWN;
201		act.dinfo = 0;
202		act.len = 0;
203		mISDN_write(mISDNdevice, &act, mISDN_HEADER_LEN+act.len, TIMEOUT_1SEC);
204		mISDNport->b_state[i] = B_STATE_ACTIVATING;
205		return;
206	}
207
208	/* if we are active, we configure our channel */
209	if (mISDNport->b_state[i] == B_STATE_ACTIVE)
210	{
211		/* it is an error if this channel is not associated with a port object */
212		PDEBUG("during activation, we add conference to %d.\n", ((mISDNport->count&(~1)) << 23) + (i<<16) + dsp_pid);
213		ph_control(mISDNport->b_addr[i], CMX_CONF_JOIN, ((mISDNport->count&(~1)) << 23) + (i<<16) + dsp_pid);
214		PDEBUG("during activation, we set rxoff.\n");
215		ph_control(mISDNport->b_addr[i], CMX_RECEIVE_OFF, 0);
216#if 0
217		if (sadks->crypt)
218		{
219			PDEBUG("during activation, we set crypt to crypt=%d.\n", mISDNport->b_port[i]->p_m_crypt);
220			ph_control_block(mISDNport->b_addr[i], BF_ENABLE_KEY, mISDNport->b_port[i]->p_m_crypt_key, mISDNport->b_port[i]->p_m_crypt_key_len);
221		}
222#endif
223	}
224}
225
226
227static void bchannel_deactivate(struct mISDNport *mISDNport, int i)
228{
229	iframe_t dact;
230
231	if (mISDNport->b_state[i] == B_STATE_ACTIVE)
232	{
233		ph_control(mISDNport->b_addr[i], CMX_CONF_SPLIT, 0);
234		ph_control(mISDNport->b_addr[i], CMX_RECEIVE_ON, 0);
235		/* deactivate bchannel */
236		PDEBUG("deactivating bchannel (index %d), because currently active.\n", i);
237		dact.prim = DL_RELEASE | REQUEST; 
238		dact.addr = mISDNport->b_addr[i] | FLG_MSG_DOWN;
239		dact.dinfo = 0;
240		dact.len = 0;
241		mISDN_write(mISDNdevice, &dact, mISDN_HEADER_LEN+dact.len, TIMEOUT_1SEC);
242		mISDNport->b_state[i] = B_STATE_DEACTIVATING;
243		return;
244	}
245}
246
247/*
248 * main loop for processing messages from mISDN device
249 */
250int mISDN_handler(void)
251{
252	iframe_t *frm;
253	struct mISDNport *mISDNport;
254	int i;
255	unsigned char data[2048];
256	int len;
257
258	/* get message from kernel */
259	len = mISDN_read(mISDNdevice, data, sizeof(data), 0);
260	if (len < 0)
261	{
262		if (errno == EAGAIN)
263			return(0);
264		fprintf(stderr, "FATAL ERROR: failed to do mISDN_read()\n");
265		exit(-1);
266	}
267	if (!len)
268	{
269		return(0);
270	}
271	frm = (iframe_t *)data;
272
273	/* global prim */
274	switch(frm->prim)
275	{
276		case MGR_INITTIMER | CONFIRM:
277		case MGR_ADDTIMER | CONFIRM:
278		case MGR_DELTIMER | CONFIRM:
279		case MGR_REMOVETIMER | CONFIRM:
280		return(1);
281	}
282
283	/* find the port */
284	mISDNport = mISDNport_first;
285	while(mISDNport)
286	{
287		if ((frm->addr&STACK_ID_MASK) == (unsigned int)(mISDNport->upper_id&STACK_ID_MASK))
288		{
289			/* d-message */
290			switch(frm->prim)
291			{
292				case MGR_SHORTSTATUS | INDICATION:
293				case MGR_SHORTSTATUS | CONFIRM:
294				switch(frm->dinfo) {
295					case SSTATUS_L1_ACTIVATED:
296					PDEBUG("Received SSTATUS_L1_ACTIVATED for port %d.\n", mISDNport->portnum);
297					goto ss_act;
298					case SSTATUS_L1_DEACTIVATED:
299					PDEBUG("Received SSTATUS_L1_DEACTIVATED for port %d.\n", mISDNport->portnum);
300					goto ss_deact;
301				}
302				break;
303
304				case PH_ACTIVATE | CONFIRM:
305				case PH_ACTIVATE | INDICATION:
306				PDEBUG("Received PH_ACTIVATE for port %d.\n", mISDNport->portnum);
307				ss_act:
308				if (!mISDNport->l1link)
309				{
310					mISDNport->l1link = 1;
311					show_state(mISDNport);
312				}
313				if (mISDNport->que_len)
314				{
315					PDEBUG("Data in que, due to inactive link on port %d.\n", mISDNport->portnum);
316					mISDN_write(mISDNdevice, mISDNport->que_frm, mISDNport->que_len, TIMEOUT_1SEC);
317					mISDNport->que_len = 0;
318				}
319				break;
320
321				case PH_DEACTIVATE | CONFIRM:
322				case PH_DEACTIVATE | INDICATION:
323				PDEBUG("Received PH_DEACTIVATE for port %d.\n", mISDNport->portnum);
324				ss_deact:
325				if (mISDNport->l1link)
326				{
327					mISDNport->l1link = 0;
328					show_state(mISDNport);
329				}
330				mISDNport->que_len = 0;
331				break;
332
333				case PH_CONTROL | CONFIRM:
334				case PH_CONTROL | INDICATION:
335				PDEBUG("Received PH_CONTROL for port %d.\n", mISDNport->portnum);
336				break;
337
338				case PH_DATA | INDICATION:
339				if (traffic)
340					show_traffic(mISDNport, data + mISDN_HEADER_LEN, frm->len);
341				PDEBUG("GOT data from %s port %d prim 0x%x dinfo 0x%x addr 0x%x\n", (mISDNport->ntmode)?"NT":"TE", mISDNport->portnum, frm->prim, frm->dinfo, frm->addr);
342				if (mISDNport->count & 1)
343				{
344					if (mISDNport->prev == NULL)
345					{
346						printf("soft error, no prev where expected.\n");
347						exit (0);
348					}
349					/* sending to previous port */
350					frm->prim = PH_DATA | REQUEST;
351					frm->addr = mISDNport->prev->upper_id | FLG_MSG_DOWN;
352				PDEBUG("sending to %s port %d prim 0x%x dinfo 0x%x addr 0x%x\n", (mISDNport->prev->ntmode)?"NT":"TE", mISDNport->prev->portnum, frm->prim, frm->dinfo, frm->addr);
353					if (mISDNport->prev->l1link)
354						mISDN_write(mISDNdevice, frm, mISDN_HEADER_LEN+frm->len, TIMEOUT_1SEC);
355					else {
356						PDEBUG("layer 1 is down, so we queue and activate link.\n");
357						memcpy(mISDNport->prev->que_frm, frm, len);
358						mISDNport->prev->que_len = len;
359						frm->prim = PH_ACTIVATE | REQUEST; 
360						frm->dinfo = 0;
361						frm->len = 0;
362						mISDN_write(mISDNdevice, frm, mISDN_HEADER_LEN+frm->len, TIMEOUT_1SEC);
363					}
364				} else {
365
366					if (mISDNport->next == NULL)
367					{
368						printf("soft error, no next where expected.\n");
369						exit (0);
370					}
371					/* sending to next port */
372					frm->prim = PH_DATA | REQUEST; 
373					frm->addr = mISDNport->next->upper_id | FLG_MSG_DOWN;
374				PDEBUG("sending to %s port %d prim 0x%x dinfo 0x%x addr 0x%x\n", (mISDNport->next->ntmode)?"NT":"TE", mISDNport->next->portnum, frm->prim, frm->dinfo, frm->addr);
375					if (mISDNport->next->l1link)
376						mISDN_write(mISDNdevice, frm, mISDN_HEADER_LEN+frm->len, TIMEOUT_1SEC);
377					else {
378						PDEBUG("layer 1 is down, so we queue and activate link.\n");
379						memcpy(mISDNport->next->que_frm, frm, len);
380						mISDNport->next->que_len = len;
381						frm->prim = PH_ACTIVATE | REQUEST; 
382						frm->dinfo = 0;
383						frm->len = 0;
384						mISDN_write(mISDNdevice, frm, mISDN_HEADER_LEN+frm->len, TIMEOUT_1SEC);
385					}
386				}
387				break;
388
389				case PH_DATA | CONFIRM:
390				//PDEBUG("GOT confirm from %s port %d prim 0x%x dinfo 0x%x addr 0x%x\n", (mISDNport->ntmode)?"NT":"TE", mISDNport->portnum, frm->prim, frm->dinfo, frm->addr);
391				break;
392
393				case PH_DATA | REQUEST:
394				PDEBUG("GOT strange PH_DATA REQUEST from %s port %d prim 0x%x dinfo 0x%x addr 0x%x\n", (mISDNport->ntmode)?"NT":"TE", mISDNport->portnum, frm->prim, frm->dinfo, frm->addr);
395				break;
396
397				default:
398				break;
399			}
400			break;
401		}
402//PDEBUG("flg:%d upper_id=%x addr=%x\n", (frm->addr&FLG_CHILD_STACK), (mISDNport->b_addr[0])&(~IF_CHILDMASK), (frm->addr)&(~IF_CHILDMASK));
403		/* check if child, and if parent stack match */
404		if ((frm->addr&FLG_CHILD_STACK) && (((unsigned int)(mISDNport->b_addr[0])&(~CHILD_ID_MASK)&STACK_ID_MASK) == ((frm->addr)&(~CHILD_ID_MASK)&STACK_ID_MASK)))
405		{
406			/* b-message */
407			switch(frm->prim)
408			{
409				/* we don't care about confirms, we use rx data to sync tx */
410				case PH_DATA | CONFIRM:
411				case DL_DATA | CONFIRM:
412				break;
413
414				/* we receive audio data, we respond to it AND we send tones */
415				case PH_DATA | INDICATION:
416				case DL_DATA | INDICATION:
417				case PH_CONTROL | INDICATION:
418				i = 0;
419				while(i < mISDNport->b_num)
420				{
421					if ((unsigned int)(mISDNport->b_addr[i]&STACK_ID_MASK) == (frm->addr&STACK_ID_MASK))
422						break;
423					i++;
424				}
425				if (i == mISDNport->b_num)
426				{
427					fprintf(stderr, "unhandled b-message (address 0x%x).\n", frm->addr);
428					break;
429				}
430				PDEBUG("got B-channel data, this should not happen all the time. (just a few until cmx release tx-data are ok)\n");
431				break;
432
433				case PH_ACTIVATE | INDICATION:
434				case DL_ESTABLISH | INDICATION:
435				case PH_ACTIVATE | CONFIRM:
436				case DL_ESTABLISH | CONFIRM:
437				PDEBUG("DL_ESTABLISH confirm: bchannel is now activated (address 0x%x).\n", frm->addr);
438				i = 0;
439				while(i < mISDNport->b_num)
440				{
441					if ((unsigned int)(mISDNport->b_addr[i]&STACK_ID_MASK) == (frm->addr&STACK_ID_MASK))
442						break;
443					i++;
444				}
445				if (i == mISDNport->b_num)
446				{
447					fprintf(stderr, "unhandled b-establish (address 0x%x).\n", frm->addr);
448					break;
449				}
450				mISDNport->b_state[i] = B_STATE_ACTIVE;
451				bchannel_activate(mISDNport, i);
452				break;
453
454				case PH_DEACTIVATE | INDICATION:
455				case DL_RELEASE | INDICATION:
456				case PH_DEACTIVATE | CONFIRM:
457				case DL_RELEASE | CONFIRM:
458				PDEBUG("DL_RELEASE confirm: bchannel is now de-activated (address 0x%x).\n", frm->addr);
459				i = 0;
460				while(i < mISDNport->b_num)
461				{
462					if ((unsigned int)(mISDNport->b_addr[i]&STACK_ID_MASK) == (frm->addr&STACK_ID_MASK))
463						break;
464					i++;
465				}
466				if (i == mISDNport->b_num)
467				{
468					fprintf(stderr, "unhandled b-release (address 0x%x).\n", frm->addr);
469					break;
470				}
471				mISDNport->b_state[i] = B_STATE_IDLE;
472				break;
473			}
474			break;
475		}
476
477		mISDNport = mISDNport->next;
478	} 
479	if (!mISDNport)
480	{
481		if (frm->prim == (MGR_TIMER | INDICATION))
482			fprintf(stderr, "unhandled timer indication message: prim(0x%x) addr(0x%x) len(%d)\n", frm->prim, frm->addr, len);
483		else
484			fprintf(stderr, "unhandled message: prim(0x%x) addr(0x%x) len(%d)\n", frm->prim, frm->addr, len);
485	}
486
487	return(1);
488}
489
490
491/*
492 * global function to add a new card (port)
493 */
494struct mISDNport *mISDN_port_open(int port)
495{
496	int ret;
497	unsigned char buff[1025];
498	iframe_t *frm = (iframe_t *)buff;
499	stack_info_t *stinf;
500	struct mISDNport *mISDNport, **mISDNportp, *mISDNport_prev;
501	int i, cnt;
502	layer_info_t li;
503//	interface_info_t ii;
504	mISDN_pid_t pid;
505	int pri = 0;
506	int nt = 0;
507	iframe_t dact;
508
509	/* open mISDNdevice if not already open */
510	if (mISDNdevice < 0)
511	{
512		ret = mISDN_open();
513		if (ret < 0)
514		{
515			fprintf(stderr, "cannot open mISDN device ret=%d errno=%d (%s) Check for mISDN modules!\nAlso did you create \"/dev/mISDN\"? Do: \"mknod /dev/mISDN c 46 0\"\n", ret, errno, strerror(errno));
516			return(0);
517		}
518		mISDNdevice = ret;
519		PDEBUG("mISDN device opened.\n");
520
521		/* create entity for layer 3 TE-mode */
522		mISDN_write_frame(mISDNdevice, buff, 0, MGR_NEWENTITY | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
523		ret = mISDN_read_frame(mISDNdevice, frm, sizeof(iframe_t), 0, MGR_NEWENTITY | CONFIRM, TIMEOUT_1SEC);
524		if (ret < (int)mISDN_HEADER_LEN)
525		{
526			noentity:
527			fprintf(stderr, "cannot request MGR_NEWENTITY from mISDN. Exitting due to software bug.");
528			exit(-1);
529		}
530		entity = frm->dinfo & 0xffff;
531		if (!entity)
532			goto noentity;
533		PDEBUG("our entity for l3-processes is %d.\n", entity);
534	}
535
536	/* query port's requirements */
537	cnt = mISDN_get_stack_count(mISDNdevice);
538	if (cnt <= 0)
539	{
540		fprintf(stderr, "Found no card. Please be sure to load card drivers.\n");
541		return(0);
542	}
543	if (port>cnt || port<1)
544	{
545		fprintf(stderr, "Port (%d) given is out of existing port range (%d-%d)\n", port, 1, cnt);
546		return(0);
547	}
548	ret = mISDN_get_stack_info(mISDNdevice, port, buff, sizeof(buff));
549	if (ret < 0)
550	{
551		fprintf(stderr, "Cannot get stack info for port %d (ret=%d)\n", port, ret);
552		return(0);
553	}
554	stinf = (stack_info_t *)&frm->data.p;
555	switch(stinf->pid.protocol[0] & ~ISDN_PID_FEATURE_MASK)
556	{
557		case ISDN_PID_L0_TE_S0:
558		PDEBUG("TE-mode BRI S/T interface line\n");
559		break;
560		case ISDN_PID_L0_NT_S0:
561		PDEBUG("NT-mode BRI S/T interface port\n");
562		nt = 1;
563		break;
564		case ISDN_PID_L0_TE_E1:
565		PDEBUG("TE-mode PRI E1  interface line\n");
566		pri = 1;
567		break;
568		case ISDN_PID_L0_NT_E1:
569		PDEBUG("LT-mode PRI E1  interface port\n");
570		pri = 1;
571		nt = 1;
572		break;
573		default:
574		fprintf(stderr, "unknown port(%d) type 0x%08x\n", port, stinf->pid.protocol[0]);
575		return(0);
576	}
577	if (stinf->pid.protocol[1] == 0)
578	{
579		fprintf(stderr, "Given port %d: Missing layer 1 protocol.\n", port);
580		return(0);
581	}
582	if (stinf->pid.protocol[2])
583	{
584		fprintf(stderr, "Given port %d: Layer 2 protocol 0x%08x is detected, but not allowed for bridging layer 1.\n", port, stinf->pid.protocol[2]);
585		return(0);
586	}
587
588	/* add mISDNport structure */
589	mISDNport = mISDNport_first;
590	mISDNportp = &mISDNport_first;
591	mISDNport_prev = NULL;
592	while(mISDNport)
593	{
594		mISDNport_prev=mISDNport;
595		mISDNportp = &mISDNport->next;
596		mISDNport = mISDNport->next;
597	}
598	mISDNport = (struct mISDNport *)calloc(1, sizeof(struct mISDNport));
599	if (!mISDNport)
600	{
601		fprintf(stderr, "Cannot alloc mISDNport structure\n");
602		return(0);
603	}
604	memset(mISDNport, 0, sizeof(mISDNport));
605	*mISDNportp = mISDNport;
606	mISDNport->prev = mISDNport_prev;
607
608	/* allocate ressources of port */
609	mISDNport->count = portcount++;
610	mISDNport->portnum = port;
611	mISDNport->ntmode = nt;
612	mISDNport->pri = pri;
613	mISDNport->d_stid = stinf->id;
614	PDEBUG("d_stid = 0x%x.\n", mISDNport->d_stid);
615	mISDNport->b_num = stinf->childcnt;
616	PDEBUG("Port has %d b-channels.\n", mISDNport->b_num);
617	i = 0;
618	while(i < stinf->childcnt)
619	{
620		mISDNport->b_stid[i] = stinf->child[i];
621		PDEBUG("b_stid[%d] = 0x%x.\n", i, mISDNport->b_stid[i]);
622		i++;
623	}
624	memset(&li, 0, sizeof(li));
625	strcpy(&li.name[0], "bridge l2");
626	li.object_id = -1;
627	li.extentions = 0;
628	li.pid.protocol[2] = (nt)?ISDN_PID_L2_LAPD_NET:ISDN_PID_L2_LAPD;
629	li.pid.layermask = ISDN_LAYER(2);
630	li.st = mISDNport->d_stid;
631	ret = mISDN_new_layer(mISDNdevice, &li);
632	if (ret)
633	{
634		fprintf(stderr, "Cannot add layer 2 of port %d (ret %d)\n", port, ret);
635		return(0);
636	}
637	mISDNport->upper_id = li.id;
638	ret = mISDN_register_layer(mISDNdevice, mISDNport->d_stid, mISDNport->upper_id);
639	if (ret)
640	{
641		fprintf(stderr, "Cannot register layer 2 of port %d\n", port);
642		return(0);
643	}
644	mISDNport->lower_id = mISDN_get_layerid(mISDNdevice, mISDNport->d_stid, 1);
645	if (mISDNport->lower_id < 0)
646	{
647		fprintf(stderr, "Cannot get layer(1) id of port %d\n", port);
648		return(0);
649	}
650	mISDNport->upper_id = mISDN_get_layerid(mISDNdevice, mISDNport->d_stid, 2);
651	if (mISDNport->upper_id < 0)
652	{
653		fprintf(stderr, "Cannot get layer(2) id of port %d\n", port);
654		return(0);
655	}
656	PDEBUG("Layer 2 of port %d added.\n", port);
657
658	/* try to activate link layer 1 */
659	{
660		iframe_t act;
661		/* L1 */
662		PDEBUG("sending PH_ACTIVATE to port %d.\n", port);
663		act.prim = PH_ACTIVATE | REQUEST; 
664		act.addr = mISDNport->upper_id | FLG_MSG_DOWN;
665		act.dinfo = 0;
666		act.len = 0;
667		mISDN_write(mISDNdevice, &act, mISDN_HEADER_LEN+act.len, TIMEOUT_1SEC);
668	}
669	/* initially, we assume that the link is down */
670	mISDNport->l1link = 0;
671
672	PDEBUG("using 'mISDN_dsp.o' module\n");
673
674	/* add all bchannel layers */
675	i = 0;
676	while(i < mISDNport->b_num)
677	{
678		mISDNport->b_state[i] = B_STATE_IDLE;
679		/* create new layer */
680		PDEBUG("creating bchannel %d (index %d).\n" , i+1+(i>=15), i);
681		memset(&li, 0, sizeof(li));
682		memset(&pid, 0, sizeof(pid));
683		li.object_id = -1;
684		li.extentions = 0;
685		li.st = mISDNport->b_stid[i];
686		strcpy(li.name, "B L4");
687		li.pid.layermask = ISDN_LAYER((4));
688		li.pid.protocol[4] = ISDN_PID_L4_B_USER;
689		ret = mISDN_new_layer(mISDNdevice, &li);
690		if (ret)
691		{
692			failed_new_layer:
693			fprintf(stderr, "mISDN_new_layer() failed to add bchannel %d (index %d)\n", i+1+(i>=15), i);
694			return(0);
695		}
696		mISDNport->b_addr[i] = li.id;
697		if (!li.id)
698		{
699			goto failed_new_layer;
700		}
701		PDEBUG("new layer (b_addr=0x%x)\n", mISDNport->b_addr[i]);
702
703		/* create new stack */
704		pid.protocol[1] = ISDN_PID_L1_B_64TRANS;
705		pid.protocol[2] = ISDN_PID_L2_B_TRANS;
706		pid.protocol[3] = ISDN_PID_L3_B_DSP;
707		pid.protocol[4] = ISDN_PID_L4_B_USER;
708		pid.layermask = ISDN_LAYER((1)) | ISDN_LAYER((2)) | ISDN_LAYER((3)) | ISDN_LAYER((4));
709		ret = mISDN_set_stack(mISDNdevice, mISDNport->b_stid[i], &pid);
710		if (ret)
711		{
712			stack_error:
713			fprintf(stderr, "mISDN_set_stack() failed (ret=%d) to add bchannel (index %d) stid=0x%x\n", ret, i, mISDNport->b_stid[i]);
714			mISDN_write_frame(mISDNdevice, buff, mISDNport->b_addr[i], MGR_DELLAYER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
715			mISDNport->b_addr[i] = 0;
716			return(0);
717		}
718		ret = mISDN_get_setstack_ind(mISDNdevice, mISDNport->b_addr[i]);
719		if (ret)
720			goto stack_error;
721
722		/* get layer id */
723		mISDNport->b_addr[i] = mISDN_get_layerid(mISDNdevice, mISDNport->b_stid[i], 4);
724		if (!mISDNport->b_addr[i])
725			goto stack_error;
726		/* deactivate bchannel if already enabled due to crash */
727		PDEBUG("deactivating bchannel (index %d) as a precaution.\n", i);
728		dact.prim = DL_RELEASE | REQUEST; 
729		dact.addr = mISDNport->b_addr[i] | FLG_MSG_DOWN;
730		dact.dinfo = 0;
731		dact.len = 0;
732		mISDN_write(mISDNdevice, &dact, mISDN_HEADER_LEN+dact.len, TIMEOUT_1SEC);
733
734		i++;
735	}
736	PDEBUG("using port %d %s %d b-channels\n", mISDNport->portnum, (mISDNport->ntmode)?"NT-mode":"TE-mode", mISDNport->b_num);
737	return(mISDNport);
738}
739
740
741/*
742 * global function to free ALL cards (ports)
743 */
744void mISDN_port_close(void)
745{
746	struct mISDNport *mISDNport, *mISDNporttemp;
747	unsigned char buf[32];
748	int i;
749
750	/* free all ports */
751	mISDNport = mISDNport_first;
752	while(mISDNport)
753	{
754		i = 0;
755		while(i < mISDNport->b_num)
756		{
757			bchannel_deactivate(mISDNport, i);
758			PDEBUG("freeing %s port %d bchannel (index %d).\n", (mISDNport->ntmode)?"NT":"TE", mISDNport->portnum, i);
759			if (mISDNport->b_stid[i])
760			{
761				mISDN_clear_stack(mISDNdevice, mISDNport->b_stid[i]);
762				if (mISDNport->b_addr[i])
763					mISDN_write_frame(mISDNdevice, buf, mISDNport->b_addr[i] | FLG_MSG_DOWN, MGR_DELLAYER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
764			}
765			i++;
766		}
767
768		PDEBUG("freeing d-stack.\n");
769		if (mISDNport->d_stid)
770		{
771//			mISDN_clear_stack(mISDNdevice, mISDNport->d_stid);
772			if (mISDNport->lower_id)
773				mISDN_write_frame(mISDNdevice, buf, mISDNport->lower_id, MGR_DELLAYER | REQUEST, 0, 0, NULL, TIMEOUT_1SEC);
774		}
775
776		mISDNporttemp = mISDNport;
777		mISDNport = mISDNport->next;
778		memset(mISDNporttemp, 0, sizeof(struct mISDNport));
779		free(mISDNporttemp);
780	}
781	mISDNport_first = NULL;
782	
783	/* close mISDNdevice */
784	if (mISDNdevice >= 0)
785	{
786		/* free entity */
787		mISDN_write_frame(mISDNdevice, buf, 0, MGR_DELENTITY | REQUEST, entity, 0, NULL, TIMEOUT_1SEC);
788		/* close device */
789		mISDN_close(mISDNdevice);
790		mISDNdevice = -1;
791		PDEBUG("mISDN device closed.\n");
792	}
793}
794
795
796/*
797 * main routine and loop
798 */
799int main(int argc, char *argv[])
800{
801	struct mISDNport *mISDNport_a, *mISDNport_b;
802	int i, j;
803	int forking = 0;
804
805	if (argc <= 1)
806	{
807		usage:
808		printf("Usage: %s [--<option> [...]] <port a> <port b> [<port a> <port b> [...]]\n\n", argv[0]);
809		printf("Bridges given pairs of ports. The number of given ports must be even.\n");
810		printf("Each pair of ports must be the same interface size (equal channel number).\n");
811		printf("Both ports may have same mode, e.g. TE-mode, to bridge ISDN to leased line.\n");
812		printf("Also bridging a card to ISDN over IP tunnel is possible. (L1oIP)\n");
813		printf("Note: Ports must have layer 1 only, so layermask must be 0x3 to make it work.\n");
814		printf("--fork will make a daemon fork.\n");
815		printf("--traffic will show D-channel traffic.\n");
816		printf("--debug will show debug info.\n");
817		return(0);
818	}
819	if (strstr("help", argv[1]))
820		goto usage;
821
822	/* open mISDN */
823	i = 1;
824	while (i < argc)
825	{
826		usleep(200000);
827		if (!strcmp(argv[i], "--traffic"))
828		{
829			traffic = 1;
830			i++;
831			continue;
832		}
833		if (!strcmp(argv[i], "--fork"))
834		{
835			forking = 1;
836			i++;
837			continue;
838		}
839		if (!strcmp(argv[i], "--debug"))
840		{
841			debug = 1;
842			i++;
843			continue;
844		}
845
846		/* open port a */
847		mISDNport_a = mISDN_port_open(strtol(argv[i], NULL, 0));
848		if (!mISDNport_a)
849			goto error;
850		printf("port A: #%d %s, %d b-channels\n", mISDNport_a->portnum, (mISDNport_a->ntmode)?"NT-mode":"TE-mode", mISDNport_a->b_num);
851		i++; // two ports at the same time
852		if (i == argc)
853		{
854			fprintf(stderr, "The number of ports given are not even.\nYou may only bridge two or more pairs of ports.\n\n");
855			goto error;
856		}
857		mISDNport_b = mISDN_port_open(strtol(argv[i], NULL, 0));
858		if (!mISDNport_b)
859			goto error;
860		/* open port b */
861		printf("port B: #%d %s, %d b-channels\n", mISDNport_b->portnum, (mISDNport_b->ntmode)?"NT-mode":"TE-mode", mISDNport_b->b_num);
862		i++; // two ports at the same time
863
864		if (mISDNport_a->b_num != mISDNport_b->b_num)
865		{
866			fprintf(stderr, "The pair of ports are not compatible for bridging.\n");
867			fprintf(stderr, "The number ob B-channels are different: port(%d)=%d, port(%d)=%d\n", mISDNport_a->portnum, mISDNport_a->b_num, mISDNport_b->portnum, mISDNport_b->b_num);
868
869			mISDN_port_close();
870			goto error;
871		}
872
873		/* opening and bridge each pair of bchannels */
874		j = 0;
875		while(j < mISDNport_a->b_num)
876		{
877			bchannel_activate(mISDNport_a, j);
878			while(mISDN_handler())
879				;
880			j++;
881		}
882		j = 0;
883		while(j < mISDNport_b->b_num)
884		{
885			bchannel_activate(mISDNport_b, j);
886			while(mISDN_handler())
887				;
888			j++;
889		}
890	}
891
892	printf("%s now started\n",argv[0]);
893
894	/* forking */
895	if (forking) {
896		pid_t pid;
897
898		/* do daemon fork */
899		pid = fork();
900
901		if (pid < 0)
902		{
903			fprintf(stderr, "Cannot fork!\n");
904			goto free;
905		}
906		if (pid != 0)
907		{
908			exit(0);
909		}
910		usleep(200000);
911		printf("\n");
912		
913		/* do second fork */
914		pid = fork();
915
916		if (pid < 0)
917		{
918			fprintf(stderr, "Cannot fork!\n");
919			goto free;
920		}
921		if (pid != 0)
922		{
923			printf("%s: Starting daemon.\n", argv[0]);
924			exit(0);
925		}
926		nooutput = 1;
927	}
928	dsp_pid = getpid();
929	
930	/* signal handlers */	
931	signal(SIGINT,sighandler);
932	signal(SIGHUP,sighandler);
933	signal(SIGTERM,sighandler);
934	signal(SIGPIPE,sighandler);
935
936	while(!quit)
937	{
938		//mISDNport_a->l1link = 1;
939		if (!mISDN_handler())
940			usleep(30000);
941	}
942
943	/* remove signal handler */
944	signal(SIGINT,SIG_DFL);
945	signal(SIGHUP,SIG_DFL);
946	signal(SIGTERM,SIG_DFL);
947	signal(SIGPIPE,SIG_DFL);
948
949free:
950	mISDN_port_close();
951	return(0);
952
953	error:
954	return(-1);
955}
956
957