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