[
Date Prev][
Date Next][
Thread Prev][
Thread Next][
Date Index][
Thread Index]
[
List Home]
[threadx-dev] Tunneldriver for the Linux-Port / Problems with BSD
|
- From: Rudolf Weber <rwissag@xxxxxx>
- Date: Sat, 8 Feb 2025 07:40:09 +0000
- Delivered-to: threadx-dev@xxxxxxxxxxx
- List-archive: <https://www.eclipse.org/mailman/private/threadx-dev/>
- List-help: <mailto:threadx-dev-request@eclipse.org?subject=help>
- List-subscribe: <https://www.eclipse.org/mailman/listinfo/threadx-dev>, <mailto:threadx-dev-request@eclipse.org?subject=subscribe>
- List-unsubscribe: <https://www.eclipse.org/mailman/options/threadx-dev>, <mailto:threadx-dev-request@eclipse.org?subject=unsubscribe>
- Ui-outboundreport: notjunk:1;M01:P0:SaIr8llzJHw=;v0/fXZxmAW/9mqqbJMdsxg4n1IU 1/Sc4Qs0wCCZX/OG9CXCxgF8vgozFAFwEIgV5jIgzBoguwSYXsqfGMlbp5AmD8E0HSTG2gP8f PLD+SL/W+zS1f7Fjkg7mkC51m4iwY87FC19uOe6LwVZtl2x0RLv5/fEuP+UnjfJEeV1XzygDw oq/XUBDSXFjdkeO8IGs1a6OtXGCutil1nmg72O2sIWtkH7XNh7XgauSJZblRec8QMtqsb5V3O MR37irs8s1dcUfYWaYzaaAnCKJ+PZCsXP/8d7yKCRGNPZzugKCti2MHVDV9+Mx5PRU57ON/qy CrRb+J23Jc7NMKKXnecLhbXCd9Q5chnc/cyB1v7DCnHhfkL4v8GFj/IOYaHEM4M3Hu0mjbrtK FqaaMNFoV7EhPc/A7xFbS96MkiKOfiNTM8DS3ElUbaZkuKTk4Nw3TweLsx9ZWYCyTH4v2nm2c Fhcxvwz1Gssnv1EmcLd9/P5bdmt34GGpkIHv8tX5oH2dU3itWzr/KEa1Bl1+S4Y4NViLspMu6 mKHfXp5u3vSvS+ThhAmJqEDAM0a4xSoHH1zXLtvun52rjma0eJZ1xtkO8wP/L8QA5GXt+m4zn M0osbas7uSMRf8pg3oRSvSRNI3mCyNMdpqBl6ABs0RaYfDFLHkXWYGqbSe84NC4nan5h68PBQ OBzIZf4joKkTa8b5g9QFgZoNbPS4mpVF5jXp8092XGRqvXXcOxuv+hYRngD3bTZ6xoWKz/08J JLHHK9r6D+8j1ed+wO/cvrUPSmAYZ+bbNEExGRdUt+pg2SrqrE3BEW0HUtcSDU40EhwANPYB2 ipJtX7PEzDgj+zJjz5ShEvO5LHZY+p8ERt0egx/TSVSG7ZLXDRyHiM1D1izEjuFTCXq5p0CFF av0+mSt/Bq2jh7sqUcI2+zy+af6rfbnukm4MnfMl+QwOQmiSI72qFcoc3nt21REOq3R5cU3vP 9ejFAJO8rn1kXY2v7sUM0rOIqU3MQc9FypDTZ+037LtItOM5aP6Guk683uYqszrpCHEVxSp/Z ABOsQsIXOkU4DHeCw2rVHYb7L2feY1yogYjN1zNf6RXU9pLuF4OTp+b6lQDMv8Tfh+7uHqMag po1H998TlnP/WInoPr7Mp1iEOz0cHa6pGawZ9Xl2QFr8A0vKOleGAa1eTfVA99v4N8hrVAqIj hisZujBlWRPNqSH9QoLubuluTaHKLSv736/a3OvfS3B5Rb/Vg2t3QTAv33a+LFBBHTIGQhC7g 26PkPc00XgYH
Hello,
I have tested threadx/netXDuo with a tunnel driver on Linux. I want to contribute the tunnel driver.
The Linuxprocess "udpserver" consists of
- ThreadX
- NetXduo
- tunnel_network_driver.c
- udpserver.c
as initialization and application code.
When it starts, it opens an internetdevice tun0.
In an other shell we initialize the tun0 with
ifconfig tun0 10.0.5.1 netmask 255.255.255.0 up
The tunnel_network_driver listens with read(2) on /dev/net/tun and sends with write(2).
ping 10.0.5.2
gets a response, thus it is working in principle.
Problem:
A UDP-Message does not awake a select/unblock receive_from
Problem:
A UDP-Message does not awake a select/unblock receive_from
select case:
Select blocks in: nxd_bsd.c:8248 status = tx_event_flags_get(&nx_bsd_events, NX_BSD_SELECT_EVENT, TX_OR_CLEAR, (ULONG *) &suspend_request, ticks);
When a UDP-Packet arrives, it goes up the TCP/IP-Stack until lead to call:
nxd_bsd.c:10372: tx_event_flags_set(&nx_bsd_events, NX_BSD_RECEIVE_EVENT, TX_OR);
NX_BSD_SELECT_EVENT and NX_BSD_RECEIVE_EVENT are defined in nxd_bsd.h:
#define NX_BSD_RECEIVE_EVENT ((ULONG) 0x00000001) /* Event flag to signal a receive packet event */
#define NX_BSD_SELECT_EVENT ((ULONG) 0x00008000) /* Event flag to signal a thread is waiting in select */
Since NX_BSD_SELECT_EVENT != NX_BSD_RECEIVE_EVENT, it's obvious, that the select in still blocking in tx_event_flags_get.
I tried tx_event_flags_set(&nx_bsd_events, NX_BSD_RECEIVE_EVENT|NX_BSD_SELECT_EVENT, TX_OR); in nxd_bsd.c:10372, but it doesn't change the behavior.
What is wrong ?
Greetings from Ravensburg Germany
Rudolf
P.S.: Since I'm not experienced in cmake, I build threadx and netxduo with the Makefiles in the attachments
Attachment:
Makefile
Description: Binary data
Attachment:
Makefile
Description: Binary data
/**
* UDP_Server receives a packet and answers
*/
#include "tx_api.h"
#include "nx_api.h"
#include "nxd_bsd.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "tunnel_network_driver.h"
#define DEMO_STACK_SIZE 2048
#define SERVER_PORT 2000
/* Define the ThreadX and NetX object control blocks... */
TX_THREAD thread_server;
NX_PACKET_POOL bsd_pool;
NX_IP bsd_ip;
ULONG error_counter=0;
VOID thread_server_entry(ULONG thread_input);
int main()
{
/* Enter the ThreadX kernel */
tx_kernel_enter();
}
void tx_application_define(void *first_unused_memory)
{
char *pointer = (char *)first_unused_memory;
UINT status=0;
/* Create a thread for the Server */
tx_thread_create(&thread_server,"UDPServer", thread_server_entry, 0,
pointer, DEMO_STACK_SIZE,
8, 8, TX_NO_TIME_SLICE, TX_AUTO_START);
pointer += DEMO_STACK_SIZE;
/* Initialize the NetX system. */
nx_system_initialize();
/* Create a BSD packet pool. */
status = nx_packet_pool_create(&bsd_pool, "NetX BSD Packet Pool", 128,
pointer, 16384);
pointer += 16384;
if (status)
{
error_counter++;
printf("Error in creating BSD packet pool !\n");
}
/* Create an IP instance for BSD. */
status += nx_ip_create(&bsd_ip, "NetX IP Instance 2", IP_ADDRESS(10, 0, 5, 2), 0xFFFFFF00UL,
&bsd_pool, nx_tunnel_network_driver,
pointer, DEMO_STACK_SIZE, 1);
pointer += DEMO_STACK_SIZE;
if (status)
{
error_counter++;
printf("Error creating BSD IP instance!\n");
}
/* Are we needing ARP ?*/
status = nx_icmp_enable(&bsd_ip);
if(status)
{
error_counter++;
printf("Error using ICMP\n");
}
status = nx_udp_enable(&bsd_ip);
/* Check for UDP enable errors. */
if (status)
{
error_counter++;
printf("Error using UDP\n");
}
/* Now initialize BSD Socket Wrapper */
status = (UINT)nx_bsd_initialize (&bsd_ip, &bsd_pool, pointer, DEMO_STACK_SIZE, 2);
if (status)
{
error_counter++;
printf("Error bsd_initialize\n");
}
}
void thread_server_entry(ULONG)
{
INT status;
INT addrlen1;
INT sockfd;
struct nx_bsd_sockaddr_in echoServAddr;
struct nx_bsd_sockaddr_in fromAddr;
char buffer[1024];
/* Create a BSD UDP Server Socket */
sockfd = nx_bsd_socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(sockfd < 0)
{
printf("Error: BSD UDP server socket create\n");
return;
}
/* Fill the socket with Server side information */
memset(&echoServAddr, 0, sizeof(echoServAddr));
echoServAddr.sin_family = PF_INET;
echoServAddr.sin_addr.s_addr = htonl(IP_ADDRESS(10,0,5,2));
echoServAddr.sin_port = htons(SERVER_PORT);
/* Bind the UDP socket to the IP port. */
status = nx_bsd_bind (sockfd, (struct nx_bsd_sockaddr *) &echoServAddr, sizeof(echoServAddr));
if (status < 0)
{
printf("Error: BSD UDP Server Socket Bind\n");
return;
}
printf("Server is listening ...\n");
while(1)
{
int ret=0;
nx_bsd_fd_set readset;
NX_BSD_FD_ZERO(&readset);
addrlen1 = sizeof(struct nx_bsd_sockaddr_in);
NX_BSD_FD_SET(sockfd,&readset);
ret = nx_bsd_select(sockfd+1,&readset,NULL,NULL,NULL);
if(ret > 0)
{
if(NX_BSD_FD_ISSET(sockfd,&readset))
{
/* Receive a UDP packet from a client. */
status = nx_bsd_recvfrom(sockfd,(VOID *)buffer, 1024, 0,(struct nx_bsd_sockaddr *)&fromAddr, &addrlen1);
if (status == ERROR)
{
printf("Error: BSD Server socket receive\n");
}
else
{
printf("Server received data from Client at IP address 0x%x at port %lu\n",
(UINT)fromAddr.sin_addr.s_addr, (ULONG)fromAddr.sin_port);
printf("Server received from Client: %s\n", buffer);
/* Now echo the recieved data string to the same client */
status = nx_bsd_sendto(sockfd,buffer, (INT)(status + 1), 0, (struct nx_bsd_sockaddr *) &fromAddr, sizeof(fromAddr));
if (status == ERROR)
{
printf("Error:BSD Server Socket echo\n");
}
}
}
}
else
{
printf("select returns %d\n",ret);
}
}
}
#ifndef TUNNEL_NETWORK_DERIVER_H
#define TUNNEL_NETWORK_DERIVER_H
/***************************************************************************
* Copyright (c) 2025 ISS AG https://www.iss-ag.com/
*
* This program and the accompanying materials are made available under the
* terms of the MIT License which is available at
* https://opensource.org/licenses/MIT.
*
* SPDX-License-Identifier: MIT
**************************************************************************/
#include "tx_api.h"
#include "nx_api.h"
#include <stdint.h>
#define TUNNELPROTO_IPV4 8
#define TUNNELPROTO_IPv6 56710
struct TunFrame
{
uint16_t flags;
uint16_t proto;
};
VOID nx_tunnel_network_driver(NX_IP_DRIVER *driver_req);
#endif
/**************************************************************************
* Copyright (c) 2025 ISS AG https://www.iss-ag.com/ Rudolf Weber
*
* This program and the accompanying materials are made available under the
* terms of the MIT License which is available at
* https://opensource.org/licenses/MIT.
*
* SPDX-License-Identifier: MIT
**************************************************************************/
#include "tunnel_network_driver.h"
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <signal.h>
#include <linux/if.h>
#include <linux/if_tun.h>
#include <stdio.h>
/* https://www.kernel.org/doc/Documentation/networking/tuntap.txt */
/*********************************************************************
* this creates an networkinterface tun0
* The tun0 can be initialzied with
* ifconfig tun0 10.0.5.1 netmask 255.255.255.0 up
*********************************************************************/
static int tun_alloc(char *dev)
{
struct ifreq ifr;
int fd, err;
if((fd = open("/dev/net/tun", O_RDWR)) < 0)
{
perror("open(/dev/net/tun)");
return -1;
}
memset(&ifr,'\0', sizeof(ifr));
/* Flags: IFF_TUN - TUN device (no Ethernet headers)
* IFF_TAP - TAP device
*
* IFF_NO_PI - Do not provide packet information
*/
ifr.ifr_flags = IFF_TUN;
if( *dev )
{
strncpy(ifr.ifr_name, dev, IFNAMSIZ);
}
if( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 )
{
perror("ioctl(TUNSETIFF)");
close(fd);
return err;
}
strcpy(dev,ifr.ifr_name);
return fd;
}
typedef struct tunnel_network_driver
{
UINT driver_in_use;
NX_INTERFACE *interface_ptr;
NX_IP *ip_ptr;
int fd;
} tunnel_network_driver_instance;
static tunnel_network_driver_instance tunnel_driver;
static char buffer[4096];
static TX_THREAD receiver_thread;
#define RECV_STACK_SIZE 2048
static char recvstack[RECV_STACK_SIZE];
static VOID thread_receiver_entry(ULONG);
VOID nx_tunnel_network_driver(NX_IP_DRIVER *driver_req)
{
NX_IP *ip_ptr;
NX_INTERFACE *interface_ptr;
ip_ptr = driver_req->nx_ip_driver_ptr;
interface_ptr = driver_req->nx_ip_driver_interface;
driver_req->nx_ip_driver_status = NX_SUCCESS;
switch (driver_req->nx_ip_driver_command)
{
case NX_LINK_INTERFACE_ATTACH:
{
tunnel_driver.driver_in_use = 1;
tunnel_driver.interface_ptr = driver_req->nx_ip_driver_interface;
tunnel_driver.ip_ptr = driver_req->nx_ip_driver_ptr;
tunnel_driver.fd = -1;
}
break;
case NX_LINK_INTERFACE_DETACH:
{
close(tunnel_driver.fd);tunnel_driver.fd=-1;
tunnel_driver.driver_in_use = 0;
tunnel_driver.interface_ptr = NULL;
tunnel_driver.ip_ptr = NULL;
}
break;
case NX_LINK_INITIALIZE:
{
char devname[IFNAMSIZ];
strcpy(devname,"tun0");
tunnel_driver.fd = tun_alloc(devname);
if(tunnel_driver.fd < 0)
{
fprintf(stderr,"Creating device %s failed\n",devname);
driver_req->nx_ip_driver_status = NX_INVALID_INTERFACE;
}
printf("NetX tunnel Driver Initialization - %s\n", ip_ptr -> nx_ip_name);
printf(" IP Address =%08lX\n", ip_ptr -> nx_ip_address);
/* The nx_interface_ip_mtu_size should be the MTU for the IP payload.
For regular Ethernet, the IP MTU is 1500. */
nx_ip_interface_mtu_set(ip_ptr, 0, 1500);
tx_thread_create(&receiver_thread,"ReceiverThread",thread_receiver_entry,0,
&recvstack,RECV_STACK_SIZE,
8, 8, TX_NO_TIME_SLICE, TX_AUTO_START);
}
break;
case NX_LINK_UNINITIALIZE:
{
close(tunnel_driver.fd);tunnel_driver.fd=-1;
tunnel_driver.driver_in_use = 0;
tunnel_driver.interface_ptr = NULL;
tunnel_driver.ip_ptr = NULL;
}
break;
case NX_LINK_ENABLE:
{
/* Process driver link enable. An Ethernet driver shall enable the
transmit and reception logic. Once the IP stack issues the
LINK_ENABLE command, the stack may start transmitting IP packets. */
/* In the tunnel driver, just set the enabled flag. */
interface_ptr -> nx_interface_link_up = NX_TRUE;
printf("NetX tunnel Driver Link Enabled - %s\n", ip_ptr -> nx_ip_name);
}
break;
case NX_LINK_DISABLE:
{
/* Process driver link disable. This command indicates the IP layer
is not going to transmit any IP datagrams, nor does it expect any
IP datagrams from the interface. Therefore after processing this command,
the device driver shall not send any incoming packets to the IP
layer. Optionally the device driver may turn off the interface. */
/* In the tunnel driver, just clear the enabled flag. */
interface_ptr -> nx_interface_link_up = NX_FALSE;
printf("NetX tunnel Driver Link Disabled - %s\n", ip_ptr -> nx_ip_name);
}
break;
case NX_LINK_PACKET_SEND:
case NX_LINK_PACKET_BROADCAST:
case NX_LINK_ARP_SEND:
case NX_LINK_ARP_RESPONSE_SEND:
case NX_LINK_RARP_SEND:
{
ssize_t nw=0;
struct TunFrame *tfptr = 0;
/*
The IP stack sends down a data packet for transmission.
The device driver needs to prepend a struct TunFraame
based on the type of packet being transmitted.
The following sequence illustrates this process.
*/
NX_PACKET *packet_ptr=0;
/* Place the ethernet frame at the front of the packet. */
packet_ptr = driver_req->nx_ip_driver_packet;
/* Adjust the prepend pointer. */
packet_ptr->nx_packet_prepend_ptr = packet_ptr->nx_packet_prepend_ptr - sizeof(struct TunFrame);
tfptr = (struct TunFrame *)(packet_ptr->nx_packet_prepend_ptr);
/* Adjust the packet length. */
packet_ptr->nx_packet_length = packet_ptr->nx_packet_length + sizeof(struct TunFrame);
tfptr->flags=0;
/*TODO: unterscheidung protocol */
tfptr->proto=TUNNELPROTO_IPV4;
printf("NexX Tunnel Driver Paket send - %s\n", ip_ptr->nx_ip_name);
nw = write(tunnel_driver.fd,packet_ptr -> nx_packet_prepend_ptr,
packet_ptr-> nx_packet_length);
if(nw < 0 || nw != packet_ptr-> nx_packet_length)
{
fprintf(stderr,"Write error\n");
}
nx_packet_release(packet_ptr);
}
break;
case NX_LINK_MULTICAST_JOIN:
{
}
break;
case NX_LINK_MULTICAST_LEAVE:
{
}
break;
case NX_LINK_GET_STATUS:
{
/* Return the link status in the supplied return pointer. */
*(driver_req->nx_ip_driver_return_ptr) = ip_ptr -> nx_ip_interface[0].nx_interface_link_up;
break;
}
break;
case NX_LINK_GET_SPEED:
{
/* Return the link's line speed in the supplied return pointer. Unsupported feature. */
*(driver_req->nx_ip_driver_return_ptr) = 0;
}
break;
case NX_LINK_GET_DUPLEX_TYPE:
{
/* Return the link's line speed in the supplied return pointer. Unsupported feature. */
*(driver_req->nx_ip_driver_return_ptr) = 0;
}
break;
case NX_LINK_GET_ERROR_COUNT:
{
/* Return the link's line speed in the supplied return pointer. Unsupported feature. */
*(driver_req->nx_ip_driver_return_ptr) = 0;
}
break;
case NX_LINK_GET_TX_COUNT:
{
/* Return the link's line speed in the supplied return pointer. Unsupported feature. */
*(driver_req->nx_ip_driver_return_ptr) = 0;
}
break;
case NX_LINK_GET_ALLOC_ERRORS:
{
/* Return the link's line speed in the supplied return pointer. Unsupported feature. */
*(driver_req->nx_ip_driver_return_ptr) = 0;
}
break;
case NX_LINK_GET_INTERFACE_TYPE:
{
/* Return the link's interface type in the supplied return pointer. Unsupported feature. */
*(driver_req->nx_ip_driver_return_ptr) = NX_INTERFACE_TYPE_UNKNOWN;
}
break;
case NX_LINK_DEFERRED_PROCESSING:
{
/* Driver defined deferred processing. This is typically used to defer interrupt
processing to the thread level.
A typical use case of this command is:
On receiving an Ethernet frame, the RX ISR does not process the received frame,
but instead records such an event in its internal data structure, and issues
a notification to the IP stack (the driver sends the notification to the IP
helping thread by calling "_nx_ip_driver_deferred_processing()". When the IP stack
gets a notification of a pending driver deferred process, it calls the
driver with the NX_LINK_DEFERRED_PROCESSING command. The driver shall complete
the pending receive process.
*/
/* The tunnel driver doesn't require a deferred process so it breaks out of
the switch case. */
}
break;
case NX_LINK_SET_PHYSICAL_ADDRESS:
break;
default:
/* Invalid driver request. */
/* Return the unhandled command status. */
driver_req -> nx_ip_driver_status = NX_UNHANDLED_COMMAND;
printf("NetX tunnel Driver Received invalid request - %s\n", ip_ptr -> nx_ip_name);
break;
}
}
static VOID thread_receiver_entry(ULONG)
{
int r=0;
sigset_t sigset;
sigset_t sigoldset;
NX_PACKET *packet_ptr = 0;
UINT status=0;
printf("Start Receiver thread \n");
r=sigfillset(&sigset);
if(r!=0) { printf("sigfillset returns %d\n",r); }
UCHAR *bufferptr=0;
UINT bufferlen=0;
ssize_t nr=1;
while(nr>0)
{
status = nx_packet_allocate(tunnel_driver.ip_ptr->nx_ip_default_packet_pool,
&packet_ptr,NX_RECEIVE_PACKET, NX_NO_WAIT);
printf("nx_packet_allocate status=%u packet_ptr=%p\n",status,packet_ptr);
NX_ASSERT(status == NX_SUCCESS);
/*read was interupted throught signals, therefore we block the signals*/
r=pthread_sigmask(SIG_BLOCK,&sigset,&sigoldset);
if(r!=0) { perror("pthread_sigmask"); }
bufferptr = packet_ptr->nx_packet_data_start;
bufferlen = packet_ptr->nx_packet_data_end - packet_ptr->nx_packet_data_start;
nr=read(tunnel_driver.fd,bufferptr,bufferlen);
r=pthread_sigmask(SIG_SETMASK,&sigoldset,NULL);
if(r!=0) { perror("pthread_sigmask"); }
if(nr > 0)
{
struct TunFrame *frame_ptr=(struct TunFrame *)bufferptr;
packet_ptr->nx_packet_length = nr;
printf("received %d bytes\n",nr);
packet_ptr->nx_packet_prepend_ptr = packet_ptr->nx_packet_prepend_ptr + sizeof(struct TunFrame);
packet_ptr->nx_packet_length -= sizeof(struct TunFrame);
packet_ptr -> nx_packet_address.nx_packet_interface_ptr = tunnel_driver.interface_ptr;
if(frame_ptr->proto == TUNNELPROTO_IPV4)
{
printf("IPv4-Packet\n");
_nx_ip_packet_receive(tunnel_driver.ip_ptr, packet_ptr);
}
else if(frame_ptr->proto == TUNNELPROTO_IPv6)
{
printf("IPv6-Packet\n");
_nx_ip_packet_receive(tunnel_driver.ip_ptr, packet_ptr);
}
else
{
printf("Unknown protocol %x\n",frame_ptr->proto);
nx_packet_transmit_release(packet_ptr);
}
}
else
{
perror("read");
}
}
}