Consolidate ifqueue macros for the upcoming ALTQ work.
[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.11 2005/01/23 13:47:24 joerg 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(__DragonFly__) || 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 defined(__FreeBSD__) && __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(__DragonFly__) || defined(__FreeBSD__)
74 #include "use_i4bing.h"
75 #endif
76
77 #ifdef __bsdi__
78 #include "ibc.h"
79 #else
80 #if defined(__DragonFly__) || defined(__FreeBSD__)
81 #include "use_i4bisppp.h"
82 #else
83 #include <net/if_sppp.h>
84 #endif
85 #endif
86
87 #if defined(__DragonFly__) || defined(__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 #if defined(__DragonFly__) || defined(__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 #if !defined(__DragonFly__) && !defined(__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 defined(__DragonFly__) || (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(__DragonFly__) || (defined(__FreeBSD__) && __FreeBSD__ >= 4)
174 static struct cdevsw i4b_cdevsw = {
175         /* name */      "i4b",
176         /* maj */       CDEV_MAJOR,
177         /* flags */     0,
178         /* port */      NULL,
179         /* clone */     NULL,
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(__DragonFly__) || (defined(__FreeBSD__) && __FreeBSD__ >= 4)
207         cdevsw_add(&i4b_cdevsw, 0, 0);
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 #if defined(__DragonFly__) || defined(__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(__DragonFly__) || 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         while(IF_QEMPTY(&i4b_rdqueue))
329         {
330                 readflag = 1;
331 #if defined (__FreeBSD__) && __FreeBSD__ > 4            
332                 error = msleep((caddr_t) &i4b_rdqueue, &i4b_rdqueue.ifq_mtx,
333                         PCATCH, "bird", 0);
334 #else
335                 error = tsleep((caddr_t) &i4b_rdqueue, PCATCH, "bird", 0);
336 #endif
337                 if (error != 0) {
338                         splx(x);
339                         return error;
340                 }
341         }
342
343         IF_DEQUEUE(&i4b_rdqueue, m);
344
345         splx(x);
346                 
347         if(m && m->m_len)
348                 error = uiomove(m->m_data, m->m_len, uio);
349         else
350                 error = EIO;
351                 
352         if(m)
353                 i4b_Dfreembuf(m);
354
355         return(error);
356 }
357
358 /*---------------------------------------------------------------------------*
359  *      i4bioctl - device driver ioctl routine
360  *---------------------------------------------------------------------------*/
361 PDEVSTATIC int
362 #if defined(__DragonFly__) || (defined (__FreeBSD_version) && __FreeBSD_version >= 300003)
363 i4bioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
364 #elif defined(__bsdi__)
365 i4bioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
366 #else
367 i4bioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
368 #endif
369 {
370         call_desc_t *cd;
371         int error = 0;
372         
373         if(minor(dev))
374                 return(ENODEV);
375
376         switch(cmd)
377         {
378                 /* cdid request, reserve cd and return cdid */
379
380                 case I4B_CDID_REQ:
381                 {
382                         msg_cdid_req_t *mir;
383                         mir = (msg_cdid_req_t *)data;
384                         cd = reserve_cd();
385                         mir->cdid = cd->cdid;
386                         break;
387                 }
388                 
389                 /* connect request, dial out to remote */
390                 
391                 case I4B_CONNECT_REQ:
392                 {
393                         msg_connect_req_t *mcr;
394                         mcr = (msg_connect_req_t *)data;        /* setup ptr */
395
396                         if((cd = cd_by_cdid(mcr->cdid)) == NULL)/* get cd */
397                         {
398                                 NDBGL4(L4_ERR, "I4B_CONNECT_REQ ioctl, cdid not found!"); 
399                                 error = EINVAL;
400                                 break;
401                         }
402
403                         /* prevent dialling on leased lines */
404                         if(ctrl_desc[mcr->controller].protocol == PROTOCOL_D64S)
405                         {
406                                 SET_CAUSE_TYPE(cd->cause_in, CAUSET_I4B);
407                                 SET_CAUSE_VAL(cd->cause_in, CAUSE_I4B_LLDIAL);
408                                 i4b_l4_disconnect_ind(cd);
409                                 freecd_by_cd(cd);
410                                 break;
411                         }
412
413                         cd->controller = mcr->controller;       /* fill cd */
414                         cd->bprot = mcr->bprot;
415                         cd->driver = mcr->driver;
416                         cd->driver_unit = mcr->driver_unit;
417                         cd->cr = get_rand_cr(ctrl_desc[cd->controller].unit);
418
419                         cd->shorthold_data.shorthold_algorithm = mcr->shorthold_data.shorthold_algorithm;
420                         cd->shorthold_data.unitlen_time  = mcr->shorthold_data.unitlen_time;
421                         cd->shorthold_data.idle_time     = mcr->shorthold_data.idle_time;
422                         cd->shorthold_data.earlyhup_time = mcr->shorthold_data.earlyhup_time;
423
424                         cd->last_aocd_time = 0;
425                         if(mcr->unitlen_method == ULEN_METHOD_DYNAMIC)
426                                 cd->aocd_flag = 1;
427                         else
428                                 cd->aocd_flag = 0;
429                                 
430                         cd->cunits = 0;
431
432                         cd->max_idle_time = 0;  /* this is outgoing */
433
434                         cd->dir = DIR_OUTGOING;
435                         
436                         NDBGL4(L4_TIMO, "I4B_CONNECT_REQ times, algorithm=%ld unitlen=%ld idle=%ld earlyhup=%ld",
437                                         (long)cd->shorthold_data.shorthold_algorithm, (long)cd->shorthold_data.unitlen_time,
438                                         (long)cd->shorthold_data.idle_time, (long)cd->shorthold_data.earlyhup_time);
439
440                         strcpy(cd->dst_telno, mcr->dst_telno);
441                         strcpy(cd->src_telno, mcr->src_telno);
442
443                         if(mcr->keypad[0] != '\0')
444                                 strcpy(cd->keypad, mcr->keypad);
445                         else
446                                 cd->keypad[0] = '\0';
447                                 
448                         cd->display[0] = '\0';
449
450                         SET_CAUSE_TYPE(cd->cause_in, CAUSET_I4B);
451                         SET_CAUSE_VAL(cd->cause_in, CAUSE_I4B_NORMAL);
452                         
453                         switch(mcr->channel)
454                         {
455                                 case CHAN_B1:
456                                 case CHAN_B2:
457                                         if(ctrl_desc[mcr->controller].bch_state[mcr->channel] != BCH_ST_FREE)
458                                                 SET_CAUSE_VAL(cd->cause_in, CAUSE_I4B_NOCHAN);
459                                         break;
460
461                                 case CHAN_ANY:
462                                 {
463                                     int i;
464                                     for (i = 0;
465                                          i < ctrl_desc[mcr->controller].nbch &&
466                                          ctrl_desc[mcr->controller].bch_state[i] != BCH_ST_FREE;
467                                          i++);
468                                     if (i == ctrl_desc[mcr->controller].nbch)
469                                                 SET_CAUSE_VAL(cd->cause_in, CAUSE_I4B_NOCHAN);
470                                     /* else mcr->channel = i; XXX */
471                                 }
472                                         break;
473
474                                 default:
475                                         SET_CAUSE_VAL(cd->cause_in, CAUSE_I4B_NOCHAN);
476                                         break;
477                         }
478
479                         cd->channelid = mcr->channel;
480
481                         cd->isdntxdelay = mcr->txdelay;
482                         
483                         /* check whether we have a pointer. Seems like */
484                         /* this should be adequate. GJ 19.09.97 */
485                         if(ctrl_desc[cd->controller].N_CONNECT_REQUEST == NULL)
486 /*XXX*/                         SET_CAUSE_VAL(cd->cause_in, CAUSE_I4B_NOCHAN);
487
488                         if((GET_CAUSE_VAL(cd->cause_in)) != CAUSE_I4B_NORMAL)
489                         {
490                                 i4b_l4_disconnect_ind(cd);
491                                 freecd_by_cd(cd);
492                         }
493                         else
494                         {
495                                 (*ctrl_desc[cd->controller].N_CONNECT_REQUEST)(mcr->cdid);
496                         }
497                         break;
498                 }
499                 
500                 /* connect response, accept/reject/ignore incoming call */
501                 
502                 case I4B_CONNECT_RESP:
503                 {
504                         msg_connect_resp_t *mcrsp;
505                         
506                         mcrsp = (msg_connect_resp_t *)data;
507
508                         if((cd = cd_by_cdid(mcrsp->cdid)) == NULL)/* get cd */
509                         {
510                                 NDBGL4(L4_ERR, "I4B_CONNECT_RESP ioctl, cdid not found!"); 
511                                 error = EINVAL;
512                                 break;
513                         }
514
515                         T400_stop(cd);
516
517                         cd->driver = mcrsp->driver;
518                         cd->driver_unit = mcrsp->driver_unit;
519                         cd->max_idle_time = mcrsp->max_idle_time;
520
521                         cd->shorthold_data.shorthold_algorithm = SHA_FIXU;
522                         cd->shorthold_data.unitlen_time = 0;    /* this is incoming */
523                         cd->shorthold_data.idle_time = 0;
524                         cd->shorthold_data.earlyhup_time = 0;
525
526                         cd->isdntxdelay = mcrsp->txdelay;                       
527                         
528                         NDBGL4(L4_TIMO, "I4B_CONNECT_RESP max_idle_time set to %ld seconds", (long)cd->max_idle_time);
529
530                         (*ctrl_desc[cd->controller].N_CONNECT_RESPONSE)(mcrsp->cdid, mcrsp->response, mcrsp->cause);
531                         break;
532                 }
533                 
534                 /* disconnect request, actively terminate connection */
535                 
536                 case I4B_DISCONNECT_REQ:
537                 {
538                         msg_discon_req_t *mdr;
539                         
540                         mdr = (msg_discon_req_t *)data;
541
542                         if((cd = cd_by_cdid(mdr->cdid)) == NULL)/* get cd */
543                         {
544                                 NDBGL4(L4_ERR, "I4B_DISCONNECT_REQ ioctl, cdid not found!"); 
545                                 error = EINVAL;
546                                 break;
547                         }
548
549                         /* preset causes with our cause */
550                         cd->cause_in = cd->cause_out = mdr->cause;
551                         
552                         (*ctrl_desc[cd->controller].N_DISCONNECT_REQUEST)(mdr->cdid, mdr->cause);
553                         break;
554                 }
555                 
556                 /* controller info request */
557
558                 case I4B_CTRL_INFO_REQ:
559                 {
560                         msg_ctrl_info_req_t *mcir;
561                         
562                         mcir = (msg_ctrl_info_req_t *)data;
563                         mcir->ncontroller = nctrl;
564
565                         if(mcir->controller > nctrl)
566                         {
567                                 mcir->ctrl_type = -1;
568                                 mcir->card_type = -1;
569                         }
570                         else
571                         {
572                                 mcir->ctrl_type = 
573                                         ctrl_desc[mcir->controller].ctrl_type;
574                                 mcir->card_type = 
575                                         ctrl_desc[mcir->controller].card_type;
576                                 mcir->nbch =
577                                         ctrl_desc[mcir->controller].nbch;
578
579                                 if(ctrl_desc[mcir->controller].ctrl_type == CTRL_PASSIVE)
580                                         mcir->tei = ctrl_desc[mcir->controller].tei;
581                                 else
582                                         mcir->tei = -1;
583                         }
584                         break;
585                 }
586                 
587                 /* dial response */
588                 
589                 case I4B_DIALOUT_RESP:
590                 {
591                         drvr_link_t *dlt = NULL;
592                         msg_dialout_resp_t *mdrsp;
593                         
594                         mdrsp = (msg_dialout_resp_t *)data;
595
596                         switch(mdrsp->driver)
597                         {
598 #if NI4BIPR > 0
599                                 case BDRV_IPR:
600                                         dlt = ipr_ret_linktab(mdrsp->driver_unit);
601                                         break;
602 #endif                                  
603
604 #if NI4BISPPP > 0
605                                 case BDRV_ISPPP:
606                                         dlt = i4bisppp_ret_linktab(mdrsp->driver_unit);
607                                         break;
608 #endif
609
610 #if NI4BTEL > 0
611                                 case BDRV_TEL:
612                                         dlt = tel_ret_linktab(mdrsp->driver_unit);
613                                         break;
614 #endif
615
616 #if NIBC > 0
617                                 case BDRV_IBC:
618                                         dlt = ibc_ret_linktab(mdrsp->driver_unit);
619                                         break;
620 #endif
621
622 #if NI4BING > 0
623                                 case BDRV_ING:
624                                         dlt = ing_ret_linktab(mdrsp->driver_unit);
625                                         break;
626 #endif                                  
627                         }
628
629                         if(dlt != NULL)         
630                                 (*dlt->dial_response)(mdrsp->driver_unit, mdrsp->stat, mdrsp->cause);
631                         break;
632                 }
633                 
634                 /* update timeout value */
635                 
636                 case I4B_TIMEOUT_UPD:
637                 {
638                         msg_timeout_upd_t *mtu;
639                         int x;
640                         
641                         mtu = (msg_timeout_upd_t *)data;
642
643                         NDBGL4(L4_TIMO, "I4B_TIMEOUT_UPD ioctl, alg %d, unit %d, idle %d, early %d!",
644                                         mtu->shorthold_data.shorthold_algorithm, mtu->shorthold_data.unitlen_time,
645                                         mtu->shorthold_data.idle_time, mtu->shorthold_data.earlyhup_time); 
646
647                         if((cd = cd_by_cdid(mtu->cdid)) == NULL)/* get cd */
648                         {
649                                 NDBGL4(L4_ERR, "I4B_TIMEOUT_UPD ioctl, cdid not found!"); 
650                                 error = EINVAL;
651                                 break;
652                         }
653
654                         switch( mtu->shorthold_data.shorthold_algorithm )
655                         {
656                                 case SHA_FIXU:
657                                         /*
658                                          * For this algorithm unitlen_time,
659                                          * idle_time and earlyhup_time are used.
660                                          */
661
662                                         if(!(mtu->shorthold_data.unitlen_time >= 0 &&
663                                              mtu->shorthold_data.idle_time >= 0    &&
664                                              mtu->shorthold_data.earlyhup_time >= 0))
665                                         {
666                                                 NDBGL4(L4_ERR, "I4B_TIMEOUT_UPD ioctl, invalid args for fix unit algorithm!"); 
667                                                 error = EINVAL;
668                                         }
669                                         break;
670         
671                                 case SHA_VARU:
672                                         /*
673                                          * For this algorithm unitlen_time and
674                                          * idle_time are used. both must be
675                                          * positive integers. earlyhup_time is
676                                          * not used and must be 0.
677                                          */
678
679                                         if(!(mtu->shorthold_data.unitlen_time > 0 &&
680                                              mtu->shorthold_data.idle_time >= 0   &&
681                                              mtu->shorthold_data.earlyhup_time == 0))
682                                         {
683                                                 NDBGL4(L4_ERR, "I4B_TIMEOUT_UPD ioctl, invalid args for var unit algorithm!"); 
684                                                 error = EINVAL;
685                                         }
686                                         break;
687         
688                                 default:
689                                         NDBGL4(L4_ERR, "I4B_TIMEOUT_UPD ioctl, invalid algorithm!"); 
690                                         error = EINVAL;
691                                         break;
692                         }
693
694                         /*
695                          * any error set above requires us to break
696                          * out of the outer switch
697                          */
698                         if(error != 0)
699                                 break;
700
701                         x = SPLI4B();
702                         cd->shorthold_data.shorthold_algorithm = mtu->shorthold_data.shorthold_algorithm;
703                         cd->shorthold_data.unitlen_time = mtu->shorthold_data.unitlen_time;
704                         cd->shorthold_data.idle_time = mtu->shorthold_data.idle_time;
705                         cd->shorthold_data.earlyhup_time = mtu->shorthold_data.earlyhup_time;
706                         splx(x);
707                         break;
708                 }
709                         
710                 /* soft enable/disable interface */
711                 
712                 case I4B_UPDOWN_IND:
713                 {
714                         msg_updown_ind_t *mui;
715                         
716                         mui = (msg_updown_ind_t *)data;
717
718 #if NI4BIPR > 0
719                         if(mui->driver == BDRV_IPR)
720                         {
721                                 drvr_link_t *dlt;
722                                 dlt = ipr_ret_linktab(mui->driver_unit);
723                                 (*dlt->updown_ind)(mui->driver_unit, mui->updown);
724                         }
725 #endif
726                         break;
727                 }
728                 
729                 /* send ALERT request */
730                 
731                 case I4B_ALERT_REQ:
732                 {
733                         msg_alert_req_t *mar;
734                         
735                         mar = (msg_alert_req_t *)data;
736
737                         if((cd = cd_by_cdid(mar->cdid)) == NULL)
738                         {
739                                 NDBGL4(L4_ERR, "I4B_ALERT_REQ ioctl, cdid not found!"); 
740                                 error = EINVAL;
741                                 break;
742                         }
743
744                         T400_stop(cd);
745                         
746                         (*ctrl_desc[cd->controller].N_ALERT_REQUEST)(mar->cdid);
747
748                         break;
749                 }
750
751                 /* version/release number request */
752                 
753                 case I4B_VR_REQ:
754                 {
755                         msg_vr_req_t *mvr;
756
757                         mvr = (msg_vr_req_t *)data;
758
759                         mvr->version = VERSION;
760                         mvr->release = REL;
761                         mvr->step = STEP;                       
762                         break;
763                 }
764
765                 /* set D-channel protocol for a controller */
766                 
767                 case I4B_PROT_IND:
768                 {
769                         msg_prot_ind_t *mpi;
770                         
771                         mpi = (msg_prot_ind_t *)data;
772
773                         ctrl_desc[mpi->controller].protocol = mpi->protocol;
774                         
775                         break;
776                 }
777                 
778                 /* Download request */
779
780                 case I4B_CTRL_DOWNLOAD:
781                 {
782                         struct isdn_dr_prot *prots = NULL, *prots2 = NULL;
783                         struct isdn_download_request *r =
784                                 (struct isdn_download_request*)data;
785                         int i;
786
787                         if (r->controller < 0 || r->controller >= nctrl)
788                         {
789                                 error = ENODEV;
790                                 goto download_done;
791                         }
792
793                         if(!ctrl_desc[r->controller].N_DOWNLOAD)
794                         {
795                                 error = ENODEV;
796                                 goto download_done;
797                         }
798
799                         prots = malloc(r->numprotos * sizeof(struct isdn_dr_prot),
800                                         M_DEVBUF, M_WAITOK);
801
802                         prots2 = malloc(r->numprotos * sizeof(struct isdn_dr_prot),
803                                         M_DEVBUF, M_WAITOK);
804
805                         if(!prots || !prots2)
806                         {
807                                 error = ENOMEM;
808                                 goto download_done;
809                         }
810
811                         copyin(r->protocols, prots, r->numprotos * sizeof(struct isdn_dr_prot));
812
813                         for(i = 0; i < r->numprotos; i++)
814                         {
815                                 prots2[i].microcode = malloc(prots[i].bytecount, M_DEVBUF, M_WAITOK);
816                                 copyin(prots[i].microcode, prots2[i].microcode, prots[i].bytecount);
817                                 prots2[i].bytecount = prots[i].bytecount; 
818                         }
819
820                         error = ctrl_desc[r->controller].N_DOWNLOAD(
821                                                 ctrl_desc[r->controller].unit,
822                                                 r->numprotos, prots2);
823
824 download_done:
825                         if(prots2)
826                         {
827                                 for(i = 0; i < r->numprotos; i++)
828                                 {
829                                         if(prots2[i].microcode)
830                                         {
831                                                 free(prots2[i].microcode, M_DEVBUF);
832                                         }
833                                 }
834                                 free(prots2, M_DEVBUF);
835                         }
836
837                         if(prots)
838                         {
839                                 free(prots, M_DEVBUF);
840                         }
841                         break;
842                 }
843
844                 /* Diagnostic request */
845
846                 case I4B_ACTIVE_DIAGNOSTIC:
847                 {
848                         struct isdn_diagnostic_request req, *r =
849                                 (struct isdn_diagnostic_request*)data;
850
851                         req.in_param = req.out_param = NULL;
852                         if (r->controller < 0 || r->controller >= nctrl)
853                         {
854                                 error = ENODEV;
855                                 goto diag_done;
856                         }
857
858                         if(!ctrl_desc[r->controller].N_DIAGNOSTICS)
859                         {
860                                 error = ENODEV;
861                                 goto diag_done;
862                         }
863
864                         memcpy(&req, r, sizeof(req));
865
866                         if(req.in_param_len)
867                         {
868                                 /* XXX arbitrary limit */
869                                 if (req.in_param_len >
870                                     I4B_ACTIVE_DIAGNOSTIC_MAXPARAMLEN) {
871                                         error = EINVAL;
872                                         goto diag_done;
873                                 }       
874
875                                 req.in_param = malloc(r->in_param_len, M_DEVBUF, M_WAITOK);
876
877                                 if(!req.in_param)
878                                 {
879                                         error = ENOMEM;
880                                         goto diag_done;
881                                 }
882                                 error = copyin(r->in_param, req.in_param, req.in_param_len);
883                                 if (error)
884                                         goto diag_done;
885                         }
886
887                         if(req.out_param_len)
888                         {
889                                 req.out_param = malloc(r->out_param_len, M_DEVBUF, M_WAITOK);
890
891                                 if(!req.out_param)
892                                 {
893                                         error = ENOMEM;
894                                         goto diag_done;
895                                 }
896                         }
897                         
898                         error = ctrl_desc[r->controller].N_DIAGNOSTICS(r->controller, &req);
899
900                         if(!error && req.out_param_len)
901                                 error = copyout(req.out_param, r->out_param, req.out_param_len);
902
903 diag_done:
904                         if(req.in_param)
905                                 free(req.in_param, M_DEVBUF);
906                                 
907                         if(req.out_param)
908                                 free(req.out_param, M_DEVBUF);
909
910                         break;
911                 }
912
913                 /* default */
914                 
915                 default:
916                         error = ENOTTY;
917                         break;
918         }
919         
920         return(error);
921 }
922
923 #ifdef OS_USES_SELECT
924
925 /*---------------------------------------------------------------------------*
926  *      i4bselect - device driver select routine
927  *---------------------------------------------------------------------------*/
928 PDEVSTATIC int
929 i4bselect(dev_t dev, int rw, struct thread *td)
930 {
931         int x;
932         
933         if(minor(dev))
934                 return(ENODEV);
935
936         switch(rw)
937         {
938                 case FREAD:
939                         if(!IF_QEMPTY(&i4b_rdqueue))
940                                 return(1);
941                         x = splimp();
942                         selrecord(td, &select_rd_info);
943                         selflag = 1;
944                         splx(x);
945                         return(0);
946                         break;
947
948                 case FWRITE:
949                         return(1);
950                         break;
951         }
952         return(0);
953 }
954
955 #else /* OS_USES_SELECT */
956
957 /*---------------------------------------------------------------------------*
958  *      i4bpoll - device driver poll routine
959  *---------------------------------------------------------------------------*/
960 PDEVSTATIC int
961 i4bpoll(dev_t dev, int events, struct thread *td)
962 {
963         int x;
964         
965         if(minor(dev))
966                 return(ENODEV);
967
968         if((events & POLLIN) || (events & POLLRDNORM))
969         {
970                 if(!IF_QEMPTY(&i4b_rdqueue))
971                         return(1);
972
973                 x = splimp();
974                 selrecord(td, &select_rd_info);
975                 selflag = 1;
976                 splx(x);
977                 return(0);
978         }
979         else if((events & POLLOUT) || (events & POLLWRNORM))
980         {
981                 return(1);
982         }
983
984         return(0);
985 }
986
987 #endif /* OS_USES_SELECT */
988
989 /*---------------------------------------------------------------------------*
990  *      i4bputqueue - put message into queue to userland
991  *---------------------------------------------------------------------------*/
992 void
993 i4bputqueue(struct mbuf *m)
994 {
995         int x;
996         
997         if(!openflag)
998         {
999                 i4b_Dfreembuf(m);
1000                 return;
1001         }
1002
1003         x = splimp();
1004         
1005         if(IF_QFULL(&i4b_rdqueue))
1006         {
1007                 struct mbuf *m1;
1008                 IF_DEQUEUE(&i4b_rdqueue, m1);
1009                 i4b_Dfreembuf(m1);
1010                 NDBGL4(L4_ERR, "ERROR, queue full, removing entry!");
1011         }
1012
1013         IF_ENQUEUE(&i4b_rdqueue, m);
1014
1015         splx(x);        
1016
1017         if(readflag)
1018         {
1019                 readflag = 0;
1020                 wakeup((caddr_t) &i4b_rdqueue);
1021         }
1022
1023         if(selflag)
1024         {
1025                 selflag = 0;
1026                 selwakeup(&select_rd_info);
1027         }
1028 }
1029
1030 /*---------------------------------------------------------------------------*
1031  *      i4bputqueue_hipri - put message into front of queue to userland
1032  *---------------------------------------------------------------------------*/
1033 void
1034 i4bputqueue_hipri(struct mbuf *m)
1035 {
1036         int x;
1037         
1038         if(!openflag)
1039         {
1040                 i4b_Dfreembuf(m);
1041                 return;
1042         }
1043
1044         x = splimp();
1045         
1046         if(IF_QFULL(&i4b_rdqueue))
1047         {
1048                 struct mbuf *m1;
1049                 IF_DEQUEUE(&i4b_rdqueue, m1);
1050                 i4b_Dfreembuf(m1);
1051                 NDBGL4(L4_ERR, "ERROR, queue full, removing entry!");
1052         }
1053
1054         IF_PREPEND(&i4b_rdqueue, m);
1055
1056         splx(x);        
1057
1058         if(readflag)
1059         {
1060                 readflag = 0;
1061                 wakeup((caddr_t) &i4b_rdqueue);
1062         }
1063
1064         if(selflag)
1065         {
1066                 selflag = 0;
1067                 selwakeup(&select_rd_info);
1068         }
1069 }
1070
1071 #endif /* NI4B > 0 */