Adding port number on the ethernet protocol.
/*
Terminal Mixer - multi-point multi-user access to terminal applications
Copyright (C) 2007 LluĂs Batlle i Rossell
Please find the license in the provided COPYING file.
*/
#include <netinet/in.h>
#include <string.h>
#include <assert.h>
#include <stdio.h>
#include <errno.h>
#include "main.h"
#include "eth_linux.h"
enum {
MAXPACKET = 1500,
MAXSEQ = 100,
HEAD = 13
};
static struct
{
int socket;
char partner[6];
int partner_set;
int send_acked;
int send_retries_left;
unsigned int seq_send;
unsigned int seq_wait;
unsigned int wrong_recv;
char send_buffer[MAXPACKET];
int send_buffer_size;
int port;
} edata;
enum Control {
SEND,
ACK,
INIT
};
static char eth_buffer[MAXPACKET];
static void eth_fill_mac(unsigned char *mac, const char *str);
static int make_head(unsigned char *data, unsigned int seq, enum Control c,
int size)
{
*((unsigned int *) data) = htonl(seq);
data[4] = (unsigned char) c;
*((unsigned int *)(data+5)) = htonl(edata.port);
*((unsigned int *)(data+5+4)) = htonl(size);
return HEAD;
}
static int parse_head(unsigned char *data, unsigned int *seq, enum Control *c,
int *port, int *size)
{
*seq = ntohl( *((unsigned int*) data) );
*c = data[4];
if (port)
*port = ntohl(*((unsigned int *)(data+5)));
if (size)
*size = ntohl(*((unsigned int *)(data+5+4)));
return HEAD;
}
int eth_proto_max_send()
{
return MAXPACKET - HEAD;
}
void eth_proto_init()
{
edata.socket = -1;
edata.port = command_line.eth_port;
edata.seq_send = 0;
edata.seq_wait = 0;
edata.send_acked = 1; /* Fine at the beginning, as if the last data was acked */
edata.partner_set = 0;
}
int eth_proto_allow_sending()
{
return edata.send_acked;
}
static int seq_next(int val)
{
if (val >= 0 && val < MAXSEQ)
val = val + 1;
else
val = 0;
return val;
}
static int seq_before(int val)
{
if (val > 0 && val < MAXSEQ)
val = val - 1;
else
val = MAXSEQ;
return val;
}
int eth_proto_open(enum Eth_type type)
{
edata.socket = eth_open(command_line.eth_device, type);
if (edata.socket == -1)
error("Cannot open device %s", command_line.eth_device);
if ( !command_line.is_server)
{
if (command_line.c_param.server_address == 0)
error("You must specify the MAC you want to connect to.");
eth_fill_mac(edata.partner, command_line.c_param.server_address);
edata.partner_set = 1;
make_head(eth_buffer, edata.seq_send, INIT, 0);
eth_send(command_line.eth_device, edata.partner, eth_buffer, HEAD);
edata.seq_send = seq_next(edata.seq_send);
}
return edata.socket;
}
int eth_proto_recv(char *data, int size)
{
int res;
int seq;
int data_length;
int port;
enum Control c;
char partner[6];
do {
res = eth_recv(eth_buffer, sizeof(eth_buffer), partner);
edata.partner_set = 1;
} while(res < HEAD);
parse_head(eth_buffer, &seq, &c, &port, &data_length);
if (port != edata.port)
return -1; /* Nothing the parent should care about. Not a packet for us. */
/* We admit any first connection */
if (seq == 0 && c == INIT)
{
edata.seq_wait = 1; /* next of the just receive 0 */
edata.seq_send = 0; /* New partner we send to, so 0 sent */
memcpy(edata.partner, partner, sizeof(edata.partner));
return -1; /* Nothing the parent should care about */
}
if (c == SEND)
{
if (seq != edata.seq_wait && seq != seq_before(edata.seq_wait))
{
dump_line("Wrong data packet seq received. Recvd: %i Expected: %i\n",
seq, edata.seq_wait);
edata.wrong_recv++;
return -1;
}
if (seq == seq_before(edata.seq_wait))
dump_line("Repeated data seq received: %i\n", seq);
if (seq == edata.seq_wait)
{
if (data_length == 0)
{
edata.partner_set = 0;
edata.seq_wait = 0;
edata.seq_send = 0;
/* We should send ACK anyway */
}
else
{
memcpy(data, eth_buffer + HEAD, data_length);
edata.seq_wait = seq_next(edata.seq_wait);
}
}
/* Ack the packed we received. In these conditions:
* - We received the packed we expected
* - We received a repeat of the old packet. The
* ACK was lost probably, so we resend it */
make_head(eth_buffer, seq, ACK, 0);
eth_send(command_line.eth_device, edata.partner, eth_buffer, HEAD);
}
else if (c == ACK)
{
if (seq == edata.seq_send)
{
edata.send_acked = 1;
edata.seq_send = seq_next(edata.seq_send);
unprogram_timeout();
}
else
{
dump_line("Wrong ack received. Recvd: %i Expected: %i\n",
seq, edata.seq_send);
}
return -1; /* not data */
}
else
return -1;
return data_length;
}
static int eth_proto_link_send()
{
int sent;
sent = eth_send(command_line.eth_device,
edata.partner,
edata.send_buffer,
edata.send_buffer_size);
if (sent >= 0) /* expected */
{
edata.send_retries_left -= 1;
edata.send_acked = 0;
program_timeout(1);
}
else /* strange case, data not sent */
{
sent = 0;
edata.send_acked = 1;
}
return sent;
}
int eth_proto_send(const char *data, int size)
{
int sent;
assert(edata.send_acked);
if (!edata.partner_set)
{
if (edata.seq_send == 0 && !command_line.is_server
&& command_line.c_param.server_address != 0)
{
eth_fill_mac(edata.partner, command_line.c_param.server_address);
edata.partner_set = 1;
}
else
return 0;
}
edata.send_retries_left = 3;
/* Prepare packet */
make_head(edata.send_buffer, edata.seq_send, SEND, size);
memcpy(edata.send_buffer+HEAD, data, size);
edata.send_buffer_size = size + HEAD;
sent = eth_proto_link_send();
sent -= HEAD;
return sent;
}
int eth_proto_process_timeouts()
{
if (!edata.send_acked && did_timeout_happen())
{
unprogram_timeout();
if (edata.send_retries_left > 0)
{
dump_line("Retrying. Left:%i\n", edata.send_retries_left);
eth_proto_link_send();
}
else
{
/* The connection has been lost */
dump_line("Connection lost");
edata.send_acked = 1;
edata.partner_set = 0;
edata.seq_wait = 0;
edata.seq_send = 0;
return 0; /* FAIL */
}
}
return 1; /* OK */
}
static void eth_fill_mac(unsigned char *mac, const char *str)
{
int res;
int imac[6];
res = sscanf(str, "%x:%x:%x:%x:%x:%x",
&imac[0], &imac[1], &imac[2], &imac[3], &imac[4], &imac[5]);
if (res != 6)
{
error("Error parsing mac: %02x:%02x:%02x:%02x:%02x:%02x\n",
imac[0], imac[1], imac[2], imac[3], imac[4], imac[5]);
}
mac[0] = imac[0]; mac[1] = imac[1]; mac[2] = imac[2];
mac[3] = imac[3]; mac[4] = imac[4]; mac[5] = imac[5];
}