Diff for /qemu/slirp/bootp.c between versions 1.1.1.4 and 1.1.1.5

version 1.1.1.4, 2018/04/24 16:54:46 version 1.1.1.5, 2018/04/24 17:25:53
Line 25 Line 25
   
 /* XXX: only DHCP is supported */  /* XXX: only DHCP is supported */
   
 #define NB_ADDR 16  
   
 #define START_ADDR 15  
   
 #define LEASE_TIME (24 * 3600)  #define LEASE_TIME (24 * 3600)
   
 typedef struct {  
     uint8_t allocated;  
     uint8_t macaddr[6];  
 } BOOTPClient;  
   
 static BOOTPClient bootp_clients[NB_ADDR];  
   
 const char *bootp_filename;  
   
 static const uint8_t rfc1533_cookie[] = { RFC1533_COOKIE };  static const uint8_t rfc1533_cookie[] = { RFC1533_COOKIE };
   
 #ifdef DEBUG  #ifdef DEBUG
 #define dprintf(fmt, args...) \  #define dprintf(fmt, ...) \
 if (slirp_debug & DBG_CALL) { fprintf(dfd, fmt, ## args); fflush(dfd); }  do if (slirp_debug & DBG_CALL) { fprintf(dfd, fmt, ##  __VA_ARGS__); fflush(dfd); } while (0)
 #else  #else
 #define dprintf(fmt, args...)  #define dprintf(fmt, ...)
 #endif  #endif
   
 static BOOTPClient *get_new_addr(struct in_addr *paddr)  static BOOTPClient *get_new_addr(Slirp *slirp, struct in_addr *paddr,
                                    const uint8_t *macaddr)
 {  {
     BOOTPClient *bc;      BOOTPClient *bc;
     int i;      int i;
   
     for(i = 0; i < NB_ADDR; i++) {      for(i = 0; i < NB_BOOTP_CLIENTS; i++) {
         if (!bootp_clients[i].allocated)          bc = &slirp->bootp_clients[i];
           if (!bc->allocated || !memcmp(macaddr, bc->macaddr, 6))
             goto found;              goto found;
     }      }
     return NULL;      return NULL;
  found:   found:
     bc = &bootp_clients[i];      bc = &slirp->bootp_clients[i];
     bc->allocated = 1;      bc->allocated = 1;
     paddr->s_addr = htonl(ntohl(special_addr.s_addr) | (i + START_ADDR));      paddr->s_addr = slirp->vdhcp_startaddr.s_addr + htonl(i);
     return bc;      return bc;
 }  }
   
 static BOOTPClient *find_addr(struct in_addr *paddr, const uint8_t *macaddr)  static BOOTPClient *request_addr(Slirp *slirp, const struct in_addr *paddr,
                                    const uint8_t *macaddr)
   {
       uint32_t req_addr = ntohl(paddr->s_addr);
       uint32_t dhcp_addr = ntohl(slirp->vdhcp_startaddr.s_addr);
       BOOTPClient *bc;
   
       if (req_addr >= dhcp_addr &&
           req_addr < (dhcp_addr + NB_BOOTP_CLIENTS)) {
           bc = &slirp->bootp_clients[req_addr - dhcp_addr];
           if (!bc->allocated || !memcmp(macaddr, bc->macaddr, 6)) {
               bc->allocated = 1;
               return bc;
           }
       }
       return NULL;
   }
   
   static BOOTPClient *find_addr(Slirp *slirp, struct in_addr *paddr,
                                 const uint8_t *macaddr)
 {  {
     BOOTPClient *bc;      BOOTPClient *bc;
     int i;      int i;
   
     for(i = 0; i < NB_ADDR; i++) {      for(i = 0; i < NB_BOOTP_CLIENTS; i++) {
         if (!memcmp(macaddr, bootp_clients[i].macaddr, 6))          if (!memcmp(macaddr, slirp->bootp_clients[i].macaddr, 6))
             goto found;              goto found;
     }      }
     return NULL;      return NULL;
  found:   found:
     bc = &bootp_clients[i];      bc = &slirp->bootp_clients[i];
     bc->allocated = 1;      bc->allocated = 1;
     paddr->s_addr = htonl(ntohl(special_addr.s_addr) | (i + START_ADDR));      paddr->s_addr = slirp->vdhcp_startaddr.s_addr + htonl(i);
     return bc;      return bc;
 }  }
   
 static void dhcp_decode(const uint8_t *buf, int size,  static void dhcp_decode(const struct bootp_t *bp, int *pmsg_type,
                         int *pmsg_type)                          const struct in_addr **preq_addr)
 {  {
     const uint8_t *p, *p_end;      const uint8_t *p, *p_end;
     int len, tag;      int len, tag;
   
     *pmsg_type = 0;      *pmsg_type = 0;
       *preq_addr = NULL;
   
     p = buf;      p = bp->bp_vend;
     p_end = buf + size;      p_end = p + DHCP_OPT_LEN;
     if (size < 5)  
         return;  
     if (memcmp(p, rfc1533_cookie, 4) != 0)      if (memcmp(p, rfc1533_cookie, 4) != 0)
         return;          return;
     p += 4;      p += 4;
Line 109  static void dhcp_decode(const uint8_t *b Line 116  static void dhcp_decode(const uint8_t *b
             if (p >= p_end)              if (p >= p_end)
                 break;                  break;
             len = *p++;              len = *p++;
             dprintf("dhcp: tag=0x%02x len=%d\n", tag, len);              dprintf("dhcp: tag=%d len=%d\n", tag, len);
   
             switch(tag) {              switch(tag) {
             case RFC2132_MSG_TYPE:              case RFC2132_MSG_TYPE:
                 if (len >= 1)                  if (len >= 1)
                     *pmsg_type = p[0];                      *pmsg_type = p[0];
                 break;                  break;
               case RFC2132_REQ_ADDR:
                   if (len >= 4)
                       *preq_addr = (struct in_addr *)p;
                   break;
             default:              default:
                 break;                  break;
             }              }
             p += len;              p += len;
         }          }
     }      }
       if (*pmsg_type == DHCPREQUEST && !*preq_addr && bp->bp_ciaddr.s_addr) {
           *preq_addr = &bp->bp_ciaddr;
       }
 }  }
   
 static void bootp_reply(struct bootp_t *bp)  static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
 {  {
     BOOTPClient *bc;      BOOTPClient *bc = NULL;
     struct mbuf *m;      struct mbuf *m;
     struct bootp_t *rbp;      struct bootp_t *rbp;
     struct sockaddr_in saddr, daddr;      struct sockaddr_in saddr, daddr;
     struct in_addr dns_addr;      const struct in_addr *preq_addr;
     int dhcp_msg_type, val;      int dhcp_msg_type, val;
     uint8_t *q;      uint8_t *q;
   
     /* extract exact DHCP msg type */      /* extract exact DHCP msg type */
     dhcp_decode(bp->bp_vend, DHCP_OPT_LEN, &dhcp_msg_type);      dhcp_decode(bp, &dhcp_msg_type, &preq_addr);
     dprintf("bootp packet op=%d msgtype=%d\n", bp->bp_op, dhcp_msg_type);      dprintf("bootp packet op=%d msgtype=%d", bp->bp_op, dhcp_msg_type);
       if (preq_addr)
           dprintf(" req_addr=%08x\n", ntohl(preq_addr->s_addr));
       else
           dprintf("\n");
   
     if (dhcp_msg_type == 0)      if (dhcp_msg_type == 0)
         dhcp_msg_type = DHCPREQUEST; /* Force reply for old BOOTP clients */          dhcp_msg_type = DHCPREQUEST; /* Force reply for old BOOTP clients */
Line 145  static void bootp_reply(struct bootp_t * Line 163  static void bootp_reply(struct bootp_t *
         dhcp_msg_type != DHCPREQUEST)          dhcp_msg_type != DHCPREQUEST)
         return;          return;
     /* XXX: this is a hack to get the client mac address */      /* XXX: this is a hack to get the client mac address */
     memcpy(client_ethaddr, bp->bp_hwaddr, 6);      memcpy(slirp->client_ethaddr, bp->bp_hwaddr, 6);
   
     if ((m = m_get()) == NULL)      m = m_get(slirp);
       if (!m) {
         return;          return;
       }
     m->m_data += IF_MAXLINKHDR;      m->m_data += IF_MAXLINKHDR;
     rbp = (struct bootp_t *)m->m_data;      rbp = (struct bootp_t *)m->m_data;
     m->m_data += sizeof(struct udpiphdr);      m->m_data += sizeof(struct udpiphdr);
     memset(rbp, 0, sizeof(struct bootp_t));      memset(rbp, 0, sizeof(struct bootp_t));
   
     if (dhcp_msg_type == DHCPDISCOVER) {      if (dhcp_msg_type == DHCPDISCOVER) {
     new_addr:          if (preq_addr) {
         bc = get_new_addr(&daddr.sin_addr);              bc = request_addr(slirp, preq_addr, slirp->client_ethaddr);
               if (bc) {
                   daddr.sin_addr = *preq_addr;
               }
           }
         if (!bc) {          if (!bc) {
             dprintf("no address left\n");           new_addr:
             return;              bc = get_new_addr(slirp, &daddr.sin_addr, slirp->client_ethaddr);
               if (!bc) {
                   dprintf("no address left\n");
                   return;
               }
           }
           memcpy(bc->macaddr, slirp->client_ethaddr, 6);
       } else if (preq_addr) {
           bc = request_addr(slirp, preq_addr, slirp->client_ethaddr);
           if (bc) {
               daddr.sin_addr = *preq_addr;
               memcpy(bc->macaddr, slirp->client_ethaddr, 6);
           } else {
               daddr.sin_addr.s_addr = 0;
         }          }
         memcpy(bc->macaddr, client_ethaddr, 6);  
     } else {      } else {
         bc = find_addr(&daddr.sin_addr, bp->bp_hwaddr);          bc = find_addr(slirp, &daddr.sin_addr, bp->bp_hwaddr);
         if (!bc) {          if (!bc) {
             /* if never assigned, behaves as if it was already              /* if never assigned, behaves as if it was already
                assigned (windows fix because it remembers its address) */                 assigned (windows fix because it remembers its address) */
Line 171  static void bootp_reply(struct bootp_t * Line 207  static void bootp_reply(struct bootp_t *
         }          }
     }      }
   
     if (bootp_filename)      saddr.sin_addr = slirp->vhost_addr;
         snprintf((char *)rbp->bp_file, sizeof(rbp->bp_file), "%s",  
                  bootp_filename);  
   
     dprintf("offered addr=%08x\n", ntohl(daddr.sin_addr.s_addr));  
   
     saddr.sin_addr.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_ALIAS);  
     saddr.sin_port = htons(BOOTP_SERVER);      saddr.sin_port = htons(BOOTP_SERVER);
   
     daddr.sin_port = htons(BOOTP_CLIENT);      daddr.sin_port = htons(BOOTP_CLIENT);
Line 191  static void bootp_reply(struct bootp_t * Line 221  static void bootp_reply(struct bootp_t *
     rbp->bp_yiaddr = daddr.sin_addr; /* Client IP address */      rbp->bp_yiaddr = daddr.sin_addr; /* Client IP address */
     rbp->bp_siaddr = saddr.sin_addr; /* Server IP address */      rbp->bp_siaddr = saddr.sin_addr; /* Server IP address */
   
     daddr.sin_addr.s_addr = 0xffffffffu;  
   
     q = rbp->bp_vend;      q = rbp->bp_vend;
     memcpy(q, rfc1533_cookie, 4);      memcpy(q, rfc1533_cookie, 4);
     q += 4;      q += 4;
   
     if (dhcp_msg_type == DHCPDISCOVER) {      if (bc) {
         *q++ = RFC2132_MSG_TYPE;          dprintf("%s addr=%08x\n",
         *q++ = 1;                  (dhcp_msg_type == DHCPDISCOVER) ? "offered" : "ack'ed",
         *q++ = DHCPOFFER;                  ntohl(daddr.sin_addr.s_addr));
     } else if (dhcp_msg_type == DHCPREQUEST) {  
         *q++ = RFC2132_MSG_TYPE;          if (dhcp_msg_type == DHCPDISCOVER) {
         *q++ = 1;              *q++ = RFC2132_MSG_TYPE;
         *q++ = DHCPACK;              *q++ = 1;
     }              *q++ = DHCPOFFER;
           } else /* DHCPREQUEST */ {
               *q++ = RFC2132_MSG_TYPE;
               *q++ = 1;
               *q++ = DHCPACK;
           }
   
           if (slirp->bootp_filename)
               snprintf((char *)rbp->bp_file, sizeof(rbp->bp_file), "%s",
                        slirp->bootp_filename);
   
     if (dhcp_msg_type == DHCPDISCOVER ||  
         dhcp_msg_type == DHCPREQUEST) {  
         *q++ = RFC2132_SRV_ID;          *q++ = RFC2132_SRV_ID;
         *q++ = 4;          *q++ = 4;
         memcpy(q, &saddr.sin_addr, 4);          memcpy(q, &saddr.sin_addr, 4);
Line 216  static void bootp_reply(struct bootp_t * Line 251  static void bootp_reply(struct bootp_t *
   
         *q++ = RFC1533_NETMASK;          *q++ = RFC1533_NETMASK;
         *q++ = 4;          *q++ = 4;
         *q++ = 0xff;          memcpy(q, &slirp->vnetwork_mask, 4);
         *q++ = 0xff;          q += 4;
         *q++ = 0xff;  
         *q++ = 0x00;  
   
         if (!slirp_restrict) {          if (!slirp->restricted) {
             *q++ = RFC1533_GATEWAY;              *q++ = RFC1533_GATEWAY;
             *q++ = 4;              *q++ = 4;
             memcpy(q, &saddr.sin_addr, 4);              memcpy(q, &saddr.sin_addr, 4);
Line 229  static void bootp_reply(struct bootp_t * Line 262  static void bootp_reply(struct bootp_t *
   
             *q++ = RFC1533_DNS;              *q++ = RFC1533_DNS;
             *q++ = 4;              *q++ = 4;
             dns_addr.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_DNS);              memcpy(q, &slirp->vnameserver_addr, 4);
             memcpy(q, &dns_addr, 4);  
             q += 4;              q += 4;
         }          }
   
Line 240  static void bootp_reply(struct bootp_t * Line 272  static void bootp_reply(struct bootp_t *
         memcpy(q, &val, 4);          memcpy(q, &val, 4);
         q += 4;          q += 4;
   
         if (*slirp_hostname) {          if (*slirp->client_hostname) {
             val = strlen(slirp_hostname);              val = strlen(slirp->client_hostname);
             *q++ = RFC1533_HOSTNAME;              *q++ = RFC1533_HOSTNAME;
             *q++ = val;              *q++ = val;
             memcpy(q, slirp_hostname, val);              memcpy(q, slirp->client_hostname, val);
             q += val;              q += val;
         }          }
       } else {
           static const char nak_msg[] = "requested address not available";
   
           dprintf("nak'ed addr=%08x\n", ntohl(preq_addr->s_addr));
   
           *q++ = RFC2132_MSG_TYPE;
           *q++ = 1;
           *q++ = DHCPNAK;
   
           *q++ = RFC2132_MESSAGE;
           *q++ = sizeof(nak_msg) - 1;
           memcpy(q, nak_msg, sizeof(nak_msg) - 1);
           q += sizeof(nak_msg) - 1;
     }      }
     *q++ = RFC1533_END;      *q++ = RFC1533_END;
   
       daddr.sin_addr.s_addr = 0xffffffffu;
   
     m->m_len = sizeof(struct bootp_t) -      m->m_len = sizeof(struct bootp_t) -
         sizeof(struct ip) - sizeof(struct udphdr);          sizeof(struct ip) - sizeof(struct udphdr);
     udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);      udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
Line 260  void bootp_input(struct mbuf *m) Line 307  void bootp_input(struct mbuf *m)
     struct bootp_t *bp = mtod(m, struct bootp_t *);      struct bootp_t *bp = mtod(m, struct bootp_t *);
   
     if (bp->bp_op == BOOTP_REQUEST) {      if (bp->bp_op == BOOTP_REQUEST) {
         bootp_reply(bp);          bootp_reply(m->slirp, bp);
     }      }
 }  }

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


unix.superglobalmegacorp.com