]> git.ipfire.org Git - people/ms/dnsmasq.git/blame - src/rfc2131.c
import of dnsmasq-2.24.tar.gz
[people/ms/dnsmasq.git] / src / rfc2131.c
CommitLineData
f6b7dc47 1/* dnsmasq is Copyright (c) 2000-2005 Simon Kelley
9e4abcb5
SK
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; version 2 dated June, 1991.
6
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
11*/
12
13/* Author's email: simon@thekelleys.org.uk */
14
15#include "dnsmasq.h"
16
17#define BOOTREQUEST 1
18#define BOOTREPLY 2
19#define DHCP_COOKIE 0x63825363
20
a222641c
SK
21/* The Linux in-kernel DHCP client silently ignores any packet
22 smaller than this. Sigh........... */
23#define MIN_PACKETSZ 300
24
9e4abcb5
SK
25#define OPTION_PAD 0
26#define OPTION_NETMASK 1
27#define OPTION_ROUTER 3
28#define OPTION_DNSSERVER 6
29#define OPTION_HOSTNAME 12
30#define OPTION_DOMAINNAME 15
31#define OPTION_BROADCAST 28
91dccd09 32#define OPTION_VENDOR_CLASS_OPT 43
9e4abcb5
SK
33#define OPTION_REQUESTED_IP 50
34#define OPTION_LEASE_TIME 51
35#define OPTION_OVERLOAD 52
36#define OPTION_MESSAGE_TYPE 53
37#define OPTION_SERVER_IDENTIFIER 54
38#define OPTION_REQUESTED_OPTIONS 55
44a2a316 39#define OPTION_MESSAGE 56
9e4abcb5 40#define OPTION_MAXMESSAGE 57
44a2a316
SK
41#define OPTION_T1 58
42#define OPTION_T2 59
a84fa1d0 43#define OPTION_VENDOR_ID 60
44a2a316 44#define OPTION_CLIENT_ID 61
a222641c 45#define OPTION_USER_CLASS 77
3d8df260 46#define OPTION_CLIENT_FQDN 81
3be34541 47#define OPTION_SUBNET_SELECT 118
9e4abcb5
SK
48#define OPTION_END 255
49
50#define DHCPDISCOVER 1
51#define DHCPOFFER 2
52#define DHCPREQUEST 3
53#define DHCPDECLINE 4
54#define DHCPACK 5
55#define DHCPNAK 6
56#define DHCPRELEASE 7
57#define DHCPINFORM 8
58
0a852541
SK
59#define have_config(config, mask) ((config) && ((config)->flags & (mask)))
60
9e4abcb5 61static unsigned char *option_put(unsigned char *p, unsigned char *end, int opt, int len, unsigned int val);
a222641c 62static unsigned char *option_end(unsigned char *p, unsigned char *end, struct dhcp_packet *start);
44a2a316 63static unsigned char *option_put_string(unsigned char *p, unsigned char *end, int opt, char *string);
26128d27
SK
64static void bootp_option_put(struct dhcp_packet *mess,
65 struct dhcp_boot *boot_opts, struct dhcp_netid *netids);
f6b7dc47 66static int option_len(unsigned char *opt);
9e4abcb5
SK
67static void *option_ptr(unsigned char *opt);
68static struct in_addr option_addr(unsigned char *opt);
44a2a316
SK
69static unsigned int option_uint(unsigned char *opt, int size);
70static void log_packet(char *type, struct in_addr *addr, unsigned char *hwaddr, char *interface, char *string);
f6b7dc47 71static unsigned char *option_find(struct dhcp_packet *mess, int size, int opt_type, int minsize);
9e4abcb5
SK
72static unsigned char *do_req_options(struct dhcp_context *context,
73 unsigned char *p, unsigned char *end,
74 unsigned char *req_options,
3be34541
SK
75 struct daemon *daemon,
76 char *hostname,
3be34541 77 struct dhcp_netid *netid,
3d8df260
SK
78 struct in_addr subnet_addr,
79 unsigned char fqdn_flags);
9e4abcb5 80
b8187c80
SK
81int dhcp_reply(struct daemon *daemon, struct dhcp_context *context, char *iface_name,
82 unsigned int sz, time_t now, int unicast_dest)
9e4abcb5 83{
26128d27 84 unsigned char *opt, *clid = NULL;
0a852541 85 struct dhcp_lease *ltmp, *lease = NULL;
a222641c 86 struct dhcp_vendor *vendor;
26128d27
SK
87 struct dhcp_netid_list *id_list;
88 int clid_len = 0, ignore = 0;
3be34541
SK
89 struct dhcp_packet *mess = &daemon->dhcp_packet->data;
90 unsigned char *p = mess->options + sizeof(u32); /* skip cookie */
91 unsigned char *end = (unsigned char *)(daemon->dhcp_packet + 1);
3d8df260 92 char *hostname = NULL, *offer_hostname = NULL, *client_hostname = NULL;
b8187c80 93 int hostname_auth = 0;
3d8df260 94 unsigned char *req_options = NULL;
44a2a316 95 char *message = NULL;
59353a6b 96 unsigned int time;
9e4abcb5 97 struct dhcp_config *config;
a222641c 98 struct dhcp_netid *netid = NULL;
3d8df260 99 struct in_addr subnet_addr;
a84fa1d0 100 unsigned short fuzz = 0;
3be34541 101 unsigned int mess_type = 0;
3d8df260
SK
102 u8 *chaddr;
103 unsigned char fqdn_flags = 0;
3be34541
SK
104 subnet_addr.s_addr = 0;
105
106 if (mess->op != BOOTREQUEST)
33820b7e 107 return 0;
9e4abcb5 108
3be34541 109 /* check for DHCP rather than BOOTP */
bb01cb96 110 if ((opt = option_find(mess, sz, OPTION_MESSAGE_TYPE, 1)))
3be34541
SK
111 {
112 mess_type = option_uint(opt, 1);
feba5c1d 113
3be34541
SK
114 /* only insist on a cookie for DHCP. */
115 if (*((u32 *)&mess->options) != htonl(DHCP_COOKIE))
116 return 0;
9e4abcb5 117
3be34541
SK
118 /* Some buggy clients set ciaddr when they shouldn't, so clear that here since
119 it can affect the context-determination code. */
bb01cb96 120 if ((option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ) || mess_type == DHCPDISCOVER))
3be34541 121 mess->ciaddr.s_addr = 0;
44a2a316 122
3be34541 123 /* Check for RFC3011 subnet selector */
bb01cb96 124 if ((opt = option_find(mess, sz, OPTION_SUBNET_SELECT, INADDRSZ)))
3be34541 125 subnet_addr = option_addr(opt);
26128d27
SK
126
127 /* If there is no client identifier option, use the hardware address */
bb01cb96 128 if ((opt = option_find(mess, sz, OPTION_CLIENT_ID, 1)))
26128d27 129 {
26128d27 130 clid_len = option_len(opt);
bb01cb96 131 clid = option_ptr(opt);
26128d27 132 }
0a852541
SK
133
134 /* do we have a lease in store? */
3d8df260
SK
135 if (mess->htype != 0)
136 lease = lease_find_by_client(mess->chaddr, clid, clid_len);
0a852541
SK
137
138 /* If this request is missing a clid, but we've seen one before,
139 use it again for option matching etc. */
140 if (lease && !clid && lease->clid)
141 {
142 clid_len = lease->clid_len;
143 clid = lease->clid;
144 }
44a2a316 145 }
3be34541 146
3d8df260
SK
147 /* htype == 0 is only allowed in DHCPINFORM, this seems to be a
148 microsoftism. chaddr == NULL in that case */
149
150 if (mess->htype == 0 && mess_type == DHCPINFORM)
151 {
152 chaddr = NULL;
153 if (mess->hlen != 0)
154 return 0;
155 }
156 else
157 {
158 chaddr = mess->chaddr;
159
160 /* Token ring is supported when we have packet sockets
161 to make the HW headers for us. We don't have the code to build
162 token ring headers when using BPF. We rely on the fact that
163 token ring hwaddrs are the same size as ethernet hwaddrs. */
164
165#ifdef HAVE_BPF
166 if (mess->htype != ARPHRD_ETHER)
167#else
168 if (mess->htype != ARPHRD_ETHER && mess->htype != ARPHRD_IEEE802)
169#endif
170 {
b8187c80 171 syslog(LOG_WARNING, _("DHCP request for unsupported hardware type (%d) recieved on %s"),
3d8df260
SK
172 mess->htype, iface_name);
173 return 0;
174 }
175
176 if (mess->hlen != ETHER_ADDR_LEN)
177 return 0;
178 }
179
0a852541
SK
180 /* Determine network for this packet. Our caller will have already linked all the
181 contexts which match the addresses of the receiving interface but if the
182 machine has an address already, or came via a relay, or we have a subnet selector,
183 we search again. If we don't have have a giaddr or explicit subnet selector,
184 use the ciaddr. This is necessary because a machine which got a lease via a
3d8df260
SK
185 relay won't use the relay to renew. If matching a ciaddr fails but we have a context
186 from the physical network, continue using that to allow correct DHCPNAK generation later. */
0a852541
SK
187 if (mess->giaddr.s_addr || subnet_addr.s_addr || mess->ciaddr.s_addr)
188 {
3d8df260
SK
189 struct dhcp_context *context_tmp, *context_new = NULL;
190 struct in_addr addr = mess->ciaddr;
191 int force = 0;
192
193 if (subnet_addr.s_addr)
194 {
195 addr = subnet_addr;
196 force = 1;
197 }
198 else if (mess->giaddr.s_addr)
199 {
200 addr = mess->giaddr;
201 force = 1;
202 }
0a852541 203
3d8df260 204 for (context_tmp = daemon->dhcp; context_tmp; context_tmp = context_tmp->next)
0a852541
SK
205 if (context_tmp->netmask.s_addr &&
206 is_same_net(addr, context_tmp->start, context_tmp->netmask) &&
207 is_same_net(addr, context_tmp->end, context_tmp->netmask))
208 {
3d8df260
SK
209 context_tmp->current = context_new;
210 context_new = context_tmp;
0a852541 211 }
3d8df260
SK
212
213 if (context_new || force)
214 context = context_new;
215
0a852541 216 }
3be34541
SK
217
218 if (!context)
219 {
b8187c80
SK
220 syslog(LOG_WARNING, _("no address range available for DHCP request %s %s"),
221 subnet_addr.s_addr ? _("with subnet selector") : _("via"),
0a852541 222 subnet_addr.s_addr ? inet_ntoa(subnet_addr) : (mess->giaddr.s_addr ? inet_ntoa(mess->giaddr) : iface_name));
3be34541
SK
223 return 0;
224 }
225
226 mess->op = BOOTREPLY;
36717eee 227
3d8df260 228 config = find_config(daemon->dhcp_conf, context, clid, clid_len, chaddr, NULL);
26128d27 229
3be34541
SK
230 if (mess_type == 0)
231 {
232 /* BOOTP request */
26128d27
SK
233 struct dhcp_netid id;
234 char save = mess->file[128];
235 struct in_addr *logaddr = NULL;
236
26128d27 237 if (have_config(config, CONFIG_DISABLE))
b8187c80 238 message = _("disabled");
26128d27
SK
239
240 end = mess->options + 64; /* BOOTP vend area is only 64 bytes */
241
242 if (have_config(config, CONFIG_NAME))
243 hostname = config->hostname;
244
245 if (have_config(config, CONFIG_NETID))
246 {
247 config->netid.next = netid;
248 netid = &config->netid;
249 }
250
251 /* Match incoming filename field as a netid. */
252 if (mess->file[0])
253 {
254 mess->file[128] = 0; /* ensure zero term. */
3d8df260 255 id.net = (char *)mess->file;
26128d27
SK
256 id.next = netid;
257 netid = &id;
258 }
259
260 for (id_list = daemon->dhcp_ignore; id_list; id_list = id_list->next)
261 if (match_netid(id_list->list, netid))
b8187c80 262 message = _("disabled");
26128d27 263
3d8df260
SK
264 if (!message)
265 {
266 if (have_config(config, CONFIG_ADDR))
267 {
268 logaddr = &config->addr;
269 mess->yiaddr = config->addr;
270 if ((lease = lease_find_by_addr(config->addr)) &&
271 memcmp(lease->hwaddr, chaddr, ETHER_ADDR_LEN) != 0)
b8187c80 272 message = _("address in use");
3d8df260
SK
273 }
274 else if (!(daemon->options & OPT_BOOTP_DYNAMIC))
b8187c80 275 message = _("no address configured");
3d8df260
SK
276 else
277 {
278 if ((lease = lease_find_by_client(mess->chaddr, NULL, 0)))
279 mess->yiaddr = lease->addr;
280 else if (!address_allocate(context, daemon, &mess->yiaddr, chaddr, netid, now))
b8187c80 281 message = _("no address available");
3d8df260
SK
282 }
283
284 if (!message && !lease && (!(lease = lease_allocate(chaddr, NULL, 0, mess->yiaddr))))
b8187c80 285 message = _("no leases left");
3d8df260
SK
286
287 if (!message)
288 {
289 logaddr = &mess->yiaddr;
290 context = narrow_context(context, mess->yiaddr);
291
292 if (context->netid.net && !(context->flags & CONTEXT_FILTER))
293 {
294 context->netid.next = netid;
295 netid = &context->netid;
296 }
297
298 lease_set_hwaddr(lease, chaddr, NULL, 0);
299 if (hostname)
b8187c80 300 lease_set_hostname(lease, hostname, daemon->domain_suffix, 1);
3d8df260
SK
301 lease_set_expires(lease, 0); /* infinite lease */
302
303 p = do_req_options(context, p, end, NULL, daemon,
304 hostname, netid, subnet_addr, fqdn_flags);
305 /* must do this after do_req_options since it overwrites filename field. */
306 mess->siaddr = context->local;
307 bootp_option_put(mess, daemon->boot_config, netid);
308 p = option_end(p, end, mess);
309 }
310 }
311
312 log_packet(NULL, logaddr, chaddr, iface_name, message);
26128d27
SK
313 mess->file[128] = save;
314
315 if (message)
316 return 0;
317 else
318 return p - (unsigned char *)mess;
3be34541
SK
319 }
320
3d8df260 321 if ((opt = option_find(mess, sz, OPTION_CLIENT_FQDN, 4)))
9e4abcb5 322 {
3d8df260 323 /* http://tools.ietf.org/wg/dhc/draft-ietf-dhc-fqdn-option/draft-ietf-dhc-fqdn-option-10.txt */
f6b7dc47 324 int len = option_len(opt);
3d8df260
SK
325 char *pq = daemon->dhcp_buff;
326 unsigned char *pp, *op = option_ptr(opt);
327
328 fqdn_flags = *op;
329 len -= 3;
330 op += 3;
331 pp = op;
332
333 /* Always force update, since the client has no way to do it itself. */
334 if (fqdn_flags & 0x01)
335 fqdn_flags |= 0x02;
336
337 fqdn_flags &= ~0x08;
338 fqdn_flags |= 0x01;
339
340 if (fqdn_flags & 0x04)
341 while (*op != 0 && ((op + (*op) + 1) - pp) < len)
342 {
343 memcpy(pq, op+1, *op);
344 pq += *op;
345 op += (*op)+1;
346 *(pq++) = '.';
347 }
348 else
9e4abcb5 349 {
3d8df260
SK
350 memcpy(pq, op, len);
351 pq += len + 1;
9e4abcb5 352 }
3d8df260
SK
353
354 if (pq != daemon->dhcp_buff)
355 pq--;
356
357 *pq = 0;
358
359 if (canonicalise(daemon->dhcp_buff))
360 offer_hostname = client_hostname = daemon->dhcp_buff;
361 }
362 else if ((opt = option_find(mess, sz, OPTION_HOSTNAME, 1)))
363 {
364 int len = option_len(opt);
365 memcpy(daemon->dhcp_buff, option_ptr(opt), len);
366 /* May not be zero terminated */
367 daemon->dhcp_buff[len] = 0;
368 if (canonicalise(daemon->dhcp_buff))
369 client_hostname = daemon->dhcp_buff;
370 }
371
372 if (have_config(config, CONFIG_NAME))
373 {
374 hostname = config->hostname;
b8187c80 375 hostname_auth = 1;
3d8df260
SK
376 /* be careful not to send an OFFER with a hostname not
377 matching the DISCOVER. */
378 if (fqdn_flags != 0 || !client_hostname || hostname_isequal(hostname, client_hostname))
379 offer_hostname = hostname;
380 }
381 else if (client_hostname && (hostname = strip_hostname(daemon, client_hostname)) && !config)
382 {
383 /* Search again now we have a hostname.
384 Only accept configs without CLID and HWADDR here, (they won't match)
385 to avoid impersonation by name. */
386 struct dhcp_config *new = find_config(daemon->dhcp_conf, context, NULL, 0, chaddr, hostname);
387 if (!have_config(new, CONFIG_CLID) && !have_config(new, CONFIG_HWADDR))
388 config = new;
9e4abcb5 389 }
a84fa1d0 390
a84fa1d0 391 if (have_config(config, CONFIG_NETID))
a84fa1d0 392 {
a222641c
SK
393 config->netid.next = netid;
394 netid = &config->netid;
a84fa1d0 395 }
36717eee 396
26128d27
SK
397 /* user-class options are, according to RFC3004, supposed to contain
398 a set of counted strings. Here we check that this is so (by seeing
399 if the counts are consistent with the overall option length) and if
400 so zero the counts so that we don't get spurious matches between
401 the vendor string and the counts. If the lengths don't add up, we
402 assume that the option is a single string and non RFC3004 compliant
403 and just do the substring match. dhclient provides these broken options. */
a222641c 404
bb01cb96 405 if ((opt = option_find(mess, sz, OPTION_USER_CLASS, 1)))
a222641c 406 {
26128d27 407 unsigned char *ucp = option_ptr(opt);
f6b7dc47 408 int tmp, j;
26128d27
SK
409 for (j = 0; j < option_len(opt); j += ucp[j] + 1);
410 if (j == option_len(opt))
411 for (j = 0; j < option_len(opt); j = tmp)
412 {
413 tmp = j + ucp[j] + 1;
414 ucp[j] = 0;
415 }
416 }
417
418 for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
bb01cb96 419 if ((opt = option_find(mess, sz, vendor->is_vendor ? OPTION_VENDOR_ID : OPTION_USER_CLASS, 1)))
26128d27 420 {
f6b7dc47 421 int i;
26128d27
SK
422 for (i = 0; i <= (option_len(opt) - vendor->len); i++)
423 if (memcmp(vendor->data, option_ptr(opt)+i, vendor->len) == 0)
a222641c 424 {
26128d27
SK
425 vendor->netid.next = netid;
426 netid = &vendor->netid;
427 break;
a222641c 428 }
26128d27
SK
429 }
430
431 /* if all the netids in the ignore list are present, ignore this client */
432 for (id_list = daemon->dhcp_ignore; id_list; id_list = id_list->next)
433 if (match_netid(id_list->list, netid))
434 ignore = 1;
435
a84fa1d0
SK
436 /* Can have setting to ignore the client ID for a particular MAC address or hostname */
437 if (have_config(config, CONFIG_NOCLID))
0a852541
SK
438 clid = NULL;
439
bb01cb96 440 if ((opt = option_find(mess, sz, OPTION_REQUESTED_OPTIONS, 0)))
a84fa1d0 441 {
3d8df260 442 req_options = (unsigned char *)daemon->dhcp_buff2;
bb01cb96
SK
443 memcpy(req_options, option_ptr(opt), option_len(opt));
444 req_options[option_len(opt)] = OPTION_END;
a84fa1d0
SK
445 }
446
3be34541 447 switch (mess_type)
9e4abcb5 448 {
44a2a316 449 case DHCPDECLINE:
bb01cb96 450 if (!(opt = option_find(mess, sz, OPTION_SERVER_IDENTIFIER, INADDRSZ)) ||
0a852541 451 (context->local.s_addr != option_addr(opt).s_addr))
44a2a316
SK
452 return 0;
453
454 /* sanitise any message. Paranoid? Moi? */
bb01cb96 455 if ((opt = option_find(mess, sz, OPTION_MESSAGE, 1)))
44a2a316 456 {
3be34541 457 char *p = option_ptr(opt), *q = daemon->dhcp_buff;
44a2a316
SK
458 int i;
459
460 for (i = option_len(opt); i > 0; i--)
461 {
462 char c = *p++;
463 if (isprint(c))
464 *q++ = c;
465 }
466 *q++ = 0; /* add terminator */
3be34541 467 message = daemon->dhcp_buff;
44a2a316
SK
468 }
469
bb01cb96 470 if (!(opt = option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ)))
44a2a316
SK
471 return 0;
472
3d8df260 473 log_packet("DECLINE", option_ptr(opt), chaddr, iface_name, message);
44a2a316
SK
474
475 if (lease && lease->addr.s_addr == option_addr(opt).s_addr)
476 lease_prune(lease, now);
477
33820b7e 478 if (have_config(config, CONFIG_ADDR) &&
44a2a316 479 config->addr.s_addr == option_addr(opt).s_addr)
9e4abcb5 480 {
b8187c80 481 syslog(LOG_WARNING, _("disabling DHCP static address %s"), inet_ntoa(config->addr));
33820b7e 482 config->flags &= ~CONFIG_ADDR ;
9e4abcb5 483 }
feba5c1d
SK
484 else
485 /* make sure this host gets a different address next time. */
36717eee
SK
486 for (; context; context = context->current)
487 context->addr_epoch++;
44a2a316
SK
488
489 return 0;
490
491 case DHCPRELEASE:
bb01cb96 492 if (!(opt = option_find(mess, sz, OPTION_SERVER_IDENTIFIER, INADDRSZ)) ||
0a852541 493 (context->local.s_addr != option_addr(opt).s_addr))
44a2a316
SK
494 return 0;
495
44a2a316
SK
496 if (lease && lease->addr.s_addr == mess->ciaddr.s_addr)
497 lease_prune(lease, now);
fd9fa481 498 else
b8187c80 499 message = _("unknown lease");
fd9fa481 500
3d8df260 501 log_packet("RELEASE", &mess->ciaddr, chaddr, iface_name, message);
44a2a316 502
9e4abcb5
SK
503 return 0;
504
505 case DHCPDISCOVER:
3d8df260
SK
506 {
507 struct in_addr addr;
508
509 if ((opt = option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ)))
510 addr = option_addr(opt);
511 if (ignore || have_config(config, CONFIG_DISABLE))
b8187c80 512 message = _("ignored");
3d8df260
SK
513 else if (have_config(config, CONFIG_ADDR) &&
514 (!(ltmp = lease_find_by_addr(config->addr)) || ltmp == lease))
515 mess->yiaddr = config->addr;
516 else if (lease && address_available(context, lease->addr))
517 mess->yiaddr = lease->addr;
518 else if (opt && address_available(context, addr) && !lease_find_by_addr(addr) &&
519 !config_find_by_address(daemon->dhcp_conf, addr))
520 mess->yiaddr = addr;
521 else if (!address_allocate(context, daemon, &mess->yiaddr, chaddr, netid, now))
b8187c80 522 message = _("no address available");
3d8df260
SK
523 log_packet("DISCOVER", opt ? &addr : NULL, chaddr, iface_name, message);
524 }
525
33820b7e
SK
526 if (message)
527 return 0;
a84fa1d0 528
59353a6b 529 context = narrow_context(context, mess->yiaddr);
0a852541 530 if (context->netid.net && !(context->flags & CONTEXT_FILTER))
59353a6b
SK
531 {
532 context->netid.next = netid;
533 netid = &context->netid;
534 }
535
536 time = have_config(config, CONFIG_TIME) ? config->lease_time : context->lease_time;
bb01cb96 537 if ((opt = option_find(mess, sz, OPTION_LEASE_TIME, 4)))
59353a6b
SK
538 {
539 unsigned int req_time = option_uint(opt, 4);
540 if (time == 0xffffffff || (req_time != 0xffffffff && req_time < time))
541 time = req_time;
542 }
543 else if (lease && lease->expires != 0)
544 time = (unsigned int)difftime(lease->expires, now);
545
0a852541 546 mess->siaddr = context->local;
26128d27 547 bootp_option_put(mess, daemon->boot_config, netid);
44a2a316 548 p = option_put(p, end, OPTION_MESSAGE_TYPE, 1, DHCPOFFER);
0a852541 549 p = option_put(p, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(context->local.s_addr));
59353a6b 550 p = option_put(p, end, OPTION_LEASE_TIME, 4, time);
a84fa1d0 551 /* T1 and T2 are required in DHCPOFFER by HP's wacky Jetdirect client. */
59353a6b 552 if (time != 0xffffffff)
a84fa1d0 553 {
59353a6b
SK
554 p = option_put(p, end, OPTION_T1, 4, (time/2));
555 p = option_put(p, end, OPTION_T2, 4, (time*7)/8);
a84fa1d0 556 }
3be34541 557 p = do_req_options(context, p, end, req_options, daemon,
3d8df260 558 offer_hostname, netid, subnet_addr, fqdn_flags);
a222641c 559 p = option_end(p, end, mess);
9e4abcb5 560
3d8df260 561 log_packet("OFFER" , &mess->yiaddr, chaddr, iface_name, NULL);
9e4abcb5 562 return p - (unsigned char *)mess;
9e4abcb5
SK
563
564 case DHCPREQUEST:
26128d27
SK
565 if (ignore || have_config(config, CONFIG_DISABLE))
566 return 0;
bb01cb96 567 if ((opt = option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ)))
9e4abcb5
SK
568 {
569 /* SELECTING or INIT_REBOOT */
44a2a316 570 mess->yiaddr = option_addr(opt);
9e4abcb5 571
bb01cb96 572 if ((opt = option_find(mess, sz, OPTION_SERVER_IDENTIFIER, INADDRSZ)))
3be34541
SK
573 {
574 /* SELECTING */
0a852541 575 if (context->local.s_addr != option_addr(opt).s_addr)
3be34541
SK
576 return 0;
577
578 /* If a lease exists for this host and another address, squash it. */
579 if (lease && lease->addr.s_addr != mess->yiaddr.s_addr)
580 {
581 lease_prune(lease, now);
582 lease = NULL;
583 }
3be34541
SK
584 }
585 else
9e4abcb5 586 {
3be34541 587 /* INIT-REBOOT */
fd9fa481 588 if (!lease && !(daemon->options & OPT_AUTHORITATIVE))
3be34541
SK
589 return 0;
590
fd9fa481 591 if (lease && lease->addr.s_addr != mess->yiaddr.s_addr)
b8187c80 592 message = _("wrong address");
9e4abcb5 593 }
44a2a316
SK
594 }
595 else
596 {
597 /* RENEWING or REBINDING */
598 /* Must exist a lease for this address */
44a2a316 599 if (!lease || mess->ciaddr.s_addr != lease->addr.s_addr)
b8187c80
SK
600 {
601 message = _("lease not found");
602 /* ensure we broadcast NAK */
603 unicast_dest = 0;
604 }
a84fa1d0
SK
605 /* desynchronise renewals */
606 fuzz = rand16();
3be34541 607 mess->yiaddr = mess->ciaddr;
44a2a316
SK
608 }
609
3d8df260 610 log_packet("REQUEST", &mess->yiaddr, chaddr, iface_name, NULL);
fd9fa481 611
dfa666f2
SK
612 if (!message)
613 {
614 struct dhcp_config *addr_config;
fd9fa481 615
dfa666f2
SK
616 /* If a machine moves networks whilst it has a lease, we catch that here. */
617 if (!is_same_net(mess->yiaddr, context->start, context->netmask))
b8187c80
SK
618 {
619 message = _("wrong network");
620 /* ensure we broadcast NAK */
621 unicast_dest = 0;
622 }
623
fd9fa481 624 /* Check for renewal of a lease which is outside the allowed range. */
dfa666f2
SK
625 else if (!address_available(context, mess->yiaddr) &&
626 (!have_config(config, CONFIG_ADDR) || config->addr.s_addr != mess->yiaddr.s_addr))
b8187c80 627 message = _("address not available");
dfa666f2
SK
628
629 /* Check if a new static address has been configured. Be very sure that
630 when the client does DISCOVER, it will get the static address, otherwise
631 an endless protocol loop will ensue. */
fd9fa481
SK
632
633 else if (have_config(config, CONFIG_ADDR) &&
634 config->addr.s_addr != mess->yiaddr.s_addr &&
635 (!(ltmp = lease_find_by_addr(config->addr)) || ltmp == lease))
b8187c80 636 message = _("static lease available");
dfa666f2
SK
637
638 /* Check to see if the address is reserved as a static address for another host */
3be34541 639 else if ((addr_config = config_find_by_address(daemon->dhcp_conf, mess->yiaddr)) && addr_config != config)
b8187c80 640 message = _("address reserved");
feba5c1d 641
fd9fa481 642 else if ((ltmp = lease_find_by_addr(mess->yiaddr)) && ltmp != lease)
b8187c80 643 message = _("address in use");
fd9fa481 644
3d8df260 645 else if (!lease && !(lease = lease_allocate(chaddr, clid, clid_len, mess->yiaddr)))
b8187c80 646 message = _("no leases left");
fd9fa481 647 }
44a2a316
SK
648
649 if (message)
650 {
3d8df260 651 log_packet("NAK", &mess->yiaddr, chaddr, iface_name, message);
44a2a316 652
b8187c80 653 mess->siaddr.s_addr = mess->yiaddr.s_addr = 0;
44a2a316
SK
654 bootp_option_put(mess, NULL, NULL);
655 p = option_put(p, end, OPTION_MESSAGE_TYPE, 1, DHCPNAK);
3d8df260 656 p = option_put(p, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(context->local.s_addr));
44a2a316 657 p = option_put_string(p, end, OPTION_MESSAGE, message);
b8187c80
SK
658 /* This fixes a problem with the DHCP spec, broadcasting a NAK to a host on
659 a distant subnet which unicast a REQ to us won't work. */
660 if (!unicast_dest || mess->giaddr.s_addr != 0 ||
661 mess->ciaddr.s_addr == 0 || is_same_net(context->local, mess->ciaddr, context->netmask))
662 {
663 mess->flags |= htons(0x8000); /* broadcast */
664 mess->ciaddr.s_addr = 0;
665 }
44a2a316 666 }
fd9fa481 667 else
44a2a316 668 {
b8187c80
SK
669 if (!hostname_auth && (client_hostname = host_from_dns(daemon, mess->yiaddr)))
670 {
671 hostname = client_hostname;
672 hostname_auth = 1;
673 }
674
3d8df260 675 log_packet("ACK", &mess->yiaddr, chaddr, iface_name, hostname);
fd9fa481 676
59353a6b 677 context = narrow_context(context, mess->yiaddr);
0a852541 678 if (context->netid.net && !(context->flags & CONTEXT_FILTER))
59353a6b
SK
679 {
680 context->netid.next = netid;
681 netid = &context->netid;
682 }
683
684 time = have_config(config, CONFIG_TIME) ? config->lease_time : context->lease_time;
bb01cb96 685 if ((opt = option_find(mess, sz, OPTION_LEASE_TIME, 4)))
59353a6b
SK
686 {
687 unsigned int req_time = option_uint(opt, 4);
688 if (time == 0xffffffff || (req_time != 0xffffffff && req_time < time))
689 time = req_time;
690 }
691
3d8df260 692 lease_set_hwaddr(lease, chaddr, clid, clid_len);
fd9fa481 693 if (hostname)
b8187c80 694 lease_set_hostname(lease, hostname, daemon->domain_suffix, hostname_auth);
59353a6b 695 lease_set_expires(lease, time == 0xffffffff ? 0 : now + (time_t)time);
0a852541
SK
696
697 mess->siaddr = context->local;
26128d27 698 bootp_option_put(mess, daemon->boot_config, netid);
fd9fa481 699 p = option_put(p, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
0a852541 700 p = option_put(p, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(context->local.s_addr));
59353a6b
SK
701 p = option_put(p, end, OPTION_LEASE_TIME, 4, time);
702 if (time != 0xffffffff)
fd9fa481 703 {
59353a6b
SK
704 while (fuzz > (time/16))
705 fuzz = fuzz/2;
706 p = option_put(p, end, OPTION_T1, 4, (time/2) - fuzz);
707 p = option_put(p, end, OPTION_T2, 4, ((time * 7)/8) - fuzz);
fd9fa481
SK
708 }
709 p = do_req_options(context, p, end, req_options, daemon,
3d8df260 710 hostname, netid, subnet_addr, fqdn_flags);
44a2a316 711 }
fd9fa481 712
a222641c 713 p = option_end(p, end, mess);
9e4abcb5
SK
714 return p - (unsigned char *)mess;
715
716 case DHCPINFORM:
26128d27 717 if (ignore || have_config(config, CONFIG_DISABLE))
b8187c80 718 message = _("ignored");
33820b7e 719
3d8df260 720 log_packet("INFORM", &mess->ciaddr, chaddr, iface_name, message);
a84fa1d0
SK
721
722 if (message || mess->ciaddr.s_addr == 0)
723 return 0;
9e4abcb5 724
59353a6b
SK
725 context = narrow_context(context, mess->ciaddr);
726 if (context->netid.net)
727 {
728 context->netid.next = netid;
729 netid = &context->netid;
730 }
731
0a852541 732 mess->siaddr = context->local;
26128d27 733 bootp_option_put(mess, daemon->boot_config, netid);
44a2a316 734 p = option_put(p, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
0a852541 735 p = option_put(p, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(context->local.s_addr));
bb01cb96
SK
736 if (!hostname)
737 hostname = host_from_dns(daemon, mess->yiaddr);
3be34541 738 p = do_req_options(context, p, end, req_options, daemon,
3d8df260 739 hostname, netid, subnet_addr, fqdn_flags);
a222641c 740 p = option_end(p, end, mess);
9e4abcb5 741
3d8df260 742 log_packet("ACK", &mess->ciaddr, chaddr, iface_name, hostname);
9e4abcb5
SK
743 return p - (unsigned char *)mess;
744 }
745
746 return 0;
747}
748
44a2a316 749static void log_packet(char *type, struct in_addr *addr, unsigned char *hwaddr, char *interface, char *string)
9e4abcb5 750{
3d8df260
SK
751 u8 empty[] = { 0, 0, 0, 0, 0, 0};
752
753 if (!hwaddr)
754 hwaddr = empty;
755
3be34541
SK
756 syslog(LOG_INFO, "%s%s(%s)%s%s %.2x:%.2x:%.2x:%.2x:%.2x:%.2x%s%s",
757 type ? "DHCP" : "BOOTP",
758 type ? type : "",
9e4abcb5
SK
759 interface,
760 addr ? " " : "",
761 addr ? inet_ntoa(*addr) : "",
44a2a316
SK
762 hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5],
763 string ? " " : "",
764 string ? string : "");
9e4abcb5
SK
765}
766
f6b7dc47 767static int option_len(unsigned char *opt)
9e4abcb5
SK
768{
769 return opt[1];
770}
771
772static void *option_ptr(unsigned char *opt)
773{
774 return &opt[2];
775}
776
777static struct in_addr option_addr(unsigned char *opt)
778{
779 /* this worries about unaligned data in the option. */
780 /* struct in_addr is network byte order */
781 struct in_addr ret;
782
783 memcpy(&ret, option_ptr(opt), INADDRSZ);
784
785 return ret;
786}
787
44a2a316 788static unsigned int option_uint(unsigned char *opt, int size)
9e4abcb5
SK
789{
790 /* this worries about unaligned data and byte order */
44a2a316
SK
791 unsigned int ret = 0;
792 int i;
793 unsigned char *p = option_ptr(opt);
9e4abcb5 794
44a2a316
SK
795 for (i = 0; i < size; i++)
796 ret = (ret << 8) | *p++;
797
798 return ret;
9e4abcb5
SK
799}
800
26128d27
SK
801static void bootp_option_put(struct dhcp_packet *mess,
802 struct dhcp_boot *boot_opts, struct dhcp_netid *netids)
9e4abcb5 803{
26128d27
SK
804 struct dhcp_boot *tmp;
805
806 for (tmp = boot_opts; tmp; tmp = tmp->next)
807 if (match_netid(tmp->netid, netids))
808 break;
809 if (!tmp)
810 /* No match, look for one without a netid */
811 for (tmp = boot_opts; tmp; tmp = tmp->next)
812 if (!tmp->netid)
813 break;
814
815 /* Do this _after_ the matching above, since in
816 BOOTP mode, one if the things we match is the filename. */
817
9e4abcb5
SK
818 memset(mess->sname, 0, sizeof(mess->sname));
819 memset(mess->file, 0, sizeof(mess->file));
26128d27
SK
820
821 if (tmp)
822 {
823 if (tmp->sname)
3d8df260 824 strncpy((char *)mess->sname, tmp->sname, sizeof(mess->sname)-1);
26128d27 825 if (tmp->file)
3d8df260 826 strncpy((char *)mess->file, tmp->file, sizeof(mess->file)-1);
26128d27
SK
827 if (tmp->next_server.s_addr)
828 mess->siaddr = tmp->next_server;
829 }
9e4abcb5
SK
830}
831
b8187c80
SK
832static int check_space(unsigned char *p, unsigned char *end, int len, int opt)
833{
834 /* always keep one octet space for the END option. */
835 if (p + len + 3 >= end)
836 {
837 syslog(LOG_WARNING, _("cannot send DHCP option %d: no space left in packet"), opt);
838 return 0;
839 }
840
841 return 1;
842}
843
844
9e4abcb5
SK
845static unsigned char *option_put(unsigned char *p, unsigned char *end, int opt, int len, unsigned int val)
846{
847 int i;
44a2a316 848
b8187c80 849 if (check_space(p, end, len, opt))
9e4abcb5
SK
850 {
851 *(p++) = opt;
a222641c
SK
852 *(p++) = len;
853
854 for (i = 0; i < len; i++)
855 *(p++) = val >> (8 * (len - (i + 1)));
9e4abcb5
SK
856 }
857 return p;
858}
859
a222641c
SK
860static unsigned char *option_end(unsigned char *p, unsigned char *end, struct dhcp_packet *start)
861{
862 *(p++) = OPTION_END;
863 while ((p < end) && (p - ((unsigned char *)start) < MIN_PACKETSZ))
864 *p++ = 0;
865
866 return p;
867}
868
44a2a316
SK
869static unsigned char *option_put_string(unsigned char *p, unsigned char *end, int opt, char *string)
870{
0a852541 871 size_t len = strlen(string);
3be34541 872
b8187c80 873 if (check_space(p, end, len, opt))
44a2a316
SK
874 {
875 *(p++) = opt;
3be34541
SK
876 *(p++) = len;
877 memcpy(p, string, len);
878 p += len;
44a2a316 879 }
3be34541 880
44a2a316
SK
881 return p;
882}
883
9e4abcb5
SK
884static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt, int *overload)
885{
9e4abcb5
SK
886 if (!p)
887 return NULL;
888
889 while (*p != OPTION_END)
890 {
bb01cb96 891 if (p >= end)
9e4abcb5
SK
892 return 0; /* malformed packet */
893 else if (*p == OPTION_PAD)
894 p++;
895 else if (*p == OPTION_OVERLOAD)
896 {
bb01cb96 897 if (p >= end - 3)
9e4abcb5
SK
898 return 0; /* malformed packet */
899 if (overload)
900 *overload = *(p+2);
901 p += 3;
902 }
903 else
904 {
905 int opt_len;;
bb01cb96 906 if (p >= end - 2)
9e4abcb5
SK
907 return 0; /* malformed packet */
908 opt_len = option_len(p);
bb01cb96 909 if (p >= end - (2 + opt_len))
9e4abcb5
SK
910 return 0; /* malformed packet */
911 if (*p == opt)
912 return p;
913 p += opt_len + 2;
914 }
915 }
916
917 return NULL;
918}
919
f6b7dc47 920static unsigned char *option_find(struct dhcp_packet *mess, int size, int opt_type, int minsize)
9e4abcb5
SK
921{
922 int overload = 0;
923 unsigned char *ret;
924
3be34541
SK
925 /* skip over DHCP cookie; */
926 ret = option_find1(&mess->options[0] + sizeof(u32), ((unsigned char *)mess) + size, opt_type, &overload);
9e4abcb5
SK
927
928 if (!ret && (overload & 1))
929 ret = option_find1(&mess->file[0], &mess->file[128], opt_type, &overload);
930
931 if (!ret && (overload & 2))
932 ret = option_find1(&mess->sname[0], &mess->file[64], opt_type, &overload);
bb01cb96
SK
933
934 /* Check the option field is big enough */
935 if (ret && (option_len(ret) < minsize))
936 ret = NULL;
937
9e4abcb5
SK
938 return ret;
939}
940
941static int in_list(unsigned char *list, int opt)
942{
943 int i;
944
a84fa1d0
SK
945 /* If no requested options, send everything, not nothing. */
946 if (!list)
947 return 1;
948
9e4abcb5
SK
949 for (i = 0; list[i] != OPTION_END; i++)
950 if (opt == list[i])
951 return 1;
952
953 return 0;
954}
955
a222641c 956static struct dhcp_opt *option_find2(struct dhcp_netid *netid, struct dhcp_opt *opts, int opt)
9e4abcb5 957{
91dccd09 958 struct dhcp_opt *tmp;
a84fa1d0 959 for (tmp = opts; tmp; tmp = tmp->next)
a222641c
SK
960 if (tmp->opt == opt)
961 {
962 if (netid)
963 {
26128d27
SK
964 if (match_netid(tmp->netid, netid))
965 return tmp;
a222641c
SK
966 }
967 else if (!tmp->netid)
968 return tmp;
969 }
970
a84fa1d0 971 return netid ? option_find2(NULL, opts, opt) : NULL;
9e4abcb5
SK
972}
973
91dccd09
SK
974static unsigned char *do_opt(struct dhcp_opt *opt, unsigned char *p, unsigned char *end, struct in_addr local)
975{
b8187c80 976 if (!check_space(p, end, opt->len, opt->opt))
91dccd09 977 return p;
b8187c80 978
91dccd09
SK
979 *(p++) = opt->opt;
980 *(p++) = opt->len;
981
982 if (opt->len == 0)
983 return p;
984
985 if (opt->is_addr && !opt->vendor_class)
986 {
987 int j;
988 struct in_addr *a = (struct in_addr *)opt->val;
989 for (j = 0; j < opt->len; j+=INADDRSZ, a++)
990 {
991 /* zero means "self" (but not in vendorclass options.) */
992 if (a->s_addr == 0)
993 memcpy(p, &local, INADDRSZ);
994 else
995 memcpy(p, a, INADDRSZ);
996 p += INADDRSZ;
997 }
998 }
999 else
1000 {
1001 memcpy(p, opt->val, opt->len);
1002 p += opt->len;
1003 }
1004
1005 return p;
1006}
1007
9e4abcb5
SK
1008static unsigned char *do_req_options(struct dhcp_context *context,
1009 unsigned char *p, unsigned char *end,
1010 unsigned char *req_options,
3be34541
SK
1011 struct daemon *daemon,
1012 char *hostname,
3be34541 1013 struct dhcp_netid *netid,
3d8df260
SK
1014 struct in_addr subnet_addr,
1015 unsigned char fqdn_flags)
9e4abcb5 1016{
3be34541 1017 struct dhcp_opt *opt, *config_opts = daemon->dhcp_opts;
91dccd09 1018 char *vendor_class = NULL;
3be34541 1019
1ab84e2f 1020 if (in_list(req_options, OPTION_MAXMESSAGE))
3be34541 1021 p = option_put(p, end, OPTION_MAXMESSAGE, 2, end - (unsigned char *)daemon->dhcp_packet);
1ab84e2f 1022
3be34541
SK
1023 /* rfc3011 says this doesn't need to be in the requested options list. */
1024 if (subnet_addr.s_addr)
1025 p = option_put(p, end, OPTION_SUBNET_SELECT, INADDRSZ, ntohl(subnet_addr.s_addr));
1026
9e4abcb5 1027 if (in_list(req_options, OPTION_NETMASK) &&
33820b7e 1028 !option_find2(netid, config_opts, OPTION_NETMASK))
9e4abcb5
SK
1029 p = option_put(p, end, OPTION_NETMASK, INADDRSZ, ntohl(context->netmask.s_addr));
1030
3be34541
SK
1031 /* May not have a "guessed" broadcast address if we got no packets via a relay
1032 from this net yet (ie just unicast renewals after a restart */
1033 if (context->broadcast.s_addr &&
1034 in_list(req_options, OPTION_BROADCAST) &&
33820b7e 1035 !option_find2(netid, config_opts, OPTION_BROADCAST))
9e4abcb5
SK
1036 p = option_put(p, end, OPTION_BROADCAST, INADDRSZ, ntohl(context->broadcast.s_addr));
1037
3be34541
SK
1038 /* Same comments as broadcast apply, and also may not be able to get a sensible
1039 default when using subnet select. User must configure by steam in that case. */
1040 if (context->router.s_addr &&
1041 in_list(req_options, OPTION_ROUTER) &&
33820b7e 1042 !option_find2(netid, config_opts, OPTION_ROUTER))
3be34541 1043 p = option_put(p, end, OPTION_ROUTER, INADDRSZ, ntohl(context->router.s_addr));
9e4abcb5
SK
1044
1045 if (in_list(req_options, OPTION_DNSSERVER) &&
33820b7e 1046 !option_find2(netid, config_opts, OPTION_DNSSERVER))
0a852541 1047 p = option_put(p, end, OPTION_DNSSERVER, INADDRSZ, ntohl(context->local.s_addr));
9e4abcb5 1048
3be34541 1049 if (daemon->domain_suffix && in_list(req_options, OPTION_DOMAINNAME) &&
33820b7e 1050 !option_find2(netid, config_opts, OPTION_DOMAINNAME))
3be34541 1051 p = option_put_string(p, end, OPTION_DOMAINNAME, daemon->domain_suffix);
9e4abcb5
SK
1052
1053 /* Note that we ignore attempts to set the hostname using
3d8df260
SK
1054 --dhcp-option=12,<name> and the fqdn using
1055 --dhc-option=81,<name> */
1056 if (hostname)
1057 {
1058 if (in_list(req_options, OPTION_HOSTNAME))
1059 p = option_put_string(p, end, OPTION_HOSTNAME, hostname);
1060
1061 if (fqdn_flags != 0)
1062 {
1063 int len = strlen(hostname) + 3;
1064 if (fqdn_flags & 0x04)
1065 len += 2;
1066
1067 if (daemon->domain_suffix)
1068 len += strlen(daemon->domain_suffix) + 1;
1069
1070 if (p + len + 1 < end)
1071 {
1072 *(p++) = OPTION_CLIENT_FQDN;
1073 *(p++) = len;
1074 *(p++) = fqdn_flags;
1075 *(p++) = 255;
1076 *(p++) = 255;
1077
1078 if (fqdn_flags & 0x04)
1079 {
1080 p = do_rfc1035_name(p, hostname);
1081 if (daemon->domain_suffix)
1082 p = do_rfc1035_name(p, daemon->domain_suffix);
1083 *p++ = 0;
1084 }
1085 else
1086 {
1087 memcpy(p, hostname, strlen(hostname));
1088 p += strlen(hostname);
1089 if (daemon->domain_suffix)
1090 {
1091 *(p++) = '.';
1092 memcpy(p, daemon->domain_suffix, strlen(daemon->domain_suffix));
1093 p += strlen(daemon->domain_suffix);
1094 }
1095 }
1096 }
1097 }
1098 }
1099
a84fa1d0 1100 for (opt=config_opts; opt; opt = opt->next)
9e4abcb5 1101 {
a84fa1d0 1102 if (opt->opt == OPTION_HOSTNAME ||
3d8df260 1103 opt->opt == OPTION_CLIENT_FQDN ||
a84fa1d0
SK
1104 opt->opt == OPTION_MAXMESSAGE ||
1105 !in_list(req_options, opt->opt) ||
91dccd09 1106 opt != option_find2(netid, config_opts, opt->opt))
33820b7e
SK
1107 continue;
1108
1109 /* For the options we have default values on
1110 dhc-option=<optionno> means "don't include this option"
1111 not "include a zero-length option" */
1112 if (opt->len == 0 &&
1113 (opt->opt == OPTION_NETMASK ||
1114 opt->opt == OPTION_BROADCAST ||
1115 opt->opt == OPTION_ROUTER ||
1116 opt->opt == OPTION_DNSSERVER))
1117 continue;
91dccd09
SK
1118
1119 /* opt->val has terminating zero */
1120 if (opt->opt == OPTION_VENDOR_ID)
3d8df260 1121 vendor_class = (char *)opt->val;
91dccd09
SK
1122 else
1123 p = do_opt(opt, p, end, context->local);
1124 }
1125
1126 if (in_list(req_options, OPTION_VENDOR_ID))
1127 {
1128 for (opt = daemon->vendor_opts; opt; opt = opt->next)
1129 if (!opt->netid || match_netid(opt->netid, netid))
1130 {
3d8df260 1131 if (vendor_class && strcmp(vendor_class, (char *)opt->vendor_class) != 0)
b8187c80 1132 syslog(LOG_WARNING, _("More than one vendor class matches, using %s"), vendor_class);
91dccd09 1133 else
3d8df260 1134 vendor_class = (char *)opt->vendor_class;
91dccd09
SK
1135 }
1136
1137 if (vendor_class)
9e4abcb5 1138 {
91dccd09
SK
1139 p = option_put_string(p, end, OPTION_VENDOR_ID, vendor_class);
1140
1141 if (in_list(req_options, OPTION_VENDOR_CLASS_OPT))
1ab84e2f 1142 {
91dccd09
SK
1143 unsigned char *plen, *oend = end;
1144
1145 /* encapsulated options can only be 256 bytes,
1146 even of the packet is larger */
1147 if (p + 256 < end)
1148 oend = p + 256;
1149
1150 if (p + 3 >= oend)
1151 return p;
1152
1153 *(p++) = OPTION_VENDOR_CLASS_OPT;
1154 plen = p++; /* fill in later */
1155
1156 for (opt = daemon->vendor_opts; opt; opt = opt->next)
1157 if ((!opt->netid || match_netid(opt->netid, netid)) &&
3d8df260 1158 strcmp(vendor_class, (char *)opt->vendor_class) == 0)
91dccd09
SK
1159 p = do_opt(opt, p, oend, context->local);
1160
1161 *plen = p - plen - 1;
1ab84e2f 1162 }
9e4abcb5 1163 }
91dccd09
SK
1164 }
1165
9e4abcb5
SK
1166 return p;
1167}
1168
1169