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/lib/libsa/bootp.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 /*      $NetBSD: bootp.c,v 1.25 2003/08/31 22:40:47 fvdl Exp $  */
    2 
    3 /*
    4  * Copyright (c) 1992 Regents of the University of California.
    5  * All rights reserved.
    6  *
    7  * This software was developed by the Computer Systems Engineering group
    8  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
    9  * contributed to Berkeley.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  * 3. All advertising materials mentioning features or use of this software
   20  *    must display the following acknowledgement:
   21  *      This product includes software developed by the University of
   22  *      California, Lawrence Berkeley Laboratory and its contributors.
   23  * 4. Neither the name of the University nor the names of its contributors
   24  *    may be used to endorse or promote products derived from this software
   25  *    without specific prior written permission.
   26  *
   27  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   28  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   30  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   31  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   32  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   33  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   34  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   35  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   36  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   37  * SUCH DAMAGE.
   38  *
   39  * @(#) Header: bootp.c,v 1.4 93/09/11 03:13:51 leres Exp  (LBL)
   40  */
   41 
   42 #include <sys/param.h>
   43 #include <netinet/in.h>
   44 #include <netinet/in_systm.h>
   45 
   46 #ifdef _STANDALONE
   47 #include <lib/libkern/libkern.h>
   48 #else
   49 #include <string.h>
   50 #endif
   51 
   52 #include "stand.h"
   53 #include "net.h"
   54 #include "bootp.h"
   55 
   56 struct in_addr servip;
   57 #ifdef SUPPORT_LINUX
   58 char linuxcmdline[256];
   59 #ifndef TAG_LINUX_CMDLINE
   60 #define TAG_LINUX_CMDLINE 123
   61 #endif
   62 #endif
   63 
   64 static n_long   nmask, smask;
   65 
   66 static time_t   bot;
   67 
   68 static  char vm_rfc1048[4] = VM_RFC1048;
   69 #ifdef BOOTP_VEND_CMU
   70 static  char vm_cmu[4] = VM_CMU;
   71 #endif
   72 
   73 /* Local forwards */
   74 static  ssize_t bootpsend __P((struct iodesc *, void *, size_t));
   75 static  ssize_t bootprecv __P((struct iodesc *, void *, size_t, time_t));
   76 static  int vend_rfc1048 __P((u_char *, u_int));
   77 #ifdef BOOTP_VEND_CMU
   78 static  void vend_cmu __P((u_char *));
   79 #endif
   80 
   81 #ifdef SUPPORT_DHCP
   82 static char expected_dhcpmsgtype = -1, dhcp_ok;
   83 struct in_addr dhcp_serverip;
   84 #endif
   85 
   86 /*
   87  * Boot programs can patch this at run-time to change the behavior
   88  * of bootp/dhcp.
   89  */
   90 int bootp_flags;
   91 
   92 /* Fetch required bootp information */
   93 void
   94 bootp(sock)
   95         int sock;
   96 {
   97         struct iodesc *d;
   98         struct bootp *bp;
   99         struct {
  100                 u_char header[HEADER_SIZE];
  101                 struct bootp wbootp;
  102         } wbuf;
  103         struct {
  104                 u_char header[HEADER_SIZE];
  105                 struct bootp rbootp;
  106         } rbuf;
  107 #ifdef SUPPORT_DHCP
  108         char vci[64];
  109         int vcilen;
  110 #endif
  111 
  112 #ifdef BOOTP_DEBUG
  113         if (debug)
  114                 printf("bootp: socket=%d\n", sock);
  115 #endif
  116         if (!bot)
  117                 bot = getsecs();
  118         
  119         if (!(d = socktodesc(sock))) {
  120                 printf("bootp: bad socket. %d\n", sock);
  121                 return;
  122         }
  123 #ifdef BOOTP_DEBUG
  124         if (debug)
  125                 printf("bootp: d=%lx\n", (long)d);
  126 #endif
  127 
  128         bp = &wbuf.wbootp;
  129         bzero(bp, sizeof(*bp));
  130 
  131         bp->bp_op = BOOTREQUEST;
  132         bp->bp_htype = 1;               /* 10Mb Ethernet (48 bits) */
  133         bp->bp_hlen = 6;
  134         bp->bp_xid = htonl(d->xid);
  135         MACPY(d->myea, bp->bp_chaddr);
  136         strncpy(bp->bp_file, bootfile, sizeof(bp->bp_file));
  137         bcopy(vm_rfc1048, bp->bp_vend, sizeof(vm_rfc1048));
  138 #ifdef SUPPORT_DHCP
  139         bp->bp_vend[4] = TAG_DHCP_MSGTYPE;
  140         bp->bp_vend[5] = 1;
  141         bp->bp_vend[6] = DHCPDISCOVER;
  142         /*
  143          * Insert a NetBSD Vendor Class Identifier option.
  144          */
  145         sprintf(vci, "NetBSD:%s:libsa", MACHINE);
  146         vcilen = strlen(vci);
  147         bp->bp_vend[7] = TAG_CLASSID;
  148         bp->bp_vend[8] = vcilen;
  149         bcopy(vci, &bp->bp_vend[9], vcilen);
  150         bp->bp_vend[9 + vcilen] = TAG_END;
  151 #else
  152         bp->bp_vend[4] = TAG_END;
  153 #endif
  154 
  155         d->myip.s_addr = INADDR_ANY;
  156         d->myport = htons(IPPORT_BOOTPC);
  157         d->destip.s_addr = INADDR_BROADCAST;
  158         d->destport = htons(IPPORT_BOOTPS);
  159 
  160 #ifdef SUPPORT_DHCP
  161         expected_dhcpmsgtype = DHCPOFFER;
  162         dhcp_ok = 0;
  163 #endif
  164 
  165         if (sendrecv(d,
  166                     bootpsend, bp, sizeof(*bp),
  167                     bootprecv, &rbuf.rbootp, sizeof(rbuf.rbootp))
  168            == -1) {
  169                 printf("bootp: no reply\n");
  170                 return;
  171         }
  172 
  173 #ifdef SUPPORT_DHCP
  174         if (dhcp_ok) {
  175                 u_int32_t leasetime;
  176                 bp->bp_vend[6] = DHCPREQUEST;
  177                 bp->bp_vend[7] = TAG_REQ_ADDR;
  178                 bp->bp_vend[8] = 4;
  179                 bcopy(&rbuf.rbootp.bp_yiaddr, &bp->bp_vend[9], 4);
  180                 bp->bp_vend[13] = TAG_SERVERID;
  181                 bp->bp_vend[14] = 4;
  182                 bcopy(&dhcp_serverip.s_addr, &bp->bp_vend[15], 4);
  183                 bp->bp_vend[19] = TAG_LEASETIME;
  184                 bp->bp_vend[20] = 4;
  185                 leasetime = htonl(300);
  186                 bcopy(&leasetime, &bp->bp_vend[21], 4);
  187                 /*
  188                  * Insert a NetBSD Vendor Class Identifier option.
  189                  */
  190                 sprintf(vci, "NetBSD:%s:libsa", MACHINE);
  191                 vcilen = strlen(vci);
  192                 bp->bp_vend[25] = TAG_CLASSID;
  193                 bp->bp_vend[26] = vcilen;
  194                 bcopy(vci, &bp->bp_vend[27], vcilen);
  195                 bp->bp_vend[27 + vcilen] = TAG_END;
  196 
  197                 expected_dhcpmsgtype = DHCPACK;
  198 
  199                 if (sendrecv(d,
  200                             bootpsend, bp, sizeof(*bp),
  201                             bootprecv, &rbuf.rbootp, sizeof(rbuf.rbootp))
  202                    == -1) {
  203                         printf("DHCPREQUEST failed\n");
  204                         return;
  205                 }
  206         }
  207 #endif
  208 
  209         myip = d->myip = rbuf.rbootp.bp_yiaddr;
  210         servip = rbuf.rbootp.bp_siaddr;
  211         if (rootip.s_addr == INADDR_ANY)
  212                 rootip = servip;
  213         bcopy(rbuf.rbootp.bp_file, bootfile, sizeof(bootfile));
  214         bootfile[sizeof(bootfile) - 1] = '\0';
  215 
  216         if (IN_CLASSA(myip.s_addr))
  217                 nmask = IN_CLASSA_NET;
  218         else if (IN_CLASSB(myip.s_addr))
  219                 nmask = IN_CLASSB_NET;
  220         else
  221                 nmask = IN_CLASSC_NET;
  222 #ifdef BOOTP_DEBUG
  223         if (debug)
  224                 printf("'native netmask' is %s\n", intoa(nmask));
  225 #endif
  226 
  227         /* Get subnet (or natural net) mask */
  228         netmask = nmask;
  229         if (smask)
  230                 netmask = smask;
  231 #ifdef BOOTP_DEBUG
  232         if (debug)
  233                 printf("mask: %s\n", intoa(netmask));
  234 #endif
  235 
  236         /* We need a gateway if root is on a different net */
  237         if (!SAMENET(myip, rootip, netmask)) {
  238 #ifdef BOOTP_DEBUG
  239                 if (debug)
  240                         printf("need gateway for root ip\n");
  241 #endif
  242         }
  243 
  244         /* Toss gateway if on a different net */
  245         if (!SAMENET(myip, gateip, netmask)) {
  246 #ifdef BOOTP_DEBUG
  247                 if (debug)
  248                         printf("gateway ip (%s) bad\n", inet_ntoa(gateip));
  249 #endif
  250                 gateip.s_addr = 0;
  251         }
  252 
  253         printf("net_open: client addr: %s\n", inet_ntoa(myip));
  254         if (smask)
  255                 printf("net_open: subnet mask: %s\n", intoa(smask));
  256         if (gateip.s_addr != 0)
  257                 printf("net_open: net gateway: %s\n", inet_ntoa(gateip));
  258         printf("net_open: server addr: %s\n", inet_ntoa(rootip));
  259         if (rootpath[0] != '\0')
  260                 printf("net_open: server path: %s\n", rootpath);
  261         if (bootfile[0] != '\0')
  262                 printf("net_open: file name: %s\n", bootfile);
  263 
  264         /* Bump xid so next request will be unique. */
  265         ++d->xid;
  266 }
  267 
  268 /* Transmit a bootp request */
  269 static ssize_t
  270 bootpsend(d, pkt, len)
  271         struct iodesc *d;
  272         void *pkt;
  273         size_t len;
  274 {
  275         struct bootp *bp;
  276 
  277 #ifdef BOOTP_DEBUG
  278         if (debug)
  279                 printf("bootpsend: d=%lx called.\n", (long)d);
  280 #endif
  281 
  282         bp = pkt;
  283         bp->bp_secs = htons((u_short)(getsecs() - bot));
  284 
  285 #ifdef BOOTP_DEBUG
  286         if (debug)
  287                 printf("bootpsend: calling sendudp\n");
  288 #endif
  289 
  290         return (sendudp(d, pkt, len));
  291 }
  292 
  293 static ssize_t
  294 bootprecv(d, pkt, len, tleft)
  295         struct iodesc *d;
  296         void *pkt;
  297         size_t len;
  298         time_t tleft;
  299 {
  300         ssize_t n;
  301         struct bootp *bp;
  302 
  303 #ifdef BOOTP_DEBUGx
  304         if (debug)
  305                 printf("bootp_recvoffer: called\n");
  306 #endif
  307 
  308         n = readudp(d, pkt, len, tleft);
  309         if (n == -1 || (size_t)n < sizeof(struct bootp) - BOOTP_VENDSIZE)
  310                 goto bad;
  311 
  312         bp = (struct bootp *)pkt;
  313         
  314 #ifdef BOOTP_DEBUG
  315         if (debug)
  316                 printf("bootprecv: checked.  bp = 0x%lx, n = %d\n",
  317                     (long)bp, (int)n);
  318 #endif
  319         if (bp->bp_xid != htonl(d->xid)) {
  320 #ifdef BOOTP_DEBUG
  321                 if (debug) {
  322                         printf("bootprecv: expected xid 0x%lx, got 0x%x\n",
  323                             d->xid, ntohl(bp->bp_xid));
  324                 }
  325 #endif
  326                 goto bad;
  327         }
  328 
  329         /* protect against bogus addresses sent by DHCP servers */
  330         if (bp->bp_yiaddr.s_addr == INADDR_ANY ||
  331             bp->bp_yiaddr.s_addr == INADDR_BROADCAST)
  332                 goto bad;
  333 
  334 #ifdef BOOTP_DEBUG
  335         if (debug)
  336                 printf("bootprecv: got one!\n");
  337 #endif
  338 
  339         /* Suck out vendor info */
  340         if (bcmp(vm_rfc1048, bp->bp_vend, sizeof(vm_rfc1048)) == 0) {
  341                 if (vend_rfc1048(bp->bp_vend, sizeof(bp->bp_vend)) != 0)
  342                         goto bad;
  343         }
  344 #ifdef BOOTP_VEND_CMU
  345         else if (bcmp(vm_cmu, bp->bp_vend, sizeof(vm_cmu)) == 0)
  346                 vend_cmu(bp->bp_vend);
  347 #endif
  348         else
  349                 printf("bootprecv: unknown vendor 0x%lx\n", (long)bp->bp_vend);
  350 
  351         return (n);
  352 bad:
  353         errno = 0;
  354         return (-1);
  355 }
  356 
  357 static int
  358 vend_rfc1048(cp, len)
  359         u_char *cp;
  360         u_int len;
  361 {
  362         u_char *ep;
  363         int size;
  364         u_char tag;
  365 
  366 #ifdef BOOTP_DEBUG
  367         if (debug)
  368                 printf("vend_rfc1048 bootp info. len=%d\n", len);
  369 #endif
  370         ep = cp + len;
  371 
  372         /* Step over magic cookie */
  373         cp += sizeof(int);
  374 
  375         while (cp < ep) {
  376                 tag = *cp++;
  377                 size = *cp++;
  378                 if (tag == TAG_END)
  379                         break;
  380 
  381                 if (tag == TAG_SUBNET_MASK) {
  382                         bcopy(cp, &smask, sizeof(smask));
  383                 }
  384                 if (tag == TAG_GATEWAY) {
  385                         bcopy(cp, &gateip.s_addr, sizeof(gateip.s_addr));
  386                 }
  387                 if (tag == TAG_SWAPSERVER) {
  388                         /* let it override bp_siaddr */
  389                         bcopy(cp, &rootip.s_addr, sizeof(rootip.s_addr));
  390                 }
  391                 if (tag == TAG_ROOTPATH) {
  392                         strncpy(rootpath, (char *)cp, sizeof(rootpath));
  393                         rootpath[size] = '\0';
  394                 }
  395                 if (tag == TAG_HOSTNAME) {
  396                         strncpy(hostname, (char *)cp, sizeof(hostname));
  397                         hostname[size] = '\0';
  398                 }
  399 #ifdef SUPPORT_DHCP
  400                 if (tag == TAG_DHCP_MSGTYPE) {
  401                         if (*cp != expected_dhcpmsgtype)
  402                                 return (-1);
  403                         dhcp_ok = 1;
  404                 }
  405                 if (tag == TAG_SERVERID) {
  406                         bcopy(cp, &dhcp_serverip.s_addr,
  407                               sizeof(dhcp_serverip.s_addr));
  408                 }
  409 #endif
  410 #ifdef SUPPORT_LINUX
  411                 if (tag == TAG_LINUX_CMDLINE) {
  412                         strncpy(linuxcmdline, (char *)cp, sizeof(linuxcmdline));
  413                         linuxcmdline[size] = '\0';
  414                 }
  415 #endif
  416                 cp += size;
  417         }
  418         return (0);
  419 }
  420 
  421 #ifdef BOOTP_VEND_CMU
  422 static void
  423 vend_cmu(cp)
  424         u_char *cp;
  425 {
  426         struct cmu_vend *vp;
  427 
  428 #ifdef BOOTP_DEBUG
  429         if (debug)
  430                 printf("vend_cmu bootp info.\n");
  431 #endif
  432         vp = (struct cmu_vend *)cp;
  433 
  434         if (vp->v_smask.s_addr != 0) {
  435                 smask = vp->v_smask.s_addr;
  436         }
  437         if (vp->v_dgate.s_addr != 0) {
  438                 gateip = vp->v_dgate;
  439         }
  440 }
  441 #endif

Cache object: 6d9d7217a88c58d7f5445afbcebba464


[ 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.