/* vim: set filetype=c:
 *
 **************************************************************************
 *
 * Boot-ROM-Code to load an operating system across a TCP/IP network.
 *
 * Module:  getext.c86
 * Purpose: Get BOOTP vendor extensions file
 * Entries: get_ext
 *
 **************************************************************************
 *
 * Copyright (C) 1995-2007 Gero Kuhlmann <gero@gkminix.han.de>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * $Id: getext.c86,v 1.6 2007/01/06 18:30:46 gkminix Exp $
 *
 **************************************************************************
 *
 * We can print error messages within this module as it gets never called
 * by a PXE function.
 */


#include <common.h86>
#include <romconfig.h86>
#include <i386/string.h86>
#include <i386/conio.h86>
#include <i386/misc.h86>
#include <pxe/general.h86>
#include <pxe/tftp.h86>
#include "headers/net.h86"
#include "headers/arpa.h86"
#include "bootp.h86"



/*
 **************************************************************************
 * 
 * Get vendor extensions file with TFTP. Note that this routine should only
 * be called when using the BOOTP protocol. For DHCP this feature is not to be
 * used.
 */
void get_ext(const __u8 *ftag)
{
  __u8 *cp, *endp;
  t_tftp_read_file params;
  short i;

  /*
   * Determine address where to load the extension file. If the END tag
   * can't be found we silently return like when no extension file has
   * been given.
   */
  if ((endp = get_vend(VEND_RFC_END)) == NULL)
	return;
  endp--;

  /*
   * Setup parameter structure for TFTP transfer. The bootp_sizes value for
   * a buffer can never exceed BOOTP_MAX_SIZE.
   */
  memset(&params, 0, sizeof(params));
  if ((i = *ftag) > (short)(sizeof(params.filename) - 1))
	i = sizeof(params.filename) - 1;
  memcpy(params.filename, ftag + 1, i);
  params.server = bootp_bufs[cur_bootp_buf]->bp_siaddr;
  params.gateway = htonl(IP_ANY);
  params.buffer = far2linear(MK_FP(getds(), endp));
  params.bufsize = (__u32)((__u8 *)(bootp_bufs[cur_bootp_buf]) +
					bootp_sizes[cur_bootp_buf] - endp);

  /*
   * If the buffer size available is not sufficient for at least a minimal
   * extensions file, return as if no extensions file has been specified.
   */
  if (params.bufsize < (BOOTP_VM_SIZE + 2))
	return;

  /*
   * Now read the file via TFTP
   */
  printf("BOOTP: Loading %s: ", params.filename);
  if ((i = tftp_read_file(&params)) != PXENV_STATUS_SUCCESS) {
	printf("TFTP error %x", i);
	goto getext_err;
  }

  /*
   * Check that the file starts with the correct vendor extension. If it
   * does, overwrite the signature with all NOPs so that the record
   * becomes valid.
   */
  cp = endp;
  if (params.bufsize < (BOOTP_VM_SIZE + 1) ||
      *((__u32 *)cp) != BOOTP_VM_RFC1048) {
	printf("Invalid file");
	goto getext_err;
  }
  *((__u32 *)cp) = ((VEND_RFC_NOP << 24) & 0xFF000000UL) |
                   ((VEND_RFC_NOP << 16) & 0x00FF0000UL) |
                   ((VEND_RFC_NOP << 8)  & 0x0000FF00UL) |
                   ((VEND_RFC_NOP)       & 0x000000FFUL);

  /* Finally check that we have an end identifier at all */
  (void)get_vend(VEND_RFC_NOP);
  if (get_vend(VEND_RFC_END) == NULL) {
	printf("No END tag");
	goto getext_err;
  }
  printf("ok\n");
  return;

getext_err:
  /* In case of error, restore the original BOOTP record */
  *endp = VEND_RFC_END;
  printf(", ignored\n");
}

