Added OID and INTEGER interpretation to derdump.py
[hexio] / llcio.c
1 /* llcio -- use a connection over LLC to access a remote stream
2  *
3  * From: Rick van Rein <rick@openfortress.nl>
4  */
5
6 #include <stdlib.h>
7 #include <stdio.h>
8 #include <string.h>
9
10 #include <net/if.h>
11 #include <net/if_arp.h>
12 #include <sys/socket.h>
13 #include <sys/select.h>
14
15 #include <linux/llc.h>
16
17 // TODO: What includes to use?
18 #ifndef PF_LLC
19 #  define PF_LLC 26
20 #endif
21
22 /*
23  * LLC is a protocol that builds directly on top of the
24  * ethernet MAC layer.  It can be connection-oriented or
25  * connectionless, the latter with or without acknowledge.
26  *
27  * Given that it does not run on top of IPv4 or IPv6, it
28  * will not route globally.  This is a disadvantage for
29  * most uses, but it actually is an advantage to others.
30  * As an example use of LLC, think of console I/O with a
31  * networked device that works as soon as the networking
32  * hardware is setup -- specifically, there is no need
33  * for DHCP or any other protocol to obtain a higher level
34  * of existence.  This is the kind of application that
35  * this tool was built for, so it is connection-oriented.
36  *
37  * Linux supports LLC, and that is the basis of this tool.
38  * A simple use of it would be to connect two instances
39  * of this program by telling each what the MAC address and
40  * SAP (service access point, a bit like ports in UDP/TCP)
41  * of the other end is -- and end up with a chat tool that
42  * runs over plain Ethernet.
43  *
44  * The same mechanism is a good replacement for serial
45  * consoles on embedded devices -- a network makes it
46  * easier to approach such a console.
47  */
48
49
50 void parsemac (unsigned char mac [6], char *mactxt) {
51         int todo = 6;
52         long val;
53         char *here = mactxt;
54         unsigned char *mactodo = mac;
55         while (todo-- > 0) {
56                 val = strtol (here, &here, 16);
57                 if ((val < 0x00) || (val > 0xff)) {
58                         fprintf (stderr, "MAC address contains bad byte: 0x%lx\n", val);
59                         exit (1);
60                 }
61                 *mactodo++ = val;
62                 if (*here++ != (todo? ':': '\0')) {
63                         fprintf (stderr, "MAC address not properly formatted: %s\n", mactxt);
64                         exit (1);
65                 }
66         }
67 }
68
69
70 void parsesap (unsigned char *sap, char *saptxt) {
71         char *endptr;
72         long sapval = strtol (saptxt, &endptr, 10);
73         if (*endptr != '\0') {
74                 fprintf (stderr, "Failure parsing SAP: %s\n", saptxt);
75                 exit (1);
76         }
77         if ((sapval < 0) || (sapval > 127)) {
78                 fprintf (stderr, "SAP value must be 7 bit, not %s\n", saptxt);
79                 exit (1);
80         }
81         if ((sapval & 0x03) || (sapval <= 0x03)) {
82                 fprintf (stderr, "SAP value is a reserved value: %s\n", saptxt);
83                 exit (1);
84         }
85         *sap = sapval;
86 }
87
88
89 int main (int argc, char *argv []) {
90         /* Process parameters */
91         if ((argc != 3) && (argc != 5)) {
92                 fprintf (stderr, "Usage: %s local_MAC local_SAP [remote_MAC remote_SAP]\n", argv [0]);
93                 exit (1);
94         }
95         /* Acquire LLC socket */
96         int sox = socket (PF_LLC, SOCK_STREAM, 0);
97         if (sox < 0) {
98                 perror ("Failed to acquire LLC socket");
99                 exit (1);
100         }
101         /* Bind to a local address */
102         struct sockaddr_llc local, remot;
103         bzero (&local, sizeof (local));
104         bzero (&remot, sizeof (remot));
105         local.sllc_family = remot.sllc_family = PF_LLC;
106         local.sllc_arphrd = remot.sllc_arphrd = ARPHRD_ETHER;
107         parsemac ( local.sllc_mac, argv [1]);
108         parsesap (&local.sllc_sap, argv [2]);
109         if (bind (sox, (struct sockaddr *) &local, sizeof (local)) == -1) {
110                 perror ("Failed to bind LLC address");
111                 exit (1);
112         }
113         /* Choose between client and server role */
114         if (argc == 5) {
115                 parsemac ( remot.sllc_mac, argv [3]);
116                 parsesap (&remot.sllc_sap, argv [4]);
117                 if (connect (sox, (struct sockaddr *) &remot, sizeof (remot)) == -1) {
118                         perror ("Failed to connect to LLC peer");
119                         exit (1);
120                 }
121         } else {
122                 if (listen (sox, 5) == -1) {
123                         perror ("Failed to listen for LLC peers");
124                         exit (1);
125                 }
126                 socklen_t remotlen = sizeof (remot);
127                 sox = accept (sox, (struct sockaddr *) &remot, &remotlen);
128                 if (sox == -1) {
129                         perror ("Failed to accept LLC");
130                         exit (1);
131                 }
132         }
133         printf ("Connected\n");
134         int exitcode = 0;
135         while (1) {
136                 fd_set inout;
137                 FD_ZERO (&inout);
138                 FD_SET (0, &inout);
139                 FD_SET (sox, &inout);
140                 if (select (sox + 1, &inout, NULL, NULL, NULL) == -1) {
141                         perror ("Failed while waiting for input");
142                         exitcode = 1;
143                         break;
144                 }
145                 char buf [80];
146                 int buflen;
147                 if (FD_ISSET (0, &inout)) {
148                         buflen = read (0, buf, 80);
149                         if (buflen > 0) {
150                                 write (sox, buf, buflen);
151                         } else {
152                                 if (buflen < 0) {
153                                         exitcode = 1;
154                                         perror ("Failed to read from stdin");
155                                 }
156                                 break;
157                         }
158                 }
159                 if (FD_ISSET (sox, &inout)) {
160                         buflen = read (sox, buf, 80);
161                         if (buflen > 0) {
162                                 write (1, buf, buflen);
163                         } else {
164                                 if (buflen < 0) {
165                                         exitcode = 1;
166                                         perror ("Failed to read LLC data");
167                                 }
168                                 break;
169                         }
170                 }
171         }
172         /* Cleanup */
173         close (sox);
174         exit (exitcode);
175 }
176