--- /dev/null
+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
+
--- /dev/null
+/* 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);
+}
--- /dev/null
+#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;
+ }
+ }
+}
--- /dev/null
+/* 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);
+}
+
--- /dev/null
+/* 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]);
+ }
+}
--- /dev/null
+#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;
+}
--- /dev/null
+/* 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);
+}