]> git.lizzy.rs Git - plan9front.git/blob - sys/src/boot/efi/pxe.c
efi: change eficonfig ordering so memconf() is first, dont fallback to fs when /cfg...
[plan9front.git] / sys / src / boot / efi / pxe.c
1 #include <u.h>
2 #include "fns.h"
3 #include "efi.h"
4
5 typedef UINT16  EFI_PXE_BASE_CODE_UDP_PORT;
6
7 typedef struct {
8         UINT8           Addr[4];
9 } EFI_IPv4_ADDRESS;
10
11 typedef struct {
12         UINT8           Addr[16];
13 } EFI_IPv6_ADDRESS;
14
15 typedef union {
16         UINT32                  Addr[4];
17         EFI_IPv4_ADDRESS        v4;
18         EFI_IPv6_ADDRESS        v6;
19 } EFI_IP_ADDRESS;
20
21 typedef struct {
22         UINT8           Addr[32];
23 } EFI_MAC_ADDRESS;
24
25 typedef struct {
26         UINT8           BootpOpcode;
27         UINT8           BootpHwType;
28         UINT8           BootpHwAddrLen;
29         UINT8           BootpGateHops;
30         UINT32          BootpIdent;
31         UINT16          BootpSeconds;
32         UINT16          BootpFlags;
33         UINT8           BootpCiAddr[4];
34         UINT8           BootpYiAddr[4];
35         UINT8           BootpSiAddr[4];
36         UINT8           BootpGiAddr[4];
37         UINT8           BootpHwAddr[16];
38         UINT8           BootpSrvName[64];
39         UINT8           BootpBootFile[128];
40         UINT32          DhcpMagik;
41         UINT8           DhcpOptions[56];                
42 } EFI_PXE_BASE_CODE_DHCPV4_PACKET;
43
44 typedef struct {
45         BOOLEAN         Started;
46         BOOLEAN         Ipv6Available;
47         BOOLEAN         Ipv6Supported;
48         BOOLEAN         UsingIpv6;
49         BOOLEAN         BisSupported;
50         BOOLEAN         BisDetected;
51         BOOLEAN         AutoArp;
52         BOOLEAN         SendGUID;
53         BOOLEAN         DhcpDiscoverValid;
54         BOOLEAN         DhcpAckReceived;
55         BOOLEAN         ProxyOfferReceived;
56         BOOLEAN         PxeDiscoverValid;
57         BOOLEAN         PxeReplyReceived;
58         BOOLEAN         PxeBisReplyReceived;
59         BOOLEAN         IcmpErrorReceived;
60         BOOLEAN         TftpErrorReceived;
61         BOOLEAN         MakeCallbacks;
62
63         UINT8           TTL;
64         UINT8           ToS;
65
66         UINT8           Reserved;
67
68         UINT8           StationIp[16];
69         UINT8           SubnetMask[16];
70
71         UINT8           DhcpDiscover[1472];
72         UINT8           DhcpAck[1472];
73         UINT8           ProxyOffer[1472];
74         UINT8           PxeDiscover[1472];
75         UINT8           PxeReply[1472];
76         UINT8           PxeBisReply[1472];
77
78 } EFI_PXE_BASE_CODE_MODE;
79
80 typedef struct {
81         UINT64          Revision;
82         void            *Start;
83         void            *Stop;
84         void            *Dhcp;
85         void            *Discover;
86         void            *Mtftp;
87         void            *UdpWrite;
88         void            *UdpRead;
89         void            *SetIpFilter;
90         void            *Arp;
91         void            *SetParameters;
92         void            *SetStationIp;
93         void            *SetPackets;
94         EFI_PXE_BASE_CODE_MODE  *Mode;
95 } EFI_PXE_BASE_CODE_PROTOCOL;
96
97
98 enum {
99         Tftp_READ       = 1,
100         Tftp_WRITE      = 2,
101         Tftp_DATA       = 3,
102         Tftp_ACK        = 4,
103         Tftp_ERROR      = 5,
104         Tftp_OACK       = 6,
105
106         TftpPort        = 69,
107
108         Segsize         = 512,
109 };
110
111 static
112 EFI_GUID EFI_PXE_BASE_CODE_PROTOCOL_GUID = {
113         0x03C4E603, 0xAC28, 0x11D3,
114         0x9A, 0x2D, 0x00, 0x90,
115         0x27, 0x3F, 0xC1, 0x4D,
116 };
117
118 static
119 EFI_PXE_BASE_CODE_PROTOCOL *pxe;
120
121 static
122 EFI_PXE_BASE_CODE_DHCPV4_PACKET *dhcp;
123
124 typedef struct Tftp Tftp;
125 struct Tftp
126 {
127         EFI_IP_ADDRESS sip;
128         EFI_IP_ADDRESS dip;
129
130         EFI_PXE_BASE_CODE_UDP_PORT sport;
131         EFI_PXE_BASE_CODE_UDP_PORT dport;
132
133         char *rp;
134         char *ep;
135
136         int seq;
137         int eof;
138         
139         char pkt[2+2+Segsize];
140         char nul;
141 };
142
143 static void
144 puts(void *x, ushort v)
145 {
146         uchar *p = x;
147
148         p[1] = (v>>8) & 0xFF;
149         p[0] = v & 0xFF;
150 }
151
152 static ushort
153 gets(void *x)
154 {
155         uchar *p = x;
156
157         return p[1]<<8 | p[0];
158 }
159
160 static void
161 hnputs(void *x, ushort v)
162 {
163         uchar *p = x;
164
165         p[0] = (v>>8) & 0xFF;
166         p[1] = v & 0xFF;
167 }
168
169 static ushort
170 nhgets(void *x)
171 {
172         uchar *p = x;
173
174         return p[0]<<8 | p[1];
175 }
176
177 enum {
178         ANY_SRC_IP      = 0x0001,
179         ANY_SRC_PORT    = 0x0002,
180         ANY_DEST_IP     = 0x0004,
181         ANY_DEST_PORT   = 0x0008,
182         USE_FILTER      = 0x0010,
183         MAY_FRAGMENT    = 0x0020,
184 };
185
186 static int
187 udpread(EFI_IP_ADDRESS *sip, EFI_IP_ADDRESS *dip, 
188         EFI_PXE_BASE_CODE_UDP_PORT *sport, 
189         EFI_PXE_BASE_CODE_UDP_PORT dport, 
190         int *len, void *data)
191 {
192         UINTN size;
193
194         size = *len;
195         if(eficall(pxe->UdpRead, pxe, (UINTN)ANY_SRC_PORT, dip, &dport, sip, sport, nil, nil, &size, data))
196                 return -1;
197
198         *len = size;
199         return 0;
200 }
201
202 static int
203 udpwrite(EFI_IP_ADDRESS *dip,
204         EFI_PXE_BASE_CODE_UDP_PORT sport, 
205         EFI_PXE_BASE_CODE_UDP_PORT dport,
206         int len, void *data)
207 {
208         UINTN size;
209
210         size = len;
211         if(eficall(pxe->UdpWrite, pxe, (UINTN)MAY_FRAGMENT, dip, &dport, nil, nil, &sport, nil, nil, &size, data))
212                 return -1;
213
214         return 0;
215 }
216
217 static int
218 pxeread(void *f, void *data, int len)
219 {
220         Tftp *t = f;
221         int seq, n;
222
223         while(!t->eof && t->rp >= t->ep){
224                 for(;;){
225                         n = sizeof(t->pkt);
226                         if(udpread(&t->dip, &t->sip, &t->dport, t->sport, &n, t->pkt))
227                                 continue;
228                         if(n >= 4)
229                                 break;
230                 }
231                 switch(nhgets(t->pkt)){
232                 case Tftp_DATA:
233                         seq = nhgets(t->pkt+2);
234                         if(seq > t->seq){
235                                 putc('?');
236                                 continue;
237                         }
238                         hnputs(t->pkt, Tftp_ACK);
239                         while(udpwrite(&t->dip, t->sport, t->dport, 4, t->pkt))
240                                 putc('!');
241                         if(seq < t->seq){
242                                 putc('@');
243                                 continue;
244                         }
245                         t->seq = seq+1;
246                         n -= 4;
247                         t->rp = t->pkt + 4;
248                         t->ep = t->rp + n;
249                         t->eof = n < Segsize;
250                         break;
251                 case Tftp_ERROR:
252                         print(t->pkt+4);
253                         print("\n");
254                 default:
255                         t->eof = 1;
256                         return -1;
257                 }
258                 break;
259         }
260         n = t->ep - t->rp;
261         if(len > n)
262                 len = n;
263         memmove(data, t->rp, len);
264         t->rp += len;
265         return len;
266 }
267
268 static void
269 pxeclose(void *f)
270 {
271         Tftp *t = f;
272         t->eof = 1;
273 }
274
275
276 static int
277 tftpopen(Tftp *t, char *path)
278 {
279         static EFI_PXE_BASE_CODE_UDP_PORT xport = 6666;
280         int r, n;
281         char *p;
282
283         t->sport = xport++;
284         t->dport = 0;
285         t->rp = t->ep = 0;
286         t->seq = 1;
287         t->eof = 0;
288         t->nul = 0;
289         p = t->pkt;
290         hnputs(p, Tftp_READ); p += 2;
291         n = strlen(path)+1;
292         memmove(p, path, n); p += n;
293         memmove(p, "octet", 6); p += 6;
294         n = p - t->pkt;
295         for(;;){
296                 if(r = udpwrite(&t->dip, t->sport, TftpPort, n, t->pkt))
297                         break;
298                 if(r = pxeread(t, 0, 0))
299                         break;
300                 return 0;
301         }
302         pxeclose(t);
303         return r;
304 }
305
306 static void*
307 pxeopen(char *name)
308 {
309         static Tftp t[1];
310
311         memset(t, 0, sizeof(Tftp));
312
313         memmove(&t->dip, dhcp->BootpSiAddr, 4);
314         memmove(&t->sip, pxe->Mode->StationIp, 4);
315
316         if(tftpopen(t, name))
317                 return nil;
318         return t;
319 }
320
321 int
322 pxeinit(void **pf)
323 {
324         EFI_PXE_BASE_CODE_MODE *mode;
325         EFI_HANDLE *Handles;
326         UINTN Count;
327         int i;
328
329         pxe = nil;
330         dhcp = nil;
331         Count = 0;
332         Handles = nil;
333         if(eficall(ST->BootServices->LocateHandleBuffer,
334                 ByProtocol, &EFI_PXE_BASE_CODE_PROTOCOL_GUID, nil, &Count, &Handles))
335                 return -1;
336
337         for(i=0; i<Count; i++){
338                 pxe = nil;
339                 if(eficall(ST->BootServices->HandleProtocol,
340                         Handles[i], &EFI_PXE_BASE_CODE_PROTOCOL_GUID, &pxe))
341                         continue;
342                 mode = pxe->Mode;
343                 if(mode == nil || mode->UsingIpv6 || mode->Started == 0)
344                         continue;
345                 if(mode->DhcpAckReceived){
346                         dhcp = (EFI_PXE_BASE_CODE_DHCPV4_PACKET*)mode->DhcpAck;
347                         goto Found;
348                 }
349                 if(mode->PxeReplyReceived){
350                         dhcp = (EFI_PXE_BASE_CODE_DHCPV4_PACKET*)mode->PxeReply;
351                         goto Found;
352                 }
353         }
354         return -1;
355
356 Found:
357         open = pxeopen;
358         read = pxeread;
359         close = pxeclose;
360
361         if(pf != nil){
362                 char ini[24];
363                 uchar *mac;
364
365                 mac = dhcp->BootpHwAddr;
366                 memmove(ini, "/cfg/pxe/", 9);
367                 for(i=0; i<6; i++){
368                         ini[9+i*2+0] = hex[mac[i] >> 4];
369                         ini[9+i*2+1] = hex[mac[i] & 0xF];
370                 }
371                 ini[9+12] = '\0';
372                 if((*pf = pxeopen(ini)) == nil)
373                         *pf = pxeopen("/cfg/pxe/default");
374         }
375
376         return 0;
377 }