NPR70/NPR_14/source/Eth_IPv4.cpp
2025-07-09 12:02:01 +02:00

302 lines
12 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;
}