blob: 77f2a2d3de2895c1e96bbcd48da3c98cc220ef0a
1 | /*********************************************************************** |
2 | * |
3 | * pppoe.h |
4 | * |
5 | * Declaration of various PPPoE constants |
6 | * |
7 | * Copyright (C) 2000 Roaring Penguin Software Inc. |
8 | * |
9 | * This program may be distributed according to the terms of the GNU |
10 | * General Public License, version 2 or (at your option) any later version. |
11 | * |
12 | * LIC: GPL |
13 | * |
14 | * $Id$ |
15 | * |
16 | ***********************************************************************/ |
17 | |
18 | #include "config.h" |
19 | |
20 | extern int IsSetID; |
21 | |
22 | #if defined(HAVE_NETPACKET_PACKET_H) || defined(HAVE_LINUX_IF_PACKET_H) |
23 | #define _POSIX_SOURCE 1 /* For sigaction defines */ |
24 | #endif |
25 | |
26 | #include <stdio.h> /* For FILE */ |
27 | #include <sys/types.h> /* For pid_t */ |
28 | |
29 | /* How do we access raw Ethernet devices? */ |
30 | #undef USE_LINUX_PACKET |
31 | #undef USE_BPF |
32 | |
33 | #if defined(HAVE_NETPACKET_PACKET_H) || defined(HAVE_LINUX_IF_PACKET_H) |
34 | #define USE_LINUX_PACKET 1 |
35 | #elif defined(HAVE_SYS_DLPI_H) |
36 | #define USE_DLPI |
37 | #elif defined(HAVE_NET_BPF_H) |
38 | #define USE_BPF 1 |
39 | #endif |
40 | |
41 | /* Sanity check */ |
42 | #if !defined(USE_BPF) && !defined(USE_LINUX_PACKET) && !defined(USE_DLPI) |
43 | #error Unknown method for accessing raw Ethernet frames |
44 | #endif |
45 | |
46 | #ifdef HAVE_SYS_CDEFS_H |
47 | #include <sys/cdefs.h> |
48 | #endif |
49 | |
50 | #ifdef HAVE_SYS_SOCKET_H |
51 | #include <sys/socket.h> |
52 | #endif |
53 | |
54 | /* Ugly header files on some Linux boxes... */ |
55 | #if defined(HAVE_LINUX_IF_H) |
56 | #include <linux/if.h> |
57 | #elif defined(HAVE_NET_IF_H) |
58 | #include <net/if.h> |
59 | #endif |
60 | |
61 | #ifdef HAVE_NET_IF_TYPES_H |
62 | #include <net/if_types.h> |
63 | #endif |
64 | |
65 | #ifdef HAVE_NET_IF_DL_H |
66 | #include <net/if_dl.h> |
67 | #endif |
68 | |
69 | /* I'm not sure why this is needed... I do not have OpenBSD */ |
70 | #if defined(__OpenBSD__) |
71 | #include <net/ppp_defs.h> |
72 | #include <net/if_ppp.h> |
73 | #endif |
74 | |
75 | #ifdef USE_BPF |
76 | extern int bpfSize; |
77 | struct PPPoEPacketStruct; |
78 | void sessionDiscoveryPacket(struct PPPoEPacketStruct *packet); |
79 | #define BPF_BUFFER_IS_EMPTY (bpfSize <= 0) |
80 | #define BPF_BUFFER_HAS_DATA (bpfSize > 0) |
81 | #define ethhdr ether_header |
82 | #define h_dest ether_dhost |
83 | #define h_source ether_shost |
84 | #define h_proto ether_type |
85 | #define ETH_DATA_LEN ETHERMTU |
86 | #define ETH_ALEN ETHER_ADDR_LEN |
87 | #else |
88 | #undef USE_BPF |
89 | #define BPF_BUFFER_IS_EMPTY 1 |
90 | #define BPF_BUFFER_HAS_DATA 0 |
91 | #endif |
92 | |
93 | #ifdef USE_DLPI |
94 | #include <sys/ethernet.h> |
95 | #define ethhdr ether_header |
96 | #define ETH_DATA_LEN ETHERMTU |
97 | #define ETH_ALEN ETHERADDRL |
98 | #define h_dest ether_dhost.ether_addr_octet |
99 | #define h_source ether_shost.ether_addr_octet |
100 | #define h_proto ether_type |
101 | |
102 | /* cloned from dltest.h */ |
103 | #define MAXDLBUF 8192 |
104 | #define MAXDLADDR 1024 |
105 | #define MAXWAIT 15 |
106 | #define OFFADDR(s, n) (u_char*)((char*)(s) + (int)(n)) |
107 | #define CASERET(s) case s: return ("s") |
108 | |
109 | #endif |
110 | |
111 | /* Define various integer types -- assumes a char is 8 bits */ |
112 | #if SIZEOF_UNSIGNED_SHORT == 2 |
113 | typedef unsigned short UINT16_t; |
114 | #elif SIZEOF_UNSIGNED_INT == 2 |
115 | typedef unsigned int UINT16_t; |
116 | #else |
117 | #error Could not find a 16-bit integer type |
118 | #endif |
119 | |
120 | #if SIZEOF_UNSIGNED_SHORT == 4 |
121 | typedef unsigned short UINT32_t; |
122 | #elif SIZEOF_UNSIGNED_INT == 4 |
123 | typedef unsigned int UINT32_t; |
124 | #elif SIZEOF_UNSIGNED_LONG == 4 |
125 | typedef unsigned long UINT32_t; |
126 | #else |
127 | #error Could not find a 32-bit integer type |
128 | #endif |
129 | |
130 | #ifdef HAVE_LINUX_IF_ETHER_H |
131 | #include <linux/if_ether.h> |
132 | #endif |
133 | |
134 | #include <netinet/in.h> |
135 | |
136 | #ifdef HAVE_NETINET_IF_ETHER_H |
137 | #include <sys/types.h> |
138 | |
139 | #ifdef HAVE_SYS_SOCKET_H |
140 | #include <sys/socket.h> |
141 | #endif |
142 | #ifndef HAVE_SYS_DLPI_H |
143 | #include <netinet/if_ether.h> |
144 | #endif |
145 | #endif |
146 | |
147 | |
148 | |
149 | /* Ethernet frame types according to RFC 2516 */ |
150 | #define ETH_PPPOE_DISCOVERY 0x8863 |
151 | #define ETH_PPPOE_SESSION 0x8864 |
152 | |
153 | /* But some brain-dead peers disobey the RFC, so frame types are variables */ |
154 | extern UINT16_t Eth_PPPOE_Discovery; |
155 | extern UINT16_t Eth_PPPOE_Session; |
156 | |
157 | extern void switchToRealID(void); |
158 | extern void switchToEffectiveID(void); |
159 | extern void dropPrivs(void); |
160 | |
161 | /* PPPoE codes */ |
162 | #define CODE_PADI 0x09 |
163 | #define CODE_PADO 0x07 |
164 | #define CODE_PADR 0x19 |
165 | #define CODE_PADS 0x65 |
166 | #define CODE_PADT 0xA7 |
167 | |
168 | /* Extensions from draft-carrel-info-pppoe-ext-00 */ |
169 | /* I do NOT like PADM or PADN, but they are here for completeness */ |
170 | #define CODE_PADM 0xD3 |
171 | #define CODE_PADN 0xD4 |
172 | |
173 | #define CODE_SESS 0x00 |
174 | |
175 | /* PPPoE Tags */ |
176 | #define TAG_END_OF_LIST 0x0000 |
177 | #define TAG_SERVICE_NAME 0x0101 |
178 | #define TAG_AC_NAME 0x0102 |
179 | #define TAG_HOST_UNIQ 0x0103 |
180 | #define TAG_AC_COOKIE 0x0104 |
181 | #define TAG_VENDOR_SPECIFIC 0x0105 |
182 | #define TAG_RELAY_SESSION_ID 0x0110 |
183 | #define TAG_SERVICE_NAME_ERROR 0x0201 |
184 | #define TAG_AC_SYSTEM_ERROR 0x0202 |
185 | #define TAG_GENERIC_ERROR 0x0203 |
186 | |
187 | /* Extensions from draft-carrel-info-pppoe-ext-00 */ |
188 | /* I do NOT like these tags one little bit */ |
189 | #define TAG_HURL 0x111 |
190 | #define TAG_MOTM 0x112 |
191 | #define TAG_IP_ROUTE_ADD 0x121 |
192 | |
193 | /* Discovery phase states */ |
194 | #define STATE_SENT_PADI 0 |
195 | #define STATE_RECEIVED_PADO 1 |
196 | #define STATE_SENT_PADR 2 |
197 | #define STATE_SESSION 3 |
198 | #define STATE_TERMINATED 4 |
199 | |
200 | /* How many PADI/PADS attempts? */ |
201 | #define MAX_PADI_ATTEMPTS 3 |
202 | |
203 | /* Initial timeout for PADO/PADS */ |
204 | #define PADI_TIMEOUT 5 |
205 | |
206 | /* States for scanning PPP frames */ |
207 | #define STATE_WAITFOR_FRAME_ADDR 0 |
208 | #define STATE_DROP_PROTO 1 |
209 | #define STATE_BUILDING_PACKET 2 |
210 | |
211 | /* Special PPP frame characters */ |
212 | #define FRAME_ESC 0x7D |
213 | #define FRAME_FLAG 0x7E |
214 | #define FRAME_ADDR 0xFF |
215 | #define FRAME_CTRL 0x03 |
216 | #define FRAME_ENC 0x20 |
217 | |
218 | #define IPV4ALEN 4 |
219 | #define SMALLBUF 256 |
220 | |
221 | /* A PPPoE Packet, including Ethernet headers */ |
222 | typedef struct PPPoEPacketStruct { |
223 | struct ethhdr ethHdr; /* Ethernet header */ |
224 | #ifdef PACK_BITFIELDS_REVERSED |
225 | unsigned int type:4; /* PPPoE Type (must be 1) */ |
226 | unsigned int ver:4; /* PPPoE Version (must be 1) */ |
227 | #else |
228 | unsigned int ver:4; /* PPPoE Version (must be 1) */ |
229 | unsigned int type:4; /* PPPoE Type (must be 1) */ |
230 | #endif |
231 | unsigned int code:8; /* PPPoE code */ |
232 | unsigned int session:16; /* PPPoE session */ |
233 | unsigned int length:16; /* Payload length */ |
234 | unsigned char payload[ETH_DATA_LEN]; /* A bit of room to spare */ |
235 | } PPPoEPacket; |
236 | |
237 | /* Header size of a PPPoE packet */ |
238 | #define PPPOE_OVERHEAD 6 /* type, code, session, length */ |
239 | #define HDR_SIZE (sizeof(struct ethhdr) + PPPOE_OVERHEAD) |
240 | #define MAX_PPPOE_PAYLOAD (ETH_DATA_LEN - PPPOE_OVERHEAD) |
241 | #define MAX_PPPOE_MTU (MAX_PPPOE_PAYLOAD - 2) |
242 | |
243 | /* PPPoE Tag */ |
244 | |
245 | typedef struct PPPoETagStruct { |
246 | unsigned int type:16; /* tag type */ |
247 | unsigned int length:16; /* Length of payload */ |
248 | unsigned char payload[ETH_DATA_LEN]; /* A LOT of room to spare */ |
249 | } PPPoETag; |
250 | /* Header size of a PPPoE tag */ |
251 | #define TAG_HDR_SIZE 4 |
252 | |
253 | /* Chunk to read from stdin */ |
254 | #define READ_CHUNK 4096 |
255 | |
256 | /* Function passed to parsePacket */ |
257 | typedef void ParseFunc(UINT16_t type, |
258 | UINT16_t len, |
259 | unsigned char *data, |
260 | void *extra); |
261 | |
262 | #define PPPINITFCS16 0xffff /* Initial FCS value */ |
263 | |
264 | /* Keep track of the state of a connection -- collect everything in |
265 | one spot */ |
266 | |
267 | typedef struct PPPoEConnectionStruct { |
268 | int discoveryState; /* Where we are in discovery */ |
269 | int discoverySocket; /* Raw socket for discovery frames */ |
270 | int sessionSocket; /* Raw socket for session frames */ |
271 | unsigned char myEth[ETH_ALEN]; /* My MAC address */ |
272 | unsigned char peerEth[ETH_ALEN]; /* Peer's MAC address */ |
273 | UINT16_t session; /* Session ID */ |
274 | char *ifName; /* Interface name */ |
275 | char *serviceName; /* Desired service name, if any */ |
276 | char *acName; /* Desired AC name, if any */ |
277 | int synchronous; /* Use synchronous PPP */ |
278 | int useHostUniq; /* Use Host-Uniq tag */ |
279 | int printACNames; /* Just print AC names */ |
280 | int skipDiscovery; /* Skip discovery */ |
281 | int noDiscoverySocket; /* Don't even open discovery socket */ |
282 | int killSession; /* Kill session and exit */ |
283 | FILE *debugFile; /* Debug file for dumping packets */ |
284 | int numPADOs; /* Number of PADO packets received */ |
285 | PPPoETag cookie; /* We have to send this if we get it */ |
286 | PPPoETag relayId; /* Ditto */ |
287 | int PADSHadError; /* If PADS had an error tag */ |
288 | int discoveryTimeout; /* Timeout for discovery packets */ |
289 | } PPPoEConnection; |
290 | |
291 | /* Structure used to determine acceptable PADO or PADS packet */ |
292 | struct PacketCriteria { |
293 | PPPoEConnection *conn; |
294 | int acNameOK; |
295 | int serviceNameOK; |
296 | int seenACName; |
297 | int seenServiceName; |
298 | }; |
299 | |
300 | /* Function Prototypes */ |
301 | UINT16_t etherType(PPPoEPacket *packet); |
302 | int openInterface(char const *ifname, UINT16_t type, unsigned char *hwaddr); |
303 | int sendPacket(PPPoEConnection *conn, int sock, PPPoEPacket *pkt, int size); |
304 | int receivePacket(int sock, PPPoEPacket *pkt, int *size); |
305 | void fatalSys(char const *str); |
306 | void rp_fatal(char const *str); |
307 | void printErr(char const *str); |
308 | void sysErr(char const *str); |
309 | #ifdef DEBUGGING_ENABLED |
310 | void dumpPacket(FILE *fp, PPPoEPacket *packet, char const *dir); |
311 | void dumpHex(FILE *fp, unsigned char const *buf, int len); |
312 | #endif |
313 | int parsePacket(PPPoEPacket *packet, ParseFunc *func, void *extra); |
314 | void parseLogErrs(UINT16_t typ, UINT16_t len, unsigned char *data, void *xtra); |
315 | void pktLogErrs(char const *pkt, UINT16_t typ, UINT16_t len, unsigned char *data, void *xtra); |
316 | void syncReadFromPPP(PPPoEConnection *conn, PPPoEPacket *packet); |
317 | void asyncReadFromPPP(PPPoEConnection *conn, PPPoEPacket *packet); |
318 | void asyncReadFromEth(PPPoEConnection *conn, int sock, int clampMss); |
319 | void syncReadFromEth(PPPoEConnection *conn, int sock, int clampMss); |
320 | char *strDup(char const *str); |
321 | void sendPADT(PPPoEConnection *conn, char const *msg); |
322 | void sendPADTf(PPPoEConnection *conn, char const *fmt, ...); |
323 | |
324 | void sendSessionPacket(PPPoEConnection *conn, |
325 | PPPoEPacket *packet, int len); |
326 | void initPPP(void); |
327 | void clampMSS(PPPoEPacket *packet, char const *dir, int clampMss); |
328 | UINT16_t computeTCPChecksum(unsigned char *ipHdr, unsigned char *tcpHdr); |
329 | UINT16_t pppFCS16(UINT16_t fcs, unsigned char *cp, int len); |
330 | void discovery(PPPoEConnection *conn); |
331 | unsigned char *findTag(PPPoEPacket *packet, UINT16_t tagType, |
332 | PPPoETag *tag); |
333 | |
334 | #define SET_STRING(var, val) do { if (var) free(var); var = strDup(val); } while(0); |
335 | |
336 | #define CHECK_ROOM(cursor, start, len) \ |
337 | do {\ |
338 | if (((cursor)-(start))+(len) > MAX_PPPOE_PAYLOAD) { \ |
339 | syslog(LOG_ERR, "Would create too-long packet"); \ |
340 | return; \ |
341 | } \ |
342 | } while(0) |
343 | |
344 | /* True if Ethernet address is broadcast or multicast */ |
345 | #define NOT_UNICAST(e) ((e[0] & 0x01) != 0) |
346 | #define BROADCAST(e) ((e[0] & e[1] & e[2] & e[3] & e[4] & e[5]) == 0xFF) |
347 | #define NOT_BROADCAST(e) ((e[0] & e[1] & e[2] & e[3] & e[4] & e[5]) != 0xFF) |
348 |