bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 1 | /* |
| 2 | * QEMU BOOTP/DHCP server |
ths | 5fafdf2 | 2007-09-16 21:08:06 +0000 | [diff] [blame] | 3 | * |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 4 | * Copyright (c) 2004 Fabrice Bellard |
ths | 5fafdf2 | 2007-09-16 21:08:06 +0000 | [diff] [blame] | 5 | * |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 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 | */ |
Peter Maydell | 7df7482 | 2016-01-29 17:49:59 +0000 | [diff] [blame] | 24 | #include "qemu/osdep.h" |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 25 | #include <slirp.h> |
| 26 | |
Stefan Weil | ecc804c | 2015-08-29 09:12:35 +0200 | [diff] [blame] | 27 | #if defined(_WIN32) |
| 28 | /* Windows ntohl() returns an u_long value. |
| 29 | * Add a type cast to match the format strings. */ |
| 30 | # define ntohl(n) ((uint32_t)ntohl(n)) |
| 31 | #endif |
| 32 | |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 33 | /* XXX: only DHCP is supported */ |
| 34 | |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 35 | #define LEASE_TIME (24 * 3600) |
| 36 | |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 37 | static const uint8_t rfc1533_cookie[] = { RFC1533_COOKIE }; |
| 38 | |
| 39 | #ifdef DEBUG |
malc | d0f2c4c | 2010-02-07 02:03:50 +0300 | [diff] [blame] | 40 | #define DPRINTF(fmt, ...) \ |
Jan Kiszka | 9f34949 | 2009-06-24 14:42:29 +0200 | [diff] [blame] | 41 | do if (slirp_debug & DBG_CALL) { fprintf(dfd, fmt, ## __VA_ARGS__); fflush(dfd); } while (0) |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 42 | #else |
Jes Sorensen | 7390cdf | 2010-08-31 09:30:37 +0200 | [diff] [blame] | 43 | #define DPRINTF(fmt, ...) do{}while(0) |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 44 | #endif |
| 45 | |
Jan Kiszka | 460fec6 | 2009-06-24 14:42:31 +0200 | [diff] [blame] | 46 | static BOOTPClient *get_new_addr(Slirp *slirp, struct in_addr *paddr, |
Jan Kiszka | 0928a95 | 2009-05-21 22:43:39 +0200 | [diff] [blame] | 47 | const uint8_t *macaddr) |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 48 | { |
| 49 | BOOTPClient *bc; |
| 50 | int i; |
| 51 | |
Jan Kiszka | 460fec6 | 2009-06-24 14:42:31 +0200 | [diff] [blame] | 52 | for(i = 0; i < NB_BOOTP_CLIENTS; i++) { |
| 53 | bc = &slirp->bootp_clients[i]; |
Jan Kiszka | 0928a95 | 2009-05-21 22:43:39 +0200 | [diff] [blame] | 54 | if (!bc->allocated || !memcmp(macaddr, bc->macaddr, 6)) |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 55 | goto found; |
| 56 | } |
| 57 | return NULL; |
| 58 | found: |
Jan Kiszka | 460fec6 | 2009-06-24 14:42:31 +0200 | [diff] [blame] | 59 | bc = &slirp->bootp_clients[i]; |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 60 | bc->allocated = 1; |
Jan Kiszka | 460fec6 | 2009-06-24 14:42:31 +0200 | [diff] [blame] | 61 | paddr->s_addr = slirp->vdhcp_startaddr.s_addr + htonl(i); |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 62 | return bc; |
| 63 | } |
| 64 | |
Jan Kiszka | 460fec6 | 2009-06-24 14:42:31 +0200 | [diff] [blame] | 65 | static BOOTPClient *request_addr(Slirp *slirp, const struct in_addr *paddr, |
aliguori | b63c7f6 | 2009-04-21 19:56:20 +0000 | [diff] [blame] | 66 | const uint8_t *macaddr) |
| 67 | { |
| 68 | uint32_t req_addr = ntohl(paddr->s_addr); |
Jan Kiszka | 460fec6 | 2009-06-24 14:42:31 +0200 | [diff] [blame] | 69 | uint32_t dhcp_addr = ntohl(slirp->vdhcp_startaddr.s_addr); |
aliguori | b63c7f6 | 2009-04-21 19:56:20 +0000 | [diff] [blame] | 70 | BOOTPClient *bc; |
| 71 | |
Jan Kiszka | a13a412 | 2009-06-24 14:42:28 +0200 | [diff] [blame] | 72 | if (req_addr >= dhcp_addr && |
Jan Kiszka | 460fec6 | 2009-06-24 14:42:31 +0200 | [diff] [blame] | 73 | req_addr < (dhcp_addr + NB_BOOTP_CLIENTS)) { |
| 74 | bc = &slirp->bootp_clients[req_addr - dhcp_addr]; |
aliguori | b63c7f6 | 2009-04-21 19:56:20 +0000 | [diff] [blame] | 75 | if (!bc->allocated || !memcmp(macaddr, bc->macaddr, 6)) { |
| 76 | bc->allocated = 1; |
| 77 | return bc; |
| 78 | } |
| 79 | } |
| 80 | return NULL; |
| 81 | } |
| 82 | |
Jan Kiszka | 460fec6 | 2009-06-24 14:42:31 +0200 | [diff] [blame] | 83 | static BOOTPClient *find_addr(Slirp *slirp, struct in_addr *paddr, |
| 84 | const uint8_t *macaddr) |
bellard | 512176d | 2004-05-04 03:14:47 +0000 | [diff] [blame] | 85 | { |
| 86 | BOOTPClient *bc; |
| 87 | int i; |
| 88 | |
Jan Kiszka | 460fec6 | 2009-06-24 14:42:31 +0200 | [diff] [blame] | 89 | for(i = 0; i < NB_BOOTP_CLIENTS; i++) { |
| 90 | if (!memcmp(macaddr, slirp->bootp_clients[i].macaddr, 6)) |
bellard | 512176d | 2004-05-04 03:14:47 +0000 | [diff] [blame] | 91 | goto found; |
| 92 | } |
| 93 | return NULL; |
| 94 | found: |
Jan Kiszka | 460fec6 | 2009-06-24 14:42:31 +0200 | [diff] [blame] | 95 | bc = &slirp->bootp_clients[i]; |
bellard | 512176d | 2004-05-04 03:14:47 +0000 | [diff] [blame] | 96 | bc->allocated = 1; |
Jan Kiszka | 460fec6 | 2009-06-24 14:42:31 +0200 | [diff] [blame] | 97 | paddr->s_addr = slirp->vdhcp_startaddr.s_addr + htonl(i); |
bellard | 512176d | 2004-05-04 03:14:47 +0000 | [diff] [blame] | 98 | return bc; |
| 99 | } |
| 100 | |
aliguori | b63c7f6 | 2009-04-21 19:56:20 +0000 | [diff] [blame] | 101 | static void dhcp_decode(const struct bootp_t *bp, int *pmsg_type, |
Aurelien Jarno | 8aaf42e | 2011-01-06 22:43:13 +0100 | [diff] [blame] | 102 | struct in_addr *preq_addr) |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 103 | { |
| 104 | const uint8_t *p, *p_end; |
| 105 | int len, tag; |
| 106 | |
ths | 3b46e62 | 2007-09-17 08:09:54 +0000 | [diff] [blame] | 107 | *pmsg_type = 0; |
Aurelien Jarno | 8aaf42e | 2011-01-06 22:43:13 +0100 | [diff] [blame] | 108 | preq_addr->s_addr = htonl(0L); |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 109 | |
aliguori | b63c7f6 | 2009-04-21 19:56:20 +0000 | [diff] [blame] | 110 | p = bp->bp_vend; |
| 111 | p_end = p + DHCP_OPT_LEN; |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 112 | if (memcmp(p, rfc1533_cookie, 4) != 0) |
| 113 | return; |
| 114 | p += 4; |
| 115 | while (p < p_end) { |
| 116 | tag = p[0]; |
| 117 | if (tag == RFC1533_PAD) { |
ths | 5fafdf2 | 2007-09-16 21:08:06 +0000 | [diff] [blame] | 118 | p++; |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 119 | } else if (tag == RFC1533_END) { |
| 120 | break; |
| 121 | } else { |
| 122 | p++; |
| 123 | if (p >= p_end) |
| 124 | break; |
| 125 | len = *p++; |
malc | d0f2c4c | 2010-02-07 02:03:50 +0300 | [diff] [blame] | 126 | DPRINTF("dhcp: tag=%d len=%d\n", tag, len); |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 127 | |
| 128 | switch(tag) { |
| 129 | case RFC2132_MSG_TYPE: |
| 130 | if (len >= 1) |
| 131 | *pmsg_type = p[0]; |
| 132 | break; |
aliguori | b63c7f6 | 2009-04-21 19:56:20 +0000 | [diff] [blame] | 133 | case RFC2132_REQ_ADDR: |
Aurelien Jarno | 8aaf42e | 2011-01-06 22:43:13 +0100 | [diff] [blame] | 134 | if (len >= 4) { |
| 135 | memcpy(&(preq_addr->s_addr), p, 4); |
| 136 | } |
aliguori | b63c7f6 | 2009-04-21 19:56:20 +0000 | [diff] [blame] | 137 | break; |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 138 | default: |
| 139 | break; |
| 140 | } |
| 141 | p += len; |
| 142 | } |
| 143 | } |
Aurelien Jarno | 8aaf42e | 2011-01-06 22:43:13 +0100 | [diff] [blame] | 144 | if (*pmsg_type == DHCPREQUEST && preq_addr->s_addr == htonl(0L) && |
| 145 | bp->bp_ciaddr.s_addr) { |
| 146 | memcpy(&(preq_addr->s_addr), &bp->bp_ciaddr, 4); |
aliguori | b63c7f6 | 2009-04-21 19:56:20 +0000 | [diff] [blame] | 147 | } |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 148 | } |
| 149 | |
Jan Kiszka | 460fec6 | 2009-06-24 14:42:31 +0200 | [diff] [blame] | 150 | static void bootp_reply(Slirp *slirp, const struct bootp_t *bp) |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 151 | { |
aliguori | b63c7f6 | 2009-04-21 19:56:20 +0000 | [diff] [blame] | 152 | BOOTPClient *bc = NULL; |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 153 | struct mbuf *m; |
| 154 | struct bootp_t *rbp; |
| 155 | struct sockaddr_in saddr, daddr; |
Aurelien Jarno | 8aaf42e | 2011-01-06 22:43:13 +0100 | [diff] [blame] | 156 | struct in_addr preq_addr; |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 157 | int dhcp_msg_type, val; |
| 158 | uint8_t *q; |
Fabien Chouteau | 1a0ca1e | 2011-08-03 12:52:54 +0200 | [diff] [blame] | 159 | uint8_t client_ethaddr[ETH_ALEN]; |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 160 | |
| 161 | /* extract exact DHCP msg type */ |
aliguori | b63c7f6 | 2009-04-21 19:56:20 +0000 | [diff] [blame] | 162 | dhcp_decode(bp, &dhcp_msg_type, &preq_addr); |
malc | d0f2c4c | 2010-02-07 02:03:50 +0300 | [diff] [blame] | 163 | DPRINTF("bootp packet op=%d msgtype=%d", bp->bp_op, dhcp_msg_type); |
Aurelien Jarno | 8aaf42e | 2011-01-06 22:43:13 +0100 | [diff] [blame] | 164 | if (preq_addr.s_addr != htonl(0L)) |
Stefan Weil | ecc804c | 2015-08-29 09:12:35 +0200 | [diff] [blame] | 165 | DPRINTF(" req_addr=%08" PRIx32 "\n", ntohl(preq_addr.s_addr)); |
aliguori | b63c7f6 | 2009-04-21 19:56:20 +0000 | [diff] [blame] | 166 | else |
malc | d0f2c4c | 2010-02-07 02:03:50 +0300 | [diff] [blame] | 167 | DPRINTF("\n"); |
ths | 3b46e62 | 2007-09-17 08:09:54 +0000 | [diff] [blame] | 168 | |
bellard | 487be8a | 2004-10-03 11:44:41 +0000 | [diff] [blame] | 169 | if (dhcp_msg_type == 0) |
| 170 | dhcp_msg_type = DHCPREQUEST; /* Force reply for old BOOTP clients */ |
ths | 3b46e62 | 2007-09-17 08:09:54 +0000 | [diff] [blame] | 171 | |
ths | 5fafdf2 | 2007-09-16 21:08:06 +0000 | [diff] [blame] | 172 | if (dhcp_msg_type != DHCPDISCOVER && |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 173 | dhcp_msg_type != DHCPREQUEST) |
| 174 | return; |
Fabien Chouteau | 1a0ca1e | 2011-08-03 12:52:54 +0200 | [diff] [blame] | 175 | |
| 176 | /* Get client's hardware address from bootp request */ |
| 177 | memcpy(client_ethaddr, bp->bp_hwaddr, ETH_ALEN); |
ths | 3b46e62 | 2007-09-17 08:09:54 +0000 | [diff] [blame] | 178 | |
Jan Kiszka | 460fec6 | 2009-06-24 14:42:31 +0200 | [diff] [blame] | 179 | m = m_get(slirp); |
| 180 | if (!m) { |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 181 | return; |
Jan Kiszka | 460fec6 | 2009-06-24 14:42:31 +0200 | [diff] [blame] | 182 | } |
blueswir1 | 9634d90 | 2007-10-26 19:01:16 +0000 | [diff] [blame] | 183 | m->m_data += IF_MAXLINKHDR; |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 184 | rbp = (struct bootp_t *)m->m_data; |
| 185 | m->m_data += sizeof(struct udpiphdr); |
| 186 | memset(rbp, 0, sizeof(struct bootp_t)); |
| 187 | |
bellard | 512176d | 2004-05-04 03:14:47 +0000 | [diff] [blame] | 188 | if (dhcp_msg_type == DHCPDISCOVER) { |
Aurelien Jarno | 8aaf42e | 2011-01-06 22:43:13 +0100 | [diff] [blame] | 189 | if (preq_addr.s_addr != htonl(0L)) { |
Fabien Chouteau | 1a0ca1e | 2011-08-03 12:52:54 +0200 | [diff] [blame] | 190 | bc = request_addr(slirp, &preq_addr, client_ethaddr); |
aliguori | b63c7f6 | 2009-04-21 19:56:20 +0000 | [diff] [blame] | 191 | if (bc) { |
Aurelien Jarno | 8aaf42e | 2011-01-06 22:43:13 +0100 | [diff] [blame] | 192 | daddr.sin_addr = preq_addr; |
aliguori | b63c7f6 | 2009-04-21 19:56:20 +0000 | [diff] [blame] | 193 | } |
| 194 | } |
bellard | 512176d | 2004-05-04 03:14:47 +0000 | [diff] [blame] | 195 | if (!bc) { |
aliguori | b63c7f6 | 2009-04-21 19:56:20 +0000 | [diff] [blame] | 196 | new_addr: |
Fabien Chouteau | 1a0ca1e | 2011-08-03 12:52:54 +0200 | [diff] [blame] | 197 | bc = get_new_addr(slirp, &daddr.sin_addr, client_ethaddr); |
aliguori | b63c7f6 | 2009-04-21 19:56:20 +0000 | [diff] [blame] | 198 | if (!bc) { |
malc | d0f2c4c | 2010-02-07 02:03:50 +0300 | [diff] [blame] | 199 | DPRINTF("no address left\n"); |
aliguori | b63c7f6 | 2009-04-21 19:56:20 +0000 | [diff] [blame] | 200 | return; |
| 201 | } |
bellard | 512176d | 2004-05-04 03:14:47 +0000 | [diff] [blame] | 202 | } |
Fabien Chouteau | 1a0ca1e | 2011-08-03 12:52:54 +0200 | [diff] [blame] | 203 | memcpy(bc->macaddr, client_ethaddr, ETH_ALEN); |
Aurelien Jarno | 8aaf42e | 2011-01-06 22:43:13 +0100 | [diff] [blame] | 204 | } else if (preq_addr.s_addr != htonl(0L)) { |
Fabien Chouteau | 1a0ca1e | 2011-08-03 12:52:54 +0200 | [diff] [blame] | 205 | bc = request_addr(slirp, &preq_addr, client_ethaddr); |
aliguori | b63c7f6 | 2009-04-21 19:56:20 +0000 | [diff] [blame] | 206 | if (bc) { |
Aurelien Jarno | 8aaf42e | 2011-01-06 22:43:13 +0100 | [diff] [blame] | 207 | daddr.sin_addr = preq_addr; |
Fabien Chouteau | 1a0ca1e | 2011-08-03 12:52:54 +0200 | [diff] [blame] | 208 | memcpy(bc->macaddr, client_ethaddr, ETH_ALEN); |
aliguori | b63c7f6 | 2009-04-21 19:56:20 +0000 | [diff] [blame] | 209 | } else { |
David Gibson | 90d7416 | 2012-02-24 01:23:28 +0100 | [diff] [blame] | 210 | /* DHCPNAKs should be sent to broadcast */ |
| 211 | daddr.sin_addr.s_addr = 0xffffffff; |
aliguori | b63c7f6 | 2009-04-21 19:56:20 +0000 | [diff] [blame] | 212 | } |
bellard | 512176d | 2004-05-04 03:14:47 +0000 | [diff] [blame] | 213 | } else { |
Jan Kiszka | 460fec6 | 2009-06-24 14:42:31 +0200 | [diff] [blame] | 214 | bc = find_addr(slirp, &daddr.sin_addr, bp->bp_hwaddr); |
bellard | 512176d | 2004-05-04 03:14:47 +0000 | [diff] [blame] | 215 | if (!bc) { |
bellard | d981b88 | 2004-09-30 18:57:28 +0000 | [diff] [blame] | 216 | /* if never assigned, behaves as if it was already |
| 217 | assigned (windows fix because it remembers its address) */ |
| 218 | goto new_addr; |
bellard | 512176d | 2004-05-04 03:14:47 +0000 | [diff] [blame] | 219 | } |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 220 | } |
ths | 47d5d01 | 2007-02-20 00:05:08 +0000 | [diff] [blame] | 221 | |
Fabien Chouteau | 1a0ca1e | 2011-08-03 12:52:54 +0200 | [diff] [blame] | 222 | /* Update ARP table for this IP address */ |
| 223 | arp_table_add(slirp, daddr.sin_addr.s_addr, client_ethaddr); |
| 224 | |
Jan Kiszka | 460fec6 | 2009-06-24 14:42:31 +0200 | [diff] [blame] | 225 | saddr.sin_addr = slirp->vhost_addr; |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 226 | saddr.sin_port = htons(BOOTP_SERVER); |
| 227 | |
| 228 | daddr.sin_port = htons(BOOTP_CLIENT); |
| 229 | |
| 230 | rbp->bp_op = BOOTP_REPLY; |
| 231 | rbp->bp_xid = bp->bp_xid; |
| 232 | rbp->bp_htype = 1; |
| 233 | rbp->bp_hlen = 6; |
Fabien Chouteau | 1a0ca1e | 2011-08-03 12:52:54 +0200 | [diff] [blame] | 234 | memcpy(rbp->bp_hwaddr, bp->bp_hwaddr, ETH_ALEN); |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 235 | |
bellard | e95c8d5 | 2004-09-30 22:22:08 +0000 | [diff] [blame] | 236 | rbp->bp_yiaddr = daddr.sin_addr; /* Client IP address */ |
| 237 | rbp->bp_siaddr = saddr.sin_addr; /* Server IP address */ |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 238 | |
| 239 | q = rbp->bp_vend; |
| 240 | memcpy(q, rfc1533_cookie, 4); |
| 241 | q += 4; |
| 242 | |
aliguori | b63c7f6 | 2009-04-21 19:56:20 +0000 | [diff] [blame] | 243 | if (bc) { |
Stefan Weil | ecc804c | 2015-08-29 09:12:35 +0200 | [diff] [blame] | 244 | DPRINTF("%s addr=%08" PRIx32 "\n", |
aliguori | b63c7f6 | 2009-04-21 19:56:20 +0000 | [diff] [blame] | 245 | (dhcp_msg_type == DHCPDISCOVER) ? "offered" : "ack'ed", |
| 246 | ntohl(daddr.sin_addr.s_addr)); |
ths | 3b46e62 | 2007-09-17 08:09:54 +0000 | [diff] [blame] | 247 | |
aliguori | b63c7f6 | 2009-04-21 19:56:20 +0000 | [diff] [blame] | 248 | if (dhcp_msg_type == DHCPDISCOVER) { |
| 249 | *q++ = RFC2132_MSG_TYPE; |
| 250 | *q++ = 1; |
| 251 | *q++ = DHCPOFFER; |
| 252 | } else /* DHCPREQUEST */ { |
| 253 | *q++ = RFC2132_MSG_TYPE; |
| 254 | *q++ = 1; |
| 255 | *q++ = DHCPACK; |
| 256 | } |
| 257 | |
Jan Kiszka | 460fec6 | 2009-06-24 14:42:31 +0200 | [diff] [blame] | 258 | if (slirp->bootp_filename) |
aliguori | b63c7f6 | 2009-04-21 19:56:20 +0000 | [diff] [blame] | 259 | snprintf((char *)rbp->bp_file, sizeof(rbp->bp_file), "%s", |
Jan Kiszka | 460fec6 | 2009-06-24 14:42:31 +0200 | [diff] [blame] | 260 | slirp->bootp_filename); |
aliguori | b63c7f6 | 2009-04-21 19:56:20 +0000 | [diff] [blame] | 261 | |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 262 | *q++ = RFC2132_SRV_ID; |
| 263 | *q++ = 4; |
| 264 | memcpy(q, &saddr.sin_addr, 4); |
| 265 | q += 4; |
| 266 | |
| 267 | *q++ = RFC1533_NETMASK; |
| 268 | *q++ = 4; |
Jan Kiszka | 460fec6 | 2009-06-24 14:42:31 +0200 | [diff] [blame] | 269 | memcpy(q, &slirp->vnetwork_mask, 4); |
Jan Kiszka | a13a412 | 2009-06-24 14:42:28 +0200 | [diff] [blame] | 270 | q += 4; |
ths | 3b46e62 | 2007-09-17 08:09:54 +0000 | [diff] [blame] | 271 | |
Jan Kiszka | 460fec6 | 2009-06-24 14:42:31 +0200 | [diff] [blame] | 272 | if (!slirp->restricted) { |
aliguori | a9ba3a8 | 2009-01-08 19:24:00 +0000 | [diff] [blame] | 273 | *q++ = RFC1533_GATEWAY; |
| 274 | *q++ = 4; |
| 275 | memcpy(q, &saddr.sin_addr, 4); |
| 276 | q += 4; |
ths | 3b46e62 | 2007-09-17 08:09:54 +0000 | [diff] [blame] | 277 | |
aliguori | a9ba3a8 | 2009-01-08 19:24:00 +0000 | [diff] [blame] | 278 | *q++ = RFC1533_DNS; |
| 279 | *q++ = 4; |
Jan Kiszka | 460fec6 | 2009-06-24 14:42:31 +0200 | [diff] [blame] | 280 | memcpy(q, &slirp->vnameserver_addr, 4); |
aliguori | a9ba3a8 | 2009-01-08 19:24:00 +0000 | [diff] [blame] | 281 | q += 4; |
| 282 | } |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 283 | |
| 284 | *q++ = RFC2132_LEASE_TIME; |
| 285 | *q++ = 4; |
| 286 | val = htonl(LEASE_TIME); |
| 287 | memcpy(q, &val, 4); |
| 288 | q += 4; |
pbrook | 115defd | 2006-04-16 11:06:58 +0000 | [diff] [blame] | 289 | |
Jan Kiszka | 460fec6 | 2009-06-24 14:42:31 +0200 | [diff] [blame] | 290 | if (*slirp->client_hostname) { |
| 291 | val = strlen(slirp->client_hostname); |
pbrook | 115defd | 2006-04-16 11:06:58 +0000 | [diff] [blame] | 292 | *q++ = RFC1533_HOSTNAME; |
| 293 | *q++ = val; |
Jan Kiszka | 460fec6 | 2009-06-24 14:42:31 +0200 | [diff] [blame] | 294 | memcpy(q, slirp->client_hostname, val); |
pbrook | 115defd | 2006-04-16 11:06:58 +0000 | [diff] [blame] | 295 | q += val; |
| 296 | } |
Klaus Stengel | 63d2960 | 2012-10-27 19:53:39 +0200 | [diff] [blame] | 297 | |
| 298 | if (slirp->vdnssearch) { |
| 299 | size_t spaceleft = sizeof(rbp->bp_vend) - (q - rbp->bp_vend); |
| 300 | val = slirp->vdnssearch_len; |
| 301 | if (val + 1 > spaceleft) { |
| 302 | g_warning("DHCP packet size exceeded, " |
| 303 | "omitting domain-search option."); |
| 304 | } else { |
| 305 | memcpy(q, slirp->vdnssearch, val); |
| 306 | q += val; |
| 307 | } |
| 308 | } |
aliguori | b63c7f6 | 2009-04-21 19:56:20 +0000 | [diff] [blame] | 309 | } else { |
| 310 | static const char nak_msg[] = "requested address not available"; |
| 311 | |
Stefan Weil | ecc804c | 2015-08-29 09:12:35 +0200 | [diff] [blame] | 312 | DPRINTF("nak'ed addr=%08" PRIx32 "\n", ntohl(preq_addr.s_addr)); |
aliguori | b63c7f6 | 2009-04-21 19:56:20 +0000 | [diff] [blame] | 313 | |
| 314 | *q++ = RFC2132_MSG_TYPE; |
| 315 | *q++ = 1; |
| 316 | *q++ = DHCPNAK; |
| 317 | |
| 318 | *q++ = RFC2132_MESSAGE; |
| 319 | *q++ = sizeof(nak_msg) - 1; |
| 320 | memcpy(q, nak_msg, sizeof(nak_msg) - 1); |
| 321 | q += sizeof(nak_msg) - 1; |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 322 | } |
Blue Swirl | 369c86e | 2010-03-07 13:45:37 +0000 | [diff] [blame] | 323 | *q = RFC1533_END; |
ths | 3b46e62 | 2007-09-17 08:09:54 +0000 | [diff] [blame] | 324 | |
aliguori | b63c7f6 | 2009-04-21 19:56:20 +0000 | [diff] [blame] | 325 | daddr.sin_addr.s_addr = 0xffffffffu; |
| 326 | |
ths | 5fafdf2 | 2007-09-16 21:08:06 +0000 | [diff] [blame] | 327 | m->m_len = sizeof(struct bootp_t) - |
bellard | 44bbf73 | 2004-06-04 15:30:48 +0000 | [diff] [blame] | 328 | sizeof(struct ip) - sizeof(struct udphdr); |
Guillaume Subiron | 5379229 | 2015-12-19 22:24:59 +0100 | [diff] [blame] | 329 | udp_output(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY); |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 330 | } |
| 331 | |
| 332 | void bootp_input(struct mbuf *m) |
| 333 | { |
bellard | 101c593 | 2005-06-05 17:11:42 +0000 | [diff] [blame] | 334 | struct bootp_t *bp = mtod(m, struct bootp_t *); |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 335 | |
| 336 | if (bp->bp_op == BOOTP_REQUEST) { |
Jan Kiszka | 460fec6 | 2009-06-24 14:42:31 +0200 | [diff] [blame] | 337 | bootp_reply(m->slirp, bp); |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 338 | } |
| 339 | } |