blob: bb4cd893b4dde6b07be03ff7db1bae0ee080c58e [file] [log] [blame]
#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
};