Revision b63c7f6b slirp/bootp.c
b/slirp/bootp.c | ||
---|---|---|
66 | 66 |
return bc; |
67 | 67 |
} |
68 | 68 |
|
69 |
static BOOTPClient *request_addr(const struct in_addr *paddr, |
|
70 |
const uint8_t *macaddr) |
|
71 |
{ |
|
72 |
uint32_t req_addr = ntohl(paddr->s_addr); |
|
73 |
uint32_t spec_addr = ntohl(special_addr.s_addr); |
|
74 |
BOOTPClient *bc; |
|
75 |
|
|
76 |
if (req_addr >= (spec_addr | START_ADDR) && |
|
77 |
req_addr < (spec_addr | (NB_ADDR + START_ADDR))) { |
|
78 |
bc = &bootp_clients[(req_addr & 0xff) - START_ADDR]; |
|
79 |
if (!bc->allocated || !memcmp(macaddr, bc->macaddr, 6)) { |
|
80 |
bc->allocated = 1; |
|
81 |
return bc; |
|
82 |
} |
|
83 |
} |
|
84 |
return NULL; |
|
85 |
} |
|
86 |
|
|
69 | 87 |
static BOOTPClient *find_addr(struct in_addr *paddr, const uint8_t *macaddr) |
70 | 88 |
{ |
71 | 89 |
BOOTPClient *bc; |
... | ... | |
83 | 101 |
return bc; |
84 | 102 |
} |
85 | 103 |
|
86 |
static void dhcp_decode(const uint8_t *buf, int size,
|
|
87 |
int *pmsg_type)
|
|
104 |
static void dhcp_decode(const struct bootp_t *bp, int *pmsg_type,
|
|
105 |
const struct in_addr **preq_addr)
|
|
88 | 106 |
{ |
89 | 107 |
const uint8_t *p, *p_end; |
90 | 108 |
int len, tag; |
91 | 109 |
|
92 | 110 |
*pmsg_type = 0; |
111 |
*preq_addr = NULL; |
|
93 | 112 |
|
94 |
p = buf; |
|
95 |
p_end = buf + size; |
|
96 |
if (size < 5) |
|
97 |
return; |
|
113 |
p = bp->bp_vend; |
|
114 |
p_end = p + DHCP_OPT_LEN; |
|
98 | 115 |
if (memcmp(p, rfc1533_cookie, 4) != 0) |
99 | 116 |
return; |
100 | 117 |
p += 4; |
... | ... | |
109 | 126 |
if (p >= p_end) |
110 | 127 |
break; |
111 | 128 |
len = *p++; |
112 |
dprintf("dhcp: tag=0x%02x len=%d\n", tag, len);
|
|
129 |
dprintf("dhcp: tag=%d len=%d\n", tag, len);
|
|
113 | 130 |
|
114 | 131 |
switch(tag) { |
115 | 132 |
case RFC2132_MSG_TYPE: |
116 | 133 |
if (len >= 1) |
117 | 134 |
*pmsg_type = p[0]; |
118 | 135 |
break; |
136 |
case RFC2132_REQ_ADDR: |
|
137 |
if (len >= 4) |
|
138 |
*preq_addr = (struct in_addr *)p; |
|
139 |
break; |
|
119 | 140 |
default: |
120 | 141 |
break; |
121 | 142 |
} |
122 | 143 |
p += len; |
123 | 144 |
} |
124 | 145 |
} |
146 |
if (*pmsg_type == DHCPREQUEST && !*preq_addr && bp->bp_ciaddr.s_addr) { |
|
147 |
*preq_addr = &bp->bp_ciaddr; |
|
148 |
} |
|
125 | 149 |
} |
126 | 150 |
|
127 |
static void bootp_reply(struct bootp_t *bp) |
|
151 |
static void bootp_reply(const struct bootp_t *bp)
|
|
128 | 152 |
{ |
129 |
BOOTPClient *bc; |
|
153 |
BOOTPClient *bc = NULL;
|
|
130 | 154 |
struct mbuf *m; |
131 | 155 |
struct bootp_t *rbp; |
132 | 156 |
struct sockaddr_in saddr, daddr; |
133 | 157 |
struct in_addr dns_addr; |
158 |
const struct in_addr *preq_addr; |
|
134 | 159 |
int dhcp_msg_type, val; |
135 | 160 |
uint8_t *q; |
136 | 161 |
|
137 | 162 |
/* extract exact DHCP msg type */ |
138 |
dhcp_decode(bp->bp_vend, DHCP_OPT_LEN, &dhcp_msg_type); |
|
139 |
dprintf("bootp packet op=%d msgtype=%d\n", bp->bp_op, dhcp_msg_type); |
|
163 |
dhcp_decode(bp, &dhcp_msg_type, &preq_addr); |
|
164 |
dprintf("bootp packet op=%d msgtype=%d", bp->bp_op, dhcp_msg_type); |
|
165 |
if (preq_addr) |
|
166 |
dprintf(" req_addr=%08x\n", ntohl(preq_addr->s_addr)); |
|
167 |
else |
|
168 |
dprintf("\n"); |
|
140 | 169 |
|
141 | 170 |
if (dhcp_msg_type == 0) |
142 | 171 |
dhcp_msg_type = DHCPREQUEST; /* Force reply for old BOOTP clients */ |
... | ... | |
155 | 184 |
memset(rbp, 0, sizeof(struct bootp_t)); |
156 | 185 |
|
157 | 186 |
if (dhcp_msg_type == DHCPDISCOVER) { |
158 |
new_addr: |
|
159 |
bc = get_new_addr(&daddr.sin_addr); |
|
187 |
if (preq_addr) { |
|
188 |
bc = request_addr(preq_addr, client_ethaddr); |
|
189 |
if (bc) { |
|
190 |
daddr.sin_addr = *preq_addr; |
|
191 |
} |
|
192 |
} |
|
160 | 193 |
if (!bc) { |
161 |
dprintf("no address left\n"); |
|
162 |
return; |
|
194 |
new_addr: |
|
195 |
bc = get_new_addr(&daddr.sin_addr); |
|
196 |
if (!bc) { |
|
197 |
dprintf("no address left\n"); |
|
198 |
return; |
|
199 |
} |
|
163 | 200 |
} |
164 | 201 |
memcpy(bc->macaddr, client_ethaddr, 6); |
202 |
} else if (preq_addr) { |
|
203 |
bc = request_addr(preq_addr, client_ethaddr); |
|
204 |
if (bc) { |
|
205 |
daddr.sin_addr = *preq_addr; |
|
206 |
memcpy(bc->macaddr, client_ethaddr, 6); |
|
207 |
} else { |
|
208 |
daddr.sin_addr.s_addr = 0; |
|
209 |
} |
|
165 | 210 |
} else { |
166 | 211 |
bc = find_addr(&daddr.sin_addr, bp->bp_hwaddr); |
167 | 212 |
if (!bc) { |
... | ... | |
171 | 216 |
} |
172 | 217 |
} |
173 | 218 |
|
174 |
if (bootp_filename) |
|
175 |
snprintf((char *)rbp->bp_file, sizeof(rbp->bp_file), "%s", |
|
176 |
bootp_filename); |
|
177 |
|
|
178 |
dprintf("offered addr=%08x\n", ntohl(daddr.sin_addr.s_addr)); |
|
179 |
|
|
180 | 219 |
saddr.sin_addr.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_ALIAS); |
181 | 220 |
saddr.sin_port = htons(BOOTP_SERVER); |
182 | 221 |
|
... | ... | |
191 | 230 |
rbp->bp_yiaddr = daddr.sin_addr; /* Client IP address */ |
192 | 231 |
rbp->bp_siaddr = saddr.sin_addr; /* Server IP address */ |
193 | 232 |
|
194 |
daddr.sin_addr.s_addr = 0xffffffffu; |
|
195 |
|
|
196 | 233 |
q = rbp->bp_vend; |
197 | 234 |
memcpy(q, rfc1533_cookie, 4); |
198 | 235 |
q += 4; |
199 | 236 |
|
200 |
if (dhcp_msg_type == DHCPDISCOVER) { |
|
201 |
*q++ = RFC2132_MSG_TYPE; |
|
202 |
*q++ = 1; |
|
203 |
*q++ = DHCPOFFER; |
|
204 |
} else if (dhcp_msg_type == DHCPREQUEST) { |
|
205 |
*q++ = RFC2132_MSG_TYPE; |
|
206 |
*q++ = 1; |
|
207 |
*q++ = DHCPACK; |
|
208 |
} |
|
237 |
if (bc) { |
|
238 |
dprintf("%s addr=%08x\n", |
|
239 |
(dhcp_msg_type == DHCPDISCOVER) ? "offered" : "ack'ed", |
|
240 |
ntohl(daddr.sin_addr.s_addr)); |
|
241 |
|
|
242 |
if (dhcp_msg_type == DHCPDISCOVER) { |
|
243 |
*q++ = RFC2132_MSG_TYPE; |
|
244 |
*q++ = 1; |
|
245 |
*q++ = DHCPOFFER; |
|
246 |
} else /* DHCPREQUEST */ { |
|
247 |
*q++ = RFC2132_MSG_TYPE; |
|
248 |
*q++ = 1; |
|
249 |
*q++ = DHCPACK; |
|
250 |
} |
|
251 |
|
|
252 |
if (bootp_filename) |
|
253 |
snprintf((char *)rbp->bp_file, sizeof(rbp->bp_file), "%s", |
|
254 |
bootp_filename); |
|
209 | 255 |
|
210 |
if (dhcp_msg_type == DHCPDISCOVER || |
|
211 |
dhcp_msg_type == DHCPREQUEST) { |
|
212 | 256 |
*q++ = RFC2132_SRV_ID; |
213 | 257 |
*q++ = 4; |
214 | 258 |
memcpy(q, &saddr.sin_addr, 4); |
... | ... | |
247 | 291 |
memcpy(q, slirp_hostname, val); |
248 | 292 |
q += val; |
249 | 293 |
} |
294 |
} else { |
|
295 |
static const char nak_msg[] = "requested address not available"; |
|
296 |
|
|
297 |
dprintf("nak'ed addr=%08x\n", ntohl(preq_addr->s_addr)); |
|
298 |
|
|
299 |
*q++ = RFC2132_MSG_TYPE; |
|
300 |
*q++ = 1; |
|
301 |
*q++ = DHCPNAK; |
|
302 |
|
|
303 |
*q++ = RFC2132_MESSAGE; |
|
304 |
*q++ = sizeof(nak_msg) - 1; |
|
305 |
memcpy(q, nak_msg, sizeof(nak_msg) - 1); |
|
306 |
q += sizeof(nak_msg) - 1; |
|
250 | 307 |
} |
251 | 308 |
*q++ = RFC1533_END; |
252 | 309 |
|
310 |
daddr.sin_addr.s_addr = 0xffffffffu; |
|
311 |
|
|
253 | 312 |
m->m_len = sizeof(struct bootp_t) - |
254 | 313 |
sizeof(struct ip) - sizeof(struct udphdr); |
255 | 314 |
udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY); |
Also available in: Unified diff