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.25 2004/03/28 14:27:26 pooka 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.25 2004/03/28 14:27:26 pooka 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 proc *p));
115 PDEVSTATIC int isdnclose __P((dev_t dev, int flag, int fmt, struct proc *p));
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 proc *p));
118
119 #ifdef OS_USES_POLL
120 PDEVSTATIC int isdnpoll __P((dev_t dev, int events, struct proc *p));
121 PDEVSTATIC int isdnkqfilter __P((dev_t dev, struct knote *kn));
122 #else
123 PDEVSTATIC int isdnselect __P((dev_t dev, int rw, struct proc *p));
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,
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 proc *p)
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, struct proc *p)
288 {
289 int x = splnet();
290 openflag = 0;
291 i4b_l4_daemon_detached();
292 i4b_Dcleanifq(&i4b_rdqueue);
293 splx(x);
294 return(0);
295 }
296
297 /*---------------------------------------------------------------------------*
298 * i4bread - device driver read routine
299 *---------------------------------------------------------------------------*/
300 PDEVSTATIC int
301 isdnread(dev_t dev, struct uio *uio, int ioflag)
302 {
303 struct mbuf *m;
304 int x;
305 int error = 0;
306
307 if(minor(dev))
308 return(ENODEV);
309
310 x = splnet();
311 while(IF_QEMPTY(&i4b_rdqueue))
312 {
313 readflag = 1;
314 error = tsleep((caddr_t) &i4b_rdqueue, (PZERO + 1) | PCATCH, "bird", 0);
315 if (error != 0) {
316 splx(x);
317 return error;
318 }
319 }
320
321 IF_DEQUEUE(&i4b_rdqueue, m);
322
323 splx(x);
324
325 if(m && m->m_len)
326 error = uiomove(m->m_data, m->m_len, uio);
327 else
328 error = EIO;
329
330 if(m)
331 i4b_Dfreembuf(m);
332
333 return(error);
334 }
335
336 /*---------------------------------------------------------------------------*
337 * i4bioctl - device driver ioctl routine
338 *---------------------------------------------------------------------------*/
339 PDEVSTATIC int
340 isdnioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
341 {
342 struct isdn_l3_driver *d;
343 call_desc_t *cd;
344 int error = 0;
345
346 if(minor(dev))
347 return(ENODEV);
348
349 switch(cmd)
350 {
351 /* cdid request, reserve cd and return cdid */
352
353 case I4B_CDID_REQ:
354 {
355 msg_cdid_req_t *mir;
356 mir = (msg_cdid_req_t *)data;
357 cd = reserve_cd();
358 mir->cdid = cd->cdid;
359 break;
360 }
361
362 /* connect request, dial out to remote */
363
364 case I4B_CONNECT_REQ:
365 {
366 msg_connect_req_t *mcr;
367 mcr = (msg_connect_req_t *)data; /* setup ptr */
368
369 if((cd = cd_by_cdid(mcr->cdid)) == NULL)/* get cd */
370 {
371 NDBGL4(L4_ERR, "I4B_CONNECT_REQ ioctl, cdid not found!");
372 error = EINVAL;
373 break;
374 }
375 cd->isdnif = -1;
376 cd->l3drv = NULL;
377
378 d = isdn_find_l3_by_isdnif(mcr->controller);
379 if (d == NULL) {
380 error = EINVAL;
381 break;
382 }
383
384 /* prevent dialling on leased lines */
385 if(d->protocol == PROTOCOL_D64S)
386 {
387 SET_CAUSE_TYPE(cd->cause_in, CAUSET_I4B);
388 SET_CAUSE_VAL(cd->cause_in, CAUSE_I4B_LLDIAL);
389 i4b_l4_disconnect_ind(cd);
390 freecd_by_cd(cd);
391 break;
392 }
393
394 cd->isdnif = mcr->controller; /* fill cd */
395 cd->l3drv = d;
396 cd->bprot = mcr->bprot;
397 cd->bchan_driver_index = mcr->driver;
398 cd->bchan_driver_unit = mcr->driver_unit;
399 cd->cr = get_rand_cr(cd->isdnif);
400
401 cd->shorthold_data.shorthold_algorithm = mcr->shorthold_data.shorthold_algorithm;
402 cd->shorthold_data.unitlen_time = mcr->shorthold_data.unitlen_time;
403 cd->shorthold_data.idle_time = mcr->shorthold_data.idle_time;
404 cd->shorthold_data.earlyhup_time = mcr->shorthold_data.earlyhup_time;
405
406 cd->last_aocd_time = 0;
407 if(mcr->unitlen_method == ULEN_METHOD_DYNAMIC)
408 cd->aocd_flag = 1;
409 else
410 cd->aocd_flag = 0;
411
412 cd->cunits = 0;
413
414 cd->max_idle_time = 0; /* this is outgoing */
415
416 cd->dir = DIR_OUTGOING;
417
418 NDBGL4(L4_TIMO, "I4B_CONNECT_REQ times, algorithm=%ld unitlen=%ld idle=%ld earlyhup=%ld",
419 (long)cd->shorthold_data.shorthold_algorithm, (long)cd->shorthold_data.unitlen_time,
420 (long)cd->shorthold_data.idle_time, (long)cd->shorthold_data.earlyhup_time);
421
422 strlcpy(cd->dst_telno, mcr->dst_telno,
423 sizeof(cd->dst_telno));
424 strlcpy(cd->src_telno, mcr->src_telno,
425 sizeof(cd->src_telno));
426 cd->display[0] = '\0';
427
428 SET_CAUSE_TYPE(cd->cause_in, CAUSET_I4B);
429 SET_CAUSE_VAL(cd->cause_in, CAUSE_I4B_NORMAL);
430
431 /*
432 * If we want a specific channel, check if that
433 * one is available.
434 */
435 if ((mcr->channel >= 0) && (mcr->channel < d->nbch)) {
436 if(d->bch_state[mcr->channel] != BCH_ST_FREE)
437 SET_CAUSE_VAL(cd->cause_in,
438 CAUSE_I4B_NOCHAN);
439
440 /*
441 * If any channel will do, see if any are free.
442 */
443 } else if (mcr->channel == CHAN_ANY) {
444 int i;
445
446 for (i = 0; i < d->nbch; i++)
447 if (d->bch_state[i] == BCH_ST_FREE)
448 break;
449
450 if (i == d->nbch)
451 SET_CAUSE_VAL(cd->cause_in,
452 CAUSE_I4B_NOCHAN);
453
454 } else {
455 SET_CAUSE_VAL(cd->cause_in, CAUSE_I4B_NOCHAN);
456 }
457
458 cd->channelid = mcr->channel;
459
460 cd->isdntxdelay = mcr->txdelay;
461
462 if((GET_CAUSE_VAL(cd->cause_in)) != CAUSE_I4B_NORMAL)
463 {
464 i4b_l4_disconnect_ind(cd);
465 freecd_by_cd(cd);
466 }
467 else
468 {
469 d->l3driver->N_CONNECT_REQUEST(cd);
470 }
471 break;
472 }
473
474 /* connect response, accept/reject/ignore incoming call */
475
476 case I4B_CONNECT_RESP:
477 {
478 msg_connect_resp_t *mcrsp;
479
480 mcrsp = (msg_connect_resp_t *)data;
481
482 if((cd = cd_by_cdid(mcrsp->cdid)) == NULL)/* get cd */
483 {
484 NDBGL4(L4_ERR, "I4B_CONNECT_RESP ioctl, cdid not found!");
485 error = EINVAL;
486 break;
487 }
488
489 T400_stop(cd);
490
491 cd->bchan_driver_index = mcrsp->driver;
492 cd->bchan_driver_unit = mcrsp->driver_unit;
493 cd->max_idle_time = mcrsp->max_idle_time;
494
495 cd->shorthold_data.shorthold_algorithm = SHA_FIXU;
496 cd->shorthold_data.unitlen_time = 0; /* this is incoming */
497 cd->shorthold_data.idle_time = 0;
498 cd->shorthold_data.earlyhup_time = 0;
499
500 cd->isdntxdelay = mcrsp->txdelay;
501
502 NDBGL4(L4_TIMO, "I4B_CONNECT_RESP max_idle_time set to %ld seconds", (long)cd->max_idle_time);
503
504 d = isdn_find_l3_by_isdnif(cd->isdnif);
505 if (d == NULL) {
506 error = EINVAL;
507 break;
508 }
509 d->l3driver->N_CONNECT_RESPONSE(cd, mcrsp->response, mcrsp->cause);
510 break;
511 }
512
513 /* disconnect request, actively terminate connection */
514
515 case I4B_DISCONNECT_REQ:
516 {
517 msg_discon_req_t *mdr;
518
519 mdr = (msg_discon_req_t *)data;
520
521 if((cd = cd_by_cdid(mdr->cdid)) == NULL)/* get cd */
522 {
523 NDBGL4(L4_ERR, "I4B_DISCONNECT_REQ ioctl, cdid %d not found!", mdr->cdid);
524 error = EINVAL;
525 break;
526 }
527
528 /* preset causes with our cause */
529 cd->cause_in = cd->cause_out = mdr->cause;
530
531 d = isdn_find_l3_by_isdnif(cd->isdnif);
532 if (d == NULL) {
533 error = EINVAL;
534 break;
535 }
536
537 d->l3driver->N_DISCONNECT_REQUEST(cd, mdr->cause);
538 break;
539 }
540
541 /* controller info request */
542
543 case I4B_CTRL_INFO_REQ:
544 {
545 msg_ctrl_info_req_t *mcir;
546 struct isdn_l3_driver *d;
547 int isdnif;
548
549 mcir = (msg_ctrl_info_req_t *)data;
550 isdnif = mcir->controller;
551 memset(mcir, 0, sizeof(msg_ctrl_info_req_t));
552 mcir->controller = isdnif;
553 mcir->ncontroller
554 = isdn_count_isdnif(&mcir->max_isdnif);
555 d = isdn_find_l3_by_isdnif(isdnif);
556 if (d != NULL) {
557 mcir->tei = d->tei;
558 mcir->nbch = d->nbch;
559 strncpy(mcir->devname, d->devname, sizeof(mcir->devname)-1);
560 strncpy(mcir->cardname, d->card_name, sizeof(mcir->cardname)-1);
561 } else {
562 error = ENODEV;
563 }
564 break;
565 }
566
567 /* dial response */
568
569 case I4B_DIALOUT_RESP:
570 {
571 const struct isdn_l4_driver_functions *drv;
572 msg_dialout_resp_t *mdrsp;
573 void * l4_softc;
574
575 mdrsp = (msg_dialout_resp_t *)data;
576 drv = isdn_l4_get_driver(mdrsp->driver, mdrsp->driver_unit);
577
578 if(drv != NULL) {
579 l4_softc = (*drv->get_softc)(mdrsp->driver_unit);
580 (*drv->dial_response)(l4_softc, mdrsp->stat, mdrsp->cause);
581 }
582 break;
583 }
584
585 /* update timeout value */
586
587 case I4B_TIMEOUT_UPD:
588 {
589 msg_timeout_upd_t *mtu;
590 int x;
591
592 mtu = (msg_timeout_upd_t *)data;
593
594 NDBGL4(L4_TIMO, "I4B_TIMEOUT_UPD ioctl, alg %d, unit %d, idle %d, early %d!",
595 mtu->shorthold_data.shorthold_algorithm, mtu->shorthold_data.unitlen_time,
596 mtu->shorthold_data.idle_time, mtu->shorthold_data.earlyhup_time);
597
598 if((cd = cd_by_cdid(mtu->cdid)) == NULL)/* get cd */
599 {
600 NDBGL4(L4_ERR, "I4B_TIMEOUT_UPD ioctl, cdid not found!");
601 error = EINVAL;
602 break;
603 }
604
605 switch( mtu->shorthold_data.shorthold_algorithm )
606 {
607 case SHA_FIXU:
608 /*
609 * For this algorithm unitlen_time,
610 * idle_time and earlyhup_time are used.
611 */
612
613 if(!(mtu->shorthold_data.unitlen_time >= 0 &&
614 mtu->shorthold_data.idle_time >= 0 &&
615 mtu->shorthold_data.earlyhup_time >= 0))
616 {
617 NDBGL4(L4_ERR, "I4B_TIMEOUT_UPD ioctl, invalid args for fix unit algorithm!");
618 error = EINVAL;
619 }
620 break;
621
622 case SHA_VARU:
623 /*
624 * For this algorithm unitlen_time and
625 * idle_time are used. both must be
626 * positive integers. earlyhup_time is
627 * not used and must be 0.
628 */
629
630 if(!(mtu->shorthold_data.unitlen_time > 0 &&
631 mtu->shorthold_data.idle_time >= 0 &&
632 mtu->shorthold_data.earlyhup_time == 0))
633 {
634 NDBGL4(L4_ERR, "I4B_TIMEOUT_UPD ioctl, invalid args for var unit algorithm!");
635 error = EINVAL;
636 }
637 break;
638
639 default:
640 NDBGL4(L4_ERR, "I4B_TIMEOUT_UPD ioctl, invalid algorithm!");
641 error = EINVAL;
642 break;
643 }
644
645 /*
646 * any error set above requires us to break
647 * out of the outer switch
648 */
649 if(error != 0)
650 break;
651
652 x = splnet();
653 cd->shorthold_data.shorthold_algorithm = mtu->shorthold_data.shorthold_algorithm;
654 cd->shorthold_data.unitlen_time = mtu->shorthold_data.unitlen_time;
655 cd->shorthold_data.idle_time = mtu->shorthold_data.idle_time;
656 cd->shorthold_data.earlyhup_time = mtu->shorthold_data.earlyhup_time;
657 splx(x);
658 break;
659 }
660
661 /* soft enable/disable interface */
662
663 case I4B_UPDOWN_IND:
664 {
665 msg_updown_ind_t *mui;
666 const struct isdn_l4_driver_functions *drv;
667 void * l4_softc;
668
669 mui = (msg_updown_ind_t *)data;
670 drv = isdn_l4_get_driver(mui->driver, mui->driver_unit);
671
672 if (drv)
673 {
674 l4_softc = drv->get_softc(mui->driver_unit);
675 (*drv->updown_ind)(l4_softc, mui->updown);
676 }
677 break;
678 }
679
680 /* send ALERT request */
681
682 case I4B_ALERT_REQ:
683 {
684 msg_alert_req_t *mar;
685
686 mar = (msg_alert_req_t *)data;
687
688 if((cd = cd_by_cdid(mar->cdid)) == NULL)
689 {
690 NDBGL4(L4_ERR, "I4B_ALERT_REQ ioctl, cdid not found!");
691 error = EINVAL;
692 break;
693 }
694
695 T400_stop(cd);
696
697 d = cd->l3drv;
698 if (d == NULL) {
699 error = EINVAL;
700 break;
701 }
702 d->l3driver->N_ALERT_REQUEST(cd);
703
704 break;
705 }
706
707 /* version/release number request */
708
709 case I4B_VR_REQ:
710 {
711 msg_vr_req_t *mvr;
712
713 mvr = (msg_vr_req_t *)data;
714
715 mvr->version = VERSION;
716 mvr->release = REL;
717 mvr->step = STEP;
718 break;
719 }
720
721 /* set D-channel protocol for a controller */
722
723 case I4B_PROT_IND:
724 {
725 msg_prot_ind_t *mpi;
726
727 mpi = (msg_prot_ind_t *)data;
728
729 d = isdn_find_l3_by_isdnif(mpi->controller);
730 if (d == NULL) {
731 error = EINVAL;
732 break;
733 }
734 d->protocol = mpi->protocol;
735
736 break;
737 }
738
739 case I4B_L4DRIVER_LOOKUP:
740 {
741 msg_l4driver_lookup_t *lookup = (msg_l4driver_lookup_t*)data;
742 lookup->name[L4DRIVER_NAME_SIZ-1] = 0;
743 lookup->driver_id = isdn_l4_find_driverid(lookup->name);
744 if (lookup->driver_id < 0)
745 error = ENXIO;
746 break;
747 }
748
749 /* Download request */
750 case I4B_CTRL_DOWNLOAD:
751 {
752 struct isdn_dr_prot *prots = NULL, *prots2 = NULL;
753 struct isdn_download_request *r =
754 (struct isdn_download_request*)data;
755 int i;
756
757 d = isdn_find_l3_by_isdnif(r->controller);
758 if (d == NULL)
759 {
760 error = ENODEV;
761 goto download_done;
762 }
763
764 if(d->l3driver->N_DOWNLOAD == NULL)
765 {
766 error = ENODEV;
767 goto download_done;
768 }
769
770 prots = malloc(r->numprotos * sizeof(struct isdn_dr_prot),
771 M_DEVBUF, M_WAITOK);
772
773 prots2 = malloc(r->numprotos * sizeof(struct isdn_dr_prot),
774 M_DEVBUF, M_WAITOK);
775
776 if(!prots || !prots2)
777 {
778 error = ENOMEM;
779 goto download_done;
780 }
781
782 copyin(r->protocols, prots, r->numprotos * sizeof(struct isdn_dr_prot));
783
784 for(i = 0; i < r->numprotos; i++)
785 {
786 prots2[i].microcode = malloc(prots[i].bytecount, M_DEVBUF, M_WAITOK);
787 copyin(prots[i].microcode, prots2[i].microcode, prots[i].bytecount);
788 prots2[i].bytecount = prots[i].bytecount;
789 }
790
791 error = d->l3driver->N_DOWNLOAD(
792 d->l1_token,
793 r->numprotos, prots2);
794
795 download_done:
796 if(prots2)
797 {
798 for(i = 0; i < r->numprotos; i++)
799 {
800 if(prots2[i].microcode)
801 {
802 free(prots2[i].microcode, M_DEVBUF);
803 }
804 }
805 free(prots2, M_DEVBUF);
806 }
807
808 if(prots)
809 {
810 free(prots, M_DEVBUF);
811 }
812 break;
813 }
814
815 /* Diagnostic request */
816
817 case I4B_ACTIVE_DIAGNOSTIC:
818 {
819 struct isdn_diagnostic_request req, *r =
820 (struct isdn_diagnostic_request*)data;
821
822 req.in_param = req.out_param = NULL;
823 d = isdn_find_l3_by_isdnif(r->controller);
824 if (d == NULL)
825 {
826 error = ENODEV;
827 goto diag_done;
828 }
829
830 if (d->l3driver->N_DIAGNOSTICS == NULL)
831 {
832 error = ENODEV;
833 goto diag_done;
834 }
835
836 memcpy(&req, r, sizeof(req));
837
838 if(req.in_param_len)
839 {
840 /* XXX arbitrary limit */
841 if (req.in_param_len > I4B_ACTIVE_DIAGNOSTIC_MAXPARAMLEN) {
842 error = EINVAL;
843 goto diag_done;
844 }
845
846 req.in_param = malloc(r->in_param_len, M_DEVBUF, M_WAITOK);
847
848 if(!req.in_param)
849 {
850 error = ENOMEM;
851 goto diag_done;
852 }
853 error = copyin(r->in_param, req.in_param, req.in_param_len);
854 if (error)
855 goto diag_done;
856 }
857
858 if(req.out_param_len)
859 {
860 req.out_param = malloc(r->out_param_len, M_DEVBUF, M_WAITOK);
861
862 if(!req.out_param)
863 {
864 error = ENOMEM;
865 goto diag_done;
866 }
867 }
868
869 error = d->l3driver->N_DIAGNOSTICS(d->l1_token, &req);
870
871 if(!error && req.out_param_len)
872 error = copyout(req.out_param, r->out_param, req.out_param_len);
873
874 diag_done:
875 if(req.in_param)
876 free(req.in_param, M_DEVBUF);
877
878 if(req.out_param)
879 free(req.out_param, M_DEVBUF);
880
881 break;
882 }
883
884 /* default */
885
886 default:
887 error = ENOTTY;
888 break;
889 }
890
891 return(error);
892 }
893
894 #ifdef OS_USES_SELECT
895
896 /*---------------------------------------------------------------------------*
897 * i4bselect - device driver select routine
898 *---------------------------------------------------------------------------*/
899 PDEVSTATIC int
900 i4bselect(dev_t dev, int rw, struct proc *p)
901 {
902 int x;
903
904 if(minor(dev))
905 return(ENODEV);
906
907 switch(rw)
908 {
909 case FREAD:
910 if(!IF_QEMPTY(&i4b_rdqueue))
911 return(1);
912 x = splnet();
913 selrecord(p, &select_rd_info);
914 selflag = 1;
915 splx(x);
916 return(0);
917 break;
918
919 case FWRITE:
920 return(1);
921 break;
922 }
923 return(0);
924 }
925
926 #else /* OS_USES_SELECT */
927
928 /*---------------------------------------------------------------------------*
929 * i4bpoll - device driver poll routine
930 *---------------------------------------------------------------------------*/
931 PDEVSTATIC int
932 isdnpoll(dev_t dev, int events, struct proc *p)
933 {
934 int x;
935
936 if(minor(dev))
937 return(ENODEV);
938
939 if((events & POLLIN) || (events & POLLRDNORM))
940 {
941 if(!IF_QEMPTY(&i4b_rdqueue))
942 return(1);
943
944 x = splnet();
945 selrecord(p, &select_rd_info);
946 selflag = 1;
947 splx(x);
948 return(0);
949 }
950 else if((events & POLLOUT) || (events & POLLWRNORM))
951 {
952 return(1);
953 }
954
955 return(0);
956 }
957
958 static void
959 filt_i4brdetach(struct knote *kn)
960 {
961 int s;
962
963 s = splnet();
964 SLIST_REMOVE(&select_rd_info.sel_klist, kn, knote, kn_selnext);
965 splx(s);
966 }
967
968 static int
969 filt_i4bread(struct knote *kn, long hint)
970 {
971 struct mbuf *m;
972
973 if (IF_QEMPTY(&i4b_rdqueue))
974 return (0);
975
976 IF_POLL(&i4b_rdqueue, m);
977
978 kn->kn_data = m->m_len;
979 return (1);
980 }
981
982 static const struct filterops i4bread_filtops =
983 { 1, NULL, filt_i4brdetach, filt_i4bread };
984
985 static const struct filterops i4b_seltrue_filtops =
986 { 1, NULL, filt_i4brdetach, filt_seltrue };
987
988 int
989 isdnkqfilter(dev_t dev, struct knote *kn)
990 {
991 struct klist *klist;
992 int s;
993
994 switch (kn->kn_filter) {
995 case EVFILT_READ:
996 klist = &select_rd_info.sel_klist;
997 kn->kn_fop = &i4bread_filtops;
998 break;
999
1000 case EVFILT_WRITE:
1001 klist = &select_rd_info.sel_klist;
1002 kn->kn_fop = &i4b_seltrue_filtops;
1003 break;
1004
1005 default:
1006 return (1);
1007 }
1008
1009 kn->kn_hook = NULL;
1010
1011 s = splnet();
1012 SLIST_INSERT_HEAD(klist, kn, kn_selnext);
1013 splx(s);
1014
1015 return (0);
1016 }
1017
1018 #endif /* OS_USES_SELECT */
1019
1020 /*---------------------------------------------------------------------------*
1021 * i4bputqueue - put message into queue to userland
1022 *---------------------------------------------------------------------------*/
1023 void
1024 i4bputqueue(struct mbuf *m)
1025 {
1026 int x;
1027
1028 if(!openflag)
1029 {
1030 i4b_Dfreembuf(m);
1031 return;
1032 }
1033
1034 x = splnet();
1035
1036 if(IF_QFULL(&i4b_rdqueue))
1037 {
1038 struct mbuf *m1;
1039 IF_DEQUEUE(&i4b_rdqueue, m1);
1040 i4b_Dfreembuf(m1);
1041 NDBGL4(L4_ERR, "ERROR, queue full, removing entry!");
1042 }
1043
1044 IF_ENQUEUE(&i4b_rdqueue, m);
1045
1046 splx(x);
1047
1048 if(readflag)
1049 {
1050 readflag = 0;
1051 wakeup((caddr_t) &i4b_rdqueue);
1052 }
1053
1054 if(selflag)
1055 {
1056 selflag = 0;
1057 selnotify(&select_rd_info, 0);
1058 }
1059 }
1060
1061 /*---------------------------------------------------------------------------*
1062 * i4bputqueue_hipri - put message into front of queue to userland
1063 *---------------------------------------------------------------------------*/
1064 void
1065 i4bputqueue_hipri(struct mbuf *m)
1066 {
1067 int x;
1068
1069 if(!openflag)
1070 {
1071 i4b_Dfreembuf(m);
1072 return;
1073 }
1074
1075 x = splnet();
1076
1077 if(IF_QFULL(&i4b_rdqueue))
1078 {
1079 struct mbuf *m1;
1080 IF_DEQUEUE(&i4b_rdqueue, m1);
1081 i4b_Dfreembuf(m1);
1082 NDBGL4(L4_ERR, "ERROR, queue full, removing entry!");
1083 }
1084
1085 IF_PREPEND(&i4b_rdqueue, m);
1086
1087 splx(x);
1088
1089 if(readflag)
1090 {
1091 readflag = 0;
1092 wakeup((caddr_t) &i4b_rdqueue);
1093 }
1094
1095 if(selflag)
1096 {
1097 selflag = 0;
1098 selnotify(&select_rd_info, 0);
1099 }
1100 }
1101
1102 void
1103 isdn_isdnif_ready(int isdnif)
1104 {
1105 struct isdn_l3_driver *d = isdn_find_l3_by_isdnif(isdnif);
1106
1107 if (d == NULL)
1108 return;
1109
1110 printf("ISDN %d at %s, %d B channels\n", isdnif, d->devname, d->nbch);
1111 if (!openflag) return;
1112
1113 d->l3driver->N_MGMT_COMMAND(d, CMR_DOPEN, 0);
1114 i4b_l4_contr_ev_ind(isdnif, 1);
1115 }
1116
1117 #endif /* NISDN > 0 */
Cache object: b7407973951a8e6cbfd750c7fa7b0ed4
|