static gboolean listener_event(GIOChannel *channel, GIOCondition condition, gpointer user_data) { GDHCPServer *dhcp_server = user_data; struct dhcp_packet packet; struct dhcp_lease *lease; uint32_t requested_nip = 0; uint8_t type, *server_id_option, *request_ip_option, *host_name; int re; GDHCPOptionType option_type; char *option_value; if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) { dhcp_server->listener_watch = 0; return FALSE; } re = dhcp_recv_l3_packet(&packet, dhcp_server->listener_sockfd); if (re < 0) return TRUE; type = check_packet_type(&packet); if (type == 0) return TRUE; server_id_option = dhcp_get_option(&packet, DHCP_SERVER_ID); if (server_id_option) { uint32_t server_nid = get_be32(server_id_option); if (server_nid != dhcp_server->server_nip) return TRUE; } request_ip_option = dhcp_get_option(&packet, DHCP_REQUESTED_IP); if (request_ip_option) requested_nip = get_be32(request_ip_option); lease = find_lease_by_mac(dhcp_server, packet.chaddr); switch (type) { case DHCPDISCOVER: debug(dhcp_server, "Received DISCOVER"); send_offer(dhcp_server, &packet, lease, requested_nip); break; case DHCPREQUEST: debug(dhcp_server, "Received REQUEST NIP %d", requested_nip); if (requested_nip == 0) { requested_nip = packet.ciaddr; if (requested_nip == 0) break; } if (lease && requested_nip == lease->lease_nip) { debug(dhcp_server, "Sending ACK"); host_name = dhcp_get_option(&packet, DHCP_HOST_NAME); option_type = dhcp_get_code_type(DHCP_HOST_NAME); option_value = malloc_option_value_string(host_name, option_type); send_ACK(dhcp_server, &packet, lease->lease_nip); if (dhcp_server->save_ack_lease_func) dhcp_server->save_ack_lease_func( option_value, lease->lease_mac, lease->lease_nip); g_free(option_value); break; } if (server_id_option || !lease) { debug(dhcp_server, "Sending NAK"); send_NAK(dhcp_server, &packet); } break; case DHCPDECLINE: debug(dhcp_server, "Received DECLINE"); if (!server_id_option) break; if (!request_ip_option) break; if (!lease) break; if (requested_nip == lease->lease_nip) remove_lease(dhcp_server, lease); break; case DHCPRELEASE: debug(dhcp_server, "Received RELEASE"); if (!server_id_option) break; if (!lease) break; if (packet.ciaddr == lease->lease_nip) lease_set_expire(dhcp_server, lease, time(NULL)); break; case DHCPINFORM: debug(dhcp_server, "Received INFORM"); send_inform(dhcp_server, &packet); break; } return TRUE; }
static gboolean listener_event(GIOChannel *channel, GIOCondition condition, gpointer user_data) { GDHCPServer *dhcp_server = user_data; struct dhcp_packet packet; struct dhcp_lease *lease; uint32_t requested_nip = 0; uint8_t type, *server_id_option, *request_ip_option; int re; if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) { dhcp_server->listener_watch = 0; return FALSE; } re = dhcp_recv_l3_packet(&packet, dhcp_server->listener_sockfd); if (re < 0) return TRUE; type = check_packet_type(&packet); if (type == 0) return TRUE; server_id_option = dhcp_get_option(&packet, DHCP_SERVER_ID); if (server_id_option) { uint32_t server_nid = dhcp_get_unaligned( (uint32_t *) server_id_option); if (server_nid != dhcp_server->server_nip) return TRUE; } request_ip_option = dhcp_get_option(&packet, DHCP_REQUESTED_IP); if (request_ip_option) requested_nip = dhcp_get_unaligned( (uint32_t *) request_ip_option); lease = find_lease_by_mac(dhcp_server, packet.chaddr); switch (type) { case DHCPDISCOVER: debug(dhcp_server, "Received DISCOVER"); send_offer(dhcp_server, &packet, lease, requested_nip); break; case DHCPREQUEST: debug(dhcp_server, "Received REQUEST NIP %d", requested_nip); if (requested_nip == 0) { requested_nip = packet.ciaddr; if (requested_nip == 0) break; } if (lease && requested_nip == lease->lease_nip) { debug(dhcp_server, "Sending ACK"); send_ACK(dhcp_server, &packet, lease->lease_nip); break; } if (server_id_option || lease == NULL) { debug(dhcp_server, "Sending NAK"); send_NAK(dhcp_server, &packet); } break; case DHCPDECLINE: debug(dhcp_server, "Received DECLINE"); if (server_id_option == NULL) break; if (request_ip_option == NULL) break; if (lease == NULL) break; if (requested_nip == lease->lease_nip) remove_lease(dhcp_server, lease); break; case DHCPRELEASE: debug(dhcp_server, "Received RELEASE"); if (server_id_option == NULL) break; if (lease == NULL) break; if (packet.ciaddr == lease->lease_nip) lease_set_expire(dhcp_server, lease, time(NULL)); break; case DHCPINFORM: debug(dhcp_server, "Received INFORM"); send_inform(dhcp_server, &packet); break; } return TRUE; }