x86 efiboot: pass a filename to BOOTP and parse a DHCP server provided filename.

This commit is contained in:
nonaka 2019-09-26 12:21:03 +00:00
parent 067319d1de
commit fcd0bf31a0
5 changed files with 193 additions and 76 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: boot.c,v 1.16 2019/09/13 02:19:45 manu Exp $ */
/* $NetBSD: boot.c,v 1.17 2019/09/26 12:21:03 nonaka Exp $ */
/*-
* Copyright (c) 2016 Kimihiro Nonaka <nonaka@netbsd.org>
@ -111,6 +111,7 @@ const struct bootblk_command commands[] = {
{ NULL, NULL },
};
static char *default_fsname;
static char *default_devname;
static int default_unit, default_partition;
static const char *default_filename;
@ -125,8 +126,11 @@ parsebootfile(const char *fname, char **fsname, char **devname, int *unit,
{
const char *col;
static char savedevname[MAXDEVNAME+1];
#if defined(SUPPORT_NFS) || defined(SUPPORT_TFTP)
const struct netboot_fstab *nf;
#endif
*fsname = "ufs";
*fsname = default_fsname;
if (default_part_name == NULL) {
*devname = default_devname;
} else {
@ -152,6 +156,7 @@ parsebootfile(const char *fname, char **fsname, char **devname, int *unit,
if (strstr(fname, "NAME=") == fname) {
strlcpy(savedevname, fname, devlen + 1);
*fsname = "ufs";
*devname = savedevname;
*unit = -1;
*partition = -1;
@ -188,6 +193,13 @@ parsebootfile(const char *fname, char **fsname, char **devname, int *unit,
if (i != devlen)
return ENXIO;
#if defined(SUPPORT_NFS) || defined(SUPPORT_TFTP)
nf = netboot_fstab_find(savedevname);
if (nf != NULL)
*fsname = (char *)nf->name;
else
#endif
*fsname = "ufs";
*devname = savedevname;
*unit = u;
*partition = p;
@ -278,6 +290,9 @@ boot(void)
{
int currname;
int c;
#if defined(SUPPORT_NFS) || defined(SUPPORT_TFTP)
const struct netboot_fstab *nf;
#endif
boot_modules_enabled = !(boot_params.bp_flags & X86_BP_FLAGS_NOMODULES);
@ -288,6 +303,14 @@ boot(void)
/* if the user types "boot" without filename */
default_filename = DEFFILENAME;
#if defined(SUPPORT_NFS) || defined(SUPPORT_TFTP)
nf = netboot_fstab_find(default_devname);
if (nf != NULL)
default_fsname = (char *)nf->name;
else
#endif
default_fsname = "ufs";
if (!(boot_params.bp_flags & X86_BP_FLAGS_NOBOOTCONF)) {
#ifdef EFIBOOTCFG_FILENAME
int rv = EINVAL;
@ -456,7 +479,7 @@ command_dev(char *arg)
{
static char savedevname[MAXDEVNAME + 1];
char buf[80];
char *fsname, *devname;
char *devname;
const char *file; /* dummy */
if (*arg == '\0') {
@ -474,7 +497,7 @@ command_dev(char *arg)
}
if (strchr(arg, ':') == NULL ||
parsebootfile(arg, &fsname, &devname, &default_unit,
parsebootfile(arg, &default_fsname, &devname, &default_unit,
&default_partition, &file)) {
command_help(NULL);
return;

View File

@ -1,4 +1,4 @@
/* $NetBSD: conf.c,v 1.2 2018/04/11 10:32:09 nonaka Exp $ */
/* $NetBSD: conf.c,v 1.3 2019/09/26 12:21:03 nonaka Exp $ */
/*
* Copyright (c) 1997
@ -54,20 +54,23 @@
#endif
#endif
#include <biosdisk.h>
#include "devopen.h"
#include "efinet.h"
struct devsw devsw[] = {
{ "disk", biosdisk_strategy, biosdisk_open, biosdisk_close, biosdisk_ioctl },
#if defined(SUPPORT_NFS) || defined(SUPPORT_TFTP)
{ "net", net_strategy, net_open, net_close, net_ioctl },
#endif
};
int ndevs = __arraycount(devsw);
#if defined(SUPPORT_NFS) || defined(SUPPORT_TFTP)
struct netif_driver *netif_drivers[] = {
#if defined(SUPPORT_NFS) || defined(SUPPORT_TFTP)
&efinetif,
#endif
};
int n_netif_drivers = __arraycount(netif_drivers);
#endif
struct fs_ops file_system[] = {
#ifdef SUPPORT_CD9660
@ -113,3 +116,15 @@ struct fs_ops file_system_nfs = FS_OPS(nfs);
#ifdef SUPPORT_TFTP
struct fs_ops file_system_tftp = FS_OPS(tftp);
#endif
#if defined(SUPPORT_NFS) || defined(SUPPORT_TFTP)
const struct netboot_fstab netboot_fstab[] = {
#ifdef SUPPORT_NFS
{ "nfs", &file_system_nfs },
#endif
#ifdef SUPPORT_TFTP
{ "tftp", &file_system_tftp },
#endif
};
const int nnetboot_fstab = __arraycount(netboot_fstab);
#endif

View File

@ -1,4 +1,4 @@
/* $NetBSD: dev_net.c,v 1.2 2019/07/26 11:30:31 nonaka Exp $ */
/* $NetBSD: dev_net.c,v 1.3 2019/09/26 12:21:03 nonaka Exp $ */
/*-
* Copyright (c) 1997 The NetBSD Foundation, Inc.
@ -76,23 +76,23 @@ int
net_open(struct open_file *f, ...)
{
va_list ap;
char *devname; /* Device part of file name (or NULL). */
struct devdesc *dev;
int error = 0;
va_start(ap, f);
devname = va_arg(ap, char *);
dev = va_arg(ap, struct devdesc *);
va_end(ap);
#ifdef NETIF_DEBUG
if (debug)
printf("%s\n", devname);
printf("%s\n", dev->devname);
#endif
/* On first open, do netif open, mount, etc. */
if (netdev_opens == 0) {
/* Find network interface. */
if (netdev_sock < 0) {
netdev_sock = netif_open(devname);
netdev_sock = netif_open(dev);
if (netdev_sock < 0) {
printf("netif_open() failed\n");
return ENXIO;

View File

@ -1,4 +1,4 @@
/* $NetBSD: devopen.c,v 1.7 2019/09/02 06:10:24 manu Exp $ */
/* $NetBSD: devopen.c,v 1.8 2019/09/26 12:21:03 nonaka Exp $ */
/*-
* Copyright (c) 2005 The NetBSD Foundation, Inc.
@ -57,6 +57,7 @@
#include "efiboot.h"
#include <lib/libsa/dev_net.h>
#include <lib/libsa/net.h>
#include <biosdisk.h>
#include "devopen.h"
@ -106,6 +107,40 @@ bios2dev(int biosdev, daddr_t sector, char **devname, int *unit,
}
}
#if defined(SUPPORT_NFS) || defined(SUPPORT_TFTP)
const struct netboot_fstab *
netboot_fstab_find(const char *name)
{
int i;
if (strcmp(name, "net") == 0)
return &netboot_fstab[0];
for (i = 0; i < nnetboot_fstab; i++) {
if (strcmp(name, netboot_fstab[i].name) == 0)
return &netboot_fstab[i];
}
return NULL;
}
static const struct netboot_fstab *
netboot_fstab_findn(const char *name, size_t len)
{
int i;
if (strncmp(name, "net", len) == 0)
return &netboot_fstab[0];
for (i = 0; i < nnetboot_fstab; i++) {
if (strncmp(name, netboot_fstab[i].name, len) == 0)
return &netboot_fstab[i];
}
return NULL;
}
#endif
struct btinfo_bootpath bibp;
extern bool kernel_loaded;
@ -115,28 +150,27 @@ extern bool kernel_loaded;
int
devopen(struct open_file *f, const char *fname, char **file)
{
#if defined(SUPPORT_NFS) || defined(SUPPORT_TFTP)
static const char *net_devnames[] = {
#if defined(SUPPORT_NFS)
"nfs",
#endif
#if defined(SUPPORT_TFTP)
"tftp",
#endif
};
#endif
struct devdesc desc;
struct devsw *dev;
char *fsname, *devname;
int unit, partition;
int biosdev;
int i, n, error;
int i, error;
#if defined(SUPPORT_NFS) || defined(SUPPORT_TFTP)
struct devdesc desc;
const struct netboot_fstab *nf;
char *filename;
size_t fsnamelen;
int n;
#endif
error = parsebootfile(fname, &fsname, &devname, &unit, &partition,
(const char **) file);
if (error)
return error;
memcpy(file_system, file_system_disk,
sizeof(struct fs_ops) * nfsys_disk);
nfsys = nfsys_disk;
/* Search by GPT label or raidframe name */
if ((strstr(devname, "NAME=") == devname) ||
(strstr(devname, "raid") == devname)) {
@ -151,64 +185,99 @@ devopen(struct open_file *f, const char *fname, char **file)
return error;
}
memcpy(file_system, file_system_disk, sizeof(*file_system) * nfsys);
nfsys = nfsys_disk;
/*
* Network
*/
#if defined(SUPPORT_NFS) || defined(SUPPORT_TFTP)
for (i = 0; i < __arraycount(net_devnames); i++) {
if (strcmp(devname, net_devnames[i]) == 0) {
fsname = devname;
devname = "net";
break;
nf = netboot_fstab_find(devname);
if (nf != NULL) {
n = 0;
if (strcmp(devname, "net") == 0) {
for (i = 0; i < nnetboot_fstab; i++) {
memcpy(&file_system[n++], netboot_fstab[i].ops,
sizeof(struct fs_ops));
}
} else {
memcpy(&file_system[n++], nf->ops,
sizeof(struct fs_ops));
}
}
nfsys = n;
#ifdef SUPPORT_BOOTP
try_bootp = 1;
#endif
for (i = 1; i < ndevs; i++) {
dev = &devsw[i];
if (strcmp(devname, DEV_NAME(dev)) == 0) {
if (strcmp(devname, "net") == 0) {
n = 0;
#if defined(SUPPORT_NFS)
if (strcmp(fsname, "nfs") == 0) {
memcpy(&file_system[n++], &file_system_nfs,
sizeof(file_system_nfs));
} else
#endif
#if defined(SUPPORT_TFTP)
if (strcmp(fsname, "tftp") == 0) {
memcpy(&file_system[n++], &file_system_tftp,
sizeof(file_system_tftp));
} else
#endif
{
#if defined(SUPPORT_NFS)
memcpy(&file_system[n++], &file_system_nfs,
sizeof(file_system_nfs));
#endif
#if defined(SUPPORT_TFTP)
memcpy(&file_system[n++], &file_system_tftp,
sizeof(file_system_tftp));
#endif
}
nfsys = n;
/* If we got passed a filename, pass it to the BOOTP server. */
if (fname) {
filename = strchr(fname, ':');
if (filename != NULL)
filename++;
else
filename = (char *)fname;
strlcpy(bootfile, filename, sizeof(bootfile));
}
try_bootp = 1;
memset(&desc, 0, sizeof(desc));
strlcpy(desc.d_name, "net", sizeof(desc.d_name));
desc.d_unit = unit;
f->f_dev = &devsw[1]; /* must be net */
if (!kernel_loaded) {
strncpy(bibp.bootpath, *file, sizeof(bibp.bootpath));
BI_ADD(&bibp, BTINFO_BOOTPATH, sizeof(bibp));
}
error = DEV_OPEN(f->f_dev)(f, &desc);
if (error)
return error;
/*
* If the DHCP server provided a file name:
* - If it contains a ":", assume it points to a NetBSD kernel.
* - If not, assume that the DHCP server was not able to pass
* a separate filename for the kernel. (The name probably was
* the same as used to load "efiboot".) Ignore it and use
* the default in this case.
* So we cater to simple DHCP servers while being able to use
* the power of conditional behaviour in modern ones.
*/
filename = strchr(bootfile, ':');
if (filename != NULL) {
fname = bootfile;
fsnamelen = filename - fname;
nf = netboot_fstab_findn(fname, fsnamelen);
if (nf == NULL ||
strncmp(fname, "net", fsnamelen) == 0) {
printf("Invalid file system type specified in "
"%s\n", fname);
error = EINVAL;
goto neterr;
}
memset(&desc, 0, sizeof(desc));
strlcpy(desc.d_name, devname, sizeof(desc.d_name));
desc.d_unit = unit;
f->f_dev = dev;
if (!kernel_loaded) {
strncpy(bibp.bootpath, *file,
sizeof(bibp.bootpath));
BI_ADD(&bibp, BTINFO_BOOTPATH, sizeof(bibp));
}
return DEV_OPEN(f->f_dev)(f, &desc);
memcpy(file_system, nf->ops, sizeof(struct fs_ops));
nfsys = 1;
}
filename = fname ? strchr(fname, ':') : NULL;
if (filename != NULL) {
filename++;
if (*filename == '\0') {
printf("No file specified in %s\n", fname);
error = EINVAL;
goto neterr;
}
} else
filename = (char *)fname;
*file = filename;
return 0;
neterr:
DEV_CLOSE(f->f_dev)(f);
f->f_dev = NULL;
return error;
}
#endif
/*
* biosdisk

View File

@ -1,4 +1,4 @@
/* $NetBSD: devopen.h,v 1.4 2019/08/18 02:18:24 manu Exp $ */
/* $NetBSD: devopen.h,v 1.5 2019/09/26 12:21:03 nonaka Exp $ */
/*-
* Copyright (c) 2016 Kimihiro Nonaka <nonaka@netbsd.org>
@ -42,3 +42,13 @@ struct devdesc {
char d_name[MAXDEVNAME];
char d_unit;
};
struct netboot_fstab {
const char *name;
struct fs_ops *ops;
};
extern const struct netboot_fstab netboot_fstab[];
extern const int nnetboot_fstab;
const struct netboot_fstab *netboot_fstab_find(const char *);