Author: luigi
Date: Tue Jan 13 22:46:24 2009
New Revision: 187200
URL: http://svn.freebsd.org/changeset/base/187200

Log:
  MFC from rev.185643 and 186799
  
  Some libstand/bootp.c extension (written by Danny Braniss, slightly
  revised/modified by me) to store dhcp options into kenv variables,
  so the information is available to the boot loader and can be used
  to customize the boot process.

Modified:
  stable/7/lib/libstand/bootp.c

Modified: stable/7/lib/libstand/bootp.c
==============================================================================
--- stable/7/lib/libstand/bootp.c       Tue Jan 13 22:35:26 2009        
(r187199)
+++ stable/7/lib/libstand/bootp.c       Tue Jan 13 22:46:24 2009        
(r187200)
@@ -47,6 +47,12 @@ __FBSDID("$FreeBSD$");
 #define BOOTP_DEBUGxx
 #define SUPPORT_DHCP
 
+#define        DHCP_ENV_NOVENDOR       1       /* do not parse vendor options 
*/
+#define        DHCP_ENV_PXE            10      /* assume pxe vendor options */
+#define        DHCP_ENV_FREEBSD        11      /* assume freebsd vendor options
+/* set DHCP_ENV to one of the values above to export dhcp options to kenv */
+#define DHCP_ENV               DHCP_ENV_NO_VENDOR
+
 #include "stand.h"
 #include "net.h"
 #include "netif.h"
@@ -72,6 +78,13 @@ static       int vend_rfc1048(u_char *, u_int)
 static void vend_cmu(u_char *);
 #endif
 
+#ifdef DHCP_ENV                /* export the dhcp response to kenv */
+struct dhcp_opt;
+static void setenv_(u_char *cp,  u_char *ep, struct dhcp_opt *opts);
+#else
+#define setenv_(a, b, c)
+#endif
+
 #ifdef SUPPORT_DHCP
 static char expected_dhcpmsgtype = -1, dhcp_ok;
 struct in_addr dhcp_serverip;
@@ -351,6 +364,8 @@ vend_rfc1048(cp, len)
        /* Step over magic cookie */
        cp += sizeof(int);
 
+       setenv_(cp, ep, NULL);
+
        while (cp < ep) {
                tag = *cp++;
                size = *cp++;
@@ -412,3 +427,316 @@ vend_cmu(cp)
        }
 }
 #endif
