net_at: silly test stack
authorAlan Cox <alan@linux.intel.com>
Mon, 11 Jan 2016 19:04:08 +0000 (19:04 +0000)
committerAlan Cox <alan@linux.intel.com>
Mon, 11 Jan 2016 19:04:08 +0000 (19:04 +0000)
The first bits of a "network" stack which implements a single offload socket
driven via AT commands. It's easier to debug this and then tackle stuff like
the WizNet5200 offloads and perhaps Drivewire for offload stacks.

Kernel/dev/net/net_at.c [new file with mode: 0644]

diff --git a/Kernel/dev/net/net_at.c b/Kernel/dev/net/net_at.c
new file mode 100644 (file)
index 0000000..ad3c854
--- /dev/null
@@ -0,0 +1,197 @@
+#include <kernel.h>
+#include <kdata.h>
+#include <netdev.h>
+#include <net_at.h>
+
+/*
+ *     Implement a one socket TCP model for interfaces that provide only AT
+ *     command emulation of ATD addr:port, ATH and carrier line.
+ */
+
+static uint8_t at_state;
+
+static void netat_write(const char *p, uint16_t len)
+{
+  while(len--)
+    netat_outbyte(*p++);
+}
+
+static void netat_write_u8ch(uint8_t v, char c)
+{
+  used(v);
+  /* FIXME: number out */
+  netat_outbyte(c);
+}
+
+static void netat_write_u16ch(uint16_t v, char c)
+{
+  used(v);
+  netat_outbyte(c);
+}
+
+static void wakeup_all(void)
+{
+  wakeup(&sockets[0]);
+  wakeup(&sockets[0].s_data);
+  wakeup(&sockets[0].s_iflag);
+}
+
+void netat_hangup(void)
+{
+  if (sockets[0].s_state != SS_UNUSED) {
+    sockets[0].s_state = SS_CLOSED;
+    sockets[0].s_error = EPIPE;
+    wakeup_all();
+  }
+}
+
+/* We read off the ready event until we get data */
+
+void netat_event(void)
+{
+  uint8_t ch;
+  if (at_state == 4) {
+    sockets[0].s_iflag |= SI_DATA;
+    wakeup(&sockets[0].s_data);
+    netat_nowake();
+    return;
+  }
+  ch = netat_byte();
+  switch(at_state) {
+    case 0:    /* Discard */
+      return;
+    case 1:
+      if (ch == 'O')
+        at_state = 2;
+      else {
+        netat_hangup();
+        at_state = 0;
+      }
+      break;
+    case 2:
+      if (ch == 'K')
+        at_state = 3;
+      else {
+        netat_hangup();
+        at_state = 0;
+      }
+      break;
+    case 3:
+      if (ch != '\n')
+        break;
+      at_state = 4;    /* Don't process */
+      break;
+  }
+}
+
+int net_init(struct socket *s)
+{
+  if (s->s_type != SOCKTYPE_TCP) {
+    udata.u_error = EPFNOSUPPORT;
+    return -1;
+  }
+  return 0;
+}
+
+int net_bind(struct socket *s)
+{
+  s->s_state = SS_BOUND;
+  return 0;
+}
+
+int net_listen(struct socket *s)
+{
+  used(s);
+  udata.u_error = EOPNOTSUPP;
+  return -1;
+}
+  
+int net_connect(struct socket *s)
+{
+  uint32_t n = s->s_addr[SADDR_DST].addr;
+  uint16_t p = s->s_addr[SADDR_DST].port;
+
+  /* Pity drivewire won't talk addresses and ports as a hex block ! */
+  netat_write("ATD ", 4);
+  netat_write_u8ch(n >> 24, '.');
+  netat_write_u8ch(n >> 16, '.');
+  netat_write_u8ch(n >> 8, '.');
+  netat_write_u8ch(n, ' ');
+  netat_write_u16ch(p, '\n');
+  /* Data ready on the channel will do the rest */
+  s->s_state = SS_CONNECTING;
+  at_state = 1;
+  return 0;
+}
+
+void net_close(struct socket *s)
+{
+  if (at_state == 4) {
+    netat_hangup();            /* Either +++ ATH with spacing, or carrier drop */
+    at_state = 0;
+  }
+  s->s_state = SS_UNUSED;
+}
+
+arg_t net_read(struct socket *s, uint8_t flag)
+{
+  uint16_t n = 0;
+  
+  while(1) {
+    if (s->s_state < SS_CONNECTED) {
+      udata.u_error = EINVAL;
+      return -1;
+    }
+    
+    while(netat_ready() && n < udata.u_count) {
+      uputc(netat_byte(), udata.u_base++);
+      n++;
+    }
+    if (n)
+      return n;
+    s->s_iflag &= ~SI_DATA;
+    netat_wake();
+    /* Could do with using timeouts here to be clever for non O_NDELAY so
+       we aggregate data. For now assume a fifo */
+    if (psleep_flags(&s->s_iflag, flag))
+      return -1;
+  }
+}
+
+arg_t net_write(struct socket *s, uint8_t flag)
+{
+  uint16_t n = 0;
+
+  used(s);
+  used(flag);
+
+  while(n < udata.u_count) {
+    if (sockets[0].s_state == SS_CLOSED) {
+      udata.u_error = EPIPE;
+      ssig(udata.u_ptab, SIGPIPE);
+      return -1;
+    }
+    /* FIXME - screen +++ handling ! */
+    netat_outbyte(ugetc(udata.u_base++));
+    n++;
+  }
+  return udata.u_count;
+}
+
+struct netdevice net_dev = {
+  0,
+  "at0",
+  IFF_POINTOPOINT
+};
+
+arg_t net_ioctl(uint8_t op, void *p)
+{
+  used(op);
+  used(p);
+  return -EINVAL;
+}
+
+void netdev_init(void)
+{
+}
+