3 * Moreton Bay DHCP Server
4 * Copyright (C) 1999 Matthew Ramsay <matthewr@moreton.com.au>
5 * Chris Trew <ctrew@moreton.com.au>
7 * Modified by Wuha Team <cjyu@tecom.com.tw> Aug 2005
9 * Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
31 #include <arpa/inet.h>
33 #include <netinet/in.h>
35 #include <sys/types.h>
36 #include <sys/socket.h>
40 #include <sys/ioctl.h>
52 #include "serverpacket.h"
54 #include "pclisttab.h"
58 struct dhcpOfferedAddr *leases;
59 struct server_config_t server_config;
62 /* Exit and cleanup */
63 static void exit_server(int retval)
65 pidfile_delete(server_config.pidfile);
72 static void udhcpd_killed(int sig)
75 LOG(LOG_INFO, "Received SIGTERM");
80 #ifdef COMBINED_BINARY
81 int udhcpd(int argc, char *argv[])
83 int main(int argc, char *argv[])
88 //BRCM --initialize server_socket to -1
89 int server_socket = -1;
91 struct dhcpMessage packet;
93 char *server_id, *requested, *hostname;
94 u_int32_t server_id_align, requested_align;
95 unsigned long timeout_end;
96 struct option_set *option;
97 struct dhcpOfferedAddr *lease;
98 struct sockaddr_in *sin;
105 argc = argv[0][0]; /* get rid of some warnings */
108 LOG(LOG_INFO, "udhcp server (v%s) started", VERSION);
110 pid_fd = pidfile_acquire(server_config.pidfile);
111 pidfile_write_release(pid_fd);
113 memset(&server_config, 0, sizeof(struct server_config_t));
115 read_config(DHCPD_CONF_FILE);
116 if ((option = find_option(server_config.options, DHCP_LEASE_TIME))) {
117 memcpy(&server_config.lease, option->data + 2, 4);
118 server_config.lease = ntohl(server_config.lease);
120 else server_config.lease = LEASE_TIME;
122 leases = malloc(sizeof(struct dhcpOfferedAddr) * server_config.max_leases);
123 memset(leases, 0, sizeof(struct dhcpOfferedAddr) * server_config.max_leases);
124 read_leases(server_config.lease_file);
126 if((fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) >= 0) {
127 ifr.ifr_addr.sa_family = AF_INET;
128 strcpy(ifr.ifr_name, server_config.interface);
129 if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
130 sin = (struct sockaddr_in *) &ifr.ifr_addr;
131 server_config.server = sin->sin_addr.s_addr;
132 DEBUG(LOG_INFO, "%s (server_ip) = %s", ifr.ifr_name, inet_ntoa(sin->sin_addr));
134 LOG(LOG_ERR, "SIOCGIFADDR failed!");
137 if (ioctl(fd, SIOCGIFINDEX, &ifr) == 0) {
138 DEBUG(LOG_INFO, "adapter index %d", ifr.ifr_ifindex);
139 server_config.ifindex = ifr.ifr_ifindex;
141 LOG(LOG_ERR, "SIOCGIFINDEX failed!");
144 if (ioctl(fd, SIOCGIFHWADDR, &ifr) == 0) {
145 memcpy(server_config.arp, ifr.ifr_hwaddr.sa_data, 6);
146 DEBUG(LOG_INFO, "adapter hardware address %02x:%02x:%02x:%02x:%02x:%02x",
147 server_config.arp[0], server_config.arp[1], server_config.arp[2],
148 server_config.arp[3], server_config.arp[4], server_config.arp[5]);
150 LOG(LOG_ERR, "SIOCGIFHWADDR failed!");
154 LOG(LOG_ERR, "socket failed!");
160 pid_fd = pidfile_acquire(server_config.pidfile); /* hold lock during fork. */
167 break; /* child continues */
169 exit(0); /* parent exits */
174 pidfile_write_release(pid_fd);
178 signal(SIGUSR1, write_leases);
179 signal(SIGTERM, udhcpd_killed);
180 /* setup pclist table */
182 signal(SIGUSR2,PcListReInit);
185 timeout_end = time(0) + server_config.auto_time;
187 while(1) { /* loop until universe collapses */
189 if (server_socket < 0) {
190 server_socket = listen_socket(INADDR_ANY, SERVER_PORT, server_config.interface);
191 if(server_socket < 0) {
192 LOG(LOG_ERR, "couldn't create server socket -- au revoir");
198 FD_SET(server_socket, &rfds);
199 if (server_config.auto_time) {
200 tv.tv_sec = timeout_end - time(0);
201 if (tv.tv_sec <= 0) {
202 tv.tv_sec = server_config.auto_time;
203 timeout_end = time(0) + server_config.auto_time;
208 retval = select(server_socket + 1, &rfds, NULL, NULL, server_config.auto_time ? &tv : NULL);
211 timeout_end = time(0) + server_config.auto_time;
212 close(server_socket);
216 } else if (retval < 0) {
217 DEBUG(LOG_INFO, "error on select");
218 close(server_socket);
224 bytes = get_packet(&packet, server_socket); /* this waits for a packet - idle */
226 //close(server_socket);
230 if((state = get_option(&packet, DHCP_MESSAGE_TYPE)) == NULL) {
231 DEBUG(LOG_ERR, "couldnt get option from packet -- ignoring");
234 lease = find_lease_by_chaddr(packet.chaddr);
237 DEBUG(LOG_INFO,"received DISCOVER");
239 if (sendOffer(&packet) < 0) {
240 LOG(LOG_ERR, "send OFFER failed -- ignoring");
244 DEBUG(LOG_INFO,"received REQUEST");
246 requested = get_option(&packet, DHCP_REQUESTED_IP);
247 server_id = get_option(&packet, DHCP_SERVER_ID);
248 hostname = get_option(&packet, DHCP_HOST_NAME);
250 if (requested) memcpy(&requested_align, requested, 4);
251 if (server_id) memcpy(&server_id_align, server_id, 4);
255 /* SELECTING State */
256 DEBUG(LOG_INFO, "server_id = %08x", ntohl(server_id_align));
257 if (server_id_align == server_config.server && requested &&
258 requested_align == lease->yiaddr) {
259 sendACK(&packet, lease->yiaddr);
263 /* INIT-REBOOT State */
264 if (lease->yiaddr == requested_align)
265 sendACK(&packet, lease->yiaddr);
266 else sendNAK(&packet);
268 /* RENEWING or REBINDING State */
269 if (lease->yiaddr == packet.ciaddr)
270 sendACK(&packet, lease->yiaddr);
272 /* don't know what to do!!!! */
278 bytes = hostname[-1];
279 if (bytes >= (int) sizeof(lease->hostname))
280 bytes = sizeof(lease->hostname) - 1;
281 strncpy(lease->hostname, hostname, bytes);
282 lease->hostname[bytes] = '\0';
284 lease->hostname[0] = '\0';
285 } else { /* else remain silent */
290 DEBUG(LOG_INFO,"received DECLINE");
292 memset(lease->chaddr, 0, 16);
293 lease->expires = time(0) + server_config.decline_time;
297 DEBUG(LOG_INFO,"received RELEASE");
298 if (lease) lease->expires = time(0);
301 DEBUG(LOG_INFO,"received INFORM");
302 send_inform(&packet);
305 LOG(LOG_WARNING, "unsupported DHCP message (%02x) -- ignoring", state[0]);
309 if (server_socket > 0)
310 close(server_socket);