Annotation of qemu/slirp/bootp.c, revision 1.1.1.10

1.1       root        1: /*
                      2:  * QEMU BOOTP/DHCP server
1.1.1.3   root        3:  *
1.1       root        4:  * Copyright (c) 2004 Fabrice Bellard
1.1.1.3   root        5:  *
1.1       root        6:  * Permission is hereby granted, free of charge, to any person obtaining a copy
                      7:  * of this software and associated documentation files (the "Software"), to deal
                      8:  * in the Software without restriction, including without limitation the rights
                      9:  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
                     10:  * copies of the Software, and to permit persons to whom the Software is
                     11:  * furnished to do so, subject to the following conditions:
                     12:  *
                     13:  * The above copyright notice and this permission notice shall be included in
                     14:  * all copies or substantial portions of the Software.
                     15:  *
                     16:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
                     17:  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
                     18:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
                     19:  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
                     20:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
                     21:  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
                     22:  * THE SOFTWARE.
                     23:  */
                     24: #include <slirp.h>
                     25: 
                     26: /* XXX: only DHCP is supported */
                     27: 
                     28: #define LEASE_TIME (24 * 3600)
                     29: 
                     30: static const uint8_t rfc1533_cookie[] = { RFC1533_COOKIE };
                     31: 
                     32: #ifdef DEBUG
