-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathmain.c
208 lines (173 loc) · 5.53 KB
/
main.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <net/if.h>
#include <libserialport.h>
#include <pthread.h>
#include <linux/if_tun.h>
#include "slip.h"
#include "tun-driver.h"
struct CommDevices {
int tunFileDescriptor;
struct sp_port *serialPort;
};
char adapterName[IFNAMSIZ];
char serialPortName[128];
int serialBaudRate = 9600;
/**
* Handles getting packets from the serial port and writing them to the TUN interface
* @param ptr - Pointer to the CommDevices struct
*/
void *serialToTun(void *ptr) {
// Grab thread parameters
struct CommDevices *args = ptr;
int tunFd = args->tunFileDescriptor;
struct sp_port *serialPort = args->serialPort;
// Create two buffers, one to store raw data from the serial port and
// one to store SLIP frames
unsigned char inBuffer[4096];
unsigned char outBuffer[4096] = {0};
unsigned long outSize = 0;
int inIndex = 0;
// Incoming byte count
size_t count;
// Serial result
enum sp_return serialResult;
// Add 'RX ready' event to serial port
struct sp_event_set *eventSet;
sp_new_event_set(&eventSet);
sp_add_port_events(eventSet, serialPort, SP_EVENT_RX_READY);
while (1) {
// Wait for the event (RX Ready)
sp_wait(eventSet, 0);
count = sp_input_waiting(serialPort); // Bytes ready for reading
// Read bytes from serial
serialResult = sp_blocking_read(serialPort, &inBuffer[inIndex], count, 0);
if (serialResult < 0) {
fprintf(stderr, "Serial error! %d\n", serialResult);
} else {
// We need to check if there is an SLIP_END sequence in the new bytes
for (unsigned long i = 0; i < serialResult; i++) {
if (inBuffer[inIndex] == SLIP_END) {
// Decode the packet that is marked by SLIP_END
slip_decode(inBuffer, inIndex, outBuffer, 4096, &outSize);
// Write the packet to the virtual interface
write(tunFd, outBuffer, outSize);
// Copy the remaining data (belonging to the next packet)
// to the start of the buffer
memcpy(inBuffer, &inBuffer[inIndex + 1], serialResult - i - 1);
inIndex = serialResult - i - 1;
break;
} else {
inIndex++;
}
}
}
}
}
void *tunToSerial(void *ptr) {
// Grab thread parameters
struct CommDevices *args = ptr;
int tunFd = args->tunFileDescriptor;
struct sp_port *serialPort = args->serialPort;
// Create TUN buffer
unsigned char inBuffer[2048];
unsigned char outBuffer[4096];
// Incoming byte count
ssize_t count;
// Encoded data size
unsigned long encodedLength = 0;
// Serial error messages
enum sp_return serialResult;
while (1) {
count = read(tunFd, inBuffer, sizeof(inBuffer));
if (count < 0) {
fprintf(stderr, "Could not read from interface\n");
}
// Encode data
slip_encode(inBuffer, (unsigned long) count, outBuffer, 4096, &encodedLength);
// Write to serial port
serialResult = sp_nonblocking_write(serialPort, outBuffer, encodedLength);
if (serialResult < 0) {
fprintf(stderr, "Could not send data to serial port: %d\n", serialResult);
}
}
}
int main(int argc, char *argv[]) {
// Grab parameters
int param;
while ((param = getopt(argc, argv, "i:p:b:")) > 0) {
switch (param) {
case 'i':
strncpy(adapterName, optarg, IFNAMSIZ - 1);
break;
case 'p':
strncpy(serialPortName, optarg, sizeof(serialPortName) - 1);
break;
case 'b':
serialBaudRate = atoi(optarg);
break;
default:
fprintf(stderr, "Unknown parameter %c\n", param);
break;
}
}
if (adapterName[0] == '\0') {
fprintf(stderr, "Adapter name required (-i)\n");
return EXIT_FAILURE;
}
if (serialPortName[0] == '\0') {
fprintf(stderr, "Serial port required (-p)\n");
return EXIT_FAILURE;
}
int tunFd = tun_alloc(adapterName, IFF_TUN | IFF_NO_PI);
if (tunFd < 0) {
fprintf(stderr, "Could not open /dev/net/tun\n");
return EXIT_FAILURE;
}
// Configure & open serial port
struct sp_port *serialPort;
sp_get_port_by_name(serialPortName, &serialPort);
enum sp_return status = sp_open(serialPort, SP_MODE_READ_WRITE);
sp_set_bits(serialPort, 8);
sp_set_parity(serialPort, SP_PARITY_NONE);
sp_set_stopbits(serialPort, 1);
sp_set_baudrate(serialPort, serialBaudRate);
sp_set_xon_xoff(serialPort, SP_XONXOFF_DISABLED);
sp_set_flowcontrol(serialPort, SP_FLOWCONTROL_NONE);
if (status < 0) {
fprintf(stderr, "Could not open serial port: ");
switch (status) {
case SP_ERR_ARG:
fprintf(stderr, "Invalid argument\n");
break;
case SP_ERR_FAIL:
fprintf(stderr, "System error\n");
break;
case SP_ERR_MEM:
fprintf(stderr, "Memory allocation error\n");
break;
case SP_ERR_SUPP:
fprintf(stderr, "Operation not supported by device\n");
break;
default:
fprintf(stderr, "Unknown error\n");
break;
}
return EXIT_FAILURE;
}
// Create threads
pthread_t tun2serial, serial2tun;
int ret1, ret2;
struct CommDevices threadParams;
threadParams.tunFileDescriptor = tunFd;
threadParams.serialPort = serialPort;
printf("Starting threads\n");
ret1 = pthread_create(&tun2serial, NULL, tunToSerial, (void *) &threadParams);
ret2 = pthread_create(&serial2tun, NULL, serialToTun, (void *) &threadParams);
pthread_join(tun2serial, NULL);
printf("Thread tun-to-network returned %d\n", ret1);
pthread_join(serial2tun, NULL);
printf("Thread network-to-tun returned %d\n", ret2);
}