Subversion Repositories HomeAutomation

Rev

Details | Last modification | View Log | SVN | RSS feed

Rev Author Line No. Line
363 johboh 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)