1 /***********************************************************************
5 * Implementation of user-space PPPoE redirector for Linux.
7 * Common functions used by PPPoE client and server
9 * Copyright (C) 2000 by Roaring Penguin Software Inc.
11 * This program may be distributed according to the terms of the GNU
12 * General Public License, version 2 or (at your option) any later version.
14 ***********************************************************************/
16 static char const RCSID[] =
17 "$Id: common.c,v 1.3 2008/06/09 08:34:23 paulus Exp $";
25 #include <pppd/pppd.h>
30 #include <syslog.h> /* for LOG_DEBUG */
37 /**********************************************************************
38 *%FUNCTION: parsePacket
40 * packet -- the PPPoE discovery packet to parse
41 * func -- function called for each tag in the packet
42 * extra -- an opaque data pointer supplied to parsing function
44 * 0 if everything went well; -1 if there was an error
46 * Parses a PPPoE discovery packet, calling "func" for each tag in the packet.
47 * "func" is passed the additional argument "extra".
48 ***********************************************************************/
50 parsePacket(PPPoEPacket *packet, ParseFunc *func, void *extra)
52 UINT16_t len = ntohs(packet->length);
53 unsigned char *curTag;
54 UINT16_t tagType, tagLen;
56 if (PPPOE_VER(packet->vertype) != 1) {
57 error("Invalid PPPoE version (%d)", PPPOE_VER(packet->vertype));
60 if (PPPOE_TYPE(packet->vertype) != 1) {
61 error("Invalid PPPoE type (%d)", PPPOE_TYPE(packet->vertype));
65 /* Do some sanity checks on packet */
66 if (len > ETH_JUMBO_LEN - PPPOE_OVERHEAD) { /* 6-byte overhead for PPPoE header */
67 error("Invalid PPPoE packet length (%u)", len);
71 /* Step through the tags */
72 curTag = packet->payload;
73 while (curTag - packet->payload + TAG_HDR_SIZE <= len) {
74 /* Alignment is not guaranteed, so do this by hand... */
75 tagType = (curTag[0] << 8) + curTag[1];
76 tagLen = (curTag[2] << 8) + curTag[3];
77 if (tagType == TAG_END_OF_LIST) {
80 if ((curTag - packet->payload) + tagLen + TAG_HDR_SIZE > len) {
81 error("Invalid PPPoE tag length (%u)", tagLen);
84 func(tagType, tagLen, curTag+TAG_HDR_SIZE, extra);
85 curTag = curTag + TAG_HDR_SIZE + tagLen;
90 /***********************************************************************
93 * conn -- PPPoE connection
94 * msg -- if non-NULL, extra error message to include in PADT packet.
99 ***********************************************************************/
101 sendPADT(PPPoEConnection *conn, char const *msg)
104 unsigned char *cursor = packet.payload;
108 /* Do nothing if no session established yet */
109 if (!conn->session) return;
111 /* Do nothing if no discovery socket */
112 if (conn->discoverySocket < 0) return;
114 memcpy(packet.ethHdr.h_dest, conn->peerEth, ETH_ALEN);
115 memcpy(packet.ethHdr.h_source, conn->myEth, ETH_ALEN);
117 packet.ethHdr.h_proto = htons(Eth_PPPOE_Discovery);
118 packet.vertype = PPPOE_VER_TYPE(1, 1);
119 packet.code = CODE_PADT;
120 packet.session = conn->session;
122 /* Reset Session to zero so there is no possibility of
123 recursive calls to this function by any signal handler */
126 /* If we're using Host-Uniq, copy it over */
127 if (conn->hostUniq.length) {
128 int len = ntohs(conn->hostUniq.length);
129 memcpy(cursor, &conn->hostUniq, len + TAG_HDR_SIZE);
130 cursor += len + TAG_HDR_SIZE;
131 plen += len + TAG_HDR_SIZE;
134 /* Copy error message */
137 size_t elen = strlen(msg);
138 err.type = htons(TAG_GENERIC_ERROR);
139 err.length = htons(elen);
140 strcpy((char*) err.payload, msg);
141 memcpy(cursor, &err, elen + TAG_HDR_SIZE);
142 cursor += elen + TAG_HDR_SIZE;
143 plen += elen + TAG_HDR_SIZE;
146 /* Copy cookie and relay-ID if needed */
147 if (conn->cookie.type) {
148 CHECK_ROOM(cursor, packet.payload,
149 ntohs(conn->cookie.length) + TAG_HDR_SIZE);
150 memcpy(cursor, &conn->cookie, ntohs(conn->cookie.length) + TAG_HDR_SIZE);
151 cursor += ntohs(conn->cookie.length) + TAG_HDR_SIZE;
152 plen += ntohs(conn->cookie.length) + TAG_HDR_SIZE;
155 if (conn->relayId.type) {
156 CHECK_ROOM(cursor, packet.payload,
157 ntohs(conn->relayId.length) + TAG_HDR_SIZE);
158 memcpy(cursor, &conn->relayId, ntohs(conn->relayId.length) + TAG_HDR_SIZE);
159 cursor += ntohs(conn->relayId.length) + TAG_HDR_SIZE;
160 plen += ntohs(conn->relayId.length) + TAG_HDR_SIZE;
163 packet.length = htons(plen);
164 sendPacket(conn, conn->discoverySocket, &packet, (int) (plen + HDR_SIZE));
169 pppoe_printpkt_hex(void (*printer)(void *, char *, ...), void *arg, unsigned char const *buf, int len)
174 /* do NOT dump PAP packets */
175 if (len >= 2 && buf[0] == 0xC0 && buf[1] == 0x23) {
176 printer(arg, "(PAP Authentication Frame -- Contents not dumped)\n");
180 for (base=0; base<len; base += 16) {
181 for (i=base; i<base+16; i++) {
183 printer(arg, "%02x ", (unsigned) buf[i]);
189 for (i=base; i<base+16; i++) {
191 if (isprint(buf[i])) {
192 printer(arg, "%c", buf[i]);
204 #define EH(x) (x)[0], (x)[1], (x)[2], (x)[3], (x)[4], (x)[5]
206 /* Print out a PPPOE packet for debugging */
207 void pppoe_printpkt(PPPoEPacket *packet,
208 void (*printer)(void *, char *, ...), void *arg)
210 int len = ntohs(packet->length);
211 int i, j, tag, tlen, text;
213 switch (ntohs(packet->ethHdr.h_proto)) {
214 case ETH_PPPOE_DISCOVERY:
215 printer(arg, "PPPOE Discovery V%dT%d ", PPPOE_VER(packet->vertype),
216 PPPOE_TYPE(packet->vertype));
217 switch (packet->code) {
219 printer(arg, "PADI");
222 printer(arg, "PADO");
225 printer(arg, "PADR");
228 printer(arg, "PADS");
231 printer(arg, "PADT");
234 printer(arg, "unknown code %x", packet->code);
236 printer(arg, " session 0x%x length %d\n", ntohs(packet->session), len);
238 case ETH_PPPOE_SESSION:
239 printer(arg, "PPPOE Session V%dT%d", PPPOE_VER(packet->vertype),
240 PPPOE_TYPE(packet->vertype));
241 printer(arg, " code 0x%x session 0x%x length %d\n", packet->code,
242 ntohs(packet->session), len);
245 printer(arg, "Unknown ethernet frame with proto = 0x%x\n",
246 ntohs(packet->ethHdr.h_proto));
249 printer(arg, " dst %02x:%02x:%02x:%02x:%02x:%02x ", EH(packet->ethHdr.h_dest));
250 printer(arg, " src %02x:%02x:%02x:%02x:%02x:%02x\n", EH(packet->ethHdr.h_source));
251 if (pppoe_verbose >= 2)
252 pppoe_printpkt_hex(printer, arg, packet->payload, ntohs(packet->length));
253 if (ntohs(packet->ethHdr.h_proto) != ETH_PPPOE_DISCOVERY)
256 for (i = 0; i + TAG_HDR_SIZE <= len; i += tlen) {
257 tag = (packet->payload[i] << 8) + packet->payload[i+1];
258 tlen = (packet->payload[i+2] << 8) + packet->payload[i+3];
259 if (i + tlen + TAG_HDR_SIZE > len)
265 case TAG_END_OF_LIST:
266 printer(arg, "end-of-list");
268 case TAG_SERVICE_NAME:
269 printer(arg, "service-name");
273 printer(arg, "AC-name");
277 printer(arg, "host-uniq");
280 printer(arg, "AC-cookie");
282 case TAG_VENDOR_SPECIFIC:
283 printer(arg, "vendor-specific");
285 case TAG_RELAY_SESSION_ID:
286 printer(arg, "relay-session-id");
288 case TAG_PPP_MAX_PAYLOAD:
289 printer(arg, "PPP-max-payload");
291 case TAG_SERVICE_NAME_ERROR:
292 printer(arg, "service-name-error");
295 case TAG_AC_SYSTEM_ERROR:
296 printer(arg, "AC-system-error");
299 case TAG_GENERIC_ERROR:
300 printer(arg, "generic-error");
304 printer(arg, "unknown tag 0x%x", tag);
307 /* If it is supposed to be text, make sure it's all printing chars */
309 for (j = 0; j < tlen; ++j) {
310 if (!isprint(packet->payload[i+j])) {
317 printer(arg, " %.*s", tlen, &packet->payload[i]);
319 for (j = 0; j < tlen && j < 32; j++)
320 printer(arg, " %02x", (unsigned) *(&packet->payload[i]+j));
322 printer(arg, "... (length %d)", tlen);
330 void pppoe_log_packet(const char *prefix, PPPoEPacket *packet)
332 init_pr_log(prefix, LOG_DEBUG);
333 pppoe_printpkt(packet, pr_log, NULL);