Added first attempt for an ethernet protocol. Even not tried.
authorviric@llimona
Tue, 25 Sep 2007 23:49:23 +0200
changeset 43 625794738afc
parent 42 eb897a05a804
child 44 41241a0f84bf
Added first attempt for an ethernet protocol. Even not tried.
Makefile
client.c
eth_client.c
eth_linux.c
eth_linux.h
eth_proto.c
eth_server.c
handlers.h
main.c
main.h
simple_math.c
unix_client.c
--- a/Makefile	Tue Sep 25 22:23:24 2007 +0200
+++ b/Makefile	Tue Sep 25 23:49:23 2007 +0200
@@ -13,7 +13,11 @@
 	dump.o \
 	filter.o \
 	filter_string.o \
-	filter_telnet.o
+	filter_telnet.o \
+	eth_linux.o \
+	eth_proto.o \
+	eth_server.o \
+	eth_client.o
 
 all: tm test_filter
 
@@ -45,3 +49,7 @@
 filter_telnet.o: filter_telnet.c filter.h
 xterm.o: xterm.c main.h
 dump.o: dump.c main.h
+eth_linux.o: eth_linux.c eth_linux.h
+eth_proto.o: eth_proto.c main.h eth_linux.h
+eth_server.o: eth_server.c main.h handlers.h
+eth_client.o: eth_client.c main.h handlers.h
--- a/client.c	Tue Sep 25 22:23:24 2007 +0200
+++ b/client.c	Tue Sep 25 23:49:23 2007 +0200
@@ -73,6 +73,12 @@
         net_prepare_read_fdset = c_unix_prepare_read_fdset;
         net_process_read_fdset = c_unix_process_read_fdset;
         net_send = c_unix_send;
+    } else if (command_line.c_param.transport == ETHERNET)
+    {
+        c_eth_init();
+        net_prepare_read_fdset = c_eth_prepare_read_fdset;
+        net_process_read_fdset = c_eth_process_read_fdset;
+        net_send = c_eth_send_to_connected;
     }
 
     if (command_line.c_param.raw_mode)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eth_client.c	Tue Sep 25 23:49:23 2007 +0200