1.1.1.6   root       33: #define DPRINTF(fmt, ...) \
1.1.1.5   root       34: do if (slirp_debug & DBG_CALL) { fprintf(dfd, fmt, ##  __VA_ARGS__); fflush(dfd); } while (0)
1.1       root       35: #else
1.1.1.7   root       36: #define DPRINTF(fmt, ...) do{}while(0)
1.1       root       37: #endif
                     38: 
1.1.1.5   root       39: static BOOTPClient *get_new_addr(Slirp *slirp, struct in_addr *paddr,
                     40:                                  const uint8_t *macaddr)
1.1       root       41: {
                     42:     BOOTPClient *bc;
                     43:     int i;
                     44: 
1.1.1.5   root       45:     for(i = 0; i < NB_BOOTP_CLIENTS; i++) {
                     46:         bc = &slirp->bootp_clients[i];
                     47:         if (!bc->allocated || !memcmp(macaddr, bc->macaddr, 6))
1.1       root       48:             goto found;
                     49:     }
                     50:     return NULL;
                     51:  found:
1.1.1.5   root       52:     bc = &slirp->bootp_clients[i];
1.1       root       53:     bc->allocated = 1;
1.1.1.5   root       54:     paddr->s_addr = slirp->vdhcp_startaddr.s_addr + htonl(i);
1.1       root       55:     return bc;
                     56: }
                     57: 
1.1.1.5   root       58: static BOOTPClient *request_addr(Slirp *slirp, const struct in_addr *paddr,
                     59:                                  const uint8_t *macaddr)
                     60: {
                     61:     uint32_t req_addr = ntohl(paddr->s_addr);
                     62:     uint32_t dhcp_addr = ntohl(slirp->vdhcp_startaddr.s_addr);
                     63:     BOOTPClient *bc;
                     64: 
                     65:     if (req_addr >= dhcp_addr &&
                     66:         req_addr < (dhcp_addr + NB_BOOTP_CLIENTS)) {
                     67:         bc = &slirp->bootp_clients[req_addr - dhcp_addr];
                     68:         if (!bc->allocated || !memcmp(macaddr, bc->macaddr, 6)) {
                     69:             bc->allocated = 1;
                     70:             return bc;
                     71:         }
                     72:     }
                     73:     return NULL;
                     74: }
                     75: 
                     76: static BOOTPClient *find_addr(Slirp *slirp, struct in_addr *paddr,
                     77:                               const uint8_t *macaddr)
1.1       root       78: {
                     79:     BOOTPClient *bc;
                     80:     int i;
                     81: 
1.1.1.5   root       82:     for(i = 0; i < NB_BOOTP_CLIENTS; i++) {
                     83:         if (!memcmp(macaddr, slirp->bootp_clients[i].macaddr, 6))
1.1       root       84:             goto found;
                     85:     }
                     86:     return NULL;
                     87:  found:
1.1.1.5   root       88:     bc = &slirp->bootp_clients[i];
1.1       root       89:     bc->allocated = 1;
1.1.1.5   root       90:     paddr->s_addr = slirp->vdhcp_startaddr.s_addr + htonl(i);
1.1       root       91:     return bc;
                     92: }
                     93: 
1.1.1.5   root       94: static void dhcp_decode(const struct bootp_t *bp, int *pmsg_type,
1.1.1.7   root       95:                         struct in_addr *preq_addr)
1.1       root       96: {
                     97:     const uint8_t *p, *p_end;
                     98:     int len, tag;
                     99: 
1.1.1.3   root      100:     *pmsg_type = 0;
1.1.1.7   root      101:     preq_addr->s_addr = htonl(0L);
1.1       root      102: 
1.1.1.5   root      103:     p = bp->bp_vend;
                    104:     p_end = p + DHCP_OPT_LEN;
1.1       root      105:     if (memcmp(p, rfc1533_cookie, 4) != 0)
                    106:         return;
                    107:     p += 4;
                    108:     while (p < p_end) {
                    109:         tag = p[0];
                    110:         if (tag == RFC1533_PAD) {
1.1.1.3   root      111:             p++;
1.1       root      112:         } else if (tag == RFC1533_END) {
                    113:             break;
                    114:         } else {
                    115:             p++;
                    116:             if (p >= p_end)
                    117:                 break;
                    118:             len = *p++;
1.1.1.6   root      119:             DPRINTF("dhcp: tag=%d len=%d\n", tag, len);
1.1       root      120: 
                    121:             switch(tag) {
                    122:             case RFC2132_MSG_TYPE:
                    123:                 if (len >= 1)
                    124:                     *pmsg_type = p[0];
                    125:                 break;
1.1.1.5   root      126:             case RFC2132_REQ_ADDR:
1.1.1.7   root      127:                 if (len >= 4) {
                    128:                     memcpy(&(preq_addr->s_addr), p, 4);
                    129:                 }
1.1.1.5   root      130:                 break;
1.1       root      131:             default:
                    132:                 break;
                    133:             }
                    134:             p += len;
                    135:         }
                    136:     }
1.1.1.7   root      137:     if (*pmsg_type == DHCPREQUEST && preq_addr->s_addr == htonl(0L) &&
                    138:         bp->bp_ciaddr.s_addr) {
                    139:         memcpy(&(preq_addr->s_addr), &bp->bp_ciaddr, 4);
1.1.1.5   root      140:     }
1.1       root      141: }
                    142: 
1.1.1.5   root      143: static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
1.1       root      144: {
1.1.1.5   root      145:     BOOTPClient *bc = NULL;
1.1       root      146:     struct mbuf *m;
                    147:     struct bootp_t *rbp;
                    148:     struct sockaddr_in saddr, daddr;
1.1.1.7   root      149:     struct in_addr preq_addr;
1.1       root      150:     int dhcp_msg_type, val;
                    151:     uint8_t *q;
1.1.1.9   root      152:     uint8_t client_ethaddr[ETH_ALEN];
1.1       root      153: 
                    154:     /* extract exact DHCP msg type */
1.1.1.5   root      155:     dhcp_decode(bp, &dhcp_msg_type, &preq_addr);
1.1.1.6   root      156:     DPRINTF("bootp packet op=%d msgtype=%d", bp->bp_op, dhcp_msg_type);
1.1.1.7   root      157:     if (preq_addr.s_addr != htonl(0L))
                    158:         DPRINTF(" req_addr=%08x\n", ntohl(preq_addr.s_addr));
1.1.1.5   root      159:     else
1.1.1.6   root      160:         DPRINTF("\n");
1.1.1.3   root      161: 
1.1       root      162:     if (dhcp_msg_type == 0)
                    163:         dhcp_msg_type = DHCPREQUEST; /* Force reply for old BOOTP clients */
1.1.1.3   root      164: 
                    165:     if (dhcp_msg_type != DHCPDISCOVER &&
1.1       root      166:         dhcp_msg_type != DHCPREQUEST)
                    167:         return;
1.1.1.9   root      168: 
                    169:     /* Get client's hardware address from bootp request */
                    170:     memcpy(client_ethaddr, bp->bp_hwaddr, ETH_ALEN);
1.1.1.3   root      171: 
1.1.1.5   root      172:     m = m_get(slirp);
                    173:     if (!m) {
1.1       root      174:         return;
1.1.1.5   root      175:     }
1.1.1.3   root      176:     m->m_data += IF_MAXLINKHDR;
1.1       root      177:     rbp = (struct bootp_t *)m->m_data;
                    178:     m->m_data += sizeof(struct udpiphdr);
                    179:     memset(rbp, 0, sizeof(struct bootp_t));
                    180: 
                    181:     if (dhcp_msg_type == DHCPDISCOVER) {
1.1.1.7   root      182:         if (preq_addr.s_addr != htonl(0L)) {
1.1.1.9   root      183:             bc = request_addr(slirp, &preq_addr, client_ethaddr);
1.1.1.5   root      184:             if (bc) {
1.1.1.7   root      185:                 daddr.sin_addr = preq_addr;
1.1.1.5   root      186:             }
                    187:         }
1.1       root      188:         if (!bc) {
1.1.1.5   root      189:          new_addr:
1.1.1.9   root      190:             bc = get_new_addr(slirp, &daddr.sin_addr, client_ethaddr);
1.1.1.5   root      191:             if (!bc) {
1.1.1.6   root      192:                 DPRINTF("no address left\n");
1.1.1.5   root      193:                 return;
                    194:             }
                    195:         }
1.1.1.9   root      196:         memcpy(bc->macaddr, client_ethaddr, ETH_ALEN);
1.1.1.7   root      197:     } else if (preq_addr.s_addr != htonl(0L)) {
1.1.1.9   root      198:         bc = request_addr(slirp, &preq_addr, client_ethaddr);
1.1.1.5   root      199:         if (bc) {
1.1.1.7   root      200:             daddr.sin_addr = preq_addr;
1.1.1.9   root      201:             memcpy(bc->macaddr, client_ethaddr, ETH_ALEN);
1.1.1.5   root      202:         } else {
1.1.1.10! root      203:             /* DHCPNAKs should be sent to broadcast */
        !           204:             daddr.sin_addr.s_addr = 0xffffffff;
1.1       root      205:         }
                    206:     } else {
1.1.1.5   root      207:         bc = find_addr(slirp, &daddr.sin_addr, bp->bp_hwaddr);
1.1       root      208:         if (!bc) {
                    209:             /* if never assigned, behaves as if it was already
                    210:                assigned (windows fix because it remembers its address) */
                    211:             goto new_addr;
                    212:         }
                    213:     }
1.1.1.3   root      214: 
1.1.1.9   root      215:     /* Update ARP table for this IP address */
                    216:     arp_table_add(slirp, daddr.sin_addr.s_addr, client_ethaddr);
                    217: 
1.1.1.5   root      218:     saddr.sin_addr = slirp->vhost_addr;
1.1       root      219:     saddr.sin_port = htons(BOOTP_SERVER);
                    220: 
                    221:     daddr.sin_port = htons(BOOTP_CLIENT);
                    222: 
                    223:     rbp->bp_op = BOOTP_REPLY;
                    224:     rbp->bp_xid = bp->bp_xid;
                    225:     rbp->bp_htype = 1;
                    226:     rbp->bp_hlen = 6;
1.1.1.9   root      227:     memcpy(rbp->bp_hwaddr, bp->bp_hwaddr, ETH_ALEN);
1.1       root      228: 
                    229:     rbp->bp_yiaddr = daddr.sin_addr; /* Client IP address */
                    230:     rbp->bp_siaddr = saddr.sin_addr; /* Server IP address */
                    231: 
                    232:     q = rbp->bp_vend;
                    233:     memcpy(q, rfc1533_cookie, 4);
                    234:     q += 4;
                    235: 
1.1.1.5   root      236:     if (bc) {
1.1.1.6   root      237:         DPRINTF("%s addr=%08x\n",
1.1.1.5   root      238:                 (dhcp_msg_type == DHCPDISCOVER) ? "offered" : "ack'ed",
                    239:                 ntohl(daddr.sin_addr.s_addr));
                    240: 
                    241:         if (dhcp_msg_type == DHCPDISCOVER) {
                    242:             *q++ = RFC2132_MSG_TYPE;
                    243:             *q++ = 1;
                    244:             *q++ = DHCPOFFER;
                    245:         } else /* DHCPREQUEST */ {
                    246:             *q++ = RFC2132_MSG_TYPE;
                    247:             *q++ = 1;
                    248:             *q++ = DHCPACK;
                    249:         }
                    250: 
                    251:         if (slirp->bootp_filename)
                    252:             snprintf((char *)rbp->bp_file, sizeof(rbp->bp_file), "%s",
                    253:                      slirp->bootp_filename);
1.1.1.3   root      254: 
1.1       root      255:         *q++ = RFC2132_SRV_ID;
                    256:         *q++ = 4;
                    257:         memcpy(q, &saddr.sin_addr, 4);
                    258:         q += 4;
                    259: 
                    260:         *q++ = RFC1533_NETMASK;
                    261:         *q++ = 4;
1.1.1.5   root      262:         memcpy(q, &slirp->vnetwork_mask, 4);
                    263:         q += 4;
1.1.1.3   root      264: 
1.1.1.5   root      265:         if (!slirp->restricted) {
1.1.1.4   root      266:             *q++ = RFC1533_GATEWAY;
                    267:             *q++ = 4;
                    268:             memcpy(q, &saddr.sin_addr, 4);
                    269:             q += 4;
                    270: 
                    271:             *q++ = RFC1533_DNS;
                    272:             *q++ = 4;
1.1.1.5   root      273:             memcpy(q, &slirp->vnameserver_addr, 4);
1.1.1.4   root      274:             q += 4;
                    275:         }
1.1       root      276: 
                    277:         *q++ = RFC2132_LEASE_TIME;
                    278:         *q++ = 4;
                    279:         val = htonl(LEASE_TIME);
                    280:         memcpy(q, &val, 4);
                    281:         q += 4;
1.1.1.2   root      282: 
1.1.1.5   root      283:         if (*slirp->client_hostname) {
                    284:             val = strlen(slirp->client_hostname);
1.1.1.2   root      285:             *q++ = RFC1533_HOSTNAME;
                    286:             *q++ = val;
1.1.1.5   root      287:             memcpy(q, slirp->client_hostname, val);
1.1.1.2   root      288:             q += val;
                    289:         }
1.1.1.5   root      290:     } else {
                    291:         static const char nak_msg[] = "requested address not available";
                    292: 
1.1.1.8   root      293:         DPRINTF("nak'ed addr=%08x\n", ntohl(preq_addr.s_addr));
1.1.1.5   root      294: 
                    295:         *q++ = RFC2132_MSG_TYPE;
                    296:         *q++ = 1;
                    297:         *q++ = DHCPNAK;
                    298: 
                    299:         *q++ = RFC2132_MESSAGE;
                    300:         *q++ = sizeof(nak_msg) - 1;
                    301:         memcpy(q, nak_msg, sizeof(nak_msg) - 1);
                    302:         q += sizeof(nak_msg) - 1;
1.1       root      303:     }
1.1.1.6   root      304:     *q = RFC1533_END;
1.1.1.3   root      305: 
1.1.1.5   root      306:     daddr.sin_addr.s_addr = 0xffffffffu;
                    307: 
1.1.1.3   root      308:     m->m_len = sizeof(struct bootp_t) -
1.1       root      309:         sizeof(struct ip) - sizeof(struct udphdr);
                    310:     udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
                    311: }
                    312: 
                    313: void bootp_input(struct mbuf *m)
                    314: {
                    315:     struct bootp_t *bp = mtod(m, struct bootp_t *);
                    316: 
                    317:     if (bp->bp_op == BOOTP_REQUEST) {
1.1.1.5   root      318:         bootp_reply(m->slirp, bp);
1.1       root      319:     }
                    320: }

unix.superglobalmegacorp.com