Diff for /embedaddon/dnsmasq/src/rfc2131.c between versions 1.1.1.3 and 1.1.1.4

version 1.1.1.3, 2016/11/02 09:57:01 version 1.1.1.4, 2021/03/17 00:56:46
Line 1 Line 1
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
   
    This program is free software; you can redistribute it and/or modify     This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by     it under the terms of the GNU General Public License as published by
Line 30  static struct in_addr server_id(struct dhcp_context *c Line 30  static struct in_addr server_id(struct dhcp_context *c
 static unsigned int calc_time(struct dhcp_context *context, struct dhcp_config *config, unsigned char *opt);  static unsigned int calc_time(struct dhcp_context *context, struct dhcp_config *config, unsigned char *opt);
 static void option_put(struct dhcp_packet *mess, unsigned char *end, int opt, int len, unsigned int val);  static void option_put(struct dhcp_packet *mess, unsigned char *end, int opt, int len, unsigned int val);
 static void option_put_string(struct dhcp_packet *mess, unsigned char *end,   static void option_put_string(struct dhcp_packet *mess, unsigned char *end, 
                              int opt, char *string, int null_term);                              int opt, const char *string, int null_term);
 static struct in_addr option_addr(unsigned char *opt);  static struct in_addr option_addr(unsigned char *opt);
static unsigned int option_uint(unsigned char *opt, int i, int size);static unsigned int option_uint(unsigned char *opt, int offset, int size);
 static void log_packet(char *type, void *addr, unsigned char *ext_mac,   static void log_packet(char *type, void *addr, unsigned char *ext_mac, 
                        int mac_len, char *interface, char *string, char *err, u32 xid);                         int mac_len, char *interface, char *string, char *err, u32 xid);
 static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt_type, int minsize);  static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt_type, int minsize);
Line 42  static void clear_packet(struct dhcp_packet *mess, uns Line 42  static void clear_packet(struct dhcp_packet *mess, uns
 static int in_list(unsigned char *list, int opt);  static int in_list(unsigned char *list, int opt);
 static void do_options(struct dhcp_context *context,  static void do_options(struct dhcp_context *context,
                        struct dhcp_packet *mess,                         struct dhcp_packet *mess,
                       unsigned char *real_end,                        unsigned char *end,
                        unsigned char *req_options,                         unsigned char *req_options,
                        char *hostname,                          char *hostname, 
                       char *config_domain,                       char *domain,
                        struct dhcp_netid *netid,                         struct dhcp_netid *netid,
                        struct in_addr subnet_addr,                          struct in_addr subnet_addr, 
                        unsigned char fqdn_flags,                         unsigned char fqdn_flags,
                       int null_term, int pxearch,                       int null_term, int pxe_arch,
                        unsigned char *uuid,                         unsigned char *uuid,
                        int vendor_class_len,                         int vendor_class_len,
                        time_t now,                         time_t now,
                        unsigned int lease_time,                         unsigned int lease_time,
                       unsigned short fuzz);                       unsigned short fuzz,
                        const char *pxevendor);
   
   
 static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt);   static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt); 
