1 /*
2 * Copyright (c) 1997, 2000 Hellmuth Michaelis. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 *
25 *---------------------------------------------------------------------------
26 *
27 * i4b_i4bdrv.c - i4b userland interface driver
28 * --------------------------------------------
29 *
30 * $Id: i4b_i4bdrv.c,v 1.30 2006/11/16 01:33:49 christos Exp $
31 *
32 * $FreeBSD$
33 *
34 * last edit-date: [Fri Jan 5 11:33:47 2001]
35 *
36 *---------------------------------------------------------------------------*/
37
38 #include <sys/cdefs.h>
39 __KERNEL_RCSID(0, "$NetBSD: i4b_i4bdrv.c,v 1.30 2006/11/16 01:33:49 christos Exp $");
40
41 #include "isdn.h"
42
43 #if NISDN > 0
44
45 #include <sys/param.h>
46
47 #if defined(__FreeBSD__)
48 #include <sys/ioccom.h>
49 #include <sys/malloc.h>
50 #include <sys/uio.h>
51 #else
52 #include <sys/ioctl.h>
53 #endif
54
55 #include <sys/kernel.h>
56 #include <sys/systm.h>
57 #include <sys/conf.h>
58 #include <sys/mbuf.h>
59 #include <sys/proc.h>
60 #include <sys/fcntl.h>
61 #include <sys/socket.h>
62 #include <sys/select.h>
63 #include <net/if.h>
64
65 #ifdef __FreeBSD__
66
67 #if defined(__FreeBSD__) && __FreeBSD__ == 3
68 #include "opt_devfs.h"
69 #endif
70
71 #ifdef DEVFS
72 #include <sys/devfsext.h>
73 #endif
74
75 #endif /* __FreeBSD__*/
76
77 #ifdef __FreeBSD__
78 #include <machine/i4b_debug.h>
79 #include <machine/i4b_ioctl.h>
80 #include <machine/i4b_cause.h>
81 #else
82 #include <netisdn/i4b_debug.h>
83 #include <netisdn/i4b_ioctl.h>
84 #include <netisdn/i4b_cause.h>
85 #endif
86
87 #include <netisdn/i4b_l3l4.h>
88 #include <netisdn/i4b_mbuf.h>
89 #include <netisdn/i4b_global.h>
90
91 #include <netisdn/i4b_l4.h>
92
93 #ifdef OS_USES_POLL
94 #include <sys/poll.h>
95 #endif
96
97 struct selinfo select_rd_info;
98
99 static struct ifqueue i4b_rdqueue;
100 static int openflag = 0;
101 static int selflag = 0;
102 static int readflag = 0;
103
104 #if defined(__FreeBSD__) && __FreeBSD__ == 3
105 #ifdef DEVFS
106 static void *devfs_token;
107 #endif
108 #endif
109
110 #ifndef __FreeBSD__
111
112 #define PDEVSTATIC /* - not static - */
113 PDEVSTATIC void isdnattach __P((void));
114 PDEVSTATIC int isdnopen __P((dev_t dev, int flag, int fmt, struct lwp *l));
115 PDEVSTATIC int isdnclose __P((dev_t dev, int flag, int fmt, struct lwp *l));
116 PDEVSTATIC int isdnread __P((dev_t dev, struct uio *uio, int ioflag));
117 PDEVSTATIC int isdnioctl __P((dev_t dev, u_long cmd, caddr_t data, int flag, struct lwp *l));
118
119 #ifdef OS_USES_POLL
120 PDEVSTATIC int isdnpoll __P((dev_t dev, int events, struct lwp *l));
121 PDEVSTATIC int isdnkqfilter __P((dev_t dev, struct knote *kn));
122 #else
123 PDEVSTATIC int isdnselect __P((dev_t dev, int rw, struct lwp *l));
124 #endif
125
126 #endif /* #ifndef __FreeBSD__ */
127
128 #if BSD > 199306 && defined(__FreeBSD__)
129
130 #define PDEVSTATIC static
131
132 PDEVSTATIC d_open_t i4bopen;
133 PDEVSTATIC d_close_t i4bclose;
134 PDEVSTATIC d_read_t i4bread;
135 PDEVSTATIC d_ioctl_t i4bioctl;
136
137 #ifdef OS_USES_POLL
138 PDEVSTATIC d_poll_t i4bpoll;
139 #define POLLFIELD i4bpoll
140 #else
141 PDEVSTATIC d_select_t i4bselect;
142 #define POLLFIELD i4bselect
143 #endif
144
145 #define CDEV_MAJOR 60
146
147 #if defined(__FreeBSD__) && __FreeBSD__ >= 4
148 static struct cdevsw i4b_cdevsw = {
149 /* open */ i4bopen,
150 /* close */ i4bclose,
151 /* read */ i4bread,
152 /* write */ nowrite,
153 /* ioctl */ i4bioctl,
154 /* poll */ POLLFIELD,
155 /* mmap */ nommap,
156 /* strategy */ nostrategy,
157 /* name */ "i4b",
158 /* maj */ CDEV_MAJOR,
159 /* dump */ nodump,
160 /* psize */ nopsize,
161 /* flags */ 0,
162 /* bmaj */ -1
163 };
164 #else
165 static struct cdevsw i4b_cdevsw = {
166 i4bopen, i4bclose, i4bread, nowrite,
167 i4bioctl, nostop, nullreset, nodevtotty,
168 POLLFIELD, nommap, NULL, "i4b", NULL, -1
169 };
170 #endif
171
172 PDEVSTATIC void i4battach(void *);
173 PSEUDO_SET(i4battach, i4b_i4bdrv);
174
175 static void
176 i4b_drvinit(void *unused)
177 {
178 #if defined(__FreeBSD__) && __FreeBSD__ >= 4
179 cdevsw_add(&i4b_cdevsw);
180 #else
181 static int i4b_devsw_installed = 0;
182 dev_t dev;
183
184 if( ! i4b_devsw_installed )
185 {
186 dev = makedev(CDEV_MAJOR,0);
187 cdevsw_add(&dev,&i4b_cdevsw,NULL);
188 i4b_devsw_installed = 1;
189 }
190 #endif
191 }
192
193 SYSINIT(i4bdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,i4b_drvinit,NULL)
194
195 #endif /* BSD > 199306 && defined(__FreeBSD__) */
196
197 #ifdef __NetBSD__
198 const struct cdevsw isdn_cdevsw = {
199 isdnopen, isdnclose, isdnread, nowrite, isdnioctl,
200 nostop, notty, isdnpoll, nommap, isdnkqfilter, D_OTHER
201 };
202 #endif /* __NetBSD__ */
203
204 #ifdef __bsdi__
205 #include <sys/device.h>
206 int i4bmatch(struct device *parent, struct cfdata *cf, void *aux);
207 void dummy_i4battach(struct device*, struct device *, void *);
208
209 #define CDEV_MAJOR 65
210
211 static struct cfdriver i4bcd =
212 { NULL, "i4b", i4bmatch, dummy_i4battach, DV_DULL,
213 sizeof(struct cfdriver) };
214 struct devsw i4bsw =
215 { &i4bcd,
216 i4bopen, i4bclose, i4bread, nowrite,
217 i4bioctl, i4bselect, nommap, nostrat,
218 nodump, nopsize, 0, nostop
219 };
220
221 int
222 i4bmatch(struct device *parent, struct cfdata *cf, void *aux)
223 {
224 printf("i4bmatch: aux=0x%x\n", aux);
225 return 1;
226 }
227 void
228 dummy_i4battach(struct device *parent, struct device *self, void *aux)
229 {
230 printf("dummy_i4battach: aux=0x%x\n", aux);
231 }
232 #endif /* __bsdi__ */
233
234 /*---------------------------------------------------------------------------*
235 * interface attach routine
236 *---------------------------------------------------------------------------*/
237 PDEVSTATIC void
238 #ifdef __FreeBSD__
239 isdnattach(void *dummy)
240 #else
241 isdnattach()
242 #endif
243 {
244 i4b_rdqueue.ifq_maxlen = IFQ_MAXLEN;
245
246 #if defined(__FreeBSD__)
247 #if __FreeBSD__ == 3
248
249 #ifdef DEVFS
250 devfs_token = devfs_add_devswf(&i4b_cdevsw, 0, DV_CHR,
251 UID_ROOT, GID_WHEEL, 0600,
252 "i4b");
253 #endif
254
255 #else
256 make_dev(&i4b_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "i4b");
257 #endif
258 #endif
259 }
260
261 /*---------------------------------------------------------------------------*
262 * i4bopen - device driver open routine
263 *---------------------------------------------------------------------------*/
264 PDEVSTATIC int
265 isdnopen(dev_t dev, int flag, int fmt, struct lwp *l)
266 {
267 int x;
268
269 if(minor(dev))
270 return(ENXIO);
271
272 if(openflag)
273 return(EBUSY);
274
275 x = splnet();
276 openflag = 1;
277 i4b_l4_daemon_attached();
278 splx(x);
279
280 return(0);
281 }
282
283 /*---------------------------------------------------------------------------*
284 * i4bclose - device driver close routine
285 *---------------------------------------------------------------------------*/
286 PDEVSTATIC int
287 isdnclose(dev_t dev, int flag, int fmt,
288 struct lwp *l)
289 {
290 int x = splnet();
291 openflag = 0;
292 i4b_l4_daemon_detached();
293 i4b_Dcleanifq(&i4b_rdqueue);
294 splx(x);
295 return(0);
296 }
297
298 /*---------------------------------------------------------------------------*
299 * i4bread - device driver read routine
300 *---------------------------------------------------------------------------*/
301 PDEVSTATIC int
302 isdnread(dev_t dev, struct uio *uio, int ioflag)
303 {
304 struct mbuf *m;
305 int x;
306 int error = 0;
307
308 if(minor(dev))
309 return(ENODEV);
310
311 x = splnet();
312 while(IF_QEMPTY(&i4b_rdqueue))
313 {
314 readflag = 1;
315 error = tsleep((caddr_t) &i4b_rdqueue, (PZERO + 1) | PCATCH, "bird", 0);
316 if (error != 0) {
317 splx(x);
318 return error;
319 }
320 }
321
322 IF_DEQUEUE(&i4b_rdqueue, m);
323
324 splx(x);
325
326 if(m && m->m_len)
327 error = uiomove(m->m_data, m->m_len, uio);
328 else
329 error = EIO;
330
331 if(m)
332 i4b_Dfreembuf(m);
333
334 return(error);
335 }
336
337 /*---------------------------------------------------------------------------*
338 * i4bioctl - device driver ioctl routine
339 *---------------------------------------------------------------------------*/
340 PDEVSTATIC int
341 isdnioctl(dev_t dev, u_long cmd, caddr_t data, int flag,
342 struct lwp *l)
343 {
344 struct isdn_l3_driver *d;
345 call_desc_t *cd;
346 int error = 0;
347
348 if(minor(dev))
349 return(ENODEV);
350
351 switch(cmd)
352 {
353 /* cdid request, reserve cd and return cdid */
354
355 case I4B_CDID_REQ:
356 {
357 msg_cdid_req_t *mir;
358 mir = (msg_cdid_req_t *)data;
359 cd = reserve_cd();
360 mir->cdid = cd->cdid;
361 break;
362 }
363
364 /* connect request, dial out to remote */
365
366 case I4B_CONNECT_REQ:
367 {
368 msg_connect_req_t *mcr;
369 mcr = (msg_connect_req_t *)data; /* setup ptr */
370
371 if((cd = cd_by_cdid(mcr->cdid)) == NULL)/* get cd */
372 {
373 NDBGL4(L4_ERR, "I4B_CONNECT_REQ ioctl, cdid not found!");
374 error = EINVAL;
375 break;
376 }
377 cd->isdnif = -1;
378 cd->l3drv = NULL;
379
380 d = isdn_find_l3_by_isdnif(mcr->controller);
381 if (d == NULL) {
382 error = EINVAL;
383 break;
384 }
385
386 /* prevent dialling on leased lines */
387 if(d->protocol == PROTOCOL_D64S)
388 {
389 SET_CAUSE_TYPE(cd->cause_in, CAUSET_I4B);
390 SET_CAUSE_VAL(cd->cause_in, CAUSE_I4B_LLDIAL);
391 i4b_l4_disconnect_ind(cd);
392 freecd_by_cd(cd);
393 break;
394 }
395
396 cd->isdnif = mcr->controller; /* fill cd */
397 cd->l3drv = d;
398 cd->bprot = mcr->bprot;
399 cd->bchan_driver_index = mcr->driver;
400 cd->bchan_driver_unit = mcr->driver_unit;
401 cd->cr = get_rand_cr(cd->isdnif);
402
403 cd->shorthold_data.shorthold_algorithm = mcr->shorthold_data.shorthold_algorithm;
404 cd->shorthold_data.unitlen_time = mcr->shorthold_data.unitlen_time;
405 cd->shorthold_data.idle_time = mcr->shorthold_data.idle_time;
406 cd->shorthold_data.earlyhup_time = mcr->shorthold_data.earlyhup_time;
407
408 cd->last_aocd_time = 0;
409 if(mcr->unitlen_method == ULEN_METHOD_DYNAMIC)
410 cd->aocd_flag = 1;
411 else
412 cd->aocd_flag = 0;
413
414 cd->cunits = 0;
415
416 cd->max_idle_time = 0; /* this is outgoing */
417
418 cd->dir = DIR_OUTGOING;
419
420 NDBGL4(L4_TIMO, "I4B_CONNECT_REQ times, algorithm=%ld unitlen=%ld idle=%ld earlyhup=%ld",
421 (long)cd->shorthold_data.shorthold_algorithm, (long)cd->shorthold_data.unitlen_time,
422 (long)cd->shorthold_data.idle_time, (long)cd->shorthold_data.earlyhup_time);
423
424 strlcpy(cd->dst_telno, mcr->dst_telno,
425 sizeof(cd->dst_telno));
426 strlcpy(cd->src_telno, mcr->src_telno,
427 sizeof(cd->src_telno));
428 cd->display[0] = '\0';
429
430 SET_CAUSE_TYPE(cd->cause_in, CAUSET_I4B);
431 SET_CAUSE_VAL(cd->cause_in, CAUSE_I4B_NORMAL);
432
433 /*
434 * If we want a specific channel, check if that
435 * one is available.
436 */
437 if ((mcr->channel >= 0) && (mcr->channel < d->nbch)) {
438 if(d->bch_state[mcr->channel] != BCH_ST_FREE)
439 SET_CAUSE_VAL(cd->cause_in,
440 CAUSE_I4B_NOCHAN);
441
442 /*
443 * If any channel will do, see if any are free.
444 */
445 } else if (mcr->channel == CHAN_ANY) {
446 int i;
447
448 for (i = 0; i < d->nbch; i++)
449 if (d->bch_state[i] == BCH_ST_FREE)
450 break;
451
452 if (i == d->nbch)
453 SET_CAUSE_VAL(cd->cause_in,
454 CAUSE_I4B_NOCHAN);
455
456 } else {
457 SET_CAUSE_VAL(cd->cause_in, CAUSE_I4B_NOCHAN);
458 }
459
460 cd->channelid = mcr->channel;
461
462 cd->isdntxdelay = mcr->txdelay;
463
464 if((GET_CAUSE_VAL(cd->cause_in)) != CAUSE_I4B_NORMAL)
465 {
466 i4b_l4_disconnect_ind(cd);
467 freecd_by_cd(cd);
468 }
469 else
470 {
471 d->l3driver->N_CONNECT_REQUEST(cd);
472 }
473 break;
474 }
475
476 /* connect response, accept/reject/ignore incoming call */
477
478 case I4B_CONNECT_RESP:
479 {
480 msg_connect_resp_t *mcrsp;
481
482 mcrsp = (msg_connect_resp_t *)data;
483
484 if((cd = cd_by_cdid(mcrsp->cdid)) == NULL)/* get cd */
485 {
486 NDBGL4(L4_ERR, "I4B_CONNECT_RESP ioctl, cdid not found!");
487 error = EINVAL;
488 break;
489 }
490
491 T400_stop(cd);
492
493 cd->bchan_driver_index = mcrsp->driver;
494 cd->bchan_driver_unit = mcrsp->driver_unit;
495 cd->max_idle_time = mcrsp->max_idle_time;
496
497 cd->shorthold_data.shorthold_algorithm = SHA_FIXU;
498 cd->shorthold_data.unitlen_time = 0; /* this is incoming */
499 cd->shorthold_data.idle_time = 0;
500 cd->shorthold_data.earlyhup_time = 0;
501
502 cd->isdntxdelay = mcrsp->txdelay;
503
504 NDBGL4(L4_TIMO, "I4B_CONNECT_RESP max_idle_time set to %ld seconds", (long)cd->max_idle_time);
505
506 d = isdn_find_l3_by_isdnif(cd->isdnif);
507 if (d == NULL) {
508 error = EINVAL;
509 break;
510 }
511 d->l3driver->N_CONNECT_RESPONSE(cd, mcrsp->response, mcrsp->cause);
512 break;
513 }
514
515 /* disconnect request, actively terminate connection */
516
517 case I4B_DISCONNECT_REQ:
518 {
519 msg_discon_req_t *mdr;
520
521 mdr = (msg_discon_req_t *)data;
522
523 if((cd = cd_by_cdid(mdr->cdid)) == NULL)/* get cd */
524 {
525 NDBGL4(L4_ERR, "I4B_DISCONNECT_REQ ioctl, cdid %d not found!", mdr->cdid);
526 error = EINVAL;
527 break;
528 }
529
530 /* preset causes with our cause */
531 cd->cause_in = cd->cause_out = mdr->cause;
532
533 d = isdn_find_l3_by_isdnif(cd->isdnif);
534 if (d == NULL) {
535 error = EINVAL;
536 break;
537 }
538
539 d->l3driver->N_DISCONNECT_REQUEST(cd, mdr->cause);
540 break;
541 }
542
543 /* controller info request */
544
545 case I4B_CTRL_INFO_REQ:
546 {
547 msg_ctrl_info_req_t *mcir;
548 int isdnif;
549
550 mcir = (msg_ctrl_info_req_t *)data;
551 isdnif = mcir->controller;
552 memset(mcir, 0, sizeof(msg_ctrl_info_req_t));
553 mcir->controller = isdnif;
554 mcir->ncontroller
555 = isdn_count_isdnif(&mcir->max_isdnif);
556 d = isdn_find_l3_by_isdnif(isdnif);
557 if (d != NULL) {
558 mcir->tei = d->tei;
559 mcir->nbch = d->nbch;
560 strncpy(mcir->devname, d->devname, sizeof(mcir->devname)-1);
561 strncpy(mcir->cardname, d->card_name, sizeof(mcir->cardname)-1);
562 } else {
563 error = ENODEV;
564 }
565 break;
566 }
567
568 /* dial response */
569
570 case I4B_DIALOUT_RESP:
571 {
572 const struct isdn_l4_driver_functions *drv;
573 msg_dialout_resp_t *mdrsp;
574 void * l4_softc;
575
576 mdrsp = (msg_dialout_resp_t *)data;
577 drv = isdn_l4_get_driver(mdrsp->driver, mdrsp->driver_unit);
578
579 if(drv != NULL) {
580 l4_softc = (*drv->get_softc)(mdrsp->driver_unit);
581 (*drv->dial_response)(l4_softc, mdrsp->stat, mdrsp->cause);
582 }
583 break;
584 }
585
586 /* update timeout value */
587
588 case I4B_TIMEOUT_UPD:
589 {
590 msg_timeout_upd_t *mtu;
591 int x;
592
593 mtu = (msg_timeout_upd_t *)data;
594
595 NDBGL4(L4_TIMO, "I4B_TIMEOUT_UPD ioctl, alg %d, unit %d, idle %d, early %d!",
596 mtu->shorthold_data.shorthold_algorithm, mtu->shorthold_data.unitlen_time,
597 mtu->shorthold_data.idle_time, mtu->shorthold_data.earlyhup_time);
598
599 if((cd = cd_by_cdid(mtu->cdid)) == NULL)/* get cd */
600 {
601 NDBGL4(L4_ERR, "I4B_TIMEOUT_UPD ioctl, cdid not found!");
602 error = EINVAL;
603 break;
604 }
605
606 switch( mtu->shorthold_data.shorthold_algorithm )
607 {
608 case SHA_FIXU:
609 /*
610 * For this algorithm unitlen_time,
611 * idle_time and earlyhup_time are used.
612 */
613
614 if(!(mtu->shorthold_data.unitlen_time >= 0 &&
615 mtu->shorthold_data.idle_time >= 0 &&
616 mtu->shorthold_data.earlyhup_time >= 0))
617 {
618 NDBGL4(L4_ERR, "I4B_TIMEOUT_UPD ioctl, invalid args for fix unit algorithm!");
619 error = EINVAL;
620 }
621 break;
622
623 case SHA_VARU:
624 /*
625 * For this algorithm unitlen_time and
626 * idle_time are used. both must be
627 * positive integers. earlyhup_time is
628 * not used and must be 0.
629 */
630
631 if(!(mtu->shorthold_data.unitlen_time > 0 &&
632 mtu->shorthold_data.idle_time >= 0 &&
633 mtu->shorthold_data.earlyhup_time == 0))
634 {
635 NDBGL4(L4_ERR, "I4B_TIMEOUT_UPD ioctl, invalid args for var unit algorithm!");
636 error = EINVAL;
637 }
638 break;
639
640 default:
641 NDBGL4(L4_ERR, "I4B_TIMEOUT_UPD ioctl, invalid algorithm!");
642 error = EINVAL;
643 break;
644 }
645
646 /*
647 * any error set above requires us to break
648 * out of the outer switch
649 */
650 if(error != 0)
651 break;
652
653 x = splnet();
654 cd->shorthold_data.shorthold_algorithm = mtu->shorthold_data.shorthold_algorithm;
655 cd->shorthold_data.unitlen_time = mtu->shorthold_data.unitlen_time;
656 cd->shorthold_data.idle_time = mtu->shorthold_data.idle_time;
657 cd->shorthold_data.earlyhup_time = mtu->shorthold_data.earlyhup_time;
658 splx(x);
659 break;
660 }
661
662 /* soft enable/disable interface */
663
664 case I4B_UPDOWN_IND:
665 {
666 msg_updown_ind_t *mui;
667 const struct isdn_l4_driver_functions *drv;
668 void * l4_softc;
669
670 mui = (msg_updown_ind_t *)data;
671 drv = isdn_l4_get_driver(mui->driver, mui->driver_unit);
672
673 if (drv)
674 {
675 l4_softc = drv->get_softc(mui->driver_unit);
676 (*drv->updown_ind)(l4_softc, mui->updown);
677 }
678 break;
679 }
680
681 /* send ALERT request */
682
683 case I4B_ALERT_REQ:
684 {
685 msg_alert_req_t *mar;
686
687 mar = (msg_alert_req_t *)data;
688
689 if((cd = cd_by_cdid(mar->cdid)) == NULL)
690 {
691 NDBGL4(L4_ERR, "I4B_ALERT_REQ ioctl, cdid not found!");
692 error = EINVAL;
693 break;
694 }
695
696 T400_stop(cd);
697
698 d = cd->l3drv;
699 if (d == NULL) {
700 error = EINVAL;
701 break;
702 }
703 d->l3driver->N_ALERT_REQUEST(cd);
704
705 break;
706 }
707
708 /* version/release number request */
709
710 case I4B_VR_REQ:
711 {
712 msg_vr_req_t *mvr;
713
714 mvr = (msg_vr_req_t *)data;
715
716 mvr->version = VERSION;
717 mvr->release = REL;
718 mvr->step = STEP;
719 break;
720 }
721
722 /* set D-channel protocol for a controller */
723
724 case I4B_PROT_IND:
725 {
726 msg_prot_ind_t *mpi;
727
728 mpi = (msg_prot_ind_t *)data;
729
730 d = isdn_find_l3_by_isdnif(mpi->controller);
731 if (d == NULL) {
732 error = EINVAL;
733 break;
734 }
735 d->protocol = mpi->protocol;
736
737 break;
738 }
739
740 case I4B_L4DRIVER_LOOKUP:
741 {
742 msg_l4driver_lookup_t *lookup = (msg_l4driver_lookup_t*)data;
743 lookup->name[L4DRIVER_NAME_SIZ-1] = 0;
744 lookup->driver_id = isdn_l4_find_driverid(lookup->name);
745 if (lookup->driver_id < 0)
746 error = ENXIO;
747 break;
748 }
749
750 /* Download request */
751 case I4B_CTRL_DOWNLOAD:
752 {
753 struct isdn_dr_prot *prots = NULL, *prots2 = NULL;
754 struct isdn_download_request *r =
755 (struct isdn_download_request*)data;
756 int i;
757
758 d = isdn_find_l3_by_isdnif(r->controller);
759 if (d == NULL)
760 {
761 error = ENODEV;
762 goto download_done;
763 }
764
765 if(d->l3driver->N_DOWNLOAD == NULL)
766 {
767 error = ENODEV;
768 goto download_done;
769 }
770
771 prots = malloc(r->numprotos * sizeof(struct isdn_dr_prot),
772 M_DEVBUF, M_WAITOK);
773
774 prots2 = malloc(r->numprotos * sizeof(struct isdn_dr_prot),
775 M_DEVBUF, M_WAITOK);
776
777 if(!prots || !prots2)
778 {
779 error = ENOMEM;
780 goto download_done;
781 }
782
783 copyin(r->protocols, prots, r->numprotos * sizeof(struct isdn_dr_prot));
784
785 for(i = 0; i < r->numprotos; i++)
786 {
787 prots2[i].microcode = malloc(prots[i].bytecount, M_DEVBUF, M_WAITOK);
788 copyin(prots[i].microcode, prots2[i].microcode, prots[i].bytecount);
789 prots2[i].bytecount = prots[i].bytecount;
790 }
791
792 error = d->l3driver->N_DOWNLOAD(
793 d->l1_token,
794 r->numprotos, prots2);
795
796 download_done:
797 if(prots2)
798 {
799 for(i = 0; i < r->numprotos; i++)
800 {
801 if(prots2[i].microcode)
802 {
803 free(prots2[i].microcode, M_DEVBUF);
804 }
805 }
806 free(prots2, M_DEVBUF);
807 }
808
809 if(prots)
810 {
811 free(prots, M_DEVBUF);
812 }
813 break;
814 }
815
816 /* Diagnostic request */
817
818 case I4B_ACTIVE_DIAGNOSTIC:
819 {
820 struct isdn_diagnostic_request req, *r =
821 (struct isdn_diagnostic_request*)data;
822
823 req.in_param = req.out_param = NULL;
824 d = isdn_find_l3_by_isdnif(r->controller);
825 if (d == NULL)
826 {
827 error = ENODEV;
828 goto diag_done;
829 }
830
831 if (d->l3driver->N_DIAGNOSTICS == NULL)
832 {
833 error = ENODEV;
834 goto diag_done;
835 }
836
837 memcpy(&req, r, sizeof(req));
838
839 if(req.in_param_len)
840 {
841 /* XXX arbitrary limit */
842 if (req.in_param_len > I4B_ACTIVE_DIAGNOSTIC_MAXPARAMLEN) {
843 error = EINVAL;
844 goto diag_done;
845 }
846
847 req.in_param = malloc(r->in_param_len, M_DEVBUF, M_WAITOK);
848
849 if(!req.in_param)
850 {
851 error = ENOMEM;
852 goto diag_done;
853 }
854 error = copyin(r->in_param, req.in_param, req.in_param_len);
855 if (error)
856 goto diag_done;
857 }
858
859 if(req.out_param_len)
860 {
861 req.out_param = malloc(r->out_param_len, M_DEVBUF, M_WAITOK);
862
863 if(!req.out_param)
864 {
865 error = ENOMEM;
866 goto diag_done;
867 }
868 }
869
870 error = d->l3driver->N_DIAGNOSTICS(d->l1_token, &req);
871
872 if(!error && req.out_param_len)
873 error = copyout(req.out_param, r->out_param, req.out_param_len);
874
875 diag_done:
876 if(req.in_param)
877 free(req.in_param, M_DEVBUF);
878
879 if(req.out_param)
880 free(req.out_param, M_DEVBUF);
881
882 break;
883 }
884
885 /* default */
886
887 default:
888 error = ENOTTY;
889 break;
890 }
891
892 return(error);
893 }
894
895 #ifdef OS_USES_SELECT
896
897 /*---------------------------------------------------------------------------*
898 * i4bselect - device driver select routine
899 *---------------------------------------------------------------------------*/
900 PDEVSTATIC int
901 i4bselect(dev_t dev, int rw, struct lwp *l)
902 {
903 int x;
904
905 if(minor(dev))
906 return(ENODEV);
907
908 switch(rw)
909 {
910 case FREAD:
911 if(!IF_QEMPTY(&i4b_rdqueue))
912 return(1);
913 x = splnet();
914 selrecord(l, &select_rd_info);
915 selflag = 1;
916 splx(x);
917 return(0);
918 break;
919
920 case FWRITE:
921 return(1);
922 break;
923 }
924 return(0);
925 }
926
927 #else /* OS_USES_SELECT */
928
929 /*---------------------------------------------------------------------------*
930 * i4bpoll - device driver poll routine
931 *---------------------------------------------------------------------------*/
932 PDEVSTATIC int
933 isdnpoll(dev_t dev, int events, struct lwp *l)
934 {
935 int x;
936
937 if(minor(dev))
938 return(ENODEV);
939
940 if((events & POLLIN) || (events & POLLRDNORM))
941 {
942 if(!IF_QEMPTY(&i4b_rdqueue))
943 return(1);
944
945 x = splnet();
946 selrecord(l, &select_rd_info);
947 selflag = 1;
948 splx(x);
949 return(0);
950 }
951 else if((events & POLLOUT) || (events & POLLWRNORM))
952 {
953 return(1);
954 }
955
956 return(0);
957 }
958
959 static void
960 filt_i4brdetach(struct knote *kn)
961 {
962 int s;
963
964 s = splnet();
965 SLIST_REMOVE(&select_rd_info.sel_klist, kn, knote, kn_selnext);
966 splx(s);
967 }
968
969 static int
970 filt_i4bread(struct knote *kn, long hint)
971 {
972 struct mbuf *m;
973
974 if (IF_QEMPTY(&i4b_rdqueue))
975 return (0);
976
977 IF_POLL(&i4b_rdqueue, m);
978
979 kn->kn_data = m->m_len;
980 return (1);
981 }
982
983 static const struct filterops i4bread_filtops =
984 { 1, NULL, filt_i4brdetach, filt_i4bread };
985
986 static const struct filterops i4b_seltrue_filtops =
987 { 1, NULL, filt_i4brdetach, filt_seltrue };
988
989 int
990 isdnkqfilter(dev_t dev, struct knote *kn)
991 {
992 struct klist *klist;
993 int s;
994
995 switch (kn->kn_filter) {
996 case EVFILT_READ:
997 klist = &select_rd_info.sel_klist;
998 kn->kn_fop = &i4bread_filtops;
999 break;
1000
1001 case EVFILT_WRITE:
1002 klist = &select_rd_info.sel_klist;
1003 kn->kn_fop = &i4b_seltrue_filtops;
1004 break;
1005
1006 default:
1007 return (1);
1008 }
1009
1010 kn->kn_hook = NULL;
1011
1012 s = splnet();
1013 SLIST_INSERT_HEAD(klist, kn, kn_selnext);
1014 splx(s);
1015
1016 return (0);
1017 }
1018
1019 #endif /* OS_USES_SELECT */
1020
1021 /*---------------------------------------------------------------------------*
1022 * i4bputqueue - put message into queue to userland
1023 *---------------------------------------------------------------------------*/
1024 void
1025 i4bputqueue(struct mbuf *m)
1026 {
1027 int x;
1028
1029 if(!openflag)
1030 {
1031 i4b_Dfreembuf(m);
1032 return;
1033 }
1034
1035 x = splnet();
1036
1037 if(IF_QFULL(&i4b_rdqueue))
1038 {
1039 struct mbuf *m1;
1040 IF_DEQUEUE(&i4b_rdqueue, m1);
1041 i4b_Dfreembuf(m1);
1042 NDBGL4(L4_ERR, "ERROR, queue full, removing entry!");
1043 }
1044
1045 IF_ENQUEUE(&i4b_rdqueue, m);
1046
1047 splx(x);
1048
1049 if(readflag)
1050 {
1051 readflag = 0;
1052 wakeup((caddr_t) &i4b_rdqueue);
1053 }
1054
1055 if(selflag)
1056 {
1057 selflag = 0;
1058 selnotify(&select_rd_info, 0);
1059 }
1060 }
1061
1062 /*---------------------------------------------------------------------------*
1063 * i4bputqueue_hipri - put message into front of queue to userland
1064 *---------------------------------------------------------------------------*/
1065 void
1066 i4bputqueue_hipri(struct mbuf *m)
1067 {
1068 int x;
1069
1070 if(!openflag)
1071 {
1072 i4b_Dfreembuf(m);
1073 return;
1074 }
1075
1076 x = splnet();
1077
1078 if(IF_QFULL(&i4b_rdqueue))
1079 {
1080 struct mbuf *m1;
1081 IF_DEQUEUE(&i4b_rdqueue, m1);
1082 i4b_Dfreembuf(m1);
1083 NDBGL4(L4_ERR, "ERROR, queue full, removing entry!");
1084 }
1085
1086 IF_PREPEND(&i4b_rdqueue, m);
1087
1088 splx(x);
1089
1090 if(readflag)
1091 {
1092 readflag = 0;
1093 wakeup((caddr_t) &i4b_rdqueue);
1094 }
1095
1096 if(selflag)
1097 {
1098 selflag = 0;
1099 selnotify(&select_rd_info, 0);
1100 }
1101 }
1102
1103 void
1104 isdn_isdnif_ready(int isdnif)
1105 {
1106 struct isdn_l3_driver *d = isdn_find_l3_by_isdnif(isdnif);
1107
1108 if (d == NULL)
1109 return;
1110
1111 printf("ISDN %d at %s, %d B channels\n", isdnif, d->devname, d->nbch);
1112 if (!openflag) return;
1113
1114 d->l3driver->N_MGMT_COMMAND(d, CMR_DOPEN, 0);
1115 i4b_l4_contr_ev_ind(isdnif, 1);
1116 }
1117
1118 #endif /* NISDN > 0 */
Cache object: 98b7fae050b409c5eb3fefc6cae01283
|