Merge from vendor branch SENDMAIL:
[dragonfly.git] / sys / net / i4b / driver / i4b_trace.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  *      i4btrc - device driver for trace data read device
28  *      ---------------------------------------------------
29  *
30  *      last edit-date: [Sat Aug 11 18:07:15 2001]
31  *
32  * $FreeBSD: src/sys/i4b/driver/i4b_trace.c,v 1.9.2.3 2001/08/12 16:22:48 hm Exp $
33  * $DragonFly: src/sys/net/i4b/driver/i4b_trace.c,v 1.12 2005/06/03 16:49:57 dillon Exp $
34  *
35  *---------------------------------------------------------------------------*/
36
37 #include "use_i4btrc.h"
38
39 #if NI4BTRC > 0
40
41 #include <sys/param.h>
42 #include <sys/systm.h>
43
44 #if defined(__DragonFly__) || (defined(__FreeBSD__) && __FreeBSD__ >= 3)
45 #include <sys/ioccom.h>
46 #else
47 #include <sys/ioctl.h>
48 #endif
49
50 #include <sys/conf.h>
51 #include <sys/uio.h>
52 #include <sys/kernel.h>
53 #include <sys/mbuf.h>
54 #include <sys/socket.h>
55 #include <net/if.h>
56 #include <sys/tty.h>
57 #include <sys/thread2.h>
58
59 #if defined(__DragonFly__) || defined(__FreeBSD__)
60
61 #ifdef DEVFS
62 #include <sys/devfsext.h>
63 #endif
64
65 #include <net/i4b/include/machine/i4b_trace.h>
66 #include <net/i4b/include/machine/i4b_ioctl.h>
67
68 #else
69
70 #include <i4b/i4b_trace.h>
71 #include <i4b/i4b_ioctl.h>
72
73 #endif
74
75 #include "../include/i4b_mbuf.h"
76 #include "../include/i4b_global.h"
77 #include "../include/i4b_l3l4.h"
78
79 #if !defined(__DragonFly__) && !defined(__FreeBSD__)
80 #define memcpy(d,s,l)   bcopy(s,d,l)
81 #endif
82
83 static struct ifqueue trace_queue[NI4BTRC];
84 static int device_state[NI4BTRC];
85 #define ST_IDLE         0x00
86 #define ST_ISOPEN       0x01
87 #define ST_WAITDATA     0x02
88
89 #if defined(__FreeBSD__) && __FreeBSD__ == 3
90 #ifdef DEVFS
91 static void *devfs_token[NI4BTRC];
92 #endif
93 #endif
94
95 static int analyzemode = 0;
96 static int rxunit = -1;
97 static int txunit = -1;
98 static int outunit = -1;
99
100 #if !defined(__DragonFly__) && !defined(__FreeBSD__)
101
102 #define PDEVSTATIC      /* - not static - */
103 void i4btrcattach (void);
104 int i4btrcopen (dev_t dev, int flag, int fmt, struct proc *p);
105 int i4btrcclose (dev_t dev, int flag, int fmt, struct proc *p);
106 int i4btrcread (dev_t dev, struct uio * uio, int ioflag);
107
108 #ifdef __bsdi__
109 int i4btrcioctl (dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p);
110 #else
111 int i4btrcioctl (dev_t dev, int cmd, caddr_t data, int flag, struct proc *p);
112 #endif
113
114 #endif
115
116 #if defined(__DragonFly__) || (BSD > 199306 && defined(__FreeBSD__))
117 #define PDEVSTATIC static
118 static d_open_t i4btrcopen;
119 static d_close_t i4btrcclose;
120 static d_read_t i4btrcread;
121 static d_ioctl_t i4btrcioctl;
122
123 #ifdef OS_USES_POLL
124 static d_poll_t i4btrcpoll;
125 #define POLLFIELD i4btrcpoll
126 #else
127 #define POLLFIELD noselect
128 #endif
129
130 #define CDEV_MAJOR 59
131
132 static struct cdevsw i4btrc_cdevsw = {
133         /* name */      "i4btrc",
134         /* maj */       CDEV_MAJOR,
135         /* flags */     0,
136         /* port */      NULL,
137         /* clone */     NULL,
138
139         /* open */      i4btrcopen,
140         /* close */     i4btrcclose,
141         /* read */      i4btrcread,
142         /* write */     nowrite,
143         /* ioctl */     i4btrcioctl,
144         /* poll */      POLLFIELD,
145         /* mmap */      nommap,
146         /* strategy */  nostrategy,
147         /* dump */      nodump,
148         /* psize */     nopsize
149 };
150
151 /*---------------------------------------------------------------------------*
152  *      interface init routine
153  *---------------------------------------------------------------------------*/
154 static
155 void i4btrcinit(void *unused)
156 {
157         cdevsw_add(&i4btrc_cdevsw, 0, 0);
158 }
159
160 SYSINIT(i4btrcdev, SI_SUB_DRIVERS,
161         SI_ORDER_MIDDLE+CDEV_MAJOR, &i4btrcinit, NULL);
162
163 static void i4btrcattach(void *);
164 PSEUDO_SET(i4btrcattach, i4b_trace);
165
166 #endif /* BSD > 199306 && defined(__FreeBSD__) */
167
168 #ifdef __bsdi__
169 #include <sys/device.h>
170 int i4btrcmatch(struct device *parent, struct cfdata *cf, void *aux);
171 void dummy_i4btrcattach(struct device*, struct device *, void *);
172
173 #define CDEV_MAJOR 60
174
175 static struct cfdriver i4btrccd =
176         { NULL, "i4btrc", i4btrcmatch, dummy_i4btrcattach, DV_DULL,
177           sizeof(struct cfdriver) };
178 struct devsw i4btrcsw = 
179         { &i4btrccd,
180           i4btrcopen,   i4btrcclose,    i4btrcread,     nowrite,
181           i4btrcioctl,  seltrue,        nommap,         nostrat,
182           nodump,       nopsize,        0,              nostop
183 };
184
185 int
186 i4btrcmatch(struct device *parent, struct cfdata *cf, void *aux)
187 {
188         printf("i4btrcmatch: aux=0x%x\n", aux);
189         return 1;
190 }
191 void
192 dummy_i4btrcattach(struct device *parent, struct device *self, void *aux)
193 {
194         printf("dummy_i4btrcattach: aux=0x%x\n", aux);
195 }
196 #endif /* __bsdi__ */
197
198 int get_trace_data_from_l1(i4b_trace_hdr_t *hdr, int len, char *buf);
199
200 /*---------------------------------------------------------------------------*
201  *      interface attach routine
202  *---------------------------------------------------------------------------*/
203 PDEVSTATIC void
204 #if defined(__DragonFly__) || defined(__FreeBSD__)
205 i4btrcattach(void *dummy)
206 #else
207 i4btrcattach()
208 #endif
209 {
210         int i;
211
212         printf("i4btrc: %d ISDN trace device(s) attached\n", NI4BTRC);
213         
214         for(i=0; i < NI4BTRC; i++)
215         {
216
217 #if defined(__DragonFly__) || defined(__FreeBSD__)
218                 make_dev(&i4btrc_cdevsw, i,
219                                      UID_ROOT, GID_WHEEL, 0600, "i4btrc%d", i);
220 #endif
221                 trace_queue[i].ifq_maxlen = IFQ_MAXLEN;
222
223 #if defined(__FreeBSD__) && __FreeBSD__ > 4
224                 mtx_init(&trace_queue[i].ifq_mtx, "i4b_trace", MTX_DEF);
225 #endif
226                 device_state[i] = ST_IDLE;
227         }
228 }
229
230 /*---------------------------------------------------------------------------*
231  *      get_trace_data_from_l1()
232  *      ------------------------
233  *      is called from layer 1, adds timestamp to trace data and puts
234  *      it into a queue, from which it can be read from the i4btrc
235  *      device. The unit number in the trace header selects the minor
236  *      device's queue the data is put into.
237  *---------------------------------------------------------------------------*/
238 int
239 get_trace_data_from_l1(i4b_trace_hdr_t *hdr, int len, char *buf)
240 {
241         struct mbuf *m;
242         int unit;
243         int trunc = 0;
244         int totlen = len + sizeof(i4b_trace_hdr_t);
245
246         /*
247          * for telephony (or better non-HDLC HSCX mode) we get 
248          * (MCLBYTE + sizeof(i4b_trace_hdr_t)) length packets
249          * to put into the queue to userland. because of this
250          * we detect this situation, strip the length to MCLBYTES
251          * max size, and infor the userland program of this fact
252          * by putting the no of truncated bytes into hdr->trunc.
253          */
254          
255         if(totlen > MCLBYTES)
256         {
257                 trunc = 1;
258                 hdr->trunc = totlen - MCLBYTES;
259                 totlen = MCLBYTES;
260         }
261         else
262         {
263                 hdr->trunc = 0;
264         }
265
266         /* set length of trace record */
267         
268         hdr->length = totlen;
269         
270         /* check valid unit no */
271         
272         if((unit = hdr->unit) > NI4BTRC)
273         {
274                 printf("i4b_trace: get_trace_data_from_l1 - unit > NI4BTRC!\n"); 
275                 return(0);
276         }
277
278         /* get mbuf */
279         
280         if(!(m = i4b_Bgetmbuf(totlen)))
281         {
282                 printf("i4b_trace: get_trace_data_from_l1 - i4b_getmbuf() failed!\n");
283                 return(0);
284         }
285
286         /* check if we are in analyzemode */
287         
288         if(analyzemode && (unit == rxunit || unit == txunit))
289         {
290                 if(unit == rxunit)
291                         hdr->dir = FROM_NT;
292                 else
293                         hdr->dir = FROM_TE;
294                 unit = outunit;                 
295         }
296
297         if(IF_QFULL(&trace_queue[unit]))
298         {
299                 struct mbuf *m1;
300
301                 crit_enter();
302                 IF_DEQUEUE(&trace_queue[unit], m1);
303                 crit_exit();
304
305                 i4b_Bfreembuf(m1);
306         }
307         
308         /* copy trace header */
309         memcpy(m->m_data, hdr, sizeof(i4b_trace_hdr_t));
310
311         /* copy trace data */
312         if(trunc)
313                 memcpy(&m->m_data[sizeof(i4b_trace_hdr_t)], buf, totlen-sizeof(i4b_trace_hdr_t));
314         else
315                 memcpy(&m->m_data[sizeof(i4b_trace_hdr_t)], buf, len);
316
317         crit_enter();
318         
319         IF_ENQUEUE(&trace_queue[unit], m);
320         
321         if(device_state[unit] & ST_WAITDATA)
322         {
323                 device_state[unit] &= ~ST_WAITDATA;
324                 wakeup((caddr_t) &trace_queue[unit]);
325         }
326
327         crit_exit();
328         
329         return(1);
330 }
331
332 /*---------------------------------------------------------------------------*
333  *      open trace device
334  *---------------------------------------------------------------------------*/
335 PDEVSTATIC int
336 i4btrcopen(dev_t dev, int flag, int fmt, struct thread *td)
337 {
338         int unit = minor(dev);
339
340         if(unit >= NI4BTRC)
341                 return(ENXIO);
342
343         if(device_state[unit] & ST_ISOPEN)
344                 return(EBUSY);
345
346         if(analyzemode && (unit == outunit || unit == rxunit || unit == txunit))
347                 return(EBUSY);
348
349         crit_enter();
350         
351         device_state[unit] = ST_ISOPEN;         
352
353         crit_exit();
354         
355         return(0);
356 }
357
358 /*---------------------------------------------------------------------------*
359  *      close trace device
360  *---------------------------------------------------------------------------*/
361 PDEVSTATIC int
362 i4btrcclose(dev_t dev, int flag, int fmt, struct thread *td)
363 {
364         int unit = minor(dev);
365         int i;
366         int cno = -1;
367
368         for(i=0; i < nctrl; i++)
369         {
370                 if((ctrl_desc[i].ctrl_type == CTRL_PASSIVE) &&
371                         (ctrl_desc[i].unit == unit))
372                 {
373                         cno = i;
374                         break;
375                 }
376         }
377
378         if(analyzemode && (unit == outunit))
379         {
380                 analyzemode = 0;                
381                 outunit = -1;
382                 
383                 if(cno >= 0)
384                 {
385                         (*ctrl_desc[cno].N_MGMT_COMMAND)(rxunit, CMR_SETTRACE, TRACE_OFF);
386                         (*ctrl_desc[cno].N_MGMT_COMMAND)(txunit, CMR_SETTRACE, TRACE_OFF);
387                 }
388                 rxunit = -1;
389                 txunit = -1;
390         }
391         
392         if(cno >= 0)
393         {
394                         (*ctrl_desc[cno].N_MGMT_COMMAND)(ctrl_desc[cno].unit, CMR_SETTRACE, TRACE_OFF);
395         }
396
397         crit_enter();
398         device_state[unit] = ST_IDLE;
399         crit_exit();
400         
401         return(0);
402 }
403
404 /*---------------------------------------------------------------------------*
405  *      read from trace device
406  *---------------------------------------------------------------------------*/
407 PDEVSTATIC int
408 i4btrcread(dev_t dev, struct uio * uio, int ioflag)
409 {
410         struct mbuf *m;
411         int error = 0;
412         int unit = minor(dev);
413         
414         if(!(device_state[unit] & ST_ISOPEN))
415                 return(EIO);
416
417         crit_enter();
418         
419         while(IF_QEMPTY(&trace_queue[unit]) && (device_state[unit] & ST_ISOPEN))
420         {
421                 device_state[unit] |= ST_WAITDATA;
422                 
423 #if defined (__FreeBSD__) && __FreeBSD__ > 4
424                 if((error = msleep((caddr_t) &trace_queue[unit],
425                                         &trace_queue[unit].ifq_mtx,
426                                         TTIPRI | PCATCH,
427                                         "bitrc", 0 )) != 0)
428 #else
429                 if((error = tsleep((caddr_t) &trace_queue[unit],
430                                         PCATCH, "bitrc", 0 )) != 0)
431 #endif                                                                                               
432                 {
433                         device_state[unit] &= ~ST_WAITDATA;
434                         crit_exit();
435                         return(error);
436                 }
437         }
438
439         IF_DEQUEUE(&trace_queue[unit], m);
440
441         if(m && m->m_len)
442                 error = uiomove(m->m_data, m->m_len, uio);
443         else
444                 error = EIO;
445                 
446         if(m)
447                 i4b_Bfreembuf(m);
448
449         crit_exit();
450         
451         return(error);
452 }
453
454 #if (defined(__DragonFly__) || defined(__FreeBSD__)) && defined(OS_USES_POLL)
455 /*---------------------------------------------------------------------------*
456  *      poll device
457  *---------------------------------------------------------------------------*/
458 PDEVSTATIC int
459 i4btrcpoll(dev_t dev, int events, struct thread *td)
460 {
461         return(ENODEV);
462 }
463 #endif
464
465 /*---------------------------------------------------------------------------*
466  *      device driver ioctl routine
467  *---------------------------------------------------------------------------*/
468 PDEVSTATIC int
469 #if defined(__DragonFly__) || (defined (__FreeBSD_version) && __FreeBSD_version >= 300003)
470 i4btrcioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
471 #elif defined(__bsdi__)
472 i4btrcioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
473 #else
474 i4btrcioctl(dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
475 #endif
476 {
477         int error = 0;
478         int unit = minor(dev);
479         i4b_trace_setupa_t *tsa;
480         int i;
481         int cno = -1;
482
483         /* find the first passive controller matching our unit no */
484
485         for(i=0; i < nctrl; i++)
486         {
487                 if((ctrl_desc[i].ctrl_type == CTRL_PASSIVE) &&
488                         (ctrl_desc[i].unit == unit))
489                 {
490                         cno = i;
491                         break;
492                 }
493         }
494         
495         switch(cmd)
496         {
497                 case I4B_TRC_SET:
498                         if(cno < 0)
499                                 return ENOTTY;
500                         (*ctrl_desc[cno].N_MGMT_COMMAND)(ctrl_desc[cno].unit, CMR_SETTRACE, (void *)*(unsigned int *)data);
501                         break;
502
503                 case I4B_TRC_SETA:
504                         tsa = (i4b_trace_setupa_t *)data;
505
506                         if(tsa->rxunit >= 0 && tsa->rxunit < NI4BTRC)
507                                 rxunit = tsa->rxunit;
508                         else
509                                 error = EINVAL;
510
511                         if(tsa->txunit >= 0 && tsa->txunit < NI4BTRC)
512                                 txunit = tsa->txunit;
513                         else
514                                 error = EINVAL;
515
516                         if(error)
517                         {
518                                 outunit = -1;
519                                 rxunit = -1;
520                                 txunit = -1;
521                         }
522                         else
523                         {
524                                 if(cno < 0)
525                                         return ENOTTY;
526                                         
527                                 outunit = unit;
528                                 analyzemode = 1;
529                                 (*ctrl_desc[cno].N_MGMT_COMMAND)(rxunit, CMR_SETTRACE, (int *)(tsa->rxflags & (TRACE_I | TRACE_D_RX | TRACE_B_RX)));
530                                 (*ctrl_desc[cno].N_MGMT_COMMAND)(txunit, CMR_SETTRACE, (int *)(tsa->txflags & (TRACE_I | TRACE_D_RX | TRACE_B_RX)));
531                         }
532                         break;
533
534                 case I4B_TRC_RESETA:
535                         analyzemode = 0;                
536                         outunit = -1;
537                         rxunit = -1;
538                         txunit = -1;
539                         break;
540                         
541                 default:
542                         error = ENOTTY;
543                         break;
544         }
545         return(error);
546 }
547
548 #endif /* NI4BTRC > 0 */