2 * Routines for packet disassembly
4 * $Id: packet.c,v 1.25 1999/05/11 08:21:38 guy Exp $
6 * Ethereal - Network traffic analyzer
7 * By Gerald Combs <gerald@zing.org>
8 * Copyright 1998 Gerald Combs
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30 #ifdef HAVE_SYS_TYPES_H
31 # include <sys/types.h>
33 #include <sys/socket.h>
43 #ifdef NEED_SNPRINTF_H
44 # include "snprintf.h"
47 #ifdef HAVE_NETINET_IN_H
48 # include <netinet/in.h>
54 extern capture_file cf;
57 ether_to_str(const guint8 *ad) {
58 static gchar str[3][18];
61 if (cur == &str[0][0]) {
63 } else if (cur == &str[1][0]) {
68 sprintf(cur, "%02x:%02x:%02x:%02x:%02x:%02x", ad[0], ad[1], ad[2],
74 ip_to_str(const guint8 *ad) {
75 static gchar str[3][16];
78 if (cur == &str[0][0]) {
80 } else if (cur == &str[1][0]) {
85 sprintf(cur, "%d.%d.%d.%d", ad[0], ad[1], ad[2], ad[3]);
89 #define PLURALIZE(n) (((n) > 1) ? "s" : "")
90 #define COMMA(do_it) ((do_it) ? ", " : "")
93 time_secs_to_str(guint32 time)
95 static gchar str[3][8+1+4+2+2+5+2+2+7+2+2+7+1];
96 static gchar *cur, *p;
97 int hours, mins, secs;
100 if (cur == &str[0][0]) {
102 } else if (cur == &str[1][0]) {
117 sprintf(p, "%u day%s", time, PLURALIZE(time));
123 sprintf(p, "%s%u hour%s", COMMA(do_comma), hours, PLURALIZE(hours));
129 sprintf(p, "%s%u minute%s", COMMA(do_comma), mins, PLURALIZE(mins));
135 sprintf(p, "%s%u second%s", COMMA(do_comma), secs, PLURALIZE(secs));
139 /* Max string length for displaying byte string. */
140 #define MAX_BYTE_STR_LEN 16
142 /* Turn an array of bytes into a string showing the bytes in hex. */
144 bytes_to_str(const guint8 *bd, int bd_len) {
145 static gchar str[3][MAX_BYTE_STR_LEN+3+1];
149 static const char hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
150 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
152 if (cur == &str[0][0]) {
154 } else if (cur == &str[1][0]) {
160 len = MAX_BYTE_STR_LEN;
161 while (bd_len > 0 && len > 0) {
162 *p++ = hex[(*bd) >> 4];
163 *p++ = hex[(*bd) & 0xF];
169 /* Note that we're not showing the full string. */
179 * Given a pointer into a data buffer, and to the end of the buffer,
180 * find the end of the (putative) line at that position in the data
182 * Return a pointer to the EOL character(s) in "*eol".
185 find_line_end(const u_char *data, const u_char *dataend, const u_char **eol)
187 const u_char *lineend;
189 lineend = memchr(data, '\n', dataend - data);
190 if (lineend == NULL) {
192 * No LF - line is probably continued in next TCP segment.
198 * Is the LF at the beginning of the line?
200 if (lineend > data) {
202 * No - is it preceded by a carriage return?
203 * (Perhaps it's supposed to be, but that's not guaranteed....)
205 if (*(lineend - 1) == '\r') {
207 * Yes. The EOL starts with the CR.
212 * No. The EOL starts with the LF.
217 * I seem to remember that we once saw lines ending with LF-CR
218 * in an HTTP request or response, so check if it's *followed*
219 * by a carriage return.
221 if (lineend < (dataend - 1) && *(lineend + 1) == '\r') {
223 * It's <non-LF><LF><CR>; say it ends with the CR.
231 * Point to the character after the last character.
238 #define MAX_COLUMNS_LINE_DETAIL 62
241 * Get the length of the next token in a line, and the beginning of the
242 * next token after that (if any).
243 * Return 0 if there is no next token.
246 get_token_len(const u_char *linep, const u_char *lineend,
247 const u_char **next_token)
249 const u_char *tokenp;
255 * Search for a blank, a CR or an LF, or the end of the buffer.
257 while (linep < lineend && *linep != ' ' && *linep != '\r' && *linep != '\n')
259 token_len = linep - tokenp;
262 * Skip trailing blanks.
264 while (linep < lineend && *linep == ' ')
273 * Given a string, generate a string from it that shows non-printable
274 * characters as C-style escapes, and return a pointer to it.
277 format_text(const u_char *string, int len)
279 static gchar fmtbuf[MAX_COLUMNS_LINE_DETAIL + 3 + 4 + 1];
282 const u_char *stringend = string + len;
287 fmtbufp = &fmtbuf[0];
288 while (string < stringend) {
289 if (column >= MAX_COLUMNS_LINE_DETAIL) {
291 * Put "..." and quit.
293 strcpy(fmtbufp, " ...");
347 *fmtbufp++ = i + '0';
350 *fmtbufp++ = i + '0';
353 *fmtbufp++ = i + '0';
364 /* Tries to match val against each element in the value_string array vs.
365 Returns the associated string ptr on a match.
366 Formats val with fmt, and returns the resulting string, on failure. */
368 val_to_str(guint32 val, const value_string *vs, const char *fmt) {
370 static gchar str[3][64];
373 ret = match_strval(val, vs);
376 if (cur == &str[0][0]) {
378 } else if (cur == &str[1][0]) {
383 snprintf(cur, 64, fmt, val);
387 /* Tries to match val against each element in the value_string array vs.
388 Returns the associated string ptr on a match, or NULL on failure. */
390 match_strval(guint32 val, const value_string *vs) {
393 while (vs[i].strptr) {
394 if (vs[i].value == val)
395 return(vs[i].strptr);
402 /* Generate, into "buf", a string showing the bits of a bitfield.
403 Return a pointer to the character after that string. */
405 decode_bitfield_value(char *buf, guint32 val, guint32 mask, int width)
413 bit = 1 << (width - 1);
416 /* This bit is part of the field. Show its value. */
422 /* This bit is not part of the field. */
437 /* Generate a string describing a Boolean bitfield (a one-bit field that
438 says something is either true of false). */
440 decode_boolean_bitfield(guint32 val, guint32 mask, int width,
441 const char *truedesc, const char *falsedesc)
443 static char buf[1025];
446 p = decode_bitfield_value(buf, val, mask, width);
450 strcpy(p, falsedesc);
454 /* Generate a string describing an enumerated bitfield (an N-bit field
455 with various specific values having particular names). */
457 decode_enumerated_bitfield(guint32 val, guint32 mask, int width,
458 const value_string *tab, const char *fmt)
460 static char buf[1025];
463 p = decode_bitfield_value(buf, val, mask, width);
464 sprintf(p, fmt, val_to_str(val & mask, tab, "Unknown"));
468 /* Generate a string describing a numeric bitfield (an N-bit field whose
469 value is just a number). */
471 decode_numeric_bitfield(guint32 val, guint32 mask, int width,
474 static char buf[1025];
477 p = decode_bitfield_value(buf, val, mask, width);
478 sprintf(p, fmt, val & mask);
482 /* Checks to see if a particular packet information element is needed for
485 check_col(frame_data *fd, gint el) {
489 for (i = 0; i < fd->cinfo->num_cols; i++) {
490 if (fd->cinfo->fmt_matx[i][el])
497 /* To do: Add check_col checks to the pinfo_add* routines */
499 /* Adds a vararg list to a packet info string. */
501 col_add_fstr(frame_data *fd, gint el, gchar *format, ...) {
505 va_start(ap, format);
506 for (i = 0; i < fd->cinfo->num_cols; i++) {
507 if (fd->cinfo->fmt_matx[i][el])
508 vsnprintf(fd->cinfo->col_data[i], COL_MAX_LEN, format, ap);
513 col_add_str(frame_data *fd, gint el, gchar* str) {
516 for (i = 0; i < fd->cinfo->num_cols; i++) {
517 if (fd->cinfo->fmt_matx[i][el]) {
518 strncpy(fd->cinfo->col_data[i], str, COL_MAX_LEN);
519 fd->cinfo->col_data[i][COL_MAX_LEN - 1] = 0;
524 static const char *mon_names[12] = {
539 /* this routine checks the frame type from the cf structure */
541 dissect_packet(const u_char *pd, frame_data *fd, proto_tree *tree)
548 /* Put in frame header information. */
549 if (check_col(fd, COL_ABS_TIME)) {
551 tmp = localtime(&then);
552 col_add_fstr(fd, COL_ABS_TIME, "%02d:%02d:%02d.%04ld",
556 (long)fd->abs_usecs/100);
558 if (check_col(fd, COL_REL_TIME)) {
559 col_add_fstr(fd, COL_REL_TIME, "%d.%06d", fd->rel_secs, fd->rel_usecs);
561 if (check_col(fd, COL_DELTA_TIME)) {
562 col_add_fstr(fd, COL_DELTA_TIME, "%d.%06d", fd->del_secs, fd->del_usecs);
566 ti = proto_tree_add_item(tree, 0, fd->cap_len,
567 "Frame (%d on wire, %d captured)",
568 fd->pkt_len, fd->cap_len);
570 fh_tree = proto_tree_new();
571 proto_item_add_subtree(ti, fh_tree, ETT_FRAME);
573 tmp = localtime(&then);
574 proto_tree_add_item(fh_tree, 0, 0,
575 "Frame arrived on %s %2d, %d %02d:%02d:%02d.%04ld",
576 mon_names[tmp->tm_mon],
582 (long)fd->abs_usecs/100);
584 proto_tree_add_item(fh_tree, 0, 0, "Total frame length: %d bytes",
586 proto_tree_add_item(fh_tree, 0, 0, "Capture frame length: %d bytes",
592 case WTAP_ENCAP_ETHERNET :
593 dissect_eth(pd, fd, tree);
595 case WTAP_ENCAP_FDDI :
596 dissect_fddi(pd, fd, tree);
599 dissect_tr(pd, fd, tree);
601 case WTAP_ENCAP_NONE :
602 dissect_null(pd, fd, tree);
604 case WTAP_ENCAP_PPP :
605 dissect_ppp(pd, fd, tree);
607 case WTAP_ENCAP_RAW_IP :
608 dissect_raw(pd, fd, tree);
614 dissect_eth(pd, fd, tree);
617 dissect_fddi(pd, fd, tree);
620 dissect_tr(pd, fd, tree);
623 dissect_null(pd, fd, tree);
626 dissect_ppp(pd, fd, tree);
629 dissect_raw(pd, fd, tree);