/*
- * Copyright (c) 2001-2004 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2001-2019 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
- *
+ *
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* unlawful or unlicensed copies of an Apple operating system, or to
* circumvent, violate, or enable the circumvention or violation of, any
* terms of an Apple operating system software license agreement.
- *
+ *
* Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this file.
- *
+ *
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
- *
+ *
* @APPLE_OSREFERENCE_LICENSE_HEADER_END@
*/
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/reboot.h>
+#include <sys/kauth.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_types.h>
#include <netinet/in.h>
#include <netinet/if_ether.h>
#include <netinet/dhcp_options.h>
-#include <pexpert/pexpert.h>
#include <kern/kern_types.h>
#include <kern/kalloc.h>
+#include <sys/netboot.h>
+#include <sys/imageboot.h>
+#include <pexpert/pexpert.h>
-//#include <libkern/libkern.h>
-extern struct filedesc filedesc0;
-
-extern int strncmp(const char *,const char *, size_t);
-extern unsigned long strtoul(const char *, char **, int);
-extern char * strchr(const char *str, int ch);
-
-extern int nfs_mountroot(void); /* nfs_vfsops.c */
+extern int nfs_mountroot(void); /* nfs_vfsops.c */
extern int (*mountroot)(void);
-extern unsigned char rootdevice[];
+extern unsigned char rootdevice[];
-static int S_netboot = 0;
-static struct netboot_info * S_netboot_info_p;
+static int S_netboot = 0;
+static struct netboot_info * S_netboot_info_p;
void *
IOBSDRegistryEntryForDeviceTree(const char * path);
IOBSDRegistryEntryRelease(void * entry);
const void *
-IOBSDRegistryEntryGetData(void * entry, const char * property_name,
- int * packet_length);
+IOBSDRegistryEntryGetData(void * entry, const char * property_name,
+ int * packet_length);
-extern int vndevice_root_image(const char * path, char devname[],
- dev_t * dev_p);
-extern int di_root_image(const char *path, char devname[], dev_t *dev_p);
+#define BOOTP_RESPONSE "bootp-response"
+#define BSDP_RESPONSE "bsdp-response"
+#define DHCP_RESPONSE "dhcp-response"
-#define BOOTP_RESPONSE "bootp-response"
-#define BSDP_RESPONSE "bsdp-response"
-#define DHCP_RESPONSE "dhcp-response"
+#define IP_FORMAT "%d.%d.%d.%d"
+#define IP_CH(ip) ((u_char *)ip)
+#define IP_LIST(ip) IP_CH(ip)[0],IP_CH(ip)[1],IP_CH(ip)[2],IP_CH(ip)[3]
-extern int
-bootp(struct ifnet * ifp, struct in_addr * iaddr_p, int max_retry,
- struct in_addr * netmask_p, struct in_addr * router_p,
- struct proc * procp);
-
-
-/* forward declarations */
-int inet_aton(char * cp, struct in_addr * pin);
-
-boolean_t netboot_iaddr(struct in_addr * iaddr_p);
-boolean_t netboot_rootpath(struct in_addr * server_ip,
- char * name, int name_len,
- char * path, int path_len);
-int netboot_setup(struct proc * p);
-int netboot_mountroot(void);
-int netboot_root(void);
-
-
-
-#define IP_FORMAT "%d.%d.%d.%d"
-#define IP_CH(ip) ((u_char *)ip)
-#define IP_LIST(ip) IP_CH(ip)[0],IP_CH(ip)[1],IP_CH(ip)[2],IP_CH(ip)[3]
-
-#define kNetBootRootPathPrefixNFS "nfs:"
-#define kNetBootRootPathPrefixHTTP "http:"
+#define kNetBootRootPathPrefixNFS "nfs:"
+#define kNetBootRootPathPrefixHTTP "http:"
typedef enum {
- kNetBootImageTypeUnknown = 0,
- kNetBootImageTypeNFS = 1,
- kNetBootImageTypeHTTP = 2,
+ kNetBootImageTypeUnknown = 0,
+ kNetBootImageTypeNFS = 1,
+ kNetBootImageTypeHTTP = 2,
} NetBootImageType;
struct netboot_info {
- struct in_addr client_ip;
- struct in_addr server_ip;
- char * server_name;
- int server_name_length;
- char * mount_point;
- int mount_point_length;
- char * image_path;
- int image_path_length;
- NetBootImageType image_type;
- boolean_t use_hdix;
+ struct in_addr client_ip;
+ struct in_addr server_ip;
+ char * server_name;
+ size_t server_name_length;
+ char * mount_point;
+ size_t mount_point_length;
+ char * image_path;
+ size_t image_path_length;
+ NetBootImageType image_type;
+ char * second_image_path;
+ size_t second_image_path_length;
};
-int
-inet_aton(char * cp, struct in_addr * pin)
-{
- u_char * b = (char *)pin;
- int i;
- char * p;
-
- for (p = cp, i = 0; i < 4; i++) {
- u_long l = strtoul(p, 0, 0);
- if (l > 255)
- return (FALSE);
- b[i] = l;
- p = strchr(p, '.');
- if (i < 3 && p == NULL)
- return (FALSE);
- p++;
- }
- return (TRUE);
-}
-
/*
* Function: parse_booter_path
* Purpose:
*
* Note:
* The passed in string is modified i.e. ':' is replaced by '\0'.
- * Example:
+ * Example:
* "17.202.16.17:seaport:/release/.images/Image9/CurrentHera"
*/
static __inline__ boolean_t
-parse_booter_path(char * path, struct in_addr * iaddr_p, char * * host,
- char * * mount_dir, char * * image_path)
+parse_booter_path(char * path, struct in_addr * iaddr_p, char const * * host,
+ char * * mount_dir, char * * image_path)
{
- char * start;
- char * colon;
-
- /* IP address */
- start = path;
- colon = strchr(start, ':');
- if (colon == NULL) {
- return (FALSE);
- }
- *colon = '\0';
- if (inet_aton(start, iaddr_p) != 1) {
- return (FALSE);
- }
-
- /* host */
- start = colon + 1;
- colon = strchr(start, ':');
- if (colon == NULL) {
- return (FALSE);
- }
- *colon = '\0';
- *host = start;
-
- /* mount */
- start = colon + 1;
- colon = strchr(start, ':');
- *mount_dir = start;
- if (colon == NULL) {
- *image_path = NULL;
- }
- else {
- /* image path */
+ char * start;
+ char * colon;
+
+ /* IP address */
+ start = path;
+ colon = strchr(start, ':');
+ if (colon == NULL) {
+ return FALSE;
+ }
+ *colon = '\0';
+ if (inet_aton(start, iaddr_p) != 1) {
+ return FALSE;
+ }
+
+ /* host */
+ start = colon + 1;
+ colon = strchr(start, ':');
+ if (colon == NULL) {
+ return FALSE;
+ }
*colon = '\0';
+ *host = start;
+
+ /* mount */
start = colon + 1;
- *image_path = start;
- }
- return (TRUE);
+ colon = strchr(start, ':');
+ *mount_dir = start;
+ if (colon == NULL) {
+ *image_path = NULL;
+ } else {
+ /* image path */
+ *colon = '\0';
+ start = colon + 1;
+ *image_path = start;
+ }
+ return TRUE;
}
/*
static __inline__ char *
find_colon(char * str)
{
- char * start = str;
- char * colon;
-
- while ((colon = strchr(start, ':')) != NULL) {
- char * dst;
- char * src;
-
- if (colon == start) {
- break;
- }
- if (colon[-1] != '\\')
- break;
- for (dst = colon - 1, src = colon; *dst != '\0'; dst++, src++) {
- *dst = *src;
- }
- start = colon;
- }
- return (colon);
+ char * start = str;
+ char * colon;
+
+ while ((colon = strchr(start, ':')) != NULL) {
+ char * dst;
+ char * src;
+
+ if (colon == start) {
+ break;
+ }
+ if (colon[-1] != '\\') {
+ break;
+ }
+ for (dst = colon - 1, src = colon; *dst != '\0'; dst++, src++) {
+ *dst = *src;
+ }
+ start = colon;
+ }
+ return colon;
}
/*
* nfs:17.202.42.112:/Volumes/Foo\:/Library/NetBoot/NetBootSP0:Jaguar/Jaguar.dmg
*/
static __inline__ boolean_t
-parse_netboot_path(char * path, struct in_addr * iaddr_p, char * * host,
- char * * mount_dir, char * * image_path)
+parse_netboot_path(char * path, struct in_addr * iaddr_p, char const * * host,
+ char * * mount_dir, char * * image_path)
{
- static char tmp[MAX_IPv4_STR_LEN]; /* Danger - not thread safe */
- char * start;
- char * colon;
-
- if (strncmp(path, kNetBootRootPathPrefixNFS,
- strlen(kNetBootRootPathPrefixNFS)) != 0) {
- return (FALSE);
- }
-
- /* IP address */
- start = path + strlen(kNetBootRootPathPrefixNFS);
- colon = strchr(start, ':');
- if (colon == NULL) {
- return (FALSE);
- }
- *colon = '\0';
- if (inet_aton(start, iaddr_p) != 1) {
- return (FALSE);
- }
-
- /* mount point */
- start = colon + 1;
- colon = find_colon(start);
- *mount_dir = start;
- if (colon == NULL) {
- *image_path = NULL;
- }
- else {
- /* image path */
+ static char tmp[MAX_IPv4_STR_LEN]; /* Danger - not thread safe */
+ char * start;
+ char * colon;
+
+ if (strncmp(path, kNetBootRootPathPrefixNFS,
+ strlen(kNetBootRootPathPrefixNFS)) != 0) {
+ return FALSE;
+ }
+
+ /* IP address */
+ start = path + strlen(kNetBootRootPathPrefixNFS);
+ colon = strchr(start, ':');
+ if (colon == NULL) {
+ return FALSE;
+ }
*colon = '\0';
+ if (inet_aton(start, iaddr_p) != 1) {
+ return FALSE;
+ }
+
+ /* mount point */
start = colon + 1;
- (void)find_colon(start);
- *image_path = start;
- }
- *host = inet_ntop(AF_INET, iaddr_p, tmp, sizeof(tmp));
- return (TRUE);
+ colon = find_colon(start);
+ *mount_dir = start;
+ if (colon == NULL) {
+ *image_path = NULL;
+ } else {
+ /* image path */
+ *colon = '\0';
+ start = colon + 1;
+ (void)find_colon(start);
+ *image_path = start;
+ }
+ *host = inet_ntop(AF_INET, iaddr_p, tmp, sizeof(tmp));
+ return TRUE;
}
static boolean_t
-parse_image_path(char * path, struct in_addr * iaddr_p, char * * host,
- char * * mount_dir, char * * image_path)
+parse_image_path(char * path, struct in_addr * iaddr_p, char const * * host,
+ char * * mount_dir, char * * image_path)
{
- if (path[0] >= '0' && path[0] <= '9') {
- return (parse_booter_path(path, iaddr_p, host, mount_dir,
- image_path));
- }
- return (parse_netboot_path(path, iaddr_p, host, mount_dir,
- image_path));
+ if (path[0] >= '0' && path[0] <= '9') {
+ return parse_booter_path(path, iaddr_p, host, mount_dir,
+ image_path);
+ }
+ return parse_netboot_path(path, iaddr_p, host, mount_dir,
+ image_path);
}
static boolean_t
get_root_path(char * root_path)
{
- void * entry;
- boolean_t found = FALSE;
- const void * pkt;
- int pkt_len;
-
- entry = IOBSDRegistryEntryForDeviceTree("/chosen");
- if (entry == NULL) {
- return (FALSE);
- }
- pkt = IOBSDRegistryEntryGetData(entry, BSDP_RESPONSE, &pkt_len);
- if (pkt != NULL && pkt_len >= (int)sizeof(struct dhcp)) {
- printf("netboot: retrieving root path from BSDP response\n");
- }
- else {
- pkt = IOBSDRegistryEntryGetData(entry, BOOTP_RESPONSE,
- &pkt_len);
+ void * entry;
+ boolean_t found = FALSE;
+ const void * pkt;
+ int pkt_len;
+
+ entry = IOBSDRegistryEntryForDeviceTree("/chosen");
+ if (entry == NULL) {
+ return FALSE;
+ }
+ pkt = IOBSDRegistryEntryGetData(entry, BSDP_RESPONSE, &pkt_len);
if (pkt != NULL && pkt_len >= (int)sizeof(struct dhcp)) {
- printf("netboot: retrieving root path from BOOTP response\n");
+ printf("netboot: retrieving root path from BSDP response\n");
+ } else {
+ pkt = IOBSDRegistryEntryGetData(entry, BOOTP_RESPONSE,
+ &pkt_len);
+ if (pkt != NULL && pkt_len >= (int)sizeof(struct dhcp)) {
+ printf("netboot: retrieving root path from BOOTP response\n");
+ }
}
- }
- if (pkt != NULL) {
- int len;
- dhcpol_t options;
- char * path;
- struct dhcp * reply;
-
- reply = (struct dhcp *)pkt;
- (void)dhcpol_parse_packet(&options, reply, pkt_len, NULL);
-
- path = (char *)dhcpol_find(&options,
- dhcptag_root_path_e, &len, NULL);
- if (path) {
- bcopy(path, root_path, len);
- root_path[len] = '\0';
- found = TRUE;
+ if (pkt != NULL) {
+ int len;
+ dhcpol_t options;
+ const char * path;
+ const struct dhcp * reply;
+
+ reply = (const struct dhcp *)pkt;
+ (void)dhcpol_parse_packet(&options, reply, pkt_len);
+
+ path = (const char *)dhcpol_find(&options,
+ dhcptag_root_path_e, &len, NULL);
+ if (path) {
+ memcpy(root_path, path, len);
+ root_path[len] = '\0';
+ found = TRUE;
+ }
}
- }
- IOBSDRegistryEntryRelease(entry);
- return (found);
+ IOBSDRegistryEntryRelease(entry);
+ return found;
+}
+static void
+save_path(char * * str_p, size_t * length_p, char * path)
+{
+ *length_p = strlen(path) + 1;
+ *str_p = (char *)kheap_alloc(KHEAP_DATA_BUFFERS, *length_p, Z_WAITOK);
+ strlcpy(*str_p, path, *length_p);
+ return;
}
static struct netboot_info *
netboot_info_init(struct in_addr iaddr)
{
- struct netboot_info * info;
- char * root_path = NULL;
- boolean_t use_hdix = TRUE;
- char * vndevice = NULL;
-
- MALLOC_ZONE(vndevice, caddr_t, MAXPATHLEN, M_NAMEI, M_WAITOK);
- if (vndevice == NULL)
- panic("netboot_info_init: M_NAMEI zone exhausted");
- if (PE_parse_boot_arg("vndevice", vndevice) == TRUE) {
- use_hdix = FALSE;
- }
- FREE_ZONE(vndevice, MAXPATHLEN, M_NAMEI);
-
- info = (struct netboot_info *)kalloc(sizeof(*info));
- bzero(info, sizeof(*info));
- info->client_ip = iaddr;
- info->image_type = kNetBootImageTypeUnknown;
- info->use_hdix = use_hdix;
-
- /* check for a booter-specified path then a NetBoot path */
- MALLOC_ZONE(root_path, caddr_t, MAXPATHLEN, M_NAMEI, M_WAITOK);
- if (root_path == NULL)
- panic("netboot_info_init: M_NAMEI zone exhausted");
- if (PE_parse_boot_arg("rp", root_path) == TRUE
- || PE_parse_boot_arg("rootpath", root_path) == TRUE
- || get_root_path(root_path) == TRUE) {
- char * server_name = NULL;
- char * mount_point = NULL;
- char * image_path = NULL;
- struct in_addr server_ip;
-
- if (parse_image_path(root_path, &server_ip, &server_name,
- &mount_point, &image_path)) {
- info->image_type = kNetBootImageTypeNFS;
- info->server_ip = server_ip;
- info->server_name_length = strlen(server_name) + 1;
- info->server_name = (char *)kalloc(info->server_name_length);
- info->mount_point_length = strlen(mount_point) + 1;
- info->mount_point = (char *)kalloc(info->mount_point_length);
- strcpy(info->server_name, server_name);
- strcpy(info->mount_point, mount_point);
-
- printf("Server %s Mount %s",
- server_name, info->mount_point);
- if (image_path != NULL) {
- boolean_t needs_slash = FALSE;
-
- info->image_path_length = strlen(image_path) + 1;
- if (image_path[0] != '/') {
- needs_slash = TRUE;
- info->image_path_length++;
+ boolean_t have_root_path = FALSE;
+ struct netboot_info * info = NULL;
+ char * root_path = NULL;
+
+ info = (struct netboot_info *)kalloc(sizeof(*info));
+ bzero(info, sizeof(*info));
+ info->client_ip = iaddr;
+ info->image_type = kNetBootImageTypeUnknown;
+
+ /* check for a booter-specified path then a NetBoot path */
+ root_path = zalloc(ZV_NAMEI);
+
+ if (PE_parse_boot_argn("rp0", root_path, MAXPATHLEN) == TRUE
+ || PE_parse_boot_argn("rp", root_path, MAXPATHLEN) == TRUE
+ || PE_parse_boot_argn("rootpath", root_path, MAXPATHLEN) == TRUE) {
+ if (imageboot_format_is_valid(root_path)) {
+ printf("netboot_info_init: rp0='%s' isn't a network path,"
+ " ignoring\n", root_path);
+ } else {
+ have_root_path = TRUE;
}
- info->image_path = (char *)kalloc(info->image_path_length);
- if (needs_slash) {
- info->image_path[0] = '/';
- strcpy(info->image_path + 1, image_path);
+ }
+ if (have_root_path == FALSE) {
+ have_root_path = get_root_path(root_path);
+ }
+ if (have_root_path) {
+ const char * server_name = NULL;
+ char * mount_point = NULL;
+ char * image_path = NULL;
+ struct in_addr server_ip;
+
+ if (parse_image_path(root_path, &server_ip, &server_name,
+ &mount_point, &image_path)) {
+ info->image_type = kNetBootImageTypeNFS;
+ info->server_ip = server_ip;
+ info->server_name_length = strlen(server_name) + 1;
+ info->server_name = kheap_alloc(KHEAP_DATA_BUFFERS,
+ info->server_name_length, Z_WAITOK);
+ info->mount_point_length = strlen(mount_point) + 1;
+ info->mount_point = kheap_alloc(KHEAP_DATA_BUFFERS,
+ info->mount_point_length, Z_WAITOK);
+ strlcpy(info->server_name, server_name, info->server_name_length);
+ strlcpy(info->mount_point, mount_point, info->mount_point_length);
+
+ printf("netboot: NFS Server %s Mount %s",
+ server_name, info->mount_point);
+ if (image_path != NULL) {
+ boolean_t needs_slash = FALSE;
+
+ info->image_path_length = strlen(image_path) + 1;
+ if (image_path[0] != '/') {
+ needs_slash = TRUE;
+ info->image_path_length++;
+ }
+ info->image_path = kheap_alloc(KHEAP_DATA_BUFFERS,
+ info->image_path_length, Z_WAITOK);
+ if (needs_slash) {
+ info->image_path[0] = '/';
+ strlcpy(info->image_path + 1, image_path,
+ info->image_path_length - 1);
+ } else {
+ strlcpy(info->image_path, image_path,
+ info->image_path_length);
+ }
+ printf(" Image %s", info->image_path);
+ }
+ printf("\n");
+ } else if (strncmp(root_path, kNetBootRootPathPrefixHTTP,
+ strlen(kNetBootRootPathPrefixHTTP)) == 0) {
+ info->image_type = kNetBootImageTypeHTTP;
+ save_path(&info->image_path, &info->image_path_length,
+ root_path);
+ printf("netboot: HTTP URL %s\n", info->image_path);
+ } else {
+ printf("netboot: root path uses unrecognized format\n");
+ }
+
+ /* check for image-within-image */
+ if (info->image_path != NULL) {
+ if (PE_parse_boot_argn(IMAGEBOOT_ROOT_ARG, root_path, MAXPATHLEN)
+ || PE_parse_boot_argn("rp1", root_path, MAXPATHLEN)) {
+ /* rp1/root-dmg is the second-level image */
+ save_path(&info->second_image_path, &info->second_image_path_length,
+ root_path);
+ }
}
- else {
- strcpy(info->image_path, image_path);
+ if (info->second_image_path != NULL) {
+ printf("netboot: nested image %s\n", info->second_image_path);
}
- printf(" Image %s", info->image_path);
- }
- printf("\n");
- }
- else if (strncmp(root_path, kNetBootRootPathPrefixHTTP,
- strlen(kNetBootRootPathPrefixHTTP)) == 0) {
- /* only HDIX supports HTTP */
- info->image_type = kNetBootImageTypeHTTP;
- info->use_hdix = TRUE;
- info->image_path_length = strlen(root_path) + 1;
- info->image_path = (char *)kalloc(info->image_path_length);
- strcpy(info->image_path, root_path);
- }
- else {
- printf("netboot: root path uses unrecognized format\n");
- }
- }
- FREE_ZONE(root_path, MAXPATHLEN, M_NAMEI);
- return (info);
+ }
+ zfree(ZV_NAMEI, root_path);
+ return info;
}
-static void
+static void
netboot_info_free(struct netboot_info * * info_p)
{
- struct netboot_info * info = *info_p;
+ struct netboot_info * info = *info_p;
- if (info) {
- if (info->mount_point) {
- kfree(info->mount_point, info->mount_point_length);
- }
- if (info->server_name) {
- kfree(info->server_name, info->server_name_length);
- }
- if (info->image_path) {
- kfree(info->image_path, info->image_path_length);
+ if (info) {
+ if (info->mount_point) {
+ kheap_free(KHEAP_DATA_BUFFERS, info->mount_point,
+ info->mount_point_length);
+ }
+ if (info->server_name) {
+ kheap_free(KHEAP_DATA_BUFFERS, info->server_name,
+ info->server_name_length);
+ }
+ if (info->image_path) {
+ kheap_free(KHEAP_DATA_BUFFERS, info->image_path,
+ info->image_path_length);
+ }
+ if (info->second_image_path) {
+ kheap_free(KHEAP_DATA_BUFFERS, info->second_image_path,
+ info->second_image_path_length);
+ }
+ kfree(info, sizeof(*info));
}
- kfree(info, sizeof(*info));
- }
- *info_p = NULL;
- return;
+ *info_p = NULL;
}
boolean_t
netboot_iaddr(struct in_addr * iaddr_p)
{
- if (S_netboot_info_p == NULL)
- return (FALSE);
+ if (S_netboot_info_p == NULL) {
+ return FALSE;
+ }
- *iaddr_p = S_netboot_info_p->client_ip;
- return (TRUE);
+ *iaddr_p = S_netboot_info_p->client_ip;
+ return TRUE;
}
boolean_t
netboot_rootpath(struct in_addr * server_ip,
- char * name, int name_len,
- char * path, int path_len)
+ char * name, size_t name_len,
+ char * path, size_t path_len)
{
- if (S_netboot_info_p == NULL)
- return (FALSE);
-
- name[0] = '\0';
- path[0] = '\0';
-
- if (S_netboot_info_p->mount_point_length == 0) {
- return (FALSE);
- }
- if (path_len < S_netboot_info_p->mount_point_length) {
- printf("netboot: path too small %d < %d\n",
- path_len, S_netboot_info_p->mount_point_length);
- return (FALSE);
- }
- strcpy(path, S_netboot_info_p->mount_point);
- strncpy(name, S_netboot_info_p->server_name, name_len);
- *server_ip = S_netboot_info_p->server_ip;
- return (TRUE);
+ if (S_netboot_info_p == NULL) {
+ return FALSE;
+ }
+
+ name[0] = '\0';
+ path[0] = '\0';
+
+ if (S_netboot_info_p->mount_point_length == 0) {
+ return FALSE;
+ }
+ if (path_len < S_netboot_info_p->mount_point_length) {
+ printf("netboot: path too small %zu < %zu\n",
+ path_len, S_netboot_info_p->mount_point_length);
+ return FALSE;
+ }
+ strlcpy(path, S_netboot_info_p->mount_point, path_len);
+ strlcpy(name, S_netboot_info_p->server_name, name_len);
+ *server_ip = S_netboot_info_p->server_ip;
+ return TRUE;
}
static boolean_t
-get_ip_parameters(struct in_addr * iaddr_p, struct in_addr * netmask_p,
- struct in_addr * router_p)
+get_ip_parameters(struct in_addr * iaddr_p, struct in_addr * netmask_p,
+ struct in_addr * router_p)
{
- void * entry;
- const void * pkt;
- int pkt_len;
-
-
- entry = IOBSDRegistryEntryForDeviceTree("/chosen");
- if (entry == NULL) {
- return (FALSE);
- }
- pkt = IOBSDRegistryEntryGetData(entry, DHCP_RESPONSE, &pkt_len);
- if (pkt != NULL && pkt_len >= (int)sizeof(struct dhcp)) {
- printf("netboot: retrieving IP information from DHCP response\n");
- }
- else {
- pkt = IOBSDRegistryEntryGetData(entry, BOOTP_RESPONSE, &pkt_len);
- if (pkt != NULL && pkt_len >= (int)sizeof(struct dhcp)) {
- printf("netboot: retrieving IP information from BOOTP response\n");
- }
- }
- if (pkt != NULL) {
- struct in_addr * ip;
- int len;
- dhcpol_t options;
- struct dhcp * reply;
-
- reply = (struct dhcp *)pkt;
- (void)dhcpol_parse_packet(&options, reply, pkt_len, NULL);
- *iaddr_p = reply->dp_yiaddr;
- ip = (struct in_addr *)
- dhcpol_find(&options,
- dhcptag_subnet_mask_e, &len, NULL);
- if (ip) {
- *netmask_p = *ip;
- }
- ip = (struct in_addr *)
- dhcpol_find(&options, dhcptag_router_e, &len, NULL);
- if (ip) {
- *router_p = *ip;
- }
- }
- IOBSDRegistryEntryRelease(entry);
- return (pkt != NULL);
-}
+ void * entry;
+ const void * pkt;
+ int pkt_len;
-static int
-inet_aifaddr(struct socket * so, char * name, const struct in_addr * addr,
- const struct in_addr * mask,
- const struct in_addr * broadcast)
-{
- struct sockaddr blank_sin;
- struct ifaliasreq ifra;
-
- bzero(&blank_sin, sizeof(blank_sin));
- blank_sin.sa_len = sizeof(blank_sin);
- blank_sin.sa_family = AF_INET;
-
- bzero(&ifra, sizeof(ifra));
- strncpy(ifra.ifra_name, name, sizeof(ifra.ifra_name));
- if (addr) {
- ifra.ifra_addr = blank_sin;
- ((struct sockaddr_in *)&ifra.ifra_addr)->sin_addr = *addr;
- }
- if (mask) {
- ifra.ifra_mask = blank_sin;
- ((struct sockaddr_in *)&ifra.ifra_mask)->sin_addr = *mask;
- }
- if (broadcast) {
- ifra.ifra_broadaddr = blank_sin;
- ((struct sockaddr_in *)&ifra.ifra_broadaddr)->sin_addr = *broadcast;
- }
- return (ifioctl(so, SIOCAIFADDR, (caddr_t)&ifra, current_proc()));
+
+ entry = IOBSDRegistryEntryForDeviceTree("/chosen");
+ if (entry == NULL) {
+ return FALSE;
+ }
+ pkt = IOBSDRegistryEntryGetData(entry, DHCP_RESPONSE, &pkt_len);
+ if (pkt != NULL && pkt_len >= (int)sizeof(struct dhcp)) {
+ printf("netboot: retrieving IP information from DHCP response\n");
+ } else {
+ pkt = IOBSDRegistryEntryGetData(entry, BOOTP_RESPONSE, &pkt_len);
+ if (pkt != NULL && pkt_len >= (int)sizeof(struct dhcp)) {
+ printf("netboot: retrieving IP information from BOOTP response\n");
+ }
+ }
+ if (pkt != NULL) {
+ const struct in_addr * ip;
+ int len;
+ dhcpol_t options;
+ const struct dhcp * reply;
+
+ reply = (const struct dhcp *)pkt;
+ (void)dhcpol_parse_packet(&options, reply, pkt_len);
+ *iaddr_p = reply->dp_yiaddr;
+ ip = (const struct in_addr *)
+ dhcpol_find(&options,
+ dhcptag_subnet_mask_e, &len, NULL);
+ if (ip) {
+ *netmask_p = *ip;
+ }
+ ip = (const struct in_addr *)
+ dhcpol_find(&options, dhcptag_router_e, &len, NULL);
+ if (ip) {
+ *router_p = *ip;
+ }
+ }
+ IOBSDRegistryEntryRelease(entry);
+ return pkt != NULL;
}
static int
-route_cmd(int cmd, struct in_addr d, struct in_addr g,
- struct in_addr m, u_long more_flags)
+route_cmd(int cmd, struct in_addr d, struct in_addr g,
+ struct in_addr m, uint32_t more_flags, unsigned int ifscope)
{
- struct sockaddr_in dst;
- u_long flags = RTF_UP | RTF_STATIC;
- struct sockaddr_in gw;
- struct sockaddr_in mask;
-
- flags |= more_flags;
-
- /* destination */
- bzero((caddr_t)&dst, sizeof(dst));
- dst.sin_len = sizeof(dst);
- dst.sin_family = AF_INET;
- dst.sin_addr = d;
-
- /* gateway */
- bzero((caddr_t)&gw, sizeof(gw));
- gw.sin_len = sizeof(gw);
- gw.sin_family = AF_INET;
- gw.sin_addr = g;
-
- /* mask */
- bzero(&mask, sizeof(mask));
- mask.sin_len = sizeof(mask);
- mask.sin_family = AF_INET;
- mask.sin_addr = m;
-
- return (rtrequest(cmd, (struct sockaddr *)&dst, (struct sockaddr *)&gw,
- (struct sockaddr *)&mask, flags, NULL));
+ struct sockaddr_in dst;
+ int error;
+ uint32_t flags = RTF_UP | RTF_STATIC;
+ struct sockaddr_in gw;
+ struct sockaddr_in mask;
+
+ flags |= more_flags;
+
+ /* destination */
+ bzero((caddr_t)&dst, sizeof(dst));
+ dst.sin_len = sizeof(dst);
+ dst.sin_family = AF_INET;
+ dst.sin_addr = d;
+
+ /* gateway */
+ bzero((caddr_t)&gw, sizeof(gw));
+ gw.sin_len = sizeof(gw);
+ gw.sin_family = AF_INET;
+ gw.sin_addr = g;
+
+ /* mask */
+ bzero(&mask, sizeof(mask));
+ mask.sin_len = sizeof(mask);
+ mask.sin_family = AF_INET;
+ mask.sin_addr = m;
+
+ error = rtrequest_scoped(cmd, (struct sockaddr *)&dst,
+ (struct sockaddr *)&gw, (struct sockaddr *)&mask, flags, NULL, ifscope);
+
+ return error;
}
static int
default_route_add(struct in_addr router, boolean_t proxy_arp)
{
- u_long flags = 0;
- struct in_addr zeroes = { 0 };
-
- if (proxy_arp == FALSE) {
- flags |= RTF_GATEWAY;
- }
- return (route_cmd(RTM_ADD, zeroes, router, zeroes, flags));
+ uint32_t flags = 0;
+ struct in_addr zeroes = { .s_addr = 0 };
+
+ if (proxy_arp == FALSE) {
+ flags |= RTF_GATEWAY;
+ }
+ return route_cmd(RTM_ADD, zeroes, router, zeroes, flags, IFSCOPE_NONE);
}
static int
-host_route_delete(struct in_addr host)
+host_route_delete(struct in_addr host, unsigned int ifscope)
{
- struct in_addr zeroes = { 0 };
-
- return (route_cmd(RTM_DELETE, host, zeroes, zeroes, RTF_HOST));
+ struct in_addr zeroes = { .s_addr = 0 };
+
+ return route_cmd(RTM_DELETE, host, zeroes, zeroes, RTF_HOST, ifscope);
}
static struct ifnet *
find_interface(void)
{
- struct ifnet * ifp = NULL;
+ struct ifnet * ifp = NULL;
- if (rootdevice[0]) {
- ifp = ifunit(rootdevice);
- }
- if (ifp == NULL) {
+ dlil_if_lock();
+ if (rootdevice[0]) {
+ ifp = ifunit((char *)rootdevice);
+ }
+ if (ifp == NULL) {
ifnet_head_lock_shared();
TAILQ_FOREACH(ifp, &ifnet_head, if_link)
- if ((ifp->if_flags & (IFF_LOOPBACK|IFF_POINTOPOINT)) == 0)
- break;
+ if ((ifp->if_flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) == 0) {
+ break;
+ }
ifnet_head_done();
- }
- return (ifp);
+ }
+ dlil_if_unlock();
+ return ifp;
+}
+
+static const struct sockaddr_in blank_sin = {
+ .sin_len = sizeof(struct sockaddr_in),
+ .sin_family = AF_INET,
+ .sin_port = 0,
+ .sin_addr = { .s_addr = 0 },
+ .sin_zero = { 0, 0, 0, 0, 0, 0, 0, 0 }
+};
+
+static int
+inet_aifaddr(struct socket * so, const char * name,
+ const struct in_addr * addr,
+ const struct in_addr * mask,
+ const struct in_addr * broadcast)
+{
+ struct ifaliasreq ifra;
+
+ bzero(&ifra, sizeof(ifra));
+ strlcpy(ifra.ifra_name, name, sizeof(ifra.ifra_name));
+ if (addr) {
+ *((struct sockaddr_in *)(void *)&ifra.ifra_addr) = blank_sin;
+ ((struct sockaddr_in *)(void *)&ifra.ifra_addr)->sin_addr = *addr;
+ }
+ if (mask) {
+ *((struct sockaddr_in *)(void *)&ifra.ifra_mask) = blank_sin;
+ ((struct sockaddr_in *)(void *)&ifra.ifra_mask)->sin_addr = *mask;
+ }
+ if (broadcast) {
+ *((struct sockaddr_in *)(void *)&ifra.ifra_broadaddr) = blank_sin;
+ ((struct sockaddr_in *)(void *)&ifra.ifra_broadaddr)->sin_addr = *broadcast;
+ }
+ return ifioctl(so, SIOCAIFADDR, (caddr_t)&ifra, current_proc());
}
+
int
netboot_mountroot(void)
{
- int error = 0;
- struct in_addr iaddr = { 0 };
- struct ifreq ifr;
- struct ifnet * ifp;
- struct in_addr netmask = { 0 };
- struct proc * procp = current_proc();
- struct in_addr router = { 0 };
- struct socket * so = NULL;
- unsigned int try;
-
- bzero(&ifr, sizeof(ifr));
-
-
- /* find the interface */
- ifp = find_interface();
- if (ifp == NULL) {
- printf("netboot: no suitable interface\n");
- error = ENXIO;
- goto failed;
- }
- sprintf(ifr.ifr_name, "%s%d", ifp->if_name, ifp->if_unit);
- printf("netboot: using network interface '%s'\n", ifr.ifr_name);
-
- /* bring it up */
- if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0)) != 0) {
- printf("netboot: socreate, error=%d\n", error);
- goto failed;
- }
- ifr.ifr_flags = ifp->if_flags | IFF_UP;
- error = ifioctl(so, SIOCSIFFLAGS, (caddr_t)&ifr, procp);
- if (error) {
- printf("netboot: SIFFLAGS, error=%d\n", error);
- goto failed;
- }
-
- /* grab information from the registry */
- if (get_ip_parameters(&iaddr, &netmask, &router) == FALSE) {
- /* use BOOTP to retrieve IP address, netmask and router */
- error = bootp(ifp, &iaddr, 32, &netmask, &router, procp);
+ int error = 0;
+ struct in_addr iaddr = { .s_addr = 0 };
+ struct ifreq ifr;
+ struct ifnet * ifp;
+ struct in_addr netmask = { .s_addr = 0 };
+ proc_t procp = current_proc();
+ struct in_addr router = { .s_addr = 0 };
+ struct socket * so = NULL;
+ unsigned int try;
+
+ bzero(&ifr, sizeof(ifr));
+
+ /* find the interface */
+ ifp = find_interface();
+ if (ifp == NULL) {
+ printf("netboot: no suitable interface\n");
+ error = ENXIO;
+ goto failed;
+ }
+ snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", if_name(ifp));
+ printf("netboot: using network interface '%s'\n", ifr.ifr_name);
+
+ /* bring it up */
+ if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0)) != 0) {
+ printf("netboot: socreate, error=%d\n", error);
+ goto failed;
+ }
+ ifr.ifr_flags = ifp->if_flags | IFF_UP;
+ error = ifioctl(so, SIOCSIFFLAGS, (caddr_t)&ifr, procp);
if (error) {
- printf("netboot: BOOTP failed %d\n", error);
- goto failed;
- }
- }
- printf("netboot: IP address " IP_FORMAT, IP_LIST(&iaddr));
- if (netmask.s_addr) {
- printf(" netmask " IP_FORMAT, IP_LIST(&netmask));
- }
- if (router.s_addr) {
- printf(" router " IP_FORMAT, IP_LIST(&router));
- }
- printf("\n");
- error = inet_aifaddr(so, ifr.ifr_name, &iaddr, &netmask, NULL);
- if (error) {
- printf("netboot: inet_aifaddr failed, %d\n", error);
- goto failed;
- }
- if (router.s_addr == 0) {
- /* enable proxy arp if we don't have a router */
- router.s_addr = iaddr.s_addr;
- }
- printf("netboot: adding default route " IP_FORMAT "\n",
- IP_LIST(&router));
- error = default_route_add(router, router.s_addr == iaddr.s_addr);
- if (error) {
- printf("netboot: default_route_add failed %d\n", error);
- }
-
- soclose(so);
-
- S_netboot_info_p = netboot_info_init(iaddr);
- switch (S_netboot_info_p->image_type) {
- default:
- case kNetBootImageTypeNFS:
- for (try = 1; TRUE; try++) {
- error = nfs_mountroot();
- if (error == 0) {
- break;
- }
- printf("netboot: nfs_mountroot() attempt %u failed; "
- "clearing ARP entry and trying again\n", try);
- /*
- * error is either EHOSTDOWN or EHOSTUNREACH, which likely means
- * that the port we're plugged into has spanning tree enabled,
- * and either the router or the server can't answer our ARP
- * requests. Clear the incomplete ARP entry by removing the
- * appropriate route, depending on the error code:
- * EHOSTDOWN NFS server's route
- * EHOSTUNREACH router's route
- */
- switch (error) {
- default:
- /* NOT REACHED */
- case EHOSTDOWN:
- /* remove the server's arp entry */
- error = host_route_delete(S_netboot_info_p->server_ip);
- if (error) {
- printf("netboot: host_route_delete(" IP_FORMAT
- ") failed %d\n",
- IP_LIST(&S_netboot_info_p->server_ip), error);
+ printf("netboot: SIFFLAGS, error=%d\n", error);
+ goto failed;
+ }
+
+ /* grab information from the registry */
+ if (get_ip_parameters(&iaddr, &netmask, &router) == FALSE) {
+ printf("netboot: can't retrieve IP parameters\n");
+ goto failed;
+ }
+ printf("netboot: IP address " IP_FORMAT, IP_LIST(&iaddr));
+ if (netmask.s_addr) {
+ printf(" netmask " IP_FORMAT, IP_LIST(&netmask));
+ }
+ if (router.s_addr) {
+ printf(" router " IP_FORMAT, IP_LIST(&router));
+ }
+ printf("\n");
+ error = inet_aifaddr(so, ifr.ifr_name, &iaddr, &netmask, NULL);
+ if (error) {
+ printf("netboot: inet_aifaddr failed, %d\n", error);
+ goto failed;
+ }
+ if (router.s_addr == 0) {
+ /* enable proxy arp if we don't have a router */
+ router.s_addr = iaddr.s_addr;
+ }
+ printf("netboot: adding default route " IP_FORMAT "\n",
+ IP_LIST(&router));
+ error = default_route_add(router, router.s_addr == iaddr.s_addr);
+ if (error) {
+ printf("netboot: default_route_add failed %d\n", error);
+ }
+
+ soclose(so);
+
+ S_netboot_info_p = netboot_info_init(iaddr);
+ switch (S_netboot_info_p->image_type) {
+ default:
+ case kNetBootImageTypeNFS:
+ for (try = 1; TRUE; try++) {
+ error = nfs_mountroot();
+ if (error == 0) {
+ break;
+ }
+ printf("netboot: nfs_mountroot() attempt %u failed; "
+ "clearing ARP entry and trying again\n", try);
+ /*
+ * error is either EHOSTDOWN or EHOSTUNREACH, which likely means
+ * that the port we're plugged into has spanning tree enabled,
+ * and either the router or the server can't answer our ARP
+ * requests. Clear the incomplete ARP entry by removing the
+ * appropriate route, depending on the error code:
+ * EHOSTDOWN NFS server's route
+ * EHOSTUNREACH router's route
+ */
+ switch (error) {
+ default:
+ /* NOT REACHED */
+ case EHOSTDOWN:
+ /* remove the server's arp entry */
+ error = host_route_delete(S_netboot_info_p->server_ip,
+ ifp->if_index);
+ if (error) {
+ printf("netboot: host_route_delete(" IP_FORMAT
+ ") failed %d\n",
+ IP_LIST(&S_netboot_info_p->server_ip), error);
+ }
+ break;
+ case EHOSTUNREACH:
+ error = host_route_delete(router, ifp->if_index);
+ if (error) {
+ printf("netboot: host_route_delete(" IP_FORMAT
+ ") failed %d\n", IP_LIST(&router), error);
+ }
+ break;
+ }
}
break;
- case EHOSTUNREACH:
- error = host_route_delete(router);
- if (error) {
- printf("netboot: host_route_delete(" IP_FORMAT
- ") failed %d\n", IP_LIST(&router), error);
- }
+ case kNetBootImageTypeHTTP:
+ error = netboot_setup();
break;
- }
- }
- break;
- case kNetBootImageTypeHTTP:
- error = netboot_setup(procp);
- break;
- }
- if (error == 0) {
- S_netboot = 1;
- }
- else {
- S_netboot = 0;
- }
- return (error);
+ }
+ if (error == 0) {
+ S_netboot = 1;
+ } else {
+ S_netboot = 0;
+ }
+ return error;
failed:
- if (so != NULL) {
- soclose(so);
- }
- return (error);
+ if (so != NULL) {
+ soclose(so);
+ }
+ return error;
}
int
-netboot_setup(struct proc * p)
+netboot_setup(void)
{
- dev_t dev;
- int error = 0;
-
- if (S_netboot_info_p == NULL
- || S_netboot_info_p->image_path == NULL) {
- goto done;
- }
- if (S_netboot_info_p->use_hdix) {
- printf("netboot_setup: calling di_root_image\n");
- error = di_root_image(S_netboot_info_p->image_path,
- rootdevice, &dev);
- if (error) {
- printf("netboot_setup: di_root_image: failed %d\n", error);
- goto done;
- }
- }
- else {
- printf("netboot_setup: calling vndevice_root_image\n");
- error = vndevice_root_image(S_netboot_info_p->image_path,
- rootdevice, &dev);
- if (error) {
- printf("netboot_setup: vndevice_root_image: failed %d\n", error);
- goto done;
- }
- }
- rootdev = dev;
- mountroot = NULL;
- printf("netboot: root device 0x%x\n", rootdev);
- error = vfs_mountroot();
- if (error == 0 && rootvnode != NULL) {
- struct vnode *tvp;
- struct vnode *newdp;
- struct vfs_context context;
-
- context.vc_proc = p;
- context.vc_ucred = proc_ucred(p); /* XXX kauth_cred_get() ??? proxy */
-
- /* Get the vnode for '/'. Set fdp->fd_fd.fd_cdir to reference it. */
- if (VFS_ROOT(mountlist.tqh_last, &newdp, &context))
- panic("netboot_setup: cannot find root vnode");
- vnode_ref(newdp);
- vnode_put(newdp);
- tvp = rootvnode;
- vnode_rele(tvp);
- filedesc0.fd_cdir = newdp;
- rootvnode = newdp;
- mount_list_lock();
- TAILQ_REMOVE(&mountlist, TAILQ_FIRST(&mountlist), mnt_list);
- mount_list_unlock();
- mountlist.tqh_first->mnt_flag |= MNT_ROOTFS;
- }
- done:
- netboot_info_free(&S_netboot_info_p);
- return (error);
+ int error = 0;
+
+ if (S_netboot_info_p == NULL
+ || S_netboot_info_p->image_path == NULL) {
+ goto done;
+ }
+ printf("netboot_setup: calling imageboot_mount_image\n");
+ error = imageboot_mount_image(S_netboot_info_p->image_path, -1, IMAGEBOOT_DMG);
+ if (error != 0) {
+ printf("netboot: failed to mount root image, %d\n", error);
+ } else if (S_netboot_info_p->second_image_path != NULL) {
+ error = imageboot_mount_image(S_netboot_info_p->second_image_path, 0, IMAGEBOOT_DMG);
+ if (error != 0) {
+ printf("netboot: failed to mount second root image, %d\n", error);
+ }
+ }
+
+done:
+ netboot_info_free(&S_netboot_info_p);
+ return error;
}
int
netboot_root(void)
{
- return (S_netboot);
+ return S_netboot;
}