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 <libsec.h>
#include "dat.h"
#include "protos.h"


/*
 *  OSPF packets
 */
typedef struct Ospfpkt  Ospfpkt;
struct Ospfpkt
{
        uchar   version;
        uchar   type;
        uchar   length[2];
        uchar   router[4];
        uchar   area[4];
        uchar   sum[2];
        uchar   autype[2];
        uchar   auth[8];
        uchar   data[1];
};
#define OSPF_HDRSIZE    24      

enum
{
        OSPFhello=      1,
        OSPFdd=         2,
        OSPFlsrequest=  3,
        OSPFlsupdate=   4,
        OSPFlsack=      5,
};


char *ospftype[] = {
        [OSPFhello]     "hello",
        [OSPFdd]        "data definition",
        [OSPFlsrequest] "link state request",
        [OSPFlsupdate]  "link state update",
        [OSPFlsack]     "link state ack",
};

char*
ospfpkttype(int x)
{
        static char type[16];

        if(x > 0 && x <= OSPFlsack)
                return ospftype[x];
        sprint(type, "type %d", x);
        return type;
}

char*
ospfauth(Ospfpkt *ospf)
{
        static char auth[100];

        switch(ospf->type){
        case 0:
                return "no authentication";
        case 1:
                sprint(auth, "password(%8.8ux %8.8ux)", NetL(ospf->auth),       
                        NetL(ospf->auth+4));
                break;
        case 2:
                sprint(auth, "crypto(plen %d id %d dlen %d)", NetS(ospf->auth), 
                        ospf->auth[2], ospf->auth[3]);
                break;
        default:
                sprint(auth, "auth%d(%8.8ux %8.8ux)", NetS(ospf->autype), NetL(ospf->auth),     
                        NetL(ospf->auth+4));
        }
        return auth;
}

typedef struct Ospfhello        Ospfhello;
struct Ospfhello
{
        uchar   mask[4];
        uchar   interval[2];
        uchar   options;
        uchar   pri;
        uchar   deadint[4];
        uchar   designated[4];
        uchar   bdesignated[4];
        uchar   neighbor[1];
};

char*
seprintospfhello(char *p, char *e, void *a)
{
        Ospfhello *h = a;

        return seprint(p, e, "%s(mask %V interval %d opt %ux pri %ux deadt %d designated %V bdesignated %V)",
                ospftype[OSPFhello],
                h->mask, NetS(h->interval), h->options, h->pri,
                NetL(h->deadint), h->designated, h->bdesignated);
}

enum
{
        LSARouter=      1,
        LSANetwork=     2,
        LSASummN=       3,
        LSASummR=       4,
        LSAASext=       5
};


char *lsatype[] = {
        [LSARouter]     "Router LSA",
        [LSANetwork]    "Network LSA",
        [LSASummN]      "Summary LSA (Network)",
        [LSASummR]      "Summary LSA (Router)",
        [LSAASext]      "LSA AS external",
};

char*
lsapkttype(int x)
{
        static char type[16];

        if(x > 0 && x <= LSAASext)
                return lsatype[x];
        sprint(type, "type %d", x);
        return type;
}

/* OSPF Link State Advertisement Header */
/* rfc2178 section 12.1 */
/* data of Ospfpkt point to a 4-uchar value that is the # of LSAs */
struct OspfLSAhdr {
        uchar   lsage[2];
        uchar   options;        /* 0x2=stub area, 0x1=TOS routing capable */

        uchar   lstype; /* 1=Router-LSAs
                                                 * 2=Network-LSAs
                                                 * 3=Summary-LSAs (to network)
                                                 * 4=Summary-LSAs (to AS boundary routers)
                                                 * 5=AS-External-LSAs
                                                 */
        uchar   lsid[4];
        uchar   advtrt[4];

        uchar   lsseqno[4];
        uchar   lscksum[2];
        uchar   lsalen[2];      /* includes the 20 byte lsa header */
};

struct Ospfrt {
        uchar   linkid[4];
        uchar   linkdata[4];
        uchar   typ;
        uchar   numtos;
        uchar   metric[2];
        
};

struct OspfrtLSA {
        struct OspfLSAhdr       hdr;
        uchar                   netmask[4];
};

struct OspfntLSA {
        struct OspfLSAhdr       hdr;
        uchar                   netmask[4];
        uchar                   attrt[4];
};

/* Summary Link State Advertisement info */
struct Ospfsumm {
        uchar   flag;   /* always zero */
        uchar   metric[3];
};

struct OspfsummLSA {
        struct OspfLSAhdr       hdr;
        uchar                   netmask[4];
        struct Ospfsumm         lsa;
};

/* AS external Link State Advertisement info */
struct OspfASext {
        uchar   flag;   /* external */
        uchar   metric[3];
        uchar   fwdaddr[4];
        uchar   exrttag[4];
};

struct OspfASextLSA {
        struct OspfLSAhdr       hdr;
        uchar                   netmask[4];
        struct OspfASext        lsa;
};

/* OSPF Link State Update Packet */
struct OspfLSupdpkt {
        uchar   lsacnt[4];
        union {
                uchar                   hdr[1];
                struct OspfrtLSA        rt[1];
                struct OspfntLSA        nt[1];
                struct OspfsummLSA      sum[1];
                struct OspfASextLSA     as[1];
        };
};

