18b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/*
28b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * QEMU BOOTP/DHCP server
35d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *
48b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Copyright (c) 2004 Fabrice Bellard
55d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *
68b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Permission is hereby granted, free of charge, to any person obtaining a copy
78b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * of this software and associated documentation files (the "Software"), to deal
88b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * in the Software without restriction, including without limitation the rights
98b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * copies of the Software, and to permit persons to whom the Software is
118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * furnished to do so, subject to the following conditions:
128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *
138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * The above copyright notice and this permission notice shall be included in
148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * all copies or substantial portions of the Software.
158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *
168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * THE SOFTWARE.
238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */
248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include <slirp.h>
255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "helper.h"
268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* XXX: only DHCP is supported */
288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define NB_ADDR 16
308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define START_ADDR 15
328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define LEASE_TIME (24 * 3600)
348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projecttypedef struct {
368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint8_t allocated;
378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint8_t macaddr[6];
388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} BOOTPClient;
398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic BOOTPClient bootp_clients[NB_ADDR];
418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectconst char *bootp_filename;
438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic const uint8_t rfc1533_cookie[] = { RFC1533_COOKIE };
458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef DEBUG
475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define dprintf(fmt, ...) \
485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerif (slirp_debug & DBG_CALL) { fprintf(dfd, fmt, ##  __VA_ARGS__); fflush(dfd); }
498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#else
505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define dprintf(fmt, ...)
518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic BOOTPClient *get_new_addr(SockAddress*  paddr,
545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                 const uint8_t *macaddr)
558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    BOOTPClient *bc;
578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i;
588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for(i = 0; i < NB_ADDR; i++) {
605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        bc = &bootp_clients[i];
615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (!bc->allocated || !memcmp(macaddr, bc->macaddr, 6))
628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            goto found;
638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return NULL;
658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project found:
668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bc = &bootp_clients[i];
678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bc->allocated = 1;
68d86c724b74e6c04a89219d87559d0b580e100445Vladimir Chtchetkine    sock_address_init_inet( paddr,
698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                            special_addr_ip | (i+START_ADDR),
708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                            BOOTP_CLIENT );
718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return bc;
728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic BOOTPClient *request_addr(const ipaddr_t *paddr,
755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                 const uint8_t *macaddr)
765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    uint32_t req_addr  = ip_geth(*paddr);
785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    uint32_t spec_addr = special_addr_ip;
795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    BOOTPClient *bc;
805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (req_addr >= (spec_addr | START_ADDR) &&
825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        req_addr < (spec_addr | (NB_ADDR + START_ADDR))) {
835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        bc = &bootp_clients[(req_addr & 0xff) - START_ADDR];
845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (!bc->allocated || !memcmp(macaddr, bc->macaddr, 6)) {
855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            bc->allocated = 1;
865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return bc;
875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return NULL;
905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic BOOTPClient *find_addr(SockAddress *paddr, const uint8_t *macaddr)
938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    BOOTPClient *bc;
958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i;
968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for(i = 0; i < NB_ADDR; i++) {
988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (!memcmp(macaddr, bootp_clients[i].macaddr, 6))
998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            goto found;
1008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
1018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return NULL;
1028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project found:
1038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bc = &bootp_clients[i];
1048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    bc->allocated = 1;
1058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    sock_address_init_inet( paddr,
1068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                            special_addr_ip | (i + START_ADDR),
1078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                            BOOTP_CLIENT );
1088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return bc;
1098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
1108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void dhcp_decode(const struct bootp_t *bp, int *pmsg_type,
1125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                        const ipaddr_t **preq_addr)
1138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
1148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    const uint8_t *p, *p_end;
1158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int len, tag;
1168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    *pmsg_type = 0;
1185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    *preq_addr = NULL;
1198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    p = bp->bp_vend;
1215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    p_end = p + DHCP_OPT_LEN;
1228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (memcmp(p, rfc1533_cookie, 4) != 0)
1238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return;
1248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    p += 4;
1258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    while (p < p_end) {
1268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        tag = p[0];
1278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (tag == RFC1533_PAD) {
1285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            p++;
1298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        } else if (tag == RFC1533_END) {
1308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            break;
1318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        } else {
1328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            p++;
1338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if (p >= p_end)
1348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                break;
1358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            len = *p++;
1365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            dprintf("dhcp: tag=%d len=%d\n", tag, len);
1378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            switch(tag) {
1398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            case RFC2132_MSG_TYPE:
1408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                if (len >= 1)
1418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    *pmsg_type = p[0];
1428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                break;
1435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            case RFC2132_REQ_ADDR:
1445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                if (len >= 4)
1455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    *preq_addr = (const ipaddr_t *)p;
1465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                break;
1478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            default:
1488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                break;
1498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
1508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            p += len;
1518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
1528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
1535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (*pmsg_type == DHCPREQUEST && !*preq_addr && bp->bp_ciaddr) {
1545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        *preq_addr = (const ipaddr_t*)&bp->bp_ciaddr;
1555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
1568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
1578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void bootp_reply(const struct bootp_t *bp)
1598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
1605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    BOOTPClient *bc = NULL;
1615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct mbuf *m;
1628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct bootp_t *rbp;
1638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    SockAddress  saddr, daddr;
1648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t     dns_addr;
1655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    const ipaddr_t *preq_addr;
1668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int dhcp_msg_type, val;
1678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint8_t *q;
1688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* extract exact DHCP msg type */
1705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    dhcp_decode(bp, &dhcp_msg_type, &preq_addr);
1715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    dprintf("bootp packet op=%d msgtype=%d", bp->bp_op, dhcp_msg_type);
1725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (preq_addr) {
173d86c724b74e6c04a89219d87559d0b580e100445Vladimir Chtchetkine        dprintf(" req_addr=%08x\n", ntohl(*(uint32_t*)preq_addr));
1745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else {
1755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        dprintf("\n");
1765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
1778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (dhcp_msg_type == 0)
1788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        dhcp_msg_type = DHCPREQUEST; /* Force reply for old BOOTP clients */
1795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (dhcp_msg_type != DHCPDISCOVER &&
1818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        dhcp_msg_type != DHCPREQUEST)
1828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return;
1838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* XXX: this is a hack to get the client mac address */
1848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    memcpy(client_ethaddr, bp->bp_hwaddr, 6);
1855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if ((m = m_get()) == NULL)
1878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return;
1885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    m->m_data += IF_MAXLINKHDR;
1898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    rbp = (struct bootp_t *)m->m_data;
1908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    m->m_data += sizeof(struct udpiphdr);
1918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    memset(rbp, 0, sizeof(struct bootp_t));
1928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (dhcp_msg_type == DHCPDISCOVER) {
1945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (preq_addr) {
1955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            bc = request_addr(preq_addr, client_ethaddr);
1965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (bc) {
1975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner				sock_address_init_inet(&daddr, ip_geth(*preq_addr), BOOTP_CLIENT);
1985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
1995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
2008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (!bc) {
2015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner         new_addr:
2025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	        bc = get_new_addr(&daddr, client_ethaddr);
2035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (!bc) {
2045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                dprintf("no address left\n");
2055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                return;
2065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
2078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
2088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        memcpy(bc->macaddr, client_ethaddr, 6);
2095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else if (preq_addr) {
2105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        bc = request_addr(preq_addr, client_ethaddr);
2115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (bc) {
2125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			sock_address_init_inet(&daddr, ip_geth(*preq_addr), BOOTP_CLIENT);
2135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            memcpy(bc->macaddr, client_ethaddr, 6);
2145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        } else {
2155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            sock_address_init_inet(&daddr, 0, BOOTP_CLIENT);
2165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
2178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else {
2188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        bc = find_addr(&daddr, bp->bp_hwaddr);
2198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (!bc) {
2208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            /* if never assigned, behaves as if it was already
2218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project               assigned (windows fix because it remembers its address) */
2228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            goto new_addr;
2238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
2248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
2258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    sock_address_init_inet( &saddr, special_addr_ip | CTL_ALIAS,
2278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                            BOOTP_SERVER );
2288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    rbp->bp_op = BOOTP_REPLY;
2308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    rbp->bp_xid = bp->bp_xid;
2318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    rbp->bp_htype = 1;
2328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    rbp->bp_hlen = 6;
2338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    memcpy(rbp->bp_hwaddr, bp->bp_hwaddr, 6);
2348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    rbp->bp_yiaddr = htonl(sock_address_get_ip(&daddr)); /* Client IP address */
2368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    rbp->bp_siaddr = htonl(sock_address_get_ip(&saddr)); /* Server IP address */
2378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    q = rbp->bp_vend;
2398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    memcpy(q, rfc1533_cookie, 4);
2408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    q += 4;
2418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (bc) {
2438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        uint32_t  saddr_ip = htonl(sock_address_get_ip(&saddr));
2445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        dprintf("%s addr=%08x\n",
2455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                (dhcp_msg_type == DHCPDISCOVER) ? "offered" : "ack'ed",
2465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                sock_address_get_ip(&daddr));
2475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (dhcp_msg_type == DHCPDISCOVER) {
2495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            *q++ = RFC2132_MSG_TYPE;
2505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            *q++ = 1;
2515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            *q++ = DHCPOFFER;
2525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        } else /* DHCPREQUEST */ {
2535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            *q++ = RFC2132_MSG_TYPE;
2545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            *q++ = 1;
2555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            *q++ = DHCPACK;
2565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
2575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (bootp_filename)
2595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            snprintf((char *)rbp->bp_file, sizeof(rbp->bp_file), "%s",
2605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                     bootp_filename);
2615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        *q++ = RFC2132_SRV_ID;
2638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        *q++ = 4;
2648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        memcpy(q, &saddr_ip, 4);
2658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        q += 4;
2668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        *q++ = RFC1533_NETMASK;
2688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        *q++ = 4;
2698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        *q++ = 0xff;
2708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        *q++ = 0xff;
2718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        *q++ = 0xff;
2728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        *q++ = 0x00;
2738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (!slirp_restrict) {
2755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            *q++ = RFC1533_GATEWAY;
2765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            *q++ = 4;
2775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            memcpy(q, &saddr_ip, 4);
2785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            q += 4;
2795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            *q++ = RFC1533_DNS;
2815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            *q++ = 4;
2825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            dns_addr = htonl(special_addr_ip | CTL_DNS);
2835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            memcpy(q, &dns_addr, 4);
2845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            q += 4;
2855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
2868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        *q++ = RFC2132_LEASE_TIME;
2888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        *q++ = 4;
2898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        val = htonl(LEASE_TIME);
2908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        memcpy(q, &val, 4);
2918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        q += 4;
2928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (*slirp_hostname) {
2948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            val = strlen(slirp_hostname);
2958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            *q++ = RFC1533_HOSTNAME;
2968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            *q++ = val;
2978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            memcpy(q, slirp_hostname, val);
2988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            q += val;
2998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
3005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else {
3015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        static const char nak_msg[] = "requested address not available";
3025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        dprintf("nak'ed addr=%08x\n", ip_geth(*preq_addr));
3045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        *q++ = RFC2132_MSG_TYPE;
3065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        *q++ = 1;
3075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        *q++ = DHCPNAK;
3085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        *q++ = RFC2132_MESSAGE;
3105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        *q++ = sizeof(nak_msg) - 1;
3115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        memcpy(q, nak_msg, sizeof(nak_msg) - 1);
3125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        q += sizeof(nak_msg) - 1;
3138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
3148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    *q++ = RFC1533_END;
3158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	sock_address_init_inet(&daddr, 0xffffffffu, BOOTP_CLIENT);
3175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    m->m_len = sizeof(struct bootp_t) -
3195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        sizeof(struct ip) - sizeof(struct udphdr);
3208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    udp_output2_(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
3218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
3228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid bootp_input(struct mbuf *m)
3248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
3255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct bootp_t *bp = mtod(m, struct bootp_t *);
3268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (bp->bp_op == BOOTP_REQUEST) {
3288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        bootp_reply(bp);
3298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
3308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
331