1 /*
2 * Copyright (c) 1997, 2000 Hellmuth Michaelis. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 *
25 *---------------------------------------------------------------------------
26 *
27 * i4btrc - device driver for trace data read device
28 * ---------------------------------------------------
29 *
30 * $Id: i4b_trace.c,v 1.13 2003/10/03 16:38:44 pooka Exp $
31 *
32 * last edit-date: [Fri Jan 5 11:33:47 2001]
33 *
34 *
35 *---------------------------------------------------------------------------*/
36
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: i4b_trace.c,v 1.13 2003/10/03 16:38:44 pooka Exp $");
39
40 #include "isdntrc.h"
41
42 #if NISDNTRC > 0
43
44 #include <sys/param.h>
45 #include <sys/systm.h>
46
47 #if defined(__FreeBSD__) && __FreeBSD__ >= 3
48 #include <sys/ioccom.h>
49 #else
50 #include <sys/ioctl.h>
51 #endif
52
53 #include <sys/conf.h>
54 #include <sys/uio.h>
55 #include <sys/kernel.h>
56 #include <sys/mbuf.h>
57 #include <sys/socket.h>
58 #include <net/if.h>
59 #include <sys/proc.h>
60 #include <sys/tty.h>
61
62 #include <netisdn/i4b_trace.h>
63 #include <netisdn/i4b_ioctl.h>
64
65 #include <netisdn/i4b_mbuf.h>
66 #include <netisdn/i4b_global.h>
67 #include <netisdn/i4b_debug.h>
68 #include <netisdn/i4b_l3l4.h>
69 #include <netisdn/i4b_l2.h>
70 #include <netisdn/i4b_l1l2.h>
71
72 static struct ifqueue trace_queue[NISDNTRC];
73 static int device_state[NISDNTRC];
74 #define ST_IDLE 0x00
75 #define ST_ISOPEN 0x01
76 #define ST_WAITDATA 0x02
77
78 static int analyzemode = 0; /* we are in anlyzer mode */
79 static int rxunit = -1; /* l2 isdnif of receiving driver */
80 static int txunit = -1; /* l2 isdnif of transmitting driver */
81 static int outunit = -1; /* output device for trace data */
82
83 #define PDEVSTATIC /* - not static - */
84 void isdntrcattach __P((void));
85 int isdntrcopen __P((dev_t dev, int flag, int fmt, struct proc *p));
86 int isdntrcclose __P((dev_t dev, int flag, int fmt, struct proc *p));
87 int isdntrcread __P((dev_t dev, struct uio * uio, int ioflag));
88 int isdntrcioctl __P((dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p));
89
90 #ifdef __NetBSD__
91 const struct cdevsw isdntrc_cdevsw = {
92 isdntrcopen, isdntrcclose, isdntrcread, nowrite, isdntrcioctl,
93 nostop, notty, nopoll, nommap, nokqfilter,
94 };
95 #endif /* __NetBSD__ */
96
97 /*---------------------------------------------------------------------------*
98 * interface attach routine
99 *---------------------------------------------------------------------------*/
100 PDEVSTATIC void
101 #ifdef __FreeBSD__
102 isdntrcattach(void *dummy)
103 #else
104 isdntrcattach()
105 #endif
106 {
107 int i;
108
109 for(i=0; i < NISDNTRC; i++)
110 {
111
112 #if defined(__FreeBSD__)
113 #if __FreeBSD__ < 4
114
115 #ifdef DEVFS
116 devfs_token[i]
117 = devfs_add_devswf(&i4btrc_cdevsw, i, DV_CHR,
118 UID_ROOT, GID_WHEEL, 0600,
119 "isdntrc%d", i);
120 #endif
121
122 #else
123 make_dev(&i4btrc_cdevsw, i,
124 UID_ROOT, GID_WHEEL, 0600, "isdntrc%d", i);
125 #endif
126 #endif
127 trace_queue[i].ifq_maxlen = IFQ_MAXLEN;
128 device_state[i] = ST_IDLE;
129 }
130 }
131
132 /*---------------------------------------------------------------------------*
133 * isdn_layer2_trace_ind
134 * ---------------------
135 * is called from layer 1, adds timestamp to trace data and puts
136 * it into a queue, from which it can be read from the i4btrc
137 * device. The unit number in the trace header selects the minor
138 * device's queue the data is put into.
139 *---------------------------------------------------------------------------*/
140 int
141 isdn_layer2_trace_ind(struct l2_softc *sc, struct isdn_l3_driver *drv, i4b_trace_hdr *hdr, size_t len, unsigned char *buf)
142 {
143 struct mbuf *m;
144 int isdnif, x;
145 int trunc = 0;
146 int totlen = len + sizeof(i4b_trace_hdr);
147
148 MICROTIME(hdr->time);
149 hdr->isdnif = sc->drv->isdnif;
150
151 /*
152 * for telephony (or better non-HDLC HSCX mode) we get
153 * (MCLBYTE + sizeof(i4b_trace_hdr_t)) length packets
154 * to put into the queue to userland. because of this
155 * we detect this situation, strip the length to MCLBYTES
156 * max size, and infor the userland program of this fact
157 * by putting the no of truncated bytes into hdr->trunc.
158 */
159
160 if(totlen > MCLBYTES)
161 {
162 trunc = 1;
163 hdr->trunc = totlen - MCLBYTES;
164 totlen = MCLBYTES;
165 }
166 else
167 {
168 hdr->trunc = 0;
169 }
170
171 /* set length of trace record */
172
173 hdr->length = totlen;
174
175 /* check valid interface */
176
177 if((isdnif = hdr->isdnif) > NISDNTRC)
178 {
179 printf("i4b_trace: get_trace_data_from_l1 - isdnif > NISDNTRC!\n");
180 return(0);
181 }
182
183 /* get mbuf */
184
185 if(!(m = i4b_Bgetmbuf(totlen)))
186 {
187 printf("i4b_trace: get_trace_data_from_l1 - i4b_getmbuf() failed!\n");
188 return(0);
189 }
190
191 /* check if we are in analyzemode */
192
193 if(analyzemode && (isdnif == rxunit || isdnif == txunit))
194 {
195 if(isdnif == rxunit)
196 hdr->dir = FROM_NT;
197 else
198 hdr->dir = FROM_TE;
199 isdnif = outunit;
200 }
201
202 if(IF_QFULL(&trace_queue[isdnif]))
203 {
204 struct mbuf *m1;
205
206 x = splnet();
207 IF_DEQUEUE(&trace_queue[isdnif], m1);
208 splx(x);
209
210 i4b_Bfreembuf(m1);
211 }
212
213 /* copy trace header */
214 memcpy(m->m_data, hdr, sizeof(i4b_trace_hdr));
215
216 /* copy trace data */
217 if(trunc)
218 memcpy(&m->m_data[sizeof(i4b_trace_hdr)], buf, totlen-sizeof(i4b_trace_hdr));
219 else
220 memcpy(&m->m_data[sizeof(i4b_trace_hdr)], buf, len);
221
222 x = splnet();
223
224 IF_ENQUEUE(&trace_queue[isdnif], m);
225
226 if(device_state[isdnif] & ST_WAITDATA)
227 {
228 device_state[isdnif] &= ~ST_WAITDATA;
229 wakeup((caddr_t) &trace_queue[isdnif]);
230 }
231
232 splx(x);
233
234 return(1);
235 }
236
237 /*---------------------------------------------------------------------------*
238 * open trace device
239 *---------------------------------------------------------------------------*/
240 PDEVSTATIC int
241 isdntrcopen(dev_t dev, int flag, int fmt, struct proc *p)
242 {
243 int x;
244 int unit = minor(dev);
245
246 if(unit >= NISDNTRC)
247 return(ENXIO);
248
249 if(device_state[unit] & ST_ISOPEN)
250 return(EBUSY);
251
252 if(analyzemode && (unit == outunit || unit == rxunit || unit == txunit))
253 return(EBUSY);
254
255
256 x = splnet();
257
258 device_state[unit] = ST_ISOPEN;
259
260 splx(x);
261
262 return(0);
263 }
264
265 /*---------------------------------------------------------------------------*
266 * close trace device
267 *---------------------------------------------------------------------------*/
268 PDEVSTATIC int
269 isdntrcclose(dev_t dev, int flag, int fmt, struct proc *p)
270 {
271 int isdnif = minor(dev);
272 int x;
273
274 if (analyzemode && (isdnif == outunit)) {
275 l2_softc_t * rx_l2sc, * tx_l2sc;
276 analyzemode = 0;
277 outunit = -1;
278
279 rx_l2sc = (l2_softc_t*)isdn_find_softc_by_isdnif(rxunit);
280 tx_l2sc = (l2_softc_t*)isdn_find_softc_by_isdnif(txunit);
281
282 if (rx_l2sc != NULL)
283 rx_l2sc->driver->mph_command_req(rx_l2sc->l1_token, CMR_SETTRACE, TRACE_OFF);
284 if (tx_l2sc != NULL)
285 tx_l2sc->driver->mph_command_req(tx_l2sc->l1_token, CMR_SETTRACE, TRACE_OFF);
286
287 x = splnet();
288 device_state[rxunit] = ST_IDLE;
289 device_state[txunit] = ST_IDLE;
290 splx(x);
291 rxunit = -1;
292 txunit = -1;
293 } else {
294 l2_softc_t * l2sc = (l2_softc_t*)isdn_find_softc_by_isdnif(isdnif);
295 if (l2sc != NULL) {
296 l2sc->driver->mph_command_req(l2sc->l1_token, CMR_SETTRACE, TRACE_OFF);
297 x = splnet();
298 device_state[isdnif] = ST_IDLE;
299 splx(x);
300 }
301 }
302 return(0);
303 }
304
305 /*---------------------------------------------------------------------------*
306 * read from trace device
307 *---------------------------------------------------------------------------*/
308 PDEVSTATIC int
309 isdntrcread(dev_t dev, struct uio * uio, int ioflag)
310 {
311 struct mbuf *m;
312 int x;
313 int error = 0;
314 int unit = minor(dev);
315
316 if(!(device_state[unit] & ST_ISOPEN))
317 return(EIO);
318
319 x = splnet();
320
321 while(IF_QEMPTY(&trace_queue[unit]) && (device_state[unit] & ST_ISOPEN))
322 {
323 device_state[unit] |= ST_WAITDATA;
324
325 if((error = tsleep((caddr_t) &trace_queue[unit],
326 TTIPRI | PCATCH,
327 "bitrc", 0 )) != 0)
328 {
329 device_state[unit] &= ~ST_WAITDATA;
330 splx(x);
331 return(error);
332 }
333 }
334
335 IF_DEQUEUE(&trace_queue[unit], m);
336
337 if(m && m->m_len)
338 error = uiomove(m->m_data, m->m_len, uio);
339 else
340 error = EIO;
341
342 if(m)
343 i4b_Bfreembuf(m);
344
345 splx(x);
346
347 return(error);
348 }
349
350 #if defined(__FreeBSD__) && defined(OS_USES_POLL)
351 /*---------------------------------------------------------------------------*
352 * poll device
353 *---------------------------------------------------------------------------*/
354 PDEVSTATIC int
355 i4btrcpoll(dev_t dev, int events, struct proc *p)
356 {
357 return(ENODEV);
358 }
359 #endif
360
361 /*---------------------------------------------------------------------------*
362 * device driver ioctl routine
363 *---------------------------------------------------------------------------*/
364 PDEVSTATIC int
365 isdntrcioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
366 {
367 int error = 0;
368 int isdnif = minor(dev);
369 i4b_trace_setupa_t *tsa;
370 l2_softc_t * l2sc = (l2_softc_t*)isdn_find_softc_by_isdnif(isdnif);
371
372 switch(cmd)
373 {
374 case I4B_TRC_SET:
375 if (l2sc == NULL)
376 return ENOTTY;
377 l2sc->driver->mph_command_req(l2sc->l1_token, CMR_SETTRACE, (void *)*(unsigned long *)data);
378 break;
379
380 case I4B_TRC_SETA:
381 tsa = (i4b_trace_setupa_t *)data;
382
383 if(tsa->rxunit >= 0 && tsa->rxunit < NISDNTRC)
384 rxunit = tsa->rxunit;
385 else
386 error = EINVAL;
387
388 if(tsa->txunit >= 0 && tsa->txunit < NISDNTRC)
389 txunit = tsa->txunit;
390 else
391 error = EINVAL;
392
393 if(error)
394 {
395 outunit = -1;
396 rxunit = -1;
397 txunit = -1;
398 }
399 else
400 {
401 l2_softc_t * rx_l2sc, * tx_l2sc;
402 rx_l2sc = (l2_softc_t*)(l2_softc_t*)isdn_find_softc_by_isdnif(rxunit);
403 tx_l2sc = (l2_softc_t*)(l2_softc_t*)isdn_find_softc_by_isdnif(txunit);
404
405 if (l2sc == NULL || rx_l2sc == NULL || tx_l2sc == NULL)
406 return ENOTTY;
407
408 outunit = isdnif;
409 analyzemode = 1;
410 rx_l2sc->driver->mph_command_req(rx_l2sc->l1_token, CMR_SETTRACE, (void *)(unsigned long)(tsa->rxflags & (TRACE_I | TRACE_D_RX | TRACE_B_RX)));
411 tx_l2sc->driver->mph_command_req(tx_l2sc->l1_token, CMR_SETTRACE, (void *)(unsigned long)(tsa->txflags & (TRACE_I | TRACE_D_RX | TRACE_B_RX)));
412 }
413 break;
414
415 case I4B_TRC_RESETA:
416 analyzemode = 0;
417 outunit = -1;
418 rxunit = -1;
419 txunit = -1;
420 break;
421
422 default:
423 error = ENOTTY;
424 break;
425 }
426 return(error);
427 }
428
429 #endif /* NISDNTRC > 0 */
Cache object: a6c2b30b493d89691549af43ebfee51a
|