/****************************************************************************
** 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();
}
syntax highlighted by Code2HTML, v. 0.9.1