diff --git a/src/apps/socket/dev.lua b/src/apps/socket/dev.lua deleted file mode 100644 index 423fbaea98..0000000000 --- a/src/apps/socket/dev.lua +++ /dev/null @@ -1,38 +0,0 @@ -module(...,package.seeall) - -local ffi = require("ffi") -local C = ffi.C - -local packet = require("core.packet") -require("lib.raw.raw_h") -require("apps.socket.io_h") - -dev = {} - -function dev:new (ifname) - assert(ifname) - self.__index = self - local dev = {fd = C.open_raw(ifname)} - return setmetatable(dev, self) -end - -function dev:transmit (p) - assert(self.fd) - assert(C.send_packet(self.fd, p) ~= -1) -end - -function dev:can_transmit () - return C.can_transmit(self.fd) == 1 -end - -function dev:receive () - assert(self.fd) - local p = packet.allocate() - local s = C.receive_packet(self.fd, p) - assert(s ~= -1) - return p -end - -function dev:can_receive () - return C.can_receive(self.fd) == 1 -end diff --git a/src/apps/socket/io.c b/src/apps/socket/io.c deleted file mode 100644 index 8666f57c4f..0000000000 --- a/src/apps/socket/io.c +++ /dev/null @@ -1,58 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "core/packet.h" - -int send_packet(int fd, struct packet *p) { - if (write(fd, &p->data, p->length) == -1) { - perror("sendmsg"); - return(-1); - } - return(0); -} - -int receive_packet(int fd, struct packet *p) { - ssize_t s; - - s = read(fd, &p->data, sizeof(p->data)); - if (s == -1) { - perror("read"); - return(-1); - } - p->length = s; - return(s); -} - -int can_receive(int fd) { - fd_set fds; - struct timeval tv = { .tv_sec = 0, .tv_usec = 0 }; - int result; - - FD_ZERO(&fds); - FD_SET(fd, &fds); - if ((result = select(fd+1, &fds, NULL, NULL, &tv)) == -1) { - perror("select"); - return(-1); - } - return(result); -} - -int can_transmit(int fd) { - fd_set fds; - struct timeval tv = { .tv_sec = 0, .tv_usec = 0 }; - int result; - - FD_ZERO(&fds); - FD_SET(fd, &fds); - if ((result = select(fd+1, NULL, &fds, NULL, &tv)) == -1) { - perror("select"); - return(-1); - } - return(result); -} diff --git a/src/apps/socket/io.h b/src/apps/socket/io.h deleted file mode 100644 index ba602269ef..0000000000 --- a/src/apps/socket/io.h +++ /dev/null @@ -1,5 +0,0 @@ -int send_packet(int, struct packet *); -int receive_packet(int, struct packet *); -int can_transmit(int); -int can_receive(int); -int msg_size(int); diff --git a/src/apps/socket/raw.lua b/src/apps/socket/raw.lua index dfa4f3a252..0f280f668d 100644 --- a/src/apps/socket/raw.lua +++ b/src/apps/socket/raw.lua @@ -1,72 +1,122 @@ -module(...,package.seeall) +module(..., package.seeall) -local app = require("core.app") -local link = require("core.link") +local S = require("syscall") +local h = require("syscall.helpers") +local bit = require("bit") +local link = require("core.link") local packet = require("core.packet") -local dev = require("apps.socket.dev").dev +local ffi = require("ffi") +local C = ffi.C + +local c, t = S.c, S.types.t RawSocket = {} function RawSocket:new (ifname) assert(ifname) - self.__index = self - return setmetatable({dev = dev:new(ifname)}, self) + local tp = h.htons(c.ETH_P["ALL"]) + local sock, err = S.socket(c.AF.PACKET, bit.bor(c.SOCK.RAW, c.SOCK.NONBLOCK), tp) + if not sock then error(err) end + local index, err = S.util.if_nametoindex(ifname, sock) + if err then + S.close(sock) + error(err) + end + local addr = t.sockaddr_ll{sll_family = c.AF.PACKET, sll_ifindex = index, sll_protocol = tp} + local ok, err = S.bind(sock, addr) + if not ok then + S.close(sock) + error(err) + end + return setmetatable({sock = sock}, {__index = RawSocket}) end function RawSocket:pull () local l = self.output.tx if l == nil then return end - while not link.full(l) and self.dev:can_receive() do - link.transmit(l, self.dev:receive()) + while not link.full(l) and self:can_receive() do + link.transmit(l, self:receive()) end end +function RawSocket:can_receive () + local ok, err = S.select({readfds = {self.sock}}, 0) + return not (err or ok.count == 0) +end + +function RawSocket:receive () + local buffer = ffi.new("uint8_t[?]", C.PACKET_PAYLOAD_SIZE) + local sz, err = S.read(self.sock, buffer, C.PACKET_PAYLOAD_SIZE) + if not sz then return err end + return packet.from_pointer(buffer, sz) +end + function RawSocket:push () local l = self.input.rx if l == nil then return end - while not link.empty(l) and self.dev:can_transmit() do + while not link.empty(l) and self:can_transmit() do local p = link.receive(l) - self.dev:transmit(p) + self:transmit(p) packet.free(p) end end +function RawSocket:can_transmit () + local ok, err = S.select({writefds = {self.sock}}, 0) + return not (err or ok.count == 0) +end + +function RawSocket:transmit (p) + local sz, err = S.write(self.sock, packet.data(p), packet.length(p)) + if not sz then return err end + return sz +end + +function RawSocket:stop() + S.close(self.sock) +end + function selftest () -- Send a packet over the loopback device and check -- that it is received correctly. - -- XXX beware of a race condition with unrelated traffic over the - -- loopback device + -- XXX Beware of a race condition with unrelated traffic over the + -- loopback device. local datagram = require("lib.protocol.datagram") local ethernet = require("lib.protocol.ethernet") local ipv6 = require("lib.protocol.ipv6") + + -- Initialize RawSocket. + local lo = RawSocket:new("lo") + lo.input, lo.output = {}, {} + lo.input.rx, lo.output.tx = link.new("test1"), link.new("test2") + -- Construct packet. local dg_tx = datagram:new() local src = ethernet:pton("02:00:00:00:00:01") local dst = ethernet:pton("02:00:00:00:00:02") local localhost = ipv6:pton("0:0:0:0:0:0:0:1") dg_tx:push(ipv6:new({src = localhost, dst = localhost, - next_header = 59, -- no next header + next_header = 59, -- No next header. hop_limit = 1})) - dg_tx:push(ethernet:new({src = src, dst = dst, type = 0x86dd})) - - local link = require("core.link") - local lo = RawSocket:new("lo") - lo.input, lo.output = {}, {} - lo.input.rx, lo.output.tx = link.new("test1"), link.new("test2") + dg_tx:push(ethernet:new({src = src, + dst = dst, + type = 0x86dd})) + -- Transmit packet. link.transmit(lo.input.rx, dg_tx:packet()) lo:push() + -- Receive packet. lo:pull() local dg_rx = datagram:new(link.receive(lo.output.tx), ethernet) - assert(dg_rx:parse({ { ethernet, function(eth) - return(eth:src_eq(src) and eth:dst_eq(dst) - and eth:type() == 0x86dd) - end }, - { ipv6, function(ipv6) - return(ipv6:src_eq(localhost) and - ipv6:dst_eq(localhost)) - end } }), "loopback test failed") + -- Assert packet was received OK. + assert(dg_rx:parse({{ethernet, function(eth) + return(eth:src_eq(src) and eth:dst_eq(dst) and eth:type() == 0x86dd) + end }, { ipv6, function(ipv6) + return(ipv6:src_eq(localhost) and ipv6:dst_eq(localhost)) + end } }), "loopback test failed") + lo:stop() + print("selftest passed") - -- Another useful test would be to feed a pcap file with + -- XXX Another useful test would be to feed a pcap file with -- pings to 127.0.0.1 and ::1 into lo and capture/compare -- the responses with a pre-recorded pcap. end diff --git a/src/lib/raw/raw.c b/src/lib/raw/raw.c deleted file mode 100644 index 3976983e66..0000000000 --- a/src/lib/raw/raw.c +++ /dev/null @@ -1,39 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Open a raw socket and return its file descriptor, or -1 on error. - - 'name' is the name of the host network interface to which the socket - is attached, e.g. 'eth0'. */ -int open_raw(const char *name) -{ - struct ifreq ifr; - struct sockaddr_ll sll; - int fd; - if ((fd = socket(AF_PACKET, SOCK_RAW | SOCK_NONBLOCK, htons(ETH_P_ALL))) < 0) { - perror("open raw socket"); - return -1; - } - memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)-1); - if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0) { - perror("get interface index"); - return -1; - } - sll.sll_family = AF_PACKET; - sll.sll_ifindex = ifr.ifr_ifindex; - sll.sll_protocol = htons(ETH_P_ALL); - if (bind(fd, (struct sockaddr *)&sll, sizeof(sll)) < 0) { - perror("bind raw socket to interface"); - return -1; - } - return fd; -} diff --git a/src/lib/raw/raw.h b/src/lib/raw/raw.h deleted file mode 100644 index c542731fc2..0000000000 --- a/src/lib/raw/raw.h +++ /dev/null @@ -1 +0,0 @@ -int open_raw(const char *name);