Hexadecimal and device-level I/O utilities
authorRick van Rein <rick@openfortress.nl>
Sun, 1 Dec 2013 21:25:44 +0000 (21:25 +0000)
committerRick van Rein <rick@openfortress.nl>
Sun, 1 Dec 2013 21:25:44 +0000 (21:25 +0000)
Makefile [new file with mode: 0644]
devio.c [new file with mode: 0644]
inputter.c [new file with mode: 0644]
llcio.c [new file with mode: 0644]
nuttin.c [new file with mode: 0644]
outputter.c [new file with mode: 0644]
pcscio.c [new file with mode: 0644]

diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..4055db4
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,28 @@
+all: inputter outputter devio llcio pcscio
+
+PCSCFLAGS=-D_THREAD_SAFE -I/usr/local/include/PCSC/ -L/usr/local/lib -L/usr/local/lib/pth -ggdb3 -pthread
+
+inputter: inputter.c
+       $(CC) $(CFLAGS) -o inputter inputter.c
+
+outputter: outputter.c
+       $(CC) $(CFLAGS) -o outputter outputter.c
+
+devio: devio.c
+       $(CC) $(CFLAGS) -o devio devio.c
+
+llcio: llcio.c
+       $(CC) $(CFLAGS) -o llcio llcio.c
+
+pcscio: pcscio.c
+       $(CC) $(CFLAGS) $(PCSCFLAGS) -o pcscio pcscio.c -lpcsclite
+
+clean:
+
+very:
+       rm inputter outputter
+
+veryclean: very clean
+
+anew: very clean all
+
diff --git a/devio.c b/devio.c
new file mode 100644 (file)
index 0000000..fa34876
--- /dev/null
+++ b/devio.c
@@ -0,0 +1,62 @@
+/* devio.c -- input/output through a file (char device, socket, ...) */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/select.h>
+
+
+int main (int argc, char *argv []) {
+       int fd;
+       fd_set sel;
+       int busy=1;
+       if (argc != 2) {
+               fprintf (stderr, "Usage: %s /dev/filename\n", argv [0]);
+               exit (1);
+       }
+       if ((fd = open (argv [1], O_RDWR)) < 0) {
+               perror ("Failed to open device");
+               exit (1);
+       }
+       while (busy) {
+               FD_ZERO (&sel);
+               FD_SET (fd, &sel);
+               FD_SET (0,  &sel);
+               if (select (fd+1, &sel, NULL, NULL, NULL) < 0) {
+                       perror ("Select failed");
+                       busy = 0;
+               } else {
+                       if (FD_ISSET (fd, &sel)) {
+                               char buf [100];
+                               int len = read (fd, buf, 100);
+                               if (len < 0) {
+                                       perror ("Error reading");
+                                       busy = 0;
+                               } else {
+                                       if (write (1, buf, len) < len) {
+                                               perror ("Partial write");
+                                               busy = 0;
+                                       }
+                               }
+                       }
+                       if (FD_ISSET (0, &sel)) {
+                               char buf [100];
+                               int len = read (0, buf, 100);
+                               if (len < 0) {
+                                       perror ("Error on stdin");
+                                       busy = 0;
+                               } else {
+                                       if (write (fd, buf, len) < len) {
+                                               perror ("Partial output");
+                                               busy = 0;
+                                       }
+                               }
+                       }
+               }
+               
+       }
+       close (fd);
+}
diff --git a/inputter.c b/inputter.c
new file mode 100644 (file)
index 0000000..e7bff6f
--- /dev/null
@@ -0,0 +1,84 @@
+#include <unistd.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#define BYTES_PER_LINE 35
+
+enum status { normal, endline, error, endfile };
+enum status status = normal;
+
+void ch2hex (char *output, int ch) {
+       if ((ch >= '0') && (ch <= '9')) {
+               *output <<= 4;
+               *output += ch - '0';
+       } else {
+               ch = toupper (ch);
+               if ((ch < 'A') || (ch > 'F')) {
+                       fprintf (stderr, "Illegal char '%c'\n", ch);
+                       status = error;
+               } else {
+                       *output <<= 4;
+                       *output += ch - 'A' + 10;
+               }
+       }
+}
+
+int getbyte (char *output) {
+       int ch;
+
+       *output = 0;
+
+       if (status == error) {
+               return;
+       }
+
+       do {
+               if ((ch = getchar ()) < 0) {
+                       status = endfile;
+                       return 0;
+               }
+               if (ch == '\n') {
+                       status = endline;
+                       return 0;
+               }
+       } while ((ch == ' ') || (ch == ':'));
+
+       if (status == normal) {
+               ch2hex (output, ch);
+               ch = getchar ();
+               ch2hex (output, ch);
+       }
+
+       return (status == normal);
+}
+
+int main (int argc, char *argv []) {
+       size_t offset = 0;
+       size_t len;
+       unsigned char buf [BYTES_PER_LINE];
+       char ch;
+
+       while (status != endfile) {
+               if (status == endline) {
+                       status = normal;
+               }
+               usleep (1000000L); // Yield to others -- better prompt printing
+               fprintf (stderr, "%08x>", offset);
+               fflush (stderr);
+               len = 0;
+               while ((len < BYTES_PER_LINE) && (status == normal)) {
+                       if (getbyte (&buf [len])) {
+                               len++;
+                               offset++;
+                       }
+               }
+               write (1, buf, len);
+               if (status == error) {
+                       while (ch = getchar (), (ch >=0) && (ch!='\n')) {
+                               ;
+                       }
+                       fprintf (stderr, "*** skipped remainder of line ***\n");
+                       status = normal;
+               }
+       }
+}
diff --git a/llcio.c b/llcio.c
new file mode 100644 (file)
index 0000000..1d8ba17
--- /dev/null
+++ b/llcio.c
@@ -0,0 +1,176 @@
+/* llcio -- use a connection over LLC to access a remote stream
+ *
+ * From: Rick van Rein <rick@openfortress.nl>
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+
+#include <linux/llc.h>
+
+// TODO: What includes to use?
+#ifndef PF_LLC
+#  define PF_LLC 26
+#endif
+
+/*
+ * LLC is a protocol that builds directly on top of the
+ * ethernet MAC layer.  It can be connection-oriented or
+ * connectionless, the latter with or without acknowledge.
+ *
+ * Given that it does not run on top of IPv4 or IPv6, it
+ * will not route globally.  This is a disadvantage for
+ * most uses, but it actually is an advantage to others.
+ * As an example use of LLC, think of console I/O with a
+ * networked device that works as soon as the networking
+ * hardware is setup -- specifically, there is no need
+ * for DHCP or any other protocol to obtain a higher level
+ * of existence.  This is the kind of application that
+ * this tool was built for, so it is connection-oriented.
+ *
+ * Linux supports LLC, and that is the basis of this tool.
+ * A simple use of it would be to connect two instances
+ * of this program by telling each what the MAC address and
+ * SAP (service access point, a bit like ports in UDP/TCP)
+ * of the other end is -- and end up with a chat tool that
+ * runs over plain Ethernet.
+ *
+ * The same mechanism is a good replacement for serial
+ * consoles on embedded devices -- a network makes it
+ * easier to approach such a console.
+ */
+
+
+void parsemac (unsigned char mac [6], char *mactxt) {
+       int todo = 6;
+       long val;
+       char *here = mactxt;
+       unsigned char *mactodo = mac;
+       while (todo-- > 0) {
+               val = strtol (here, &here, 16);
+               if ((val < 0x00) || (val > 0xff)) {
+                       fprintf (stderr, "MAC address contains bad byte: 0x%lx\n", val);
+                       exit (1);
+               }
+               *mactodo++ = val;
+               if (*here++ != (todo? ':': '\0')) {
+                       fprintf (stderr, "MAC address not properly formatted: %s\n", mactxt);
+                       exit (1);
+               }
+       }
+}
+
+
+void parsesap (unsigned char *sap, char *saptxt) {
+       char *endptr;
+       long sapval = strtol (saptxt, &endptr, 10);
+       if (*endptr != '\0') {
+               fprintf (stderr, "Failure parsing SAP: %s\n", saptxt);
+               exit (1);
+       }
+       if ((sapval < 0) || (sapval > 127)) {
+               fprintf (stderr, "SAP value must be 7 bit, not %s\n", saptxt);
+               exit (1);
+       }
+       if ((sapval & 0x03) || (sapval <= 0x03)) {
+               fprintf (stderr, "SAP value is a reserved value: %s\n", saptxt);
+               exit (1);
+       }
+       *sap = sapval;
+}
+
+
+int main (int argc, char *argv []) {
+       /* Process parameters */
+       if ((argc != 3) && (argc != 5)) {
+               fprintf (stderr, "Usage: %s local_MAC local_SAP [remote_MAC remote_SAP]\n", argv [0]);
+               exit (1);
+       }
+       /* Acquire LLC socket */
+       int sox = socket (PF_LLC, SOCK_STREAM, 0);
+       if (sox < 0) {
+               perror ("Failed to acquire LLC socket");
+               exit (1);
+       }
+       /* Bind to a local address */
+       struct sockaddr_llc local, remot;
+       bzero (&local, sizeof (local));
+       bzero (&remot, sizeof (remot));
+       local.sllc_family = remot.sllc_family = PF_LLC;
+       local.sllc_arphrd = remot.sllc_arphrd = ARPHRD_ETHER;
+       parsemac ( local.sllc_mac, argv [1]);
+       parsesap (&local.sllc_sap, argv [2]);
+       if (bind (sox, (struct sockaddr *) &local, sizeof (local)) == -1) {
+               perror ("Failed to bind LLC address");
+               exit (1);
+       }
+       /* Choose between client and server role */
+       if (argc == 5) {
+               parsemac ( remot.sllc_mac, argv [3]);
+               parsesap (&remot.sllc_sap, argv [4]);
+               if (connect (sox, (struct sockaddr *) &remot, sizeof (remot)) == -1) {
+                       perror ("Failed to connect to LLC peer");
+                       exit (1);
+               }
+       } else {
+               if (listen (sox, 5) == -1) {
+                       perror ("Failed to listen for LLC peers");
+                       exit (1);
+               }
+               socklen_t remotlen = sizeof (remot);
+               sox = accept (sox, (struct sockaddr *) &remot, &remotlen);
+               if (sox == -1) {
+                       perror ("Failed to accept LLC");
+                       exit (1);
+               }
+       }
+       printf ("Connected\n");
+       int exitcode = 0;
+       while (1) {
+               fd_set inout;
+               FD_ZERO (&inout);
+               FD_SET (0, &inout);
+               FD_SET (sox, &inout);
+               if (select (sox + 1, &inout, NULL, NULL, NULL) == -1) {
+                       perror ("Failed while waiting for input");
+                       exitcode = 1;
+                       break;
+               }
+               char buf [80];
+               int buflen;
+               if (FD_ISSET (0, &inout)) {
+                       buflen = read (0, buf, 80);
+                       if (buflen > 0) {
+                               write (sox, buf, buflen);
+                       } else {
+                               if (buflen < 0) {
+                                       exitcode = 1;
+                                       perror ("Failed to read from stdin");
+                               }
+                               break;
+                       }
+               }
+               if (FD_ISSET (sox, &inout)) {
+                       buflen = read (sox, buf, 80);
+                       if (buflen > 0) {
+                               write (1, buf, buflen);
+                       } else {
+                               if (buflen < 0) {
+                                       exitcode = 1;
+                                       perror ("Failed to read LLC data");
+                               }
+                               break;
+                       }
+               }
+       }
+       /* Cleanup */
+       close (sox);
+       exit (exitcode);
+}
+
diff --git a/nuttin.c b/nuttin.c
new file mode 100644 (file)
index 0000000..268b6cd
--- /dev/null
+++ b/nuttin.c
@@ -0,0 +1,10 @@
+/* zero-content thread-testing program */
+
+#include <stdio.h>
+
+int main (int argc, char *argv []) {
+       int i;
+       for (i=0; i<argc; i++) {
+               printf ("argv [%d] = \"%s\"\n", i, argv [i]);
+       }
+}
diff --git a/outputter.c b/outputter.c
new file mode 100644 (file)
index 0000000..73b7b42
--- /dev/null
@@ -0,0 +1,76 @@
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/time.h>
+#include <signal.h>
+#include <errno.h>
+
+
+/* Outputter reads input from stdin and prints it in hex on stdout.
+ * It will collect lines of one character plus anything that arrives
+ * within a second after that first character, limited to a maximum
+ * number of characters that just fits on a 80-char wide display.
+ */
+
+
+#define BYTES_PER_LINE 24
+
+unsigned long timersofar = 123;
+
+void tick (int signal) {
+       timersofar++;
+}
+
+struct itimerval tickival = { { 0, 0 } , { 1, 0 } };
+struct itimerval stopival = { { 0, 0 } , { 0, 0 } };
+
+int main (int argc, char *argv []) {
+       unsigned char buf [BYTES_PER_LINE];
+       unsigned long timer;
+       size_t len;
+       size_t offset = 0;
+       if (signal (SIGALRM, tick) == SIG_ERR) {
+               perror ("Failed to install interval handler");
+               exit (1);
+       }
+       system ("stty raw -echo");
+       printf ("*** outputter starts -- in hex mode ***\r\n");
+       fflush (stdout);
+/*
+       while (timersofar = timer,
+                       len = read (0, buf, BYTES_PER_LINE),
+                       (len > 0) || ( errno == SIGALRM ) ) {
+*/
+       while (len = read (0, buf, 1), len > 0) {
+               size_t i;
+               int len2;
+               /* Set a timeout before reading more; ignore problems */
+               setitimer (ITIMER_REAL, &tickival, NULL);
+               len2 = read (0, buf + 1, BYTES_PER_LINE - 1);
+               setitimer (ITIMER_REAL, &stopival, NULL);
+               if ((len2 == -1) && (errno == EINTR)) {
+                       len2 = 0;
+               }
+               if (len2 >= 0) {
+                       len += len2;
+               }
+               printf ("%08x", offset);
+               offset += len;
+               for (i=0; i<len; i++) {
+                       printf (" %02x", buf [i]);
+               }
+               printf ("\r\n");
+               fflush (stdout);
+               if (len2 < 0) {
+                       len = -1;
+                       break;
+               }
+       }
+       if (len < 0) {
+               perror ("read(2) failed");
+       } else {
+               printf ("*** outputter ends ***\r\n");
+       }
+       system ("stty cooked echo");
+       return 0;
+}
diff --git a/pcscio.c b/pcscio.c
new file mode 100644 (file)
index 0000000..83f2835
--- /dev/null
+++ b/pcscio.c
@@ -0,0 +1,88 @@
+/* pcscio.c -- input/output through PCSClite */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/select.h>
+
+#include <pthread.h>
+#include <winscard.h>
+
+
+/*
+int             pthread_detach __P((pthread_t pth)) {
+       fprintf (stderr, "ERROR: pthread_detach called\n");
+}
+*/
+
+
+int main (int argc, char *argv []) {
+       int busy=1;
+       SCARDCONTEXT ctx;
+       SCARDHANDLE card;
+       LONG err;
+       DWORD actproto;
+
+       if (SCardEstablishContext (SCARD_SCOPE_SYSTEM, NULL, NULL, &ctx) != SCARD_S_SUCCESS) {
+               fprintf (stderr, "Failed to contact pcscd\n");
+               exit (1);
+       }
+       if (argc != 2) {
+               DWORD listsz=0;
+               LPTSTR readers=NULL, reader=NULL;
+               fprintf (stderr, "Usage: %s readername\n", argv [0]);
+               if ((SCardListReaders (ctx, NULL, NULL, &listsz) == SCARD_S_SUCCESS)
+                && (readers=malloc (listsz))
+                && (SCardListReaders (ctx, NULL, readers, &listsz) == SCARD_S_SUCCESS)) {
+                       fprintf (stderr, "Currently attached readers:\n");
+                       reader = readers;
+                       while (*reader) {
+                               fprintf (stderr, " - %s\n", reader);
+                               reader = reader + strlen (reader);
+                               reader++;
+                       }
+               }
+               if (readers) {
+                       free (readers);
+               }
+               SCardReleaseContext (ctx);
+               exit (1);
+       }
+       err = SCardConnect (ctx, argv [1], SCARD_SHARE_EXCLUSIVE, SCARD_PROTOCOL_T1, &card, &actproto);
+       if (err != SCARD_S_SUCCESS) {
+               fprintf (stderr, "Failed to access the smart card\n");
+               busy = 0;
+       }
+       fprintf (stderr, "Yippy!\n");
+       while (busy) {
+               BYTE txbuf [275], rxbuf [275];
+               DWORD rxlen;
+               SCARD_IO_REQUEST req;
+               int txlen = read (0, txbuf, sizeof (txbuf));
+               if (txlen < 0) {
+                       perror ("Error on stdin");
+                       busy = 0;
+               } else if (txlen == 0) {
+                       /* EOF encountered */
+                       busy = 0;
+               } else {
+                       req.dwProtocol = actproto;
+                       req.cbPciLength = sizeof (req);
+                       rxlen = sizeof (rxbuf);
+                       err = SCardTransmit (card, &req, txbuf, txlen, &req, rxbuf, &rxlen);
+                       if (err != SCARD_S_SUCCESS) {
+                               fprintf (stderr, "Error writing to smart card\n");
+                               busy = 0;
+                       } else {
+                               if (write (1, txbuf, rxlen) < rxlen) {
+                                       perror ("Partial output");
+                                       busy = 0;
+                               }
+                       }
+               }
+       }
+       SCardReleaseContext (ctx);
+}