www.usr.com/support/gpl/USR9107_release.1.4.tar.gz
[bcm963xx.git] / userapps / opensource / ppp / pppoecd / pppoe.c
1 /* pppoe.c - pppd plugin to implement PPPoE protocol.
2  *
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.
7  *
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.
12  */
13
14 #include <string.h>
15 #include <sys/ioctl.h>
16 #include <sys/types.h>
17 #include <sys/socket.h>
18 #include <unistd.h>
19 #include <errno.h>
20 #include <sys/stat.h>
21 #include <pppoe.h>
22 #if _linux_
23 #include <linux/ppp_defs.h>
24 #include <linux/if_pppox.h>
25 #include <linux/if_ppp.h>
26 #else
27 #error this module meant for use with linux only at this time
28 #endif
29
30
31 #include <pppd.h>
32 #include <fsm.h>
33 #include <lcp.h>
34 #include <ipcp.h>
35 #include <ccp.h>
36 #include <pathnames.h>
37
38 const char pppd_version[] = VERSION;
39
40 #define _PATH_ETHOPT         _ROOT_PATH "/etc/ppp/options."
41
42 #define PPPOE_MTU       1492
43 extern int kill_link;
44
45 bool    pppoe_server=0;
46 char    *pppoe_srv_name=NULL;
47 char    *pppoe_ac_name=NULL;
48 char    *hostuniq = NULL;
49 int     retries = 0;
50
51 int setdevname_pppoe(const char *cp);
52
53 struct session *ses = NULL;
54 static int connect_pppoe_ses(void)
55 {
56     int err=-1;
57
58     client_init_ses(ses,devnam);
59
60 #if 0
61     ses->np=1;  /* jamal debug the discovery portion */
62 #endif
63     strlcpy(ppp_devnam, devnam, sizeof(ppp_devnam));
64
65     err= session_connect ( ses );
66
67     if(err < 0){
68         poe_fatal(ses,"Failed to negotiate PPPoE connection: %d %m",errno,errno);
69     }
70
71
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);
76
77     err = connect(ses->fd, (struct sockaddr*)&ses->sp,
78                   sizeof(struct sockaddr_pppox));
79
80
81     if( err < 0 ){
82         poe_fatal(ses,"Failed to connect PPPoE socket: %d %m",errno,errno);
83         return err;
84     }
85 #if 0
86     if (ses->np)
87         fatal("discovery complete\n");
88 #endif
89     /* Once the logging is fixed, print a message here indicating
90        connection parameters */
91
92     return ses->fd;
93 }
94
95 static void disconnect_pppoe_ses(void)
96 {
97     int ret;
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));
103
104 }
105
106 static void init_device_pppoe(void)
107 {
108     struct filter *filt;
109     ses=(void *)malloc(sizeof(struct session));
110     if(!ses){
111         fatal("No memory for new PPPoE session");
112     }
113     memset(ses,0,sizeof(struct session));
114
115     if ((ses->filt=malloc(sizeof(struct filter))) == NULL) {
116         poe_error (ses,"failed to malloc for Filter ");
117         poe_die (-1);
118     }
119
120     filt=ses->filt;  /* makes the code more readable */
121     memset(filt,0,sizeof(struct filter));
122
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)");
126             poe_die(-1);
127         }
128         ses->filt->ntag = make_filter_tag(PTT_AC_NAME,
129                                           strlen(pppoe_ac_name),
130                                           pppoe_ac_name);
131
132         if ( ses->filt->ntag== NULL) {
133             poe_error (ses,"failed to malloc for AC name");
134             poe_die(-1);
135         }
136
137     }
138
139
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)");
144             poe_die(-1);
145         }
146         ses->filt->stag = make_filter_tag(PTT_SRV_NAME,
147                                           strlen(pppoe_srv_name),
148                                           pppoe_srv_name);
149         if ( ses->filt->stag == NULL) {
150             poe_error (ses,"failed to malloc for service name");
151             poe_die(-1);
152         }
153     }
154
155     if (hostuniq) {
156         ses->filt->htag = make_filter_tag(PTT_HOST_UNIQ,
157                                           strlen(hostuniq),
158                                           hostuniq);
159         if ( ses->filt->htag == NULL) {
160             poe_error (ses,"failed to malloc for Uniq Host Id ");
161             poe_die(-1);
162         }
163     }
164
165     if (retries) {
166         ses->retries=retries;
167     }
168
169     memcpy( ses->name, devnam, IFNAMSIZ);
170     ses->opt_debug=1;
171 }
172
173 static void send_config_pppoe(int mtu,
174                               u_int32_t asyncmap,
175                               int pcomp,
176                               int accomp)
177 {
178     int sock;
179     struct ifreq ifr;
180
181     if (mtu > PPPOE_MTU)
182         warn("Couldn't increase MTU to %d", mtu);
183     sock = socket(AF_INET, SOCK_DGRAM, 0);
184     if (sock < 0)
185         fatal("Couldn't create IP socket: %m");
186     strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
187     ifr.ifr_mtu = mtu;
188     if (ioctl(sock, SIOCSIFMTU, (caddr_t) &ifr) < 0)
189         fatal("ioctl(SIOCSIFMTU): %m");
190     (void) close (sock);
191 }
192
193
194 static void recv_config_pppoe(int mru,
195                               u_int32_t asyncmap,
196                               int pcomp,
197                               int accomp)
198 {
199     if (mru > PPPOE_MTU)
200         error("Couldn't increase MRU to %d", mru);
201 }
202
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
206  * or die.
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
210  */
211
212 int (*old_setdevname_hook)(const char* cp) = NULL;
213 int setdevname_pppoe(const char *cp)
214 {
215     int ret;
216     char dev[IFNAMSIZ+1];
217     int addr[ETH_ALEN];
218     int sid;
219     option_t *opt;
220
221     ret =sscanf(cp, FMTSTRING(IFNAMSIZ),addr, addr+1, addr+2,
222                 addr+3, addr+4, addr+5,&sid,dev);
223     if( ret != 8 ){
224
225         ret = get_sockaddr_ll(cp,NULL);
226         if (ret < 0)
227             fatal("PPPoE: Cannot create PF_PACKET socket for PPPoE discovery\n");
228         if (ret == 1)
229             strncpy(devnam, cp, sizeof(devnam));
230     }else{
231         /* long form parsed */
232         ret = get_sockaddr_ll(dev,NULL);
233         if (ret < 0)
234             fatal("PPPoE: Cannot create PF_PACKET socket for PPPoE discovery\n");
235
236         strncpy(devnam, cp, sizeof(devnam));
237         ret = 1;
238     }
239
240
241     if( ret == 1 && the_channel != &pppoe_channel ){
242
243         the_channel = &pppoe_channel;
244
245         lcp_allowoptions[0].neg_accompression = 0;
246         lcp_wantoptions[0].neg_accompression = 0;
247
248         lcp_allowoptions[0].neg_asyncmap = 0;
249         lcp_wantoptions[0].neg_asyncmap = 0;
250
251         lcp_allowoptions[0].neg_pcompression = 0;
252         lcp_wantoptions[0].neg_pcompression = 0;
253
254         ipcp_allowoptions[0].neg_vj=0;
255         ipcp_wantoptions[0].neg_vj=0;
256
257         ipcp_allowoptions[0].default_route=1;
258         ipcp_wantoptions[0].default_route=1;
259         
260         for (opt = ipcp_protent.options; opt->name != NULL; ++opt) {
261                 if (!strncmp(opt->name, "usepeerdns", 10)) {
262                         *(bool *)(opt->addr) = 1;
263                         break;
264                 }
265         }
266
267 #ifdef CCP_SUPPORT
268         ccp_allowoptions[0].deflate = 0 ;
269         ccp_wantoptions[0].deflate = 0 ;
270
271         ccp_allowoptions[0].bsd_compress = 0;
272         ccp_wantoptions[0].bsd_compress = 0;
273 #endif
274
275         init_device_pppoe();
276     }
277     return ret;
278 }
279
280 struct channel pppoe_channel = {
281     options: NULL,
282     process_extra_options: NULL,
283     check_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,
290     close: NULL,
291     cleanup: NULL
292 };
293