/****************************************************************************
** File: pppoe.c
**
** Author: Andy Juniper
**
** Comments: PPP module.
**
** $Id: pppoe.c,v 1.5 2001/05/28 19:24:04 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 "pppoe.h"
#include "ppp.h"
/*
* PPPOE code types
*/
#define PPPOE_CODE_PADI 0x09
#define PPPOE_CODE_PADO 0x07
#define PPPOE_CODE_PADR 0x19
#define PPPOE_CODE_PADS 0x65
#define PPPOE_CODE_PADT 0xa7
#define PPPOE_CODE_SESS 0x00
/*
* PPPOE tag types
*/
#define PPPOE_TAG_ENDOFLIST 0x0000
#define PPPOE_TAG_SERVICENAME 0x0101
#define PPPOE_TAG_ACNAME 0x0102
#define PPPOE_TAG_HOSTUNIQ 0x0103
#define PPPOE_TAG_ACCOOKIE 0x0104
#define PPPOE_TAG_VENDORSPEC 0x0105
#define PPPOE_TAG_RELAYSESSID 0x0110
#define PPPOE_TAG_SERVNAMEERR 0x0201
#define PPPOE_TAG_ACSYSERR 0x0202
#define PPPOE_TAG_GENERICERR 0x0203
/*
* PPPOE code map
*/
strmap_t pppoe_code_map[] =
{
{ PPPOE_CODE_PADI ,"PADI" },
{ PPPOE_CODE_PADO ,"PADO" },
{ PPPOE_CODE_PADR ,"PADR" },
{ PPPOE_CODE_PADS ,"PADS" },
{ PPPOE_CODE_PADT ,"PADT" },
{ PPPOE_CODE_SESS ,"SESSION" },
{ 0, "" }
};
/*
* PPPOE TLV map
*/
strmap_t pppoe_tlv_map[] =
{
{ PPPOE_TAG_ENDOFLIST ,"End of List" },
{ PPPOE_TAG_SERVICENAME ,"Service Name" },
{ PPPOE_TAG_ACNAME ,"AC Name" },
{ PPPOE_TAG_HOSTUNIQ ,"Host Uniq" },
{ PPPOE_TAG_ACCOOKIE ,"AC Cookie" },
{ PPPOE_TAG_VENDORSPEC ,"Vendor Specific" },
{ PPPOE_TAG_RELAYSESSID ,"Relay Session ID" },
{ PPPOE_TAG_SERVNAMEERR ,"Service Name Error" },
{ PPPOE_TAG_ACSYSERR ,"AC System Error" },
{ PPPOE_TAG_GENERICERR ,"Generic Error" },
{ 0, "" }
};
/*
* PPPOE frame format
*/
typedef struct pppoe
{
u_int8_t vertype;
u_int8_t code;
u_int16_t session;
u_int16_t length;
} pppoe_t;
typedef struct pppoe_tlv
{
u_int16_t tagtype;
u_int16_t taglen;
} pppoe_tlv_t;
extern struct arg_t * my_args;
/*----------------------------------------------------------------------------
**
** dump_pppoe_hdr()
**
** Displays PPPOE headers
**
**----------------------------------------------------------------------------
*/
int dump_pppoe_hdr(packet_t *pkt)
{
pppoe_t pppoe;
int len;
/* Set the layer */
set_layer(LAYER_DATALINK);
/*
* Get the header
*/
if (get_packet_bytes((u_int8_t *) &pppoe, pkt, sizeof(pppoe_t)) == 0)
return 0;
len = ntohs(pppoe.length);
/*
* Dump the header
*/
if (my_args->m)
{
display_minimal_string("| PPPOE ");
}
else
{
display_header_banner("PPPOE Header");
display("Version/Type", &pppoe.vertype, 1, DISP_HEX);
display("Session ID", (u_int8_t *) &pppoe.session, 2, DISP_HEX);
display("Length", (u_int8_t *) &len, 2, DISP_DEC);
display_strmap_hex("Message code", pppoe.code, pppoe_code_map);
}
/* dump the hex buffer */
hexbuffer_flush();
return len;
}
/*----------------------------------------------------------------------------
**
** dump_pppoed()
**
** Displays PPPOE discovery packets
**
**----------------------------------------------------------------------------
*/
void dump_pppoed(packet_t *pkt)
{
pppoe_tlv_t tlv;
int len;
int offset;
int totlen;
u_int8_t data[1000]; /* should be enough */
totlen = dump_pppoe_hdr(pkt);
/* do no more if we don't need to */
if (my_args->m)
return;
/* dump the TLVs */
while ((totlen > 0) &&
(get_packet_bytes((u_int8_t*)&tlv, pkt, sizeof(pppoe_tlv_t))))
{
/* do the header */
len = ntohs(tlv.taglen);
totlen -= (sizeof(pppoe_tlv_t)+len);
display_strmap_hex(" TLV type", ntohs(tlv.tagtype), pppoe_tlv_map);
display(" TLV len", (u_int8_t*)&len, 2, DISP_DEC);
/* copy the data out */
len = (len>sizeof(data))?sizeof(data)-1:len;
if (len == 0) continue;
if (get_packet_bytes(data, pkt, len) == 0)
return;
offset=0;
if (tlv.tagtype == PPPOE_TAG_ENDOFLIST) break;
/* and the data */
switch (ntohs(tlv.tagtype)) {
case PPPOE_TAG_SERVICENAME:
case PPPOE_TAG_ACNAME:
case PPPOE_TAG_SERVNAMEERR:
case PPPOE_TAG_ACSYSERR:
case PPPOE_TAG_GENERICERR:
/* all string values, if present, not necessarily null terminated */
data[len]=0;
display(" TLV value", data, len, DISP_STRING);
break;
case PPPOE_TAG_VENDORSPEC:
/*
* 4 bytes vendor id followed by whatever - we dump as hex by
* falling through
*/
display(" TLV vendor", data, 4, DISP_HEX);
offset+=4;
case PPPOE_TAG_HOSTUNIQ:
case PPPOE_TAG_ACCOOKIE:
case PPPOE_TAG_RELAYSESSID:
default:
/* all hex values, if present, and not necessarily null terminated */
display(" TLV value", data+offset, len-offset, DISP_HEX);
break;
}
}
/* dump the hex buffer */
hexbuffer_flush();
}
/*----------------------------------------------------------------------------
**
** dump_pppoes()
**
** Displays PPPOE data session packets
**
**----------------------------------------------------------------------------
*/
void dump_pppoes(packet_t *pkt)
{
dump_pppoe_hdr(pkt);
dump_ppp(pkt);
}
syntax highlighted by Code2HTML, v. 0.9.1