📄 dhcpd.c
字号:
/* Send the offer response */ return dhcpd_sendpacket(FALSE);}/**************************************************************************** * Name: dhcpd_sendnak ****************************************************************************/static int dhcpd_sendnak(void){ /* Initialize and send the NAK response */ dhcpd_initpacket(DHCPNAK); memcpy(g_state.ds_outpacket.ciaddr, g_state.ds_inpacket.ciaddr, 4); return dhcpd_sendpacket(TRUE);}/**************************************************************************** * Name: dhcpd_sendack ****************************************************************************/int dhcpd_sendack(in_addr_t ipaddr){ uint32 leasetime = CONFIG_NETUTILS_DHCPD_LEASETIME; /* Initialize the ACK response */ dhcpd_initpacket(DHCPACK); memcpy(g_state.ds_outpacket.ciaddr, g_state.ds_inpacket.ciaddr, 4); /* Add the IP address assigned to the client */ memcpy(g_state.ds_outpacket.yiaddr, &ipaddr, 4); /* Did the client request a specific lease time? */ (void)dhcpd_verifyreqleasetime(&leasetime); /* Add the lease time to the response */ dhcpd_addoption32(DHCP_OPTION_LEASE_TIME, htonl(leasetime)); if (dhcpd_sendpacket(FALSE) < 0) { return ERROR; } dhcpd_setlease(g_state.ds_inpacket.chaddr, ipaddr, leasetime); return OK;}/**************************************************************************** * Name: dhcpd_discover ****************************************************************************/static inline int dhcpd_discover(void){ struct lease_s *lease; in_addr_t ipaddr; uint32 leasetime = CONFIG_NETUTILS_DHCPD_LEASETIME; /* Check if the client is aleady in the lease table */ lease = dhcpd_findbymac(g_state.ds_inpacket.chaddr); if (lease) { /* Yes... get the remaining time on the lease */#ifdef HAVE_LEASE_TIME if (!dhcpd_leaseexpired(lease)) { leasetime = lease->expiry - dhcpd_time(); if (leasetime < CONFIG_NETUTILS_DHCPD_MINLEASETIME) { leasetime = CONFIG_NETUTILS_DHCPD_MINLEASETIME; } }#endif /* Get the IP address associated with the lease */ ipaddr = dhcp_leaseipaddr(lease); } /* Check if the client has requested a specific IP address */ else if (dhcpd_verifyreqip()) { /* Use the requested IP address */ ipaddr = g_state.ds_optreqip; } else { /* No... allocate a new IP address */ ipaddr = dhcpd_allocipaddr(); } /* Did we get any IP address? */ if (!ipaddr) { /* Nope... return failure */ dbg("Failed to get IP address\n"); return ERROR; } /* Reserve the leased IP for a shorter time for the offer */ if (!dhcpd_setlease(g_state.ds_inpacket.chaddr, ipaddr, CONFIG_NETUTILS_DHCPD_OFFERTIME)) { dbg("Failed to set lease\n"); return ERROR; } /* Check if the client has requested a specific lease time */ (void)dhcpd_verifyreqleasetime(&leasetime); /* Send the offer response */ return dhcpd_sendoffer(ipaddr, leasetime);}/**************************************************************************** * Name: dhcpd_request ****************************************************************************/static inline int dhcpd_request(void){ struct lease_s *lease; in_addr_t ipaddr; uint8 response = 0; /* Check if this client already holds a lease. This can happen when the client (1) * the IP is reserved for the client from a previous offer, or (2) the client is * re-initializing or rebooting while the lease is still valid. */ lease = dhcpd_findbymac(g_state.ds_inpacket.chaddr); if (lease) { /* Yes.. the client already holds a lease. Verify that the request is consistent * with the existing lease. */ ipaddr = dhcp_leaseipaddr(lease); if (g_state.ds_optserverip) { /* ACK if the serverip is correct and the requested IP address is the one * already offered to the client. */ if (g_state.ds_optserverip == ntohl(g_state.ds_serverip) && (g_state.ds_optreqip != 0 || g_state.ds_optreqip == ipaddr)) { response = DHCPACK; } else { response = DHCPNAK; } } /* We have the lease and no server IP was requested. Was as specific IP address * requested? */ else if (g_state.ds_optreqip) { /* Yes..ACK if the requested IP address is the one already leased */ if (ipaddr == g_state.ds_optreqip) { response = DHCPACK; } else { response = DHCPNAK; } } /* The client has specified neither a server IP nor requested IP address */ else { /* ACK if the IP used by the client is the one already assigned to it */ if (memcmp(&ipaddr, g_state.ds_inpacket.ciaddr, 4) == 0) { response = DHCPACK; } else { response = DHCPNAK; } } } /* The client does not hold a lease (referenced by its MAC address) and is * requesting a specific IP address that was, apparently, never offered to * to the client. Perform some sanity checks before sending the NAK. */ else if (g_state.ds_optreqip && !g_state.ds_optserverip) { /* Is this IP address already assigned? */ lease = dhcpd_findbyipaddr(g_state.ds_optreqip); if (lease) { /* Yes.. Send NAK unless the lease has expired */ if (!dhcpd_leaseexpired(lease)) { response = DHCPNAK; } } /* No.. is the requested IP address in range? NAK if not */ else if (g_state.ds_optreqip < CONFIG_NETUTILS_DHCPD_STARTIP || g_state.ds_optreqip > CONFIG_NETUTILS_DHCP_OPTION_ENDIP) { response = DHCPNAK; } } /* Finally, either (1) send the ACK, (2) send a NAK, or (3) remain silent * based on the checks above. */ if (response == DHCPACK) { dhcpd_sendack(ipaddr); } else if (response == DHCPNAK) { dhcpd_sendnak(); } return OK;}/**************************************************************************** * Name: dhcpd_decline ****************************************************************************/static inline int dhcpd_decline(void){ struct lease_s *lease; /* Find the lease associated with this hardware address */ lease = dhcpd_findbymac(g_state.ds_inpacket.chaddr); if (lease) { /* Disassociate the IP from the MAC, but prevent re-used of this * address for a period of time. */ memset(lease->mac, 0, DHCP_HLEN_ETHERNET);#ifdef HAVE_LEASE_TIME lease->expiry = dhcpd_time() + CONFIG_NETUTILS_DHCPD_DECLINETIME;#endif } return OK;}static inline int dhcpd_release(void){ struct lease_s *lease; /* Find the lease associated with this hardware address */ lease = dhcpd_findbymac(g_state.ds_inpacket.chaddr); if (lease) { /* Release the IP address now */ memset(lease, 0, sizeof(struct lease_s)); } return OK;}/**************************************************************************** * Name: dhcpd_openlistener ****************************************************************************/static inline int dhcpd_openlistener(void){ struct sockaddr_in addr; struct ifreq req; int sockfd; int ret; /* Create a socket to listen for requests from DHCP clients */ sockfd = dhcpd_socket(); if (sockfd < 0) { dbg("socket failed: %d\n", errno); return ERROR; } /* Get the IP address of the selected device */ strncpy(req.ifr_name, CONFIG_NETUTILS_DHCPD_INTERFACE, IFNAMSIZ); ret = ioctl(sockfd, SIOCGIFADDR, (unsigned long)&req); if (ret < 0) { dbg("setsockopt SIOCGIFADDR failed: %d\n", errno); close(sockfd); return ERROR; } g_state.ds_serverip = ((struct sockaddr_in*)&req.ifr_addr)->sin_addr.s_addr; vdbg("serverip: %08x\n", ntohl(g_state.ds_serverip)); /* Bind the socket to a local port. We have to bind to INADDRY_ANY to * receive broadcast messages. */ addr.sin_family = AF_INET; addr.sin_port = htons(DHCP_SERVER_PORT); addr.sin_addr.s_addr = INADDR_ANY; ret = bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)); if (ret < 0) { dbg("bind failed: %d\n", errno); close(sockfd); return ERROR; } return sockfd;}/**************************************************************************** * Public Functions ****************************************************************************//**************************************************************************** * Name: dhcpd_run ****************************************************************************/int dhcpd_run(void){ int sockfd; int nbytes; vdbg("Started\n"); /* Initialize everything to zero */ memset(&g_state, 0, sizeof(struct dhcpd_state_s)); /* Now loop indefinitely, reading packets from the DHCP server socket */ sockfd = -1; for (;;) { /* Create a socket to listen for requests from DHCP clients */ if (sockfd < 0) { sockfd = dhcpd_openlistener(); if (sockfd < 0) { dbg("Failed to create socket\n"); break; } } /* Read the next g_state.ds_outpacket */ nbytes = recv(sockfd, &g_state.ds_inpacket, sizeof(struct dhcpmsg_s), 0); if (nbytes < 0) { /* On errors (other EINTR), close the socket and try again */ dbg("recv failed: %d\n", errno); if (errno != EINTR) { close(sockfd); sockfd = -1; } continue; } /* Parse the incoming message options */ if (!dhcpd_parseoptions()) { /* Failed to parse the message options */ dbg("No msg type\n"); continue; }#ifdef CONFIG_NETUTILS_DHCPD_HOST /* Get the poor little uC a change to get its recvfrom in place */ usleep(500*1000);#endif /* Now process the incoming DHCP message by its message type */ switch (g_state.ds_optmsgtype) { case DHCPDISCOVER: vdbg("DHCPDISCOVER\n"); dhcpd_discover(); break; case DHCPREQUEST: vdbg("DHCPREQUEST\n"); dhcpd_request(); break; case DHCPDECLINE: vdbg("DHCPDECLINE\n"); dhcpd_decline(); break; case DHCPRELEASE: vdbg("DHCPRELEASE\n"); dhcpd_release(); break; case DHCPINFORM: /* Not supported */ default: dbg("Unsupported message type: %d\n", g_state.ds_optmsgtype); break; } } return OK;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -