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