[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[tyndur-devel] [PATCH v2 5/5] tcpip: DHCP-Unterstützung
+ tcpip: Der eigentliche DHCP-Prozess kann jetzt durchgeführt werden
(solange keine Fehler auftreten jedenfalls...), dazu muss 'fetch' nach
tcpip:/$TREIBER/0/dhcp geschrieben werden. Wird stattdessen
'configure' geschrieben, wird die Karte mit den Informationen
konfiguriert. Zurückgeben kann man ein Lease noch nicht.
Signed-off-by: Kevin Wolf <kevin@xxxxxxxxxx>
---
src/modules/tcpip/dhcp.c | 435 +++++++++++++++++++++++++++++++++
src/modules/tcpip/include/dhcp.h | 47 ++++
src/modules/tcpip/include/ip.h | 1 +
src/modules/tcpip/include/lostio_if.h | 1 +
src/modules/tcpip/include/main.h | 3 +
src/modules/tcpip/ip.c | 15 ++
src/modules/tcpip/lostio_if.c | 4 +
src/modules/tcpip/main.c | 4 +-
8 files changed, 508 insertions(+), 2 deletions(-)
create mode 100644 src/modules/tcpip/dhcp.c
create mode 100644 src/modules/tcpip/include/dhcp.h
diff --git a/src/modules/tcpip/dhcp.c b/src/modules/tcpip/dhcp.c
new file mode 100644
index 0000000..3cb7aa8
--- /dev/null
+++ b/src/modules/tcpip/dhcp.c
@@ -0,0 +1,435 @@
+/*
+ * Copyright (c) 2011 The tyndur Project. All rights reserved.
+ *
+ * This code is derived from software contributed to the tyndur Project
+ * by Kevin Wolf.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "dhcp.h"
+#include "udp.h"
+#include "ip.h"
+#include "lostio_if.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <syscall.h>
+#include <stdint.h>
+#include <ctype.h>
+#include <rpc.h>
+
+struct dhcp_packet {
+ uint8_t op;
+ uint8_t htype;
+ uint8_t hlen;
+ uint8_t hops;
+ uint32_t xid;
+ uint16_t secs;
+ uint16_t flags;
+ uint32_t ciaddr; /* Client IP address */
+ uint32_t yiaddr; /* 'your' (client) address */
+ uint32_t siaddr;
+ uint32_t giaddr;
+ uint8_t chaddr[16];
+ char sname[64];
+ char file[128];
+ uint8_t options[312];
+} __attribute__((packed));
+
+enum {
+ BOOTREQUEST = 1,
+ BOOTREPLY = 2,
+};
+
+struct dhcp_msgtype {
+ uint8_t magic[4];
+ uint8_t code;
+ uint8_t len;
+ uint8_t type;
+} __attribute__((packed));
+
+struct dhcp_serverid {
+ uint8_t code;
+ uint8_t len;
+ uint32_t addr;
+} __attribute__((packed));
+
+struct dhcp_requested_ip {
+ uint8_t code;
+ uint8_t len;
+ uint32_t addr;
+} __attribute__((packed));
+
+struct dhcp_end {
+ uint8_t code;
+} __attribute__((packed));
+
+struct dhcp_discover_opts {
+ struct dhcp_msgtype msgtype;
+ struct dhcp_end end;
+} __attribute__((packed));
+
+struct dhcp_request_opts {
+ struct dhcp_msgtype msgtype;
+ struct dhcp_serverid serverid;
+ struct dhcp_requested_ip req_ip;
+ struct dhcp_end end;
+} __attribute__((packed));
+
+enum {
+ DHCPDISCOVER = 1,
+ DHCPOFFER = 2,
+ DHCPREQUEST = 3,
+ DHCPDECLINE = 4,
+ DHCPACK = 5,
+ DHCPNAK = 6,
+ DHCPRELEASE = 7,
+ DHCPINFORM = 8,
+};
+
+static void dhcp_fill_packet(struct device* device, struct dhcp_packet* p,
+ struct dhcp_msgtype* m, struct dhcp_end* end, int type)
+{
+ uint64_t mac = device->dev.mac;
+
+ *p = (struct dhcp_packet) {
+ .op = BOOTREQUEST,
+ .htype = 0x01,
+ .hlen = 6,
+ .xid = 0,
+ .chaddr = { mac >> 0, mac >> 8, mac >> 16,
+ mac >> 24, mac >> 32, mac >> 40 },
+ };
+
+ *m = (struct dhcp_msgtype) {
+ .magic = { 99, 130, 83, 99 },
+ .code = 53,
+ .len = 1,
+ .type = type,
+ };
+
+ *end = (struct dhcp_end) {
+ .code = 255,
+ };
+}
+
+static int dhcp_discover(struct device* device, struct udp_socket* s)
+{
+ struct dhcp_discover_opts* opts;
+ struct dhcp_packet p;
+
+ opts = (void*) &p.options;
+ dhcp_fill_packet(device, &p, &opts->msgtype, &opts->end, DHCPDISCOVER);
+
+ return udp_write(s, &p, sizeof(p));
+}
+
+static void dhcp_parse_options(struct device* device, struct dhcp_packet *p)
+{
+ int i;
+
+ /* Optionen parsen (DHCP-Magic überspringen) */
+ i = 4;
+
+ while (i < sizeof(p->options) - 1) {
+ uint8_t* option = &p->options[i];
+ uint8_t op = option[0];
+
+ if (op == 0xff) {
+ break;
+ } else if (op == 0x0) {
+ i++;
+ continue;
+ }
+
+ i += 2 + option[1];
+ if (i > sizeof(p->options)) {
+ break;
+ }
+
+ switch (op) {
+ case 1: /* Subnet Mask */
+ device->dhcp.subnet = *(uint32_t*) &option[2];
+ break;
+
+ case 3: /* Router */
+ device->dhcp.gateway = *(uint32_t*) &option[2];
+ break;
+
+ case 6: /* Domain Name Server */
+ device->dhcp.nameserver = *(uint32_t*) &option[2];
+ break;
+
+ case 51: /* IP Address Lease Time */
+ /* TODO */
+ break;
+
+ case 53: /* Message Type */
+ device->dhcp.last_op = option[2];
+ break;
+
+ case 54: /* Server Identifier */
+ device->dhcp.server_ip = *(uint32_t*) &option[2];
+ break;
+ }
+ }
+}
+
+static void do_nothing(void) {}
+
+static int dhcp_wait_response(struct device* device, struct udp_socket* s,
+ uint8_t msgtype, uint8_t naktype)
+{
+ int ret;
+ uint8_t buf[1024];
+ struct dhcp_packet* p = (void*) buf;
+
+again:
+ ret = udp_read(s, buf, sizeof(*p));
+
+ /* Mit Timeout auf die Antwort warten */
+ if (ret != sizeof(struct dhcp_packet)) {
+ uint64_t timeout;
+
+ timeout = get_tick_count() + 4 * 1000000;
+ timer_register(do_nothing, 5 * 1000000);
+
+ p();
+ while ((ret != sizeof(struct dhcp_packet))
+ && (get_tick_count() < timeout))
+ {
+ v_and_wait_for_rpc();
+ p();
+ ret = udp_read(s, buf, sizeof(buf));
+ }
+ v();
+ }
+
+ if (ret != sizeof(struct dhcp_packet)) {
+ return -ETIMEDOUT;
+ }
+
+ /* Antwort auswerten */
+ device->dhcp.client_ip = p->yiaddr;
+ dhcp_parse_options(device, p);
+
+ if (naktype && device->dhcp.last_op == naktype) {
+ return -1;
+ } else if (device->dhcp.last_op != msgtype) {
+ goto again;
+ }
+
+ return 0;
+}
+
+static int dhcp_request(struct device* device, struct udp_socket* s)
+{
+ struct dhcp_request_opts* opts;
+ struct dhcp_packet p;
+
+ opts = (void*) &p.options;
+ dhcp_fill_packet(device, &p, &opts->msgtype, &opts->end, DHCPREQUEST);
+
+ opts->serverid = (struct dhcp_serverid) {
+ .code = 54,
+ .len = 4,
+ .addr = device->dhcp.server_ip,
+ };
+ opts->req_ip = (struct dhcp_requested_ip) {
+ .code = 50,
+ .len = 4,
+ .addr = device->dhcp.client_ip,
+ };
+
+ return udp_write(s, &p, sizeof(p));
+}
+
+/**
+ * Sendet eine DHCP-Anfrage und holt die Informationen vom Server
+ */
+static int dhcp_fetch(struct device* device)
+{
+ struct udp_socket* s;
+ int ret;
+
+ struct routing_entry route = {
+ .target = 0,
+ .subnet = 0xffffffff,
+ .gateway = 0,
+ .device = device,
+ };
+
+ device->ip = 0;
+ memset(&device->dhcp, 0, sizeof(device->dhcp));
+
+ s = udp_open_route(68, 0xffffffff, 67, &route);
+ if (s == NULL) {
+ return -EIO;
+ }
+
+restart:
+ ret = dhcp_discover(device, s);
+ if (ret < 0) {
+ goto out;
+ }
+
+ ret = dhcp_wait_response(device, s, DHCPOFFER, 0);
+ if (ret < 0) {
+ goto out;
+ }
+
+ dhcp_request(device, s);
+ if (ret < 0) {
+ goto out;
+ }
+
+ dhcp_wait_response(device, s, DHCPACK, DHCPNAK);
+ if (ret == -1) {
+ goto restart;
+ } else if (ret < 0) {
+ goto out;
+ }
+
+ printf("ip = %08x\n", device->dhcp.client_ip);
+ printf("sub = %08x\n", device->dhcp.subnet);
+ printf("gw = %08x\n", device->dhcp.gateway);
+ printf("dns = %08x\n", device->dhcp.nameserver);
+
+ device->dhcp.valid = true;
+ ret = 0;
+out:
+ if (ret != 0) {
+ printf("DHCP-Anfrage für %s/%d fehlgeschlagen: %s\n",
+ device->driver->name, device->dev.number, strerror(-ret));
+ }
+ udp_close(s);
+
+ return ret;
+}
+
+/**
+ * Konfiguriert eine Netzwerkkarte über DHCP
+ */
+static int dhcp_configure(struct device* device)
+{
+ int ret;
+ struct routing_entry* entry;
+
+ /* Falls die DHCP-Daten noch nicht geholt sind, erstmal machen */
+ if (!device->dhcp.valid) {
+ ret = dhcp_fetch(device);
+ if (ret < 0) {
+ return ret;
+ }
+ }
+
+ /* Netzwerkkarte entsprechend umkonfigurieren */
+ device->ip = device->dhcp.client_ip;
+
+ remove_device_routes(device);
+
+ if (device->dhcp.gateway) {
+ entry = malloc(sizeof(*entry));
+ *entry = (struct routing_entry) {
+ .target = 0,
+ .subnet = 0,
+ .gateway = device->dhcp.gateway,
+ .device = device,
+ };
+ add_routing_entry(entry);
+ }
+
+ entry = malloc(sizeof(*entry));
+ *entry = (struct routing_entry) {
+ .target = device->dhcp.client_ip & device->dhcp.subnet,
+ .subnet = device->dhcp.subnet,
+ .device = device,
+ };
+ add_routing_entry(entry);
+
+ if (!options.nameserver) {
+ options.nameserver = device->dhcp.nameserver;
+ }
+
+ return 0;
+}
+
+/**
+ * TODO Lesen aus der DHCP-Datei
+ */
+static size_t lio_dhcp_read(lostio_filehandle_t* fh, void* buf,
+ size_t blocksize, size_t count)
+{
+ return 0;
+}
+
+/**
+ * Behandelt Schreibzugriffe in die DHCP-Datei. Mögliche Werte sind "fetch",
+ * "configure" und "release"
+ */
+static size_t lio_dhcp_write(lostio_filehandle_t* fh, size_t blocksize,
+ size_t count, void* buf)
+{
+ struct device *device = fh->node->data;
+ size_t len = count * blocksize;
+ char* p;
+ int ret;
+
+ /* Sicherstellen, dass der Puffer nullterminiert ist */
+ p = buf;
+ p[len - 1] = '\0';
+
+ /* Alles abschneiden, was keine Buchstaben sind */
+ while (isalpha(*p)) {
+ p++;
+ }
+ *p = '\0';
+
+ /* Entsprechende Aktion ausführen */
+ if (!strcmp(buf, "fetch")) {
+ ret = dhcp_fetch(device);
+ } else if (!strcmp(buf, "configure")) {
+ ret = dhcp_configure(device);
+ } else {
+ ret = -EINVAL;
+ }
+
+ return ret == 0 ? len : 0;
+}
+
+/** Typ fuer die DHCP-Steuerdatei */
+static typehandle_t lio_type_dhcp = {
+ .id = LOSTIO_TYPES_DHCP,
+ .read = &lio_dhcp_read,
+ .write = &lio_dhcp_write,
+};
+
+/**
+ * Registriert die LostIO-Typehandles, die fuer DHCP benoetigt werden
+ */
+void dhcp_register_lostio(void)
+{
+ lostio_register_typehandle(&lio_type_dhcp);
+}
diff --git a/src/modules/tcpip/include/dhcp.h b/src/modules/tcpip/include/dhcp.h
new file mode 100644
index 0000000..603c490
--- /dev/null
+++ b/src/modules/tcpip/include/dhcp.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2011 The tyndur Project. All rights reserved.
+ *
+ * This code is derived from software contributed to the tyndur Project
+ * by Kevin Wolf.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DHCP_H
+#define DHCP_H
+
+#include <stdint.h>
+#include <stdbool.h>
+
+struct dhcp_device_info {
+ bool valid;
+ uint8_t last_op;
+ uint32_t server_ip;
+ uint32_t client_ip;
+ uint32_t subnet;
+ uint32_t gateway;
+ uint32_t nameserver;
+};
+
+void dhcp_register_lostio(void);
+
+#endif
diff --git a/src/modules/tcpip/include/ip.h b/src/modules/tcpip/include/ip.h
index 73d40b5..42a5536 100644
--- a/src/modules/tcpip/include/ip.h
+++ b/src/modules/tcpip/include/ip.h
@@ -79,6 +79,7 @@ void add_routing_entry(struct routing_entry* entry);
struct routing_entry* get_routing_entry(uint32_t ip);
struct routing_entry* enum_routing_entry(size_t i);
size_t routing_get_entry_count(void);
+void remove_device_routes(struct device* device);
bool ip_send(uint32_t dest_ip, uint8_t proto, void* data, size_t data_size);
bool ip_send_route(uint32_t dest_ip, uint8_t proto, void* data,
diff --git a/src/modules/tcpip/include/lostio_if.h b/src/modules/tcpip/include/lostio_if.h
index 854de9e..78f2e03 100644
--- a/src/modules/tcpip/include/lostio_if.h
+++ b/src/modules/tcpip/include/lostio_if.h
@@ -50,6 +50,7 @@
#define LOSTIO_TYPES_SERVER_CONN 249
#define LOSTIO_TYPES_UDP_DIR 248
#define LOSTIO_TYPES_UDP 247
+#define LOSTIO_TYPES_DHCP 246
void init_lostio_interface(void);
diff --git a/src/modules/tcpip/include/main.h b/src/modules/tcpip/include/main.h
index 03f11e4..9226038 100644
--- a/src/modules/tcpip/include/main.h
+++ b/src/modules/tcpip/include/main.h
@@ -36,6 +36,8 @@
#ifndef _MAIN_H_
#define _MAIN_H_
+#include "dhcp.h"
+
#include <collections.h>
#include <network.h>
#include <stdint.h>
@@ -59,6 +61,7 @@ struct device
struct net_device dev;
struct driver *driver;
uint32_t ip;
+ struct dhcp_device_info dhcp;
};
extern struct module_options options;
diff --git a/src/modules/tcpip/ip.c b/src/modules/tcpip/ip.c
index 7fcb253..0a503c8 100644
--- a/src/modules/tcpip/ip.c
+++ b/src/modules/tcpip/ip.c
@@ -111,6 +111,21 @@ size_t routing_get_entry_count()
return list_size(routing_table);
}
+void remove_device_routes(struct device* device)
+{
+ int i;
+ struct routing_entry* entry;
+
+ for (i = 0; (entry = list_get_element_at(routing_table, i)); i++)
+ {
+ if (entry->device == device) {
+ list_remove(routing_table, i);
+ free(entry);
+ i--;
+ }
+ }
+}
+
/**
* IP-Paket versenden und dabei das Routing umgehen und das angegebene Device
* benutzen.
diff --git a/src/modules/tcpip/lostio_if.c b/src/modules/tcpip/lostio_if.c
index e37c305..96c62cd 100644
--- a/src/modules/tcpip/lostio_if.c
+++ b/src/modules/tcpip/lostio_if.c
@@ -50,6 +50,7 @@
#include "udp.h"
#include "lostio_if.h"
#include "dns.h"
+#include "dhcp.h"
//Hier koennen die Debug-Nachrichten aktiviert werden
#define DEBUG 0
@@ -131,6 +132,7 @@ void init_lostio_interface(void)
// Weitere Typen
tcp_server_register_lostio();
udp_register_lostio();
+ dhcp_register_lostio();
// Dateien/Verzeichnisse anlegen
vfstree_create_node("/dns", LOSTIO_TYPES_DNS, 0, NULL,
@@ -163,6 +165,8 @@ void lostio_add_device(struct device *device)
vfstree_create_node(fsname, LOSTIO_TYPES_NETCONFIG, 1, device, 0);
strcpy(fsname_suffix, "mac");
vfstree_create_node(fsname, LOSTIO_TYPES_NETCONFIG, 2, device, 0);
+ strcpy(fsname_suffix, "dhcp");
+ vfstree_create_node(fsname, LOSTIO_TYPES_DHCP, 0, device, 0);
}
bool lostio_tcp_not_found(char** path, uint8_t flags, pid_t pid,
diff --git a/src/modules/tcpip/main.c b/src/modules/tcpip/main.c
index 9581dc9..c0aa5e8 100644
--- a/src/modules/tcpip/main.c
+++ b/src/modules/tcpip/main.c
@@ -158,8 +158,8 @@ void rpc_register_driver(pid_t pid, uint32_t cid, size_t data_size, void* data)
}
// Device in die Liste hinzufügen
- struct device *device = malloc(sizeof(struct device));
- memcpy(device, data, sizeof(struct net_device));
+ struct device *device = calloc(1, sizeof(struct device));
+ memcpy(&device->dev, data, sizeof(struct net_device));
device->driver = driver;
device->ip = options.ip;
list_push(driver->devices, device);
--
1.6.0.2