# HG changeset patch # User Brett Gordon # Date 1479523903 25200 # Node ID f8226a33698d152d9028f03b86850e20a2ef4c57 # Parent 38184ef1296ded46a35e5884b4bd06178d3db32c Add PACKET extension diff -r 38184ef1296d -r f8226a33698d src/Makefile --- 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 $@ $< diff -r 38184ef1296d -r f8226a33698d src/lwwire-packet.c --- /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 +#include "lwwire.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#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); +}