+
+#ifdef DHCP_ENV
+/*
+ * Parse DHCP options and store them into kenv variables.
+ * Original code from Danny Braniss, modifications by Luigi Rizzo.
+ *
+ * The parser is driven by tables which specify the type and name of
+ * each dhcp option and how it appears in kenv.
+ * The first entry in the list contains the prefix used to set the kenv
+ * name (including the . if needed), the last entry must have a 0 tag.
+ * Entries do not need to be sorted though it helps for readability.
+ *
+ * Certain vendor-specific tables can be enabled according to DHCP_ENV.
+ * Set it to 0 if you don't want any.
+ */
+enum opt_fmt { __NONE = 0,
+       __8 = 1, __16 = 2, __32 = 4,    /* Unsigned fields, value=size  */
+       __IP,                           /* IPv4 address                 */
+       __TXT,                          /* C string                     */
+       __BYTES,                        /* byte sequence, printed %02x  */
+       __INDIR,                        /* name=value                   */
+       __ILIST,                        /* name=value;name=value ... */
+       __VE,                           /* vendor specific, recurse     */
+};
+
+struct dhcp_opt {
+       uint8_t tag;
+       uint8_t fmt;
+       const char      *desc;
+};
+
+static struct dhcp_opt vndr_opt[] = { /* Vendor Specific Options */
+#if DHCP_ENV == DHCP_ENV_FREEBSD /* FreeBSD table in the original code */
+       {0,     0,      "FreeBSD"},             /* prefix */
+       {1,     __TXT,  "kernel"},
+       {2,     __TXT,  "kernelname"},
+       {3,     __TXT,  "kernel_options"},
+       {4,     __IP,   "usr-ip"},
+       {5,     __TXT,  "conf-path"},
+       {6,     __TXT,  "rc.conf0"},
+       {7,     __TXT,  "rc.conf1"},
+       {8,     __TXT,  "rc.conf2"},
+       {9,     __TXT,  "rc.conf3"},
+       {10,    __TXT,  "rc.conf4"},
+       {11,    __TXT,  "rc.conf5"},
+       {12,    __TXT,  "rc.conf6"},
+       {13,    __TXT,  "rc.conf7"},
+       {14,    __TXT,  "rc.conf8"},
+       {15,    __TXT,  "rc.conf9"},
+
+       {20,    __TXT,  "boot.nfsroot.options"},
+
+       {245,   __INDIR, ""},
+       {246,   __INDIR, ""},
+       {247,   __INDIR, ""},
+       {248,   __INDIR, ""},
+       {249,   __INDIR, ""},
+       {250,   __INDIR, ""},
+       {251,   __INDIR, ""},
+       {252,   __INDIR, ""},
+       {253,   __INDIR, ""},
+       {254,   __INDIR, ""},
+
+#elif DHCP_ENV == DHCP_ENV_PXE         /* some pxe options, RFC4578 */
+       {0,     0,      "pxe"},         /* prefix */
+       {93,    __16,   "system-architecture"},
+       {94,    __BYTES,        "network-interface"},
+       {97,    __BYTES,        "machine-identifier"},
+#else                                  /* default (empty) table */
+       {0,     0,      "dhcp.vendor."},                /* prefix */
+#endif
+       {0,     __TXT,  "%soption-%d"}
+};
+
+static struct dhcp_opt dhcp_opt[] = {
+       /* DHCP Option names, formats and codes, from RFC2132. */
+       {0,     0,      "dhcp."},       // prefix
+       {1,     __IP,   "subnet-mask"},
+       {2,     __32,   "time-offset"}, /* this is signed */
+       {3,     __IP,   "routers"},
+       {4,     __IP,   "time-servers"},
+       {5,     __IP,   "ien116-name-servers"},
+       {6,     __IP,   "domain-name-servers"},
+       {7,     __IP,   "log-servers"},
+       {8,     __IP,   "cookie-servers"},
+       {9,     __IP,   "lpr-servers"},
+       {10,    __IP,   "impress-servers"},
+       {11,    __IP,   "resource-location-servers"},
+       {12,    __TXT,  "host-name"},
+       {13,    __16,   "boot-size"},
+       {14,    __TXT,  "merit-dump"},
+       {15,    __TXT,  "domain-name"},
+       {16,    __IP,   "swap-server"},
+       {17,    __TXT,  "root-path"},
+       {18,    __TXT,  "extensions-path"},
+       {19,    __8,    "ip-forwarding"},
+       {20,    __8,    "non-local-source-routing"},
+       {21,    __IP,   "policy-filter"},
+       {22,    __16,   "max-dgram-reassembly"},
+       {23,    __8,    "default-ip-ttl"},
+       {24,    __32,   "path-mtu-aging-timeout"},
+       {25,    __16,   "path-mtu-plateau-table"},
+       {26,    __16,   "interface-mtu"},
+       {27,    __8,    "all-subnets-local"},
+       {28,    __IP,   "broadcast-address"},
+       {29,    __8,    "perform-mask-discovery"},
+       {30,    __8,    "mask-supplier"},
+       {31,    __8,    "perform-router-discovery"},
+       {32,    __IP,   "router-solicitation-address"},
+       {33,    __IP,   "static-routes"},
+       {34,    __8,    "trailer-encapsulation"},
+       {35,    __32,   "arp-cache-timeout"},
+       {36,    __8,    "ieee802-3-encapsulation"},
+       {37,    __8,    "default-tcp-ttl"},
+       {38,    __32,   "tcp-keepalive-interval"},
+       {39,    __8,    "tcp-keepalive-garbage"},
+       {40,    __TXT,  "nis-domain"},
+       {41,    __IP,   "nis-servers"},
+       {42,    __IP,   "ntp-servers"},
+       {43,    __VE,   "vendor-encapsulated-options"},
+       {44,    __IP,   "netbios-name-servers"},
+       {45,    __IP,   "netbios-dd-server"},
+       {46,    __8,    "netbios-node-type"},
+       {47,    __TXT,  "netbios-scope"},
+       {48,    __IP,   "x-font-servers"},
+       {49,    __IP,   "x-display-managers"},
+       {50,    __IP,   "dhcp-requested-address"},
+       {51,    __32,   "dhcp-lease-time"},
+       {52,    __8,    "dhcp-option-overload"},
+       {53,    __8,    "dhcp-message-type"},
+       {54,    __IP,   "dhcp-server-identifier"},
+       {55,    __8,    "dhcp-parameter-request-list"},
+       {56,    __TXT,  "dhcp-message"},
+       {57,    __16,   "dhcp-max-message-size"},
+       {58,    __32,   "dhcp-renewal-time"},
+       {59,    __32,   "dhcp-rebinding-time"},
+       {60,    __TXT,  "vendor-class-identifier"},
+       {61,    __TXT,  "dhcp-client-identifier"},
+       {64,    __TXT,  "nisplus-domain"},
+       {65,    __IP,   "nisplus-servers"},
+       {66,    __TXT,  "tftp-server-name"},
+       {67,    __TXT,  "bootfile-name"},
+       {68,    __IP,   "mobile-ip-home-agent"},
+       {69,    __IP,   "smtp-server"},
+       {70,    __IP,   "pop-server"},
+       {71,    __IP,   "nntp-server"},
+       {72,    __IP,   "www-server"},
+       {73,    __IP,   "finger-server"},
+       {74,    __IP,   "irc-server"},
+       {75,    __IP,   "streettalk-server"},
+       {76,    __IP,   "streettalk-directory-assistance-server"},
+       {77,    __TXT,  "user-class"},
+       {85,    __IP,   "nds-servers"},
+       {86,    __TXT,  "nds-tree-name"},
+       {87,    __TXT,  "nds-context"},
+       {210,   __TXT,  "authenticate"},
+
+       /* use the following entries for arbitrary variables */
+       {246,   __ILIST, ""},
+       {247,   __ILIST, ""},
+       {248,   __ILIST, ""},
+       {249,   __ILIST, ""},
+       {250,   __INDIR, ""},
+       {251,   __INDIR, ""},
+       {252,   __INDIR, ""},
+       {253,   __INDIR, ""},
+       {254,   __INDIR, ""},
+       {0,     __TXT,  "%soption-%d"}
+};
+
+/*
+ * parse a dhcp response, set environment variables translating options
+ * names and values according to the tables above. Also set dhcp.tags
+ * to the list of selected tags.
+ */
+static void
+setenv_(u_char *cp,  u_char *ep, struct dhcp_opt *opts)
+{
+    u_char     *ncp;
+    u_char     tag;
+    char       tags[512], *tp; /* the list of tags */
+
+#define FLD_SEP        ','     /* separator in list of elements */
+    ncp = cp;
+    tp = tags;
+    if (opts == NULL)
+       opts = dhcp_opt;
+
+    while (ncp < ep) {
+       unsigned int    size;           /* option size */
+       char *vp, *endv, buf[256];      /* the value buffer */
+       struct dhcp_opt *op;
+
+       tag = *ncp++;                   /* extract tag and size */
+       size = *ncp++;
+       cp = ncp;                       /* current payload */
+       ncp += size;                    /* point to the next option */
+
+       if (tag == TAG_END)
+           break;
+       if (tag == 0)
+           continue;
+
+       for (op = opts+1; op->tag && op->tag != tag; op++)
+               ;
+       /* if not found we end up on the default entry */
+
+       /*
+        * Copy data into the buffer. libstand does not have snprintf so we
+        * need to be careful with sprintf(). With strings, the source is
+        * always <256 char so shorter than the buffer so we are safe; with
+        * other arguments, the longest string is inet_ntoa which is 16 bytes
+        * so we make sure to have always enough room in the string before
+        * trying an sprint.
+        */
+       vp = buf;
+       *vp = '\0';
+       endv = buf + sizeof(buf) - 1 - 16;      /* last valid write position */
+
+       switch(op->fmt) {
+       case __NONE:
+           break;      /* should not happen */
+
+       case __VE: /* recurse, vendor specific */
+           setenv_(cp, cp+size, vndr_opt);
+           break;
+
+       case __IP:      /* ip address */
+           for (; size > 0 && vp < endv; size -= 4, cp += 4) {
+               struct  in_addr in_ip;          /* ip addresses */
+               if (vp != buf)
+                   *vp++ = FLD_SEP;
+               bcopy(cp, &in_ip.s_addr, sizeof(in_ip.s_addr));
+               sprintf(vp, "%s", inet_ntoa(in_ip));
+               vp += strlen(vp);
+           }
+           break;
+
+       case __BYTES:   /* opaque byte string */
+           for (; size > 0 && vp < endv; size -= 1, cp += 1) {
+               sprintf(vp, "%02x", *cp);
+               vp += strlen(vp);
+           }
+           break;
+
+       case __TXT:
+           bcopy(cp, buf, size);       /* cannot overflow */
+           buf[size] = 0;
+           break;
+
+       case __32:
+       case __16:
+       case __8:       /* op->fmt is also the length of each field */
+           for (; size > 0 && vp < endv; size -= op->fmt, cp += op->fmt) {
+               uint32_t v;
+               if (op->fmt == __32)
+                       v = (cp[0]<<24) + (cp[1]<<16) + (cp[2]<<8) + cp[3];
+               else if (op->fmt == __16)
+                       v = (cp[0]<<8) + cp[1];
+               else
+                       v = cp[0];
+               if (vp != buf)
+                   *vp++ = FLD_SEP;
+               sprintf(vp, "%u", v);
+               vp += strlen(vp);
+           }
+           break;
+
+       case __INDIR:   /* name=value */
+       case __ILIST:   /* name=value;name=value... */
+           bcopy(cp, buf, size);       /* cannot overflow */
+           buf[size] = '\0';
+           for (endv = buf; endv; endv = vp) {
+               u_char *s = NULL;       /* semicolon ? */
+
+               /* skip leading whitespace */
+               while (*endv && index(" \t\n\r", *endv))
+                   endv++;
+               vp = index(endv, '=');  /* find name=value separator */
+               if (!vp)
+                   break;
+               *vp++ = 0;
+               if (op->fmt == __ILIST && (s = index(vp, ';')))
+                   *s++ = '\0';
+               setenv(endv, vp, 1);
+               vp = s; /* prepare for next round */
+           }
+           buf[0] = '\0';      /* option already done */
+       }
+
+       if (tp - tags < sizeof(tags) - 5) {     /* add tag to the list */
+           if (tp != tags)
+               *tp++ = FLD_SEP;
+           sprintf(tp, "%d", tag);
+           tp += strlen(tp);
+       }
+       if (buf[0]) {
+           char        env[128];       /* the string name */
+
+           if (op->tag == 0)
+               sprintf(env, op->desc, opts[0].desc, tag);
+           else
+               sprintf(env, "%s%s", opts[0].desc, op->desc);
+           setenv(env, buf, 1);
+       }
+    }
+    if (tp != tags) {
+       char    env[128];       /* the string name */
+       sprintf(env, "%stags", opts[0].desc);
+       setenv(env, tags, 1);
+    }
+}
+#endif /* additional dhcp */
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to