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