Contents of /trunk/mkinitrd-magellan/busybox/networking/udhcp/dhcpd.c
Parent Directory | Revision Log
Revision 532 -
(show annotations)
(download)
Sat Sep 1 22:45:15 2007 UTC (16 years, 8 months ago) by niro
File MIME type: text/plain
File size: 6124 byte(s)
Sat Sep 1 22:45:15 2007 UTC (16 years, 8 months ago) by niro
File MIME type: text/plain
File size: 6124 byte(s)
-import if magellan mkinitrd; it is a fork of redhats mkinitrd-5.0.8 with all magellan patches and features; deprecates magellan-src/mkinitrd
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 | } |
74 | |
75 | max_sock = udhcp_sp_fd_set(&rfds, server_socket); |
76 | if (server_config.auto_time) { |
77 | tv.tv_sec = timeout_end - time(0); |
78 | tv.tv_usec = 0; |
79 | } |
80 | if (!server_config.auto_time || tv.tv_sec > 0) { |
81 | retval = select(max_sock + 1, &rfds, NULL, NULL, |
82 | server_config.auto_time ? &tv : NULL); |
83 | } else retval = 0; /* If we already timed out, fall through */ |
84 | |
85 | if (retval == 0) { |
86 | write_leases(); |
87 | timeout_end = time(0) + server_config.auto_time; |
88 | continue; |
89 | } else if (retval < 0 && errno != EINTR) { |
90 | DEBUG("error on select"); |
91 | continue; |
92 | } |
93 | |
94 | switch (udhcp_sp_read(&rfds)) { |
95 | case SIGUSR1: |
96 | bb_info_msg("Received a SIGUSR1"); |
97 | write_leases(); |
98 | /* why not just reset the timeout, eh */ |
99 | timeout_end = time(0) + server_config.auto_time; |
100 | continue; |
101 | case SIGTERM: |
102 | bb_info_msg("Received a SIGTERM"); |
103 | return 0; |
104 | case 0: break; /* no signal */ |
105 | default: continue; /* signal or error (probably EINTR) */ |
106 | } |
107 | |
108 | if ((bytes = udhcp_get_packet(&packet, server_socket)) < 0) { /* this waits for a packet - idle */ |
109 | if (bytes == -1 && errno != EINTR) { |
110 | DEBUG("error on read, %s, reopening socket", strerror(errno)); |
111 | close(server_socket); |
112 | server_socket = -1; |
113 | } |
114 | continue; |
115 | } |
116 | |
117 | if ((state = get_option(&packet, DHCP_MESSAGE_TYPE)) == NULL) { |
118 | bb_error_msg("cannot get option from packet, ignoring"); |
119 | continue; |
120 | } |
121 | |
122 | /* Look for a static lease */ |
123 | static_lease_ip = getIpByMac(server_config.static_leases, &packet.chaddr); |
124 | |
125 | if (static_lease_ip) { |
126 | bb_info_msg("Found static lease: %x", static_lease_ip); |
127 | |
128 | memcpy(&static_lease.chaddr, &packet.chaddr, 16); |
129 | static_lease.yiaddr = static_lease_ip; |
130 | static_lease.expires = 0; |
131 | |
132 | lease = &static_lease; |
133 | |
134 | } else { |
135 | lease = find_lease_by_chaddr(packet.chaddr); |
136 | } |
137 | |
138 | switch (state[0]) { |
139 | case DHCPDISCOVER: |
140 | DEBUG("Received DISCOVER"); |
141 | |
142 | if (sendOffer(&packet) < 0) { |
143 | bb_error_msg("send OFFER failed"); |
144 | } |
145 | break; |
146 | case DHCPREQUEST: |
147 | DEBUG("received REQUEST"); |
148 | |
149 | requested = get_option(&packet, DHCP_REQUESTED_IP); |
150 | server_id = get_option(&packet, DHCP_SERVER_ID); |
151 | |
152 | if (requested) memcpy(&requested_align, requested, 4); |
153 | if (server_id) memcpy(&server_id_align, server_id, 4); |
154 | |
155 | if (lease) { |
156 | if (server_id) { |
157 | /* SELECTING State */ |
158 | DEBUG("server_id = %08x", ntohl(server_id_align)); |
159 | if (server_id_align == server_config.server && requested && |
160 | requested_align == lease->yiaddr) { |
161 | sendACK(&packet, lease->yiaddr); |
162 | } |
163 | } else { |
164 | if (requested) { |
165 | /* INIT-REBOOT State */ |
166 | if (lease->yiaddr == requested_align) |
167 | sendACK(&packet, lease->yiaddr); |
168 | else sendNAK(&packet); |
169 | } else { |
170 | /* RENEWING or REBINDING State */ |
171 | if (lease->yiaddr == packet.ciaddr) |
172 | sendACK(&packet, lease->yiaddr); |
173 | else { |
174 | /* don't know what to do!!!! */ |
175 | sendNAK(&packet); |
176 | } |
177 | } |
178 | } |
179 | |
180 | /* what to do if we have no record of the client */ |
181 | } else if (server_id) { |
182 | /* SELECTING State */ |
183 | |
184 | } else if (requested) { |
185 | /* INIT-REBOOT State */ |
186 | if ((lease = find_lease_by_yiaddr(requested_align))) { |
187 | if (lease_expired(lease)) { |
188 | /* probably best if we drop this lease */ |
189 | memset(lease->chaddr, 0, 16); |
190 | /* make some contention for this address */ |
191 | } else sendNAK(&packet); |
192 | } else if (requested_align < server_config.start || |
193 | requested_align > server_config.end) { |
194 | sendNAK(&packet); |
195 | } /* else remain silent */ |
196 | |
197 | } else { |
198 | /* RENEWING or REBINDING State */ |
199 | } |
200 | break; |
201 | case DHCPDECLINE: |
202 | DEBUG("Received DECLINE"); |
203 | if (lease) { |
204 | memset(lease->chaddr, 0, 16); |
205 | lease->expires = time(0) + server_config.decline_time; |
206 | } |
207 | break; |
208 | case DHCPRELEASE: |
209 | DEBUG("Received RELEASE"); |
210 | if (lease) lease->expires = time(0); |
211 | break; |
212 | case DHCPINFORM: |
213 | DEBUG("Received INFORM"); |
214 | send_inform(&packet); |
215 | break; |
216 | default: |
217 | bb_info_msg("Unsupported DHCP message (%02x) - ignoring", state[0]); |
218 | } |
219 | } |
220 | |
221 | return 0; |
222 | } |