1 /*
2 Terminal Mixer - multi-point multi-user access to terminal applications
3 Copyright (C) 2007 Lluís Batlle i Rossell
4
5 Please find the license in the provided COPYING file.
6 */
7 #include <netinet/in.h>
8 #include <string.h>
9 #include <assert.h>
10 #include <stdio.h>
11 #include <errno.h>
12
13 #include "main.h"
14 #include "eth_linux.h"
15
16 enum {
17 MAXPACKET = 1500,
18 MAXSEQ = 100,
19 HEAD = 13
20 };
21
22 static struct
23 {
24 int socket;
25 char partner[6];
26 int partner_set;
27 int send_acked;
28 int send_retries_left;
29 unsigned int seq_send;
30 unsigned int seq_wait;
31 unsigned int wrong_recv;
32 char send_buffer[MAXPACKET];
33 int send_buffer_size;
34 int port;
35 } edata;
36
37 enum Control {
38 SEND,
39 ACK,
40 INIT
41 };
42
43 static char eth_buffer[MAXPACKET];
44
45 static void eth_fill_mac(unsigned char *mac, const char *str);
46
make_head(unsigned char * data,unsigned int seq,enum Control c,int size)47 static int make_head(unsigned char *data, unsigned int seq, enum Control c,
48 int size)
49 {
50 *((unsigned int *) data) = htonl(seq);
51 data[4] = (unsigned char) c;
52 *((unsigned int *)(data+5)) = htonl(edata.port);
53 *((unsigned int *)(data+5+4)) = htonl(size);
54 return HEAD;
55 }
56
parse_head(unsigned char * data,unsigned int * seq,enum Control * c,int * port,int * size)57 static int parse_head(unsigned char *data, unsigned int *seq, enum Control *c,
58 int *port, int *size)
59 {
60 *seq = ntohl( *((unsigned int*) data) );
61 *c = data[4];
62 if (port)
63 *port = ntohl(*((unsigned int *)(data+5)));
64 if (size)
65 *size = ntohl(*((unsigned int *)(data+5+4)));
66 return HEAD;
67 }
68
eth_proto_max_send()69 int eth_proto_max_send()
70 {
71 return MAXPACKET - HEAD;
72 }
73
eth_proto_init()74 void eth_proto_init()
75 {
76 edata.socket = -1;
77 edata.port = command_line.eth_port;
78 edata.seq_send = 0;
79 edata.seq_wait = 0;
80 edata.send_acked = 1; /* Fine at the beginning, as if the last data was acked */
81 edata.partner_set = 0;
82 }
83
eth_proto_allow_sending()84 int eth_proto_allow_sending()
85 {
86 return edata.send_acked;
87 }
88
seq_next(int val)89 static int seq_next(int val)
90 {
91 if (val >= 0 && val < MAXSEQ)
92 val = val + 1;
93 else
94 val = 0;
95 return val;
96 }
97
seq_before(int val)98 static int seq_before(int val)
99 {
100 if (val > 0 && val < MAXSEQ)
101 val = val - 1;
102 else
103 val = MAXSEQ;
104 return val;
105 }
106
eth_proto_open(enum Eth_type type)107 int eth_proto_open(enum Eth_type type)
108 {
109 edata.socket = eth_open(command_line.eth_device, type);
110 if (edata.socket == -1)
111 error("Cannot open device %s", command_line.eth_device);
112
113 if ( !command_line.is_server)
114 {
115 if (command_line.c_param.server_address == 0)
116 error("You must specify the MAC you want to connect to.");
117 eth_fill_mac(edata.partner, command_line.c_param.server_address);
118 edata.partner_set = 1;
119
120 make_head(eth_buffer, edata.seq_send, INIT, 0);
121 eth_send(command_line.eth_device, edata.partner, eth_buffer, HEAD);
122 edata.seq_send = seq_next(edata.seq_send);
123 }
124
125 return edata.socket;
126 }
127
eth_proto_recv(char * data,int size)128 int eth_proto_recv(char *data, int size)
129 {
130 int res;
131 int seq;
132 int data_length;
133 int port;
134 enum Control c;
135 char partner[6];
136
137 do {
138 res = eth_recv(eth_buffer, sizeof(eth_buffer), partner);
139 edata.partner_set = 1;
140 } while(res < HEAD);
141 parse_head(eth_buffer, &seq, &c, &port, &data_length);
142 if (port != edata.port)
143 return -1; /* Nothing the parent should care about. Not a packet for us. */
144
145 /* We admit any first connection */
146 if (seq == 0 && c == INIT)
147 {
148 edata.seq_wait = 1; /* next of the just receive 0 */
149 edata.seq_send = 0; /* New partner we send to, so 0 sent */
150 memcpy(edata.partner, partner, sizeof(edata.partner));
151 return -1; /* Nothing the parent should care about */
152 }
153 if (c == SEND)
154 {
155 if (seq != edata.seq_wait && seq != seq_before(edata.seq_wait))
156 {
157 dump_line("Wrong data packet seq received. Recvd: %i Expected: %i\n",
158 seq, edata.seq_wait);
159 edata.wrong_recv++;
160 return -1;
161 }
162
163 if (seq == seq_before(edata.seq_wait))
164 dump_line("Repeated data seq received: %i\n", seq);
165
166 if (seq == edata.seq_wait)
167 {
168 if (data_length == 0)
169 {
170 edata.partner_set = 0;
171 edata.seq_wait = 0;
172 edata.seq_send = 0;
173 /* We should send ACK anyway */
174 }
175 else
176 {
177 memcpy(data, eth_buffer + HEAD, data_length);
178 edata.seq_wait = seq_next(edata.seq_wait);
179 }
180 }
181
182 /* Ack the packed we received. In these conditions:
183 * - We received the packed we expected
184 * - We received a repeat of the old packet. The
185 * ACK was lost probably, so we resend it */
186 make_head(eth_buffer, seq, ACK, 0);
187 eth_send(command_line.eth_device, edata.partner, eth_buffer, HEAD);
188 }
189 else if (c == ACK)
190 {
191 if (seq == edata.seq_send)
192 {
193 edata.send_acked = 1;
194 edata.seq_send = seq_next(edata.seq_send);
195 unprogram_timeout();
196 }
197 else
198 {
199 dump_line("Wrong ack received. Recvd: %i Expected: %i\n",
200 seq, edata.seq_send);
201 }
202 return -1; /* not data */
203 }
204 else
205 return -1;
206
207 return data_length;
208 }
209
eth_proto_link_send()210 static int eth_proto_link_send()
211 {
212 int sent;
213 sent = eth_send(command_line.eth_device,
214 edata.partner,
215 edata.send_buffer,
216 edata.send_buffer_size);
217
218 if (sent >= 0) /* expected */
219 {
220 edata.send_retries_left -= 1;
221 edata.send_acked = 0;
222 program_timeout(1);
223 }
224 else /* strange case, data not sent */
225 {
226 sent = 0;
227 edata.send_acked = 1;
228 }
229 return sent;
230 }
231
eth_proto_send(const char * data,int size)232 int eth_proto_send(const char *data, int size)
233 {
234 int sent;
235
236 assert(edata.send_acked);
237
238 if (!edata.partner_set)
239 {
240 if (edata.seq_send == 0 && !command_line.is_server
241 && command_line.c_param.server_address != 0)
242 {
243 eth_fill_mac(edata.partner, command_line.c_param.server_address);
244 edata.partner_set = 1;
245 }
246 else
247 return 0;
248 }
249
250 edata.send_retries_left = 3;
251
252 /* Prepare packet */
253 make_head(edata.send_buffer, edata.seq_send, SEND, size);
254 memcpy(edata.send_buffer+HEAD, data, size);
255 edata.send_buffer_size = size + HEAD;
256
257 sent = eth_proto_link_send();
258 sent -= HEAD;
259 return sent;
260 }
261
eth_proto_process_timeouts()262 int eth_proto_process_timeouts()
263 {
264 if (!edata.send_acked && did_timeout_happen())
265 {
266 unprogram_timeout();
267 if (edata.send_retries_left > 0)
268 {
269 dump_line("Retrying. Left:%i\n", edata.send_retries_left);
270 eth_proto_link_send();
271 }
272 else
273 {
274 /* The connection has been lost */
275 dump_line("Connection lost");
276 edata.send_acked = 1;
277 edata.partner_set = 0;
278 edata.seq_wait = 0;
279 edata.seq_send = 0;
280 return 0; /* FAIL */
281 }
282 }
283 return 1; /* OK */
284 }
285
eth_fill_mac(unsigned char * mac,const char * str)286 static void eth_fill_mac(unsigned char *mac, const char *str)
287 {
288 int res;
289 int imac[6];
290 res = sscanf(str, "%x:%x:%x:%x:%x:%x",
291 &imac[0], &imac[1], &imac[2], &imac[3], &imac[4], &imac[5]);
292 if (res != 6)
293 {
294 error("Error parsing mac: %02x:%02x:%02x:%02x:%02x:%02x\n",
295 imac[0], imac[1], imac[2], imac[3], imac[4], imac[5]);
296 }
297 mac[0] = imac[0]; mac[1] = imac[1]; mac[2] = imac[2];
298 mac[3] = imac[3]; mac[4] = imac[4]; mac[5] = imac[5];
299 }
300