2 * Routines for PPP Over Ethernet (PPPoE) packet disassembly (RFC2516)
4 * $Id: packet-pppoe.c,v 1.11 2000/09/11 16:24:09 gram 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>
37 #include "packet-ppp.h"
40 static gint ett_pppoed = -1;
41 static gint ett_pppoed_tags = -1;
43 /* For lack of a better source, I made up the following defines. -jsj */
45 #define PPPOE_CODE_SESSION 0x00
46 #define PPPOE_CODE_PADO 0x7
47 #define PPPOE_CODE_PADI 0x9
48 #define PPPOE_CODE_PADR 0x19
49 #define PPPOE_CODE_PADS 0x65
50 #define PPPOE_CODE_PADT 0xa7
52 #define PPPOE_TAG_EOL 0x0000
53 #define PPPOE_TAG_SVC_NAME 0x0101
54 #define PPPOE_TAG_AC_NAME 0x0102
55 #define PPPOE_TAG_HOST_UNIQ 0x0103
56 #define PPPOE_TAG_AC_COOKIE 0x0104
57 #define PPPOE_TAG_VENDOR 0x0105
58 #define PPPOE_TAG_RELAY_ID 0x0110
59 #define PPPOE_TAG_SVC_ERR 0x0201
60 #define PPPOE_TAG_AC_ERR 0x0202
61 #define PPPOE_TAG_GENERIC_ERR 0x0203
64 pppoecode_to_str(guint8 codetype, const char *fmt) {
65 static const value_string code_vals[] = {
66 {PPPOE_CODE_SESSION, "Session Data" },
67 {PPPOE_CODE_PADO, "Active Discovery Offer (PADO)" },
68 {PPPOE_CODE_PADI, "Active Discovery Initiation (PADI)" },
69 {PPPOE_CODE_PADR, "Active Discovery Request (PADR)" },
70 {PPPOE_CODE_PADS, "Active Discovery Session-confirmation (PADS)"},
71 {PPPOE_CODE_PADT, "Active Discovery Terminate (PADT)" },
74 return val_to_str(codetype, code_vals, fmt);
78 pppoetag_to_str(guint16 tag_type, const char *fmt) {
79 static const value_string code_vals[] = {
80 {PPPOE_TAG_EOL, "End-Of-List" },
81 {PPPOE_TAG_SVC_NAME, "Service-Name" },
82 {PPPOE_TAG_AC_NAME, "AC-Name" },
83 {PPPOE_TAG_HOST_UNIQ, "Host-Uniq" },
84 {PPPOE_TAG_AC_COOKIE, "AC-Cookie" },
85 {PPPOE_TAG_VENDOR, "Vendor-Specific" },
86 {PPPOE_TAG_RELAY_ID, "Relay-Session-Id" },
87 {PPPOE_TAG_SVC_ERR, "Service-Name-Error"},
88 {PPPOE_TAG_AC_ERR, "AC-System-Error" },
89 {PPPOE_TAG_GENERIC_ERR,"Generic-Error" },
92 return val_to_str(tag_type, code_vals, fmt);
97 dissect_pppoe_tags(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, int payload_length) {
100 guint16 poe_tag_length;
103 proto_tree *pppoe_tree;
106 /* Start Decoding Here. */
109 ti = proto_tree_add_text(tree, NullTVB,offset,payload_length,"PPPoE Tags");
110 pppoe_tree = proto_item_add_subtree(ti, ett_pppoed_tags);
113 while(tagstart <= payload_length-2 ) {
115 poe_tag = pntohs(&pd[tagstart]);
116 poe_tag_length = pntohs(&pd[tagstart + 2]);
118 proto_tree_add_text(pppoe_tree, NullTVB,tagstart,4,
119 "Tag: %s", pppoetag_to_str(poe_tag,"Unknown (0x%02x)"));
122 case PPPOE_TAG_SVC_NAME:
123 case PPPOE_TAG_AC_NAME:
124 case PPPOE_TAG_SVC_ERR:
125 case PPPOE_TAG_AC_ERR:
126 case PPPOE_TAG_GENERIC_ERR:
127 /* tag value should be interpreted as a utf-8 unterminated string.*/
128 if(poe_tag_length > 0 ) {
129 /* really should do some limit checking here. :( */
130 proto_tree_add_text(pppoe_tree, NullTVB,tagstart+4,poe_tag_length,
131 " String Data: %s", format_text(&pd[tagstart+4],poe_tag_length ));
135 if(poe_tag_length > 0 ) {
136 proto_tree_add_text(pppoe_tree, NullTVB,tagstart+4,poe_tag_length,
137 " Binary Data: (%d bytes)", poe_tag_length );
141 if (poe_tag == PPPOE_TAG_EOL) break;
143 tagstart += 4 + poe_tag_length;
149 dissect_pppoed(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
153 guint16 pppoe_session_id;
154 guint16 pppoe_length;
156 proto_tree *pppoe_tree;
159 /* Start Decoding Here. */
160 pppoe_ver = (guint8) ((pd[offset] >> 4) & 0x0f);
161 pppoe_type = (guint8) (pd[offset] & 0x0f);
162 pppoe_code = (guint8) pd[offset + 1];
163 pppoe_session_id = pntohs(&pd[offset + 2]);
164 pppoe_length = pntohs(&pd[offset + 4]);
166 if (check_col(fd, COL_PROTOCOL)) {
167 col_add_str(fd,COL_PROTOCOL, "PPPoED");
170 if (check_col(fd,COL_INFO)) {
171 col_add_fstr(fd,COL_INFO,pppoecode_to_str(pppoe_code,"Unknown code (0x%02x)"));
175 ti = proto_tree_add_text(tree, NullTVB,offset,pppoe_length+6,"PPPoE Discovery");
176 pppoe_tree = proto_item_add_subtree(ti, ett_pppoed);
177 proto_tree_add_text(pppoe_tree, NullTVB,offset,1,
178 "Version: %d", pppoe_ver);
179 proto_tree_add_text(pppoe_tree, NullTVB,offset,1,
180 "Type: %d", pppoe_type);
181 proto_tree_add_text(pppoe_tree, NullTVB,offset+1,1,
182 "Code: %s", pppoecode_to_str(pppoe_code,"Unknown (0x%02x)"));
183 proto_tree_add_text(pppoe_tree, NullTVB,offset+2,2,
184 "Session ID: %04x", pppoe_session_id);
185 proto_tree_add_text(pppoe_tree, NullTVB,offset+4,2,
186 "Payload Length: %d", pppoe_length);
188 dissect_pppoe_tags(pd,offset+6,fd,tree,offset+6+pppoe_length);
193 dissect_pppoes(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
197 guint16 pppoe_session_id;
198 guint16 pppoe_length;
200 proto_tree *pppoe_tree;
203 /* Start Decoding Here. */
204 pppoe_ver = (guint8) ((pd[offset] >> 4) & 0x0f);
205 pppoe_type = (guint8) (pd[offset] & 0x0f);
206 pppoe_code = (guint8) pd[offset + 1];
207 pppoe_session_id = pntohs(&pd[offset + 2]);
208 pppoe_length = pntohs(&pd[offset + 4]);
210 if (check_col(fd, COL_PROTOCOL)) {
211 col_add_str(fd,COL_PROTOCOL, "PPPoES");
214 if (check_col(fd,COL_INFO)) {
215 col_add_fstr(fd,COL_INFO,pppoecode_to_str(pppoe_code,"Unknown code (0x%02x)"));
219 ti = proto_tree_add_text(tree, NullTVB,offset,pppoe_length+6,"PPPoE Session");
220 pppoe_tree = proto_item_add_subtree(ti, ett_pppoed);
221 proto_tree_add_text(pppoe_tree, NullTVB,offset,1,
222 "Version: %d", pppoe_ver);
223 proto_tree_add_text(pppoe_tree, NullTVB,offset,1,
224 "Type: %d", pppoe_type);
225 proto_tree_add_text(pppoe_tree, NullTVB,offset+1,1,
226 "Code: %s", pppoecode_to_str(pppoe_code,"Unknown (0x%02x)"));
227 proto_tree_add_text(pppoe_tree, NullTVB,offset+2,2,
228 "Session ID: %04x", pppoe_session_id);
229 proto_tree_add_text(pppoe_tree, NullTVB,offset+4,2,
230 "Payload Length: %d", pppoe_length);
232 /* dissect_ppp is apparently done as a 'top level' dissector,
233 * so this doesn't work:
234 * dissect_ppp(pd,offset+6,fd,tree);
235 * Im gonna try fudging it.
238 dissect_payload_ppp(pd,offset+6,fd,tree);
242 proto_register_pppoed(void)
244 static gint *ett[] = {
249 proto_register_subtree_array(ett, array_length(ett));
253 proto_reg_handoff_pppoe(void)
255 old_dissector_add("ethertype", ETHERTYPE_PPPOED, dissect_pppoed);
256 old_dissector_add("ethertype", ETHERTYPE_PPPOES, dissect_pppoes);