Subversion Repositories planix.SVN

Rev

Blame | Last modification | View Log | RSS feed

#include <u.h>
#include <libc.h>
#include <ip.h>
#include <libsec.h>
#include "dat.h"
#include "protos.h"

/* PPP stuff */
enum {
        PPP_addr=       0xff,
        PPP_ctl=        0x3,
        PPP_period=     3*1000, /* period of retransmit process (in ms) */
};

/* PPP protocols */
enum {
        PPP_ip=         0x21,           /* internet */
        PPP_vjctcp=     0x2d,           /* compressing van jacobson tcp */
        PPP_vjutcp=     0x2f,           /* uncompressing van jacobson tcp */
        PPP_ml=         0x3d,           /* multi link */
        PPP_comp=       0xfd,           /* compressed packets */
        PPP_ipcp=       0x8021,         /* ip control */
        PPP_ccp=        0x80fd,         /* compression control */
        PPP_passwd=     0xc023,         /* passwd authentication */
        PPP_lcp=        0xc021,         /* link control */
        PPP_lqm=        0xc025,         /* link quality monitoring */
        PPP_chap=       0xc223,         /* challenge/response */
};

/* LCP protocol (and IPCP) */


typedef struct Lcppkt   Lcppkt;
struct Lcppkt
{
        uchar   code;
        uchar   id;
        uchar   len[2];
        uchar   data[1];
};

typedef struct Lcpopt   Lcpopt;
struct Lcpopt
{
        uchar   type;
        uchar   len;
        uchar   data[1];
};

enum
{
        /* LCP codes */
        Lconfreq=       1,
        Lconfack=       2,
        Lconfnak=       3,
        Lconfrej=       4,
        Ltermreq=       5,
        Ltermack=       6,
        Lcoderej=       7,
        Lprotorej=      8,
        Lechoreq=       9,
        Lechoack=       10,
        Ldiscard=       11,
        Lresetreq=      14,     /* for ccp only */
        Lresetack=      15,     /* for ccp only */

        /* Lcp configure options */
        Omtu=           1,
        Octlmap=        2,
        Oauth=          3,
        Oquality=       4,
        Omagic=         5,
        Opc=            7,
        Oac=            8,

        /* authentication protocols */
        APmd5=          5,
        APmschap=       128,

        /* Chap codes */
        Cchallenge=     1,
        Cresponse=      2,
        Csuccess=       3,
        Cfailure=       4,

        /* ipcp configure options */
        Oipaddrs=       1,
        Oipcompress=    2,
        Oipaddr=        3,
        Oipdns=         129,
        Oipwins=        130,
        Oipdns2=        131,
        Oipwins2=       132,
};

char *
lcpcode[] = {
        0,
        "confreq",
        "confack",
        "confnak",
        "confrej",
        "termreq",
        "termack",
        "coderej",
        "protorej",
        "echoreq",
        "echoack",
        "discard",
        "id",
        "timeremain",
        "resetreq",
        "resetack",
};

static Mux p_mux[] =
{
        {"ip",          PPP_ip, },
        {"ppp_vjctcp",  PPP_vjctcp, },
        {"ppp_vjutcp",  PPP_vjutcp, },
        {"ppp_ml",      PPP_ml, },
        {"ppp_comp",    PPP_comp, },
        {"ppp_ipcp",    PPP_ipcp, },
        {"ppp_ccp",     PPP_ccp, },
        {"ppp_passwd",  PPP_passwd, },
        {"ppp_lcp",     PPP_lcp, },
        {"ppp_lqm",     PPP_lqm, },
        {"ppp_chap",    PPP_chap, },
        {0},
};

enum
{
        OOproto,
};

static void
p_compile(Filter *f)
{
        Mux *m;

        for(m = p_mux; m->name != nil; m++)
                if(strcmp(f->s, m->name) == 0){
                        f->pr = m->pr;
                        f->ulv = m->val;
                        f->subop = OOproto;
                        return;
                }

        sysfatal("unknown ppp field or protocol: %s", f->s);
}

