tools/adflib: build only host variant which is used by Sam440 target
[AROS.git] / workbench / network / stacks / AROSTCP / dhcp / relay / dhcrelay.c
blob7f048a42b3137a2a7533dd9fa26f33e9d2c4a6ed
1 /* dhcrelay.c
3 DHCP/BOOTP Relay Agent. */
5 /*
6 * Copyright (c) 2004-2005 by Internet Systems Consortium, Inc. ("ISC")
7 * Copyright (c) 1997-2003 by Internet Software Consortium
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
13 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 * Internet Systems Consortium, Inc.
22 * 950 Charter Street
23 * Redwood City, CA 94063
24 * <info@isc.org>
25 * http://www.isc.org/
27 * This software has been written for Internet Systems Consortium
28 * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
29 * To learn more about Internet Systems Consortium, see
30 * ``http://www.isc.org/''. To learn more about Vixie Enterprises,
31 * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
32 * ``http://www.nominum.com''.
35 #ifndef lint
36 static char ocopyright[] =
37 "$Id$ Copyright (c) 2004-2005 Internet Systems Consortium. All rights reserved.\n";
38 #endif /* not lint */
40 #include "dhcpd.h"
41 #include "version.h"
43 static void usage PROTO ((void));
45 TIME default_lease_time = 43200; /* 12 hours... */
46 TIME max_lease_time = 86400; /* 24 hours... */
47 struct tree_cache *global_options [256];
49 /* Needed to prevent linking against conflex.c. */
50 int lexline;
51 int lexchar;
52 char *token_line;
53 char *tlname;
55 const char *path_dhcrelay_pid = _PATH_DHCRELAY_PID;
57 int bogus_agent_drops = 0; /* Packets dropped because agent option
58 field was specified and we're not relaying
59 packets that already have an agent option
60 specified. */
61 int bogus_giaddr_drops = 0; /* Packets sent to us to relay back to a
62 client, but with a bogus giaddr. */
63 int client_packets_relayed = 0; /* Packets relayed from client to server. */
64 int server_packet_errors = 0; /* Errors sending packets to servers. */
65 int server_packets_relayed = 0; /* Packets relayed from server to client. */
66 int client_packet_errors = 0; /* Errors sending packets to clients. */
68 int add_agent_options = 0; /* If nonzero, add relay agent options. */
69 int drop_agent_mismatches = 0; /* If nonzero, drop server replies that
70 don't have matching circuit-id's. */
71 int corrupt_agent_options = 0; /* Number of packets dropped because
72 relay agent information option was bad. */
73 int missing_agent_option = 0; /* Number of packets dropped because no
74 RAI option matching our ID was found. */
75 int bad_circuit_id = 0; /* Circuit ID option in matching RAI option
76 did not match any known circuit ID. */
77 int missing_circuit_id = 0; /* Circuit ID option in matching RAI option
78 was missing. */
79 int max_hop_count = 10; /* Maximum hop count */
82 /* Maximum size of a packet with agent options added. */
83 int dhcp_max_agent_option_packet_length = 576;
85 /* What to do about packets we're asked to relay that
86 already have a relay option: */
87 enum { forward_and_append, /* Forward and append our own relay option. */
88 forward_and_replace, /* Forward, but replace theirs with ours. */
89 forward_untouched, /* Forward without changes. */
90 discard } agent_relay_mode = forward_and_replace;
92 u_int16_t local_port;
93 u_int16_t remote_port;
95 struct server_list {
96 struct server_list *next;
97 struct sockaddr_in to;
98 } *servers;
100 static char copyright [] = "Copyright 2004-2005 Internet Systems Consortium.";
101 static char arr [] = "All rights reserved.";
102 static char message [] = "Internet Systems Consortium DHCP Relay Agent";
103 static char url [] = "For info, please visit http://www.isc.org/sw/dhcp/";
105 int main (argc, argv, envp)
106 int argc;
107 char **argv, **envp;
109 int i;
110 struct servent *ent;
111 struct server_list *sp = (struct server_list *)0;
112 int no_daemon = 0;
113 int quiet = 0;
114 isc_result_t status;
115 char *s;
117 /* Make sure we have stdin, stdout and stderr. */
118 #ifdef AMIGA
119 struct Process *me;
121 me = (struct Process *)FindTask(NULL);
122 if (!me->pr_COS)
123 log_perror = 0;
124 #else
125 i = open ("/dev/null", O_RDWR);
126 if (i == 0)
127 i = open ("/dev/null", O_RDWR);
128 if (i == 1) {
129 i = open ("/dev/null", O_RDWR);
130 log_perror = 0; /* No sense logging to /dev/null. */
131 } else if (i != -1)
132 close (i);
133 #endif
134 #ifdef SYSLOG_4_2
135 openlog ("dhcrelay", LOG_NDELAY);
136 log_priority = LOG_DAEMON;
137 #else
138 openlog ("dhcrelay", LOG_NDELAY, LOG_DAEMON);
139 #endif
141 #if !(defined (DEBUG) || defined (SYSLOG_4_2))
142 setlogmask (LOG_UPTO (LOG_INFO));
143 #endif
145 /* Set up the OMAPI. */
146 status = omapi_init ();
147 if (status != ISC_R_SUCCESS)
148 log_fatal ("Can't initialize OMAPI: %s",
149 isc_result_totext (status));
151 /* Set up the OMAPI wrappers for the interface object. */
152 interface_setup ();
154 for (i = 1; i < argc; i++) {
155 if (!strcmp (argv [i], "-p")) {
156 if (++i == argc)
157 usage ();
158 local_port = htons (atoi (argv [i]));
159 log_debug ("binding to user-specified port %d",
160 ntohs (local_port));
161 } else if (!strcmp (argv [i], "-d")) {
162 no_daemon = 1;
163 } else if (!strcmp (argv [i], "-i")) {
164 struct interface_info *tmp =
165 (struct interface_info *)0;
166 status = interface_allocate (&tmp, MDL);
167 if (status != ISC_R_SUCCESS)
168 log_fatal ("%s: interface_allocate: %s",
169 argv [i],
170 isc_result_totext (status));
171 if (++i == argc) {
172 usage ();
174 strcpy (tmp -> name, argv [i]);
175 interface_snorf (tmp, INTERFACE_REQUESTED);
176 interface_dereference (&tmp, MDL);
177 } else if (!strcmp (argv [i], "-q")) {
178 quiet = 1;
179 quiet_interface_discovery = 1;
180 } else if (!strcmp (argv [i], "-a")) {
181 add_agent_options = 1;
182 } else if (!strcmp (argv [i], "-c")) {
183 int hcount;
184 if (++i == argc)
185 usage ();
186 hcount = atoi(argv[i]);
187 if (hcount <= 255)
188 max_hop_count= hcount;
189 else
190 usage ();
191 } else if (!strcmp (argv [i], "-A")) {
192 if (++i == argc)
193 usage ();
194 dhcp_max_agent_option_packet_length = atoi (argv [i]);
195 } else if (!strcmp (argv [i], "-m")) {
196 if (++i == argc)
197 usage ();
198 if (!strcasecmp (argv [i], "append")) {
199 agent_relay_mode = forward_and_append;
200 } else if (!strcasecmp (argv [i], "replace")) {
201 agent_relay_mode = forward_and_replace;
202 } else if (!strcasecmp (argv [i], "forward")) {
203 agent_relay_mode = forward_untouched;
204 } else if (!strcasecmp (argv [i], "discard")) {
205 agent_relay_mode = discard;
206 } else
207 usage ();
208 } else if (!strcmp (argv [i], "-D")) {
209 drop_agent_mismatches = 1;
210 } else if (argv [i][0] == '-') {
211 usage ();
212 } else if (!strcmp (argv [i], "--version")) {
213 log_info ("isc-dhcrelay-%s", DHCP_VERSION);
214 exit (0);
215 } else {
216 struct hostent *he;
217 struct in_addr ia, *iap = (struct in_addr *)0;
218 if (inet_aton (argv [i], &ia)) {
219 iap = &ia;
220 } else {
221 he = gethostbyname (argv [i]);
222 if (!he) {
223 log_error ("%s: host unknown",
224 argv [i]);
225 } else {
226 iap = ((struct in_addr *)
227 he -> h_addr_list [0]);
230 if (iap) {
231 sp = ((struct server_list *)
232 dmalloc (sizeof *sp, MDL));
233 if (!sp)
234 log_fatal ("no memory for server.\n");
235 sp -> next = servers;
236 servers = sp;
237 memcpy (&sp -> to.sin_addr,
238 iap, sizeof *iap);
243 if ((s = getenv ("PATH_DHCRELAY_PID"))) {
244 path_dhcrelay_pid = s;
247 if (!quiet) {
248 log_info ("%s %s", message, DHCP_VERSION);
249 log_info (copyright);
250 log_info (arr);
251 log_info (url);
252 } else {
253 quiet = 0;
254 log_perror = 0;
257 /* Default to the DHCP/BOOTP port. */
258 if (!local_port) {
259 ent = getservbyname ("dhcps", "udp");
260 if (!ent)
261 local_port = htons (67);
262 else
263 local_port = ent -> s_port;
264 endservent ();
266 remote_port = htons (ntohs (local_port) + 1);
268 /* We need at least one server. */
269 if (!sp) {
270 usage ();
273 /* Set up the server sockaddrs. */
274 for (sp = servers; sp; sp = sp -> next) {
275 sp -> to.sin_port = local_port;
276 sp -> to.sin_family = AF_INET;
277 #ifdef HAVE_SA_LEN
278 sp -> to.sin_len = sizeof sp -> to;
279 #endif
282 /* Get the current time... */
283 GET_TIME (&cur_time);
285 /* Discover all the network interfaces. */
286 discover_interfaces (DISCOVER_RELAY);
288 /* Set up the bootp packet handler... */
289 bootp_packet_handler = relay;
291 /* Become a daemon... */
292 #ifndef FORK_MISSING
293 if (!no_daemon) {
294 int pid;
295 FILE *pf;
296 int pfdesc;
298 log_perror = 0;
300 if ((pid = fork()) < 0)
301 log_fatal ("can't fork daemon: %m");
302 else if (pid)
303 exit (0);
305 pfdesc = open (path_dhcrelay_pid,
306 O_CREAT | O_TRUNC | O_WRONLY, 0644);
308 if (pfdesc < 0) {
309 log_error ("Can't create %s: %m", path_dhcrelay_pid);
310 } else {
311 pf = fdopen (pfdesc, "w");
312 if (!pf)
313 log_error ("Can't fdopen %s: %m",
314 path_dhcrelay_pid);
315 else {
316 fprintf (pf, "%ld\n", (long)getpid ());
317 fclose (pf);
321 close (0);
322 close (1);
323 close (2);
324 pid = setsid ();
326 #endif
327 /* Start dispatching packets and timeouts... */
328 dispatch ();
330 /*NOTREACHED*/
331 return 0;
334 void relay (ip, packet, length, from_port, from, hfrom)
335 struct interface_info *ip;
336 struct dhcp_packet *packet;
337 unsigned length;
338 unsigned int from_port;
339 struct iaddr from;
340 struct hardware *hfrom;
342 struct server_list *sp;
343 struct sockaddr_in to;
344 struct interface_info *out;
345 struct hardware hto, *htop;
347 if (packet -> hlen > sizeof packet -> chaddr) {
348 log_info ("Discarding packet with invalid hlen.");
349 return;
352 /* Find the interface that corresponds to the giaddr
353 in the packet. */
354 if (packet -> giaddr.s_addr) {
355 for (out = interfaces; out; out = out -> next) {
356 if (!memcmp (&out -> primary_address,
357 &packet -> giaddr,
358 sizeof packet -> giaddr))
359 break;
361 } else {
362 out = (struct interface_info *)0;
365 /* If it's a bootreply, forward it to the client. */
366 if (packet -> op == BOOTREPLY) {
367 if (!(packet -> flags & htons (BOOTP_BROADCAST)) &&
368 can_unicast_without_arp (out)) {
369 to.sin_addr = packet -> yiaddr;
370 to.sin_port = remote_port;
372 /* and hardware address is not broadcast */
373 htop = &hto;
374 } else {
375 to.sin_addr.s_addr = htonl (INADDR_BROADCAST);
376 to.sin_port = remote_port;
378 /* hardware address is broadcast */
379 htop = NULL;
381 to.sin_family = AF_INET;
382 #ifdef HAVE_SA_LEN
383 to.sin_len = sizeof to;
384 #endif
386 memcpy (&hto.hbuf [1], packet -> chaddr, packet -> hlen);
387 hto.hbuf [0] = packet -> htype;
388 hto.hlen = packet -> hlen + 1;
390 /* Wipe out the agent relay options and, if possible, figure
391 out which interface to use based on the contents of the
392 option that we put on the request to which the server is
393 replying. */
394 if (!(length =
395 strip_relay_agent_options (ip, &out, packet, length)))
396 return;
398 if (!out) {
399 log_error ("packet to bogus giaddr %s.\n",
400 inet_ntoa (packet -> giaddr));
401 ++bogus_giaddr_drops;
402 return;
405 if (send_packet (out,
406 (struct packet *)0,
407 packet, length, out -> primary_address,
408 &to, htop) < 0) {
409 ++server_packet_errors;
410 } else {
411 log_debug ("forwarded BOOTREPLY for %s to %s",
412 print_hw_addr (packet -> htype, packet -> hlen,
413 packet -> chaddr),
414 inet_ntoa (to.sin_addr));
416 ++server_packets_relayed;
418 return;
421 /* If giaddr matches one of our addresses, ignore the packet -
422 we just sent it. */
423 if (out)
424 return;
426 /* Add relay agent options if indicated. If something goes wrong,
427 drop the packet. */
428 if (!(length = add_relay_agent_options (ip, packet, length,
429 ip -> primary_address)))
430 return;
432 /* If giaddr is not already set, Set it so the server can
433 figure out what net it's from and so that we can later
434 forward the response to the correct net. If it's already
435 set, the response will be sent directly to the relay agent
436 that set giaddr, so we won't see it. */
437 if (!packet -> giaddr.s_addr)
438 packet -> giaddr = ip -> primary_address;
439 if (packet -> hops < max_hop_count)
440 packet -> hops = packet -> hops + 1;
441 else
442 return;
444 /* Otherwise, it's a BOOTREQUEST, so forward it to all the
445 servers. */
446 for (sp = servers; sp; sp = sp -> next) {
447 if (send_packet ((fallback_interface
448 ? fallback_interface : interfaces),
449 (struct packet *)0,
450 packet, length, ip -> primary_address,
451 &sp -> to, (struct hardware *)0) < 0) {
452 ++client_packet_errors;
453 } else {
454 log_debug ("forwarded BOOTREQUEST for %s to %s",
455 print_hw_addr (packet -> htype, packet -> hlen,
456 packet -> chaddr),
457 inet_ntoa (sp -> to.sin_addr));
458 ++client_packets_relayed;
464 static void usage ()
466 log_fatal ("Usage: dhcrelay [-p <port>] [-d] [-D] [-i %s%s%s%s",
467 "interface] [-q] [-a]\n ",
468 "[-c count] [-A length] ",
469 "[-m append|replace|forward|discard]\n",
470 " [server1 [... serverN]]");
473 int write_lease (lease)
474 struct lease *lease;
476 return 1;
479 int write_host (host)
480 struct host_decl *host;
482 return 1;
485 int commit_leases ()
487 return 1;
490 void bootp (packet)
491 struct packet *packet;
495 void dhcp (packet)
496 struct packet *packet;
500 int find_subnet (struct subnet **sp,
501 struct iaddr addr, const char *file, int line)
503 return 0;
506 #if defined (DEBUG)
507 int check_collection (struct packet *p, struct lease *l,
508 struct collection *c)
510 return 0;
513 void classify (struct packet *p, struct class *c)
517 isc_result_t find_class (struct class **class, const char *c1,
518 const char *c2, int i)
520 return ISC_R_NOTFOUND;
523 int parse_allow_deny (struct option_cache **oc, struct parse *p, int i)
525 return 0;
528 /* As a wise man once said in dhcpctl/omshell.c: */
529 /* Sigh */
530 isc_result_t dhcp_set_control_state (control_object_state_t oldstate,
531 control_object_state_t newstate)
533 return ISC_R_SUCCESS;
536 #endif
538 /* Strip any Relay Agent Information options from the DHCP packet
539 option buffer. If there is a circuit ID suboption, look up the
540 outgoing interface based upon it. */
542 int strip_relay_agent_options (in, out, packet, length)
543 struct interface_info *in, **out;
544 struct dhcp_packet *packet;
545 unsigned length;
547 int is_dhcp = 0;
548 u_int8_t *op, *sp, *max;
549 int good_agent_option = 0;
550 int status;
552 /* If we're not adding agent options to packets, we're not taking
553 them out either. */
554 if (!add_agent_options)
555 return length;
557 /* If there's no cookie, it's a bootp packet, so we should just
558 forward it unchanged. */
559 if (memcmp (packet -> options, DHCP_OPTIONS_COOKIE, 4))
560 return length;
562 max = ((u_int8_t *)packet) + length;
563 sp = op = &packet -> options [4];
565 while (op < max) {
566 switch (*op) {
567 /* Skip padding... */
568 case DHO_PAD:
569 if (sp != op)
570 *sp = *op;
571 ++op;
572 ++sp;
573 continue;
575 /* If we see a message type, it's a DHCP packet. */
576 case DHO_DHCP_MESSAGE_TYPE:
577 is_dhcp = 1;
578 goto skip;
579 break;
581 /* Quit immediately if we hit an End option. */
582 case DHO_END:
583 if (sp != op)
584 *sp++ = *op++;
585 goto out;
587 case DHO_DHCP_AGENT_OPTIONS:
588 /* We shouldn't see a relay agent option in a
589 packet before we've seen the DHCP packet type,
590 but if we do, we have to leave it alone. */
591 if (!is_dhcp)
592 goto skip;
594 status = find_interface_by_agent_option (packet,
595 out, op + 2,
596 op [1]);
597 if (status == -1 && drop_agent_mismatches)
598 return 0;
599 if (status)
600 good_agent_option = 1;
601 op += op [1] + 2;
602 break;
604 skip:
605 /* Skip over other options. */
606 default:
607 if (sp != op)
608 memcpy (sp, op, (unsigned)(op [1] + 2));
609 sp += op [1] + 2;
610 op += op [1] + 2;
611 break;
614 out:
616 /* If it's not a DHCP packet, we're not supposed to touch it. */
617 if (!is_dhcp)
618 return length;
620 /* If none of the agent options we found matched, or if we didn't
621 find any agent options, count this packet as not having any
622 matching agent options, and if we're relying on agent options
623 to determine the outgoing interface, drop the packet. */
625 if (!good_agent_option) {
626 ++missing_agent_option;
627 if (drop_agent_mismatches)
628 return 0;
631 /* Adjust the length... */
632 if (sp != op) {
633 length = sp - ((u_int8_t *)packet);
635 /* Make sure the packet isn't short (this is unlikely,
636 but WTH) */
637 if (length < BOOTP_MIN_LEN) {
638 memset (sp, 0, BOOTP_MIN_LEN - length);
639 length = BOOTP_MIN_LEN;
642 return length;
646 /* Find an interface that matches the circuit ID specified in the
647 Relay Agent Information option. If one is found, store it through
648 the pointer given; otherwise, leave the existing pointer alone.
650 We actually deviate somewhat from the current specification here:
651 if the option buffer is corrupt, we suggest that the caller not
652 respond to this packet. If the circuit ID doesn't match any known
653 interface, we suggest that the caller to drop the packet. Only if
654 we find a circuit ID that matches an existing interface do we tell
655 the caller to go ahead and process the packet. */
657 int find_interface_by_agent_option (packet, out, buf, len)
658 struct dhcp_packet *packet;
659 struct interface_info **out;
660 u_int8_t *buf;
661 int len;
663 int i = 0;
664 u_int8_t *circuit_id = 0;
665 unsigned circuit_id_len = 0;
666 struct interface_info *ip;
668 while (i < len) {
669 /* If the next agent option overflows the end of the
670 packet, the agent option buffer is corrupt. */
671 if (i + 1 == len ||
672 i + buf [i + 1] + 2 > len) {
673 ++corrupt_agent_options;
674 return -1;
676 switch (buf [i]) {
677 /* Remember where the circuit ID is... */
678 case RAI_CIRCUIT_ID:
679 circuit_id = &buf [i + 2];
680 circuit_id_len = buf [i + 1];
681 i += circuit_id_len + 2;
682 continue;
684 default:
685 i += buf [i + 1] + 2;
686 break;
690 /* If there's no circuit ID, it's not really ours, tell the caller
691 it's no good. */
692 if (!circuit_id) {
693 ++missing_circuit_id;
694 return -1;
697 /* Scan the interface list looking for an interface whose
698 name matches the one specified in circuit_id. */
700 for (ip = interfaces; ip; ip = ip -> next) {
701 if (ip -> circuit_id &&
702 ip -> circuit_id_len == circuit_id_len &&
703 !memcmp (ip -> circuit_id, circuit_id, circuit_id_len))
704 break;
707 /* If we got a match, use it. */
708 if (ip) {
709 *out = ip;
710 return 1;
713 /* If we didn't get a match, the circuit ID was bogus. */
714 ++bad_circuit_id;
715 return -1;
718 /* Examine a packet to see if it's a candidate to have a Relay
719 Agent Information option tacked onto its tail. If it is, tack
720 the option on. */
722 int add_relay_agent_options (ip, packet, length, giaddr)
723 struct interface_info *ip;
724 struct dhcp_packet *packet;
725 unsigned length;
726 struct in_addr giaddr;
728 int is_dhcp = 0, agent_options_present = 0;
729 u_int8_t *op, *sp, *max, *end_pad = 0;
731 /* If we're not adding agent options to packets, we can skip
732 this. */
733 if (!add_agent_options)
734 return length;
736 /* If there's no cookie, it's a bootp packet, so we should just
737 forward it unchanged. */
738 if (memcmp (packet -> options, DHCP_OPTIONS_COOKIE, 4))
739 return length;
741 max = ((u_int8_t *)packet) + length;
742 sp = op = &packet -> options [4];
744 while (op < max) {
745 switch (*op) {
746 /* Skip padding... */
747 case DHO_PAD:
748 end_pad = sp;
749 if (sp != op)
750 *sp = *op;
751 ++op;
752 ++sp;
753 continue;
755 /* If we see a message type, it's a DHCP packet. */
756 case DHO_DHCP_MESSAGE_TYPE:
757 is_dhcp = 1;
758 goto skip;
759 break;
761 /* Quit immediately if we hit an End option. */
762 case DHO_END:
763 goto out;
765 case DHO_DHCP_AGENT_OPTIONS:
766 /* We shouldn't see a relay agent option in a
767 packet before we've seen the DHCP packet type,
768 but if we do, we have to leave it alone. */
769 if (!is_dhcp)
770 goto skip;
771 end_pad = 0;
773 /* There's already a Relay Agent Information option
774 in this packet. How embarrassing. Decide what
775 to do based on the mode the user specified. */
777 switch (agent_relay_mode) {
778 case forward_and_append:
779 goto skip;
780 case forward_untouched:
781 return length;
782 case discard:
783 return 0;
784 case forward_and_replace:
785 default:
786 break;
789 /* Skip over the agent option and start copying
790 if we aren't copying already. */
791 op += op [1] + 2;
792 break;
794 skip:
795 /* Skip over other options. */
796 default:
797 end_pad = 0;
798 if (sp != op)
799 memcpy (sp, op, (unsigned)(op [1] + 2));
800 sp += op [1] + 2;
801 op += op [1] + 2;
802 break;
805 out:
807 /* If it's not a DHCP packet, we're not supposed to touch it. */
808 if (!is_dhcp)
809 return length;
811 /* If the packet was padded out, we can store the agent option
812 at the beginning of the padding. */
814 if (end_pad)
815 sp = end_pad;
817 /* Remember where the end of the packet was after parsing
818 it. */
819 op = sp;
821 /* XXX Is there room? */
823 /* Okay, cons up *our* Relay Agent Information option. */
824 *sp++ = DHO_DHCP_AGENT_OPTIONS;
825 *sp++ = 0; /* Dunno... */
827 /* Copy in the circuit id... */
828 *sp++ = RAI_CIRCUIT_ID;
829 /* Sanity check. Had better not every happen. */
830 if (ip -> circuit_id_len > 255 || ip -> circuit_id_len < 1)
831 log_fatal ("completely bogus circuit id length %d on %s\n",
832 ip -> circuit_id_len, ip -> name);
833 *sp++ = ip -> circuit_id_len;
834 memcpy (sp, ip -> circuit_id, ip -> circuit_id_len);
835 sp += ip -> circuit_id_len;
837 /* Copy in remote ID... */
838 if (ip -> remote_id) {
839 *sp++ = RAI_REMOTE_ID;
840 if (ip -> remote_id_len > 255 || ip -> remote_id_len < 1)
841 log_fatal ("bogus remote id length %d on %s\n",
842 ip -> circuit_id_len, ip -> name);
843 *sp++ = ip -> remote_id_len;
844 memcpy (sp, ip -> remote_id, ip -> remote_id_len);
845 sp += ip -> remote_id_len;
848 /* Relay option's total length shouldn't ever get to be more than
849 257 bytes. */
850 if (sp - op > 257)
851 log_fatal ("total agent option length exceeds 257 (%ld) on %s\n",
852 (long)(sp - op), ip -> name);
854 /* Calculate length of RAI option. */
855 op [1] = sp - op - 2;
857 /* Deposit an END token. */
858 *sp++ = DHO_END;
860 /* Recalculate total packet length. */
861 length = sp - ((u_int8_t *)packet);
863 /* Make sure the packet isn't short (this is unlikely, but WTH) */
864 if (length < BOOTP_MIN_LEN) {
865 memset (sp, 0, BOOTP_MIN_LEN - length);
866 length = BOOTP_MIN_LEN;
869 return length;