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" |
Markus Armbruster | a9c9427 | 2016-06-22 19:11:19 +0200 | [diff] [blame] | 25 | #include "slirp.h" |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 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++; |
Prasad J Pandit | 413d463 | 2017-07-17 17:33:26 +0530 | [diff] [blame] | 126 | if (p + len > p_end) { |
| 127 | break; |
| 128 | } |
malc | d0f2c4c | 2010-02-07 02:03:50 +0300 | [diff] [blame] | 129 | DPRINTF("dhcp: tag=%d len=%d\n", tag, len); |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 130 | |
| 131 | switch(tag) { |
| 132 | case RFC2132_MSG_TYPE: |
| 133 | if (len >= 1) |
| 134 | *pmsg_type = p[0]; |
| 135 | break; |
aliguori | b63c7f6 | 2009-04-21 19:56:20 +0000 | [diff] [blame] | 136 | case RFC2132_REQ_ADDR: |
Aurelien Jarno | 8aaf42e | 2011-01-06 22:43:13 +0100 | [diff] [blame] | 137 | if (len >= 4) { |
| 138 | memcpy(&(preq_addr->s_addr), p, 4); |
| 139 | } |
aliguori | b63c7f6 | 2009-04-21 19:56:20 +0000 | [diff] [blame] | 140 | break; |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 141 | default: |
| 142 | break; |
| 143 | } |
| 144 | p += len; |
| 145 | } |
| 146 | } |
Aurelien Jarno | 8aaf42e | 2011-01-06 22:43:13 +0100 | [diff] [blame] | 147 | if (*pmsg_type == DHCPREQUEST && preq_addr->s_addr == htonl(0L) && |
| 148 | bp->bp_ciaddr.s_addr) { |
| 149 | memcpy(&(preq_addr->s_addr), &bp->bp_ciaddr, 4); |
aliguori | b63c7f6 | 2009-04-21 19:56:20 +0000 | [diff] [blame] | 150 | } |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 151 | } |
| 152 | |
Jan Kiszka | 460fec6 | 2009-06-24 14:42:31 +0200 | [diff] [blame] | 153 | static void bootp_reply(Slirp *slirp, const struct bootp_t *bp) |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 154 | { |
aliguori | b63c7f6 | 2009-04-21 19:56:20 +0000 | [diff] [blame] | 155 | BOOTPClient *bc = NULL; |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 156 | struct mbuf *m; |
| 157 | struct bootp_t *rbp; |
| 158 | struct sockaddr_in saddr, daddr; |
Aurelien Jarno | 8aaf42e | 2011-01-06 22:43:13 +0100 | [diff] [blame] | 159 | struct in_addr preq_addr; |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 160 | int dhcp_msg_type, val; |
| 161 | uint8_t *q; |
Fabien Chouteau | 1a0ca1e | 2011-08-03 12:52:54 +0200 | [diff] [blame] | 162 | uint8_t client_ethaddr[ETH_ALEN]; |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 163 | |
| 164 | /* extract exact DHCP msg type */ |
aliguori | b63c7f6 | 2009-04-21 19:56:20 +0000 | [diff] [blame] | 165 | dhcp_decode(bp, &dhcp_msg_type, &preq_addr); |
malc | d0f2c4c | 2010-02-07 02:03:50 +0300 | [diff] [blame] | 166 | 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] | 167 | if (preq_addr.s_addr != htonl(0L)) |
Stefan Weil | ecc804c | 2015-08-29 09:12:35 +0200 | [diff] [blame] | 168 | DPRINTF(" req_addr=%08" PRIx32 "\n", ntohl(preq_addr.s_addr)); |
aliguori | b63c7f6 | 2009-04-21 19:56:20 +0000 | [diff] [blame] | 169 | else |
malc | d0f2c4c | 2010-02-07 02:03:50 +0300 | [diff] [blame] | 170 | DPRINTF("\n"); |
ths | 3b46e62 | 2007-09-17 08:09:54 +0000 | [diff] [blame] | 171 | |
bellard | 487be8a | 2004-10-03 11:44:41 +0000 | [diff] [blame] | 172 | if (dhcp_msg_type == 0) |
| 173 | dhcp_msg_type = DHCPREQUEST; /* Force reply for old BOOTP clients */ |
ths | 3b46e62 | 2007-09-17 08:09:54 +0000 | [diff] [blame] | 174 | |
ths | 5fafdf2 | 2007-09-16 21:08:06 +0000 | [diff] [blame] | 175 | if (dhcp_msg_type != DHCPDISCOVER && |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 176 | dhcp_msg_type != DHCPREQUEST) |
| 177 | return; |
Fabien Chouteau | 1a0ca1e | 2011-08-03 12:52:54 +0200 | [diff] [blame] | 178 | |
| 179 | /* Get client's hardware address from bootp request */ |
| 180 | memcpy(client_ethaddr, bp->bp_hwaddr, ETH_ALEN); |
ths | 3b46e62 | 2007-09-17 08:09:54 +0000 | [diff] [blame] | 181 | |
Jan Kiszka | 460fec6 | 2009-06-24 14:42:31 +0200 | [diff] [blame] | 182 | m = m_get(slirp); |
| 183 | if (!m) { |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 184 | return; |
Jan Kiszka | 460fec6 | 2009-06-24 14:42:31 +0200 | [diff] [blame] | 185 | } |
blueswir1 | 9634d90 | 2007-10-26 19:01:16 +0000 | [diff] [blame] | 186 | m->m_data += IF_MAXLINKHDR; |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 187 | rbp = (struct bootp_t *)m->m_data; |
| 188 | m->m_data += sizeof(struct udpiphdr); |
| 189 | memset(rbp, 0, sizeof(struct bootp_t)); |
| 190 | |
bellard | 512176d | 2004-05-04 03:14:47 +0000 | [diff] [blame] | 191 | if (dhcp_msg_type == DHCPDISCOVER) { |
Aurelien Jarno | 8aaf42e | 2011-01-06 22:43:13 +0100 | [diff] [blame] | 192 | if (preq_addr.s_addr != htonl(0L)) { |
Fabien Chouteau | 1a0ca1e | 2011-08-03 12:52:54 +0200 | [diff] [blame] | 193 | bc = request_addr(slirp, &preq_addr, client_ethaddr); |
aliguori | b63c7f6 | 2009-04-21 19:56:20 +0000 | [diff] [blame] | 194 | if (bc) { |
Aurelien Jarno | 8aaf42e | 2011-01-06 22:43:13 +0100 | [diff] [blame] | 195 | daddr.sin_addr = preq_addr; |
aliguori | b63c7f6 | 2009-04-21 19:56:20 +0000 | [diff] [blame] | 196 | } |
| 197 | } |
bellard | 512176d | 2004-05-04 03:14:47 +0000 | [diff] [blame] | 198 | if (!bc) { |
aliguori | b63c7f6 | 2009-04-21 19:56:20 +0000 | [diff] [blame] | 199 | new_addr: |
Fabien Chouteau | 1a0ca1e | 2011-08-03 12:52:54 +0200 | [diff] [blame] | 200 | bc = get_new_addr(slirp, &daddr.sin_addr, client_ethaddr); |
aliguori | b63c7f6 | 2009-04-21 19:56:20 +0000 | [diff] [blame] | 201 | if (!bc) { |
malc | d0f2c4c | 2010-02-07 02:03:50 +0300 | [diff] [blame] | 202 | DPRINTF("no address left\n"); |
aliguori | b63c7f6 | 2009-04-21 19:56:20 +0000 | [diff] [blame] | 203 | return; |
| 204 | } |
bellard | 512176d | 2004-05-04 03:14:47 +0000 | [diff] [blame] | 205 | } |
Fabien Chouteau | 1a0ca1e | 2011-08-03 12:52:54 +0200 | [diff] [blame] | 206 | memcpy(bc->macaddr, client_ethaddr, ETH_ALEN); |
Aurelien Jarno | 8aaf42e | 2011-01-06 22:43:13 +0100 | [diff] [blame] | 207 | } else if (preq_addr.s_addr != htonl(0L)) { |
Fabien Chouteau | 1a0ca1e | 2011-08-03 12:52:54 +0200 | [diff] [blame] | 208 | bc = request_addr(slirp, &preq_addr, client_ethaddr); |
aliguori | b63c7f6 | 2009-04-21 19:56:20 +0000 | [diff] [blame] | 209 | if (bc) { |
Aurelien Jarno | 8aaf42e | 2011-01-06 22:43:13 +0100 | [diff] [blame] | 210 | daddr.sin_addr = preq_addr; |
Fabien Chouteau | 1a0ca1e | 2011-08-03 12:52:54 +0200 | [diff] [blame] | 211 | memcpy(bc->macaddr, client_ethaddr, ETH_ALEN); |
aliguori | b63c7f6 | 2009-04-21 19:56:20 +0000 | [diff] [blame] | 212 | } else { |
David Gibson | 90d7416 | 2012-02-24 01:23:28 +0100 | [diff] [blame] | 213 | /* DHCPNAKs should be sent to broadcast */ |
| 214 | daddr.sin_addr.s_addr = 0xffffffff; |
aliguori | b63c7f6 | 2009-04-21 19:56:20 +0000 | [diff] [blame] | 215 | } |
bellard | 512176d | 2004-05-04 03:14:47 +0000 | [diff] [blame] | 216 | } else { |
Jan Kiszka | 460fec6 | 2009-06-24 14:42:31 +0200 | [diff] [blame] | 217 | bc = find_addr(slirp, &daddr.sin_addr, bp->bp_hwaddr); |
bellard | 512176d | 2004-05-04 03:14:47 +0000 | [diff] [blame] | 218 | if (!bc) { |
bellard | d981b88 | 2004-09-30 18:57:28 +0000 | [diff] [blame] | 219 | /* if never assigned, behaves as if it was already |
| 220 | assigned (windows fix because it remembers its address) */ |
| 221 | goto new_addr; |
bellard | 512176d | 2004-05-04 03:14:47 +0000 | [diff] [blame] | 222 | } |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 223 | } |
ths | 47d5d01 | 2007-02-20 00:05:08 +0000 | [diff] [blame] | 224 | |
Fabien Chouteau | 1a0ca1e | 2011-08-03 12:52:54 +0200 | [diff] [blame] | 225 | /* Update ARP table for this IP address */ |
| 226 | arp_table_add(slirp, daddr.sin_addr.s_addr, client_ethaddr); |
| 227 | |
Jan Kiszka | 460fec6 | 2009-06-24 14:42:31 +0200 | [diff] [blame] | 228 | saddr.sin_addr = slirp->vhost_addr; |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 229 | saddr.sin_port = htons(BOOTP_SERVER); |
| 230 | |
| 231 | daddr.sin_port = htons(BOOTP_CLIENT); |
| 232 | |
| 233 | rbp->bp_op = BOOTP_REPLY; |
| 234 | rbp->bp_xid = bp->bp_xid; |
| 235 | rbp->bp_htype = 1; |
| 236 | rbp->bp_hlen = 6; |
Fabien Chouteau | 1a0ca1e | 2011-08-03 12:52:54 +0200 | [diff] [blame] | 237 | memcpy(rbp->bp_hwaddr, bp->bp_hwaddr, ETH_ALEN); |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 238 | |
bellard | e95c8d5 | 2004-09-30 22:22:08 +0000 | [diff] [blame] | 239 | rbp->bp_yiaddr = daddr.sin_addr; /* Client IP address */ |
| 240 | rbp->bp_siaddr = saddr.sin_addr; /* Server IP address */ |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 241 | |
| 242 | q = rbp->bp_vend; |
| 243 | memcpy(q, rfc1533_cookie, 4); |
| 244 | q += 4; |
| 245 | |
aliguori | b63c7f6 | 2009-04-21 19:56:20 +0000 | [diff] [blame] | 246 | if (bc) { |
Stefan Weil | ecc804c | 2015-08-29 09:12:35 +0200 | [diff] [blame] | 247 | DPRINTF("%s addr=%08" PRIx32 "\n", |
aliguori | b63c7f6 | 2009-04-21 19:56:20 +0000 | [diff] [blame] | 248 | (dhcp_msg_type == DHCPDISCOVER) ? "offered" : "ack'ed", |
| 249 | ntohl(daddr.sin_addr.s_addr)); |
ths | 3b46e62 | 2007-09-17 08:09:54 +0000 | [diff] [blame] | 250 | |
aliguori | b63c7f6 | 2009-04-21 19:56:20 +0000 | [diff] [blame] | 251 | if (dhcp_msg_type == DHCPDISCOVER) { |
| 252 | *q++ = RFC2132_MSG_TYPE; |
| 253 | *q++ = 1; |
| 254 | *q++ = DHCPOFFER; |
| 255 | } else /* DHCPREQUEST */ { |
| 256 | *q++ = RFC2132_MSG_TYPE; |
| 257 | *q++ = 1; |
| 258 | *q++ = DHCPACK; |
| 259 | } |
| 260 | |
Jan Kiszka | 460fec6 | 2009-06-24 14:42:31 +0200 | [diff] [blame] | 261 | if (slirp->bootp_filename) |
aliguori | b63c7f6 | 2009-04-21 19:56:20 +0000 | [diff] [blame] | 262 | snprintf((char *)rbp->bp_file, sizeof(rbp->bp_file), "%s", |
Jan Kiszka | 460fec6 | 2009-06-24 14:42:31 +0200 | [diff] [blame] | 263 | slirp->bootp_filename); |
aliguori | b63c7f6 | 2009-04-21 19:56:20 +0000 | [diff] [blame] | 264 | |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 265 | *q++ = RFC2132_SRV_ID; |
| 266 | *q++ = 4; |
| 267 | memcpy(q, &saddr.sin_addr, 4); |
| 268 | q += 4; |
| 269 | |
| 270 | *q++ = RFC1533_NETMASK; |
| 271 | *q++ = 4; |
Jan Kiszka | 460fec6 | 2009-06-24 14:42:31 +0200 | [diff] [blame] | 272 | memcpy(q, &slirp->vnetwork_mask, 4); |
Jan Kiszka | a13a412 | 2009-06-24 14:42:28 +0200 | [diff] [blame] | 273 | q += 4; |
ths | 3b46e62 | 2007-09-17 08:09:54 +0000 | [diff] [blame] | 274 | |
Jan Kiszka | 460fec6 | 2009-06-24 14:42:31 +0200 | [diff] [blame] | 275 | if (!slirp->restricted) { |
aliguori | a9ba3a8 | 2009-01-08 19:24:00 +0000 | [diff] [blame] | 276 | *q++ = RFC1533_GATEWAY; |
| 277 | *q++ = 4; |
| 278 | memcpy(q, &saddr.sin_addr, 4); |
| 279 | q += 4; |
ths | 3b46e62 | 2007-09-17 08:09:54 +0000 | [diff] [blame] | 280 | |
aliguori | a9ba3a8 | 2009-01-08 19:24:00 +0000 | [diff] [blame] | 281 | *q++ = RFC1533_DNS; |
| 282 | *q++ = 4; |
Jan Kiszka | 460fec6 | 2009-06-24 14:42:31 +0200 | [diff] [blame] | 283 | memcpy(q, &slirp->vnameserver_addr, 4); |
aliguori | a9ba3a8 | 2009-01-08 19:24:00 +0000 | [diff] [blame] | 284 | q += 4; |
| 285 | } |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 286 | |
| 287 | *q++ = RFC2132_LEASE_TIME; |
| 288 | *q++ = 4; |
| 289 | val = htonl(LEASE_TIME); |
| 290 | memcpy(q, &val, 4); |
| 291 | q += 4; |
pbrook | 115defd | 2006-04-16 11:06:58 +0000 | [diff] [blame] | 292 | |
Jan Kiszka | 460fec6 | 2009-06-24 14:42:31 +0200 | [diff] [blame] | 293 | if (*slirp->client_hostname) { |
| 294 | val = strlen(slirp->client_hostname); |
pbrook | 115defd | 2006-04-16 11:06:58 +0000 | [diff] [blame] | 295 | *q++ = RFC1533_HOSTNAME; |
| 296 | *q++ = val; |
Jan Kiszka | 460fec6 | 2009-06-24 14:42:31 +0200 | [diff] [blame] | 297 | memcpy(q, slirp->client_hostname, val); |
pbrook | 115defd | 2006-04-16 11:06:58 +0000 | [diff] [blame] | 298 | q += val; |
| 299 | } |
Klaus Stengel | 63d2960 | 2012-10-27 19:53:39 +0200 | [diff] [blame] | 300 | |
| 301 | if (slirp->vdnssearch) { |
| 302 | size_t spaceleft = sizeof(rbp->bp_vend) - (q - rbp->bp_vend); |
| 303 | val = slirp->vdnssearch_len; |
| 304 | if (val + 1 > spaceleft) { |
| 305 | g_warning("DHCP packet size exceeded, " |
| 306 | "omitting domain-search option."); |
| 307 | } else { |
| 308 | memcpy(q, slirp->vdnssearch, val); |
| 309 | q += val; |
| 310 | } |
| 311 | } |
aliguori | b63c7f6 | 2009-04-21 19:56:20 +0000 | [diff] [blame] | 312 | } else { |
| 313 | static const char nak_msg[] = "requested address not available"; |
| 314 | |
Stefan Weil | ecc804c | 2015-08-29 09:12:35 +0200 | [diff] [blame] | 315 | DPRINTF("nak'ed addr=%08" PRIx32 "\n", ntohl(preq_addr.s_addr)); |
aliguori | b63c7f6 | 2009-04-21 19:56:20 +0000 | [diff] [blame] | 316 | |
| 317 | *q++ = RFC2132_MSG_TYPE; |
| 318 | *q++ = 1; |
| 319 | *q++ = DHCPNAK; |
| 320 | |
| 321 | *q++ = RFC2132_MESSAGE; |
| 322 | *q++ = sizeof(nak_msg) - 1; |
| 323 | memcpy(q, nak_msg, sizeof(nak_msg) - 1); |
| 324 | q += sizeof(nak_msg) - 1; |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 325 | } |
Blue Swirl | 369c86e | 2010-03-07 13:45:37 +0000 | [diff] [blame] | 326 | *q = RFC1533_END; |
ths | 3b46e62 | 2007-09-17 08:09:54 +0000 | [diff] [blame] | 327 | |
aliguori | b63c7f6 | 2009-04-21 19:56:20 +0000 | [diff] [blame] | 328 | daddr.sin_addr.s_addr = 0xffffffffu; |
| 329 | |
ths | 5fafdf2 | 2007-09-16 21:08:06 +0000 | [diff] [blame] | 330 | m->m_len = sizeof(struct bootp_t) - |
bellard | 44bbf73 | 2004-06-04 15:30:48 +0000 | [diff] [blame] | 331 | sizeof(struct ip) - sizeof(struct udphdr); |
Guillaume Subiron | 5379229 | 2015-12-19 22:24:59 +0100 | [diff] [blame] | 332 | udp_output(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY); |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 333 | } |
| 334 | |
| 335 | void bootp_input(struct mbuf *m) |
| 336 | { |
bellard | 101c593 | 2005-06-05 17:11:42 +0000 | [diff] [blame] | 337 | struct bootp_t *bp = mtod(m, struct bootp_t *); |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 338 | |
| 339 | if (bp->bp_op == BOOTP_REQUEST) { |
Jan Kiszka | 460fec6 | 2009-06-24 14:42:31 +0200 | [diff] [blame] | 340 | bootp_reply(m->slirp, bp); |
bellard | f0cbd3e | 2004-04-22 00:10:48 +0000 | [diff] [blame] | 341 | } |
| 342 | } |