1 /* ----------------------------------------------------------------------- *
3 * Copyright 2010-2012 Gene Cumm - All Rights Reserved
5 * Portions from chain.c:
6 * Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
7 * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
8 * Significant portions copyright (C) 2010 Shao Miller
9 * [partition iteration, GPT, "fs"]
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation, Inc., 53 Temple Place Ste 330,
14 * Boston MA 02111-1307, USA; either version 2 of the License, or
15 * (at your option) any later version; incorporated herein by reference.
17 * ----------------------------------------------------------------------- */
22 * PXE Chain Loader; Chain load to another PXE network boot program
23 * that may be on another host.
32 #include <syslinux/config.h>
33 #include <syslinux/loadfile.h>
34 #include <syslinux/bootrm.h>
35 #include <syslinux/video.h>
38 #include <syslinux/pxe.h>
46 #define PXECHN_DEBUG 1
55 #define dprintf0(f, ...) ((void)0)
57 #if (PXECHN_DEBUG > 0)
58 # define dpressanykey pressanykey
59 # define dprintf printf
60 # define dprint_pxe_bootp_t print_pxe_bootp_t
61 # define dprint_pxe_vendor_blk print_pxe_vendor_blk
62 # define dprint_pxe_vendor_raw print_pxe_vendor_raw
64 # define dpressanykey(tm) ((void)0)
65 # define dprintf(f, ...) ((void)0)
66 # define dprint_pxe_bootp_t(p, l) ((void)0)
67 # define dprint_pxe_vendor_blk(p, l) ((void)0)
68 # define dprint_pxe_vendor_raw(p, l) ((void)0)
71 #define dprintf_opt_cp dprintf0
72 #define dprintf_opt_inj dprintf0
73 #define dprintf_pc_pa dprintf
74 #define dprintf_pc_so_s dprintf0
76 #define t_PXENV_RESTART_TFTP t_PXENV_TFTP_READ_FILE
78 #define STACK_SPLIT 11
80 /* same as pxelinux.asm REBOOT_TIME */
81 #define REBOOT_TIME 300
83 #define NUM_DHCP_OPTS 256
84 #define DHCP_OPT_LEN_MAX 256
85 #define PXE_VENDOR_RAW_PRN_MAX 0x7F
86 #define PXECHN_HOST_LEN 256 /* 63 bytes per label; 255 max total */
88 #define PXECHN_NUM_PKT_TYPE 3
89 #define PXECHN_NUM_PKT_AVAIL 2*PXECHN_NUM_PKT_TYPE
90 #define PXECHN_PKT_TYPE_START PXENV_PACKET_TYPE_DHCP_DISCOVER
92 #define PXECHN_FORCE_PKT1 0x80000000
93 #define PXECHN_FORCE_PKT2 0x40000000
94 #define PXECHN_FORCE_ALL (PXECHN_FORCE_PKT1 | PXECHN_FORCE_PKT2)
95 #define PXECHN_FORCE_ALL_1 0
96 #define STRASINT_str ('s' + (('t' + ('r' << 8)) << 8))
98 #define min(a,b) (((a) < (b)) ? (a) : (b))
100 const char app_name_str[] = "pxechn.c32";
102 struct pxelinux_opt {
103 char *fn; /* Filename as passed to us */
104 in_addr_t fip; /* fn's IP component */
105 char *fp; /* fn's path component */
106 in_addr_t gip; /* giaddr; Gateway/DHCP relay */
108 uint32_t wait; /* Additional decision to wait before boot */
109 int32_t wds; /* WDS option/level */
110 struct dhcp_option p[PXECHN_NUM_PKT_AVAIL];
111 /* original _DHCP_DISCOVER, _DHCP_ACK, _CACHED_REPLY then modified packets */
112 char host[PXECHN_HOST_LEN];
113 struct dhcp_option opts[PXECHN_NUM_PKT_TYPE][NUM_DHCP_OPTS];
114 char p_unpacked[PXECHN_NUM_PKT_TYPE];
126 static inline void error(const char *msg)
132 static void do_boot(struct data_area *data, int ndata,
133 struct syslinux_rm_regs *regs)
135 uint16_t *const bios_fbm = (uint16_t *) 0x413;
136 addr_t dosmem = *bios_fbm << 10; /* Technically a low bound */
137 struct syslinux_memmap *mmap;
138 struct syslinux_movelist *mlist = NULL;
142 mmap = syslinux_memory_map();
145 error("Cannot read system memory map\n");
150 for (i = 0; i < ndata; i++) {
151 if (data[i].base + data[i].size > endimage)
152 endimage = data[i].base + data[i].size;
154 if (endimage > dosmem)
157 for (i = 0; i < ndata; i++) {
158 if (syslinux_add_movelist(&mlist, data[i].base,
159 (addr_t) data[i].data, data[i].size))
164 /* Tell the shuffler not to muck with this area... */
165 syslinux_add_memmap(&mmap, endimage, 0xa0000 - endimage, SMT_RESERVED);
167 /* Force text mode */
168 syslinux_force_text_mode();
170 fputs("Booting...\n", stdout);
171 syslinux_shuffle_boot_rm(mlist, mmap, 3, regs);
172 error("Chainboot failed!\n");
176 error("Loader file too large\n");
180 error("Out of memory\n");
187 " %s [OPTIONS]... _new-nbp_\n"
188 " %s -r _new-nbp_ (calls PXE stack PXENV_RESTART_TFTP)\n"
190 " [-c config] [-g gateway] [-p prefix] [-t reboot] [-u] [-w] [-W]"
191 " [-o opt.ty=val]\n\n",
192 app_name_str, app_name_str);
195 void pxe_error(int ierr, const char *evt, const char *msg)
200 printf("Error while %s: ", evt);
201 printf("%d:%s\n", ierr, strerror(ierr));
204 int pressanykey(clock_t tm) {
207 printf("Press any key to continue. ");
208 inc = get_key(stdin, tm);
213 int dhcp_find_opt(pxe_bootp_t *p, size_t len, uint8_t opt)
221 dprintf(" packet pointer is null\n");
224 vlen = len - ((void *)&(p->vendor) - (void *)p);
226 magic = ntohl(*((uint32_t *)d));
227 if (magic != VM_RFC1048) /* Invalid DHCP packet */
229 for (i = 4; i < vlen; i++) {
231 dprintf("\n @%03X-%2d\n", i, d[i]);
235 if (d[i] == ((NUM_DHCP_OPTS) - 1)) /* End of list */
237 if (d[i]) { /* Skip padding */
245 void print_pxe_vendor_raw(pxe_bootp_t *p, size_t len)
250 printf(" packet pointer is null\n");
253 vlen = len - ((void *)&(p->vendor) - (void *)p);
254 if (vlen > PXE_VENDOR_RAW_PRN_MAX)
255 vlen = PXE_VENDOR_RAW_PRN_MAX;
256 dprintf(" rawLen = %d", vlen);
257 for (i = 0; i < vlen; i++) {
259 printf("\n %04X:", i);
260 printf(" %02X", p->vendor.d[i]);
265 void print_pxe_vendor_blk(pxe_bootp_t *p, size_t len)
267 int i, vlen, oplen, j;
271 printf(" packet pointer is null\n");
274 vlen = len - ((void *)&(p->vendor) - (void *)p);
275 printf(" Vendor Data: Len=%d", vlen);
277 magic = ntohl(*((uint32_t *)d));
278 printf(" Magic: %08X", ntohl(*((uint32_t *)d)));
279 if (magic != VM_RFC1048) /* Invalid DHCP packet */
281 for (i = 4; i < vlen; i++) {
282 if (d[i]) /* Skip the padding */
283 printf("\n @%03X-%3d", i, d[i]);
284 if (d[i] == ((NUM_DHCP_OPTS) - 1)) /* End of list */
288 printf(" l=%3d:", oplen);
289 for (j = (++i + oplen); i < vlen && i < j; i++) {
290 printf(" %02X", d[i]);
298 void print_pxe_bootp_t(pxe_bootp_t *p, size_t len)
300 if (!p || len <= 0) {
301 printf(" packet pointer is null\n");
304 printf(" op:%02X hw:%02X hl:%02X gh:%02X id:%08X se:%04X f:%04X"
305 " cip:%08X\n", p->opcode, p->Hardware, p->Hardlen, p->Gatehops,
306 ntohl(p->ident), ntohs(p->seconds), ntohs(p->Flags), ntohl(p->cip));
307 printf(" yip:%08X sip:%08X gip:%08X",
308 ntohl(p->yip), ntohl(p->sip), ntohl(p->gip));
309 printf(" caddr-%02X:%02X:%02X:%02X:%02X:%02X\n", p->CAddr[0],
310 p->CAddr[1], p->CAddr[2], p->CAddr[3], p->CAddr[4], p->CAddr[5]);
311 printf(" sName: '%s'\n", p->Sname);
312 printf(" bootfile: '%s'\n", p->bootfile);
313 dprint_pxe_vendor_blk(p, len);
316 void pxe_set_regs(struct syslinux_rm_regs *regs)
321 /* Plan A uses SS:[SP + 4] */
322 /* sdi->pxe.stack is a usable pointer, not something that can be nicely
323 and reliably split to SS:SP without causing issues */
324 tregs.eax.l = 0x000A;
325 __intcall(0x22, &tregs, &tregs);
327 regs->esp.l = tregs.esi.w[0] + sizeof(tregs);
328 /* Plan B uses [ES:BX] */
330 regs->ebx = tregs.ebx;
331 dprintf("\nsp:%04x ss:%04x es:%04x bx:%04x\n", regs->esp.w[0],
332 regs->ss, regs->es, regs->ebx.w[0]);
333 /* Zero out everything else just to be sure */
334 regs->cs = regs->ds = regs->fs = regs->gs = 0;
335 regs->eax.l = regs->ecx.l = regs->edx.l = 0;
338 int hostlen_limit(int len)
340 return min(len, ((PXECHN_HOST_LEN) - 1));
343 //FIXME: To a library
344 /* Parse a filename into an IPv4 address and filename pointer
345 * returns Based on the interpretation of fn
346 * 0 regular file name
352 * -1 if fn is another URL type
354 int pxechn_parse_fn(char fn[], in_addr_t *fip, char *host, char *fp[])
357 char *csep, *ssep, *hsep; /* Colon, Slash separator positions */
358 int hlen, plen; /* Hostname, protocol length */
361 csep = strchr(fn, ':');
363 if (csep[1] == ':') { /* assume IP::FN */
367 hlen = hostlen_limit(csep - fn);
368 memcpy(host, fn, hlen);
371 } else if ((csep[1] == '/') && (csep[2] == '/')) {
372 /* URL: proto://host:port/path/file */
373 /* proto://[user[:passwd]@]host[:port]/path/file */
374 ssep = strchr(csep + 3, '/');
376 hlen = hostlen_limit(ssep - (csep + 3));
379 hlen = hostlen_limit(strlen(csep + 3));
381 memcpy(host, (csep + 3), hlen);
384 if (strncmp(fn, "tftp", plen) == 0)
386 else if (strncmp(fn, "http", plen) == 0)
388 else if (strncmp(fn, "ftp", plen) == 0)
390 else if (strncmp(fn, "https", plen) == 0)
391 rv = 3 + ( 1 << 30 );
402 hsep = strchr(host, '@');
409 dprintf0(" host '%s'\n fp '%s'\n fip %08x\n", host, *fp, ntohl(*fip));
413 void pxechn_opt_free(struct dhcp_option *opt)
419 void pxechn_fill_pkt(struct pxelinux_opt *pxe, int ptype)
423 if ((ptype < 0) || (ptype > PXECHN_NUM_PKT_TYPE))
425 p1 = ptype - PXECHN_PKT_TYPE_START;
426 p2 = p1 + PXECHN_NUM_PKT_TYPE;
427 if ((rv >= -1) && (!pxe_get_cached_info(ptype,
428 (void **)&(pxe->p[p1].data), (size_t *)&(pxe->p[p1].len)))) {
429 pxe->p[p2].data = malloc(2048);
430 if (pxe->p[p2].data) {
431 memcpy(pxe->p[p2].data, pxe->p[p1].data, pxe->p[p1].len);
432 pxe->p[p2].len = pxe->p[p1].len;
434 dprint_pxe_bootp_t((pxe_bootp_t *)(pxe->p[p1].data), pxe->p[p1].len);
435 dpressanykey(INT_MAX);
437 printf("%s: ERROR: Unable to malloc() for second packet\n", app_name_str);
440 printf("%s: ERROR: Unable to retrieve first packet\n", app_name_str);
443 pxechn_opt_free(&pxe->p[p1]);
447 void pxechn_init(struct pxelinux_opt *pxe)
449 /* Init for paranoia */
457 pxe->host[((NUM_DHCP_OPTS) - 1)] = 0;
458 for (int j = 0; j < PXECHN_NUM_PKT_TYPE; j++){
459 for (int i = 0; i < NUM_DHCP_OPTS; i++) {
460 pxe->opts[j][i].data = NULL;
461 pxe->opts[j][i].len = -1;
463 pxe->p_unpacked[j] = 0;
464 pxe->p[j].data = NULL;
465 pxe->p[j+PXECHN_NUM_PKT_TYPE].data = NULL;
467 pxe->p[j+PXECHN_NUM_PKT_TYPE].len = 0;
469 pxechn_fill_pkt(pxe, PXENV_PACKET_TYPE_CACHED_REPLY);
472 int pxechn_to_hex(char i)
474 if (i >= '0' && i <= '9')
476 if (i >= 'A' && i <= 'F')
477 return (i - 'A' + 10);
478 if (i >= 'a' && i <= 'f')
479 return (i - 'a' + 10);
485 int pxechn_parse_2bhex(char ins[])
488 int n0 = -3, n1 = -3;
492 /* pxechn_to_hex can handle the NULL character by returning -1 and
493 breaking the execution of the statement chain */
494 } else if (((n0 = pxechn_to_hex(ins[0])) >= 0)
495 && ((n1 = pxechn_to_hex(ins[1])) >= 0)) {
496 ret = (n0 * 16) + n1;
497 } else if (n0 == -1) { /* Leading NULL char */
503 int pxechn_optnum_ok(int optnum)
505 if ((optnum > 0) && (optnum < ((NUM_DHCP_OPTS) - 1)))
510 int pxechn_optnum_ok_notres(int optnum)
512 if ((optnum <= 0) && (optnum >= ((NUM_DHCP_OPTS) - 1)))
522 int pxechn_optlen_ok(int optlen)
524 if ((optlen >= 0) && (optlen < ((DHCP_OPT_LEN_MAX) - 1)))
529 int pxechn_setopt(struct dhcp_option *opt, void *data, int len)
537 p = realloc(opt->data, len);
538 if (!p && len) { /* Allow for len=0 */
539 pxechn_opt_free(opt);
543 memcpy(opt->data, data, len);
548 int pxechn_setopt_str(struct dhcp_option *opt, void *data)
550 return pxechn_setopt(opt, data, strnlen(data, DHCP_OPT_LEN_MAX));
553 int pxechn_parse_int(char *data, char istr[], int tlen)
557 if ((tlen == 1) || (tlen == 2) || (tlen == 4)) {
559 uint32_t optval = strtoul(istr, NULL, 0);
565 if (optval & 0xFFFFFF00)
569 if (optval & 0xFFFF0000)
571 optval = htons(optval);
574 optval = htonl(optval);
577 memcpy(data, &optval, tlen);
578 } else if (tlen == 8) {
580 uint64_t optval = strtoull(istr, NULL, 0);
584 optval = htonq(optval);
585 memcpy(data, &optval, tlen);
592 int pxechn_parse_hex_sep(char *data, char istr[], char sep)
599 while ((istr[ipos]) && (len < DHCP_OPT_LEN_MAX)) {
600 dprintf(" %02X%02X", *((int *)(istr + ipos)) & 0xFF, *((int *)(istr + ipos +1)) & 0xFF);
601 ichar = pxechn_parse_2bhex(istr + ipos);
609 } else if (istr[ipos+2] != sep) {
610 return -(EINVAL + 1);
618 int pxechn_parse_opttype(char istr[], int optnum)
621 int tlen, type, tmask;
625 pos = strchr(istr, '=');
628 if (istr[0] != '.') {
629 if (!pxechn_optnum_ok(optnum))
631 return -3; /* do lookup here */
633 tlen = pos - istr - 1;
634 if ((tlen < 1) || (tlen > 4))
636 tmask = 0xFFFFFFFF >> (8 * (4 - tlen));
637 type = (*(int*)(istr + 1)) & tmask;
642 int pxechn_parse_setopt(struct dhcp_option opts[], struct dhcp_option *iopt,
645 int rv = 0, optnum, opttype;
646 char *cpos = NULL, *pos;
648 if (!opts || !iopt || !(iopt->data))
650 if (!istr || !istr[0])
653 optnum = strtoul(istr, &cpos, 0);
654 if (!pxechn_optnum_ok(optnum))
656 pos = strchr(cpos, '=');
659 opttype = pxechn_parse_opttype(cpos, optnum);
663 iopt->len = pxechn_parse_int(iopt->data, pos, 1);
666 iopt->len = pxechn_parse_int(iopt->data, pos, 4);
669 iopt->len = pxechn_parse_int(iopt->data, pos, 8);
673 iopt->len = strlen(pos);
674 if (iopt->len > DHCP_OPT_LEN_MAX)
675 iopt->len = DHCP_OPT_LEN_MAX;
676 memcpy(iopt->data, pos, iopt->len);
677 dprintf_pc_so_s("s.len=%d\trv=%d\n", iopt->len, rv);
680 iopt->len = pxechn_parse_int(iopt->data, pos, 2);
683 iopt->len = pxechn_parse_hex_sep(iopt->data, pos, ':');
689 if (pxechn_optlen_ok(iopt->len)) {
690 rv = pxechn_setopt(&(opts[optnum]), (void *)(iopt->data), iopt->len);
692 if((opttype == 's') || (opttype == STRASINT_str))
693 dprintf_pc_so_s("rv=%d\n", rv);
697 int pxechn_parse_force(const char istr[])
704 rv = strtoul(istr, &pos, 0);
705 if ((istr == pos ) || ((rv == ULONG_MAX) && (errno)))
711 int pxechn_uuid_set(struct pxelinux_opt *pxe)
715 if (!pxe->p_unpacked[0])
716 ret = dhcp_unpack_packet((pxe_bootp_t *)(pxe->p[0].data),
717 pxe->p[0].len, pxe->opts[0]);
719 error("Could not unpack packet\n");
720 return -ret; /* dhcp_unpack_packet always returns positive errors */
723 if (pxe->opts[0][97].len >= 0 )
724 pxechn_setopt(&(pxe->opts[2][97]), pxe->opts[0][97].data, pxe->opts[0][97].len);
729 int pxechn_parse_args(int argc, char *argv[], struct pxelinux_opt *pxe,
730 struct dhcp_option opts[])
732 int arg, optnum, rv = 0;
734 const char optstr[] = "c:f:g:o:p:t:uwW";
735 struct dhcp_option iopt;
738 pxe->fip = ( (pxe_bootp_t *)(pxe->p[5].data) )->sip;
743 pxechn_parse_fn(pxe->fn, &(pxe->fip), pxe->host, &(pxe->fp));
744 pxechn_setopt_str(&(opts[67]), pxe->fp);
745 pxechn_setopt_str(&(opts[66]), pxe->host);
746 iopt.data = malloc(DHCP_OPT_LEN_MAX);
748 while ((rv >= 0) && (arg = getopt(argc, argv, optstr)) >= 0) {
749 dprintf_pc_pa(" Got arg '%c'/'%c' addr %08X val %s\n", arg == '?' ? optopt : arg, arg, (unsigned int)optarg, optarg ? optarg : "");
751 case 'c': /* config */
752 pxechn_setopt_str(&(opts[209]), optarg);
754 case 'f': /* force */
755 pxe->force = pxechn_parse_force(optarg);
757 case 'g': /* gateway/DHCP relay */
758 pxe->gip = pxe_dns(optarg);
760 case 'n': /* native */
762 case 'o': /* option */
763 rv = pxechn_parse_setopt(opts, &iopt, optarg);
765 case 'p': /* prefix */
766 pxechn_setopt_str(&(opts[210]), optarg);
768 case 't': /* timeout */
769 optnum = strtoul(optarg, &p, 0);
771 optnum = htonl(optnum);
772 pxechn_setopt(&(opts[211]), (void *)(&optnum), 4);
777 case 'u': /* UUID: copy option 97 from packet 1 if present */
778 pxechn_uuid_set(pxe);
791 if (rv >= 0) /* Clear it since getopt() doesn't guarentee it */
795 pxechn_opt_free(&iopt);
796 /* FIXME: consider reordering the application of parsed command line options
797 such that the new nbp may be at the end */
800 } else if (arg != '?') {
801 printf("Invalid argument for -%c: %s\n", arg, optarg);
803 dprintf("pxechn_parse_args rv=%d\n", rv);
807 int pxechn_args(int argc, char *argv[], struct pxelinux_opt *pxe)
809 pxe_bootp_t *bootp0, *bootp1;
811 struct dhcp_option *opts;
814 /* Start filling packet #1 */
815 bootp0 = (pxe_bootp_t *)(pxe->p[2].data);
816 bootp1 = (pxe_bootp_t *)(pxe->p[5].data);
818 ret = dhcp_unpack_packet(bootp0, pxe->p[2].len, opts);
820 error("Could not unpack packet\n");
823 pxe->p_unpacked[2] = 1;
824 pxe->gip = bootp1->gip;
826 ret = pxechn_parse_args(argc, argv, pxe, opts);
829 bootp1->sip = pxe->fip;
830 bootp1->gip = pxe->gip;
832 ret = dhcp_pack_packet(bootp1, (size_t *)&(pxe->p[5].len), opts);
834 error("Could not pack packet\n");
835 return -ret; /* dhcp_pack_packet always returns positive errors */
840 /* dhcp_pkt2pxe: Copy packet to PXE's BC data for a ptype packet
842 * p Packet data to copy
843 * len length of data to copy
844 * ptype Packet type to overwrite
846 int dhcp_pkt2pxe(pxe_bootp_t *p, size_t len, int ptype)
849 t_PXENV_GET_CACHED_INFO *ci;
853 if (!(ci = lzalloc(sizeof(t_PXENV_GET_CACHED_INFO)))){
854 dprintf("Unable to lzalloc() for PXE call structure\n");
858 ci->Status = PXENV_STATUS_FAILURE;
859 ci->PacketType = ptype;
860 memset(®, 0, sizeof(reg));
861 reg.eax.w[0] = 0x0009;
862 reg.ebx.w[0] = PXENV_GET_CACHED_INFO;
863 reg.edi.w[0] = OFFS(ci);
865 __intcall(0x22, ®, ®);
867 if (ci->Status != PXENV_STATUS_SUCCESS) {
868 dprintf("PXE Get Cached Info failed: %d\n", ci->Status);
873 cp = MK_PTR(ci->Buffer.seg, ci->Buffer.offs);
874 if (!(memcpy(cp, p, len))) {
875 dprintf("Failed to copy packet\n");
884 int pxechn_mergeopt(struct pxelinux_opt *pxe, int d, int s)
888 if ((d >= PXECHN_NUM_PKT_TYPE) || (s >= PXECHN_NUM_PKT_TYPE)
889 || (d < 0) || (s < 0)) {
892 if (!pxe->p_unpacked[s])
893 ret = dhcp_unpack_packet(pxe->p[s].data, pxe->p[s].len, pxe->opts[s]);
895 error("Could not unpack packet for merge\n");
896 printf("Error %d (%d)\n", ret, EINVAL);
898 if (pxe->p[s].len < 240)
899 printf("Packet %d is too short: %d (240)\n", s, pxe->p[s].len);
900 else if (((const struct dhcp_packet *)(pxe->p[s].data))->magic != htonl(DHCP_VENDOR_MAGIC))
901 printf("Packet %d has no magic\n", s);
903 error("Unknown EINVAL error\n");
905 error("Unknown error\n");
909 for (i = 0; i < NUM_DHCP_OPTS; i++) {
910 if (pxe->opts[d][i].len <= -1) {
911 if (pxe->opts[s][i].len >= 0)
912 pxechn_setopt(&(pxe->opts[d][i]), pxe->opts[s][i].data, pxe->opts[s][i].len);
918 /* pxechn: Chainload to new PXE file ourselves
920 * argc Count of arguments passed
921 * argv Values of arguments passed
922 * Returns 0 on success (which should never happen)
923 * 1 on loadfile() error
924 * 2 if DHCP Option 52 (Option Overload) used file field
927 int pxechn(int argc, char *argv[])
929 struct pxelinux_opt pxe;
930 pxe_bootp_t* p[(2 * PXECHN_NUM_PKT_TYPE)];
933 struct data_area file;
934 struct syslinux_rm_regs regs;
937 for (i = 0; i < (2 * PXECHN_NUM_PKT_TYPE); i++) {
938 p[i] = (pxe_bootp_t *)(pxe.p[i].data);
941 /* Parse arguments and patch packet 1 */
942 rv = pxechn_args(argc, argv, &pxe);
943 dpressanykey(INT_MAX);
947 /* Load the file late; it's the most time-expensive operation */
948 printf("%s: Attempting to load '%s': ", app_name_str, pxe.fn);
949 if (loadfile(pxe.fn, &file.data, &file.size)) {
950 pxe_error(errno, NULL, NULL);
955 /* we'll be shuffling to the standard location of 7C00h */
958 ((pxe.force) && ((pxe.force & (~PXECHN_FORCE_ALL)) == 0))) {
959 printf("Forcing behavior %08X\n", pxe.force);
960 // P2 is the same as P3 if no PXE server present.
962 (pxe.force & PXECHN_FORCE_PKT2)) {
963 pxechn_fill_pkt(&pxe, PXENV_PACKET_TYPE_DHCP_ACK);
964 rv = pxechn_mergeopt(&pxe, 2, 1);
966 dprintf("Merge Option returned %d\n", rv);
968 rv = dhcp_pack_packet(p[5], (size_t *)&(pxe.p[5].len), pxe.opts[2]);
969 rv = dhcp_pkt2pxe(p[5], pxe.p[5].len, PXENV_PACKET_TYPE_DHCP_ACK);
971 if (pxe.force & PXECHN_FORCE_PKT1) {
972 puts("Unimplemented force option utilized");
975 rv = dhcp_pkt2pxe(p[5], pxe.p[5].len, PXENV_PACKET_TYPE_CACHED_REPLY);
976 dprint_pxe_bootp_t(p[5], pxe.p[5].len);
978 ((pxe.force) && ((pxe.force & (~PXECHN_FORCE_ALL)) == 0))) {
979 // printf("Forcing behavior %08X\n", pxe.force);
980 // P2 is the same as P3 if no PXE server present.
982 (pxe.force & PXECHN_FORCE_PKT2)) {
983 rv = dhcp_pkt2pxe(p[5], pxe.p[5].len, PXENV_PACKET_TYPE_DHCP_ACK);
985 } else if (pxe.force) {
986 printf("FORCE: bad argument %08X\n", pxe.force);
988 printf("\n...Ready to boot:\n");
990 pressanykey(INT_MAX);
992 dpressanykey(INT_MAX);
995 puts(" Attempting to boot...");
996 do_boot(&file, 1, ®s);
998 /* If failed, copy backup back in and abort */
999 dhcp_pkt2pxe(p[2], pxe.p[2].len, PXENV_PACKET_TYPE_CACHED_REPLY);
1000 if (pxe.force && ((pxe.force & (~PXECHN_FORCE_ALL)) == 0)) {
1001 if (pxe.force & PXECHN_FORCE_PKT2) {
1002 rv = dhcp_pkt2pxe(p[1], pxe.p[1].len, PXENV_PACKET_TYPE_DHCP_ACK);
1009 /* pxe_restart: Restart the PXE environment with a new PXE file
1011 * ifn Name of file to chainload to in a format PXELINUX understands
1012 * This must strictly be TFTP or relative file
1014 int pxe_restart(char *ifn)
1017 struct pxelinux_opt pxe;
1019 t_PXENV_RESTART_TFTP *pxep; /* PXENV callback Parameter */
1022 pxechn_fill_pkt(&pxe, PXENV_PACKET_TYPE_CACHED_REPLY);
1024 pxe.fip = ( (pxe_bootp_t *)(pxe.p[5].data) )->sip;
1027 rv = pxechn_parse_fn(pxe.fn, &(pxe.fip), pxe.host, &(pxe.fp));
1028 if ((rv > 2) || (rv < 0)) {
1029 printf("%s: ERROR: Unparsable filename argument: '%s'\n\n", app_name_str, pxe.fn);
1032 printf(" Attempting to boot '%s'...\n\n", pxe.fn);
1033 memset(®, 0, sizeof reg);
1034 if (sizeof(t_PXENV_TFTP_READ_FILE) <= __com32.cs_bounce_size) {
1035 pxep = __com32.cs_bounce;
1036 memset(pxep, 0, sizeof(t_PXENV_RESTART_TFTP));
1037 } else if (!(pxep = lzalloc(sizeof(t_PXENV_RESTART_TFTP)))){
1038 dprintf("Unable to lzalloc() for PXE call structure\n");
1041 pxep->Status = PXENV_STATUS_SUCCESS; /* PXENV_STATUS_FAILURE */
1042 strcpy((char *)pxep->FileName, ifn);
1043 pxep->BufferSize = 0x8000;
1044 pxep->Buffer = (void *)0x7c00;
1045 pxep->ServerIPAddress = pxe.fip;
1046 dprintf("FN='%s' %08X %08X %08X %08X\n\n", (char *)pxep->FileName,
1047 pxep->ServerIPAddress, (unsigned int)pxep,
1048 pxep->BufferSize, (unsigned int)pxep->Buffer);
1049 dprintf("PXENV_RESTART_TFTP status %d\n", pxep->Status);
1050 reg.eax.w[0] = 0x0009;
1051 reg.ebx.w[0] = PXENV_RESTART_TFTP;
1052 reg.edi.w[0] = OFFS(pxep);
1055 __intcall(0x22, ®, ®);
1057 printf("PXENV_RESTART_TFTP returned %d\n", pxep->Status);
1058 if (pxep != __com32.cs_bounce)
1065 /* pxechn_gpxe: Use gPXE to chainload a new NBP
1067 * argc Count of arguments passed
1068 * argv Values of arguments passed
1069 * Returns 0 on success (which should never happen)
1070 * 1 on loadfile() error
1074 int pxechn_gpxe(int argc, char *argv[])
1077 struct pxelinux_opt pxe;
1080 printf("%s\n", argv[0]);
1081 pxechn_args(argc, argv, &pxe);
1086 int main(int argc, char *argv[])
1090 const struct syslinux_version *sv;
1092 /* Initialization */
1094 console_ansi_raw(); /* sets errno = 9 (EBADF) */
1095 /* printf("%d %d\n", err, errno); */
1097 sv = syslinux_version();
1098 if (sv->filesystem != SYSLINUX_FS_PXELINUX) {
1099 printf("%s: May only run in PXELINUX\n", app_name_str);
1100 argc = 1; /* prevents further processing to boot */
1103 if ((strcasecmp(argv[1], "-h") == 0) || ((strcmp(argv[1], "-?") == 0))
1104 || (strcasecmp(argv[1], "--help") == 0)) {
1107 rv = pxechn(argc - 1, &argv[1]);
1109 } else if (argc >= 3) {
1110 if ((strcmp(argv[1], "-r") == 0)) {
1112 rv = pxe_restart(argv[2]);
1114 rv = pxechn(argc - 1, &argv[1]);