| #include <u.h> |
| #include <libc.h> |
| #include <ip.h> |
| #include "dat.h" |
| #include "protos.h" |
| |
| enum |
| { |
| OfferTimeout= 60, /* when an offer times out */ |
| MaxLease= 60*60, /* longest lease for dynamic binding */ |
| MinLease= 15*60, /* shortest lease for dynamic binding */ |
| StaticLease= 30*60, /* lease for static binding */ |
| |
| IPUDPHDRSIZE= 28, /* size of an IP plus UDP header */ |
| MINSUPPORTED= 576, /* biggest IP message the client must support */ |
| |
| /* lengths of some bootp fields */ |
| Maxhwlen= 16, |
| Maxfilelen= 128, |
| Maxoptlen= 312-4, |
| |
| /* bootp types */ |
| Bootrequest= 1, |
| Bootreply= 2, |
| |
| /* bootp flags */ |
| Fbroadcast= 1<<15 |
| }; |
| |
| typedef struct Hdr Hdr; |
| struct Hdr |
| { |
| uchar op; /* opcode */ |
| uchar htype; /* hardware type */ |
| uchar hlen; /* hardware address len */ |
| uchar hops; /* hops */ |
| uchar xid[4]; /* a random number */ |
| uchar secs[2]; /* elapsed since client started booting */ |
| uchar flags[2]; |
| uchar ciaddr[IPv4addrlen]; /* client IP address (client tells server) */ |
| uchar yiaddr[IPv4addrlen]; /* client IP address (server tells client) */ |
| uchar siaddr[IPv4addrlen]; /* server IP address */ |
| uchar giaddr[IPv4addrlen]; /* gateway IP address */ |
| uchar chaddr[Maxhwlen]; /* client hardware address */ |
| char sname[64]; /* server host name (optional) */ |
| char file[Maxfilelen]; /* boot file name */ |
| uchar optmagic[4]; |
| uchar optdata[Maxoptlen]; |
| }; |
| |
| enum |
| { |
| Oca, |
| Osa, |
| Ot |
| }; |
| |
| static Field p_fields[] = |
| { |
| {"ca", Fv4ip, Oca, "client IP addr", } , |
| {"sa", Fv4ip, Osa, "server IP addr", } , |
| {0} |
| }; |
| |
| #define plan9opt ((ulong)(('p'<<24) | ('9'<<16) | (' '<<8) | ' ')) |
| #define genericopt (0x63825363UL) |
| |
| static Mux p_mux[] = |
| { |
| {"dhcp", genericopt,}, |
| {"plan9bootp", plan9opt,}, |
| {"dump", 0,}, |
| {0} |
| }; |
| |
| static void |
| p_compile(Filter *f) |
| { |
| Mux *m; |
| |
| if(f->op == '='){ |
| compile_cmp(arp.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 = Ot; |
| return; |
| } |
| sysfatal("unknown bootp field: %s", f->s); |
| } |
| |
| static int |
| p_filter(Filter *f, Msg *m) |
| { |
| Hdr *h; |
| |
| h = (Hdr*)m->ps; |
| |
| if(m->pe < (uchar*)h->sname) |
| return 0; |
| m->ps = h->optdata; |
| |
| switch(f->subop){ |
| case Oca: |
| return NetL(h->ciaddr) == f->ulv || NetL(h->yiaddr) == f->ulv; |
| case Osa: |
| return NetL(h->siaddr) == f->ulv; |
| case Ot: |
| return NetL(h->optmagic) == f->ulv; |
| } |
| return 0; |
| } |
| |
| static char* |
| op(int i) |
| { |
| static char x[20]; |
| |
| switch(i){ |
| case Bootrequest: |
| return "Req"; |
| case Bootreply: |
| return "Rep"; |
| default: |
| sprint(x, "%d", i); |
| return x; |
| } |
| } |
| |
| |
| static int |
| p_seprint(Msg *m) |
| { |
| Hdr *h; |
| ulong x; |
| |
| h = (Hdr*)m->ps; |
| |
| if(m->pe < (uchar*)h->sname) |
| return -1; |
| |
| /* point past data */ |
| m->ps = h->optdata; |
| |
| /* next protocol */ |
| m->pr = nil; |
| if(m->pe >= (uchar*)h->optdata){ |
| x = NetL(h->optmagic); |
| demux(p_mux, x, x, m, &dump); |
| } |
| |
| m->p = seprint(m->p, m->e, "t=%s ht=%d hl=%d hp=%d xid=%ux sec=%d fl=%4.4ux ca=%V ya=%V sa=%V ga=%V cha=%E magic=%lux", |
| op(h->op), h->htype, h->hlen, h->hops, |
| NetL(h->xid), NetS(h->secs), NetS(h->flags), |
| h->ciaddr, h->yiaddr, h->siaddr, h->giaddr, h->chaddr, |
| (ulong)NetL(h->optmagic)); |
| if(m->pe > (uchar*)h->sname && *h->sname) |
| m->p = seprint(m->p, m->e, " snam=%s", h->sname); |
| if(m->pe > (uchar*)h->file && *h->file) |
| m->p = seprint(m->p, m->e, " file=%s", h->file); |
| return 0; |
| } |
| |
| Proto bootp = |
| { |
| "bootp", |
| p_compile, |
| p_filter, |
| p_seprint, |
| p_mux, |
| "%#.8lux", |
| p_fields, |
| defaultframer |
| }; |