static int
p_filter(Filter *f, Msg *m)
{
        int proto;
        int len;

        if(f->subop != OOproto)
                return 0;

        len = m->pe - m->ps;
        if(len < 3)
                return -1;

        if(m->ps[0] == PPP_addr && m->ps[1] == PPP_ctl)
                m->ps += 2;

        proto = *m->ps++;
        if((proto&1) == 0)
                proto = (proto<<8) | *m->ps++;

        if(proto == f->ulv)
                return 1;

        return 0;
}

static int
p_seprint(Msg *m)
{
        int proto;
        int len;

        len = m->pe - m->ps;
        if(len < 3)
                return -1;

        if(m->ps[0] == PPP_addr && m->ps[1] == PPP_ctl)
                m->ps += 2;

        proto = *m->ps++;
        if((proto&1) == 0)
                proto = (proto<<8) | *m->ps++;
        
        m->p = seprint(m->p, m->e, "pr=%ud len=%d", proto, len);
        demux(p_mux, proto, proto, m, &dump);

        return 0;
}

static int
p_seprintchap(Msg *m)
{
        Lcppkt *lcp;
        char *p, *e;
        int len;

        if(m->pe-m->ps < 4)
                return -1;

        p = m->p;
        e = m->e;
        m->pr = nil;

        /* resize packet */
        lcp = (Lcppkt*)m->ps;
        len = NetS(lcp->len);
        if(m->ps+len < m->pe)
                m->pe = m->ps+len;
        else if(m->ps+len > m->pe)
                return -1;

        p = seprint(p, e, "id=%d code=%d", lcp->id, lcp->code);
        switch(lcp->code) {
        default:
                p = seprint(p, e, " data=%.*H", len>64?64:len, lcp->data);
                break;
        case 1:
        case 2:
                if(lcp->data[0] > len-4){
                        p = seprint(p, e, "%.*H", len-4, lcp->data);
                } else {
                        p = seprint(p, e, " %s=", lcp->code==1?"challenge ":"response ");
                        p = seprint(p, e, "%.*H", lcp->data[0], lcp->data+1);
                        p = seprint(p, e, " name=");
                        p = seprint(p, e, "%.*H", len-4-lcp->data[0]-1, lcp->data+lcp->data[0]+1);
                }
                break;
        case 3:
        case 4:
                if(len > 64)
                        len = 64;
                p = seprint(p, e, " %s=%.*H", lcp->code==3?"success ":"failure",
                                len>64?64:len, lcp->data);
                break;
        }
        m->p = seprint(p, e, " len=%d", len);
        return 0;
}

static char*
seprintlcpopt(char *p, char *e, void *a, int len)
{
        Lcpopt *o;
        int proto, x, period;
        uchar *cp, *ecp;

        cp = a;
        ecp = cp+len;

        for(; cp < ecp; cp += o->len){
                o = (Lcpopt*)cp;
                if(cp + o->len > ecp || o->len == 0){
                        p = seprint(p, e, " bad-opt-len=%d", o->len);
                        return p;
                }

                switch(o->type){
                default:
                        p = seprint(p, e, " (type=%d len=%d)", o->type, o->len);
                        break;
                case Omtu:
                        p = seprint(p, e, " mtu=%d", NetS(o->data));
                        break;
                case Octlmap:
                        p = seprint(p, e, " ctlmap=%ux", NetL(o->data));
                        break;
                case Oauth:
                        proto = NetS(o->data);
                        switch(proto) {
                        default:
                                p = seprint(p, e, " auth=%d", proto);
                                break;
                        case PPP_passwd:
                                p = seprint(p, e, " auth=passwd");
                                break;
                        case PPP_chap:
                                p = seprint(p, e, " (auth=chap data=%2.2ux)", o->data[2]);
                                break;
                        }
                        break;
                case Oquality:
                        proto = NetS(o->data);
                        switch(proto) {
                        default:
                                p = seprint(p, e, " qproto=%d", proto);
                                break;
                        case PPP_lqm:
                                x = NetL(o->data+2)*10;
                                period = (x+(PPP_period-1))/PPP_period;
                                p = seprint(p, e, " (qproto=lqm period=%d)", period);
                                break;
                        }
                case Omagic:
                        p = seprint(p, e, " magic=%ux", NetL(o->data));
                        break;
                case Opc:
                        p = seprint(p, e, " protocol-compress");
                        break;
                case Oac:
                        p = seprint(p, e, " addr-compress");
                        break;
                }
        }
        return p;
}


