diff options
Diffstat (limited to 'networking/udhcp/dhcpd.c')
-rw-r--r-- | networking/udhcp/dhcpd.c | 226 |
1 files changed, 226 insertions, 0 deletions
diff --git a/networking/udhcp/dhcpd.c b/networking/udhcp/dhcpd.c new file mode 100644 index 000000000..74380367f --- /dev/null +++ b/networking/udhcp/dhcpd.c | |||
@@ -0,0 +1,226 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* dhcpd.c | ||
3 | * | ||
4 | * udhcp Server | ||
5 | * Copyright (C) 1999 Matthew Ramsay <matthewr@moreton.com.au> | ||
6 | * Chris Trew <ctrew@moreton.com.au> | ||
7 | * | ||
8 | * Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001 | ||
9 | * | ||
10 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. | ||
11 | */ | ||
12 | |||
13 | #include "common.h" | ||
14 | #include "dhcpd.h" | ||
15 | #include "options.h" | ||
16 | |||
17 | |||
18 | /* globals */ | ||
19 | struct dhcpOfferedAddr *leases; | ||
20 | struct server_config_t server_config; | ||
21 | |||
22 | |||
23 | int udhcpd_main(int argc, char *argv[]) | ||
24 | { | ||
25 | fd_set rfds; | ||
26 | struct timeval tv; | ||
27 | int server_socket = -1, bytes, retval, max_sock; | ||
28 | struct dhcpMessage packet; | ||
29 | uint8_t *state, *server_id, *requested; | ||
30 | uint32_t server_id_align, requested_align, static_lease_ip; | ||
31 | unsigned long timeout_end, num_ips; | ||
32 | struct option_set *option; | ||
33 | struct dhcpOfferedAddr *lease, static_lease; | ||
34 | |||
35 | read_config(argc < 2 ? DHCPD_CONF_FILE : argv[1]); | ||
36 | |||
37 | /* Start the log, sanitize fd's, and write a pid file */ | ||
38 | udhcp_start_log_and_pid(server_config.pidfile); | ||
39 | |||
40 | if ((option = find_option(server_config.options, DHCP_LEASE_TIME))) { | ||
41 | memcpy(&server_config.lease, option->data + 2, 4); | ||
42 | server_config.lease = ntohl(server_config.lease); | ||
43 | } | ||
44 | else server_config.lease = LEASE_TIME; | ||
45 | |||
46 | /* Sanity check */ | ||
47 | num_ips = ntohl(server_config.end) - ntohl(server_config.start) + 1; | ||
48 | if (server_config.max_leases > num_ips) { | ||
49 | bb_error_msg("max_leases value (%lu) not sane, " | ||
50 | "setting to %lu instead", | ||
51 | server_config.max_leases, num_ips); | ||
52 | server_config.max_leases = num_ips; | ||
53 | } | ||
54 | |||
55 | leases = xzalloc(server_config.max_leases * sizeof(struct dhcpOfferedAddr)); | ||
56 | read_leases(server_config.lease_file); | ||
57 | |||
58 | if (read_interface(server_config.interface, &server_config.ifindex, | ||
59 | &server_config.server, server_config.arp) < 0) | ||
60 | return 1; | ||
61 | |||
62 | if (!ENABLE_FEATURE_UDHCP_DEBUG) | ||
63 | udhcp_background(server_config.pidfile); /* hold lock during fork. */ | ||
64 | |||
65 | /* Setup the signal pipe */ | ||
66 | udhcp_sp_setup(); | ||
67 | |||
68 | timeout_end = time(0) + server_config.auto_time; | ||
69 | while (1) { /* loop until universe collapses */ | ||
70 | |||
71 | if (server_socket < 0) { | ||
72 | server_socket = listen_socket(INADDR_ANY, SERVER_PORT, server_config.interface); | ||
73 | if (server_socket < 0) { | ||
74 | bb_perror_msg("FATAL: cannot create server socket"); | ||
75 | return 2; | ||
76 | } | ||
77 | } | ||
78 | |||
79 | max_sock = udhcp_sp_fd_set(&rfds, server_socket); | ||
80 | if (server_config.auto_time) { | ||
81 | tv.tv_sec = timeout_end - time(0); | ||
82 | tv.tv_usec = 0; | ||
83 | } | ||
84 | if (!server_config.auto_time || tv.tv_sec > 0) { | ||
85 | retval = select(max_sock + 1, &rfds, NULL, NULL, | ||
86 | server_config.auto_time ? &tv : NULL); | ||
87 | } else retval = 0; /* If we already timed out, fall through */ | ||
88 | |||
89 | if (retval == 0) { | ||
90 | write_leases(); | ||
91 | timeout_end = time(0) + server_config.auto_time; | ||
92 | continue; | ||
93 | } else if (retval < 0 && errno != EINTR) { | ||
94 | DEBUG("error on select"); | ||
95 | continue; | ||
96 | } | ||
97 | |||
98 | switch (udhcp_sp_read(&rfds)) { | ||
99 | case SIGUSR1: | ||
100 | bb_info_msg("Received a SIGUSR1"); | ||
101 | write_leases(); | ||
102 | /* why not just reset the timeout, eh */ | ||
103 | timeout_end = time(0) + server_config.auto_time; | ||
104 | continue; | ||
105 | case SIGTERM: | ||
106 | bb_info_msg("Received a SIGTERM"); | ||
107 | return 0; | ||
108 | case 0: break; /* no signal */ | ||
109 | default: continue; /* signal or error (probably EINTR) */ | ||
110 | } | ||
111 | |||
112 | if ((bytes = udhcp_get_packet(&packet, server_socket)) < 0) { /* this waits for a packet - idle */ | ||
113 | if (bytes == -1 && errno != EINTR) { | ||
114 | DEBUG("error on read, %s, reopening socket", strerror(errno)); | ||
115 | close(server_socket); | ||
116 | server_socket = -1; | ||
117 | } | ||
118 | continue; | ||
119 | } | ||
120 | |||
121 | if ((state = get_option(&packet, DHCP_MESSAGE_TYPE)) == NULL) { | ||
122 | bb_error_msg("cannot get option from packet, ignoring"); | ||
123 | continue; | ||
124 | } | ||
125 | |||
126 | /* Look for a static lease */ | ||
127 | static_lease_ip = getIpByMac(server_config.static_leases, &packet.chaddr); | ||
128 | |||
129 | if (static_lease_ip) { | ||
130 | bb_info_msg("Found static lease: %x", static_lease_ip); | ||
131 | |||
132 | memcpy(&static_lease.chaddr, &packet.chaddr, 16); | ||
133 | static_lease.yiaddr = static_lease_ip; | ||
134 | static_lease.expires = 0; | ||
135 | |||
136 | lease = &static_lease; | ||
137 | |||
138 | } else { | ||
139 | lease = find_lease_by_chaddr(packet.chaddr); | ||
140 | } | ||
141 | |||
142 | switch (state[0]) { | ||
143 | case DHCPDISCOVER: | ||
144 | DEBUG("Received DISCOVER"); | ||
145 | |||
146 | if (sendOffer(&packet) < 0) { | ||
147 | bb_error_msg("send OFFER failed"); | ||
148 | } | ||
149 | break; | ||
150 | case DHCPREQUEST: | ||
151 | DEBUG("received REQUEST"); | ||
152 | |||
153 | requested = get_option(&packet, DHCP_REQUESTED_IP); | ||
154 | server_id = get_option(&packet, DHCP_SERVER_ID); | ||
155 | |||
156 | if (requested) memcpy(&requested_align, requested, 4); | ||
157 | if (server_id) memcpy(&server_id_align, server_id, 4); | ||
158 | |||
159 | if (lease) { | ||
160 | if (server_id) { | ||
161 | /* SELECTING State */ | ||
162 | DEBUG("server_id = %08x", ntohl(server_id_align)); | ||
163 | if (server_id_align == server_config.server && requested && | ||
164 | requested_align == lease->yiaddr) { | ||
165 | sendACK(&packet, lease->yiaddr); | ||
166 | } | ||
167 | } else { | ||
168 | if (requested) { | ||
169 | /* INIT-REBOOT State */ | ||
170 | if (lease->yiaddr == requested_align) | ||
171 | sendACK(&packet, lease->yiaddr); | ||
172 | else sendNAK(&packet); | ||
173 | } else { | ||
174 | /* RENEWING or REBINDING State */ | ||
175 | if (lease->yiaddr == packet.ciaddr) | ||
176 | sendACK(&packet, lease->yiaddr); | ||
177 | else { | ||
178 | /* don't know what to do!!!! */ | ||
179 | sendNAK(&packet); | ||
180 | } | ||
181 | } | ||
182 | } | ||
183 | |||
184 | /* what to do if we have no record of the client */ | ||
185 | } else if (server_id) { | ||
186 | /* SELECTING State */ | ||
187 | |||
188 | } else if (requested) { | ||
189 | /* INIT-REBOOT State */ | ||
190 | if ((lease = find_lease_by_yiaddr(requested_align))) { | ||
191 | if (lease_expired(lease)) { | ||
192 | /* probably best if we drop this lease */ | ||
193 | memset(lease->chaddr, 0, 16); | ||
194 | /* make some contention for this address */ | ||
195 | } else sendNAK(&packet); | ||
196 | } else if (requested_align < server_config.start || | ||
197 | requested_align > server_config.end) { | ||
198 | sendNAK(&packet); | ||
199 | } /* else remain silent */ | ||
200 | |||
201 | } else { | ||
202 | /* RENEWING or REBINDING State */ | ||
203 | } | ||
204 | break; | ||
205 | case DHCPDECLINE: | ||
206 | DEBUG("Received DECLINE"); | ||
207 | if (lease) { | ||
208 | memset(lease->chaddr, 0, 16); | ||
209 | lease->expires = time(0) + server_config.decline_time; | ||
210 | } | ||
211 | break; | ||
212 | case DHCPRELEASE: | ||
213 | DEBUG("Received RELEASE"); | ||
214 | if (lease) lease->expires = time(0); | ||
215 | break; | ||
216 | case DHCPINFORM: | ||
217 | DEBUG("Received INFORM"); | ||
218 | send_inform(&packet); | ||
219 | break; | ||
220 | default: | ||
221 | bb_info_msg("Unsupported DHCP message (%02x) - ignoring", state[0]); | ||
222 | } | ||
223 | } | ||
224 | |||
225 | return 0; | ||
226 | } | ||