Watt-32 tcp/ip  2.2 dev-rel.10
pppoe.c
Go to the documentation of this file.
1 
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <time.h>
42 
43 #include "wattcp.h"
44 #include "misc.h"
45 #include "timer.h"
46 #include "strings.h"
47 #include "language.h"
48 #include "run.h"
49 #include "pcconfig.h"
50 #include "pcdbug.h"
51 #include "pcqueue.h"
52 #include "pctcp.h"
53 #include "pcsed.h"
54 #include "pcpkt.h"
55 #include "pppoe.h"
56 #include "ppp.h"
57 
58 #if defined(USE_PPPOE)
59 
60 enum States {
61  STATE_NONE = 0,
62  STATE_DISCOVERY,
63  STATE_SESSION
64  };
65 
66 static void (W32_CALL *prev_hook) (const char*, const char*) = NULL;
67 
68 static BOOL got_PADO;
69 static BOOL got_PADS;
70 static BOOL got_PADT;
71 static BOOL got_PADM;
72 static WORD session = 0;
73 static enum States state = STATE_NONE;
74 static mac_address ac_mac_addr; /* Access Consentrator's (AC) MAC address */
75 
76 static struct {
77  int enable;
78  int trace;
79  int timeout;
80  int retries;
82  char service_name [MAX_VALUELEN+1];
83  char user_name [MAX_VALUELEN+1];
84  char password [MAX_VALUELEN+1];
85  } cfg = { 0, 0, 1, 3, 60, "", "", "" };
86 
87 static int pppoe_send_disc (int code);
88 
89 static void W32_CALL pppoe_config (const char *name, const char *value)
90 {
91  static const struct config_table pppoe_cfg[] = {
92  { "ENABLE", ARG_ATOI, (void*)&cfg.enable },
93  { "TRACE", ARG_ATOI, (void*)&cfg.trace },
94  { "TIMEOUT", ARG_ATOI, (void*)&cfg.timeout },
95  { "RETRIES", ARG_ATOI, (void*)&cfg.retries },
96  { "LCP_ECHO", ARG_ATOI, (void*)&cfg.lcp_echo_intv },
97  { "SERVICENAME", ARG_STRCPY, (void*)&cfg.service_name },
98  { "USER", ARG_STRCPY, (void*)&cfg.user_name },
99  { "PASSWD", ARG_STRCPY, (void*)&cfg.password },
100  { NULL, 0, NULL }
101  };
102  if (!parse_config_table(&pppoe_cfg[0], "PPPOE.", name, value) && prev_hook)
103  (*prev_hook) (name, value);
104 }
105 
110 static BOOL pppoe_wait (int wait_code)
111 {
112  DWORD timer = set_timeout (1000 * cfg.timeout);
113 
114  while (1)
115  {
116  tcp_tick (NULL);
117 
118  if ((wait_code == PPPOE_CODE_PADO && got_PADO) ||
119  (wait_code == PPPOE_CODE_PADS && got_PADS))
120  {
121 #if defined(USE_DEBUG)
122  if (cfg.trace)
123  (*_printf) ("PPPoE: got %s\n", pppoe_get_code(wait_code));
124 #endif
125  return (TRUE);
126  }
127  if (chk_timeout(timer))
128  break;
129  }
130  return (FALSE);
131 }
132 
137 static BOOL pppoe_discovery (void)
138 {
139  int loop;
140 
141  for (loop = 1; loop <= cfg.retries; loop++)
142  {
143  if (!pppoe_send_disc(PPPOE_CODE_PADI)) /* send Init packet */
144  return (FALSE);
145 
146  if (pppoe_wait(PPPOE_CODE_PADO)) /* wait for Offer */
147  break;
148  }
149  if (loop > cfg.retries)
150  return (FALSE);
151 
152  for (loop = 1; loop <= cfg.retries; loop++)
153  {
154  if (!pppoe_send_disc(PPPOE_CODE_PADR)) /* send Request */
155  return (FALSE);
156 
157  if (pppoe_wait(PPPOE_CODE_PADS)) /* wait for Session-confirm */
158  break;
159  }
160  return (loop <= cfg.retries);
161 }
162 
166 void pppoe_init (void)
167 {
168  prev_hook = usr_init;
169  usr_init = pppoe_config;
170  state = STATE_DISCOVERY;
171  got_PADO = got_PADS = got_PADT = FALSE;
172  memcpy (ac_mac_addr, _eth_brdcast, sizeof(ac_mac_addr));
173 }
174 
175 
184 int pppoe_start (void)
185 {
186  if (!cfg.enable || _pktdevclass != PDCLASS_ETHER)
187  return (1);
188 
189  if (!pppoe_discovery())
190  return (0);
191 
192 #undef MSS_MAX
193 #define MSS_MAX (PPPOE_MAX_DATA - TCP_OVERHEAD)
194  _mss = min (_mss, MSS_MAX);
195 
196  /* If not already clamped by user/pktdrvr, set MTU == 1492
197  */
198  if (_mtu > PPPOE_MAX_DATA)
199  _mtu = PPPOE_MAX_DATA;
200 
201  state = STATE_SESSION;
202  ppp_start (cfg.trace);
203  return (1);
204 }
205 
209 void pppoe_exit (void)
210 {
211  if (!cfg.enable || state == STATE_NONE)
212  return;
213 
214  pppoe_send_disc (PPPOE_CODE_PADT);
215  session = 0;
216  state = STATE_NONE;
217  memcpy (ac_mac_addr, _eth_brdcast, sizeof(ac_mac_addr));
218 }
219 
223 int pppoe_handler (const pppoe_Packet *pkt)
224 {
225  const BYTE *buf;
226  const void *src;
227  const void *dst;
228  WORD proto, len;
229  BOOL bcast, delivered = FALSE;
230 
231  if (pkt->type != 1 || pkt->ver != 1)
232  return (0);
233 
234  src = MAC_SRC (pkt);
235  dst = MAC_DST (pkt);
236  proto = MAC_TYP (pkt);
237  bcast = !memcmp (dst, _eth_brdcast, _eth_mac_len);
238 
239  if (proto == PPPOE_SESS_TYPE && state == STATE_SESSION)
240  {
241  if (pkt->code == PPPOE_CODE_SESS &&
242  pkt->session == session &&
243  !bcast &&
244  !memcmp(dst, _eth_addr, _eth_mac_len) && /* to us? */
245  !memcmp(src, ac_mac_addr, _eth_mac_len))
246  {
247  len = intel16 (pkt->length);
248  buf = &pkt->data[0];
249  ppp_input (buf, len); /* assume ppp_input() traces it */
250  delivered = TRUE;
251  }
252  }
253  else if (!bcast && proto == PPPOE_DISC_TYPE && state == STATE_DISCOVERY)
254  {
255  if (pkt->code == PPPOE_CODE_PADO) /* Offer (can this be bcast?) */
256  {
257  got_PADO = TRUE;
258  memcpy (ac_mac_addr, src, _eth_mac_len);
259  }
260  else if (pkt->code == PPPOE_CODE_PADT && /* Terminate */
261  pkt->session == session)
262  {
263  if (cfg.trace)
264  outsnl (_LANG("PPPoE: session terminated"));
265  got_PADT = TRUE;
266  session = 0;
267  }
268  else if (pkt->code == PPPOE_CODE_PADS) /* Session-confirmation */
269  {
270  got_PADS = TRUE;
271  session = pkt->session;
272  }
273  else if (pkt->code == PPPOE_CODE_PADM) /* Message (what to do?) */
274  {
275  got_PADM = TRUE;
276  }
277  }
278  if (!delivered)
279  DEBUG_RX (NULL, pkt);
280  return (1);
281 }
282 
287 BOOL pppoe_is_up (const void *dest)
288 {
289 #if 1
290  if (!cfg.enable || memcmp(dest,ac_mac_addr,_eth_mac_len))
291  return (FALSE);
292  return (session != 0 && !got_PADT);
293 #else
294  session = 0xAA55;
295  return (TRUE); /* test */
296 #endif
297 }
298 
302 static WORD build_pad (struct pppoe_Packet *pkt, WORD code)
303 {
304  BYTE *tags = &pkt->data[0];
305 
306  if (code == PPPOE_CODE_PADI || code == PPPOE_CODE_PADR)
307  {
308  WORD srv_len = 0;
309 
310  *(WORD*) tags = PPPOE_TAG_SERVICE_NAME;
311  tags += 2;
312  if (cfg.service_name[0])
313  {
314  srv_len = strlen (cfg.service_name);
315  srv_len = min (srv_len, sizeof(pkt->data)-2-PPPOE_TAG_HDR_SIZE);
316  memcpy (tags+2, cfg.service_name, srv_len);
317  }
318  *(WORD*) tags = intel16 (srv_len);
319 
320  /* Insert PPPOE_TAG_END_LIST ?
321  */
322  return (srv_len + PPPOE_TAG_HDR_SIZE);
323  }
324  *(WORD*)tags = 0; /* No tags */
325  return (0);
326 }
327 
332 static int pppoe_send_disc (int code)
333 {
334  pppoe_Packet *pkt;
335  WORD len;
336 
337  pkt = (pppoe_Packet*) _eth_formatpacket (&ac_mac_addr[0], PPPOE_DISC_TYPE);
338  len = build_pad (pkt, code);
339 
340  pkt->ver = 1;
341  pkt->type = 1;
342  pkt->code = code;
343  pkt->session = session;
344  pkt->length = intel16 (len);
345 
346 #if defined(USE_DEBUG)
347  if (cfg.trace)
348  (*_printf) ("PPPOE: sending %s\n", pppoe_get_code(code));
349 #endif
350 
351  return _eth_send (len + PPPOE_HDR_SIZE, NULL, __FILE__, __LINE__);
352 }
353 
357 int pppoe_send_sess (const void *sock, const BYTE *buf, WORD len)
358 {
359  pppoe_Packet *pkt;
360 
361  pkt = (pppoe_Packet*) _eth_formatpacket (&ac_mac_addr[0], PPPOE_SESS_TYPE);
362 
363  pkt->ver = 1;
364  pkt->type = 1;
365  pkt->code = PPPOE_CODE_SESS;
366  pkt->session = session;
367  pkt->length = intel16 (len);
368 
369  memcpy (pkt->data, buf, len);
370  return _eth_send (len + PPPOE_HDR_SIZE, sock, __FILE__, __LINE__);
371 }
372 
377 void *pppoe_mac_format (union link_Packet *tx)
378 {
379  pppoe_Packet *pppoe = (pppoe_Packet*) tx->eth.data;
380 
381  memcpy (&tx->eth.head.destination[0], ac_mac_addr, sizeof(mac_address));
382  memcpy (&tx->eth.head.source[0], _eth_addr, sizeof(mac_address));
383 
384  tx->eth.head.type = PPPOE_SESS_TYPE;
385  pppoe->ver = 1;
386  pppoe->type = 1;
387  pppoe->code = PPPOE_CODE_SESS;
388  pppoe->session = session;
389  _pkt_ip_ofs = sizeof(eth_Header) + PPPOE_HDR_SIZE + 2; /* !! see _eth_send() */
390  *(WORD*) &pppoe->data[0] = intel16 (PPP_IP);
391  return (void*) &pppoe->data[2];
392 }
393 #endif /* USE_PPPOE */
394 
int W32_CALL parse_config_table(const struct config_table *tab, const char *section, const char *name, const char *value)
Parse the config-table and if a match is found for ('section'+'.
Definition: pcconfig.c:379
mac_address _eth_brdcast
Link-layer broadcast address.
Definition: pcsed.c:51
convert to int
Definition: tcp.h:424
BOOL pppoe_is_up(const void *dest)
Determine if we have a PPPoE session with the machine given by 'dest'.
Definition: pppoe.c:287
static BOOL pppoe_discovery(void)
The PPPoE Discovery handler.
Definition: pppoe.c:137
int W32_CALL _eth_send(WORD len, const void *sock, const char *file, unsigned line)
_eth_send() does the actual transmission once we are complete with filling the buffer.
Definition: pcsed.c:306
void pppoe_init(void)
Set config-parser hook and initial values.
Definition: pppoe.c:166
static WORD build_pad(struct pppoe_Packet *pkt, WORD code)
Build a PADx packet.
Definition: pppoe.c:302
copy string value
Definition: tcp.h:432
Core definitions.
void pppoe_exit(void)
Close down PPPoE by sending a PADT.
Definition: pppoe.c:209
mac_address _eth_addr
Local link-layer source address.
Definition: pcsed.c:50
DWORD W32_CALL set_timeout(DWORD msec)
Return time for when given timeout (msec) expires.
Definition: timer.c:503
int pppoe_send_sess(const void *sock, const BYTE *buf, WORD len)
Build and send a PPPoE Session packet (IPCP or LCP packet).
Definition: pppoe.c:357
void *W32_CALL _eth_formatpacket(const void *mac_dest, WORD eth_type)
_eth_format_packet() places the next packet to be transmitted into the above link-layer output packet...
Definition: pcsed.c:135
BYTE _eth_mac_len
Size of a MAC address.
Definition: pcsed.c:54
WORD _pktdevclass
Ethernet, Token, FDDI etc.
Definition: pcpkt.c:51
int pppoe_handler(const pppoe_Packet *pkt)
Handle incoming PPPoE packets.
Definition: pppoe.c:223
void * pppoe_mac_format(union link_Packet *tx)
Build a PPPoE session packet header.
Definition: pppoe.c:377
int pppoe_start(void)
Start PPPoE by doing a Discovery.
Definition: pppoe.c:184
Definition: zinftree.h:24
int lcp_echo_intv
Not used.
Definition: pppoe.c:81
char user_name[MAX_VALUELEN+1]
Definition: pppoe.c:83
void ppp_input(const BYTE *inbuffer, WORD len)
The PPP input handler.
Definition: ppp.c:845
static BOOL pppoe_wait(int wait_code)
Loop waiting for timeout or a PAD response.
Definition: pppoe.c:110
WORD W32_CALL tcp_tick(sock_type *s)
Must be called periodically by user application (or BSD socket API).
Definition: pctcp.c:1389
static int pppoe_send_disc(int code)
Build and send a PADx (PPPoE Active Discovery) packet as link-layer broadcast or unicast.
Definition: pppoe.c:332
BOOL W32_CALL chk_timeout(DWORD value)
Check if milli-sec value has expired:
Definition: timer.c:547
WORD _pkt_ip_ofs
ofs from link-layer head to ip
Definition: pcpkt.c:52