static int
p_seprintlcp(Msg *m)
{
        Lcppkt *lcp;
        char *p, *e;
        int len;

        if(m->pe-m->ps < 4)
                return -1;

        p = m->p;
        e = m->e;
        m->pr = nil;

        lcp = (Lcppkt*)m->ps;
        len = NetS(lcp->len);
        if(m->ps+len < m->pe)
                m->pe = m->ps+len;
        else if(m->ps+len > m->pe)
                return -1;

        p = seprint(p, e, "id=%d code=%d", lcp->id, lcp->code);
        switch(lcp->code) {
        default:
                p = seprint(p, e, " data=%.*H", len>64?64:len, lcp->data);
                break;
        case Lconfreq:
        case Lconfack:
        case Lconfnak:
        case Lconfrej:
                p = seprint(p, e, "=%s", lcpcode[lcp->code]);
                p = seprintlcpopt(p, e, lcp->data, len-4);
                break;
        case Ltermreq:
        case Ltermack:
        case Lcoderej:
        case Lprotorej:
        case Lechoreq:
        case Lechoack:
        case Ldiscard:
                p = seprint(p, e, "=%s", lcpcode[lcp->code]);
                break;
        }
        m->p = seprint(p, e, " len=%d", len);
        return 0;
}

static char*
seprintipcpopt(char *p, char *e, void *a, int len)
{
        Lcpopt *o;
        uchar *cp, *ecp;

        cp = a;
        ecp = cp+len;

        for(; cp < ecp; cp += o->len){
                o = (Lcpopt*)cp;
                if(cp + o->len > ecp){
                        p = seprint(p, e, " bad opt len %ux", o->type);
                        return p;
                }

                switch(o->type){
                default:
                        p = seprint(p, e, " (type=%d len=%d)", o->type, o->len);
                        break;
                case Oipaddrs:  
                        p = seprint(p, e, " ipaddrs(deprecated)");
                        break;
                case Oipcompress:
                        p = seprint(p, e, " ipcompress");
                        break;
                case Oipaddr:   
                        p = seprint(p, e, " ipaddr=%V", o->data);
                        break;
                case Oipdns:    
                        p = seprint(p, e, " dnsaddr=%V", o->data);
                        break;
                case Oipwins:   
                        p = seprint(p, e, " winsaddr=%V", o->data);
                        break;
                case Oipdns2:   
                        p = seprint(p, e, " dns2addr=%V", o->data);
                        break;
                case Oipwins2:  
                        p = seprint(p, e, " wins2addr=%V", o->data);
                        break;
                }
        }
        return p;
}

static int
p_seprintipcp(Msg *m)
{
        Lcppkt *lcp;
        char *p, *e;
        int len;

        if(m->pe-m->ps < 4)
                return -1;

        p = m->p;
        e = m->e;
        m->pr = nil;

        lcp = (Lcppkt*)m->ps;
        len = NetS(lcp->len);
        if(m->ps+len < m->pe)
                m->pe = m->ps+len;
        else if(m->ps+len > m->pe)
                return -1;
                
        p = seprint(p, e, "id=%d code=%d", lcp->id, lcp->code);
        switch(lcp->code) {
        default:
                p = seprint(p, e, " data=%.*H", len>64?64:len, lcp->data);
                break;
        case Lconfreq:
        case Lconfack:
        case Lconfnak:
        case Lconfrej:
                p = seprint(p, e, "=%s", lcpcode[lcp->code]);
                p = seprintipcpopt(p, e, lcp->data, len-4);
                break;
        case Ltermreq:
        case Ltermack:
                p = seprint(p, e, "=%s", lcpcode[lcp->code]);
                break;
        }
        m->p = seprint(p, e, " len=%d", len);
        return 0;
}

