1*529c1f20SDavid du Colombier #include <u.h>
2*529c1f20SDavid du Colombier #include "fns.h"
3*529c1f20SDavid du Colombier #include "efi.h"
4*529c1f20SDavid du Colombier
5*529c1f20SDavid du Colombier typedef UINT16 EFI_PXE_BASE_CODE_UDP_PORT;
6*529c1f20SDavid du Colombier
7*529c1f20SDavid du Colombier typedef struct {
8*529c1f20SDavid du Colombier UINT8 Addr[4];
9*529c1f20SDavid du Colombier } EFI_IPv4_ADDRESS;
10*529c1f20SDavid du Colombier
11*529c1f20SDavid du Colombier typedef struct {
12*529c1f20SDavid du Colombier UINT8 Addr[16];
13*529c1f20SDavid du Colombier } EFI_IPv6_ADDRESS;
14*529c1f20SDavid du Colombier
15*529c1f20SDavid du Colombier typedef union {
16*529c1f20SDavid du Colombier UINT32 Addr[4];
17*529c1f20SDavid du Colombier EFI_IPv4_ADDRESS v4;
18*529c1f20SDavid du Colombier EFI_IPv6_ADDRESS v6;
19*529c1f20SDavid du Colombier } EFI_IP_ADDRESS;
20*529c1f20SDavid du Colombier
21*529c1f20SDavid du Colombier typedef struct {
22*529c1f20SDavid du Colombier UINT8 Addr[32];
23*529c1f20SDavid du Colombier } EFI_MAC_ADDRESS;
24*529c1f20SDavid du Colombier
25*529c1f20SDavid du Colombier typedef struct {
26*529c1f20SDavid du Colombier UINT8 BootpOpcode;
27*529c1f20SDavid du Colombier UINT8 BootpHwType;
28*529c1f20SDavid du Colombier UINT8 BootpHwAddrLen;
29*529c1f20SDavid du Colombier UINT8 BootpGateHops;
30*529c1f20SDavid du Colombier UINT32 BootpIdent;
31*529c1f20SDavid du Colombier UINT16 BootpSeconds;
32*529c1f20SDavid du Colombier UINT16 BootpFlags;
33*529c1f20SDavid du Colombier UINT8 BootpCiAddr[4];
34*529c1f20SDavid du Colombier UINT8 BootpYiAddr[4];
35*529c1f20SDavid du Colombier UINT8 BootpSiAddr[4];
36*529c1f20SDavid du Colombier UINT8 BootpGiAddr[4];
37*529c1f20SDavid du Colombier UINT8 BootpHwAddr[16];
38*529c1f20SDavid du Colombier UINT8 BootpSrvName[64];
39*529c1f20SDavid du Colombier UINT8 BootpBootFile[128];
40*529c1f20SDavid du Colombier UINT32 DhcpMagik;
41*529c1f20SDavid du Colombier UINT8 DhcpOptions[56];
42*529c1f20SDavid du Colombier } EFI_PXE_BASE_CODE_DHCPV4_PACKET;
43*529c1f20SDavid du Colombier
44*529c1f20SDavid du Colombier typedef struct {
45*529c1f20SDavid du Colombier BOOLEAN Started;
46*529c1f20SDavid du Colombier BOOLEAN Ipv6Available;
47*529c1f20SDavid du Colombier BOOLEAN Ipv6Supported;
48*529c1f20SDavid du Colombier BOOLEAN UsingIpv6;
49*529c1f20SDavid du Colombier BOOLEAN BisSupported;
50*529c1f20SDavid du Colombier BOOLEAN BisDetected;
51*529c1f20SDavid du Colombier BOOLEAN AutoArp;
52*529c1f20SDavid du Colombier BOOLEAN SendGUID;
53*529c1f20SDavid du Colombier BOOLEAN DhcpDiscoverValid;
54*529c1f20SDavid du Colombier BOOLEAN DhcpAckReceived;
55*529c1f20SDavid du Colombier BOOLEAN ProxyOfferReceived;
56*529c1f20SDavid du Colombier BOOLEAN PxeDiscoverValid;
57*529c1f20SDavid du Colombier BOOLEAN PxeReplyReceived;
58*529c1f20SDavid du Colombier BOOLEAN PxeBisReplyReceived;
59*529c1f20SDavid du Colombier BOOLEAN IcmpErrorReceived;
60*529c1f20SDavid du Colombier BOOLEAN TftpErrorReceived;
61*529c1f20SDavid du Colombier BOOLEAN MakeCallbacks;
62*529c1f20SDavid du Colombier
63*529c1f20SDavid du Colombier UINT8 TTL;
64*529c1f20SDavid du Colombier UINT8 ToS;
65*529c1f20SDavid du Colombier
66*529c1f20SDavid du Colombier UINT8 Reserved;
67*529c1f20SDavid du Colombier
68*529c1f20SDavid du Colombier UINT8 StationIp[16];
69*529c1f20SDavid du Colombier UINT8 SubnetMask[16];
70*529c1f20SDavid du Colombier
71*529c1f20SDavid du Colombier UINT8 DhcpDiscover[1472];
72*529c1f20SDavid du Colombier UINT8 DhcpAck[1472];
73*529c1f20SDavid du Colombier UINT8 ProxyOffer[1472];
74*529c1f20SDavid du Colombier UINT8 PxeDiscover[1472];
75*529c1f20SDavid du Colombier UINT8 PxeReply[1472];
76*529c1f20SDavid du Colombier UINT8 PxeBisReply[1472];
77*529c1f20SDavid du Colombier
78*529c1f20SDavid du Colombier } EFI_PXE_BASE_CODE_MODE;
79*529c1f20SDavid du Colombier
80*529c1f20SDavid du Colombier typedef struct {
81*529c1f20SDavid du Colombier UINT64 Revision;
82*529c1f20SDavid du Colombier void *Start;
83*529c1f20SDavid du Colombier void *Stop;
84*529c1f20SDavid du Colombier void *Dhcp;
85*529c1f20SDavid du Colombier void *Discover;
86*529c1f20SDavid du Colombier void *Mtftp;
87*529c1f20SDavid du Colombier void *UdpWrite;
88*529c1f20SDavid du Colombier void *UdpRead;
89*529c1f20SDavid du Colombier void *SetIpFilter;
90*529c1f20SDavid du Colombier void *Arp;
91*529c1f20SDavid du Colombier void *SetParameters;
92*529c1f20SDavid du Colombier void *SetStationIp;
93*529c1f20SDavid du Colombier void *SetPackets;
94*529c1f20SDavid du Colombier EFI_PXE_BASE_CODE_MODE *Mode;
95*529c1f20SDavid du Colombier } EFI_PXE_BASE_CODE_PROTOCOL;
96*529c1f20SDavid du Colombier
97*529c1f20SDavid du Colombier
98*529c1f20SDavid du Colombier enum {
99*529c1f20SDavid du Colombier Tftp_READ = 1,
100*529c1f20SDavid du Colombier Tftp_WRITE = 2,
101*529c1f20SDavid du Colombier Tftp_DATA = 3,
102*529c1f20SDavid du Colombier Tftp_ACK = 4,
103*529c1f20SDavid du Colombier Tftp_ERROR = 5,
104*529c1f20SDavid du Colombier Tftp_OACK = 6,
105*529c1f20SDavid du Colombier
106*529c1f20SDavid du Colombier TftpPort = 69,
107*529c1f20SDavid du Colombier
108*529c1f20SDavid du Colombier Segsize = 512,
109*529c1f20SDavid du Colombier };
110*529c1f20SDavid du Colombier
111*529c1f20SDavid du Colombier static
112*529c1f20SDavid du Colombier EFI_GUID EFI_PXE_BASE_CODE_PROTOCOL_GUID = {
113*529c1f20SDavid du Colombier 0x03C4E603, 0xAC28, 0x11D3,
114*529c1f20SDavid du Colombier 0x9A, 0x2D, 0x00, 0x90,
115*529c1f20SDavid du Colombier 0x27, 0x3F, 0xC1, 0x4D,
116*529c1f20SDavid du Colombier };
117*529c1f20SDavid du Colombier
118*529c1f20SDavid du Colombier static
119*529c1f20SDavid du Colombier EFI_PXE_BASE_CODE_PROTOCOL *pxe;
120*529c1f20SDavid du Colombier
121*529c1f20SDavid du Colombier static uchar mymac[6];
122*529c1f20SDavid du Colombier static uchar myip[16];
123*529c1f20SDavid du Colombier static uchar serverip[16];
124*529c1f20SDavid du Colombier
125*529c1f20SDavid du Colombier typedef struct Tftp Tftp;
126*529c1f20SDavid du Colombier struct Tftp
127*529c1f20SDavid du Colombier {
128*529c1f20SDavid du Colombier EFI_IP_ADDRESS sip;
129*529c1f20SDavid du Colombier EFI_IP_ADDRESS dip;
130*529c1f20SDavid du Colombier
131*529c1f20SDavid du Colombier EFI_PXE_BASE_CODE_UDP_PORT sport;
132*529c1f20SDavid du Colombier EFI_PXE_BASE_CODE_UDP_PORT dport;
133*529c1f20SDavid du Colombier
134*529c1f20SDavid du Colombier char *rp;
135*529c1f20SDavid du Colombier char *ep;
136*529c1f20SDavid du Colombier
137*529c1f20SDavid du Colombier int seq;
138*529c1f20SDavid du Colombier int eof;
139*529c1f20SDavid du Colombier
140*529c1f20SDavid du Colombier char pkt[2+2+Segsize];
141*529c1f20SDavid du Colombier char nul;
142*529c1f20SDavid du Colombier };
143*529c1f20SDavid du Colombier
144*529c1f20SDavid du Colombier static void
puts(void * x,ushort v)145*529c1f20SDavid du Colombier puts(void *x, ushort v)
146*529c1f20SDavid du Colombier {
147*529c1f20SDavid du Colombier uchar *p = x;
148*529c1f20SDavid du Colombier
149*529c1f20SDavid du Colombier p[1] = (v>>8) & 0xFF;
150*529c1f20SDavid du Colombier p[0] = v & 0xFF;
151*529c1f20SDavid du Colombier }
152*529c1f20SDavid du Colombier
153*529c1f20SDavid du Colombier static ushort
gets(void * x)154*529c1f20SDavid du Colombier gets(void *x)
155*529c1f20SDavid du Colombier {
156*529c1f20SDavid du Colombier uchar *p = x;
157*529c1f20SDavid du Colombier
158*529c1f20SDavid du Colombier return p[1]<<8 | p[0];
159*529c1f20SDavid du Colombier }
160*529c1f20SDavid du Colombier
161*529c1f20SDavid du Colombier static void
hnputs(void * x,ushort v)162*529c1f20SDavid du Colombier hnputs(void *x, ushort v)
163*529c1f20SDavid du Colombier {
164*529c1f20SDavid du Colombier uchar *p = x;
165*529c1f20SDavid du Colombier
166*529c1f20SDavid du Colombier p[0] = (v>>8) & 0xFF;
167*529c1f20SDavid du Colombier p[1] = v & 0xFF;
168*529c1f20SDavid du Colombier }
169*529c1f20SDavid du Colombier
170*529c1f20SDavid du Colombier static ushort
nhgets(void * x)171*529c1f20SDavid du Colombier nhgets(void *x)
172*529c1f20SDavid du Colombier {
173*529c1f20SDavid du Colombier uchar *p = x;
174*529c1f20SDavid du Colombier
175*529c1f20SDavid du Colombier return p[0]<<8 | p[1];
176*529c1f20SDavid du Colombier }
177*529c1f20SDavid du Colombier
178*529c1f20SDavid du Colombier enum {
179*529c1f20SDavid du Colombier ANY_SRC_IP = 0x0001,
180*529c1f20SDavid du Colombier ANY_SRC_PORT = 0x0002,
181*529c1f20SDavid du Colombier ANY_DEST_IP = 0x0004,
182*529c1f20SDavid du Colombier ANY_DEST_PORT = 0x0008,
183*529c1f20SDavid du Colombier USE_FILTER = 0x0010,
184*529c1f20SDavid du Colombier MAY_FRAGMENT = 0x0020,
185*529c1f20SDavid du Colombier };
186*529c1f20SDavid du Colombier
187*529c1f20SDavid du Colombier static int
udpread(EFI_IP_ADDRESS * sip,EFI_IP_ADDRESS * dip,EFI_PXE_BASE_CODE_UDP_PORT * sport,EFI_PXE_BASE_CODE_UDP_PORT dport,int * len,void * data)188*529c1f20SDavid du Colombier udpread(EFI_IP_ADDRESS *sip, EFI_IP_ADDRESS *dip,
189*529c1f20SDavid du Colombier EFI_PXE_BASE_CODE_UDP_PORT *sport,
190*529c1f20SDavid du Colombier EFI_PXE_BASE_CODE_UDP_PORT dport,
191*529c1f20SDavid du Colombier int *len, void *data)
192*529c1f20SDavid du Colombier {
193*529c1f20SDavid du Colombier UINTN size;
194*529c1f20SDavid du Colombier
195*529c1f20SDavid du Colombier size = *len;
196*529c1f20SDavid du Colombier if(eficall(pxe->UdpRead, pxe, (UINTN)ANY_SRC_PORT, dip, &dport, sip, sport, nil, nil, &size, data))
197*529c1f20SDavid du Colombier return -1;
198*529c1f20SDavid du Colombier
199*529c1f20SDavid du Colombier *len = size;
200*529c1f20SDavid du Colombier return 0;
201*529c1f20SDavid du Colombier }
202*529c1f20SDavid du Colombier
203*529c1f20SDavid du Colombier static int
udpwrite(EFI_IP_ADDRESS * dip,EFI_PXE_BASE_CODE_UDP_PORT sport,EFI_PXE_BASE_CODE_UDP_PORT dport,int len,void * data)204*529c1f20SDavid du Colombier udpwrite(EFI_IP_ADDRESS *dip,
205*529c1f20SDavid du Colombier EFI_PXE_BASE_CODE_UDP_PORT sport,
206*529c1f20SDavid du Colombier EFI_PXE_BASE_CODE_UDP_PORT dport,
207*529c1f20SDavid du Colombier int len, void *data)
208*529c1f20SDavid du Colombier {
209*529c1f20SDavid du Colombier UINTN size;
210*529c1f20SDavid du Colombier
211*529c1f20SDavid du Colombier size = len;
212*529c1f20SDavid du Colombier if(eficall(pxe->UdpWrite, pxe, (UINTN)MAY_FRAGMENT, dip, &dport, nil, nil, &sport, nil, nil, &size, data))
213*529c1f20SDavid du Colombier return -1;
214*529c1f20SDavid du Colombier
215*529c1f20SDavid du Colombier return 0;
216*529c1f20SDavid du Colombier }
217*529c1f20SDavid du Colombier
218*529c1f20SDavid du Colombier static int
pxeread(void * f,void * data,int len)219*529c1f20SDavid du Colombier pxeread(void *f, void *data, int len)
220*529c1f20SDavid du Colombier {
221*529c1f20SDavid du Colombier Tftp *t = f;
222*529c1f20SDavid du Colombier int seq, n;
223*529c1f20SDavid du Colombier
224*529c1f20SDavid du Colombier while(!t->eof && t->rp >= t->ep){
225*529c1f20SDavid du Colombier for(;;){
226*529c1f20SDavid du Colombier n = sizeof(t->pkt);
227*529c1f20SDavid du Colombier if(udpread(&t->dip, &t->sip, &t->dport, t->sport, &n, t->pkt))
228*529c1f20SDavid du Colombier continue;
229*529c1f20SDavid du Colombier if(n >= 4)
230*529c1f20SDavid du Colombier break;
231*529c1f20SDavid du Colombier }
232*529c1f20SDavid du Colombier switch(nhgets(t->pkt)){
233*529c1f20SDavid du Colombier case Tftp_DATA:
234*529c1f20SDavid du Colombier seq = nhgets(t->pkt+2);
235*529c1f20SDavid du Colombier if(seq > t->seq){
236*529c1f20SDavid du Colombier putc('?');
237*529c1f20SDavid du Colombier continue;
238*529c1f20SDavid du Colombier }
239*529c1f20SDavid du Colombier hnputs(t->pkt, Tftp_ACK);
240*529c1f20SDavid du Colombier while(udpwrite(&t->dip, t->sport, t->dport, 4, t->pkt))
241*529c1f20SDavid du Colombier putc('!');
242*529c1f20SDavid du Colombier if(seq < t->seq){
243*529c1f20SDavid du Colombier putc('@');
244*529c1f20SDavid du Colombier continue;
245*529c1f20SDavid du Colombier }
246*529c1f20SDavid du Colombier t->seq = seq+1;
247*529c1f20SDavid du Colombier n -= 4;
248*529c1f20SDavid du Colombier t->rp = t->pkt + 4;
249*529c1f20SDavid du Colombier t->ep = t->rp + n;
250*529c1f20SDavid du Colombier t->eof = n < Segsize;
251*529c1f20SDavid du Colombier break;
252*529c1f20SDavid du Colombier case Tftp_ERROR:
253*529c1f20SDavid du Colombier print(t->pkt+4);
254*529c1f20SDavid du Colombier print("\n");
255*529c1f20SDavid du Colombier default:
256*529c1f20SDavid du Colombier t->eof = 1;
257*529c1f20SDavid du Colombier return -1;
258*529c1f20SDavid du Colombier }
259*529c1f20SDavid du Colombier break;
260*529c1f20SDavid du Colombier }
261*529c1f20SDavid du Colombier n = t->ep - t->rp;
262*529c1f20SDavid du Colombier if(len > n)
263*529c1f20SDavid du Colombier len = n;
264*529c1f20SDavid du Colombier memmove(data, t->rp, len);
265*529c1f20SDavid du Colombier t->rp += len;
266*529c1f20SDavid du Colombier return len;
267*529c1f20SDavid du Colombier }
268*529c1f20SDavid du Colombier
269*529c1f20SDavid du Colombier static void
pxeclose(void * f)270*529c1f20SDavid du Colombier pxeclose(void *f)
271*529c1f20SDavid du Colombier {
272*529c1f20SDavid du Colombier Tftp *t = f;
273*529c1f20SDavid du Colombier t->eof = 1;
274*529c1f20SDavid du Colombier }
275*529c1f20SDavid du Colombier
276*529c1f20SDavid du Colombier
277*529c1f20SDavid du Colombier static int
tftpopen(Tftp * t,char * path)278*529c1f20SDavid du Colombier tftpopen(Tftp *t, char *path)
279*529c1f20SDavid du Colombier {
280*529c1f20SDavid du Colombier static EFI_PXE_BASE_CODE_UDP_PORT xport = 6666;
281*529c1f20SDavid du Colombier int r, n;
282*529c1f20SDavid du Colombier char *p;
283*529c1f20SDavid du Colombier
284*529c1f20SDavid du Colombier t->sport = xport++;
285*529c1f20SDavid du Colombier t->dport = 0;
286*529c1f20SDavid du Colombier t->rp = t->ep = 0;
287*529c1f20SDavid du Colombier t->seq = 1;
288*529c1f20SDavid du Colombier t->eof = 0;
289*529c1f20SDavid du Colombier t->nul = 0;
290*529c1f20SDavid du Colombier p = t->pkt;
291*529c1f20SDavid du Colombier hnputs(p, Tftp_READ); p += 2;
292*529c1f20SDavid du Colombier n = strlen(path)+1;
293*529c1f20SDavid du Colombier memmove(p, path, n); p += n;
294*529c1f20SDavid du Colombier memmove(p, "octet", 6); p += 6;
295*529c1f20SDavid du Colombier n = p - t->pkt;
296*529c1f20SDavid du Colombier for(;;){
297*529c1f20SDavid du Colombier if(r = udpwrite(&t->dip, t->sport, TftpPort, n, t->pkt))
298*529c1f20SDavid du Colombier break;
299*529c1f20SDavid du Colombier if(r = pxeread(t, 0, 0))
300*529c1f20SDavid du Colombier break;
301*529c1f20SDavid du Colombier return 0;
302*529c1f20SDavid du Colombier }
303*529c1f20SDavid du Colombier pxeclose(t);
304*529c1f20SDavid du Colombier return r;
305*529c1f20SDavid du Colombier }
306*529c1f20SDavid du Colombier
307*529c1f20SDavid du Colombier static void*
pxeopen(char * name)308*529c1f20SDavid du Colombier pxeopen(char *name)
309*529c1f20SDavid du Colombier {
310*529c1f20SDavid du Colombier static uchar buf[sizeof(Tftp)+8];
311*529c1f20SDavid du Colombier Tftp *t = (Tftp*)((uintptr)(buf+7)&~7);
312*529c1f20SDavid du Colombier
313*529c1f20SDavid du Colombier memset(t, 0, sizeof(Tftp));
314*529c1f20SDavid du Colombier memmove(&t->sip, myip, sizeof(myip));
315*529c1f20SDavid du Colombier memmove(&t->dip, serverip, sizeof(serverip));
316*529c1f20SDavid du Colombier if(tftpopen(t, name))
317*529c1f20SDavid du Colombier return nil;
318*529c1f20SDavid du Colombier return t;
319*529c1f20SDavid du Colombier }
320*529c1f20SDavid du Colombier
321*529c1f20SDavid du Colombier static int
parseipv6(uchar to[16],char * from)322*529c1f20SDavid du Colombier parseipv6(uchar to[16], char *from)
323*529c1f20SDavid du Colombier {
324*529c1f20SDavid du Colombier int i, dig, elipsis;
325*529c1f20SDavid du Colombier char *p;
326*529c1f20SDavid du Colombier
327*529c1f20SDavid du Colombier elipsis = 0;
328*529c1f20SDavid du Colombier memset(to, 0, 16);
329*529c1f20SDavid du Colombier for(i = 0; i < 16; i += 2){
330*529c1f20SDavid du Colombier dig = 0;
331*529c1f20SDavid du Colombier for(p = from;; p++){
332*529c1f20SDavid du Colombier if(*p >= '0' && *p <= '9')
333*529c1f20SDavid du Colombier dig = (dig << 4) | (*p - '0');
334*529c1f20SDavid du Colombier else if(*p >= 'a' && *p <= 'f')
335*529c1f20SDavid du Colombier dig = (dig << 4) | (*p - 'a'+10);
336*529c1f20SDavid du Colombier else if(*p >= 'A' && *p <= 'F')
337*529c1f20SDavid du Colombier dig = (dig << 4) | (*p - 'A'+10);
338*529c1f20SDavid du Colombier else
339*529c1f20SDavid du Colombier break;
340*529c1f20SDavid du Colombier if(dig > 0xFFFF)
341*529c1f20SDavid du Colombier return -1;
342*529c1f20SDavid du Colombier }
343*529c1f20SDavid du Colombier to[i] = dig>>8;
344*529c1f20SDavid du Colombier to[i+1] = dig;
345*529c1f20SDavid du Colombier if(*p == ':'){
346*529c1f20SDavid du Colombier if(*++p == ':'){ /* :: is elided zero short(s) */
347*529c1f20SDavid du Colombier if (elipsis)
348*529c1f20SDavid du Colombier return -1; /* second :: */
349*529c1f20SDavid du Colombier elipsis = i+2;
350*529c1f20SDavid du Colombier p++;
351*529c1f20SDavid du Colombier }
352*529c1f20SDavid du Colombier } else if (p == from)
353*529c1f20SDavid du Colombier break;
354*529c1f20SDavid du Colombier from = p;
355*529c1f20SDavid du Colombier }
356*529c1f20SDavid du Colombier if(i < 16){
357*529c1f20SDavid du Colombier memmove(&to[elipsis+16-i], &to[elipsis], i-elipsis);
358*529c1f20SDavid du Colombier memset(&to[elipsis], 0, 16-i);
359*529c1f20SDavid du Colombier }
360*529c1f20SDavid du Colombier return 0;
361*529c1f20SDavid du Colombier }
362*529c1f20SDavid du Colombier
363*529c1f20SDavid du Colombier static void
parsedhcp(EFI_PXE_BASE_CODE_DHCPV4_PACKET * dhcp)364*529c1f20SDavid du Colombier parsedhcp(EFI_PXE_BASE_CODE_DHCPV4_PACKET *dhcp)
365*529c1f20SDavid du Colombier {
366*529c1f20SDavid du Colombier uchar *p, *e;
367*529c1f20SDavid du Colombier char *x;
368*529c1f20SDavid du Colombier int opt;
369*529c1f20SDavid du Colombier int len;
370*529c1f20SDavid du Colombier uint type;
371*529c1f20SDavid du Colombier
372*529c1f20SDavid du Colombier memset(mymac, 0, sizeof(mymac));
373*529c1f20SDavid du Colombier memset(serverip, 0, sizeof(serverip));
374*529c1f20SDavid du Colombier
375*529c1f20SDavid du Colombier /* DHCPv4 */
376*529c1f20SDavid du Colombier if(pxe->Mode->UsingIpv6 == 0){
377*529c1f20SDavid du Colombier memmove(mymac, dhcp->BootpHwAddr, 6);
378*529c1f20SDavid du Colombier memmove(serverip, dhcp->BootpSiAddr, 4);
379*529c1f20SDavid du Colombier return;
380*529c1f20SDavid du Colombier }
381*529c1f20SDavid du Colombier
382*529c1f20SDavid du Colombier /* DHCPv6 */
383*529c1f20SDavid du Colombier
384*529c1f20SDavid du Colombier /*
385*529c1f20SDavid du Colombier * some UEFI implementations use random UUID based DUID instead of
386*529c1f20SDavid du Colombier * ethernet address, but use ethernet derived link-local addresses.
387*529c1f20SDavid du Colombier * so extract the MAC from our IPv6 address as a fallback.
388*529c1f20SDavid du Colombier */
389*529c1f20SDavid du Colombier p = pxe->Mode->StationIp;
390*529c1f20SDavid du Colombier mymac[0] = p[8] ^ 2;
391*529c1f20SDavid du Colombier mymac[1] = p[9];
392*529c1f20SDavid du Colombier mymac[2] = p[10];
393*529c1f20SDavid du Colombier mymac[3] = p[13];
394*529c1f20SDavid du Colombier mymac[4] = p[14];
395*529c1f20SDavid du Colombier mymac[5] = p[15];
396*529c1f20SDavid du Colombier
397*529c1f20SDavid du Colombier e = (uchar*)dhcp + sizeof(*dhcp);
398*529c1f20SDavid du Colombier p = (uchar*)dhcp + 4;
399*529c1f20SDavid du Colombier while(p+4 <= e){
400*529c1f20SDavid du Colombier opt = p[0]<<8 | p[1];
401*529c1f20SDavid du Colombier len = p[2]<<8 | p[3];
402*529c1f20SDavid du Colombier p += 4;
403*529c1f20SDavid du Colombier if(p + len > e)
404*529c1f20SDavid du Colombier break;
405*529c1f20SDavid du Colombier switch(opt){
406*529c1f20SDavid du Colombier case 1: /* Client DUID */
407*529c1f20SDavid du Colombier if(len < 4+6)
408*529c1f20SDavid du Colombier break;
409*529c1f20SDavid du Colombier type = p[0]<<24 | p[1]<<16 | p[2]<<8 | p[3];
410*529c1f20SDavid du Colombier switch(type){
411*529c1f20SDavid du Colombier case 0x00010001:
412*529c1f20SDavid du Colombier case 0x00030001:
413*529c1f20SDavid du Colombier memmove(mymac, p+len-6, 6);
414*529c1f20SDavid du Colombier break;
415*529c1f20SDavid du Colombier }
416*529c1f20SDavid du Colombier break;
417*529c1f20SDavid du Colombier case 59: /* Boot File URL */
418*529c1f20SDavid du Colombier for(x = (char*)p; x < (char*)p+len; x++){
419*529c1f20SDavid du Colombier if(*x == '['){
420*529c1f20SDavid du Colombier parseipv6(serverip, x+1);
421*529c1f20SDavid du Colombier break;
422*529c1f20SDavid du Colombier }
423*529c1f20SDavid du Colombier }
424*529c1f20SDavid du Colombier break;
425*529c1f20SDavid du Colombier }
426*529c1f20SDavid du Colombier p += len;
427*529c1f20SDavid du Colombier }
428*529c1f20SDavid du Colombier }
429*529c1f20SDavid du Colombier
430*529c1f20SDavid du Colombier int
pxeinit(void ** pf)431*529c1f20SDavid du Colombier pxeinit(void **pf)
432*529c1f20SDavid du Colombier {
433*529c1f20SDavid du Colombier EFI_PXE_BASE_CODE_DHCPV4_PACKET *dhcp;
434*529c1f20SDavid du Colombier EFI_PXE_BASE_CODE_MODE *mode;
435*529c1f20SDavid du Colombier EFI_HANDLE *Handles;
436*529c1f20SDavid du Colombier UINTN Count;
437*529c1f20SDavid du Colombier int i;
438*529c1f20SDavid du Colombier
439*529c1f20SDavid du Colombier pxe = nil;
440*529c1f20SDavid du Colombier Count = 0;
441*529c1f20SDavid du Colombier Handles = nil;
442*529c1f20SDavid du Colombier if(eficall(ST->BootServices->LocateHandleBuffer,
443*529c1f20SDavid du Colombier ByProtocol, &EFI_PXE_BASE_CODE_PROTOCOL_GUID, nil, &Count, &Handles))
444*529c1f20SDavid du Colombier return -1;
445*529c1f20SDavid du Colombier
446*529c1f20SDavid du Colombier for(i=0; i<Count; i++){
447*529c1f20SDavid du Colombier pxe = nil;
448*529c1f20SDavid du Colombier if(eficall(ST->BootServices->HandleProtocol,
449*529c1f20SDavid du Colombier Handles[i], &EFI_PXE_BASE_CODE_PROTOCOL_GUID, &pxe))
450*529c1f20SDavid du Colombier continue;
451*529c1f20SDavid du Colombier mode = pxe->Mode;
452*529c1f20SDavid du Colombier if(mode == nil || mode->Started == 0)
453*529c1f20SDavid du Colombier continue;
454*529c1f20SDavid du Colombier if(mode->DhcpAckReceived){
455*529c1f20SDavid du Colombier dhcp = (EFI_PXE_BASE_CODE_DHCPV4_PACKET*)mode->DhcpAck;
456*529c1f20SDavid du Colombier goto Found;
457*529c1f20SDavid du Colombier }
458*529c1f20SDavid du Colombier if(mode->PxeReplyReceived){
459*529c1f20SDavid du Colombier dhcp = (EFI_PXE_BASE_CODE_DHCPV4_PACKET*)mode->PxeReply;
460*529c1f20SDavid du Colombier goto Found;
461*529c1f20SDavid du Colombier }
462*529c1f20SDavid du Colombier }
463*529c1f20SDavid du Colombier return -1;
464*529c1f20SDavid du Colombier
465*529c1f20SDavid du Colombier Found:
466*529c1f20SDavid du Colombier parsedhcp(dhcp);
467*529c1f20SDavid du Colombier memmove(myip, mode->StationIp, 16);
468*529c1f20SDavid du Colombier
469*529c1f20SDavid du Colombier open = pxeopen;
470*529c1f20SDavid du Colombier read = pxeread;
471*529c1f20SDavid du Colombier close = pxeclose;
472*529c1f20SDavid du Colombier
473*529c1f20SDavid du Colombier if(pf != nil){
474*529c1f20SDavid du Colombier char ini[24];
475*529c1f20SDavid du Colombier
476*529c1f20SDavid du Colombier memmove(ini, "/cfg/pxe/", 9);
477*529c1f20SDavid du Colombier for(i=0; i<6; i++){
478*529c1f20SDavid du Colombier ini[9+i*2+0] = hex[mymac[i] >> 4];
479*529c1f20SDavid du Colombier ini[9+i*2+1] = hex[mymac[i] & 0xF];
480*529c1f20SDavid du Colombier }
481*529c1f20SDavid du Colombier ini[9+12] = '\0';
482*529c1f20SDavid du Colombier if((*pf = pxeopen(ini)) == nil)
483*529c1f20SDavid du Colombier *pf = pxeopen("/cfg/pxe/default");
484*529c1f20SDavid du Colombier }
485*529c1f20SDavid du Colombier
486*529c1f20SDavid du Colombier return 0;
487*529c1f20SDavid du Colombier }
488