1 #include <u.h>
2 #include "fns.h"
3
4 enum {
5 Tftp_READ = 1,
6 Tftp_WRITE = 2,
7 Tftp_DATA = 3,
8 Tftp_ACK = 4,
9 Tftp_ERROR = 5,
10 Tftp_OACK = 6,
11
12 TftpPort = 69,
13
14 Segsize = 512,
15 Maxpath = 64,
16 };
17
18 typedef uchar IP4[4];
19
20 typedef struct Tftp Tftp;
21 typedef struct Dhcp Dhcp;
22
23 struct Tftp
24 {
25 IP4 sip;
26 IP4 dip;
27 IP4 gip;
28
29 int sport;
30 int dport;
31
32 char *rp;
33 char *ep;
34
35 int seq;
36 int eof;
37
38 char pkt[2+2+Segsize];
39 char nul;
40 };
41
42 struct Dhcp
43 {
44 uchar opcode;
45 uchar hardware;
46 uchar hardlen;
47 uchar gatehops;
48 uchar ident[4];
49 uchar seconds[2];
50 uchar flags[2];
51 uchar cip[4];
52 uchar yip[4];
53 uchar sip[4];
54 uchar gip[4];
55 uchar mac[16];
56 char sname[64];
57 char bootfile[128];
58 };
59
60 int pxeinit(void);
61 int pxecall(int op, void *buf);
62
63 static void*
unfar(ulong seg,ulong off)64 unfar(ulong seg, ulong off)
65 {
66 return (void*)((off & 0xFFFF) + (seg & 0xFFFF)*16);
67 }
68
69 static void
puts(void * x,ushort v)70 puts(void *x, ushort v)
71 {
72 uchar *p = x;
73
74 p[1] = (v>>8) & 0xFF;
75 p[0] = v & 0xFF;
76 }
77
78 static ushort
gets(void * x)79 gets(void *x)
80 {
81 uchar *p = x;
82
83 return p[1]<<8 | p[0];
84 }
85
86 static void
hnputs(void * x,ushort v)87 hnputs(void *x, ushort v)
88 {
89 uchar *p = x;
90
91 p[0] = (v>>8) & 0xFF;
92 p[1] = v & 0xFF;
93 }
94
95 static ushort
nhgets(void * x)96 nhgets(void *x)
97 {
98 uchar *p = x;
99
100 return p[0]<<8 | p[1];
101 }
102
103 static void
moveip(IP4 d,IP4 s)104 moveip(IP4 d, IP4 s)
105 {
106 memmove(d, s, sizeof(d));
107 }
108
109 void
unload(void)110 unload(void)
111 {
112 struct {
113 uchar status[2];
114 uchar junk[10];
115 } buf;
116 static uchar shutdown[] = { 0x05, 0x070, 0x02, 0 };
117 uchar *o;
118
119 for(o = shutdown; *o; o++){
120 memset(&buf, 0, sizeof(buf));
121 if(pxecall(*o, &buf))
122 break;
123 }
124 }
125
126 static int
getip(IP4 yip,IP4 sip,IP4 gip,char mac[16])127 getip(IP4 yip, IP4 sip, IP4 gip, char mac[16])
128 {
129 struct {
130 uchar status[2];
131 uchar pkttype[2];
132 uchar bufsize[2];
133 uchar off[2];
134 uchar seg[2];
135 uchar lim[2];
136 } buf;
137 int i, r;
138 Dhcp *p;
139
140 memset(&buf, 0, sizeof(buf));
141 puts(buf.pkttype, 3);
142
143 if(r = pxecall(0x71, &buf))
144 return -r;
145 if((p = unfar(gets(buf.seg), gets(buf.off))) == 0)
146 return -1;
147 moveip(yip, p->yip);
148 moveip(sip, p->sip);
149 moveip(gip, p->gip);
150 mac[12] = 0;
151 for(i=0; i<6; i++){
152 mac[i*2] = hex[p->mac[i]>>4];
153 mac[i*2+1] = hex[p->mac[i]&15];
154 }
155 return 0;
156 }
157
158 static int
udpopen(IP4 sip)159 udpopen(IP4 sip)
160 {
161 struct {
162 uchar status[2];
163 uchar sip[4];
164 } buf;
165
166 puts(buf.status, 0);
167 moveip(buf.sip, sip);
168 return pxecall(0x30, &buf);
169 }
170
171 static int
udpclose(void)172 udpclose(void)
173 {
174 uchar status[2];
175 puts(status, 0);
176 return pxecall(0x31, status);
177 }
178
179 static int
udpread(IP4 sip,IP4 dip,int * sport,int dport,int * len,void * data)180 udpread(IP4 sip, IP4 dip, int *sport, int dport, int *len, void *data)
181 {
182 struct {
183 uchar status[2];
184 uchar sip[4];
185 uchar dip[4];
186 uchar sport[2];
187 uchar dport[2];
188 uchar len[2];
189 uchar off[2];
190 uchar seg[2];
191 } buf;
192 int r;
193
194 puts(buf.status, 0);
195 moveip(buf.sip, sip);
196 moveip(buf.dip, dip);
197 hnputs(buf.sport, *sport);
198 hnputs(buf.dport, dport);
199 puts(buf.len, *len);
200 puts(buf.off, (long)data);
201 puts(buf.seg, 0);
202 if(r = pxecall(0x32, &buf))
203 return r;
204 moveip(sip, buf.sip);
205 *sport = nhgets(buf.sport);
206 *len = gets(buf.len);
207 return 0;
208 }
209
210 static int
udpwrite(IP4 ip,IP4 gw,int sport,int dport,int len,void * data)211 udpwrite(IP4 ip, IP4 gw, int sport, int dport, int len, void *data)
212 {
213 struct {
214 uchar status[2];
215 uchar ip[4];
216 uchar gw[4];
217 uchar sport[2];
218 uchar dport[2];
219 uchar len[2];
220 uchar off[2];
221 uchar seg[2];
222 } buf;
223
224 puts(buf.status, 0);
225 moveip(buf.ip, ip);
226 moveip(buf.gw, gw);
227 hnputs(buf.sport, sport);
228 hnputs(buf.dport, dport);
229 puts(buf.len, len);
230 puts(buf.off, (long)data);
231 puts(buf.seg, 0);
232 return pxecall(0x33, &buf);
233 }
234
235 int
read(void * f,void * data,int len)236 read(void *f, void *data, int len)
237 {
238 Tftp *t = f;
239 int seq, n;
240
241 while(!t->eof && t->rp >= t->ep){
242 for(;;){
243 n = sizeof(t->pkt);
244 if(udpread(t->dip, t->sip, &t->dport, t->sport, &n, t->pkt))
245 continue;
246 if(n >= 4)
247 break;
248 }
249 switch(nhgets(t->pkt)){
250 case Tftp_DATA:
251 seq = nhgets(t->pkt+2);
252 if(seq > t->seq){
253 putc('?');
254 continue;
255 }
256 hnputs(t->pkt, Tftp_ACK);
257 while(udpwrite(t->dip, t->gip, t->sport, t->dport, 4, t->pkt))
258 putc('!');
259 if(seq < t->seq){
260 putc('@');
261 continue;
262 }
263 t->seq = seq+1;
264 n -= 4;
265 t->rp = t->pkt + 4;
266 t->ep = t->rp + n;
267 t->eof = n < Segsize;
268 break;
269 case Tftp_ERROR:
270 print(t->pkt+4);
271 print("\n");
272 default:
273 t->eof = 1;
274 return -1;
275 }
276 break;
277 }
278 n = t->ep - t->rp;
279 if(len > n)
280 len = n;
281 memmove(data, t->rp, len);
282 t->rp += len;
283 return len;
284 }
285
286 void
close(void * f)287 close(void *f)
288 {
289 Tftp *t = f;
290 t->eof = 1;
291 udpclose();
292 }
293
294
295 static int
tftpopen(Tftp * t,char * path,IP4 sip,IP4 dip,IP4 gip)296 tftpopen(Tftp *t, char *path, IP4 sip, IP4 dip, IP4 gip)
297 {
298 static ushort xport = 6666;
299 int r, n;
300 char *p;
301
302 moveip(t->sip, sip);
303 moveip(t->gip, gip);
304 memset(t->dip, 0, sizeof(t->dip));
305 t->sport = xport++;
306 t->dport = 0;
307 t->rp = t->ep = 0;
308 t->seq = 1;
309 t->eof = 0;
310 t->nul = 0;
311 if(r = udpopen(t->sip))
312 return r;
313 p = t->pkt;
314 hnputs(p, Tftp_READ); p += 2;
315 n = strlen(path)+1;
316 memmove(p, path, n); p += n;
317 memmove(p, "octet", 6); p += 6;
318 n = p - t->pkt;
319 for(;;){
320 if(r = udpwrite(dip, t->gip, t->sport, TftpPort, n, t->pkt))
321 break;
322 if(r = read(t, 0, 0))
323 break;
324 return 0;
325 }
326 close(t);
327 return r;
328 }
329
330 void
start(void *)331 start(void *)
332 {
333 char mac[16], path[Maxpath], *kern;
334 IP4 yip, sip, gip;
335 void *f;
336 Tftp t;
337
338 if(pxeinit()){
339 print("pxe init\n");
340 halt();
341 }
342 if(getip(yip, sip, gip, mac)){
343 print("bad dhcp\n");
344 halt();
345 }
346 memmove(path, "/cfg/pxe/", 9);
347 memmove(path+9, mac, 13);
348 if(tftpopen(f = &t, path, yip, sip, gip))
349 if(tftpopen(f, "/cfg/pxe/default", yip, sip, gip)){
350 print("no config\n");
351 f = 0;
352 }
353 for(;;){
354 kern = configure(f, path); f = 0;
355 if(tftpopen(&t, kern, yip, sip, gip)){
356 print("not found\n");
357 continue;
358 }
359 print(bootkern(&t));
360 print("\n");
361 }
362 }
363