302 lines
9.8 KiB
C++
302 lines
9.8 KiB
C++
// This file is part of "NPR70 modem firmware" software
|
|
// (A GMSK data modem for ham radio 430-440MHz, at several hundreds of kbps)
|
|
// Copyright (c) 2017-2020 Guillaume F. F4HDK (amateur radio callsign)
|
|
//
|
|
// "NPR70 modem firmware" is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// "NPR70 modem firmware" is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with "NPR70 modem firmware". If not, see <http://www.gnu.org/licenses/>
|
|
|
|
#include "Eth_IPv4.h"
|
|
#include "mbed.h"
|
|
#include "global_variables.h"
|
|
#include "L1L2_radio.h"
|
|
#include "DHCP_ARP.h"
|
|
|
|
static unsigned char temp_Eth_buffer[1600];//temporary buffer waiting for ARP entry
|
|
static unsigned long int temp_Eth_buff_IP;
|
|
static int temp_Eth_buff_size = 0;
|
|
|
|
unsigned long int IP_char2int(unsigned char* IP_char) {
|
|
unsigned long int result;
|
|
result = 0x1000000*IP_char[0] + 0x10000*IP_char[1] + 0x100*IP_char[2] + IP_char[3];
|
|
return result;
|
|
}
|
|
|
|
void IP_int2char (unsigned long int IP_int, unsigned char* IP_char) {
|
|
IP_char[0] = (IP_int & 0xFF000000) / 0x1000000;
|
|
IP_char[1] = (IP_int & 0x00FF0000) / 0x10000;
|
|
IP_char[2] = (IP_int & 0x0000FF00) / 0x100;
|
|
IP_char[3] = (IP_int & 0xFF);
|
|
}
|
|
|
|
//static unsigned char match_RTP_value[2][12] = {// FOR TEST ONLY
|
|
// {0x00, 0x13, 0x3B, 0x73, 0x12, 0xAE},
|
|
// {0x98, 0xDE, 0xD0, 0x01, 0x2D, 0x09}
|
|
//}; //first ping test : MAC filter
|
|
|
|
//void init_RTP_filter(void) {
|
|
//
|
|
//}
|
|
|
|
int Eth_RX_dequeue (W5500_chip* W5500) {
|
|
int answer=0;
|
|
unsigned char RX_data[1600];//1600
|
|
unsigned int RX_port=0;
|
|
unsigned char RX_proto;
|
|
unsigned long int RX_dest_IP=0;
|
|
//unsigned char* RX_Eth_pckt;
|
|
//static int match_RTP_index[12] = {8, 9, 10, 11, 12, 13}; //first ping tests : TX MAC filter
|
|
|
|
static int more_to_read = 0;
|
|
|
|
int RX_size=0;
|
|
int mac_size=0;
|
|
// int i;
|
|
//int match_RTP = 1;
|
|
unsigned int ethertype;
|
|
if (*(W5500->interrupt)==0) {
|
|
W5500_write_byte(W5500, 0x0002, 1, 0xFF);//ack interrupt
|
|
more_to_read=1;
|
|
}
|
|
if ((more_to_read == 1)) {
|
|
RX_size = W5500_read_received_size(W5500, 0);
|
|
//if (RX_size > DEBUG_max_rx_size_w5500) {//!!!
|
|
// DEBUG_max_rx_size_w5500 = RX_size;//!!!
|
|
// printf("max buffer:%i\r\n", DEBUG_max_rx_size_w5500);//!!!
|
|
//}//!!!
|
|
if (RX_size > 0) {
|
|
answer=1;
|
|
|
|
mac_size = W5500_read_MAC_pckt(W5500, 0, RX_data);
|
|
if (RX_size > mac_size) {
|
|
more_to_read = 1;
|
|
} else {
|
|
more_to_read = 0;
|
|
}
|
|
|
|
// Check if RTP packet
|
|
RX_Eth_IPv4_counter++;
|
|
//match_RTP = 1;
|
|
//for (i=0; i<=6; i++) {
|
|
// if (RX_data[match_RTP_index[i]] != match_RTP_value[is_TDMA_master][i]) {
|
|
// match_RTP = 0;
|
|
// }
|
|
|
|
//}
|
|
// FOR FUTURE VIRTUAL CHANNEL
|
|
//if (match_RTP==1) {
|
|
// W5500_write_TX_buffer(W5500, 2, RX_data+44, mac_size-44, 0);
|
|
//}
|
|
|
|
ethertype = RX_data[14]*0x100 + RX_data[15];
|
|
|
|
if (ethertype == 0x0806) { //ARP packet received
|
|
//printf("ARP packet received!\r\n");
|
|
if ((is_TDMA_master == 0)||(CONF_master_FDD<2)) {
|
|
ARP_RX_packet_treatment (RX_data+2, mac_size-2);
|
|
}
|
|
}
|
|
|
|
if (ethertype == 0x0800) { // IPv4 packet
|
|
RX_port = 0;
|
|
RX_proto = 0;
|
|
RX_dest_IP = 0;
|
|
if ( (is_TDMA_master==1) && (CONF_master_FDD == 1) ) {//master down
|
|
//RX_Eth_pckt = RX_data+2;
|
|
RX_port = (RX_data[38] << 8) + RX_data[39];
|
|
RX_proto = RX_data[25];//11 for UDP
|
|
RX_dest_IP = IP_char2int(RX_data+32);
|
|
}
|
|
if ( (RX_proto == 0x11) && (RX_dest_IP == LAN_conf_applied.LAN_modem_IP) && (RX_port == 0x1A3C) ) { // data for FDD down
|
|
//printf("RX_from_Eth\r\n");
|
|
FDDdown_RX_pckt_treat(RX_data+44, mac_size-44);
|
|
} else {
|
|
//printf("RXeth %i\r\n", mac_size-2);
|
|
IPv4_to_radio (RX_data+2, mac_size-2);
|
|
//Eth_pause_frame_TX(10);//!!!
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
}
|
|
return answer;
|
|
}
|
|
|
|
void Eth_pause_frame_TX(unsigned int time) {
|
|
int i;
|
|
unsigned char pause_frame[70] = {
|
|
0x01, 0x80, 0xC2, 0x00, 0x00, 0x01,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x88, 0x08, 0x00, 0x01, 0x4E, 0x70,/* 0x17, 0x70 */
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
|
for (i=0; i<6; i++) {
|
|
pause_frame[i+6] = CONF_modem_MAC[i];
|
|
}
|
|
W5500_write_TX_buffer(W5500_p1, 0, pause_frame, 60, 0);
|
|
}
|
|
|
|
void IPv4_to_radio (unsigned char* RX_Eth_frame, int size) {
|
|
int i;
|
|
unsigned long int dest_IP_addr;
|
|
int MAC_dest_match = 1;
|
|
int is_inside_subnet = 0;
|
|
int is_inside_client_range = 0;
|
|
unsigned char loc_client_ID;
|
|
int radio_tx_need;
|
|
for (i=0; i<6; i++) {
|
|
if (RX_Eth_frame[i] != CONF_modem_MAC[i]) {
|
|
MAC_dest_match = 0;
|
|
}
|
|
}
|
|
radio_tx_need = 0;
|
|
if (MAC_dest_match == 1) {//we only take frame with destination = modem_MAC, not broadcast or multicast
|
|
dest_IP_addr = IP_char2int(RX_Eth_frame+30);
|
|
|
|
if ( (is_TDMA_master == 1) && (dest_IP_addr != LAN_conf_applied.LAN_modem_IP) ) { // TDMA Master
|
|
if ( (dest_IP_addr >= CONF_radio_IP_start) && (dest_IP_addr < (CONF_radio_IP_start + CONF_radio_IP_size) ) ) {
|
|
loc_client_ID = lookfor_client_ID_from_IP (dest_IP_addr);
|
|
//printf ("IP %X is client %i\r\n", dest_IP_addr, loc_client_ID);
|
|
if (loc_client_ID < 250) {
|
|
radio_tx_need = 1;
|
|
|
|
}
|
|
}
|
|
}
|
|
if ( (is_TDMA_master == 0) && (dest_IP_addr != LAN_conf_applied.LAN_modem_IP) ) { // TDMA Client
|
|
if ( (dest_IP_addr & LAN_conf_applied.LAN_subnet_mask) == (LAN_conf_applied.LAN_modem_IP & LAN_conf_applied.LAN_subnet_mask) ) {
|
|
is_inside_subnet = 1;
|
|
}
|
|
if ( (dest_IP_addr >= LAN_conf_applied.DHCP_range_start) && (dest_IP_addr < (LAN_conf_applied.DHCP_range_start + LAN_conf_applied.DHCP_range_size)) ) {
|
|
is_inside_client_range = 1;
|
|
}
|
|
//printf ("inside subnet:%i inside_DHCP%i\r\n", is_inside_subnet, is_inside_client_range);
|
|
// inside subnet but outside radio range -> to master
|
|
if ( (is_inside_subnet == 1) && (is_inside_client_range == 0) ) {
|
|
loc_client_ID = my_radio_client_ID;
|
|
radio_tx_need = 1;
|
|
}
|
|
// outside subnet and IP gateway active -> to master
|
|
if ( (is_inside_subnet == 0) && (LAN_conf_applied.LAN_def_route_activ == 1) ) {
|
|
loc_client_ID = my_radio_client_ID;
|
|
radio_tx_need = 1;
|
|
}
|
|
}
|
|
|
|
if ( (radio_tx_need) && (my_client_radio_connexion_state == 2) ) {
|
|
segment_and_push(RX_Eth_frame + 14, size - 14, loc_client_ID, 0x02); //0x02 is IPv4 access protocol
|
|
//printf("seg&push %i\r\n", size - 14);
|
|
}
|
|
}
|
|
}
|
|
|
|
void IPv4_from_radio (unsigned char* RX_eth_frame, int RX_size) { //Rx size includes ethernet header
|
|
unsigned long int dest_IP_addr;
|
|
unsigned long int LAN_dest_IP;
|
|
int local_size;
|
|
int dest_MAC_found;
|
|
int is_inside_subnet = 0;
|
|
int is_inside_radio_range = 0;
|
|
unsigned char loc_client_ID;
|
|
int i;
|
|
//dest_IP_addr = IP_char2int(RX_radio_frame+16)
|
|
int eth_TX_need = 0;
|
|
int radio_tx_need = 0;
|
|
dest_IP_addr = IP_char2int(RX_eth_frame + 30);
|
|
|
|
local_size = 0x100*RX_eth_frame[16] + RX_eth_frame[17];
|
|
//printf("size IPv4 : %i\r\n", local_size);
|
|
|
|
//printf (" IPv4 radio RX\r\n");
|
|
if (is_TDMA_master == 1) { // TDMA Master
|
|
if ( (dest_IP_addr & LAN_conf_applied.LAN_subnet_mask) == (LAN_conf_applied.LAN_modem_IP & LAN_conf_applied.LAN_subnet_mask) ) {
|
|
is_inside_subnet = 1;
|
|
}
|
|
if ( (dest_IP_addr >= CONF_radio_IP_start) && (dest_IP_addr < (CONF_radio_IP_start + CONF_radio_IP_size) ) ) {
|
|
is_inside_radio_range = 1;
|
|
}
|
|
//printf("IPv4 from R: inside subnet:%i inside_radio:%i\r\n", is_inside_subnet, is_inside_radio_range);
|
|
// destinated to IP on LAN
|
|
if ( (is_inside_subnet == 1) && (is_inside_radio_range == 0) ) {
|
|
eth_TX_need = 1;
|
|
LAN_dest_IP = dest_IP_addr;
|
|
}
|
|
// destinated to gateway (out of subnet)
|
|
if ( (is_inside_subnet == 0) && (LAN_conf_applied.LAN_def_route_activ == 1) ) {
|
|
eth_TX_need = 1;
|
|
LAN_dest_IP = LAN_conf_applied.LAN_def_route;
|
|
}
|
|
//forward to another radio client
|
|
if (is_inside_radio_range) {
|
|
loc_client_ID = lookfor_client_ID_from_IP (dest_IP_addr);
|
|
if (loc_client_ID < 250) {
|
|
radio_tx_need = 1;
|
|
}
|
|
}
|
|
}
|
|
if (is_TDMA_master == 0) { // TDMA client
|
|
// Checks if dest IP is inside local range
|
|
if ( (dest_IP_addr >= LAN_conf_applied.DHCP_range_start) && (dest_IP_addr < (LAN_conf_applied.DHCP_range_start + LAN_conf_applied.DHCP_range_size)) ) {
|
|
eth_TX_need = 1;
|
|
LAN_dest_IP = dest_IP_addr;
|
|
}
|
|
}
|
|
// transmit to Ethernet
|
|
if ( (eth_TX_need) && (local_size < 1510) ) {
|
|
//printf("IPv4 Eth TX\r\n");
|
|
for (i=0; i<6; i++) {
|
|
RX_eth_frame[i+6] = CONF_modem_MAC[i];
|
|
}
|
|
RX_eth_frame[12] = 0x08; // Ethertype IPv4
|
|
RX_eth_frame[13] = 0x00;
|
|
dest_MAC_found = lookfor_MAC_from_IP (RX_eth_frame, LAN_dest_IP);
|
|
if (dest_MAC_found) {
|
|
W5500_write_TX_buffer(W5500_p1, 0, RX_eth_frame, local_size + 14, 0);
|
|
//RX_radio_IPv4_counter++;
|
|
}
|
|
else {
|
|
temp_Eth_buff_IP = LAN_dest_IP;
|
|
temp_Eth_buff_size = local_size + 14;
|
|
memcpy (temp_Eth_buffer, RX_eth_frame, temp_Eth_buff_size);
|
|
}
|
|
}
|
|
// transmit to radio
|
|
if (radio_tx_need) {
|
|
segment_and_push(RX_eth_frame + 14, local_size, loc_client_ID, 0x02); //0x02 is IPv4 access protocol
|
|
//TX_radio_IPv4_counter++;
|
|
}
|
|
}
|
|
|
|
void flush_temp_Eth_buffer(unsigned long int loc_IP) {
|
|
if (temp_Eth_buff_size > 0) {
|
|
if (loc_IP == temp_Eth_buff_IP) {
|
|
lookfor_MAC_from_IP (temp_Eth_buffer, loc_IP); //puts MAC inside Eth
|
|
W5500_write_TX_buffer(W5500_p1, 0, temp_Eth_buffer, temp_Eth_buff_size, 0);
|
|
//RX_radio_IPv4_counter++;
|
|
}
|
|
temp_Eth_buff_size = 0;
|
|
}
|
|
}
|
|
|
|
unsigned char lookfor_client_ID_from_IP(unsigned long int IP_addr) {
|
|
unsigned char i, i_found;
|
|
unsigned long int last_IP;
|
|
i_found = 250;
|
|
|
|
for (i=0; i<radio_addr_table_size; i++) {
|
|
last_IP = CONF_radio_addr_table_IP_begin[i] + CONF_radio_addr_table_IP_size[i];
|
|
if ( (IP_addr >= CONF_radio_addr_table_IP_begin[i]) && (IP_addr < last_IP) ) {
|
|
i_found = i;
|
|
}
|
|
}
|
|
return i_found;
|
|
}
|