/*
**************************************************************************
*
* Boot-ROM-Code to load an operating system across a TCP/IP network.
*
* Module: getvend.c
* Purpose: Get information out of BOOTP/DHCP answer
* Entries: get_vend
*
**************************************************************************
*
* Copyright (C) 1998-2003 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: getvend.c,v 1.4 2003/01/25 23:29:41 gkminix Exp $
*/
#include <general.h>
#include <kernel/net.h>
#include <kernel/arpa.h>
#include <kernel/romlib.h>
#include "bootp.h"
/*
**************************************************************************
*
* Variables local to this module
*/
static int lastbuf = -1; /* buffer with last requested ID */
static int lastid; /* last request ID */
static int overload; /* overload flags */
static unsigned char *pxeptr; /* pointer to PXE vendor record */
static unsigned char *lastptr; /* pointer to last requested ID */
/*
**************************************************************************
*
* Find a tag in the BOOTP/DHCP record.
*
*/
static unsigned char *find_tag(id, startp, endp)
int id;
unsigned char *startp;
unsigned char *endp;
{
register unsigned char *cp = startp;
while (*cp != VEND_END && cp < endp) {
if (*cp != VEND_NOP) {
if (*cp == id)
break;
cp += *(cp + 1) + 1;
}
cp++;
}
return(*cp == id ? cp + 1 : NULL);
}
/*
**************************************************************************
*
* Find a tag either in the vendor information area or the boot filename
* or server name fields.
*/
static unsigned char *search_tag(id, lastp)
int id;
unsigned char *lastp;
{
register unsigned char *cp;
unsigned char *startp, *endp;
unsigned char *retp = NULL;
/* Setup start and end pointers */
startp = bootp_bufs[cur_bootp_buf]->bp_vend + VM_SIZE;
endp = (unsigned char *)(bootp_bufs[cur_bootp_buf]) +
bootp_sizes[cur_bootp_buf];
/* Search for the tag in the vendor extension area */
if (lastp == NULL)
retp = find_tag(id, startp, endp);
else if (lastp >= startp && lastp < endp)
retp = find_tag(id, lastp, endp);
/* Only search overload areas for valid tags, not NOP, END etc. */
if (id != VEND_NOP && id != VEND_END && id != VEND_OVERLOAD) {
/* Search for the tag in the filename area if buffer is overloaded */
if (retp == NULL && (overload & VEND_OVR_FILE)) {
cp = bootp_bufs[cur_bootp_buf]->bp_file;
if (lastp == NULL)
retp = find_tag(id, cp, cp + BOOTP_FILE_SIZE);
else if (lastp >= cp && lastp < (cp + BOOTP_FILE_SIZE))
retp = find_tag(id, lastp, cp + BOOTP_FILE_SIZE);
}
/* Search for the tag in the server name area if buffer is overloaded */
if (retp == NULL && (overload & VEND_OVR_SNAME)) {
cp = bootp_bufs[cur_bootp_buf]->bp_sname;
if (lastp == NULL)
retp = find_tag(id, cp, cp + BOOTP_SNAME_SIZE);
else if (lastp >= cp && lastp < (cp + BOOTP_SNAME_SIZE))
retp = find_tag(id, lastp, cp + BOOTP_SNAME_SIZE);
}
}
return(retp);
}
/*
**************************************************************************
*
* Return the overload flag of a BOOTP/DHCP buffer
*/
static void check_overload()
{
register unsigned char *cp;
overload = 0;
cp = search_tag(VEND_OVERLOAD, NULL);
if (cp != NULL) {
cp++;
overload = *cp;
}
}
/*
**************************************************************************
*
* Check if we have PXE vendor extensions
*/
static void check_pxe()
{
register unsigned char *cp;
pxeptr = NULL;
cp = search_tag(VEND_CLASS, NULL);
if (cp != NULL && *cp == VEND_PXE_STRLEN) {
cp++;
if (!memcmp(cp, VEND_PXE_STRING, VEND_PXE_STRLEN))
pxeptr = search_tag(VEND_VENDOR, NULL);
}
}
/*
**************************************************************************
*
* Return information from the vendor area of a BOOTP/DHCP record. Note
* that this will work only with RFC1048-compliant messages.
* It will return a pointer to the length byte of the tag.
*
*/
unsigned char *get_vend(id)
int id;
{
register unsigned char *cp;
unsigned char *endp;
unsigned char *retp = NULL;
cp = (unsigned char *)(bootp_bufs[cur_bootp_buf]);
if (cp != NULL) {
cp = bootp_bufs[cur_bootp_buf]->bp_vend;
if (*cp) {
/* Check if we are accessing the same buffer as before */
if (lastbuf != cur_bootp_buf) {
lastbuf = cur_bootp_buf;
lastptr = NULL;
check_overload();
check_pxe();
} else {
/* Determine start address for new search */
if (lastid != id)
lastptr = NULL;
else if (lastptr != NULL)
lastptr += *lastptr + 1;
}
/* Now actually search for the tag, NOP just recycles */
if (id == VEND_NOP)
retp = NULL;
else if (id < VEND_PXE_BASE)
retp = search_tag(id, lastptr);
else if (pxeptr != NULL) {
cp = pxeptr;
endp = cp + *cp + 1;
cp++;
if (lastptr == NULL)
retp = find_tag(id & VEND_PXE_MASK, cp, endp);
else if (lastptr >= cp && lastptr < endp)
retp = find_tag(id & VEND_PXE_MASK,
lastptr, endp);
}
}
}
lastid = id;
lastptr = retp;
return(retp);
}
syntax highlighted by Code2HTML, v. 0.9.1