1 /* pppoe.c - pppd plugin to implement PPPoE protocol.
3 * Copyright 2000 Michal Ostrowski <mostrows@styx.uwaterloo.ca>,
4 * Jamal Hadi Salim <hadi@cyberus.ca>
5 * Borrows heavily from the PPPoATM plugin by Mitchell Blank Jr.,
6 * which is based in part on work from Jens Axboe and Paul Mackerras.
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version
11 * 2 of the License, or (at your option) any later version.
15 #include <sys/ioctl.h>
16 #include <sys/types.h>
17 #include <sys/socket.h>
23 extern int new_style_driver; /* From sys-linux.c */
24 #include <linux/ppp_defs.h>
25 #include <linux/if_pppox.h>
26 #include <linux/if_ppp.h>
28 #error this module meant for use with linux only at this time
37 #include "pathnames.h"
38 #define _PATH_ETHOPT _ROOT_PATH "/etc/ppp/options."
40 #define PPPOE_MTU 1492
42 static char *bad_options[] = {
72 char *pppoe_srv_name=NULL;
73 char *pppoe_ac_name=NULL;
74 char *hostuniq = NULL;
77 int setdevname_pppoe(const char *cp);
79 static option_t pppoe_options[] = {
80 { "device name", o_wild, (void *) &setdevname_pppoe,
81 "Serial port device name",
82 OPT_DEVNAM | OPT_PRIVFIX | OPT_NOARG | OPT_A2STRVAL | OPT_STATIC,
84 { "pppoe_srv_name", o_string, &pppoe_srv_name,
85 "PPPoE service name"},
86 { "pppoe_ac_name", o_string, &pppoe_ac_name,
87 "PPPoE access concentrator name"},
88 { "pppoe_hostuniq", o_string, &hostuniq,
89 "PPPoE client uniq hostid "},
90 { "pppoe_retransmit", o_int, &retries,
91 "PPPoE client number of retransmit tries"},
92 { "pppoe_server", o_bool, &pppoe_server,
93 "PPPoE listen for incoming requests",1},
99 struct session *ses = NULL;
100 static int connect_pppoe_ses(void)
103 if( pppoe_server == 1 ){
104 srv_init_ses(ses,devnam);
106 client_init_ses(ses,devnam);
109 ses->np=1; /* jamal debug the discovery portion */
111 strlcpy(ppp_devnam, devnam, sizeof(ppp_devnam));
113 err= session_connect ( ses );
116 poe_fatal(ses,"Failed to negotiate PPPoE connection: %d %m",errno,errno);
120 poe_info(ses,"Connecting PPPoE socket: %E %04x %s %p",
121 ses->sp.sa_addr.pppoe.remote,
122 ses->sp.sa_addr.pppoe.sid,
123 ses->sp.sa_addr.pppoe.dev,ses);
125 err = connect(ses->fd, (struct sockaddr*)&ses->sp,
126 sizeof(struct sockaddr_pppox));
130 poe_fatal(ses,"Failed to connect PPPoE socket: %d %m",errno,errno);
135 fatal("discovery complete\n");
137 /* Once the logging is fixed, print a message here indicating
138 connection parameters */
143 static void disconnect_pppoe_ses(void)
146 warn("Doing disconnect");
147 session_disconnect(ses);
148 ses->sp.sa_addr.pppoe.sid = 0;
149 ret = connect(ses->fd, (struct sockaddr*)&ses->sp,
150 sizeof(struct sockaddr_pppox));
155 static int setspeed_pppoe(const char *cp)
160 static void init_device_pppoe(void)
164 ses=(void *)malloc(sizeof(struct session));
166 fatal("No memory for new PPPoE session");
168 memset(ses,0,sizeof(struct session));
170 if ((ses->filt=malloc(sizeof(struct filter))) == NULL) {
171 poe_error (ses,"failed to malloc for Filter ");
175 filt=ses->filt; /* makes the code more readable */
176 memset(filt,0,sizeof(struct filter));
178 if (pppoe_ac_name !=NULL) {
179 if (strlen (pppoe_ac_name) > 255) {
180 poe_error (ses," AC name too long (maximum allowed 256 chars)");
183 ses->filt->ntag = make_filter_tag(PTT_AC_NAME,
184 strlen(pppoe_ac_name),
187 if ( ses->filt->ntag== NULL) {
188 poe_error (ses,"failed to malloc for AC name");
195 if (pppoe_srv_name !=NULL) {
196 if (strlen (pppoe_srv_name) > 255) {
197 poe_error (ses," Service name too long
198 (maximum allowed 256 chars)");
201 ses->filt->stag = make_filter_tag(PTT_SRV_NAME,
202 strlen(pppoe_srv_name),
204 if ( ses->filt->stag == NULL) {
205 poe_error (ses,"failed to malloc for service name");
211 ses->filt->htag = make_filter_tag(PTT_HOST_UNIQ,
214 if ( ses->filt->htag == NULL) {
215 poe_error (ses,"failed to malloc for Uniq Host Id ");
221 ses->retries=retries;
224 memcpy( ses->name, devnam, IFNAMSIZ);
228 static void pppoe_extra_options()
232 snprintf(buf, 256, _PATH_ETHOPT "%s",devnam);
233 if(!options_from_file(buf, 0, 0, 1))
234 exit(EXIT_OPTION_ERROR);
240 static void send_config_pppoe(int mtu,
248 if (mtu > PPPOE_MTU) {
249 warn("Not increasing MTU to %d, max is %d", mtu, PPPOE_MTU);
255 static void recv_config_pppoe(int mru,
261 error("Not increasing MRU to %d, max is %d", mru, PPPOE_MTU);
264 static void set_xaccm_pppoe(int unit, ext_accm accm)
271 struct channel pppoe_channel;
272 /* Check is cp is a valid ethernet device
273 * return either 1 if "cp" is a reasonable thing to name a device
275 * Note that we don't actually open the device at this point
276 * We do need to fill in:
277 * devnam: a string representation of the device
280 int (*old_setdevname_hook)(const char* cp) = NULL;
281 int setdevname_pppoe(const char *cp)
284 char dev[IFNAMSIZ+1];
289 ret =sscanf(cp, FMTSTRING(IFNAMSIZ),addr, addr+1, addr+2,
290 addr+3, addr+4, addr+5,&sid,dev);
293 ret = get_sockaddr_ll(cp,NULL);
295 fatal("PPPoE: Cannot create PF_PACKET socket for PPPoE discovery\n");
297 strncpy(devnam, cp, sizeof(devnam));
299 /* long form parsed */
300 ret = get_sockaddr_ll(dev,NULL);
302 fatal("PPPoE: Cannot create PF_PACKET socket for PPPoE discovery\n");
304 strncpy(devnam, cp, sizeof(devnam));
309 if( ret == 1 && the_channel != &pppoe_channel ){
311 the_channel = &pppoe_channel;
313 lcp_allowoptions[0].neg_accompression = 0;
314 lcp_wantoptions[0].neg_accompression = 0;
316 lcp_allowoptions[0].neg_asyncmap = 0;
317 lcp_wantoptions[0].neg_asyncmap = 0;
319 lcp_allowoptions[0].neg_pcompression = 0;
320 lcp_wantoptions[0].neg_pcompression = 0;
322 ccp_allowoptions[0].deflate = 0 ;
323 ccp_wantoptions[0].deflate = 0 ;
325 ipcp_allowoptions[0].neg_vj=0;
326 ipcp_wantoptions[0].neg_vj=0;
328 ccp_allowoptions[0].bsd_compress = 0;
329 ccp_wantoptions[0].bsd_compress = 0;
338 void plugin_init(void)
341 fatal("PPPoE plugin loading...");
345 if (!ppp_available() && !new_style_driver)
346 fatal("Kernel doesn't support ppp_generic needed for PPPoE");
348 fatal("No PPPoE support on this OS");
350 add_options(pppoe_options);
353 info("PPPoE Plugin Initialized");
356 struct channel pppoe_channel = {
357 options: pppoe_options,
358 process_extra_options: &pppoe_extra_options,
360 connect: &connect_pppoe_ses,
361 disconnect: &disconnect_pppoe_ses,
362 establish_ppp: &generic_establish_ppp,
363 disestablish_ppp: &generic_disestablish_ppp,
364 send_config: &send_config_pppoe,
365 recv_config: &recv_config_pppoe,