static char*
seprintccpopt(char *p, char *e, void *a, int len)
{
        Lcpopt *o;
        uchar *cp, *ecp;

        cp = a;
        ecp = cp+len;

        for(; cp < ecp; cp += o->len){
                o = (Lcpopt*)cp;
                if(cp + o->len > ecp){
                        p = seprint(p, e, " bad opt len %ux", o->type);
                        return p;
                }
                
                switch(o->type){
                default:
                        p = seprint(p, e, " type=%d ", o->type);
                        break;
                case 0:
                        p = seprint(p, e, " OUI=(%d %.2ux%.2ux%.2ux) ", o->type, 
                                o->data[0], o->data[1], o->data[2]);
                        break;
                case 17:
                        p = seprint(p, e, " Stac-LZS");
                        break;
                case 18:
                        p = seprint(p, e, " Microsoft-PPC=%ux", NetL(o->data));
                        break;
                }
        }
        return p;
}

static int
p_seprintccp(Msg *m)
{
        Lcppkt *lcp;
        char *p, *e;
        int len;

        if(m->pe-m->ps < 4)
                return -1;

        p = m->p;
        e = m->e;
        m->pr = nil;

        lcp = (Lcppkt*)m->ps;
        len = NetS(lcp->len);
        if(m->ps+len < m->pe)
                m->pe = m->ps+len;
        else if(m->ps+len > m->pe)
                return -1;
                
        p = seprint(p, e, "id=%d code=%d", lcp->id, lcp->code);
        switch(lcp->code) {
        default:
                p = seprint(p, e, " data=%.*H", len>64?64:len, lcp->data);
                break;
        case Lconfreq:
        case Lconfack:
        case Lconfnak:
        case Lconfrej:
                p = seprint(p, e, "=%s", lcpcode[lcp->code]);
                p = seprintccpopt(p, e, lcp->data, len-4);
                break;
        case Ltermreq:
        case Ltermack:
        case Lresetreq:
        case Lresetack:
                p = seprint(p, e, "=%s", lcpcode[lcp->code]);
                break;
        }
        m->p = seprint(p, e, " len=%d", len);
        
        return 0;
}

static int
p_seprintcomp(Msg *m)
{
        char compflag[5];
        ushort x;
        int i;
        int len;

        len = m->pe-m->ps;
        if(len < 2)
                return -1;

        x = NetS(m->ps);
        m->ps += 2;
        i = 0;
        if(x & (1<<15))
                compflag[i++] = 'r';
        if(x & (1<<14))
                compflag[i++] = 'f';
        if(x & (1<<13))
                compflag[i++] = 'c';
        if(x & (1<<12))
                compflag[i++] = 'e';
        compflag[i] = 0;
        m->p = seprint(m->p, m->e, "flag=%s count=%.3ux", compflag, x&0xfff);
        m->p = seprint(m->p, m->e, " data=%.*H", len>64?64:len, m->ps);
        m->pr = nil;
        return 0;
}

Proto ppp =
{
        "ppp",
        p_compile,
        p_filter,
        p_seprint,
        p_mux,
        "%#.4lux",
        nil,
        defaultframer,
};

Proto ppp_ipcp =
{
        "ppp_ipcp",
        p_compile,
        p_filter,
        p_seprintipcp,
        nil,
        nil,
        nil,
        defaultframer,
};

Proto ppp_lcp =
{
        "ppp_lcp",
        p_compile,
        p_filter,
        p_seprintlcp,
        nil,
        nil,
        nil,
        defaultframer,
};

Proto ppp_ccp =
{
        "ppp_ccp",
        p_compile,
        p_filter,
        p_seprintccp,
        nil,
        nil,
        nil,
        defaultframer,
};

Proto ppp_chap =
{
        "ppp_chap",
        p_compile,
        p_filter,
        p_seprintchap,
        nil,
        nil,
        nil,
        defaultframer,
};

Proto ppp_comp =
{
        "ppp_comp",
        p_compile,
        p_filter,
        p_seprintcomp,
        nil,
        nil,
        nil,
        defaultframer,
};