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