Add svn:eol-style.
[metze/wireshark/wip.git] / wiretap / ascend.y
1 %{
2 /* ascend.y
3  *
4  * $Id$
5  *
6  * Wiretap Library
7  * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22  *
23  */
24
25 /*
26     Example 'pridisp' output data - one paragraph/frame:
27
28 PRI-XMIT-27: (task "l1Task" at 0x10216fe0, time: 560194.01) 4 octets @ 0x1027c5b0
29   [0000]: 00 01 01 a9                                         ....
30 PRI-RCV-27: (task "idle task" at 0x10123570, time: 560194.01) 4 octets @ 0x1027fb00
31   [0000]: 00 01 01 dd
32
33     Example 'pridisp' output data - two paragraphs/frame for XMIT case only:
34
35 PRI-XMIT-19/1:  (task "l1Task" at 0x10216840, time: 274759.98) 4 octets @ 0x1027f230
36   [0000]: 00 01 30 d8                                         ..0.
37 PRI-XMIT-19/2 (task "l1Task" at 0x10216840, time: 274759.98) 11 octets @ 0x1027f234
38   [0000]: 08 02 8c bf 02 18 04 e9  82 83 8f                   ........ ...
39
40     Example 'ether-disp' output data:
41
42 ETHER3ND RECV: (task "_sarTask" at 0x802c6eb0, time: 259848.03) 775 octets @ 0xa8fb2020
43   [0000]: 00 d0 52 04 e7 1e 08 00  20 ae 51 b5 08 00 45 00    ..R..... .Q...E.
44   [0010]: 02 f9 05 e6 40 00 3f 11  6e 39 87 fe c4 95 3c 3c    ....@.?.  n9....<<
45   [0020]: 3c 05 13 c4 13 c4 02 e5  ef ed 49 4e 56 49 54 45    <.......  ..INVITE
46   [0030]: 20 73 69 70 3a 35 32 30  37 33 40 36 30 2e 36 30     sip:520 73@60.60
47   [0040]: 2e 36 30 2e 35 20 53 49  50 2f 32 2e 30 0d 0a 56    .60.5 SI P/2.0..V
48   [0050]: 69 61 3a 20 53 49 50 2f  32 2e 30 2f 55 44 50 20    ia: SIP/ 2.0/UDP
49   [0060]: 31 33 35 2e                                         135.
50
51     Example 'wandsess' output data:
52
53 RECV-iguana:241:(task: B02614C0, time: 1975432.85) 49 octets @ 8003BD94
54   [0000]: FF 03 00 3D C0 06 CA 22 2F 45 00 00 28 6A 3B 40
55   [0010]: 00 3F 03 D7 37 CE 41 62 12 CF 00 FB 08 20 27 00
56   [0020]: 50 E4 08 DD D7 7C 4C 71 92 50 10 7D 78 67 C8 00
57   [0030]: 00
58 XMIT-iguana:241:(task: B04E12C0, time: 1975432.85) 53 octets @ 8009EB16
59   [0000]: FF 03 00 3D C0 09 1E 31 21 45 00 00 2C 2D BD 40
60   [0010]: 00 7A 06 D8 B1 CF 00 FB 08 CE 41 62 12 00 50 20
61   [0020]: 29 7C 4C 71 9C 9A 6A 93 A4 60 12 22 38 3F 10 00
62   [0030]: 00 02 04 05 B4
63
64     Example 'wdd' output data:
65
66 Date: 01/12/1990.  Time: 12:22:33
67 Cause an attempt to place call to 14082750382
68 WD_DIALOUT_DISP: chunk 2515EE type IP.
69 (task: 251790, time: 994953.28) 44 octets @ 2782B8
70   [0000]: 00 C0 7B 71 45 6C 00 60 08 16 AA 51 08 00 45 00
71   [0010]: 00 2C 66 1C 40 00 80 06 53 F6 AC 14 00 18 CC 47
72   [0020]: C8 45 0A 31 00 50 3B D9 5B 75 00 00
73
74     The following output comes from a MAX with Software 7.2.3:
75
76 RECV-187:(task: B050B480, time: 18042248.03) 100 octets @ 800012C0
77   [0000]: FF 03 00 21 45 00 00 60 E3 49 00 00 7F 11 FD 7B
78   [0010]: C0 A8 F7 05 8A C8 18 51 00 89 00 89 00 4C C7 C1
79   [0020]: CC 8E 40 00 00 01 00 00 00 00 00 01 20 45 4A 45
80   [0030]: 42 45 43 45 48 43 4E 46 43 46 41 43 41 43 41 43
81   [0040]: 41 43 41 43 41 43 41 43 41 43 41 42 4E 00 00 20
82   [0050]: 00 01 C0 0C 00 20 00 01 00 04 93 E0 00 06 60 00
83   [0060]: C0 A8 F7 05
84 XMIT-187:(task: B0292CA0, time: 18042248.04) 60 octets @ 800AD576
85   [0000]: FF 03 00 21 45 00 00 38 D7 EE 00 00 0F 01 11 2B
86   [0010]: 0A FF FF FE C0 A8 F7 05 03 0D 33 D3 00 00 00 00
87   [0020]: 45 00 00 60 E3 49 00 00 7E 11 FE 7B C0 A8 F7 05
88   [0030]: 8A C8 18 51 00 89 00 89 00 4C C7 C1
89 RECV-187:(task: B0292CA0, time: 18042251.92) 16 octets @ 800018E8
90   [0000]: FF 03 C0 21 09 01 00 0C DE 61 96 4B 00 30 94 92
91
92   In TAOS 8.0, Lucent slightly changed the format as follows:
93
94     Example 'wandisp' output data (TAOS 8.0.3): (same format is used
95     for 'wanopen' and 'wannext' command)
96
97 RECV-14: (task "idle task" at 0xb05e6e00, time: 1279.01) 29 octets @ 0x8000e0fc
98   [0000]: ff 03 c0 21 01 01 00 19  01 04 05 f4 11 04 05 f4    ...!.... ........
99   [0010]: 13 09 03 00 c0 7b 9a 9f  2d 17 04 10 00             .....{.. -....
100 XMIT-14: (task "idle task" at 0xb05e6e00, time: 1279.02) 38 octets @ 0x8007fd56
101   [0000]: ff 03 c0 21 01 01 00 22  00 04 00 00 01 04 05 f4    ...!..." ........
102   [0010]: 03 05 c2 23 05 11 04 05  f4 13 09 03 00 c0 7b 80    ...#.... ......{.
103   [0020]: 7c ef 17 04 0e 00                                   |.....
104 XMIT-14: (task "idle task" at 0xb05e6e00, time: 1279.02) 29 octets @ 0x8007fa36
105   [0000]: ff 03 c0 21 02 01 00 19  01 04 05 f4 11 04 05 f4    ...!.... ........
106   [0010]: 13 09 03 00 c0 7b 9a 9f  2d 17 04 10 00             .....{.. -....
107
108     Example 'wandsess' output data (TAOS 8.0.3):
109
110 RECV-Max7:20: (task "_brouterControlTask" at 0xb094ac20, time: 1481.50) 20 octets @ 0x8000d198
111   [0000]: ff 03 00 3d c0 00 00 04  80 fd 02 01 00 0a 11 06    ...=.... ........
112   [0010]: 00 01 01 03                                         ....
113 XMIT-Max7:20: (task "_brouterControlTask" at 0xb094ac20, time: 1481.51) 26 octets @ 0x800806b6
114   [0000]: ff 03 00 3d c0 00 00 00  80 21 01 01 00 10 02 06    ...=.... .!......
115   [0010]: 00 2d 0f 01 03 06 89 64  03 08                      .-.....d ..
116 XMIT-Max7:20: (task "_brouterControlTask" at 0xb094ac20, time: 1481.51) 20 octets @ 0x8007f716
117   [0000]: ff 03 00 3d c0 00 00 01  80 fd 01 01 00 0a 11 06    ...=.... ........
118   [0010]: 00 01 01 03                                         ....
119
120   The changes since TAOS 7.X are:
121
122     1) White space is added before "(task".
123     2) Task has a name, indicated by a subsequent string surrounded by a
124        double-quote.
125     3) Address expressed in hex number has a preceeding "0x".
126     4) Hex numbers are in lower case.
127     5) There is a character display corresponding to hex data in each line.
128
129  */
130
131 #include "config.h"
132
133 #include <stdio.h>
134 #include <stdlib.h>
135 #include <string.h>
136
137 #include "wtap-int.h"
138 #include "buffer.h"
139 #include "ascendtext.h"
140 #include "ascend-int.h"
141 #include "file_wrappers.h"
142
143 #define NO_USER "<none>"
144
145 int yyparse(FILE_T fh);
146 void yyerror(FILE_T fh _U_, const char *);
147
148 const gchar *ascend_parse_error;
149
150 static unsigned int bcur;
151 static guint32 start_time, secs, usecs, caplen, wirelen;
152 struct ascend_phdr *pseudo_header;
153 static guint8 *pkt_data;
154 static gint64 first_hexbyte;
155
156 %}
157
158 %union {
159 gchar  *s;
160 guint32 d;
161 guint8  b;
162 }
163
164 %token <s> STRING KEYWORD WDD_DATE WDD_CHUNK COUNTER SLASH_SUFFIX
165 %token <d> WDS_PREFIX ISDN_PREFIX ETHER_PREFIX DECNUM HEXNUM
166 %token <b> HEXBYTE
167
168 %type <s> string dataln datagroup
169 %type <d> wds_prefix isdn_prefix ether_prefix decnum hexnum
170 %type <b> byte bytegroup
171
172 %parse-param { FILE_T fh }
173
174 %%
175
176 data_packet:
177   | ether_hdr datagroup
178   | deferred_isdn_hdr datagroup deferred_isdn_hdr datagroup
179   | isdn_hdr datagroup
180   | wds_hdr datagroup
181   | wds8_hdr datagroup
182   | wdp7_hdr datagroup
183   | wdp8_hdr datagroup
184   | wdd_date wdd_hdr datagroup
185   | wdd_hdr datagroup
186 ;
187
188 isdn_prefix: ISDN_PREFIX;
189
190 ether_prefix: ETHER_PREFIX;
191
192 wds_prefix: WDS_PREFIX;
193
194 string: STRING;
195
196 decnum: DECNUM;
197
198 hexnum: HEXNUM;
199
200 /*
201   pridisp special case - I-frame header printed separately from contents,
202   one frame across two messages.
203
204 PRI-XMIT-0/1:  (task "l1Task" at 0x80152b20, time: 283529.65) 4 octets @
205 0x80128220
206   [0000]: 00 01 ae b2                                         ....
207 PRI-XMIT-0/2 (task "l1Task" at 0x80152b20, time: 283529.65) 10 octets @
208 0x80128224
209   [0000]: 08 02 d7 e3 02 18 03 a9  83 8a                      ........
210
211 */
212 deferred_isdn_hdr: isdn_prefix decnum SLASH_SUFFIX KEYWORD string KEYWORD hexnum KEYWORD decnum decnum decnum KEYWORD HEXNUM {
213   wirelen += $11;
214   caplen += $11;
215   secs = $9;
216   usecs = $10;
217   if (pseudo_header != NULL) {
218     pseudo_header->type = $1;
219     pseudo_header->sess = $2;
220     pseudo_header->call_num[0] = '\0';
221     pseudo_header->chunk = 0;
222     pseudo_header->task = $7;
223   }
224   /* because we have two data groups */
225   first_hexbyte = 0;
226 }
227 ;
228
229 /*
230 PRI-XMIT-19:  (task "l1Task" at 0x10216840, time: 274758.67) 4 octets @ 0x1027c1c0
231  ... or ...
232 PRI-RCV-27:  (task "idle task" at 0x10123570, time: 560194.01) 4 octets @ 0x1027fb00
233 */
234 isdn_hdr: isdn_prefix decnum KEYWORD string KEYWORD hexnum KEYWORD decnum decnum decnum KEYWORD HEXNUM {
235   wirelen = $10;
236   caplen = $10;
237   secs = $8;
238   usecs = $9;
239   if (pseudo_header != NULL) {
240     pseudo_header->type = $1;
241     pseudo_header->sess = $2;
242     pseudo_header->call_num[0] = '\0';
243     pseudo_header->chunk = 0;
244     pseudo_header->task = $6;
245   }
246   first_hexbyte = 0;
247 }
248 ;
249
250 /*
251 ETHER3ND XMIT: (task "_sarTask" at 0x802c6eb0, time: 259848.11) 414 octets @ 0xa
252 885f80e
253 */
254 ether_hdr: ether_prefix string KEYWORD string KEYWORD hexnum KEYWORD decnum decnum
255  decnum KEYWORD HEXNUM {
256   wirelen = $10;
257   caplen = $10;
258   secs = $8;
259   usecs = $9;
260   if (pseudo_header != NULL) {
261     pseudo_header->type = $1;
262     pseudo_header->call_num[0] = '\0';
263     pseudo_header->chunk = 0;
264     pseudo_header->task = $6;
265   }
266 }
267 ;
268
269 /* RECV-iguana:241:(task: B02614C0, time: 1975432.85) 49 octets @ 8003BD94 */
270 /*            1        2      3      4       5      6       7      8      9      10     11 */
271 wds_hdr: wds_prefix string decnum KEYWORD hexnum KEYWORD decnum decnum decnum KEYWORD HEXNUM {
272   wirelen = $9;
273   caplen = $9;
274   secs = $7;
275   usecs = $8;
276   if (pseudo_header != NULL) {
277     /* pseudo_header->user is set in ascend_scanner.l */
278     pseudo_header->type = $1;
279     pseudo_header->sess = $3;
280     pseudo_header->call_num[0] = '\0';
281     pseudo_header->chunk = 0;
282     pseudo_header->task = $5;
283   }
284 }
285 ;
286
287 /* RECV-Max7:20: (task "_brouterControlTask" at 0xb094ac20, time: 1481.50) 20 octets @ 0x8000d198 */
288 /*                1       2       3     4       5       6      7       8      9      10     11     12      13 */
289 wds8_hdr: wds_prefix string decnum KEYWORD string KEYWORD hexnum KEYWORD decnum decnum decnum KEYWORD HEXNUM {
290   wirelen = $11;
291   caplen = $11;
292   secs = $9;
293   usecs = $10;
294   if (pseudo_header != NULL) {
295     /* pseudo_header->user is set in ascend_scanner.l */
296     pseudo_header->type = $1;
297     pseudo_header->sess = $3;
298     pseudo_header->call_num[0] = '\0';
299     pseudo_header->chunk = 0;
300     pseudo_header->task = $7;
301   }
302 }
303 ;
304
305 /* RECV-187:(task: B050B480, time: 18042248.03) 100 octets @ 800012C0 */
306 /*            1        2       3      4       5       6      7      8      9      10    */
307 wdp7_hdr: wds_prefix decnum KEYWORD hexnum KEYWORD decnum decnum decnum KEYWORD HEXNUM {
308   wirelen = $8;
309   caplen = $8;
310   secs = $6;
311   usecs = $7;
312   if (pseudo_header != NULL) {
313     /* pseudo_header->user is set in ascend_scanner.l */
314     pseudo_header->type = $1;
315     pseudo_header->sess = $2;
316     pseudo_header->call_num[0] = '\0';
317     pseudo_header->chunk = 0;
318     pseudo_header->task = $4;
319   }
320 }
321 ;
322
323 /* XMIT-44: (task "freedm_task" at 0xe051fd10, time: 6258.66) 29 octets @ 0x606d1f00 */
324 /*              1        2       3      4       5      6      7       8      9      10     11      12 */
325 wdp8_hdr: wds_prefix decnum KEYWORD string KEYWORD hexnum KEYWORD decnum decnum decnum KEYWORD HEXNUM {
326   wirelen = $10;
327   caplen = $10;
328   secs = $8;
329   usecs = $9;
330   if (pseudo_header != NULL) {
331     /* pseudo_header->user is set in ascend_scanner.l */
332     pseudo_header->type = $1;
333     pseudo_header->sess = $2;
334     pseudo_header->call_num[0] = '\0';
335     pseudo_header->chunk = 0;
336     pseudo_header->task = $6;
337   }
338 }
339 ;
340
341 /*
342 Date: 01/12/1990.  Time: 12:22:33
343 Cause an attempt to place call to 14082750382
344 */
345 /*           1        2      3      4      5       6      7      8      9      10*/
346 wdd_date: WDD_DATE decnum decnum decnum KEYWORD decnum decnum decnum KEYWORD string {
347   /*
348    * Supply the date/time value to the code above us; it will use the
349    * first date/time value supplied as the capture start date/time.
350    */
351   struct tm wddt;
352
353   wddt.tm_sec  = $8;
354   wddt.tm_min  = $7;
355   wddt.tm_hour = $6;
356   wddt.tm_mday = $3;
357   wddt.tm_mon  = $2 - 1;
358   wddt.tm_year = ($4 > 1970) ? $4 - 1900 : 70;
359   wddt.tm_isdst = -1;
360
361   start_time = (guint32) mktime(&wddt);
362 }
363 ;
364
365 /*
366 WD_DIALOUT_DISP: chunk 2515EE type IP.
367 (task: 251790, time: 994953.28) 44 octets @ 2782B8
368 */
369 /*           1        2      3       4       5      6       7      8      9      10     11*/
370 wdd_hdr: WDD_CHUNK hexnum KEYWORD KEYWORD hexnum KEYWORD decnum decnum decnum KEYWORD HEXNUM {
371   wirelen = $9;
372   caplen = $9;
373   secs = $7;
374   usecs = $8;
375   if (pseudo_header != NULL) {
376     /* pseudo_header->call_num is set in ascend_scanner.l */
377     pseudo_header->type = ASCEND_PFX_WDD;
378     pseudo_header->user[0] = '\0';
379     pseudo_header->sess = 0;
380     pseudo_header->chunk = $2;
381     pseudo_header->task = $5;
382   }
383 }
384 ;
385
386 byte: HEXBYTE {
387   /* remember the position of the data group in the trace, to tip
388      off ascend_seek() as to where to look for the next header. */
389   if (first_hexbyte == 0)
390     first_hexbyte = file_tell(fh);
391
392   if (bcur < caplen) {
393     pkt_data[bcur] = $1;
394     bcur++;
395   }
396
397   /* arbitrary safety maximum... */
398   if (bcur >= ASCEND_MAX_PKT_LEN)
399     YYACCEPT;
400 }
401 ;
402
403 /* XXX  There must be a better way to do this... */
404 bytegroup: byte
405   | byte byte
406   | byte byte byte
407   | byte byte byte byte
408   | byte byte byte byte byte
409   | byte byte byte byte byte byte
410   | byte byte byte byte byte byte byte
411   | byte byte byte byte byte byte byte byte
412   | byte byte byte byte byte byte byte byte byte
413   | byte byte byte byte byte byte byte byte byte byte
414   | byte byte byte byte byte byte byte byte byte byte byte
415   | byte byte byte byte byte byte byte byte byte byte byte byte
416   | byte byte byte byte byte byte byte byte byte byte byte byte byte
417   | byte byte byte byte byte byte byte byte byte byte byte byte byte byte
418   | byte byte byte byte byte byte byte byte byte byte byte byte byte byte byte
419   | byte byte byte byte byte byte byte byte byte byte byte byte byte byte byte byte
420 ;
421
422 dataln: COUNTER bytegroup;
423
424 datagroup: dataln
425   | dataln dataln
426   | dataln dataln dataln
427   | dataln dataln dataln dataln
428   | dataln dataln dataln dataln dataln
429   | dataln dataln dataln dataln dataln dataln
430   | dataln dataln dataln dataln dataln dataln dataln
431   | dataln dataln dataln dataln dataln dataln dataln dataln
432 ;
433
434 %%
435
436 void
437 init_parse_ascend(void)
438 {
439   at_eof = 0;
440   start_time = 0;       /* we haven't see a date/time yet */
441 }
442
443 /* Run the parser. */
444 static int
445 run_ascend_parser(FILE_T fh, struct wtap_pkthdr *phdr, guint8 *pd)
446 {
447   /* yydebug = 1; */
448   int retval;
449
450   ascend_init_lexer(fh);
451   pseudo_header = &phdr->pseudo_header.ascend;
452   pkt_data = pd;
453
454   bcur = 0;
455   first_hexbyte = 0;
456   wirelen = 0;
457   caplen = 0;
458
459   /*
460    * Not all packets in a "wdd" dump necessarily have a "Cause an
461    * attempt to place call to" header (I presume this can happen if
462    * there was a call in progress when the packet was sent or
463    * received), so we won't necessarily have the phone number for
464    * the packet.
465    *
466    * XXX - we could assume, in the sequential pass, that it's the
467    * phone number from the last call, and remember that for use
468    * when doing random access.
469    */
470   pseudo_header->call_num[0] = '\0';
471
472   retval = yyparse(fh);
473
474   caplen = bcur;
475
476   return retval;
477 }
478
479 /* Parse the capture file.
480    Returns:
481      TRUE if we got a packet
482      FALSE otherwise. */
483 gboolean
484 check_ascend(FILE_T fh, struct wtap_pkthdr *phdr)
485 {
486   guint8 buf[ASCEND_MAX_PKT_LEN];
487
488   run_ascend_parser(fh, phdr, buf);
489   
490   /* if we got at least some data, return success even if the parser
491      reported an error. This is because the debug header gives the number
492      of bytes on the wire, not actually how many bytes are in the trace.
493      We won't know where the data ends until we run into the next packet. */
494   return (caplen != 0);
495 }
496
497 /* Parse the capture file.
498    Returns:
499      PARSED_RECORD if we got a packet
500      PARSED_NONRECORD if the parser succeeded but didn't see a packet
501      PARSE_FAILED if the parser failed. */
502 parse_t
503 parse_ascend(ascend_t *ascend, FILE_T fh, struct wtap_pkthdr *phdr, Buffer *buf,
504              guint length)
505 {
506   int retval;
507
508   buffer_assure_space(buf, length);
509   retval = run_ascend_parser(fh, phdr, buffer_start_ptr(buf));
510
511   /* did we see any data (hex bytes)? if so, tip off ascend_seek()
512      as to where to look for the next packet, if any. If we didn't,
513      maybe this record was broken. Advance so we don't get into
514      an infinite loop reading a broken trace. */
515   if (first_hexbyte) {
516     ascend->next_packet_seek_start = first_hexbyte;
517   } else {
518     /* Sometimes, a header will be printed but the data will be omitted, or
519        worse -- two headers will be printed, followed by the data for each.
520        Because of this, we need to be fairly tolerant of what we accept
521        here.  If we didn't find any hex bytes, skip over what we've read so
522        far so we can try reading a new packet. */
523     ascend->next_packet_seek_start = file_tell(fh);
524     retval = 0;
525   }
526
527   /* if we got at least some data, return success even if the parser
528      reported an error. This is because the debug header gives the number
529      of bytes on the wire, not actually how many bytes are in the trace.
530      We won't know where the data ends until we run into the next packet. */
531   if (caplen) {
532     if (! ascend->adjusted) {
533       ascend->adjusted = TRUE;
534       if (start_time != 0) {
535         /*
536          * Capture file contained a date and time.
537          * We do this only if this is the very first packet we've seen -
538          * i.e., if "ascend->adjusted" is false - because
539          * if we get a date and time after the first packet, we can't
540          * go back and adjust the time stamps of the packets we've already
541          * processed, and basing the time stamps of this and following
542          * packets on the time stamp from the file text rather than the
543          * ctime of the capture file means times before this and after
544          * this can't be compared.
545          */
546         ascend->inittime = start_time;
547       }
548       if (ascend->inittime > secs)
549         ascend->inittime -= secs;
550     }
551     phdr->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
552     phdr->ts.secs = secs + ascend->inittime;
553     phdr->ts.nsecs = usecs * 1000;
554     phdr->caplen = caplen;
555     phdr->len = wirelen;
556  
557     /*
558      * For these types, the encapsulation we use is not WTAP_ENCAP_ASCEND,
559      * so set the pseudo-headers appropriately for the type (WTAP_ENCAP_ISDN
560      * or WTAP_ENCAP_ETHERNET).
561      */
562     switch(phdr->pseudo_header.ascend.type) {
563       case ASCEND_PFX_ISDN_X:
564         phdr->pseudo_header.isdn.uton = TRUE;
565         phdr->pseudo_header.isdn.channel = 0;
566         break;
567
568       case ASCEND_PFX_ISDN_R:
569         phdr->pseudo_header.isdn.uton = FALSE;
570         phdr->pseudo_header.isdn.channel = 0;
571         break;
572
573       case ASCEND_PFX_ETHER:
574         phdr->pseudo_header.eth.fcs_len = 0;
575         break;
576     }
577     return PARSED_RECORD;
578   }
579
580   /* Didn't see any data. Still, perhaps the parser was happy.  */
581   if (retval)
582     return PARSE_FAILED;
583   else
584     return PARSED_NONRECORD;
585 }
586
587 void
588 yyerror (FILE_T fh _U_, const char *s)
589 {
590   ascend_parse_error = s;
591 }