char*
seprintospflsaheader(char *p, char *e, struct OspfLSAhdr *h)
{
        return seprint(p, e, "age %d opt %ux type %ux lsid %V adv_rt %V seqno %ux c %4.4ux l %d",
                NetS(h->lsage), h->options&0xff, h->lstype,
                h->lsid, h->advtrt, NetL(h->lsseqno), NetS(h->lscksum),
                NetS(h->lsalen));
}

/* OSPF Database Description Packet */
struct OspfDDpkt {
        uchar   intMTU[2];
        uchar   options;
        uchar   bits;
        uchar   DDseqno[4];
        struct OspfLSAhdr       hdr[1];         /* LSA headers... */
};

char*
seprintospfdatadesc(char *p, char *e, void *a, int len)
{
        int nlsa, i;
        struct OspfDDpkt *g;

        g = (struct OspfDDpkt *)a;
        nlsa = len/sizeof(struct OspfLSAhdr);
        for (i=0; i<nlsa; i++) {
                p = seprint(p, e, "lsa%d(", i);
                p = seprintospflsaheader(p, e, &(g->hdr[i]));
                p = seprint(p, e, ")");
        }
        return seprint(p, e, ")");
}

char*
seprintospflsupdate(char *p, char *e, void *a, int len)
{
        int nlsa, i;
        struct OspfLSupdpkt *g;
        struct OspfLSAhdr *h;

        g = (struct OspfLSupdpkt *)a;
        nlsa = NetL(g->lsacnt);
        h = (struct OspfLSAhdr *)(g->hdr);
        p = seprint(p, e, "%d-%s(", nlsa, ospfpkttype(OSPFlsupdate));

        switch(h->lstype) {
        case LSARouter:
                {
/*                      struct OspfrtLSA *h;
 */
                }
                break;
        case LSANetwork:
                {
                        struct OspfntLSA *h;

                        for (i=0; i<nlsa; i++) {
                                h = &(g->nt[i]);
                                p = seprint(p, e, "lsa%d(", i);
                                p = seprintospflsaheader(p, e, &(h->hdr));
                                p = seprint(p, e, " mask %V attrt %V)",
                                        h->netmask, h->attrt);
                        }
                }
                break;
        case LSASummN:
        case LSASummR:
                {
                        struct OspfsummLSA *h;

                        for (i=0; i<nlsa; i++) {
                                h = &(g->sum[i]);
                                p = seprint(p, e, "lsa%d(", i);
                                p = seprintospflsaheader(p, e, &(h->hdr));
                                p = seprint(p, e, " mask %V met %d)",
                                        h->netmask, Net3(h->lsa.metric));
                        }
                }
                break;
        case LSAASext:
                {
                        struct OspfASextLSA *h;

                        for (i=0; i<nlsa; i++) {
                                h = &(g->as[i]);
                                p = seprint(p, e, " lsa%d(", i);
                                p = seprintospflsaheader(p, e, &(h->hdr));
                                p = seprint(p, e, " mask %V extflg %1.1ux met %d fwdaddr %V extrtflg %ux)",
                                        h->netmask, h->lsa.flag, Net3(h->lsa.metric),
                                        h->lsa.fwdaddr, NetL(h->lsa.exrttag));
                        }
                }
                break;
        default:
                p = seprint(p, e, "Not an LS update, lstype %d ", h->lstype);
                p = seprint(p, e, " %.*H", len>64?64:len, a);
                break;
        }
        return seprint(p, e, ")");
}

char*
seprintospflsack(char *p, char *e, void *a, int len)
{
        int nlsa, i;
        struct OspfLSAhdr *h;

        h = (struct OspfLSAhdr *)a;
        nlsa = len/sizeof(struct OspfLSAhdr);
        p = seprint(p, e, "%d-%s(", nlsa, ospfpkttype(OSPFlsack));
        for (i=0; i<nlsa; i++) {
                p = seprint(p, e, " lsa%d(", i);
                p = seprintospflsaheader(p, e, &(h[i]));
                p = seprint(p, e, ")");
        }
        return seprint(p, e, ")");
}

int
p_seprint(Msg *m)
{
        Ospfpkt *ospf;
        int len, x;
        char *p, *e;

        len = m->pe - m->ps;
        if(len < OSPF_HDRSIZE)
                return -1;
        p = m->p;
        e = m->e;

        /* adjust packet size */
        ospf = (Ospfpkt*)m->ps;
        x = NetS(ospf->length);
        if(x < len)
                return -1;
        x -= OSPF_HDRSIZE;

        p = seprint(p, e, "ver=%d type=%d len=%d r=%V a=%V c=%4.4ux %s ",
                ospf->version, ospf->type, x, 
                ospf->router, ospf->area, NetS(ospf->sum),
                ospfauth(ospf));

        switch (ospf->type) {
        case OSPFhello:
                p = seprintospfhello(p, e, ospf->data);
                break;
        case OSPFdd:
                p = seprintospfdatadesc(p, e, ospf->data, x);
                break;
        case OSPFlsrequest:
                p = seprint(p, e, " %s->", ospfpkttype(ospf->type));
                goto Default;
        case OSPFlsupdate:
                p = seprintospflsupdate(p, e, ospf->data, x);
                break;
        case OSPFlsack:
                p = seprintospflsack(p, e, ospf->data, x);
                break;
        default:
Default:
                p = seprint(p, e, " data=%.*H", x>64?64:x, ospf->data);
        }
        m->p = p;
        m->pr = nil;
        return 0;
}

Proto ospf =
{
        "ospf",
        nil,
        nil,
        p_seprint,
        nil,
        nil,
        nil,
        defaultframer,
};