1 #include <u.h>
2 #include <libc.h>
3 #include <ip.h>
4 #include "dat.h"
5 #include "protos.h"
6
7 enum
8 {
9 OfferTimeout= 60, /* when an offer times out */
10 MaxLease= 60*60, /* longest lease for dynamic binding */
11 MinLease= 15*60, /* shortest lease for dynamic binding */
12 StaticLease= 30*60, /* lease for static binding */
13
14 IPUDPHDRSIZE= 28, /* size of an IP plus UDP header */
15 MINSUPPORTED= 576, /* biggest IP message the client must support */
16
17 /* lengths of some bootp fields */
18 Maxhwlen= 16,
19 Maxfilelen= 128,
20 Maxoptlen= 312-4,
21
22 /* bootp types */
23 Bootrequest= 1,
24 Bootreply= 2,
25
26 /* bootp flags */
27 Fbroadcast= 1<<15
28 };
29
30 typedef struct Hdr Hdr;
31 struct Hdr
32 {
33 uchar op; /* opcode */
34 uchar htype; /* hardware type */
35 uchar hlen; /* hardware address len */
36 uchar hops; /* hops */
37 uchar xid[4]; /* a random number */
38 uchar secs[2]; /* elapsed since client started booting */
39 uchar flags[2];
40 uchar ciaddr[IPv4addrlen]; /* client IP address (client tells server) */
41 uchar yiaddr[IPv4addrlen]; /* client IP address (server tells client) */
42 uchar siaddr[IPv4addrlen]; /* server IP address */
43 uchar giaddr[IPv4addrlen]; /* gateway IP address */
44 uchar chaddr[Maxhwlen]; /* client hardware address */
45 char sname[64]; /* server host name (optional) */
46 char file[Maxfilelen]; /* boot file name */
47 uchar optmagic[4];
48 uchar optdata[Maxoptlen];
49 };
50
51 enum
52 {
53 Oca,
54 Osa,
55 Ot
56 };
57
58 static Field p_fields[] =
59 {
60 {"ca", Fv4ip, Oca, "client IP addr", } ,
61 {"sa", Fv4ip, Osa, "server IP addr", } ,
62 {0}
63 };
64
65 #define plan9opt ((ulong)(('p'<<24) | ('9'<<16) | (' '<<8) | ' '))
66 #define genericopt (0x63825363UL)
67
68 static Mux p_mux[] =
69 {
70 {"dhcp", genericopt,},
71 {"plan9bootp", plan9opt,},
72 {"dump", 0,},
73 {0}
74 };
75
76 static void
p_compile(Filter * f)77 p_compile(Filter *f)
78 {
79 Mux *m;
80
81 if(f->op == '='){
82 compile_cmp(arp.name, f, p_fields);
83 return;
84 }
85 for(m = p_mux; m->name != nil; m++)
86 if(strcmp(f->s, m->name) == 0){
87 f->pr = m->pr;
88 f->ulv = m->val;
89 f->subop = Ot;
90 return;
91 }
92 sysfatal("unknown bootp field: %s", f->s);
93 }
94
95 static int
p_filter(Filter * f,Msg * m)96 p_filter(Filter *f, Msg *m)
97 {
98 Hdr *h;
99
100 h = (Hdr*)m->ps;
101
102 if(m->pe < (uchar*)h->sname)
103 return 0;
104 m->ps = h->optdata;
105
106 switch(f->subop){
107 case Oca:
108 return NetL(h->ciaddr) == f->ulv || NetL(h->yiaddr) == f->ulv;
109 case Osa:
110 return NetL(h->siaddr) == f->ulv;
111 case Ot:
112 return NetL(h->optmagic) == f->ulv;
113 }
114 return 0;
115 }
116
117 static char*
op(int i)118 op(int i)
119 {
120 static char x[20];
121
122 switch(i){
123 case Bootrequest:
124 return "Req";
125 case Bootreply:
126 return "Rep";
127 default:
128 sprint(x, "%d", i);
129 return x;
130 }
131 }
132
133
134 static int
p_seprint(Msg * m)135 p_seprint(Msg *m)
136 {
137 Hdr *h;
138 ulong x;
139
140 h = (Hdr*)m->ps;
141
142 if(m->pe < (uchar*)h->sname)
143 return -1;
144
145 /* point past data */
146 m->ps = h->optdata;
147
148 /* next protocol */
149 m->pr = nil;
150 if(m->pe >= (uchar*)h->optdata){
151 x = NetL(h->optmagic);
152 demux(p_mux, x, x, m, &dump);
153 }
154
155 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",
156 op(h->op), h->htype, h->hlen, h->hops,
157 NetL(h->xid), NetS(h->secs), NetS(h->flags),
158 h->ciaddr, h->yiaddr, h->siaddr, h->giaddr, h->chaddr,
159 (ulong)NetL(h->optmagic));
160 if(m->pe > (uchar*)h->sname && *h->sname)
161 m->p = seprint(m->p, m->e, " snam=%s", h->sname);
162 if(m->pe > (uchar*)h->file && *h->file)
163 m->p = seprint(m->p, m->e, " file=%s", h->file);
164 return 0;
165 }
166
167 Proto bootp =
168 {
169 "bootp",
170 p_compile,
171 p_filter,
172 p_seprint,
173 p_mux,
174 "%#.8lux",
175 p_fields,
176 defaultframer
177 };
178