sd-dhcp-server.c revision 8de4a226c71ef43e652274b33b5d19211a44ac7b
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering/***
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering This file is part of systemd.
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering Copyright (C) 2013 Intel Corporation. All rights reserved.
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering Copyright (C) 2014 Tom Gundersen
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering systemd is free software; you can redistribute it and/or modify it
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering under the terms of the GNU Lesser General Public License as published by
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering (at your option) any later version.
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering systemd is distributed in the hope that it will be useful, but
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering Lesser General Public License for more details.
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering You should have received a copy of the GNU Lesser General Public License
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering***/
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering#include <sys/ioctl.h>
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering#include <netinet/if_ether.h>
3f6fd1ba65f962702753c4ad284b588e59689a23Lennart Poettering
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering#include "sd-dhcp-server.h"
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering#include "dhcp-server-internal.h"
f4f15635ec05293ffcc83a5b39f624bbabbd8fd0Lennart Poettering#include "dhcp-internal.h"
25300b5a1fcf54674a69d0f4ab08925be00b0227Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poetteringsd_dhcp_server *sd_dhcp_server_ref(sd_dhcp_server *server) {
3f6fd1ba65f962702753c4ad284b588e59689a23Lennart Poettering if (server)
3f6fd1ba65f962702753c4ad284b588e59689a23Lennart Poettering assert_se(REFCNT_INC(server->n_ref) >= 2);
3f6fd1ba65f962702753c4ad284b588e59689a23Lennart Poettering
3f6fd1ba65f962702753c4ad284b588e59689a23Lennart Poettering return server;
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering}
3f6fd1ba65f962702753c4ad284b588e59689a23Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poetteringsd_dhcp_server *sd_dhcp_server_unref(sd_dhcp_server *server) {
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering if (server && REFCNT_DEC(server->n_ref) <= 0) {
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering log_dhcp_server(server, "UNREF");
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering sd_dhcp_server_stop(server);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering sd_event_unref(server->event);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering free(server);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering }
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering return NULL;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering}
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poetteringint sd_dhcp_server_new(sd_dhcp_server **ret, int ifindex) {
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering _cleanup_dhcp_server_unref_ sd_dhcp_server *server = NULL;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering assert_return(ret, -EINVAL);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering assert_return(ifindex > 0, -EINVAL);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering server = new0(sd_dhcp_server, 1);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering if (!server)
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering return -ENOMEM;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering server->n_ref = REFCNT_INIT;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering server->fd_raw = -1;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering server->fd = -1;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering server->index = ifindex;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering *ret = server;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering server = NULL;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering return 0;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering}
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poetteringint sd_dhcp_server_attach_event(sd_dhcp_server *server, sd_event *event, int priority) {
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering int r;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering assert_return(server, -EINVAL);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering assert_return(!server->event, -EBUSY);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering if (event)
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering server->event = sd_event_ref(event);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering else {
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering r = sd_event_default(&server->event);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering if (r < 0)
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering return r;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering }
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering server->event_priority = priority;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering return 0;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering}
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poetteringint sd_dhcp_server_detach_event(sd_dhcp_server *server) {
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering assert_return(server, -EINVAL);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering server->event = sd_event_unref(server->event);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering return 0;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering}
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poetteringsd_event *sd_dhcp_server_get_event(sd_dhcp_server *server) {
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering assert_return(server, NULL);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering return server->event;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering}
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poetteringint sd_dhcp_server_stop(sd_dhcp_server *server) {
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering assert_return(server, -EINVAL);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering server->receive_message =
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering sd_event_source_unref(server->receive_message);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering server->fd_raw = safe_close(server->fd_raw);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering server->fd = safe_close(server->fd);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering log_dhcp_server(server, "STOPPED");
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering return 0;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering}
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poetteringstatic int parse_request(uint8_t code, uint8_t len, const uint8_t *option,
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering void *user_data) {
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering DHCPRequest *req = user_data;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering assert(req);
72c0a2c255b172ebbb2a2b7dab7c9aec4c9582d9Lennart Poettering
72c0a2c255b172ebbb2a2b7dab7c9aec4c9582d9Lennart Poettering switch(code) {
72c0a2c255b172ebbb2a2b7dab7c9aec4c9582d9Lennart Poettering case DHCP_OPTION_SERVER_IDENTIFIER:
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering if (len == 4)
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering req->server_id = *(be32_t*)option;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering break;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering case DHCP_OPTION_CLIENT_IDENTIFIER:
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering if (len >= 2) {
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering uint8_t *data;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering data = memdup(option, len);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering if (!data)
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering return -ENOMEM;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering free(req->client_id.data);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering req->client_id.data = data;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering req->client_id.length = len;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering }
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering break;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering case DHCP_OPTION_MAXIMUM_MESSAGE_SIZE:
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering if (len == 2)
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering req->max_optlen = be16toh(*(be16_t*)option) -
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering - sizeof(DHCPPacket);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering break;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering }
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering return 0;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering}
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poetteringstatic void dhcp_request_free(DHCPRequest *req) {
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering if (!req)
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering return;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering free(req->client_id.data);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering free(req);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering}
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart PoetteringDEFINE_TRIVIAL_CLEANUP_FUNC(DHCPRequest*, dhcp_request_free);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering#define _cleanup_dhcp_request_free_ _cleanup_(dhcp_request_freep)
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poetteringstatic int ensure_sane_request(DHCPRequest *req, DHCPMessage *message) {
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering assert(req);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering assert(message);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering req->message = message;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering /* set client id based on mac address if client did not send an explicit one */
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering if (!req->client_id.data) {
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering uint8_t *data;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering data = new0(uint8_t, ETH_ALEN + 1);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering if (!data)
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering return -ENOMEM;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering req->client_id.length = ETH_ALEN + 1;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering req->client_id.data = data;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering req->client_id.data[0] = 0x01;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering memcpy(&req->client_id.data[1], &message->chaddr, ETH_ALEN);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering }
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering if (req->max_optlen < DHCP_MIN_OPTIONS_SIZE)
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering req->max_optlen = DHCP_MIN_OPTIONS_SIZE;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering return 0;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering}
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poetteringint dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message,
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering size_t length) {
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering _cleanup_dhcp_request_free_ DHCPRequest *req = NULL;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering int type, r;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering assert(server);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering assert(message);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering if (message->op != BOOTREQUEST ||
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering message->htype != ARPHRD_ETHER ||
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering message->hlen != ETHER_ADDR_LEN)
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering return 0;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering req = new0(DHCPRequest, 1);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering if (!req)
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering return -ENOMEM;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering type = dhcp_option_parse(message, length, parse_request, req);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering if (type < 0)
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering return 0;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering r = ensure_sane_request(req, message);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering if (r < 0)
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering /* this only fails on critical errors */
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering return r;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
72c0a2c255b172ebbb2a2b7dab7c9aec4c9582d9Lennart Poettering log_dhcp_server(server, "received message of type %d", type);
72c0a2c255b172ebbb2a2b7dab7c9aec4c9582d9Lennart Poettering
72c0a2c255b172ebbb2a2b7dab7c9aec4c9582d9Lennart Poettering return 1;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering}
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poetteringstatic int server_receive_message(sd_event_source *s, int fd,
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering uint32_t revents, void *userdata) {
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering _cleanup_free_ DHCPMessage *message = NULL;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering uint8_t cmsgbuf[CMSG_LEN(sizeof(struct in_pktinfo))];
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering sd_dhcp_server *server = userdata;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering struct iovec iov = {};
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering struct msghdr msg = {
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering .msg_iov = &iov,
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering .msg_iovlen = 1,
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering .msg_control = cmsgbuf,
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering .msg_controllen = sizeof(cmsgbuf),
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering };
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering struct cmsghdr *cmsg;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering int buflen = 0, len, r;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering assert(server);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering r = ioctl(fd, FIONREAD, &buflen);
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering if (r < 0)
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering return r;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering if (buflen < 0)
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering return -EIO;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering message = malloc0(buflen);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering if (!message)
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering return -ENOMEM;
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering iov.iov_base = message;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering iov.iov_len = buflen;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering len = recvmsg(fd, &msg, 0);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering if (len < buflen)
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering return 0;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering else if ((size_t)len < sizeof(DHCPMessage))
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering return 0;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering if (cmsg->cmsg_level == IPPROTO_IP &&
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering cmsg->cmsg_type == IP_PKTINFO &&
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering cmsg->cmsg_len == CMSG_LEN(sizeof(struct in_pktinfo))) {
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering struct in_pktinfo *info = (struct in_pktinfo*)CMSG_DATA(cmsg);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering /* TODO figure out if this can be done as a filter on the socket, like for IPv6 */
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering if (server->index != info->ipi_ifindex)
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering return 0;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering break;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering }
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering }
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering return dhcp_server_handle_message(server, message, (size_t)len);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering}
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poetteringint sd_dhcp_server_start(sd_dhcp_server *server) {
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering int r;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering assert_return(server, -EINVAL);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering assert_return(server->event, -EINVAL);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering assert_return(!server->receive_message, -EBUSY);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering assert_return(server->fd_raw == -1, -EBUSY);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering assert_return(server->fd == -1, -EBUSY);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering r = socket(AF_PACKET, SOCK_DGRAM | SOCK_NONBLOCK, 0);
3f6fd1ba65f962702753c4ad284b588e59689a23Lennart Poettering if (r < 0) {
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering r = -errno;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering sd_dhcp_server_stop(server);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering return r;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering }
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering server->fd_raw = r;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering r = dhcp_network_bind_udp_socket(INADDR_ANY, DHCP_PORT_SERVER);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering if (r < 0) {
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering sd_dhcp_server_stop(server);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering return r;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering }
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering server->fd = r;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering r = sd_event_add_io(server->event, &server->receive_message,
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering server->fd, EPOLLIN,
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering server_receive_message, server);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering if (r < 0) {
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering sd_dhcp_server_stop(server);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering return r;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering }
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering r = sd_event_source_set_priority(server->receive_message,
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering server->event_priority);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering if (r < 0) {
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering sd_dhcp_server_stop(server);
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering return r;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering }
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering log_dhcp_server(server, "STARTED");
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering return 0;
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering}
b6e676ce41508e2aeea22202fc8f234126177f52Lennart Poettering