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