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