/**************************************************************************** ** File: lcp.c ** ** Author: Mike Borella ** ** Comments: LCP module. ** ** $Id: lcp.c,v 1.10 2001/10/02 18:37:43 mborella Exp $ ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU Library General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ** *****************************************************************************/ #include "lcp.h" #define LCP_OPTION_LEN 64 /* * LCP codes */ #define LCP_CODE_CONFREQ 1 #define LCP_CODE_CONFACK 2 #define LCP_CODE_CONFNAK 3 #define LCP_CODE_CONFREJ 4 #define LCP_CODE_TERMREQ 5 #define LCP_CODE_TERMACK 6 #define LCP_CODE_CODEREJ 7 #define LCP_CODE_PROTREJ 8 #define LCP_CODE_ECHOREQ 9 #define LCP_CODE_ECHOREP 10 #define LCP_CODE_DISCREQ 11 #define LCP_CODE_IDENTIFICATION 12 #define LCP_CODE_TIMEREMAINING 13 #define LCP_CODE_RESETREQ 14 #define LCP_CODE_RESETREP 15 /* * LCP code map */ strmap_t lcp_code_map[] = { { LCP_CODE_CONFREQ, "Configure-Request" }, { LCP_CODE_CONFACK, "Configure-Ack" }, { LCP_CODE_CONFNAK, "Configure-Nak" }, { LCP_CODE_CONFREJ, "Configure-Reject" }, { LCP_CODE_TERMREQ, "Terminate-Request" }, { LCP_CODE_TERMACK, "Terminate-Ack" }, { LCP_CODE_CODEREJ, "Code-Rej" }, { LCP_CODE_PROTREJ, "Protocol-Reject" }, { LCP_CODE_ECHOREQ, "Echo-Request" }, { LCP_CODE_ECHOREP, "Echo-Reply" }, { LCP_CODE_DISCREQ, "Discard-Request" }, { LCP_CODE_IDENTIFICATION, "Identification" }, { LCP_CODE_TIMEREMAINING, "Time-Remaining" }, { LCP_CODE_RESETREQ, "Reset-Request" }, { LCP_CODE_RESETREP, "Reset-Replay" }, { 0, ""} }; /* * LCP options */ #define LCP_OPTION_VENDORSPECIFIC 0 #define LCP_OPTION_MAXRECVUNIT 1 #define LCP_OPTION_ASYNCCTRLCHARMAP 2 #define LCP_OPTION_AUTHPROTOCOL 3 #define LCP_OPTION_QUALITYPROTOCOL 4 #define LCP_OPTION_MAGICNUMBER 5 #define LCP_OPTION_PROTOFIELDCOMP 7 #define LCP_OPTION_ADDRCTRLFIELDCOMP 8 #define LCP_OPTION_FCSALTERNATIVES 9 #define LCP_OPTION_SELFDESCRIBINGPAD 10 #define LCP_OPTION_NUMBEREDMODE 11 #define LCP_OPTION_CALLBACK 13 #define LCP_OPTION_MULTILINKMRRU 17 #define LCP_OPTION_MULTILINKSSNHEADER 18 #define LCP_OPTION_MULTILINKENDPNTDISC 19 #define LCP_OPTION_PROPRIETARY 20 #define LCP_OPTION_DCEIDENTIFIER 21 #define LCP_OPTION_MULTILINKPLUSPROC 22 #define LCP_OPTION_LINKDISCFORBACP 23 #define LCP_OPTION_LCPAUTH 24 #define LCP_OPTION_COBS 25 #define LCP_OPTION_PREFIXELISION 26 #define LCP_OPTION_MULTILINKHDRFORMAT 27 #define LCP_OPTION_INTERNATIONALIZATION 28 #define LCP_OPTION_SIMPLEDATALINKSONET 29 #define LCP_OPTION_PPPMUXING 30 /* * LCP option map */ strmap_t lcp_option_map[] = { { LCP_OPTION_VENDORSPECIFIC, "vendor specific" }, { LCP_OPTION_MAXRECVUNIT, "max receive unit" }, { LCP_OPTION_ASYNCCTRLCHARMAP, "async char control map" }, { LCP_OPTION_AUTHPROTOCOL, "authentication protocol" }, { LCP_OPTION_QUALITYPROTOCOL, "quality protocol" }, { LCP_OPTION_MAGICNUMBER, "magic number" }, { LCP_OPTION_PROTOFIELDCOMP, "protocol field compression" }, { LCP_OPTION_ADDRCTRLFIELDCOMP, "address control field compression" }, { LCP_OPTION_FCSALTERNATIVES, "FCS alternatives" }, { LCP_OPTION_SELFDESCRIBINGPAD, "self describing pad" }, { LCP_OPTION_NUMBEREDMODE, "numbered mode" }, { LCP_OPTION_CALLBACK, "callback" }, { LCP_OPTION_MULTILINKMRRU, "multilink MRRU" }, { LCP_OPTION_MULTILINKSSNHEADER, "multilink short seq number header" }, { LCP_OPTION_MULTILINKENDPNTDISC, "multilink endpoint discriminator" }, { LCP_OPTION_PROPRIETARY, "proprietary" }, { LCP_OPTION_DCEIDENTIFIER, "DCE identifier" }, { LCP_OPTION_MULTILINKPLUSPROC, "multilink-plus procedure" }, { LCP_OPTION_LINKDISCFORBACP, "link discriminator for BACP" }, { LCP_OPTION_LCPAUTH, "LCP authentication" }, { LCP_OPTION_COBS, "consistent overhead byte stuffing" }, { LCP_OPTION_PREFIXELISION, "prefix elision" }, { LCP_OPTION_MULTILINKHDRFORMAT, "multilink header format" }, { LCP_OPTION_INTERNATIONALIZATION, "internationalization" }, { LCP_OPTION_SIMPLEDATALINKSONET, "simple datalink on SONET/SDH" }, { LCP_OPTION_PPPMUXING, "PPP muxing" }, { 0, "" } }; /* * LCP frame format */ typedef struct lcp { u_int8_t code; u_int8_t identifier; u_int16_t length; } lcp_t; extern struct arg_t * my_args; /*---------------------------------------------------------------------------- ** ** dump_lcp() ** ** Displays LCP packets. ** **---------------------------------------------------------------------------- */ void dump_lcp(packet_t *pkt) { lcp_t lcp; /* Set the layer */ set_layer(LAYER_DATALINK); /* * Get the header */ if (get_packet_bytes((u_int8_t *) &lcp, pkt, sizeof(lcp_t)) == 0) return; /* * Conversion */ lcp.length = ntohs(lcp.length); /* * Dump the header */ if (my_args->m) { display_minimal_string("| LCP "); display_minimal_string(map2str(lcp_code_map, lcp.code)); display_minimal_string(" "); } else { display_header_banner("LCP Header"); display_strmap("Code", lcp.code, lcp_code_map); display("Identifier", &lcp.identifier, 1, DISP_DEC); display("Length", (u_int8_t *) &lcp.length, 2, DISP_DEC); } /* * Grab the payload data */ if (lcp.length > sizeof(lcp_t)) { switch(lcp.code) { case LCP_CODE_CONFREQ: case LCP_CODE_CONFACK: case LCP_CODE_CONFNAK: case LCP_CODE_CONFREJ: { u_int8_t bytes_read = 0; u_int8_t type; u_int8_t length; u_int8_t value [LCP_OPTION_LEN]; int comma = 0; /* * LCP options appear in Type-Length-Value format */ while (bytes_read < lcp.length - sizeof(lcp_t)) { /* * Get type */ if (get_packet_bytes((u_int8_t *) &type, pkt, 1) == 0) break; bytes_read ++; /* * Get length */ if (get_packet_bytes((u_int8_t *) &length, pkt, 1) == 0) break; bytes_read ++; /* * In minimal mode we start all LCP options with an open paren * and put a comma before all but the first */ if (my_args->m) { if (comma) display_minimal_string(", "); else display_minimal_string("("); } comma = 1; /* * Display the type and length */ if (my_args->m) { display_minimal_string(map2str(lcp_option_map, type)); } else { display_strmap("Option", type, lcp_option_map); display(" Length", &length, 1, DISP_DEC); } /* * Figure out if we need to get a value */ if (length > 2) { if (get_packet_bytes((u_int8_t *) value, pkt, length-2) == 0) break; bytes_read = bytes_read + length - 2; /* * Display the value */ if (my_args->m) { display_minimal_string(" "); display_minimal(value, length-2, DISP_HEX); } else { display(" Value", (u_int8_t *) value, length-2, DISP_HEX); } } /* if */ } /* while */ /* * Insert end paren in minimal mode */ if (my_args->m) display_minimal_string(")"); } break; case LCP_CODE_TERMREQ: case LCP_CODE_TERMACK: { u_int8_t * data; u_int8_t data_len; /* * Read the data, if any */ data_len = lcp.length - sizeof(lcp_t); if (data_len > 0) { /* allocate memory for the data */ data = (u_int8_t *) my_malloc(data_len); /* grab the data field */ if (get_packet_bytes(data, pkt, data_len) == 0) { my_free(data); return; } /* dump it out as hex, but don't dump in minimal mode */ if (!my_args->m) { display("Data", data, data_len, DISP_HEX); } /* free that darn mem! */ my_free(data); } } break; case LCP_CODE_ECHOREQ: case LCP_CODE_ECHOREP: case LCP_CODE_DISCREQ: case LCP_CODE_IDENTIFICATION: { u_int32_t magic_number; u_int8_t * data; u_int8_t data_len; /* get the magic number */ if (get_packet_bytes((u_int8_t *) &magic_number, pkt, 4) == 0) return; /* display it */ if (my_args->m) { display_minimal((u_int8_t *) &magic_number, 4, DISP_HEX); display_minimal_string(" "); } else { display("Magic number", (u_int8_t *) &magic_number, 4, DISP_HEX); } /* Read the data, if any */ data_len = lcp.length - sizeof(lcp_t) - 4; if (data_len > 0) { /* Allocate memory for the data - extra for nulling a string */ data = (u_int8_t *) my_malloc(data_len + 1); /* grab the data field */ if (get_packet_bytes(data, pkt, data_len) == 0) { my_free(data); return; } data[data_len] = '\0'; /* dump it out as hex, but don't dump in minimal mode */ if (!my_args->m) { if (isprint_str(data, data_len)) display_string("Data", data); else display("Data", data, data_len, DISP_HEX); } /* free that darn mem! */ my_free(data); } } break; case LCP_CODE_CODEREJ: dump_lcp(pkt); break; case LCP_CODE_PROTREJ: { } break; default: break; } } /* dump the hex buffer */ if (!my_args->l) hexbuffer_flush(); }