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