@@ -0,0 +1,61 @@
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/select.h>
+#include "main.h"
+#include "handlers.h"
+#include "filter.h"
+
+static int myfd = -1;
+
+extern struct FilterRules *client_fr;
+
+void c_eth_init()
+{
+    eth_proto_init();
+    myfd = eth_proto_open();
+    if (myfd < 0)
+        error("Cannot eth_proto_open");
+}
+
+void c_eth_shutdown()
+{
+    if (myfd >= 0)
+        close(myfd);
+}
+
+void c_eth_prepare_read_fdset(fd_set *read_set, int *maxfd)
+{
+    FD_SET(myfd, read_set);
+    *maxfd = max(*maxfd, myfd);
+}
+
+/* Send -1 on eof */
+int c_eth_process_read_fdset(fd_set *read_set)
+{
+    if (FD_ISSET(myfd, read_set))
+    {
+        int res;
+        int olen;
+        res = eth_proto_recv(stream_buffer, stream_buffer_size);
+        if (res == 0) /* EOF */
+        {
+            filter_flush(client_fr, ostream_buffer, &olen);
+            if (olen > 0)
+                send_to_client_stdout(ostream_buffer, olen);
+            return -1;
+        }
+        hex_dump("recv_unix_client",stream_buffer, res);
+
+        filter_stream(client_fr, ostream_buffer, &olen, stream_buffer,
+                res);
+        if (olen > 0)
+            send_to_client_stdout(ostream_buffer, olen);
+    }
+
+    return 0;
+}
+
+void c_eth_send_to_connected(const char *buffer, size_t size)
+{
+    eth_proto_send(buffer, size);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eth_linux.c	Tue Sep 25 23:49:23 2007 +0200
@@ -0,0 +1,128 @@
+/* Copyright Coraid, Inc. 2006.  All rights reserved. */
+/* Modified by Lluis Batlle */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <features.h>    /* for the glibc version number */
+#if __GLIBC__ >= 2 && __GLIBC_MINOR >= 1
+#include <netpacket/packet.h>
+#include <net/ethernet.h>     /* the L2 protocols */
+#else
+#include <asm/types.h>
+#include <linux/if_packet.h>
+#include <linux/if_ether.h>   /* The L2 protocols */
+#endif
+
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <linux/fs.h>
+#include <sys/stat.h>
+
+#include "eth_linux.h"
+
+enum {
+    ETH_PROTO = 0xBACA
+};
+
+static int fd;
+static char srcaddr[6];
+static int debug = 0;
+
+static void dump(unsigned char *buf, int len)
+{
+  int i;
+  for(i=0; i < len; ++i)
+  {
+    printf("%x ", (int) buf[i]);
+  }
+  putchar('\n');
+}
+
+// return the index of device 'name'
+static int getindx(int s, char *name)
+{
+    struct ifreq xx;
+    int n;
+
+    strncpy(xx.ifr_name, name, sizeof(xx.ifr_name));
+    xx.ifr_name[sizeof(xx.ifr_name)-1] = 0;
+    n = ioctl(s, SIOCGIFINDEX, &xx);
+    if (n == -1)
+        return -1;
+    return xx.ifr_ifindex;
+}
+
+// get us a raw connection to an interface
+int eth_open(char *eth)
+{
+    int i, n;
+    struct sockaddr_ll sa;
+    struct ifreq xx;
+
+    memset(&sa, 0, sizeof sa);
+    fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_PROTO));
+    if (fd == -1) {
+        perror("got bad socket");
+        return -1;
+    }
+    i = getindx(fd, eth);
+    sa.sll_family = AF_PACKET;
+    sa.sll_protocol = htons(ETH_PROTO);
+    sa.sll_ifindex = i;
+    n = bind(fd, (struct sockaddr *)&sa, sizeof sa);
+    if (n == -1) {
+        perror("bind funky");
+        return -1;
+    }
+        strcpy(xx.ifr_name, eth);
+    n = ioctl(fd, SIOCGIFHWADDR, &xx);
+    if (n == -1) {
+        perror("Can't get hw addr");
+        return -1;
+    }
+    memmove(srcaddr, xx.ifr_hwaddr.sa_data, 6);
+    return fd;
+}
+
+int eth_recv(char *buf, int len, char *partner_mac)
+{
+    struct sockaddr_ll sa;
+    int sa_len;
+    int res;
+    res = recvfrom(fd, buf, len, 0, (struct sockaddr *) &sa, &sa_len);
+    if (debug) {
+        printf("read %d bytes\r\n", res);
+        dump(buf, res);
+    }
+    if (sa_len != sizeof(sa))
+        return -1;
+    if (partner_mac)
+        memcpy(partner_mac, sa.sll_addr, sa.sll_halen);
+    return res;
+}
+
+int eth_send(char *dev, char *mac, void *p, int len)
+{
+    struct sockaddr_ll sa;
+    int i;
+
+    i = getindx(fd, dev);
+    sa.sll_family = AF_PACKET;
+    sa.sll_protocol = htons(ETH_PROTO);
+    sa.sll_ifindex = i;
+    sa.sll_halen = 6;
+    memcpy(sa.sll_addr, mac, 6);
+    if (debug) {
+        printf("sending %d bytes\r\n", len);
+        dump(p, len);
+    }
+    if (len > 1500)
+        len = 1500;
+    return sendto(fd, p, len, 0, (struct sockaddr*) &sa, sizeof(sa));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eth_linux.h	Tue Sep 25 23:49:23 2007 +0200
@@ -0,0 +1,3 @@
+int eth_open(char *eth);
+int eth_recv(char *buf, int len, char *partner_mac);
+int eth_send(char *dev, char *mac, void *p, int len);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eth_proto.c	Tue Sep 25 23:49:23 2007 +0200
@@ -0,0 +1,151 @@
+#include <netinet/in.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "eth_linux.h"
+#include "main.h"
+
+static struct
+{
+    int socket;
+    char partner[6];
+    unsigned int seq_send;
+    unsigned int seq_wait;
+    unsigned int wrong_recv;
+} edata;
+
+enum Control{
+    SEND,
+    ACK,
+    NAK
+};
+
+enum {
+    MAXPACKET = 1000,
+    HEAD = 5
+};
+
+static char eth_buffer[1000];
+
+static void eth_fill_mac(unsigned char *mac, const char *str);
+
+static int make_head(unsigned char *data, unsigned int seq, enum Control c)
+{
+    *((unsigned int *) data) = htonl(seq);
+    data[5] = (unsigned char) c;
+    return 5;
+}
+
+static int parse_head(unsigned char *data, unsigned int *seq, enum Control *c)
+{
+    *seq = ntohl( *((int*) data) );
+    *c = data[5];
+    return 5;
+}
+
+void eth_proto_init()
+{
+    edata.socket = -1;
+    edata.seq_send = 0;
+    edata.seq_wait = 0;
+}
+
+int eth_proto_open()
+{
+    edata.socket = eth_open(command_line.eth_device);
+    if (edata.socket == -1)
+        error("Cannot open device %s", command_line.eth_device);
+    return edata.socket;
+}
+
+int eth_proto_recv(char *data, int size)
+{
+    int res;
+    int seq;
+    enum Control c;
+
+    do {
+        if (edata.seq_wait == 0)
+            res = eth_recv(eth_buffer, sizeof(eth_buffer), edata.partner);
+        else
+            res = eth_recv(eth_buffer, sizeof(eth_buffer), 0);
+    } while(res >= HEAD);
+    parse_head(eth_buffer, &seq, &c);
+    if (seq != edata.seq_wait)
+    {
+        edata.wrong_recv++;
+        return -1;
+    }
+    memcpy(data, eth_buffer + HEAD, min(size, res - HEAD));
+
+    make_head(eth_buffer, seq, ACK);
+    eth_send(command_line.eth_device, edata.partner, eth_buffer, HEAD);
+    edata.seq_wait++;
+
+    return (res - HEAD);
+}
+
+int eth_proto_send(const char *data, int size)
+{
+    int total = size;
+
+    if (edata.partner == 0)
+    {
+        if (command_line.c_param.server_address != 0)
+            eth_fill_mac(edata.partner, command_line.c_param.server_address);
+        else
+            return 0;
+    }
+
+    do {
+        int once;
+        int sent;
+        int rseq;
+        enum Control rc;
+
+        once = max(sizeof(eth_buffer)-HEAD, size);
+
+        make_head(eth_buffer, edata.seq_send, SEND);
+        sent = eth_send(command_line.eth_device, edata.partner,
+                eth_buffer, once);
+
+        eth_recv(eth_buffer, HEAD, 0);
+        parse_head(eth_buffer, &rseq, &rc);
+        if (rc != ACK || rseq != edata.seq_send)
+            continue;
+
+        edata.seq_send++;
+        size -= sent;
+        data += sent;
+    } while(size > 0);
+    return total;
+}
+
+static void eth_fill_mac(unsigned char *mac, const char *str)
+{
+  int res;
+  int imac[6];
+  res = sscanf(str, "%x:%x:%x:%x:%x:%x",
+      &imac[0],
+      &imac[1],
+      &imac[2],
+      &imac[3],
+      &imac[4],
+      &imac[5]);
+  if (res != 6)
+  {
+    error("Error parsing mac: %02x:%02x:%02x:%02x:%02x:%02x\n",
+      imac[0],
+      imac[1],
+      imac[2],
+      imac[3],
+      imac[4],
+      imac[5]);
+  }
+  mac[0] = imac[0];
+  mac[1] = imac[1];
+  mac[2] = imac[2];
+  mac[3] = imac[3];
+  mac[4] = imac[4];
+  mac[5] = imac[5];
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eth_server.c	Tue Sep 25 23:49:23 2007 +0200
@@ -0,0 +1,44 @@
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/select.h>
+#include "main.h"
+#include "handlers.h"
+
+static int myfd = -1;
+
+void s_eth_init()
+{
+    eth_proto_init();
+    myfd = eth_proto_open();
+    if (myfd < 0)
+        error("Cannot eth_proto_open");
+}
+
+void s_eth_shutdown()
+{
+    if (myfd >= 0)
+        close(myfd);
+}
+
+void s_eth_prepare_read_fdset(fd_set *read_set, int *maxfd)
+{
+    FD_SET(myfd, read_set);
+    *maxfd = max(*maxfd, myfd);
+}
+
+void s_eth_process_read_fdset(fd_set *read_set)
+{
+    if (FD_ISSET(myfd, read_set))
+    {
+        int res;
+
+        res = eth_proto_recv(stream_buffer, stream_buffer_size);
+
+        app_control_remote_send_to_stdin(stream_buffer, res);
+    }
+}
+
+void s_eth_send_to_connected(const char *buffer, size_t size)
+{
+    eth_proto_send(buffer, size);
+}
--- a/handlers.h	Tue Sep 25 22:23:24 2007 +0200
+++ b/handlers.h	Tue Sep 25 23:49:23 2007 +0200
@@ -1,7 +1,7 @@
 typedef void (*Net_c_prepare_read_fdset)(fd_set *read_set, int *maxfd);
 /* Send -1 on eof */
 typedef int (*Net_c_process_read_fdset)(fd_set *read_set);
-typedef void (*Net_c_send)(const char *buf, int len);
+typedef void (*Net_c_send)(const char *buf, size_t len);
 
 /* unix_server.c */
 void s_unix_update_served(int new);
@@ -24,7 +24,7 @@
 /* Send -1 on eof */
 void c_unix_prepare_read_fdset(fd_set *read_set, int *maxfd);
 int c_unix_process_read_fdset(fd_set *read_set);
-void c_unix_send(const char *buf, int len);
+void c_unix_send(const char *buf, size_t len);
 
 /* client_term.c */
 void send_to_client_stdout(const char *buf, int len);
@@ -35,3 +35,17 @@
 void s_tcp_prepare_read_fdset(fd_set *read_set, int *maxfd);
 void s_tcp_process_read_fdset(fd_set *read_set);
 void s_tcp_send_to_connected(const char *buffer, size_t size);
+
+/* eth_server.c */
+void s_eth_init();
+void s_eth_shutdown();
+void s_eth_prepare_read_fdset(fd_set *read_set, int *maxfd);
+void s_eth_process_read_fdset(fd_set *read_set);
+void s_eth_send_to_connected(const char *buffer, size_t size);
+
+/* eth_server.c */
+void c_eth_init();
+void c_eth_shutdown();
+void c_eth_prepare_read_fdset(fd_set *read_set, int *maxfd);
+int  c_eth_process_read_fdset(fd_set *read_set);
+void c_eth_send_to_connected(const char *buffer, size_t size);
--- a/main.c	Tue Sep 25 22:23:24 2007 +0200
+++ b/main.c	Tue Sep 25 23:49:23 2007 +0200
@@ -51,7 +51,9 @@
     printf(" -p NUM Listen to tcp port NUM for 'telnet', and not listen to "
             "any\n"
            "        Unix socket.\n");
-    printf(" -e     Echo remote input to the server terminal.\n");
+    printf(" -E     Echo remote input to the server terminal.\n");
+    printf(" -e dev Serve/connect using raw ethernet, device 'dev'.\n");
+    printf(" -c adr Connect to address (MAC if eth).\n");
     printf(" -r     Send xterm's resize control string to clients.\n");
     return 0;
 }
@@ -92,9 +94,11 @@
     command_line.s_param.client_can_write = 0;
     command_line.s_param.echo_in_local_terminal = 0;
     command_line.s_param.send_xterm_resize = 0;
+    command_line.s_param.serve_eth = 0;
 
     command_line.tcp_port = 40000; /* Arbitrary */
     command_line.buffer_size = 4096; /* Arbitrary */
+    command_line.eth_device = 0;
     get_unix_path(); /* for command_line.unix_path */
 
     command_line.c_param.transport = UNIX;
@@ -110,7 +114,7 @@
     extern int optind, opterr, optopt;
 
     while(1) {
-        c = my_getopt(argc, argv, "tp:nBrdPN:c:hwxe");
+        c = my_getopt(argc, argv, "tp:nBrdPN:c:hwxEe:");
 
         if (c == -1)
             break;
@@ -154,8 +158,13 @@
             case 'r':
                 command_line.s_param.send_xterm_resize = 1;
                 break;
+            case 'E':
+                command_line.s_param.echo_in_local_terminal = 1;
+                break;
             case 'e':
-                command_line.s_param.echo_in_local_terminal = 1;
+                command_line.s_param.serve_eth = 1;
+                command_line.eth_device = strdup(optarg);
+                command_line.c_param.transport = ETHERNET;
                 break;
             case '?':
                 error("Wrong option %c.\n", optopt);
--- a/main.h	Tue Sep 25 22:23:24 2007 +0200
+++ b/main.h	Tue Sep 25 23:49:23 2007 +0200
@@ -9,9 +9,11 @@
     int is_server;
     char *unix_path; /* path or 0 if not to be used */
     int tcp_port;
+    char *eth_device;
     struct {
         int serve_tcp; /* yes/no */
         int serve_unix; /* yes/no */
+        int serve_eth; /* yes/no */
         int max_served; /* how many */
         char run_in_subterminal; /* use opentty */
         char echo_in_local_terminal;
@@ -46,6 +48,7 @@
 extern int app_stderr;
 extern struct Command_line command_line;
 int max(int a, int b);
+int min(int a, int b);
 
 /* gen_sockets.c */
 extern char *stream_buffer;
@@ -74,3 +77,9 @@
 /* dump.c */
 void hex_dump(const char *head, const unsigned char *data, int len);
 void dump_line(const char *msg, ...);
+
+/* eth_proto.c */
+void eth_proto_init();
+int eth_proto_open();
+int eth_proto_recv(char *data, int size);
+int eth_proto_send(const char *data, int size);
--- a/simple_math.c	Tue Sep 25 22:23:24 2007 +0200
+++ b/simple_math.c	Tue Sep 25 23:49:23 2007 +0200
@@ -6,3 +6,10 @@
         return a;
     return b;
 }
+
+int min(int a, int b)
+{
+    if (a < b)
+        return a;
+    return b;
+}
--- a/unix_client.c	Tue Sep 25 22:23:24 2007 +0200
+++ b/unix_client.c	Tue Sep 25 23:49:23 2007 +0200
@@ -62,7 +62,7 @@
     return 0;
 }
 
-void c_unix_send(const char *buf, int len)
+void c_unix_send(const char *buf, size_t len)
 {
     hex_dump("send_unix_client",buf, len);
     write(conn_socket, stream_buffer, len);