OSDev.org

The Place to Start for Operating System Developers
It is currently Thu Mar 28, 2024 12:11 pm

All times are UTC - 6 hours




Post new topic Reply to topic  [ 1 post ] 
Author Message
 Post subject: UDP checksum not calculated fully in TSO mode Intel 8254x
PostPosted: Fri Nov 15, 2019 12:35 pm 
Offline

Joined: Fri Oct 04, 2019 2:19 am
Posts: 3
Description:
So I am at the stage where I want to include Ethernet connectivity in my OS and I am in process of writing a simple driver for Intel 8254x. The setup I am currently using is Virtual Box 6 with Intel Pro /1000MT (82545).

I made majority of things work, RX is fully functional, TX with legacy descriptors as well. However I am struggling with TSO descriptor parameters for the transmit. What I want to do at this point is send UDP over IPv6 with segmentation and checksum offloading. My approach is to set context descriptor for segmentation offload, than data descriptor including only header, than data descriptor with the payload.

Code:

Here is the gist of the code ( non essential stuff have been omitted ):
Code:
          // create context descriptor: TSO
          context->ipcss = ETH_HEADER_LENGTH; // ip checksum not used
          context->ipcso = 0;
          context->ipcse = 0; // to the end of the packet
          context->tucss = ETH_HEADER_LENGTH + IPV6_HEADER_LENGTH;
          context->tucso = ETH_HEADER_LENGTH + IPV6_HEADER_LENGTH + UDP_HEADER_LENGTH - 2;
          context->tucse = 0; // to the end of the packet
          context->cmd_len = data_count | TX_CONTEX_CMD_IDE | TX_CONTEX_CMD_DEXT | TX_CONTEX_CMD_RS | TX_CONTEX_CMD_TSE;
          context->status = 0;
          context->hdrlen = ETH_HEADER_LENGTH + IPV6_HEADER_LENGTH + UDP_HEADER_LENGTH;
          context->mss = mtu - (context->hdrlen);
     
          // insert the header
          data->addr_low = (t_uint32)((t_mem_ptr)p->header + sizeof(struct net_buffer));
          data->addr_high = 0x00000000;
          data->datalen_0 = (t_uint8)(p->header->length);
          data->datalen_1 = (t_uint8)(p->header->length >> 8);
          data->datalen_2 = ((t_uint8)(p->header->length >> 16) & (0x0f)) | 0x10;
          data->dcmd = TX_DATA_CMD_IDE | TX_DATA_CMD_DEXT | TX_DATA_CMD_RS | TX_DATA_CMD_TSE;
          data->status = 0;
          data->popts = TX_DATA_POPTS_TXSM;
          data->special = 0;
     
          // data packets
          buffer = p->data;
          while(buffer)
          {
            data->addr_low = (t_uint32)((t_mem_ptr)buffer + sizeof(struct net_buffer));
            data->addr_high = 0x00000000;
            data->datalen_0 = (t_uint8)(buffer->length);
            data->datalen_1 = (t_uint8)(buffer->length >> 8);
            data->datalen_2 = ((t_uint8)(buffer->length >> 16) & (0x0f)) | 0x10;
            if(buffer->next)
              data->dcmd = TX_DATA_CMD_IDE | TX_DATA_CMD_DEXT | TX_DATA_CMD_RS | TX_DATA_CMD_TSE;
            else
              data->dcmd = TX_DATA_CMD_IDE | TX_DATA_CMD_DEXT | TX_DATA_CMD_RS | TX_DATA_CMD_IFCS | TX_DATA_CMD_EOP;
            data->status = 0;
            data->popts = 0;
            data->special = 0;
     
            buffer = net_buffer_next(buffer);
          }


Results:

The result is well segmented stream of packets, with the only problem being the UDP checksum. The value there is the partial header checksum which obviously gets calculated correct. However the data is not included in the checksum. I should note that:
    header is prepared with checksum 0
    if I manually add the data checksum to what is written in the UDP checksum field I get the correct result

Observations:

From the manual I was under the impression, that the partial/pseudoheader checksum must be calculated and put into the checksum field. However I input 0 and UDP checksum field gets filled with precisely that.

Questions:
    I have learned, what is not really evident from the manual. There are two internal contexts. One for TSO and one for checksum (depending on the TSE bit of the command field in register) and in principle both need to be set (https://lists.gnu.org/archive/html/qemu ... 02721.html). What is the relation? Are they independent and for UDP segmentation with checksum offload I need to set both? Or if I am setting the segmentation, the values there also define the checksum offloading - namely is the use of checksum context for scenarios where only checksum without segmentation is used?

    Should TXSM flag be set for the first data descriptor only (the one with the header) or should I set this flag for all data descriptors to follow (payload) as well?

    Is there something obvious with my setup of context descriptors that partial checksum (pseudo header checksum) gets calculated but does not include the data in the checksum?

    When should I pre-calculate the partial UDP pseudo-header and set it up so data gets added and when should the checksum of the prototype header be left 0?


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 1 post ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: Google [Bot], Octocontrabass and 91 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group