static int do_encap_opts(struct dhcp_opt *opts, int encap, int flag, struct dhcp_packet *mess, unsigned char *end, int null_term);static int do_encap_opts(struct dhcp_opt *opt, int encap, int flag, struct dhcp_packet *mess, unsigned char *end, int null_term);
static void pxe_misc(struct dhcp_packet *mess, unsigned char *end, unsigned char *uuid);static void pxe_misc(struct dhcp_packet *mess, unsigned char *end, unsigned char *uuid, const char *pxevendor);
 static int prune_vendor_opts(struct dhcp_netid *netid);  static int prune_vendor_opts(struct dhcp_netid *netid);
 static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid, struct in_addr local, time_t now);  static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid, struct in_addr local, time_t now);
 struct dhcp_boot *find_boot(struct dhcp_netid *netid);  struct dhcp_boot *find_boot(struct dhcp_netid *netid);
 static int pxe_uefi_workaround(int pxe_arch, struct dhcp_netid *netid, struct dhcp_packet *mess, struct in_addr local, time_t now, int pxe);  static int pxe_uefi_workaround(int pxe_arch, struct dhcp_netid *netid, struct dhcp_packet *mess, struct in_addr local, time_t now, int pxe);
  static void apply_delay(u32 xid, time_t recvtime, struct dhcp_netid *netid);
 static int is_pxe_client(struct dhcp_packet *mess, size_t sz, const char **pxe_vendor);
 
 size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,  size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
                  size_t sz, time_t now, int unicast_dest, int *is_inform, int pxe, struct in_addr fallback)                  size_t sz, time_t now, int unicast_dest, int loopback,
                   int *is_inform, int pxe, struct in_addr fallback, time_t recvtime)
 {  {
   unsigned char *opt, *clid = NULL;    unsigned char *opt, *clid = NULL;
   struct dhcp_lease *ltmp, *lease = NULL;    struct dhcp_lease *ltmp, *lease = NULL;
   struct dhcp_vendor *vendor;    struct dhcp_vendor *vendor;
   struct dhcp_mac *mac;    struct dhcp_mac *mac;
   struct dhcp_netid_list *id_list;    struct dhcp_netid_list *id_list;
  int clid_len = 0, ignore = 0, do_classes = 0, selecting = 0, pxearch = -1;  int clid_len = 0, ignore = 0, do_classes = 0, rapid_commit = 0, selecting = 0, pxearch = -1;
   const char *pxevendor = NULL;
   struct dhcp_packet *mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;    struct dhcp_packet *mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
   unsigned char *end = (unsigned char *)(mess + 1);     unsigned char *end = (unsigned char *)(mess + 1); 
   unsigned char *real_end = (unsigned char *)(mess + 1);     unsigned char *real_end = (unsigned char *)(mess + 1); 
Line 155  size_t dhcp_reply(struct dhcp_context *context, char * Line 160  size_t dhcp_reply(struct dhcp_context *context, char *
           for (offset = 0; offset < (len - 5); offset += elen + 5)            for (offset = 0; offset < (len - 5); offset += elen + 5)
             {              {
               elen = option_uint(opt, offset + 4 , 1);                elen = option_uint(opt, offset + 4 , 1);
              if (option_uint(opt, offset, 4) == BRDBAND_FORUM_IANA)              if (option_uint(opt, offset, 4) == BRDBAND_FORUM_IANA && offset + elen + 5 <= len)
                 {                  {
                   unsigned char *x = option_ptr(opt, offset + 5);                    unsigned char *x = option_ptr(opt, offset + 5);
                   unsigned char *y = option_ptr(opt, offset + elen + 5);                    unsigned char *y = option_ptr(opt, offset + elen + 5);
Line 186  size_t dhcp_reply(struct dhcp_context *context, char * Line 191  size_t dhcp_reply(struct dhcp_context *context, char *
              be enough free space at the end of the packet to copy the option. */               be enough free space at the end of the packet to copy the option. */
           unsigned char *sopt;            unsigned char *sopt;
           unsigned int total = option_len(opt) + 2;            unsigned int total = option_len(opt) + 2;
          unsigned char *last_opt = option_find(mess, sz, OPTION_END, 0);          unsigned char *last_opt = option_find1(&mess->options[0] + sizeof(u32), ((unsigned char *)mess) + sz,
                                                  OPTION_END, 0);
           if (last_opt && last_opt < end - total)            if (last_opt && last_opt < end - total)
             {              {
               end -= total;                end -= total;
Line 231  size_t dhcp_reply(struct dhcp_context *context, char * Line 237  size_t dhcp_reply(struct dhcp_context *context, char *
         subnet_addr = option_addr(opt);          subnet_addr = option_addr(opt);
               
       /* If there is no client identifier option, use the hardware address */        /* If there is no client identifier option, use the hardware address */
      if ((opt = option_find(mess, sz, OPTION_CLIENT_ID, 1)))      if (!option_bool(OPT_IGNORE_CLID) && (opt = option_find(mess, sz, OPTION_CLIENT_ID, 1)))
         {          {
           clid_len = option_len(opt);            clid_len = option_len(opt);
           clid = option_ptr(opt, 0);            clid = option_ptr(opt, 0);
Line 271  size_t dhcp_reply(struct dhcp_context *context, char * Line 277  size_t dhcp_reply(struct dhcp_context *context, char *
   if (mess->giaddr.s_addr || subnet_addr.s_addr || mess->ciaddr.s_addr)    if (mess->giaddr.s_addr || subnet_addr.s_addr || mess->ciaddr.s_addr)
     {      {
       struct dhcp_context *context_tmp, *context_new = NULL;        struct dhcp_context *context_tmp, *context_new = NULL;
         struct shared_network *share = NULL;
       struct in_addr addr;        struct in_addr addr;
      int force = 0;      int force = 0, via_relay = 0;
               
       if (subnet_addr.s_addr)        if (subnet_addr.s_addr)
         {          {
Line 283  size_t dhcp_reply(struct dhcp_context *context, char * Line 290  size_t dhcp_reply(struct dhcp_context *context, char *
         {          {
           addr = mess->giaddr;            addr = mess->giaddr;
           force = 1;            force = 1;
             via_relay = 1;
         }          }
       else        else
         {          {
Line 299  size_t dhcp_reply(struct dhcp_context *context, char * Line 307  size_t dhcp_reply(struct dhcp_context *context, char *
         }           } 
                                   
       if (!context_new)        if (!context_new)
        for (context_tmp = daemon->dhcp; context_tmp; context_tmp = context_tmp->next)        {
          {          for (context_tmp = daemon->dhcp; context_tmp; context_tmp = context_tmp->next)
            struct in_addr netmask = context_tmp->netmask;            {
               struct in_addr netmask = context_tmp->netmask;
               
               /* guess the netmask for relayed networks */
               if (!(context_tmp->flags & CONTEXT_NETMASK) && context_tmp->netmask.s_addr == 0)
                 {
                   if (IN_CLASSA(ntohl(context_tmp->start.s_addr)) && IN_CLASSA(ntohl(context_tmp->end.s_addr)))
                     netmask.s_addr = htonl(0xff000000);
                   else if (IN_CLASSB(ntohl(context_tmp->start.s_addr)) && IN_CLASSB(ntohl(context_tmp->end.s_addr)))
                     netmask.s_addr = htonl(0xffff0000);
                   else if (IN_CLASSC(ntohl(context_tmp->start.s_addr)) && IN_CLASSC(ntohl(context_tmp->end.s_addr)))
                     netmask.s_addr = htonl(0xffffff00); 
                 }
   
            /* guess the netmask for relayed networks */              /* check to see is a context is OK because of a shared address on
            if (!(context_tmp->flags & CONTEXT_NETMASK) && context_tmp->netmask.s_addr == 0)                 the relayed subnet. */
              {              if (via_relay)
                if (IN_CLASSA(ntohl(context_tmp->start.s_addr)) && IN_CLASSA(ntohl(context_tmp->end.s_addr)))                for (share = daemon->shared_networks; share; share = share->next)
                  netmask.s_addr = htonl(0xff000000);                  {
                else if (IN_CLASSB(ntohl(context_tmp->start.s_addr)) && IN_CLASSB(ntohl(context_tmp->end.s_addr)))#ifdef HAVE_DHCP6
                  netmask.s_addr = htonl(0xffff0000);                    if (share->shared_addr.s_addr == 0)
                else if (IN_CLASSC(ntohl(context_tmp->start.s_addr)) && IN_CLASSC(ntohl(context_tmp->end.s_addr)))                      continue;
                  netmask.s_addr = htonl(0xffffff00)#endif
              }                    if (share->if_index != 0 ||
                                    share->match_addr.s_addr != mess->giaddr.s_addr)
            /* This section fills in context mainly when a client which is on a remote (relayed)                      continue;
               network renews a lease without using the relay, after dnsmasq has restarted. */                    
            if (netmask.s_addr != 0  &&                     if (netmask.s_addr != 0  && 
                is_same_net(addr, context_tmp->start, netmask) &&                        is_same_net(share->shared_addr, context_tmp->start, netmask) &&
                is_same_net(addr, context_tmp->end, netmask))                        is_same_net(share->shared_addr, context_tmp->end, netmask))
              {                      break;
                context_tmp->netmask = netmask;                  }
                if (context_tmp->local.s_addr == 0)              
                  context_tmp->local = fallback;              /* This section fills in context mainly when a client which is on a remote (relayed)
                if (context_tmp->router.s_addr == 0)                 network renews a lease without using the relay, after dnsmasq has restarted. */
                  context_tmp->router = mess->giaddr;              if (share ||
                             (netmask.s_addr != 0  && 
                /* fill in missing broadcast addresses for relayed ranges */                   is_same_net(addr, context_tmp->start, netmask) &&
                if (!(context_tmp->flags & CONTEXT_BRDCAST) && context_tmp->broadcast.s_addr == 0 )                   is_same_net(addr, context_tmp->end, netmask)))
                  context_tmp->broadcast.s_addr = context_tmp->start.s_addr | ~context_tmp->netmask.s_addr;                {
                                  context_tmp->netmask = netmask;
                context_tmp->current = context_new;                  if (context_tmp->local.s_addr == 0)
                context_new = context_tmp;                    context_tmp->local = fallback;
              }                  if (context_tmp->router.s_addr == 0 && !share)
          }                    context_tmp->router = mess->giaddr;
                        
                   /* fill in missing broadcast addresses for relayed ranges */
                   if (!(context_tmp->flags & CONTEXT_BRDCAST) && context_tmp->broadcast.s_addr == 0 )
                     context_tmp->broadcast.s_addr = context_tmp->start.s_addr | ~context_tmp->netmask.s_addr;
                   
                   context_tmp->current = context_new;
                   context_new = context_tmp;
                 }
               
             }
         }
           
       if (context_new || force)        if (context_new || force)
         context = context_new;           context = context_new; 
     }      }
Line 364  size_t dhcp_reply(struct dhcp_context *context, char * Line 395  size_t dhcp_reply(struct dhcp_context *context, char *
       
   /* dhcp-match. If we have hex-and-wildcards, look for a left-anchored match.    /* dhcp-match. If we have hex-and-wildcards, look for a left-anchored match.
      Otherwise assume the option is an array, and look for a matching element.        Otherwise assume the option is an array, and look for a matching element. 
     If no data given, existance of the option is enough. This code handles      If no data given, existence of the option is enough. This code handles 
      rfc3925 V-I classes too. */       rfc3925 V-I classes too. */
   for (o = daemon->dhcp_match; o; o = o->next)    for (o = daemon->dhcp_match; o; o = o->next)
     {      {
Line 380  size_t dhcp_reply(struct dhcp_context *context, char * Line 411  size_t dhcp_reply(struct dhcp_context *context, char *
             {              {
               len = option_uint(opt, offset + 4 , 1);                len = option_uint(opt, offset + 4 , 1);
               /* Need to take care that bad data can't run us off the end of the packet */                /* Need to take care that bad data can't run us off the end of the packet */
              if ((offset + len + 5 <= (option_len(opt))) &&              if ((offset + len + 5 <= (unsigned)(option_len(opt))) &&
                   (option_uint(opt, offset, 4) == (unsigned int)o->u.encap))                    (option_uint(opt, offset, 4) == (unsigned int)o->u.encap))
                 for (o2 = offset + 5; o2 < offset + len + 5; o2 += elen + 1)                  for (o2 = offset + 5; o2 < offset + len + 5; o2 += elen + 1)
                   {                     { 
                     elen = option_uint(opt, o2, 1);                      elen = option_uint(opt, o2, 1);
                    if ((o2 + elen + 1 <= option_len(opt)) &&                    if ((o2 + elen + 1 <= (unsigned)option_len(opt)) &&
                         (match = match_bytes(o, option_ptr(opt, o2 + 1), elen)))                          (match = match_bytes(o, option_ptr(opt, o2 + 1), elen)))
                       break;                        break;
                   }                    }
Line 476  size_t dhcp_reply(struct dhcp_context *context, char * Line 507  size_t dhcp_reply(struct dhcp_context *context, char *
   mess->op = BOOTREPLY;    mess->op = BOOTREPLY;
       
   config = find_config(daemon->dhcp_conf, context, clid, clid_len,     config = find_config(daemon->dhcp_conf, context, clid, clid_len, 
                       mess->chaddr, mess->hlen, mess->htype, NULL);                       mess->chaddr, mess->hlen, mess->htype, NULL, run_tag_if(netid));
   
   /* set "known" tag for known hosts */    /* set "known" tag for known hosts */
   if (config)    if (config)
Line 485  size_t dhcp_reply(struct dhcp_context *context, char * Line 516  size_t dhcp_reply(struct dhcp_context *context, char *
       known_id.next = netid;        known_id.next = netid;
       netid = &known_id;        netid = &known_id;
     }      }
     else if (find_config(daemon->dhcp_conf, NULL, clid, clid_len, 
                          mess->chaddr, mess->hlen, mess->htype, NULL, run_tag_if(netid)))
       {
         known_id.net = "known-othernet";
         known_id.next = netid;
         netid = &known_id;
       }
       
   if (mess_type == 0 && !pxe)    if (mess_type == 0 && !pxe)
     {      {
Line 566  size_t dhcp_reply(struct dhcp_context *context, char * Line 604  size_t dhcp_reply(struct dhcp_context *context, char *
                        lease_prune(lease, now);                         lease_prune(lease, now);
                        lease = NULL;                         lease = NULL;
                      }                       }
                   if (!address_allocate(context, &mess->yiaddr, mess->chaddr, mess->hlen, tagif_netid, now))                   if (!address_allocate(context, &mess->yiaddr, mess->chaddr, mess->hlen, tagif_netid, now, loopback))
                      message = _("no address available");                       message = _("no address available");
                 }                  }
               else                else
Line 612  size_t dhcp_reply(struct dhcp_context *context, char * Line 650  size_t dhcp_reply(struct dhcp_context *context, char *
                               
               clear_packet(mess, end);                clear_packet(mess, end);
               do_options(context, mess, end, NULL, hostname, get_domain(mess->yiaddr),                 do_options(context, mess, end, NULL, hostname, get_domain(mess->yiaddr), 
                         netid, subnet_addr, 0, 0, -1, NULL, vendor_class_len, now, 0xffffffff, 0);                         netid, subnet_addr, 0, 0, -1, NULL, vendor_class_len, now, 0xffffffff, 0, NULL);
             }              }
         }          }
               
         daemon->metrics[METRIC_BOOTP]++;
       log_packet("BOOTP", logaddr, mess->chaddr, mess->hlen, iface_name, NULL, message, mess->xid);        log_packet("BOOTP", logaddr, mess->chaddr, mess->hlen, iface_name, NULL, message, mess->xid);
               
       return message ? 0 : dhcp_packet_size(mess, agent_id, real_end);        return message ? 0 : dhcp_packet_size(mess, agent_id, real_end);
Line 689  size_t dhcp_reply(struct dhcp_context *context, char * Line 728  size_t dhcp_reply(struct dhcp_context *context, char *
         client_hostname = daemon->dhcp_buff;          client_hostname = daemon->dhcp_buff;
     }      }
   
  if (client_hostname && option_bool(OPT_LOG_OPTS))  if (client_hostname)
    my_syslog(MS_DHCP | LOG_INFO, _("%u client provides name: %s"), ntohl(mess->xid), client_hostname);    {
       struct dhcp_match_name *m;
       size_t nl = strlen(client_hostname);
       
       if (option_bool(OPT_LOG_OPTS))
         my_syslog(MS_DHCP | LOG_INFO, _("%u client provides name: %s"), ntohl(mess->xid), client_hostname);
       for (m = daemon->dhcp_name_match; m; m = m->next)
         {
           size_t ml = strlen(m->name);
           char save = 0;
           
           if (nl < ml)
             continue;
           if (nl > ml)
             {
               save = client_hostname[ml];
               client_hostname[ml] = 0;
             }
           
           if (hostname_isequal(client_hostname, m->name) &&
               (save == 0 || m->wildcard))
             {
               m->netid->next = netid;
               netid = m->netid;
             }
           
           if (save != 0)
             client_hostname[ml] = save;
         }
     }
       
   if (have_config(config, CONFIG_NAME))    if (have_config(config, CONFIG_NAME))
     {      {
Line 708  size_t dhcp_reply(struct dhcp_context *context, char * Line 776  size_t dhcp_reply(struct dhcp_context *context, char *
       if (strlen(client_hostname) != 0)        if (strlen(client_hostname) != 0)
         {          {
           hostname = client_hostname;            hostname = client_hostname;
             
           if (!config)            if (!config)
             {              {
               /* Search again now we have a hostname.                 /* Search again now we have a hostname. 
Line 715  size_t dhcp_reply(struct dhcp_context *context, char * Line 784  size_t dhcp_reply(struct dhcp_context *context, char *
                  to avoid impersonation by name. */                   to avoid impersonation by name. */
               struct dhcp_config *new = find_config(daemon->dhcp_conf, context, NULL, 0,                struct dhcp_config *new = find_config(daemon->dhcp_conf, context, NULL, 0,
                                                     mess->chaddr, mess->hlen,                                                       mess->chaddr, mess->hlen, 
                                                    mess->htype, hostname);                                                    mess->htype, hostname, run_tag_if(netid));
               if (new && !have_config(new, CONFIG_CLID) && !new->hwaddr)                if (new && !have_config(new, CONFIG_CLID) && !new->hwaddr)
                 {                  {
                   config = new;                    config = new;
Line 769  size_t dhcp_reply(struct dhcp_context *context, char * Line 838  size_t dhcp_reply(struct dhcp_context *context, char *
     clid = NULL;      clid = NULL;
                       
   /* Check if client is PXE client. */    /* Check if client is PXE client. */
  if (daemon->enable_pxe &&   if (daemon->enable_pxe &&
      (opt = option_find(mess, sz, OPTION_VENDOR_ID, 9)) &&       is_pxe_client(mess, sz, &pxevendor))
      strncmp(option_ptr(opt, 0), "PXEClient", 9) == 0) 
     {      {
       if ((opt = option_find(mess, sz, OPTION_PXE_UUID, 17)))        if ((opt = option_find(mess, sz, OPTION_PXE_UUID, 17)))
         {          {
Line 824  size_t dhcp_reply(struct dhcp_context *context, char * Line 892  size_t dhcp_reply(struct dhcp_context *context, char *
           else            else
             mess->siaddr = context->local;               mess->siaddr = context->local; 
                       
          snprintf((char *)mess->file, sizeof(mess->file),           if (strchr(service->basename, '.'))
                   strchr(service->basename, '.') ? "%s" :"%s.%d",             snprintf((char *)mess->file, sizeof(mess->file),
                   service->basename, layer);                "%s", service->basename);
           else
             snprintf((char *)mess->file, sizeof(mess->file),
                 "%s.%d", service->basename, layer);
                       
           option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);            option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
           option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(context->local.s_addr));            option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(context->local.s_addr));
          pxe_misc(mess, end, uuid);          pxe_misc(mess, end, uuid, pxevendor);
                       
           prune_vendor_opts(tagif_netid);            prune_vendor_opts(tagif_netid);
           opt71.val = save71;            opt71.val = save71;
Line 896  size_t dhcp_reply(struct dhcp_context *context, char * Line 967  size_t dhcp_reply(struct dhcp_context *context, char *
                                       
                   if (!workaround && boot)                    if (!workaround && boot)
                     {                      {
                      /* Provide the bootfile here, for gPXE, and in case we have no menu items                      /* Provide the bootfile here, for iPXE, and in case we have no menu items
                          and set discovery_control = 8 */                           and set discovery_control = 8 */
                       if (boot->next_server.s_addr)                         if (boot->next_server.s_addr) 
                         mess->siaddr = boot->next_server;                          mess->siaddr = boot->next_server;
Line 904  size_t dhcp_reply(struct dhcp_context *context, char * Line 975  size_t dhcp_reply(struct dhcp_context *context, char *
                         mess->siaddr = a_record_from_hosts(boot->tftp_sname, now);                          mess->siaddr = a_record_from_hosts(boot->tftp_sname, now);
                                               
                       if (boot->file)                        if (boot->file)
                        strncpy((char *)mess->file, boot->file, sizeof(mess->file)-1);                        safe_strncpy((char *)mess->file, boot->file, sizeof(mess->file));
                     }                      }
                                       
                   option_put(mess, end, OPTION_MESSAGE_TYPE, 1,                     option_put(mess, end, OPTION_MESSAGE_TYPE, 1, 
                              mess_type == DHCPDISCOVER ? DHCPOFFER : DHCPACK);                               mess_type == DHCPDISCOVER ? DHCPOFFER : DHCPACK);
                   option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(tmp->local.s_addr));                    option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(tmp->local.s_addr));
                  pxe_misc(mess, end, uuid);                  pxe_misc(mess, end, uuid, pxevendor);
                   prune_vendor_opts(tagif_netid);                    prune_vendor_opts(tagif_netid);
                   if ((pxe && !workaround) || !redirect4011)                    if ((pxe && !workaround) || !redirect4011)
                     do_encap_opts(pxe_opts(pxearch, tagif_netid, tmp->local, now), OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);                      do_encap_opts(pxe_opts(pxearch, tagif_netid, tmp->local, now), OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
                           
                     daemon->metrics[METRIC_PXE]++;
                   log_packet("PXE", NULL, emac, emac_len, iface_name, ignore ? "proxy-ignored" : "proxy", NULL, mess->xid);                    log_packet("PXE", NULL, emac, emac_len, iface_name, ignore ? "proxy-ignored" : "proxy", NULL, mess->xid);
                   log_tags(tagif_netid, ntohl(mess->xid));                    log_tags(tagif_netid, ntohl(mess->xid));
                     if (!ignore)
                       apply_delay(mess->xid, recvtime, tagif_netid);
                   return ignore ? 0 : dhcp_packet_size(mess, agent_id, real_end);                             return ignore ? 0 : dhcp_packet_size(mess, agent_id, real_end);         
                 }                  }
             }              }
Line 947  size_t dhcp_reply(struct dhcp_context *context, char * Line 1021  size_t dhcp_reply(struct dhcp_context *context, char *
       if (!(opt = option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ)))        if (!(opt = option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ)))
         return 0;          return 0;
               
         daemon->metrics[METRIC_DHCPDECLINE]++;
       log_packet("DHCPDECLINE", option_ptr(opt, 0), emac, emac_len, iface_name, NULL, daemon->dhcp_buff, mess->xid);        log_packet("DHCPDECLINE", option_ptr(opt, 0), emac, emac_len, iface_name, NULL, daemon->dhcp_buff, mess->xid);
               
       if (lease && lease->addr.s_addr == option_addr(opt).s_addr)        if (lease && lease->addr.s_addr == option_addr(opt).s_addr)
Line 979  size_t dhcp_reply(struct dhcp_context *context, char * Line 1054  size_t dhcp_reply(struct dhcp_context *context, char *
       else        else
         message = _("unknown lease");          message = _("unknown lease");
   
         daemon->metrics[METRIC_DHCPRELEASE]++;
       log_packet("DHCPRELEASE", &mess->ciaddr, emac, emac_len, iface_name, NULL, message, mess->xid);        log_packet("DHCPRELEASE", &mess->ciaddr, emac, emac_len, iface_name, NULL, message, mess->xid);
                   
       return 0;        return 0;
Line 1037  size_t dhcp_reply(struct dhcp_context *context, char * Line 1113  size_t dhcp_reply(struct dhcp_context *context, char *
                    !config_find_by_address(daemon->dhcp_conf, lease->addr))                     !config_find_by_address(daemon->dhcp_conf, lease->addr))
             mess->yiaddr = lease->addr;              mess->yiaddr = lease->addr;
           else if (opt && address_available(context, addr, tagif_netid) && !lease_find_by_addr(addr) &&             else if (opt && address_available(context, addr, tagif_netid) && !lease_find_by_addr(addr) && 
                   !config_find_by_address(daemon->dhcp_conf, addr))                   !config_find_by_address(daemon->dhcp_conf, addr) && do_icmp_ping(now, addr, 0, loopback))
             mess->yiaddr = addr;              mess->yiaddr = addr;
           else if (emac_len == 0)            else if (emac_len == 0)
             message = _("no unique-id");              message = _("no unique-id");
          else if (!address_allocate(context, &mess->yiaddr, emac, emac_len, tagif_netid, now))          else if (!address_allocate(context, &mess->yiaddr, emac, emac_len, tagif_netid, now, loopback))
             message = _("no address available");                    message = _("no address available");      
         }          }
               
         daemon->metrics[METRIC_DHCPDISCOVER]++;
       log_packet("DHCPDISCOVER", opt ? option_ptr(opt, 0) : NULL, emac, emac_len, iface_name, NULL, message, mess->xid);         log_packet("DHCPDISCOVER", opt ? option_ptr(opt, 0) : NULL, emac, emac_len, iface_name, NULL, message, mess->xid); 
   
       if (message || !(context = narrow_context(context, mess->yiaddr, tagif_netid)))        if (message || !(context = narrow_context(context, mess->yiaddr, tagif_netid)))
Line 1057  size_t dhcp_reply(struct dhcp_context *context, char * Line 1134  size_t dhcp_reply(struct dhcp_context *context, char *
         }          }
   
       log_tags(tagif_netid, ntohl(mess->xid));        log_tags(tagif_netid, ntohl(mess->xid));
         apply_delay(mess->xid, recvtime, tagif_netid);
   
         if (option_bool(OPT_RAPID_COMMIT) && option_find(mess, sz, OPTION_RAPID_COMMIT, 0))
           {
             rapid_commit = 1;
             goto rapid_commit;
           }
               
         daemon->metrics[METRIC_DHCPOFFER]++;
       log_packet("DHCPOFFER" , &mess->yiaddr, emac, emac_len, iface_name, NULL, NULL, mess->xid);        log_packet("DHCPOFFER" , &mess->yiaddr, emac, emac_len, iface_name, NULL, NULL, mess->xid);
               
       time = calc_time(context, config, option_find(mess, sz, OPTION_LEASE_TIME, 4));        time = calc_time(context, config, option_find(mess, sz, OPTION_LEASE_TIME, 4));
Line 1067  size_t dhcp_reply(struct dhcp_context *context, char * Line 1152  size_t dhcp_reply(struct dhcp_context *context, char *
       option_put(mess, end, OPTION_LEASE_TIME, 4, time);        option_put(mess, end, OPTION_LEASE_TIME, 4, time);
       /* T1 and T2 are required in DHCPOFFER by HP's wacky Jetdirect client. */        /* T1 and T2 are required in DHCPOFFER by HP's wacky Jetdirect client. */
       do_options(context, mess, end, req_options, offer_hostname, get_domain(mess->yiaddr),         do_options(context, mess, end, req_options, offer_hostname, get_domain(mess->yiaddr), 
                 netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, time, fuzz);                 netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, time, fuzz, pxevendor);
               
       return dhcp_packet_size(mess, agent_id, real_end);        return dhcp_packet_size(mess, agent_id, real_end);
              
 
     case DHCPREQUEST:      case DHCPREQUEST:
       if (ignore || have_config(config, CONFIG_DISABLE))        if (ignore || have_config(config, CONFIG_DISABLE))
         return 0;          return 0;
Line 1168  size_t dhcp_reply(struct dhcp_context *context, char * Line 1254  size_t dhcp_reply(struct dhcp_context *context, char *
           fuzz = rand16();            fuzz = rand16();
           mess->yiaddr = mess->ciaddr;            mess->yiaddr = mess->ciaddr;
         }          }
      
       daemon->metrics[METRIC_DHCPREQUEST]++;
       log_packet("DHCPREQUEST", &mess->yiaddr, emac, emac_len, iface_name, NULL, NULL, mess->xid);        log_packet("DHCPREQUEST", &mess->yiaddr, emac, emac_len, iface_name, NULL, NULL, mess->xid);
       
     rapid_commit:
       if (!message)        if (!message)
         {          {
           struct dhcp_config *addr_config;            struct dhcp_config *addr_config;
Line 1241  size_t dhcp_reply(struct dhcp_context *context, char * Line 1329  size_t dhcp_reply(struct dhcp_context *context, char *
   
       if (message)        if (message)
         {          {
          log_packet("DHCPNAK", &mess->yiaddr, emac, emac_len, iface_name, NULL, message, mess->xid);          daemon->metrics[rapid_commit ? METRIC_NOANSWER : METRIC_DHCPNAK]++;
           log_packet(rapid_commit ? "NOANSWER" : "DHCPNAK", &mess->yiaddr, emac, emac_len, iface_name, NULL, message, mess->xid);
 
           /* rapid commit case: lease allocate failed but don't send DHCPNAK */
           if (rapid_commit)
             return 0;
                       
           mess->yiaddr.s_addr = 0;            mess->yiaddr.s_addr = 0;
           clear_packet(mess, end);            clear_packet(mess, end);
Line 1303  size_t dhcp_reply(struct dhcp_context *context, char * Line 1396  size_t dhcp_reply(struct dhcp_context *context, char *
                       add_extradata_opt(lease, NULL);                        add_extradata_opt(lease, NULL);
                     }                      }
   
                     /* DNSMASQ_REQUESTED_OPTIONS */
                     if ((opt = option_find(mess, sz, OPTION_REQUESTED_OPTIONS, 1)))
                       {
                         int len = option_len(opt);
                         unsigned char *rop = option_ptr(opt, 0);
                         char *q = daemon->namebuff;
                         int i;
                         for (i = 0; i < len; i++)
                           {
                             q += snprintf(q, MAXDNAME - (q - daemon->namebuff), "%d%s", rop[i], i + 1 == len ? "" : ",");
                           }
                         lease_add_extradata(lease, (unsigned char *)daemon->namebuff, (q - daemon->namebuff), 0); 
                       }
                     else
                       {
                         add_extradata_opt(lease, NULL);
                       }
   
                   /* space-concat tag set */                    /* space-concat tag set */
                   if (!tagif_netid)                    if (!tagif_netid)
                     add_extradata_opt(lease, NULL);                      add_extradata_opt(lease, NULL);
Line 1380  size_t dhcp_reply(struct dhcp_context *context, char * Line 1491  size_t dhcp_reply(struct dhcp_context *context, char *
           else            else
             override = lease->override;              override = lease->override;
   
             daemon->metrics[METRIC_DHCPACK]++;
           log_packet("DHCPACK", &mess->yiaddr, emac, emac_len, iface_name, hostname, NULL, mess->xid);              log_packet("DHCPACK", &mess->yiaddr, emac, emac_len, iface_name, hostname, NULL, mess->xid);  
          
           clear_packet(mess, end);            clear_packet(mess, end);
           option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);            option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
           option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));            option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));
           option_put(mess, end, OPTION_LEASE_TIME, 4, time);            option_put(mess, end, OPTION_LEASE_TIME, 4, time);
          do_options(context, mess, end, req_options, hostname, get_domain(mess->yiaddr),           if (rapid_commit)
                     netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, time, fuzz);             option_put(mess, end, OPTION_RAPID_COMMIT, 0, 0);
            do_options(context, mess, end, req_options, hostname, get_domain(mess->yiaddr), 
                      netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, time, fuzz, pxevendor);
         }          }
   
       return dhcp_packet_size(mess, agent_id, real_end);         return dhcp_packet_size(mess, agent_id, real_end); 
Line 1396  size_t dhcp_reply(struct dhcp_context *context, char * Line 1510  size_t dhcp_reply(struct dhcp_context *context, char *
       if (ignore || have_config(config, CONFIG_DISABLE))        if (ignore || have_config(config, CONFIG_DISABLE))
         message = _("ignored");          message = _("ignored");
               
         daemon->metrics[METRIC_DHCPINFORM]++;
       log_packet("DHCPINFORM", &mess->ciaddr, emac, emac_len, iface_name, message, NULL, mess->xid);        log_packet("DHCPINFORM", &mess->ciaddr, emac, emac_len, iface_name, message, NULL, mess->xid);
             
       if (message || mess->ciaddr.s_addr == 0)        if (message || mess->ciaddr.s_addr == 0)
Line 1422  size_t dhcp_reply(struct dhcp_context *context, char * Line 1537  size_t dhcp_reply(struct dhcp_context *context, char *
   
       log_tags(tagif_netid, ntohl(mess->xid));        log_tags(tagif_netid, ntohl(mess->xid));
               
         daemon->metrics[METRIC_DHCPACK]++;
       log_packet("DHCPACK", &mess->ciaddr, emac, emac_len, iface_name, hostname, NULL, mess->xid);        log_packet("DHCPACK", &mess->ciaddr, emac, emac_len, iface_name, hostname, NULL, mess->xid);
               
       if (lease)        if (lease)
Line 1452  size_t dhcp_reply(struct dhcp_context *context, char * Line 1568  size_t dhcp_reply(struct dhcp_context *context, char *
         }          }
   
       do_options(context, mess, end, req_options, hostname, get_domain(mess->ciaddr),        do_options(context, mess, end, req_options, hostname, get_domain(mess->ciaddr),
                 netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, 0xffffffff, 0);                 netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, 0xffffffff, 0, pxevendor);
               
       *is_inform = 1; /* handle reply differently */        *is_inform = 1; /* handle reply differently */
       return dhcp_packet_size(mess, agent_id, real_end);         return dhcp_packet_size(mess, agent_id, real_end); 
Line 1588  static void log_packet(char *type, void *addr, unsigne Line 1704  static void log_packet(char *type, void *addr, unsigne
               daemon->namebuff,                daemon->namebuff,
               string ? string : "",                string ? string : "",
               err ? err : "");                err ? err : "");
   
   #ifdef HAVE_UBUS
           if (!strcmp(type, "DHCPACK"))
                   ubus_event_bcast("dhcp.ack", daemon->namebuff, addr ? inet_ntoa(a) : NULL, string ? string : NULL, interface);
           else if (!strcmp(type, "DHCPRELEASE"))
                   ubus_event_bcast("dhcp.release", daemon->namebuff, addr ? inet_ntoa(a) : NULL, string ? string : NULL, interface);
   #endif
 }  }
   
 static void log_options(unsigned char *start, u32 xid)  static void log_options(unsigned char *start, u32 xid)
Line 1606  static unsigned char *option_find1(unsigned char *p, u Line 1729  static unsigned char *option_find1(unsigned char *p, u
 {  {
   while (1)     while (1) 
     {      {
      if (p > end)      if (p >= end)
         return NULL;          return NULL;
       else if (*p == OPTION_END)        else if (*p == OPTION_END)
         return opt == OPTION_END ? p : NULL;          return opt == OPTION_END ? p : NULL;
Line 1827  static void option_put(struct dhcp_packet *mess, unsig Line 1950  static void option_put(struct dhcp_packet *mess, unsig
 }  }
   
 static void option_put_string(struct dhcp_packet *mess, unsigned char *end, int opt,   static void option_put_string(struct dhcp_packet *mess, unsigned char *end, int opt, 
                              char *string, int null_term)                              const char *string, int null_term)
 {  {
   unsigned char *p;    unsigned char *p;
   size_t len = strlen(string);    size_t len = strlen(string);
Line 1905  static void match_vendor_opts(unsigned char *opt, stru Line 2028  static void match_vendor_opts(unsigned char *opt, stru
       dopt->flags &= ~DHOPT_VENDOR_MATCH;        dopt->flags &= ~DHOPT_VENDOR_MATCH;
       if (opt && (dopt->flags & DHOPT_VENDOR))        if (opt && (dopt->flags & DHOPT_VENDOR))
         {          {
          int i, len = 0;          const struct dhcp_pxe_vendor *pv;
          if (dopt->u.vendor_class)          struct dhcp_pxe_vendor dummy_vendor = {
            len = strlen((char *)dopt->u.vendor_class);            .data = (char *)dopt->u.vendor_class,
          for (i = 0; i <= (option_len(opt) - len); i++)            .next = NULL,
            if (len == 0 || memcmp(dopt->u.vendor_class, option_ptr(opt, i), len) == 0)          };
              {          if (dopt->flags & DHOPT_VENDOR_PXE)
                dopt->flags |= DHOPT_VENDOR_MATCH;            pv = daemon->dhcp_pxe_vendors;
                break;          else
              }            pv = &dummy_vendor;
           for (; pv; pv = pv->next)
             {
               int i, len = 0, matched = 0;
               if (pv->data)
                 len = strlen(pv->data);
               for (i = 0; i <= (option_len(opt) - len); i++)
                 if (len == 0 || memcmp(pv->data, option_ptr(opt, i), len) == 0)
                   {
                     matched = 1;
                     break;
                   }
               if (matched)
                 {
                   dopt->flags |= DHOPT_VENDOR_MATCH;
                   break;
                 }
             }
         }          }
     }      }
 }  }
Line 1966  static int do_encap_opts(struct dhcp_opt *opt, int enc Line 2106  static int do_encap_opts(struct dhcp_opt *opt, int enc
   return ret;    return ret;
 }  }
   
static void pxe_misc(struct dhcp_packet *mess, unsigned char *end, unsigned char *uuid)static void pxe_misc(struct dhcp_packet *mess, unsigned char *end, unsigned char *uuid, const char *pxevendor)
 {  {
   unsigned char *p;    unsigned char *p;
   
  option_put_string(mess, end, OPTION_VENDOR_ID, "PXEClient", 0);  if (!pxevendor)
     pxevendor="PXEClient";
   option_put_string(mess, end, OPTION_VENDOR_ID, pxevendor, 0);
   if (uuid && (p = free_space(mess, end, OPTION_PXE_UUID, 17)))    if (uuid && (p = free_space(mess, end, OPTION_PXE_UUID, 17)))
     memcpy(p, uuid, 17);      memcpy(p, uuid, 17);
 }  }
Line 2187  struct dhcp_boot *find_boot(struct dhcp_netid *netid) Line 2329  struct dhcp_boot *find_boot(struct dhcp_netid *netid)
   return boot;    return boot;
 }  }
   
   static int is_pxe_client(struct dhcp_packet *mess, size_t sz, const char **pxe_vendor)
   {
     const unsigned char *opt = NULL;
     ssize_t conf_len = 0;
     const struct dhcp_pxe_vendor *conf = daemon->dhcp_pxe_vendors;
     opt = option_find(mess, sz, OPTION_VENDOR_ID, 0);
     if (!opt) 
       return 0;
     for (; conf; conf = conf->next)
       {
         conf_len = strlen(conf->data);
         if (option_len(opt) < conf_len)
           continue;
         if (strncmp(option_ptr(opt, 0), conf->data, conf_len) == 0)
           {
             if (pxe_vendor)
               *pxe_vendor = conf->data;
             return 1;
           }
       }
     return 0;
   }
   
 static void do_options(struct dhcp_context *context,  static void do_options(struct dhcp_context *context,
                        struct dhcp_packet *mess,                         struct dhcp_packet *mess,
                        unsigned char *end,                          unsigned char *end, 
Line 2201  static void do_options(struct dhcp_context *context, Line 2366  static void do_options(struct dhcp_context *context,
                        int vendor_class_len,                         int vendor_class_len,
                        time_t now,                         time_t now,
                        unsigned int lease_time,                         unsigned int lease_time,
                       unsigned short fuzz)                       unsigned short fuzz,
                        const char *pxevendor)
 {  {
   struct dhcp_opt *opt, *config_opts = daemon->dhcp_opts;    struct dhcp_opt *opt, *config_opts = daemon->dhcp_opts;
   struct dhcp_boot *boot;    struct dhcp_boot *boot;
Line 2251  static void do_options(struct dhcp_context *context, Line 2417  static void do_options(struct dhcp_context *context,
   /* See if we can send the boot stuff as options.    /* See if we can send the boot stuff as options.
      To do this we need a requested option list, BOOTP       To do this we need a requested option list, BOOTP
      and very old DHCP clients won't have this, we also        and very old DHCP clients won't have this, we also 
     provide an manual option to disable it.     provide a manual option to disable it.
      Some PXE ROMs have bugs (surprise!) and need zero-terminated        Some PXE ROMs have bugs (surprise!) and need zero-terminated 
      names, so we always send those.  */       names, so we always send those.  */
   if ((boot = find_boot(tagif)))    if ((boot = find_boot(tagif)))
Line 2263  static void do_options(struct dhcp_context *context, Line 2429  static void do_options(struct dhcp_context *context,
               in_list(req_options, OPTION_SNAME))                in_list(req_options, OPTION_SNAME))
             option_put_string(mess, end, OPTION_SNAME, boot->sname, 1);              option_put_string(mess, end, OPTION_SNAME, boot->sname, 1);
           else            else
            strncpy((char *)mess->sname, boot->sname, sizeof(mess->sname)-1);            safe_strncpy((char *)mess->sname, boot->sname, sizeof(mess->sname));
         }          }
               
       if (boot->file)        if (boot->file)
Line 2273  static void do_options(struct dhcp_context *context, Line 2439  static void do_options(struct dhcp_context *context,
               in_list(req_options, OPTION_FILENAME))                in_list(req_options, OPTION_FILENAME))
             option_put_string(mess, end, OPTION_FILENAME, boot->file, 1);              option_put_string(mess, end, OPTION_FILENAME, boot->file, 1);
           else            else
            strncpy((char *)mess->file, boot->file, sizeof(mess->file)-1);            safe_strncpy((char *)mess->file, boot->file, sizeof(mess->file));
         }          }
               
       if (boot->next_server.s_addr)         if (boot->next_server.s_addr) 
Line 2290  static void do_options(struct dhcp_context *context, Line 2456  static void do_options(struct dhcp_context *context,
       if ((!req_options || !in_list(req_options, OPTION_FILENAME)) &&        if ((!req_options || !in_list(req_options, OPTION_FILENAME)) &&
           (opt = option_find2(OPTION_FILENAME)) && !(opt->flags & DHOPT_FORCE))            (opt = option_find2(OPTION_FILENAME)) && !(opt->flags & DHOPT_FORCE))
         {          {
          strncpy((char *)mess->file, (char *)opt->val, sizeof(mess->file)-1);          safe_strncpy((char *)mess->file, (char *)opt->val, sizeof(mess->file));
           done_file = 1;            done_file = 1;
         }          }
               
       if ((!req_options || !in_list(req_options, OPTION_SNAME)) &&        if ((!req_options || !in_list(req_options, OPTION_SNAME)) &&
           (opt = option_find2(OPTION_SNAME)) && !(opt->flags & DHOPT_FORCE))            (opt = option_find2(OPTION_SNAME)) && !(opt->flags & DHOPT_FORCE))
         {          {
          strncpy((char *)mess->sname, (char *)opt->val, sizeof(mess->sname)-1);          safe_strncpy((char *)mess->sname, (char *)opt->val, sizeof(mess->sname));
           done_server = 1;            done_server = 1;
         }          }
               
Line 2419  static void do_options(struct dhcp_context *context, Line 2585  static void do_options(struct dhcp_context *context,
   
               if (fqdn_flags & 0x04)                if (fqdn_flags & 0x04)
                 {                  {
                  p = do_rfc1035_name(p, hostname);                  p = do_rfc1035_name(p, hostname, NULL);
                   if (domain)                    if (domain)
                     {                      {
                      p = do_rfc1035_name(p, domain);                      p = do_rfc1035_name(p, domain, NULL);
                       *p++ = 0;                        *p++ = 0;
                     }                      }
                 }                  }
Line 2575  static void do_options(struct dhcp_context *context, Line 2741  static void do_options(struct dhcp_context *context,
       
   if (context && pxe_arch != -1)    if (context && pxe_arch != -1)
     {      {
      pxe_misc(mess, end, uuid);      pxe_misc(mess, end, uuid, pxevendor);
       if (!pxe_uefi_workaround(pxe_arch, tagif, mess, context->local, now, 0))        if (!pxe_uefi_workaround(pxe_arch, tagif, mess, context->local, now, 0))
         config_opts = pxe_opts(pxe_arch, tagif, context->local, now);          config_opts = pxe_opts(pxe_arch, tagif, context->local, now);
     }      }
Line 2593  static void do_options(struct dhcp_context *context, Line 2759  static void do_options(struct dhcp_context *context,
     {      {
       mess->file[0] = f0;        mess->file[0] = f0;
       mess->sname[0] = s0;        mess->sname[0] = s0;
       }
   }
   
   static void apply_delay(u32 xid, time_t recvtime, struct dhcp_netid *netid)
   {
     struct delay_config *delay_conf;
     
     /* Decide which delay_config option we're using */
     for (delay_conf = daemon->delay_conf; delay_conf; delay_conf = delay_conf->next)
       if (match_netid(delay_conf->netid, netid, 0))
         break;
     
     if (!delay_conf)
       /* No match, look for one without a netid */
       for (delay_conf = daemon->delay_conf; delay_conf; delay_conf = delay_conf->next)
         if (match_netid(delay_conf->netid, netid, 1))
           break;
   
     if (delay_conf)
       {
         if (!option_bool(OPT_QUIET_DHCP))
           my_syslog(MS_DHCP | LOG_INFO, _("%u reply delay: %d"), ntohl(xid), delay_conf->delay);
         delay_dhcp(recvtime, delay_conf->delay, -1, 0, 0);
     }      }
 }  }
   

Removed from v.1.1.1.3  
changed lines
  Added in v.1.1.1.4


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>