source: src/router/pppd.new/pppd/plugins/rp-pppoe/plugin.c @ 17829

Last change on this file since 17829 was 17829, checked in by chris, 20 months ago

hostapd/pppd/rp-pppoe/rt2860apd needed fixes for new qos

File size: 14.2 KB
Line 
1/***********************************************************************
2*
3* plugin.c
4*
5* pppd plugin for kernel-mode PPPoE on Linux
6*
7* Copyright (C) 2001 by Roaring Penguin Software Inc., Michal Ostrowski
8* and Jamal Hadi Salim.
9*
10* Much code and many ideas derived from pppoe plugin by Michal
11* Ostrowski and Jamal Hadi Salim, which carries this copyright:
12*
13* Copyright 2000 Michal Ostrowski <mostrows@styx.uwaterloo.ca>,
14*                Jamal Hadi Salim <hadi@cyberus.ca>
15* Borrows heavily from the PPPoATM plugin by Mitchell Blank Jr.,
16* which is based in part on work from Jens Axboe and Paul Mackerras.
17*
18* This program is free software; you can redistribute it and/or
19* modify it under the terms of the GNU General Public License
20* as published by the Free Software Foundation; either version
21* 2 of the License, or (at your option) any later version.
22***********************************************************************/
23
24static char const RCSID[] =
25"$Id: plugin.c,v 1.15 2006/05/29 23:29:16 paulus Exp $";
26
27#define _GNU_SOURCE 1
28#include "pppoe.h"
29
30#include "pppd/pppd.h"
31#include "pppd/fsm.h"
32#include "pppd/lcp.h"
33#include "pppd/ipcp.h"
34#include "pppd/ccp.h"
35#include "pppd/pathnames.h"
36
37#include <linux/types.h>
38#include <syslog.h>
39#include <sys/ioctl.h>
40#include <sys/types.h>
41#include <sys/socket.h>
42#include <sys/stat.h>
43#include <string.h>
44#include <stdlib.h>
45#include <errno.h>
46#include <unistd.h>
47#include <fcntl.h>
48#include <signal.h>
49#include <net/ethernet.h>
50#include <net/if_arp.h>
51#include "ppp_defs.h"
52#include "if_ppp.h"
53#include "if_pppox.h"
54
55#define _PATH_ETHOPT         _ROOT_PATH "/etc/ppp/options."
56
57char pppd_version[] = VERSION;
58
59/* From sys-linux.c in pppd -- MUST FIX THIS! */
60extern int new_style_driver;
61
62char *pppd_pppoe_service = NULL;
63static char *acName = NULL;
64static char *existingSession = NULL;
65static int printACNames = 0;
66
67static int PPPoEDevnameHook(char *cmd, char **argv, int doit);
68static option_t Options[] = {
69    { "device name", o_wild, (void *) &PPPoEDevnameHook,
70      "PPPoE device name",
71      OPT_DEVNAM | OPT_PRIVFIX | OPT_NOARG  | OPT_A2STRVAL | OPT_STATIC,
72      devnam},
73    { "rp_pppoe_service", o_string, &pppd_pppoe_service,
74      "Desired PPPoE service name" },
75    { "rp_pppoe_ac",      o_string, &acName,
76      "Desired PPPoE access concentrator name" },
77    { "rp_pppoe_sess",    o_string, &existingSession,
78      "Attach to existing session (sessid:macaddr)" },
79    { "rp_pppoe_verbose", o_int, &printACNames,
80      "Be verbose about discovered access concentrators"},
81    { NULL }
82};
83
84static PPPoEConnection *conn = NULL;
85
86/**********************************************************************
87 * %FUNCTION: PPPOEInitDevice
88 * %ARGUMENTS:
89 * None
90 * %RETURNS:
91 *
92 * %DESCRIPTION:
93 * Initializes PPPoE device.
94 ***********************************************************************/
95static int
96PPPOEInitDevice(void)
97{
98    conn = malloc(sizeof(PPPoEConnection));
99    if (!conn) {
100        fatal("Could not allocate memory for PPPoE session");
101    }
102    memset(conn, 0, sizeof(PPPoEConnection));
103    if (acName) {
104        SET_STRING(conn->acName, acName);
105    }
106    if (pppd_pppoe_service) {
107        SET_STRING(conn->serviceName, pppd_pppoe_service);
108    }
109    SET_STRING(conn->ifName, devnam);
110    conn->discoverySocket = -1;
111    conn->sessionSocket = -1;
112    conn->useHostUniq = 1;
113    conn->printACNames = printACNames;
114    return 1;
115}
116
117#ifdef HAVE_AQOS
118int stricmp(char *a,char *b)
119{
120int l1 = strlen(a);
121int l2 = strlen(b);
122if (l2>l1)
123    return -1;
124int i;
125int i2=0;
126for (i=0;i<l2;i++)
127    {
128    if (i2==strlen(b))
129        {
130        return -1;
131        break;
132        }
133    if (a[i]==' ')
134        continue;
135    if (b[i2]==' ')
136        {
137        i2++;
138        i--;
139        continue;
140        }
141    if (toupper(a[i])!=toupper(b[i2]))
142        return -1;
143    i2++;
144    }
145return 0;
146}
147extern void add_usermac( char *mac, int idx, char *upstream,
148                         char *downstream, char *lanstream );
149extern char *nvram_safe_get(const char *name);
150
151int addrule(char *mac, char *upstream, char *downstream)
152{
153    char *qos_mac = nvram_safe_get( "svqos_macs" );
154    int ret = 0;
155    if (strlen(qos_mac)>0)
156    {
157    char *newqos = malloc(strlen(qos_mac)*2);
158    memset(newqos,0,strlen(qos_mac)*2);
159    char level[32], level2[32], level3[32], data[32], type[32];
160    strcpy(level3, "0");
161        do
162    {
163        if( sscanf( qos_mac, "%31s %31s %31s %31s %31s |", data, level, level2 , type, level3) < 4 )
164            break;
165        if (!stricmp(data,mac) && !strcmp(level,upstream) && !strcmp(level2,downstream))
166            {
167            sprintf(newqos,"%s %s %s %s %s %s |",newqos,data,level,level2,type,level3);     
168            ret |=1;
169            }
170            else
171            {
172            if (!stricmp(data,mac))
173            {
174            ret |=2;
175            }
176            sprintf(newqos,"%s %s %s %s %s %s |",newqos,data,upstream,downstream,"pppd",level3);           
177//          sprintf(newqos,"%s %s %s %s %s |",newqos,data,level,level2,type);       
178            }
179    }
180    while( ( qos_mac = strpbrk( ++qos_mac, "|" ) ) && qos_mac++ );
181    nvram_set("svqos_macs",newqos);
182    free(newqos);
183    }else
184    {
185    char newqos[128];
186    sprintf(newqos,"%s %s %s %s %s |",mac,upstream,downstream,"pppd",level3);       
187    nvram_set("svqos_macs",newqos);   
188    }
189return ret;
190
191}
192#endif
193
194#ifndef MAC2STR
195#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
196#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
197#endif
198
199/**********************************************************************
200 * %FUNCTION: PPPOEConnectDevice
201 * %ARGUMENTS:
202 * None
203 * %RETURNS:
204 * Non-negative if all goes well; -1 otherwise
205 * %DESCRIPTION:
206 * Connects PPPoE device.
207 ***********************************************************************/
208static int
209PPPOEConnectDevice(void)
210{
211    struct sockaddr_pppox sp;
212    static int qosidx=500;
213
214    strlcpy(ppp_devnam, devnam, sizeof(ppp_devnam));
215    if (existingSession) {
216        unsigned int mac[ETH_ALEN];
217        int i, ses;
218        if (sscanf(existingSession, "%d:%x:%x:%x:%x:%x:%x",
219                   &ses, &mac[0], &mac[1], &mac[2],
220                   &mac[3], &mac[4], &mac[5]) != 7) {
221            fatal("Illegal value for rp_pppoe_sess option");
222        }
223        conn->session = htons(ses);
224        for (i=0; i<ETH_ALEN; i++) {
225            conn->peerEth[i] = (unsigned char) mac[i];
226        }
227    } else {
228        discovery(conn);
229        if (conn->discoveryState != STATE_SESSION) {
230            error("Unable to complete PPPoE Discovery");
231            return -1;
232        }
233    }
234
235    /* Set PPPoE session-number for further consumption */
236    ppp_session_number = ntohs(conn->session);
237
238    /* Make the session socket */
239    conn->sessionSocket = socket(AF_PPPOX, SOCK_STREAM, PX_PROTO_OE);
240    if (conn->sessionSocket < 0) {
241        fatal("Failed to create PPPoE socket: %m");
242    }
243    sp.sa_family = AF_PPPOX;
244    sp.sa_protocol = PX_PROTO_OE;
245    sp.sa_addr.pppoe.sid = conn->session;
246    memcpy(sp.sa_addr.pppoe.dev, conn->ifName, IFNAMSIZ);
247    memcpy(sp.sa_addr.pppoe.remote, conn->peerEth, ETH_ALEN);
248
249    /* Set remote_number for ServPoET */
250    sprintf(remote_number, "%02X:%02X:%02X:%02X:%02X:%02X",
251            (unsigned) conn->peerEth[0],
252            (unsigned) conn->peerEth[1],
253            (unsigned) conn->peerEth[2],
254            (unsigned) conn->peerEth[3],
255            (unsigned) conn->peerEth[4],
256            (unsigned) conn->peerEth[5]);
257
258    if (connect(conn->sessionSocket, (struct sockaddr *) &sp,
259                sizeof(struct sockaddr_pppox)) < 0) {
260        fatal("Failed to connect PPPoE socket: %d %m", errno);
261        return -1;
262    }
263#ifdef HAVE_AQOS
264    if (bandwidthup!=0 && bandwidthdown!=0)
265        {
266        char uplevel[64];
267        char downlevel[64];
268        char mac[64];
269        sprintf(mac, MACSTR, MAC2STR(conn->myEth));
270        sprintf(uplevel,"%d",bandwidthup/1000);
271        sprintf(downlevel,"%d",bandwidthdown/1000);
272        fprintf(stderr,"use bandwidth down value to %d\n",bandwidthdown);
273        fprintf(stderr,"use bandwidth up value to %d\n",bandwidthdown);
274        int ret = addrule(mac,uplevel,downlevel);
275                    if (!ret)
276                        {
277                        qosidx+=2;
278                        if (qosidx>500)
279                            qosidx=0;
280                        add_usermac(mac, qosidx, uplevel,downlevel,"0" );
281                        }else if (ret>1)
282                        {
283                        system("startstop_f wshaper");
284                        }           
285        }
286#endif
287    return conn->sessionSocket;
288}
289
290/*static void
291PPPOESendConfig(int mtu,
292                u_int32_t asyncmap,
293                int pcomp,
294                int accomp)
295{
296    int sock;
297    struct ifreq ifr;
298
299    if (mtu > MAX_PPPOE_MTU) {
300        warn("Couldn't increase MTU to %d", mtu);
301        mtu = MAX_PPPOE_MTU;
302    }
303    sock = socket(AF_INET, SOCK_DGRAM, 0);
304    if (sock < 0) {
305        error("Couldn't create IP socket: %m");
306        return;
307    }
308    strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
309//    info("set mtu rp-pppoe to %s (%d)\n",ifname,mtu);
310    ifr.ifr_mtu = mtu;
311    if (ioctl(sock, SIOCSIFMTU, &ifr) < 0) {
312        error("Couldn't set interface MTU to %d: %m", mtu);
313        return;
314    }
315    (void) close (sock);
316}
317*/
318static void
319PPPOERecvConfig(int mru,
320                u_int32_t asyncmap,
321                int pcomp,
322                int accomp)
323{
324#if 0 /* broken protocol, but no point harrassing the users I guess... */
325    if (mru > MAX_PPPOE_MTU)
326        warn("Couldn't increase MRU to %d", mru);
327#endif
328}
329
330/**********************************************************************
331 * %FUNCTION: PPPOEDisconnectDevice
332 * %ARGUMENTS:
333 * None
334 * %RETURNS:
335 * Nothing
336 * %DESCRIPTION:
337 * Disconnects PPPoE device
338 ***********************************************************************/
339static void
340PPPOEDisconnectDevice(void)
341{
342    struct sockaddr_pppox sp;
343
344    sp.sa_family = AF_PPPOX;
345    sp.sa_protocol = PX_PROTO_OE;
346    sp.sa_addr.pppoe.sid = 0;
347    memcpy(sp.sa_addr.pppoe.dev, conn->ifName, IFNAMSIZ);
348    memcpy(sp.sa_addr.pppoe.remote, conn->peerEth, ETH_ALEN);
349    if (connect(conn->sessionSocket, (struct sockaddr *) &sp,
350                sizeof(struct sockaddr_pppox)) < 0) {
351        fatal("Failed to disconnect PPPoE socket: %d %m", errno);
352        return;
353    }
354    close(conn->sessionSocket);
355    /* don't send PADT?? */
356    close(conn->discoverySocket);
357}
358
359static void
360PPPOEDeviceOptions(void)
361{
362    char buf[256];
363    snprintf(buf, 256, _PATH_ETHOPT "%s",devnam);
364    if(!options_from_file(buf, 0, 0, 1))
365        exit(EXIT_OPTION_ERROR);
366
367}
368
369struct channel pppoe_channel;
370
371/**********************************************************************
372 * %FUNCTION: PPPoEDevnameHook
373 * %ARGUMENTS:
374 * cmd -- the command (actually, the device name
375 * argv -- argument vector
376 * doit -- if non-zero, set device name.  Otherwise, just check if possible
377 * %RETURNS:
378 * 1 if we will handle this device; 0 otherwise.
379 * %DESCRIPTION:
380 * Checks if name is a valid interface name; if so, returns 1.  Also
381 * sets up devnam (string representation of device).
382 ***********************************************************************/
383static int
384PPPoEDevnameHook(char *cmd, char **argv, int doit)
385{
386    int r = 1;
387    int fd;
388    struct ifreq ifr;
389
390    /*
391     * Take any otherwise-unrecognized option as a possible device name,
392     * and test if it is the name of a network interface with a
393     * hardware address whose sa_family is ARPHRD_ETHER.
394     */
395    if (strlen(cmd) > 4 && !strncmp(cmd, "nic-", 4)) {
396        /* Strip off "nic-" */
397        cmd += 4;
398    }
399
400    /* Open a socket */
401    if ((fd = socket(PF_PACKET, SOCK_RAW, 0)) < 0) {
402        r = 0;
403    }
404
405    /* Try getting interface index */
406    if (r) {
407        strncpy(ifr.ifr_name, cmd, sizeof(ifr.ifr_name));
408        if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0) {
409            r = 0;
410        } else {
411            if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
412                r = 0;
413            } else {
414                if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
415                    if (doit)
416                        error("Interface %s not Ethernet", cmd);
417                    r = 0;
418                }
419            }
420        }
421    }
422
423    /* Close socket */
424    close(fd);
425    if (r && doit) {
426        strncpy(devnam, cmd, sizeof(devnam));
427        if (the_channel != &pppoe_channel) {
428
429            the_channel = &pppoe_channel;
430            modem = 0;
431
432            PPPOEInitDevice();
433        }
434        return 1;
435    }
436
437    return r;
438}
439
440/**********************************************************************
441 * %FUNCTION: plugin_init
442 * %ARGUMENTS:
443 * None
444 * %RETURNS:
445 * Nothing
446 * %DESCRIPTION:
447 * Initializes hooks for pppd plugin
448 ***********************************************************************/
449void
450plugin_init(void)
451{
452    if (!ppp_available() && !new_style_driver) {
453        fatal("Linux kernel does not support PPPoE -- are you running 2.4.x?");
454    }
455
456    add_options(Options);
457
458    info("RP-PPPoE plugin version %s compiled against pppd %s",
459         RP_VERSION, VERSION);
460}
461
462/**********************************************************************
463*%FUNCTION: fatalSys
464*%ARGUMENTS:
465* str -- error message
466*%RETURNS:
467* Nothing
468*%DESCRIPTION:
469* Prints a message plus the errno value to stderr and syslog and exits.
470***********************************************************************/
471void
472fatalSys(char const *str)
473{
474    char buf[1024];
475    int i = errno;
476    sprintf(buf, "%.256s: %.256s", str, strerror(i));
477    printErr(buf);
478    sprintf(buf, "RP-PPPoE: %.256s: %.256s", str, strerror(i));
479    sendPADT(conn, buf);
480    exit(1);
481}
482
483/**********************************************************************
484*%FUNCTION: rp_fatal
485*%ARGUMENTS:
486* str -- error message
487*%RETURNS:
488* Nothing
489*%DESCRIPTION:
490* Prints a message to stderr and syslog and exits.
491***********************************************************************/
492void
493rp_fatal(char const *str)
494{
495    char buf[1024];
496    printErr(str);
497    sprintf(buf, "RP-PPPoE: %.256s", str);
498    sendPADT(conn, buf);
499    exit(1);
500}
501/**********************************************************************
502*%FUNCTION: sysErr
503*%ARGUMENTS:
504* str -- error message
505*%RETURNS:
506* Nothing
507*%DESCRIPTION:
508* Prints a message plus the errno value to syslog.
509***********************************************************************/
510void
511sysErr(char const *str)
512{
513    rp_fatal(str);
514}
515
516void pppoe_check_options(void)
517{
518    lcp_allowoptions[0].neg_accompression = 0;
519    lcp_wantoptions[0].neg_accompression = 0;
520
521    lcp_allowoptions[0].neg_asyncmap = 0;
522    lcp_wantoptions[0].neg_asyncmap = 0;
523
524    lcp_allowoptions[0].neg_pcompression = 0;
525    lcp_wantoptions[0].neg_pcompression = 0;
526
527    if (lcp_allowoptions[0].mru > MAX_PPPOE_MTU)
528        lcp_allowoptions[0].mru = MAX_PPPOE_MTU;
529    if (lcp_wantoptions[0].mru > MAX_PPPOE_MTU)
530        lcp_wantoptions[0].mru = MAX_PPPOE_MTU;
531
532    ccp_allowoptions[0].deflate = 0;
533    ccp_wantoptions[0].deflate = 0;
534
535    ipcp_allowoptions[0].neg_vj = 0;
536    ipcp_wantoptions[0].neg_vj = 0;
537
538    ccp_allowoptions[0].bsd_compress = 0;
539    ccp_wantoptions[0].bsd_compress = 0;
540}
541
542struct channel pppoe_channel = {
543    options: Options,
544    process_extra_options: &PPPOEDeviceOptions,
545    check_options: pppoe_check_options,
546    connect: &PPPOEConnectDevice,
547    disconnect: &PPPOEDisconnectDevice,
548    establish_ppp: &generic_establish_ppp,
549    disestablish_ppp: &generic_disestablish_ppp,
550    send_config: NULL,
551    recv_config: &PPPOERecvConfig,
552    close: NULL,
553    cleanup: NULL
554};
Note: See TracBrowser for help on using the repository browser.