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 #include <linux/ppp_defs.h>
24 #include <linux/if_pppox.h>
25 #include <linux/if_ppp.h>
27 #error this module meant for use with linux only at this time
36 #include <pathnames.h>
38 const char pppd_version[] = VERSION;
40 #define _PATH_ETHOPT _ROOT_PATH "/etc/ppp/options."
42 #define PPPOE_MTU 1492
46 char *pppoe_srv_name=NULL;
47 char *pppoe_ac_name=NULL;
48 char *hostuniq = NULL;
51 int setdevname_pppoe(const char *cp);
53 struct session *ses = NULL;
54 static int connect_pppoe_ses(void)
58 client_init_ses(ses,devnam);
61 ses->np=1; /* jamal debug the discovery portion */
63 strlcpy(ppp_devnam, devnam, sizeof(ppp_devnam));
65 err= session_connect ( ses );
68 poe_fatal(ses,"Failed to negotiate PPPoE connection: %d %m",errno,errno);
72 poe_info(ses,"Connecting PPPoE socket: %E %04x %s %p",
73 ses->sp.sa_addr.pppoe.remote,
74 ses->sp.sa_addr.pppoe.sid,
75 ses->sp.sa_addr.pppoe.dev,ses);
77 err = connect(ses->fd, (struct sockaddr*)&ses->sp,
78 sizeof(struct sockaddr_pppox));
82 poe_fatal(ses,"Failed to connect PPPoE socket: %d %m",errno,errno);
87 fatal("discovery complete\n");
89 /* Once the logging is fixed, print a message here indicating
90 connection parameters */
95 static void disconnect_pppoe_ses(void)
98 warn("Doing disconnect");
99 session_disconnect(ses);
100 ses->sp.sa_addr.pppoe.sid = 0;
101 ret = connect(ses->fd, (struct sockaddr*)&ses->sp,
102 sizeof(struct sockaddr_pppox));
106 static void init_device_pppoe(void)
109 ses=(void *)malloc(sizeof(struct session));
111 fatal("No memory for new PPPoE session");
113 memset(ses,0,sizeof(struct session));
115 if ((ses->filt=malloc(sizeof(struct filter))) == NULL) {
116 poe_error (ses,"failed to malloc for Filter ");
120 filt=ses->filt; /* makes the code more readable */
121 memset(filt,0,sizeof(struct filter));
123 if (pppoe_ac_name !=NULL) {
124 if (strlen (pppoe_ac_name) > 255) {
125 poe_error (ses," AC name too long (maximum allowed 256 chars)");
128 ses->filt->ntag = make_filter_tag(PTT_AC_NAME,
129 strlen(pppoe_ac_name),
132 if ( ses->filt->ntag== NULL) {
133 poe_error (ses,"failed to malloc for AC name");
140 if (pppoe_srv_name !=NULL) {
141 if (strlen (pppoe_srv_name) > 255) {
142 poe_error (ses," Service name too long
143 (maximum allowed 256 chars)");
146 ses->filt->stag = make_filter_tag(PTT_SRV_NAME,
147 strlen(pppoe_srv_name),
149 if ( ses->filt->stag == NULL) {
150 poe_error (ses,"failed to malloc for service name");
156 ses->filt->htag = make_filter_tag(PTT_HOST_UNIQ,
159 if ( ses->filt->htag == NULL) {
160 poe_error (ses,"failed to malloc for Uniq Host Id ");
166 ses->retries=retries;
169 memcpy( ses->name, devnam, IFNAMSIZ);
173 static void send_config_pppoe(int mtu,
182 warn("Couldn't increase MTU to %d", mtu);
183 sock = socket(AF_INET, SOCK_DGRAM, 0);
185 fatal("Couldn't create IP socket: %m");
186 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
188 if (ioctl(sock, SIOCSIFMTU, (caddr_t) &ifr) < 0)
189 fatal("ioctl(SIOCSIFMTU): %m");
194 static void recv_config_pppoe(int mru,
200 error("Couldn't increase MRU to %d", mru);
203 struct channel pppoe_channel;
204 /* Check is cp is a valid ethernet device
205 * return either 1 if "cp" is a reasonable thing to name a device
207 * Note that we don't actually open the device at this point
208 * We do need to fill in:
209 * devnam: a string representation of the device
212 int (*old_setdevname_hook)(const char* cp) = NULL;
213 int setdevname_pppoe(const char *cp)
216 char dev[IFNAMSIZ+1];
221 ret =sscanf(cp, FMTSTRING(IFNAMSIZ),addr, addr+1, addr+2,
222 addr+3, addr+4, addr+5,&sid,dev);
225 ret = get_sockaddr_ll(cp,NULL);
227 fatal("PPPoE: Cannot create PF_PACKET socket for PPPoE discovery\n");
229 strncpy(devnam, cp, sizeof(devnam));
231 /* long form parsed */
232 ret = get_sockaddr_ll(dev,NULL);
234 fatal("PPPoE: Cannot create PF_PACKET socket for PPPoE discovery\n");
236 strncpy(devnam, cp, sizeof(devnam));
241 if( ret == 1 && the_channel != &pppoe_channel ){
243 the_channel = &pppoe_channel;
245 lcp_allowoptions[0].neg_accompression = 0;
246 lcp_wantoptions[0].neg_accompression = 0;
248 lcp_allowoptions[0].neg_asyncmap = 0;
249 lcp_wantoptions[0].neg_asyncmap = 0;
251 lcp_allowoptions[0].neg_pcompression = 0;
252 lcp_wantoptions[0].neg_pcompression = 0;
254 ipcp_allowoptions[0].neg_vj=0;
255 ipcp_wantoptions[0].neg_vj=0;
257 ipcp_allowoptions[0].default_route=1;
258 ipcp_wantoptions[0].default_route=1;
260 for (opt = ipcp_protent.options; opt->name != NULL; ++opt) {
261 if (!strncmp(opt->name, "usepeerdns", 10)) {
262 *(bool *)(opt->addr) = 1;
268 ccp_allowoptions[0].deflate = 0 ;
269 ccp_wantoptions[0].deflate = 0 ;
271 ccp_allowoptions[0].bsd_compress = 0;
272 ccp_wantoptions[0].bsd_compress = 0;
280 struct channel pppoe_channel = {
282 process_extra_options: NULL,
284 connect: &connect_pppoe_ses,
285 disconnect: &disconnect_pppoe_ses,
286 establish_ppp: &generic_establish_ppp,
287 disestablish_ppp: &generic_disestablish_ppp,
288 send_config: &send_config_pppoe,
289 recv_config: &recv_config_pppoe,