The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/bsd/kern/netboot.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (c) 2001-2002 Apple Computer, Inc. All rights reserved.
    3  *
    4  * @APPLE_LICENSE_HEADER_START@
    5  * 
    6  * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
    7  * 
    8  * This file contains Original Code and/or Modifications of Original Code
    9  * as defined in and that are subject to the Apple Public Source License
   10  * Version 2.0 (the 'License'). You may not use this file except in
   11  * compliance with the License. Please obtain a copy of the License at
   12  * http://www.opensource.apple.com/apsl/ and read it before using this
   13  * file.
   14  * 
   15  * The Original Code and all software distributed under the License are
   16  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
   17  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
   18  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
   19  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
   20  * Please see the License for the specific language governing rights and
   21  * limitations under the License.
   22  * 
   23  * @APPLE_LICENSE_HEADER_END@
   24  */
   25 
   26 /*
   27  * History:
   28  * 14 December, 2001    Dieter Siegmund (dieter@apple.com)
   29  * - created
   30  */
   31 #include <sys/param.h>
   32 #include <sys/systm.h>
   33 #include <sys/kernel.h>
   34 #include <sys/conf.h>
   35 #include <sys/ioctl.h>
   36 #include <sys/proc.h>
   37 #include <sys/mount.h>
   38 #include <sys/mbuf.h>
   39 #include <sys/filedesc.h>
   40 #include <sys/vnode.h>
   41 #include <sys/malloc.h>
   42 #include <sys/socket.h>
   43 #include <sys/reboot.h>
   44 #include <net/if.h>
   45 #include <net/if_dl.h>
   46 #include <net/if_types.h>
   47 #include <net/route.h>
   48 #include <netinet/in.h>
   49 #include <netinet/if_ether.h>
   50 #include <netinet/dhcp_options.h>
   51 
   52 
   53 //#include <libkern/libkern.h>
   54 
   55 extern dev_t            rootdev;                /* device of the root */
   56 extern struct filedesc  filedesc0;
   57 
   58 extern char *   strchr(const char *str, int ch);
   59 
   60 extern int      nfs_mountroot();        /* nfs_vfsops.c */
   61 extern int (*mountroot)(void);
   62 
   63 extern unsigned char    rootdevice[];
   64 
   65 static int                      S_netboot = 0;
   66 static struct netboot_info *    S_netboot_info_p;
   67 
   68 void *
   69 IOBSDRegistryEntryForDeviceTree(char * path);
   70 
   71 void
   72 IOBSDRegistryEntryRelease(void * entry);
   73 
   74 const void *
   75 IOBSDRegistryEntryGetData(void * entry, char * property_name, 
   76                           int * packet_length);
   77 
   78 extern int vndevice_root_image(const char * path, char devname[], 
   79                                dev_t * dev_p);
   80 extern int di_root_image(const char *path, char devname[], dev_t *dev_p);
   81 
   82 
   83 static boolean_t path_getfile __P((char * image_path, 
   84                                    struct sockaddr_in * sin_p, 
   85                                    char * serv_name, char * pathname));
   86 
   87 #define BOOTP_RESPONSE  "bootp-response"
   88 #define BSDP_RESPONSE   "bsdp-response"
   89 #define DHCP_RESPONSE   "dhcp-response"
   90 
   91 extern int 
   92 bootp(struct ifnet * ifp, struct in_addr * iaddr_p, int max_retry,
   93       struct in_addr * netmask_p, struct in_addr * router_p,
   94       struct proc * procp);
   95 
   96 #define IP_FORMAT       "%d.%d.%d.%d"
   97 #define IP_CH(ip)       ((u_char *)ip)
   98 #define IP_LIST(ip)     IP_CH(ip)[0],IP_CH(ip)[1],IP_CH(ip)[2],IP_CH(ip)[3]
   99 
  100 #define kNetBootRootPathPrefixNFS       "nfs:"
  101 #define kNetBootRootPathPrefixHTTP      "http:"
  102 
  103 typedef enum {
  104     kNetBootImageTypeUnknown = 0,
  105     kNetBootImageTypeNFS = 1,
  106     kNetBootImageTypeHTTP = 2,
  107 } NetBootImageType;
  108 
  109 struct netboot_info {
  110     struct in_addr      client_ip;
  111     struct in_addr      server_ip;
  112     char *              server_name;
  113     int                 server_name_length;
  114     char *              mount_point;
  115     int                 mount_point_length;
  116     char *              image_path;
  117     int                 image_path_length;
  118     NetBootImageType    image_type;
  119     boolean_t           use_hdix;
  120 };
  121 
  122 int
  123 inet_aton(char * cp, struct in_addr * pin)
  124 {
  125     u_char * b = (char *)pin;
  126     int    i;
  127     char * p;
  128 
  129     for (p = cp, i = 0; i < 4; i++) {
  130         u_long l = strtoul(p, 0, 0);
  131         if (l > 255)
  132             return (FALSE);
  133         b[i] = l;
  134         p = strchr(p, '.');
  135         if (i < 3 && p == NULL)
  136             return (FALSE);
  137         p++;
  138     }
  139     return (TRUE);
  140 }
  141 
  142 /*
  143  * Function: parse_booter_path
  144  * Purpose:
  145  *   Parse a string of the form:
  146  *        "<IP>:<host>:<mount>[:<image_path>]"
  147  *   into the given ip address, host, mount point, and optionally, image_path.
  148  *
  149  * Note:
  150  *   The passed in string is modified i.e. ':' is replaced by '\0'.
  151  * Example: 
  152  *   "17.202.16.17:seaport:/release/.images/Image9/CurrentHera"
  153  */
  154 static __inline__ boolean_t
  155 parse_booter_path(char * path, struct in_addr * iaddr_p, char * * host,
  156                   char * * mount_dir, char * * image_path)
  157 {
  158     char *      start;
  159     char *      colon;
  160 
  161     /* IP address */
  162     start = path;
  163     colon = strchr(start, ':');
  164     if (colon == NULL) {
  165         return (FALSE);
  166     }
  167     *colon = '\0';
  168     if (inet_aton(start, iaddr_p) != 1) {
  169         return (FALSE);
  170     }
  171 
  172     /* host */
  173     start = colon + 1;
  174     colon = strchr(start, ':');
  175     if (colon == NULL) {
  176         return (FALSE);
  177     }
  178     *colon = '\0';
  179     *host = start;
  180 
  181     /* mount */
  182     start = colon + 1;
  183     colon = strchr(start, ':');
  184     *mount_dir = start;
  185     if (colon == NULL) {
  186         *image_path = NULL;
  187     }
  188     else {
  189         /* image path */
  190         *colon = '\0';
  191         start = colon + 1;
  192         *image_path = start;
  193     }
  194     return (TRUE);
  195 }
  196 
  197 /*
  198  * Function: find_colon
  199  * Purpose:
  200  *   Find the next unescaped instance of the colon character.
  201  *   If a colon is escaped (preceded by a backslash '\' character),
  202  *   shift the string over by one character to overwrite the backslash.
  203  */
  204 static __inline__ char *
  205 find_colon(char * str)
  206 {
  207     char * start = str;
  208     char * colon;
  209     
  210     while ((colon = strchr(start, ':')) != NULL) {
  211         char * dst;
  212         char * src;
  213 
  214         if (colon == start) {
  215             break;
  216         }
  217         if (colon[-1] != '\\')
  218             break;
  219         for (dst = colon - 1, src = colon; *dst != '\0'; dst++, src++) {
  220             *dst = *src;
  221         }
  222         start = colon;
  223     }
  224     return (colon);
  225 }
  226 
  227 /*
  228  * Function: parse_netboot_path
  229  * Purpose:
  230  *   Parse a string of the form:
  231  *        "nfs:<IP>:<mount>[:<image_path>]"
  232  *   into the given ip address, host, mount point, and optionally, image_path.
  233  * Notes:
  234  * - the passed in string is modified i.e. ':' is replaced by '\0'
  235  * - literal colons must be escaped with a backslash
  236  *
  237  * Examples:
  238  * nfs:17.202.42.112:/Library/NetBoot/NetBootSP0:Jaguar/Jaguar.dmg
  239  * nfs:17.202.42.112:/Volumes/Foo\:/Library/NetBoot/NetBootSP0:Jaguar/Jaguar.dmg
  240  */
  241 static __inline__ boolean_t
  242 parse_netboot_path(char * path, struct in_addr * iaddr_p, char * * host,
  243                    char * * mount_dir, char * * image_path)
  244 {
  245     char *      start;
  246     char *      colon;
  247 
  248     if (strncmp(path, kNetBootRootPathPrefixNFS, 
  249                 strlen(kNetBootRootPathPrefixNFS)) != 0) {
  250         return (FALSE);
  251     }
  252 
  253     /* IP address */
  254     start = path + strlen(kNetBootRootPathPrefixNFS);
  255     colon = strchr(start, ':');
  256     if (colon == NULL) {
  257         return (FALSE);
  258     }
  259     *colon = '\0';
  260     if (inet_aton(start, iaddr_p) != 1) {
  261         return (FALSE);
  262     }
  263 
  264     /* mount point */
  265     start = colon + 1;
  266     colon = find_colon(start);
  267     *mount_dir = start;
  268     if (colon == NULL) {
  269         *image_path = NULL;
  270     }
  271     else {
  272         /* image path */
  273         *colon = '\0';
  274         start = colon + 1;
  275         (void)find_colon(start);
  276         *image_path = start;
  277     }
  278     *host = inet_ntoa(*iaddr_p);
  279     return (TRUE);
  280 }
  281 
  282 static boolean_t
  283 parse_image_path(char * path, struct in_addr * iaddr_p, char * * host,
  284                  char * * mount_dir, char * * image_path)
  285 {
  286     if (path[0] >= '' && path[0] <= '9') {
  287         return (parse_booter_path(path, iaddr_p, host, mount_dir,
  288                                   image_path));
  289     }
  290     return (parse_netboot_path(path, iaddr_p, host, mount_dir,
  291                                image_path));
  292 }
  293 
  294 static boolean_t
  295 get_root_path(char * root_path)
  296 {
  297     void *              entry;
  298     boolean_t           found = FALSE;
  299     const void *        pkt;
  300     int                 pkt_len;
  301     
  302     entry = IOBSDRegistryEntryForDeviceTree("/chosen");
  303     if (entry == NULL) {
  304         return (FALSE);
  305     }
  306     pkt = IOBSDRegistryEntryGetData(entry, BSDP_RESPONSE, &pkt_len);
  307     if (pkt != NULL && pkt_len >= sizeof(struct dhcp)) {
  308         printf("netboot: retrieving root path from BSDP response\n");
  309     }
  310     else {
  311         pkt = IOBSDRegistryEntryGetData(entry, BOOTP_RESPONSE, 
  312                                         &pkt_len);
  313         if (pkt != NULL && pkt_len >= sizeof(struct dhcp)) {
  314             printf("netboot: retrieving root path from BOOTP response\n");
  315         }
  316     }
  317     if (pkt != NULL) {
  318         int                     len;
  319         dhcpol_t                options;
  320         char *                  path;
  321         struct dhcp *           reply;
  322 
  323         reply = (struct dhcp *)pkt;
  324         (void)dhcpol_parse_packet(&options, reply, pkt_len, NULL);
  325 
  326         path = (char *)dhcpol_find(&options, 
  327                                    dhcptag_root_path_e, &len, NULL);
  328         if (path) {
  329             bcopy(path, root_path, len);
  330             root_path[len] = '\0';
  331             found = TRUE;
  332         }
  333     }
  334     IOBSDRegistryEntryRelease(entry);
  335     return (found);
  336 
  337 }
  338 
  339 static struct netboot_info *
  340 netboot_info_init(struct in_addr iaddr)
  341 {
  342     struct netboot_info *       info;
  343     char *                      root_path = NULL;
  344     boolean_t                   use_hdix = TRUE;
  345     char *                      vndevice = NULL;
  346 
  347     MALLOC_ZONE(vndevice, caddr_t, MAXPATHLEN, M_NAMEI, M_WAITOK);
  348     if (PE_parse_boot_arg("vndevice", vndevice) == TRUE) {
  349         use_hdix = FALSE;
  350     }
  351     FREE_ZONE(vndevice, MAXPATHLEN, M_NAMEI);
  352 
  353     info = (struct netboot_info *)kalloc(sizeof(*info));
  354     bzero(info, sizeof(*info));
  355     info->client_ip = iaddr;
  356     info->image_type = kNetBootImageTypeUnknown;
  357     info->use_hdix = use_hdix;
  358 
  359     /* check for a booter-specified path then a NetBoot path */
  360     MALLOC_ZONE(root_path, caddr_t, MAXPATHLEN, M_NAMEI, M_WAITOK);
  361     if (PE_parse_boot_arg("rp", root_path) == TRUE
  362         || PE_parse_boot_arg("rootpath", root_path) == TRUE
  363         || get_root_path(root_path) == TRUE) {
  364         char * server_name = NULL;
  365         char * mount_point = NULL;
  366         char * image_path = NULL;
  367         struct in_addr  server_ip;
  368 
  369         if (parse_image_path(root_path, &server_ip, &server_name, 
  370                              &mount_point, &image_path)) {
  371             info->image_type = kNetBootImageTypeNFS;
  372             info->server_ip = server_ip;
  373             info->server_name_length = strlen(server_name) + 1;
  374             info->server_name = (char *)kalloc(info->server_name_length);
  375             info->mount_point_length = strlen(mount_point) + 1;
  376             info->mount_point = (char *)kalloc(info->mount_point_length);
  377             strcpy(info->server_name, server_name);
  378             strcpy(info->mount_point, mount_point);
  379             
  380             printf("Server %s Mount %s", 
  381                    server_name, info->mount_point);
  382             if (image_path != NULL) {
  383                 boolean_t       needs_slash;
  384 
  385                 info->image_path_length = strlen(image_path) + 1;
  386                 if (image_path[0] != '/') {
  387                     needs_slash = TRUE;
  388                     info->image_path_length++;
  389                 }
  390                 info->image_path = (char *)kalloc(info->image_path_length);
  391                 if (needs_slash) {
  392                     info->image_path[0] = '/';
  393                     strcpy(info->image_path + 1, image_path);
  394                 }
  395                 else {
  396                     strcpy(info->image_path, image_path);
  397                 }
  398                 printf(" Image %s", info->image_path);
  399             }
  400             printf("\n");
  401         }
  402         else if (strncmp(root_path, kNetBootRootPathPrefixHTTP, 
  403                          strlen(kNetBootRootPathPrefixHTTP)) == 0) {
  404             /* only HDIX supports HTTP */
  405             info->image_type = kNetBootImageTypeHTTP;
  406             info->use_hdix = TRUE;
  407             info->image_path_length = strlen(root_path) + 1;
  408             info->image_path = (char *)kalloc(info->image_path_length);
  409             strcpy(info->image_path, root_path);
  410         }           
  411         else {
  412             printf("netboot: root path uses unrecognized format\n");
  413         }
  414     }
  415     FREE_ZONE(root_path, MAXPATHLEN, M_NAMEI);
  416     return (info);
  417 }
  418 
  419 static void 
  420 netboot_info_free(struct netboot_info * * info_p)
  421 {
  422     struct netboot_info * info = *info_p;
  423 
  424     if (info) {
  425         if (info->mount_point) {
  426             kfree(info->mount_point, info->mount_point_length);
  427         }
  428         if (info->server_name) {
  429             kfree(info->server_name, info->server_name_length);
  430         }
  431         if (info->image_path) {
  432             kfree(info->image_path, info->image_path_length);
  433         }
  434         kfree(info, sizeof(*info));
  435     }
  436     *info_p = NULL;
  437     return;
  438 }
  439 
  440 boolean_t
  441 netboot_iaddr(struct in_addr * iaddr_p)
  442 {
  443     if (S_netboot_info_p == NULL)
  444         return (FALSE);
  445 
  446     *iaddr_p = S_netboot_info_p->client_ip;
  447     return (TRUE);
  448 }
  449 
  450 boolean_t
  451 netboot_rootpath(struct in_addr * server_ip,
  452                  char * name, int name_len, 
  453                  char * path, int path_len)
  454 {
  455     if (S_netboot_info_p == NULL)
  456         return (FALSE);
  457 
  458     name[0] = '\0';
  459     path[0] = '\0';
  460 
  461     if (S_netboot_info_p->mount_point_length == 0) {
  462         return (FALSE);
  463     }
  464     if (path_len < S_netboot_info_p->mount_point_length) {
  465         printf("netboot: path too small %d < %d\n",
  466                path_len, S_netboot_info_p->mount_point_length);
  467         return (FALSE);
  468     }
  469     strcpy(path, S_netboot_info_p->mount_point);
  470     strncpy(name, S_netboot_info_p->server_name, name_len);
  471     *server_ip = S_netboot_info_p->server_ip;
  472     return (TRUE);
  473 }
  474 
  475 
  476 static boolean_t
  477 get_ip_parameters(struct in_addr * iaddr_p, struct in_addr * netmask_p, 
  478                    struct in_addr * router_p)
  479 {
  480     void *              entry;
  481     const void *        pkt;
  482     int                 pkt_len;
  483 
  484 
  485     entry = IOBSDRegistryEntryForDeviceTree("/chosen");
  486     if (entry == NULL) {
  487         return (FALSE);
  488     }
  489     pkt = IOBSDRegistryEntryGetData(entry, DHCP_RESPONSE, &pkt_len);
  490     if (pkt != NULL && pkt_len >= sizeof(struct dhcp)) {
  491         printf("netboot: retrieving IP information from DHCP response\n");
  492     }
  493     else {
  494         pkt = IOBSDRegistryEntryGetData(entry, BOOTP_RESPONSE, &pkt_len);
  495         if (pkt != NULL && pkt_len >= sizeof(struct dhcp)) {
  496             printf("netboot: retrieving IP information from BOOTP response\n");
  497         }
  498     }
  499     if (pkt != NULL) {
  500         struct in_addr *        ip;
  501         int                     len;
  502         dhcpol_t                options;
  503         struct dhcp *           reply;
  504 
  505         reply = (struct dhcp *)pkt;
  506         (void)dhcpol_parse_packet(&options, reply, pkt_len, NULL);
  507         *iaddr_p = reply->dp_yiaddr;
  508         ip = (struct in_addr *)
  509             dhcpol_find(&options, 
  510                         dhcptag_subnet_mask_e, &len, NULL);
  511         if (ip) {
  512             *netmask_p = *ip;
  513         }
  514         ip = (struct in_addr *)
  515             dhcpol_find(&options, dhcptag_router_e, &len, NULL);
  516         if (ip) {
  517             *router_p = *ip;
  518         }
  519     }
  520     IOBSDRegistryEntryRelease(entry);
  521     return (pkt != NULL);
  522 }
  523 
  524 static int
  525 inet_aifaddr(struct socket * so, char * name, const struct in_addr * addr, 
  526              const struct in_addr * mask,
  527              const struct in_addr * broadcast)
  528 {
  529     struct sockaddr     blank_sin = { sizeof(blank_sin), AF_INET };
  530     struct ifaliasreq   ifra;
  531 
  532     bzero(&ifra, sizeof(ifra));
  533     strncpy(ifra.ifra_name, name, sizeof(ifra.ifra_name));
  534     if (addr) {
  535         ifra.ifra_addr = blank_sin;
  536         ((struct sockaddr_in *)&ifra.ifra_addr)->sin_addr = *addr;
  537     }
  538     if (mask) {
  539         ifra.ifra_mask = blank_sin;
  540         ((struct sockaddr_in *)&ifra.ifra_mask)->sin_addr = *mask;
  541     }
  542     if (broadcast) {
  543         ifra.ifra_broadaddr = blank_sin;
  544         ((struct sockaddr_in *)&ifra.ifra_broadaddr)->sin_addr = *broadcast;
  545     }
  546     return (ifioctl(so, SIOCAIFADDR, (caddr_t)&ifra, current_proc()));
  547 }
  548 
  549 static int
  550 default_route_add(struct in_addr router, boolean_t proxy_arp)
  551 {
  552     struct sockaddr_in          dst;
  553     u_long                      flags = RTF_UP | RTF_STATIC;
  554     struct sockaddr_in          gw;
  555     struct sockaddr_in          mask;
  556     
  557     if (proxy_arp == FALSE) {
  558         flags |= RTF_GATEWAY;
  559     }
  560 
  561     /* dest 0.0.0.0 */
  562     bzero((caddr_t)&dst, sizeof(dst));
  563     dst.sin_len = sizeof(dst);
  564     dst.sin_family = AF_INET;
  565 
  566     /* gateway */
  567     bzero((caddr_t)&gw, sizeof(gw));
  568     gw.sin_len = sizeof(gw);
  569     gw.sin_family = AF_INET;
  570     gw.sin_addr = router;
  571 
  572     /* mask 0.0.0.0 */
  573     bzero(&mask, sizeof(mask));
  574     mask.sin_len = sizeof(mask);
  575     mask.sin_family = AF_INET;
  576 
  577     printf("netboot: adding default route " IP_FORMAT "\n", 
  578            IP_LIST(&router));
  579 
  580     return (rtrequest(RTM_ADD, (struct sockaddr *)&dst, (struct sockaddr *)&gw,
  581                       (struct sockaddr *)&mask, flags, NULL));
  582 }
  583 
  584 static struct ifnet *
  585 find_interface()
  586 {
  587     struct ifnet *              ifp = NULL;
  588 
  589     if (rootdevice[0]) {
  590         ifp = ifunit(rootdevice);
  591     }
  592     if (ifp == NULL) {
  593         TAILQ_FOREACH(ifp, &ifnet, if_link)
  594             if ((ifp->if_flags &
  595                  (IFF_LOOPBACK|IFF_POINTOPOINT)) == 0)
  596                 break;
  597     }
  598     return (ifp);
  599 }
  600 
  601 int
  602 netboot_mountroot()
  603 {
  604     int                         error = 0;
  605     struct in_addr              iaddr = { 0 };
  606     struct ifreq                ifr;
  607     struct ifnet *              ifp;
  608     struct in_addr              netmask = { 0 };
  609     struct proc *               procp = current_proc();
  610     struct in_addr              router = { 0 };
  611     struct socket *             so = NULL;
  612 
  613     bzero(&ifr, sizeof(ifr));
  614 
  615     thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
  616 
  617     /* find the interface */
  618     ifp = find_interface();
  619     if (ifp == NULL) {
  620         printf("netboot: no suitable interface\n");
  621         error = ENXIO;
  622         goto failed;
  623     }
  624     sprintf(ifr.ifr_name, "%s%d", ifp->if_name, ifp->if_unit);
  625     printf("netboot: using network interface '%s'\n", ifr.ifr_name);
  626 
  627     /* bring it up */
  628     if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0)) != 0) {
  629         printf("netboot: socreate, error=%d\n", error);
  630         goto failed;
  631     }
  632     ifr.ifr_flags = ifp->if_flags | IFF_UP;
  633     error = ifioctl(so, SIOCSIFFLAGS, (caddr_t)&ifr, procp);
  634     if (error) {
  635         printf("netboot: SIFFLAGS, error=%d\n", error);
  636         goto failed;
  637     }
  638 
  639     /* grab information from the registry */
  640     if (get_ip_parameters(&iaddr, &netmask, &router) == FALSE) {
  641         /* use BOOTP to retrieve IP address, netmask and router */
  642         error = bootp(ifp, &iaddr, 32, &netmask, &router, procp);
  643         if (error) {
  644             printf("netboot: BOOTP failed %d\n", error);
  645             goto failed;
  646         }
  647     }
  648     printf("netboot: IP address " IP_FORMAT, IP_LIST(&iaddr));
  649     if (netmask.s_addr) {
  650         printf(" netmask " IP_FORMAT, IP_LIST(&netmask));
  651     }
  652     if (router.s_addr) {
  653         printf(" router " IP_FORMAT, IP_LIST(&router));
  654     }
  655     printf("\n");
  656     error = inet_aifaddr(so, ifr.ifr_name, &iaddr, &netmask, NULL);
  657     if (error) {
  658         printf("netboot: inet_aifaddr failed, %d\n", error);
  659         goto failed;
  660     }
  661     if (router.s_addr == 0) {
  662         /* enable proxy arp if we don't have a router */
  663         router.s_addr = iaddr.s_addr;
  664     }
  665     error = default_route_add(router, router.s_addr == iaddr.s_addr);
  666     if (error) {
  667         printf("netboot: default_route_add failed %d\n", error);
  668     }
  669 
  670     soclose(so);
  671     thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
  672 
  673     S_netboot_info_p = netboot_info_init(iaddr);
  674     switch (S_netboot_info_p->image_type) {
  675     default:
  676     case kNetBootImageTypeNFS:
  677         error = nfs_mountroot();
  678         break;
  679     case kNetBootImageTypeHTTP:
  680         error = netboot_setup(procp);
  681         break;
  682     }
  683     if (error == 0) {
  684         S_netboot = 1;
  685     }
  686     else {
  687         S_netboot = 0;
  688     }
  689     return (error);
  690 failed:
  691     if (so != NULL) {
  692         soclose(so);
  693     }
  694     thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
  695     return (error);
  696 }
  697 
  698 int
  699 netboot_setup(struct proc * p)
  700 {
  701     dev_t       dev;
  702     int         error = 0;
  703 
  704     if (S_netboot_info_p == NULL
  705         || S_netboot_info_p->image_path == NULL) {
  706         goto done;
  707     }
  708     if (S_netboot_info_p->use_hdix) {
  709         printf("netboot_setup: calling di_root_image\n");
  710         error = di_root_image(S_netboot_info_p->image_path, 
  711                               rootdevice, &dev);
  712         if (error) {
  713             printf("netboot_setup: di_root_image: failed %d\n", error);
  714             goto done;
  715         }
  716     }
  717     else {
  718         printf("netboot_setup: calling vndevice_root_image\n");
  719         error = vndevice_root_image(S_netboot_info_p->image_path, 
  720                                     rootdevice, &dev);
  721         if (error) {
  722             printf("netboot_setup: vndevice_root_image: failed %d\n", error);
  723             goto done;
  724         }
  725     }
  726     rootdev = dev;
  727     mountroot = NULL;
  728     printf("netboot: root device 0x%x\n", rootdev);
  729     error = vfs_mountroot();
  730     if (error == 0 && rootvnode != NULL) {
  731         struct vnode *tvp;
  732         struct vnode *newdp;
  733 
  734         /* Get the vnode for '/'.  Set fdp->fd_fd.fd_cdir to reference it. */
  735         if (VFS_ROOT(mountlist.cqh_last, &newdp))
  736                 panic("netboot_setup: cannot find root vnode");
  737         VREF(newdp);
  738         tvp = rootvnode;
  739         vrele(tvp);
  740         filedesc0.fd_cdir = newdp;
  741         rootvnode = newdp;
  742         simple_lock(&mountlist_slock);
  743         CIRCLEQ_REMOVE(&mountlist, CIRCLEQ_FIRST(&mountlist), mnt_list);
  744         simple_unlock(&mountlist_slock);
  745         VOP_UNLOCK(rootvnode, 0, p);
  746         mountlist.cqh_first->mnt_flag |= MNT_ROOTFS;
  747     }
  748  done:
  749     netboot_info_free(&S_netboot_info_p);
  750     return (error);
  751 }
  752 
  753 int
  754 netboot_root()
  755 {
  756     return (S_netboot);
  757 }

Cache object: f059cb8b99e0ad8ba2285d4994106d00


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.