Subversion Repositories HomeAutomation

Rev

Rev 363 | Blame | Compare with Previous | Last modification | View Log | SVN | RSS feed

  1. /*********************************************************************
  2.  *
  3.  *                  UDP Module for Microchip TCP/IP Stack
  4.  *
  5.  *********************************************************************
  6.  * FileName:        UDP.c
  7.  * Dependencies:    StackTsk.h
  8.  *                  MAC.h
  9.  * Processor:       PIC18, PIC24F, PIC24H, dsPIC30F, dsPIC33F
  10.  * Complier:        Microchip C18 v3.02 or higher
  11.  *                  Microchip C30 v2.01 or higher
  12.  * Company:         Microchip Technology, Inc.
  13.  *
  14.  * Software License Agreement
  15.  *
  16.  * This software is owned by Microchip Technology Inc. ("Microchip")
  17.  * and is supplied to you for use exclusively as described in the
  18.  * associated software agreement.  This software is protected by
  19.  * software and other intellectual property laws.  Any use in
  20.  * violation of the software license may subject the user to criminal
  21.  * sanctions as well as civil liability.  Copyright 2006 Microchip
  22.  * Technology Inc.  All rights reserved.
  23.  *
  24.  * This software is provided "AS IS."  MICROCHIP DISCLAIMS ALL
  25.  * WARRANTIES, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, NOT LIMITED
  26.  * TO MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
  27.  * INFRINGEMENT.  Microchip shall in no event be liable for special,
  28.  * incidental, or consequential damages.
  29.  *
  30.  *
  31.  * Author               Date    Comment
  32.  *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  33.  * Nilesh Rajbharti     3/19/01  Original        (Rev 1.0)
  34.  * Nilesh Rajbharti     2/26/03  Fixed UDPGet and UDPProcess bugs
  35.  *                               as discovered and fixed by John Owen
  36.  *                               of Powerwave.
  37.  *                               1. UDPGet would return FALSE on last good byte
  38.  *                               2. UDPProcess was incorrectly calculating length.
  39.  * Nilesh Rajbharti     5/19/03  Added bFirstRead flag similar to TCP
  40.  *                               to detect very first UDPGet and
  41.  *                               reset MAC Rx pointer to begining of
  42.  *                               UDP data area.  This would ensure that
  43.  *                               if UDP socket has pending Rx data and
  44.  *                               another module resets MAC Rx pointer,
  45.  *                               next UDP socket Get would get correct
  46.  *                               data.
  47.  * Robert Sloan (RSS)    5/29/03 Improved FindMatchingSocket()
  48.  * Nilesh Rajbharti     12/2/03  Added UDPChecksum logic in UDPProcess()
  49.  * Nilesh Rajbharti     12/5/03  Modified UDPProcess() and FindMatchingSocket()
  50.  *                               to include localIP as new parameter.
  51.  *                               This corrects pseudo header checksum
  52.  *                               logic in UDPProcess().
  53.  *                               It also corrects broadcast packet
  54.  *                               matching correct in FindMatchingSocket().
  55.  * Howard Schlunder     1/16/06  Fixed an imporbable RX checksum bug
  56.  *                               when using a Microchip Ethernet controller)
  57.  * Howard Schlunder     6/02/06  Fixed a bug where all RXed UDP packets
  58.  *                               without a checksum (0x0000) were thrown
  59.  *                               away.  No checksum is legal in UDP.
  60.  * Howard Schlunder     8/10/06  Fixed a bug where UDP sockets would
  61.  *                               unintentionally keep the remote MAC
  62.  *                               address cached, even after calling
  63.  *                               UDPInit(), UDPClose(), or reseting
  64.  *                               the part without clearing all the
  65.  *                               PICmicro memory.
  66.  ********************************************************************/
  67.  
  68. #define THIS_IS_UDP_MODULE
  69.  
  70. #include <string.h>
  71.  
  72. #include "..\Include\StackTsk.h"
  73. #include "..\Include\Helpers.h"
  74. #include "..\Include\MAC.h"
  75. #include "..\Include\IP.h"
  76. #include "..\Include\UDP.h"
  77.  
  78. #if defined(STACK_USE_UDP)
  79.  
  80. UDP_SOCKET_INFO  UDPSocketInfo[MAX_UDP_SOCKETS];
  81. UDP_SOCKET activeUDPSocket;
  82.  
  83. static UDP_SOCKET FindMatchingSocket(UDP_HEADER *h, NODE_INFO *remoteNode,
  84.                                     IP_ADDR *localIP);
  85.  
  86. /*********************************************************************
  87.  * Function:        void UDPInit(void)
  88.  *
  89.  * PreCondition:    None
  90.  *
  91.  * Input:           None
  92.  *
  93.  * Output:          None
  94.  *
  95.  * Side Effects:    None
  96.  *
  97.  * Overview:        Initializes internal variables.
  98.  *
  99.  * Note:
  100.  ********************************************************************/
  101. void UDPInit(void)
  102. {
  103.     UDP_SOCKET s;
  104.  
  105.     for ( s = 0; s < MAX_UDP_SOCKETS; s++ )
  106.     {
  107.         UDPClose(s);
  108.     }
  109. }
  110.  
  111. /*********************************************************************
  112.  * Function:        UDP_SOCKET UDPOpen(UDP_PORT localPort,
  113.  *                                     NODE_INFO *remoteNode,
  114.  *                                     UDP_PORT remotePort)
  115.  *
  116.  * PreCondition:    UDPInit() is already called
  117.  *
  118.  * Input:           remoteNode - Remote Node info such as MAC and IP
  119.  *                               address
  120.  *                               If NULL, broadcast node address is set.
  121.  *                  remotePort - Remote Port to which to talk to
  122.  *                               If INVALID_UDP_SOCKET, localPort is
  123.  *                               opened for Listen.
  124.  *                  localPort  - A valid port number.
  125.  *
  126.  * Output:          A valid UDP socket that is to be used for
  127.  *                  subsequent UDP communications.
  128.  *
  129.  * Side Effects:    None
  130.  *
  131.  * Overview:        A UDP packet header is assembled and loaded into
  132.  *                  UDP transmit buffer.
  133.  *
  134.  * Note:            This call must always have valid localPort
  135.  *                  value.
  136.   ********************************************************************/
  137. UDP_SOCKET UDPOpen(UDP_PORT localPort,
  138.                    NODE_INFO *remoteNode,
  139.                    UDP_PORT remotePort)
  140. {
  141.     UDP_SOCKET s;
  142.     UDP_SOCKET_INFO *p;
  143.  
  144.  
  145.     p = UDPSocketInfo;
  146.     for ( s = 0; s < MAX_UDP_SOCKETS; s++ )
  147.     {
  148.         if ( p->localPort == INVALID_UDP_PORT )
  149.         {
  150.             p->localPort    = localPort;
  151.  
  152.             // If remoteNode is supplied, remember it.
  153.             if ( remoteNode )
  154.             {
  155.                 memcpy((void*)&p->remoteNode,
  156.                         (const void*)remoteNode,
  157.                         sizeof(p->remoteNode));
  158.             }
  159.             // else Set broadcast address - TO BE DONE
  160.  
  161.  
  162.             p->remotePort   = remotePort;
  163.             p->TxCount      = 0;
  164.             p->RxCount      = 0;
  165.  
  166.             // Mark this socket as active.
  167.             // Once an active socket is set, subsequent operation can be
  168.             // done without explicitely supply socket identifier.
  169.             activeUDPSocket = s;
  170.             return s;
  171.         }
  172.         p++;
  173.     }
  174.  
  175.     return (UDP_SOCKET)INVALID_UDP_SOCKET;
  176. }
  177.  
  178.  
  179.  
  180.  
  181. /*********************************************************************
  182.  * Function:        void UDPClose(UDP_SOCKET s)
  183.  *
  184.  * PreCondition:    UDPOpen() is already called
  185.  *
  186.  * Input:           s       - Socket that is to be closed.
  187.  *
  188.  * Output:          None
  189.  *
  190.  * Side Effects:    None
  191.  *
  192.  * Overview:        Given socket is marked as available for future
  193.  *                  new communcations.
  194.  *
  195.  * Note:            This function does not affect previous
  196.  *                  active UDP socket designation.
  197.   ********************************************************************/
  198. void UDPClose(UDP_SOCKET s)
  199. {
  200.     UDPSocketInfo[s].localPort = INVALID_UDP_PORT;
  201.     UDPSocketInfo[s].remoteNode.IPAddr.Val = 0x00000000;
  202.     UDPSocketInfo[s].Flags.bFirstRead = FALSE;
  203. }
  204.  
  205.  
  206. /*********************************************************************
  207.  * Function:        BOOL UDPPut(BYTE v)
  208.  *
  209.  * PreCondition:    UDPIsPutReady() == TRUE with desired UDP socket
  210.  *                  that is to be loaded.
  211.  *
  212.  * Input:           v       - Data byte to loaded into transmit buffer
  213.  *
  214.  * Output:          TRUE if transmit buffer is still ready to accept
  215.  *                  more data bytes
  216.  *
  217.  *                  FALSE if transmit buffer can no longer accept
  218.  *                  any more data byte.
  219.  *
  220.  * Side Effects:    None
  221.  *
  222.  * Overview:        Given data byte is put into UDP transmit buffer
  223.  *                  and active UDP socket buffer length is incremented
  224.  *                  by one.
  225.  *                  If buffer has become full, FALSE is returned.
  226.  *                  Or else TRUE is returned.
  227.  *
  228.  * Note:            This function loads data into an active UDP socket
  229.  *                  as determined by previous call to UDPIsPutReady()
  230.  ********************************************************************/
  231. BOOL UDPPut(BYTE v)
  232. {
  233.     UDP_SOCKET_INFO *p;
  234.     WORD temp;
  235.  
  236.     p = &UDPSocketInfo[activeUDPSocket];
  237.  
  238.     if ( p->TxCount == 0 )
  239.     {
  240.         // This is the very first byte that is loaded in UDP buffer.
  241.         // Remember what transmit buffer we are loading, and
  242.         // start loading this and next bytes in data area of UDP packet.
  243.         p->TxBuffer = MACGetTxBuffer(TRUE);
  244.  
  245.         // Make sure that we received a TX buffer
  246.         if(p->TxBuffer == INVALID_BUFFER)
  247.             return FALSE;
  248.  
  249.         IPSetTxBuffer(p->TxBuffer, sizeof(UDP_HEADER));
  250.  
  251.         p->TxOffset = 0;
  252.     }
  253.  
  254.     // Load it.
  255.     MACPut(v);
  256.  
  257.     // Keep track of number of bytes loaded.
  258.     // If total bytes fill up buffer, transmit it.
  259.     if ( p->TxOffset++ >= p->TxCount )
  260.         p->TxCount++;
  261.  
  262. #define SIZEOF_MAC_HEADER       (14)
  263.  
  264.     // Depending on what communication media is used, allowable UDP
  265.     // data length will vary.
  266. #if !defined(STACK_USE_SLIP)
  267. #define MAX_UDP_DATA  (MAC_TX_BUFFER_SIZE - SIZEOF_MAC_HEADER - sizeof(IP_HEADER) - sizeof(UDP_HEADER))
  268. #else
  269. #define MAX_UDP_DATA  (MAC_TX_BUFFER_SIZE - sizeof(IP_HEADER) - sizeof(UDP_HEADER) )
  270. #endif
  271.  
  272.     temp = p->TxCount;
  273.     if ( temp >= MAX_UDP_DATA )
  274.     {
  275.         UDPFlush();
  276.     }
  277. #undef MAX_UDP_DATA
  278.  
  279.     return TRUE;
  280. }
  281.  
  282.  
  283. /*********************************************************************
  284.  * Function:        BOOL UDPFlush(void)
  285.  *
  286.  * PreCondition:    UDPPut() is already called and desired UDP socket
  287.  *                  is set as an active socket by calling
  288.  *                  UDPIsPutReady().
  289.  *
  290.  * Input:           None
  291.  *
  292.  * Output:          All and any data associated with active UDP socket
  293.  *                  buffer is marked as ready for transmission.
  294.  *
  295.  * Side Effects:    None
  296.  *
  297.  * Overview:        None
  298.  *
  299.  * Note:            This function transmit all data from
  300.  *                  an active UDP socket.
  301.  ********************************************************************/
  302. void UDPFlush(void)
  303. {
  304.     UDP_HEADER      h;
  305.     UDP_SOCKET_INFO *p;
  306.  
  307.     // Wait for TX hardware to become available (finish transmitting
  308.     // any previous packet)
  309.     while( !IPIsTxReady(TRUE) );
  310.  
  311.     p = &UDPSocketInfo[activeUDPSocket];
  312.  
  313.     h.SourcePort        = swaps(p->localPort);
  314.     h.DestinationPort   = swaps(p->remotePort);
  315.     h.Length            = (WORD)((WORD)p->TxCount + (WORD)sizeof(UDP_HEADER));
  316.     // Do not swap h.Length yet.  It is needed in IPPutHeader.
  317.     h.Checksum          = 0x0000;
  318.  
  319.     IPSetTxBuffer(p->TxBuffer, 0);
  320.  
  321.     // Load IP header.
  322.     IPPutHeader( &p->remoteNode,
  323.                  IP_PROT_UDP,
  324.                  h.Length );
  325.  
  326.  
  327.     // Now swap h.Length.
  328.     h.Length            = swaps(h.Length);
  329.  
  330.     // Now load UDP header.
  331.     IPPutArray((BYTE*)&h, sizeof(h));
  332.  
  333.     // Update checksum.
  334.     // TO BE IMPLEMENTED
  335.  
  336.     MACFlush();
  337.  
  338.     // The buffer was reserved with AutoFree, so we can immediately
  339.     // discard it.  The MAC layer will free it after transmission.
  340.     p->TxBuffer         = INVALID_BUFFER;
  341.     p->TxCount          = 0;
  342.  
  343. }
  344.  
  345.  
  346.  
  347. /*********************************************************************
  348.  * Function:        BOOL UDPIsGetReady(UDP_SOCKET s)
  349.  *
  350.  * PreCondition:    UDPInit() is already called.
  351.  *
  352.  * Input:           A valid UDP socket that is already "Listen"ed on
  353.  *                  or opened.
  354.  *
  355.  * Output:          TRUE if given port contains any data.
  356.  *                  FALSE if given port does not contain any data.
  357.  *
  358.  * Side Effects:    Given socket is set as an active UDP Socket.
  359.  *
  360.  * Overview:        None
  361.  *
  362.  * Note:            This function automatically sets supplied socket
  363.  *                  as an active socket.  Caller need not call
  364.  *                  explicit function UDPSetActiveSocket().  All
  365.  *                  subsequent calls will us this socket as an
  366.  *                  active socket.
  367.  ********************************************************************/
  368. BOOL UDPIsGetReady(UDP_SOCKET s)
  369. {
  370.     activeUDPSocket = s;
  371.     return ( UDPSocketInfo[activeUDPSocket].RxCount > 0 );
  372. }
  373.  
  374. /*********************************************************************
  375.  * Function:        BOOL UDPGet(BYTE *v)
  376.  *
  377.  * PreCondition:    UDPInit() is already called     AND
  378.  *                  UDPIsGetReady(s) == TRUE
  379.  *
  380.  * Input:           v       - Buffer to receive UDP data byte
  381.  *
  382.  * Output:          TRUE    if a data byte was read
  383.  *                  FALSE   if no data byte was read or available
  384.  *
  385.  * Side Effects:    None
  386.  *
  387.  * Overview:        None
  388.  *
  389.  * Note:            This function fetches data from an active UDP
  390.  *                  socket as set by UDPIsGetReady() call.
  391.  ********************************************************************/
  392. BOOL UDPGet(BYTE *v)
  393. {
  394.     // CALLER MUST MAKE SURE THAT THERE IS ENOUGH DATA BYTE IN BUFFER
  395.     // BEFORE CALLING THIS FUNCTION.
  396.     // USE UDPIsGetReady() TO CONFIRM.
  397.     if ( UDPSocketInfo[activeUDPSocket].RxCount == 0 )
  398.         return FALSE;
  399.  
  400.     // If if this very first read to packet, set MAC Rx Pointer to
  401.     // beginig of UDP data area.
  402.     if ( UDPSocketInfo[activeUDPSocket].Flags.bFirstRead )
  403.     {
  404.         UDPSocketInfo[activeUDPSocket].Flags.bFirstRead = FALSE;
  405.         UDPSetRxBuffer(0);
  406.     }
  407.  
  408.     *v = MACGet();
  409.  
  410.     UDPSocketInfo[activeUDPSocket].RxCount--;
  411.  
  412.     if ( UDPSocketInfo[activeUDPSocket].RxCount == 0 )
  413.     {
  414.         MACDiscardRx();
  415.     }
  416.  
  417.     return TRUE;
  418. }
  419.  
  420.  
  421. /*********************************************************************
  422.  * Function:        void UDPDiscard(void)
  423.  *
  424.  * PreCondition:    UDPInit() is already called    AND
  425.  *                  UDPIsGetReady() == TRUE with desired UDP socket.
  426.  *
  427.  * Input:           None
  428.  *
  429.  * Output:          None
  430.  *
  431.  * Side Effects:    None
  432.  *
  433.  * Overview:        None
  434.  *
  435.  * Note:            This function discards an active UDP socket content.
  436.  ********************************************************************/
  437. void UDPDiscard(void)
  438. {
  439.     if ( UDPSocketInfo[activeUDPSocket].RxCount )
  440.         MACDiscardRx();
  441.  
  442.     UDPSocketInfo[activeUDPSocket].RxCount = 0;
  443. }
  444.  
  445.  
  446.  
  447. /*********************************************************************
  448.  * Function:        BOOL UDPProcess(NODE_INFO* remoteNode,
  449.  *                                  IP_ADDR *localIP,
  450.  *                                  WORD len)
  451.  *
  452.  * PreCondition:    UDPInit() is already called     AND
  453.  *                  UDP segment is ready in MAC buffer
  454.  *
  455.  * Input:           remoteNode      - Remote node info
  456.  *                  len             - Total length of UDP semgent.
  457.  *
  458.  * Output:          TRUE if this function has completed its task
  459.  *                  FALSE otherwise
  460.  *
  461.  * Side Effects:    None
  462.  *
  463.  * Overview:        None
  464.  *
  465.  * Note:            None
  466.  ********************************************************************/
  467. // Pseudo header as defined by rfc 793.
  468. typedef struct _PSEUDO_HEADER
  469. {
  470.     IP_ADDR SourceAddress;
  471.     IP_ADDR DestAddress;
  472.     BYTE Zero;
  473.     BYTE Protocol;
  474.     WORD Length;
  475. } PSEUDO_HEADER;
  476.  
  477. #define SwapPseudoHeader(h)  (h.Length = swaps(h.Length))
  478.  
  479. BOOL UDPProcess(NODE_INFO *remoteNode, IP_ADDR *localIP, WORD len)
  480. {
  481.     UDP_HEADER h;
  482.     UDP_SOCKET s;
  483.     PSEUDO_HEADER   pseudoHeader;
  484.     WORD_VAL        checksum;
  485.  
  486.  
  487.     // Retrieve UDP header.
  488.     MACGetArray((BYTE*)&h, sizeof(h));
  489.  
  490.     h.SourcePort        = swaps(h.SourcePort);
  491.     h.DestinationPort   = swaps(h.DestinationPort);
  492.     h.Length            = swaps(h.Length) - sizeof(UDP_HEADER);
  493.     // See if we need to validate the checksum field (0x0000 is disabled)
  494.     if(h.Checksum)
  495.     {
  496.         h.Checksum          = swaps(h.Checksum);
  497.    
  498.         // Calculate IP pseudoheader checksum.
  499.         pseudoHeader.SourceAddress      = remoteNode->IPAddr;
  500.         pseudoHeader.DestAddress.v[0]   = localIP->v[0];
  501.         pseudoHeader.DestAddress.v[1]   = localIP->v[1];
  502.         pseudoHeader.DestAddress.v[2]   = localIP->v[2];
  503.         pseudoHeader.DestAddress.v[3]   = localIP->v[3];
  504.         pseudoHeader.Zero               = 0x0;
  505.         pseudoHeader.Protocol           = IP_PROT_UDP;
  506.         pseudoHeader.Length             = len;
  507.    
  508.         SwapPseudoHeader(pseudoHeader);
  509.    
  510.         checksum.Val = ~CalcIPChecksum((BYTE*)&pseudoHeader,
  511.                                         sizeof(pseudoHeader));
  512.    
  513.    
  514.         // Set UDP packet checksum = pseudo header checksum in MAC RAM.
  515.         IPSetRxBuffer(6);
  516.         MACPut(checksum.v[0]);
  517.         // In case if the end of the RX buffer is reached and a wraparound is needed, set the next address to prevent writing to the wrong address.
  518.         IPSetRxBuffer(7);
  519.         MACPut(checksum.v[1]);
  520.         IPSetRxBuffer(0);
  521.    
  522.         // Now calculate UDP packet checksum in NIC RAM - including
  523.         // pesudo header.
  524.         checksum.Val = CalcIPBufferChecksum(len);
  525.    
  526.         if ( checksum.Val != h.Checksum )
  527.         {
  528.             MACDiscardRx();
  529.             return TRUE;
  530.         }
  531.     }
  532.  
  533.     s = FindMatchingSocket(&h, remoteNode, localIP);
  534.     if ( s == INVALID_UDP_SOCKET )
  535.     {
  536.          // If there is no matching socket, There is no one to handle
  537.          // this data.  Discard it.
  538.         MACDiscardRx();
  539.     }
  540.     else
  541.     {
  542.         UDPSocketInfo[s].RxCount = h.Length;
  543.         UDPSocketInfo[s].Flags.bFirstRead = TRUE;
  544.     }
  545.  
  546.  
  547.     return TRUE;
  548. }
  549.  
  550.  
  551. /*********************************************************************
  552.  * Function:        UDP_SOCKET FindMatchingSocket(UDP_HEADER *h,
  553.  *                                NODE_INFO *remoteNode,
  554.  *                                IP_ADDR *localIP)
  555.  *
  556.  * PreCondition:    UDP Segment header has been retrieved from buffer
  557.  *                  The IP header has also been retrieved
  558.  *
  559.  * Input:           remoteNode      - Remote node info from IP header
  560.  *                  h               - header of UDP semgent.
  561.  *
  562.  * Output:          matching UDP socket or INVALID_UDP_SOCKET
  563.  *
  564.  * Side Effects:    None
  565.  *
  566.  * Overview:        None
  567.  *
  568.  * Note:            None
  569.  ********************************************************************/
  570. #define BROADCAST_ADDRESS   (0xffffffffL)
  571. static UDP_SOCKET FindMatchingSocket(UDP_HEADER *h,
  572.                                      NODE_INFO *remoteNode,
  573.                                      IP_ADDR *localIP)
  574. {
  575.     UDP_SOCKET s;
  576.     UDP_SOCKET partialMatch;
  577.     UDP_SOCKET_INFO *p;
  578.  
  579.     partialMatch = INVALID_UDP_SOCKET;
  580.  
  581.     p = UDPSocketInfo;
  582.     for ( s = 0; s < MAX_UDP_SOCKETS; s++ )
  583.     {
  584.         // This packet is said to be matching with current socket
  585.         // 1. If its destination port matches with our local port.
  586.         // 2. This socket does not have any data pending.
  587.         // 3. Packet source IP address matches with socket remote IP address.
  588.         //    OR this socket had transmitted packet with destination address as broadcast.
  589.         if ( p->localPort == h->DestinationPort )
  590.         {
  591.             if ( (p->remotePort == h->SourcePort) && (p->RxCount == 0L) )
  592.             {
  593.                 if ( (p->remoteNode.IPAddr.Val == remoteNode->IPAddr.Val) ||
  594.                      (localIP->Val == BROADCAST_ADDRESS) )
  595.                 {
  596.                     return s;
  597.                 }
  598.             }
  599.  
  600.             partialMatch = s;
  601.         }
  602.         p++;
  603.     }
  604.  
  605.     if ( partialMatch != INVALID_UDP_SOCKET )
  606.     {
  607.         p = &UDPSocketInfo[partialMatch];
  608.  
  609.         memcpy((void*)&p->remoteNode,
  610.                 (const void*)remoteNode, sizeof(p->remoteNode) );
  611.  
  612.         p->remotePort = h->SourcePort;
  613.     }
  614.     return partialMatch;
  615. }
  616.  
  617.  
  618. #endif //#if defined(STACK_USE_UDP)
  619.