Subversion Repositories planix.SVN

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

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

typedef struct Hdr      Hdr;
struct Hdr
{
        uchar   sport[2];       /* Source port */
        uchar   dport[2];       /* Destination port */
        uchar   len[2];         /* data length */
        uchar   cksum[2];       /* Checksum */
};

enum
{
        UDPLEN= 8,
};

enum
{
        Os,
        Od,
        Osd,
        Osetport,
};

static Field p_fields[] = 
{
        {"s",           Fnum,   Os,     "source port",  } ,
        {"d",           Fnum,   Od,     "dest port",    } ,
        {"a",           Fnum,   Osd,    "source/dest port",     } ,
        {"sd",          Fnum,   Osd,    "source/dest port",     } ,
        {0}
};

#define ANYPORT ~0UL

static Mux p_mux[] =
{
        {"dns", 53, },
        {"bootp",       67, },
        {"ninep",       6346, },        /* tvs */
        {"rtp",         ANYPORT, },
        {"rtcp",        ANYPORT, },
        {0},
};

/* default next protocol, can be changed by p_filter, reset by p_compile */
static Proto    *defproto = &dump;

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

        if(f->op == '='){
                compile_cmp(udp.name, f, p_fields);
                return;
        }
        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 = Osd;
                        return;
                }

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

static int
p_filter(Filter *f, Msg *m)
{
        Hdr *h;

        if(m->pe - m->ps < UDPLEN)
                return 0;

        h = (Hdr*)m->ps;
        m->ps += UDPLEN;

        switch(f->subop){
        case Os:
                return NetS(h->sport) == f->ulv;
        case Od:
                return NetS(h->dport) == f->ulv;
        case Osd:
                if(f->ulv == ANYPORT){
                        defproto = f->pr;
                        return 1;
                }
                return NetS(h->sport) == f->ulv || NetS(h->dport) == f->ulv;
        }
        return 0;
}

static int
p_seprint(Msg *m)
{
        Hdr *h;
        int dport, sport;


        if(m->pe - m->ps < UDPLEN)
                return -1;
        h = (Hdr*)m->ps;
        m->ps += UDPLEN;

        /* next protocol */
        sport = NetS(h->sport);
        dport = NetS(h->dport);
        demux(p_mux, sport, dport, m, defproto);
        defproto = &dump;

        m->p = seprint(m->p, m->e, "s=%d d=%d ck=%4.4ux ln=%4d",
                        NetS(h->sport), dport,
                        NetS(h->cksum), NetS(h->len));
        return 0;
}

Proto udp =
{
        "udp",
        p_compile,
        p_filter,
        p_seprint,
        p_mux,
        "%lud",
        p_fields,
        defaultframer,
};