changeset 12:f8226a33698d

Add PACKET extension
author Brett Gordon <beretta42@gmail.com>
date Fri, 18 Nov 2016 19:51:43 -0700
parents 38184ef1296d
children 7702bb8a8216
files src/Makefile src/lwwire-packet.c
diffstat 2 files changed, 259 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/src/Makefile	Thu Aug 04 12:50:12 2016 -0600
+++ b/src/Makefile	Fri Nov 18 19:51:43 2016 -0700
@@ -1,7 +1,7 @@
 CFLAGS += -Wall
 LDLIBS += -ldl -rdynamic
 
-all: lwwire lwwire-serial lwwire-pingpong.so
+all: lwwire lwwire-serial lwwire-pingpong.so lwwire-packet.so
 
 %.so: %.c
 	$(CC) $(CPPFLAGS) $(CFLAGS) -fPIC -shared -o $@ $<
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lwwire-packet.c	Fri Nov 18 19:51:43 2016 -0700
@@ -0,0 +1,258 @@
+/*
+  Packet extension for lwwire
+
+  Talks Layer 2, Ethernet Frames, sends them to a Linux TAP/TUN device.
+
+  TODO:
+  * better (any) RXMTU and TXMTU, Queue Length handling
+
+*/
+
+#include <stdio.h>
+#include "lwwire.h"
+
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <linux/if.h>
+#include <linux/if_tun.h>
+
+
+#define MAX_FRAME 1526
+static int tunfd = -1;
+static char tundev[10];
+static unsigned char opacket[MAX_FRAME];
+static unsigned char packet[MAX_FRAME];
+static int tunz = -1;
+static unsigned char *packet_ptr;
+static int csize = 511;
+static int rxmtu = 1500;
+static int txmtu = 1500;
+static int qlen = 10;
+
+/*
+
+  NOTE: the __attribute__((used)) tags are there to prevent the functions
+  from being optimized out as would often be the case with functions declared
+  static. This could be avoided by removing the static declarations. However,
+  by declaring everything static except for the lwwire_register() function,
+  we avoid polluting the global namespace and possibly having conflicts with
+  other extensions.
+*/
+
+
+/* Allocate (open) a new tap device
+   Take symbolic name of device and tap/tun flags. Returns fd, or < 0 on
+   error.
+*/
+static int tun_alloc(char *dev, int flags)
+{
+    struct ifreq ifr;
+    int fd, err;
+    char *clonedev = "/dev/net/tun";
+
+    /* open the clone device */
+    if ((fd = open(clonedev, O_RDWR)) < 0)
+    {
+	perror("tun_alloc");
+	return fd;
+    }
+    /* preparation of the struct ifr, of type "struct ifreq" */
+    memset(&ifr, 0, sizeof(ifr));
+    ifr.ifr_flags = flags;
+    if (*dev)
+    {
+	strncpy(ifr.ifr_name, dev, IFNAMSIZ);
+    }
+    /* try to create the device */
+    if ((err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0)
+    {
+	perror("tun_alloc");
+	close(fd);
+	return err;
+    }
+    /* write acquired tap device name back to struct */
+    strcpy(dev, ifr.ifr_name);
+
+    nonblock(fd);
+    return fd;
+}
+
+
+/* Tell client how many bytes to expect for the next read. */
+static int tun_proto_poll()
+{
+    unsigned char buf[2];
+    while (1)
+    {
+	if (tunz < 1)
+	    tunz = read(tunfd, packet, MAX_FRAME);
+	if (tunz < rxmtu)
+	    break;
+	else
+	    tunz = 0;
+    }
+    buf[0] = (unsigned char)(tunz >> 8);
+    buf[1] = (unsigned char)(tunz & 0xff);
+    lwwire_write(buf,2);
+    packet_ptr = packet;
+    return 0;
+}
+
+/* Drop the current packet */
+static int tun_proto_drop()
+{
+    tunz = 0;
+    return 0;
+}
+
+
+/* receive *entire* frame */
+static int tun_proto_recv()
+{
+    if (tunz < 1)
+	return -1;
+    lwwire_write(packet, tunz);
+    tunz = 0;
+    return 0;
+}
+
+/* receive next chunk (upto 511 bytes) of frame */
+static int tun_proto_recv_chunk()
+{
+    int s;
+    if (csize < tunz)
+	s = csize;
+    else
+	s = tunz;
+    lwwire_write(packet_ptr, s);
+    packet_ptr += s;
+    tunz -= s;
+    return 0;
+}
+
+/* send a frame */
+static int tun_proto_send()
+{
+    int len;
+    unsigned char buf[2];
+    if (lwwire_read(buf, 2) < 0)
+	return -1;
+    len = (buf[0]<<8) + buf[1];
+    if (lwwire_read(opacket, len) < 0)
+	return -1;
+    if (write(tunfd, opacket, len) < 0)
+	return -1;
+    return 0;
+}
+
+
+/* set/return receive mtu */
+static int tun_proto_setrxmtu()
+{
+    unsigned char buf[2];
+    if (lwwire_read(buf, 2) < 0)
+	return -1;
+    rxmtu = (buf[0]<<8) + buf[1];
+    lwwire_write(buf, 2);
+    return 0;
+}
+
+/* set/return transmit mtu */
+static int tun_proto_settxmtu()
+{
+    unsigned char buf[2];
+    if (lwwire_read(buf, 2) < 0)
+	return -1;
+    txmtu = (buf[0]<<8) + buf[1];
+    lwwire_write(buf, 2);
+    return 0;
+}
+
+/* set/return receive mtu */
+static int tun_proto_setqlen()
+{
+    unsigned char buf[1];
+    if (lwwire_read(buf, 1) < 0)
+	return -1;
+    qlen = buf[0];
+    lwwire_write(buf, 1);
+    return 0;
+}
+
+
+
+// this is called to handle an operation for this extension
+// it should return nonzero if the operation code (op) is not
+// supported. Otherwise, it should implement the operation codes.
+__attribute__((used)) static int packet_handler(int op)
+{
+    switch (op)
+    {
+    case 0:
+	return tun_proto_poll();
+    case 1:
+	return tun_proto_recv();
+    case 2:
+	return tun_proto_send();
+    case 3:
+	return tun_proto_drop();
+    case 4:
+	return tun_proto_setrxmtu();
+    case 5:
+	return tun_proto_setqlen();
+    case 6:
+	return tun_proto_settxmtu();
+    case 7:
+	return tun_proto_recv_chunk();
+    default:
+	return -1;
+    }
+    return 0;
+}
+
+// this will be called when the extension is enabled
+// return nonzero if enabling the extension cannot happen for some reason
+__attribute__((used)) static int packet_enable(void)
+{
+    if (tunfd < 0)
+    {
+	strcpy(tundev, "tap0");
+	tunfd = tun_alloc(tundev, IFF_TAP | IFF_NO_PI);
+	if (tunfd < 0) return -1;
+	tunz = -1;
+    }
+    return 0;
+}
+
+// this will be called when an extension is disabled
+// if this extension cannot be disabled after it is enabled, it should return
+// nonzero; otherwise, this MUST succeed
+__attribute__((used)) static int packet_disable(void)
+{
+    close(tunfd);
+    tunfd = -1;
+    return 0;
+}
+
+// this call should do anything needed to disable the extension
+// and anything special that might be needed on a protocol reset
+// it will only be called if the extension is enabled when the
+// reset occurs. Even if the extension isn't disablable, this call
+// MUST disable it and reset things as if the extension was never
+// enabled.
+__attribute__((used)) static void packet_reset(void)
+{
+    packet_disable();
+}
+
+int lwwire_register(void)
+{
+    fprintf(stderr, "Registering PACKET extension\n");
+    return lwwire_register_extension(0x01, packet_handler, packet_enable, packet_disable, packet_reset);
+}