udp.c

Go to the documentation of this file.
00001 /*##############################################################################
00002 
00003 nIP - nano IP stack
00004 
00005 File        : udp.c
00006 
00007 Description : UDP
00008 
00009 Copyright notice:
00010 
00011 Copyright (C) 2005 -
00012 Andreas Dittrich, dittrich@informatik.hu-berlin.de
00013 Jon Kowal, kowal@informatik.hu-berlin.de
00014 
00015 This program is free software; you can redistribute it and/or
00016 modify it under the terms of the GNU General Public License
00017 as published by the Free Software Foundation; either version 2
00018 of the License, or (at your option) any later version.
00019 
00020 This program is distributed in the hope that it will be useful,
00021 but WITHOUT ANY WARRANTY; without even the implied warranty of
00022 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00023 GNU General Public License for more details.
00024 
00025 You should have received a copy of the GNU General Public License
00026 along with this program; if not, write to the Free Software
00027 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00028 
00029 #############################################################################*/
00030 
00031 #include "nip_init.h"
00032 #include "dispatcher.h"
00033 #include "inet.h"
00034 #include "os_core.h"
00035 #include "nip_error.h"
00036 #include "net/net_if.h"
00037 #include "net/udp.h"
00038 
00039 
00040 #if (NIP_UDP_ENABLE == 1 )
00041 
00042 #if (NIP_UDP_USE_FIXED_SOCKETS == 1)
00043 /** Fixed array of UDP sockets */
00044 static struct nip_udp_sock   udp_sockets[ NIP_UDP_FIXED_SOCKETS ];
00045 #else
00046 
00047 /** Handle of reserved memory area for UDP Sockets */
00048 static nip_udp_sock_cnt_t udp_socket_cnt;
00049 static nip_mem_handle_t   udp_sockets;
00050 #endif // NIP_UDP_USE_FIXED_SOCKETS == 1
00051 
00052 /** Fixed array of UDP queue */
00053 static struct nip_udp_buffer udp_rx_queue[ NIP_UDP_PACKET_QUEUE_SIZE ];
00054 
00055 /** Register UDP socket with given address and flags.
00056  * @param addr structure to be filled with address and port. If all address
00057  *             bytes are set to Zero, the socket will listen on all interfaces.
00058  * @param flags possible flags are:
00059  *               - NIP_UDP_SOCK_FLG_NON_BLOCK
00060  *               - NIP_UDP_SOCK_FLG_LISTENING
00061  * @return NIP_UDP_NO_SOCKET on error. Global nip_error variable will be set to
00062  * NIP_E_OUT_OF_RESSOURCES in that case.
00063  */
00064 nip_udp_sock_id_t nip_udp_socket( struct nip_udp_sock_addr *addr, uint8_t flags )
00065 {
00066         nip_udp_sock_id_t   id    = 0;
00067         struct nip_udp_sock *sock = NULL;
00068         ///@todo reserve socket in global list
00069 #if (NIP_UDP_USE_FIXED_SOCKETS==1)
00070         do
00071         {
00072                 if ( (udp_sockets[ id ].flags & NIP_UDP_SOCK_FLG_USED) == 0 )
00073                 {
00074                         sock = & udp_sockets[ id ];
00075                         sock->sockid = id;
00076                         sock->flags  = flags | NIP_UDP_SOCK_FLG_USED;
00077                         nip_memcpy( &sock->addr, addr, sizeof( struct nip_udp_sock_addr ) );
00078                         sock->rx_packet = NIP_UDP_EOQ;
00079                         sock->tx_packet = NIP_MEM_NULL;
00080                         return id;
00081                 }
00082         } while ( ++id < NIP_UDP_FIXED_SOCKETS );
00083 
00084 #else
00085         ///@todo implement not fixed sockets
00086 #endif // (NIP_UDP_USE_FIXED_SOCKETS==1)
00087 
00088 
00089         nip_error = NIP_E_OUT_OF_RESSOURCES;
00090         return NIP_UDP_NO_SOCKET;
00091 
00092 }
00093 
00094 /** Unregister previous socket registration */
00095 void nip_udp_close( nip_udp_sock_id_t id )
00096 {
00097         struct nip_udp_buffer *qbuf = udp_rx_queue;
00098 
00099         // empty receive queue for that socket
00100         do
00101         {
00102                 if ( qbuf->sockid == id )
00103                 {
00104                         nip_mem_free( qbuf->buf );
00105                         qbuf->buf = NIP_MEM_NULL;
00106                 }
00107         } while ( ++qbuf != &udp_rx_queue[NIP_UDP_EOQ] );
00108 
00109 #if (NIP_UDP_USE_FIXED_SOCKETS==1)
00110         if ( id >= NIP_UDP_FIXED_SOCKETS ) return;
00111 
00112         nip_mem_free( udp_sockets[id].tx_packet );
00113         udp_sockets[ id ].flags = 0;
00114 #else
00115         ///@todo implement not fixed sockets
00116 #endif // (NIP_UDP_USE_FIXED_SOCKETS==1)
00117 }
00118 
00119 /** Return pointer to socket structure belonging to given sockid or NULL if
00120  * socket was not found.
00121  */
00122 struct nip_udp_sock *nip_udp_sock_ptr ( nip_udp_sock_id_t sockid )
00123 {
00124 #if (NIP_UDP_USE_FIXED_SOCKETS==1)
00125         if ( sockid < NIP_UDP_FIXED_SOCKETS && udp_sockets[ sockid ].flags & NIP_UDP_SOCK_FLG_USED )
00126                 return &udp_sockets[ sockid ];
00127         else
00128         {
00129                 nip_error = NIP_E_INVALID_SOCK;
00130                 return NULL;
00131         }
00132 #else
00133         ///@todo implement not fixed sockets
00134 #endif // (NIP_UDP_USE_FIXED_SOCKETS==1)
00135 }
00136 
00137 /** Return handle to current Receive or Transmit buffer of UDP socket
00138  */
00139 nip_mem_handle_t nip_udp_buf_handle( nip_udp_sock_id_t sockid, nip_udp_buf_type_t buftype )
00140 {
00141         struct nip_udp_sock *sock = nip_udp_sock_ptr( sockid );
00142         nip_mem_handle_t    res   = NIP_MEM_NULL;
00143 
00144         if ( sock != NULL )
00145         {
00146                 res = sock->tx_packet;
00147 
00148                 if ( buftype == NIP_UDP_RX_BUF )
00149                 {
00150                                 if ( sock->rx_packet != NIP_UDP_EOQ )
00151                                         res       = udp_rx_queue[ sock->rx_packet ].buf;
00152                                 else
00153                                 {
00154                                         nip_error = NIP_E_INVALID_BLOCK;
00155                                 }
00156                 }
00157         }
00158         else
00159                 nip_error = NIP_E_INVALID_SOCK;
00160 
00161         return res;
00162 }
00163 
00164 /** Release previously granted direct access.
00165  *
00166  * This function has to be used in combination with nip_udp_data_ptr() as all all
00167  * pointers obtained by the latter have to be released again.
00168  *
00169  * @warning Do not use the given direct-access pointer after calling this
00170  * function.
00171  */
00172 void nip_udp_ptr_release( nip_udp_sock_id_t sockid, nip_udp_buf_type_t buftype )
00173 {
00174         nip_mem_handle_t    bufhandle = nip_udp_buf_handle( sockid, buftype );
00175 
00176         if ( bufhandle != NIP_MEM_NULL )
00177                 nip_mem_release_block( bufhandle );
00178 }
00179 
00180 /** Return mem-ptr to buffer data. The call failed, if res->id is NIP_MEM_NULL.
00181  */
00182 void nip_udp_data_mem_ptr( nip_udp_sock_id_t sockid, nip_udp_buf_type_t buftype, nip_mem_ptr_t *res )
00183 {
00184         res->id  = nip_udp_buf_handle( sockid, buftype );
00185         if ( res->id != NIP_MEM_NULL )
00186                 res->ptr = (void*) sizeof( struct nip_udp_header );
00187         else
00188                 res->ptr = NULL;
00189 }
00190 
00191 /** Give direct access (pointer) to a socket buffer.
00192  *
00193  * Normally the buffer space is administered by the UDP implementation and the
00194  * application only has write access through the nip_udp_write() function. For
00195  * optimization reasons it may be better for the application to have direct
00196  * access, though.
00197  *
00198  * The direct TX buffer access is intended to be used in combination with the
00199  * nip_udp_write() function, which still has to be used to allocate enough
00200  * memory. You may call nip_udp_write() without supplying a buffer pointer to
00201  * allocate uninitialized memory.
00202  *
00203  * If the requested buffer size could not be allocated NULL will returned and
00204  * nip_error be set to NIP_E_OUT_OF_MEMORY.
00205  *
00206  * @warning The buffer will be locked until nip_udp_ptr_release() has been called
00207  * which will affect memory management and packet transmission. You have to call
00208  * nip_udp_ptr_release() before transmitting the packet.
00209  *
00210  * @warning Make sure you know how much memory has been allocated previously
00211  * (using the nip_udp_write() function). You MUST NOT write beyond that mark or
00212  * buffer overflows in the memory management system will occur.
00213  *
00214  * @param sockid id of socket to return pointer at buffer for
00215  *
00216  * @return pointer to buffer or NULL. In the latter case nip_error
00217  * NIP_E_INVALID_SOCK for an invalid sockid or NIP_E_INVALID_BLOCK if the
00218  * buffer had not been initialized, or NIP_E_BLOCK_LOCKED if ressource was
00219  * locked.
00220  */
00221 void *nip_udp_data_ptr( nip_udp_sock_id_t sockid, nip_udp_buf_type_t buftype )
00222 {
00223         nip_mem_ptr_t  ptr;
00224 
00225         nip_udp_data_mem_ptr( sockid, buftype, &ptr );
00226 
00227         return nip_mem_ptr( &ptr );
00228 }
00229 
00230 /** Initialize send buffer for new packet. Use this function in combination with
00231  * nip_udp_write() or nip_udp_data_ptr() and nip_udp_transmit().
00232  *
00233  * @param sockid    ID of socket to initialize send buffer for.
00234  * @param size      Size to be reserved (may be 0 for dynamic allocation)
00235  *
00236  * The socket buffer will be initialized without data, use nip_udp_write() to
00237  * fill the buffer. You should provide the buffer size, if known in advance, to
00238  * ensure there is enough memory available to buffer your packet. If you do
00239  * not provide the buffer size it will be automatically increased whenever
00240  * nip_udp_write() is being called, which may then fail if not enough memory is
00241  * available.
00242  *
00243  * Call nip_udp_transmit() to send the buffer. nip_udp_data_ptr() will hand you a
00244  * pointer to the buffer. See the description of nip_udp_data_ptr() for further
00245  * instructions and warnings!
00246  *
00247  * @warning Any previous buffer that has not been scheduled for transmission
00248  * will be overwritten.
00249  *
00250  * @return NIP_E_OK, NIP_E_OUT_OF_MEMORY, of NIP_E_INVALID_SOCK
00251  */
00252 nip_error_t nip_udp_init_send( nip_udp_sock_id_t sockid, nip_mem_size_t size )
00253 {
00254         struct nip_udp_sock   *sock = nip_udp_sock_ptr( sockid );
00255 
00256         if ( sock == NULL )
00257         {
00258                 return NIP_E_INVALID_SOCK;
00259         }
00260 
00261         // add UDP header to packet size
00262         size += sizeof ( struct nip_udp_header );
00263         sock->tx_packet = nip_mem_alloc( size, size, NIP_MEM_FLG_DELREAD, NULL );
00264 
00265         if ( sock->tx_packet == NIP_MEM_NULL )
00266         {
00267                 return NIP_E_OUT_OF_MEMORY;
00268         }
00269 
00270         // add UDP header space to buffer without initializing any values (that will
00271         // be done in nip_udp_transmit().
00272         nip_mem_write( sock->tx_packet, NULL, sizeof( struct nip_udp_header ) );
00273 
00274         return NIP_E_OK;
00275 }
00276 
00277 /** Cancel transmission. The send buffer will be cleared and removed. For the
00278  * next packet to be sent, nip_udp_init_send() will have to be called.
00279  *
00280  * This function will usually be called by the application after nip_udp_write()
00281  * failed before the packet was complete, which normally is a caused by
00282  * insufficient memory. If the application does not want to wait in place for
00283  * enough memory to be available and has no means to safe the send-status it
00284  * will cancel the transmission and retry later.
00285  */
00286 void nip_udp_cancel_send( nip_udp_sock_id_t sockid )
00287 {
00288         struct nip_udp_sock   *sock = nip_udp_sock_ptr( sockid );
00289 
00290         nip_mem_free( sock->tx_packet );
00291         sock->tx_packet = NIP_MEM_NULL;
00292 }
00293 
00294 /** Write bytes to socket. Transmission has to be trigged by nip_udp_transmit().
00295  */
00296 nip_error_t nip_udp_write( nip_udp_sock_id_t sockid, uint8_t *buf, nip_mem_size_t size)
00297 {
00298         struct nip_udp_sock *sock = nip_udp_sock_ptr( sockid );
00299 
00300         //copy bytes to transmission buffer
00301         return nip_mem_write( sock->tx_packet, buf, size );
00302 }
00303 
00304 /** Transmit the packet from the current send buffer to the given destination.
00305  *
00306  * @warning Never perform transmit calls from within the dispatcher on blocking
00307  * sockets!!! That will most likely lead to deadlock as nip_udp_transmit() will
00308  * prevent the dispatcher from finishing the transmission until it has finished
00309  * the transmission, which would happen in the not so near future near infinity.
00310  * ;)
00311  *
00312  * @param sockid     Socket ID
00313  * @param *dest_addr pointer to destination address structure
00314  * @param net_if     ID of network interface to transmit message on. If you do
00315  *                   not wish to specify the interface, put NIP_NET_NO_IF.
00316  *
00317  * @return
00318  *   - NIP_E_OK               packet has been added to outgoing packet queue
00319  *   - NIP_E_DEV_BUSY         outgoing queue of interface is full, try again
00320  *   - NIP_E_NO_ROUTE_TO_HOST no interface will deliver to destination address
00321  */
00322 nip_error_t nip_udp_transmit( nip_udp_sock_id_t sockid,struct nip_udp_sock_addr *dest_addr, nip_net_if_id_t if_id )
00323 {
00324         struct nip_udp_sock   *sock = nip_udp_sock_ptr( sockid );
00325         struct nip_udp_header *head;
00326         nip_net_if_trans_t    *trans;
00327 
00328         if ( sock == NULL )
00329                 return NIP_E_INVALID_SOCK;
00330 
00331         // Call IP route to get transmission pointer
00332         trans = nip_ip_route( dest_addr->ip, if_id, NULL );
00333         if ( trans == NULL )
00334         {
00335                 return nip_error;
00336         }
00337 
00338         // add UDP packet to transmission and configure transmission to be freed
00339         // after sending.
00340         trans->payload = sock->tx_packet;
00341         trans->payload_size = nip_mem_buf_used( sock->tx_packet );
00342         trans->flags.free_payload = 1;
00343         trans->flags.reset_status = 1;
00344         trans->params.ip.protocol = NIP_IP_PROTO_UDP;
00345 
00346         // get pointer to packet buffer and fill UDP header
00347         head = nip_mem_obtain_ptr( sock->tx_packet );
00348         head->src_port = sock->addr.port;
00349         head->dst_port = dest_addr->port;
00350         head->length   = htons( trans->payload_size );
00351 
00352         // add pseudo header to checksum
00353         ///@todo add checksum
00354 //      head->checksum = NIP_NUM_IP_PROTO_UDP +
00355         head->checksum = 0;
00356 
00357         // release pointer to UDP header
00358         nip_mem_release_block( sock->tx_packet );
00359 
00360 
00361         // reset socket transmission status
00362         sock->tx_packet = NIP_MEM_NULL;
00363 
00364         // Notify dispatcher to continue IP transmission
00365         trans->status = NIP_NET_IF_RESOLV_ADDR;
00366         nip_disp_notify( NIP_DISP_CHECK_TRANS );
00367         nip_dispatcher();
00368 
00369         // all went well
00370         return NIP_E_OK;
00371 }
00372 
00373 
00374 /** Attempt to receive new packet from UDP socket. The payload will be written
00375  * to the supplied buffer pointer. If the datagram is to large to fit in the
00376  * supplied buffer, it will be truncated at the buffer boundary, but not
00377  * discarded. Subsequent calls to nip_udp_recvfrom() may be performed to read the
00378  * remaining data.
00379  *
00380  * @param sockid     id of socket to read from
00381  * @param *buf       pointer to buffer to write payload to
00382  * @param size       size of supplied buffer
00383  * @param *from_addr pointer to structure where sender address information will
00384  *                   be copied to. This pointer may be NULL if you're not
00385  *                   interested in address information.
00386  *
00387  * @return total size of available buffer. If the return value is smaller than
00388  * the provided buffer it indicates how much of the buffer has been filled, if
00389  * it is larger it indicates that the packet has been truncated. If 0 is returned
00390  * the nip_error variable will be set to one of the following values:
00391  *  - NIP_E_AGAIN        no data available on non-blocking socket
00392  *  - NIP_E_INVALID_SOCK invalid socket or socket closed while waiting for data
00393  */
00394 nip_mem_size_t nip_udp_recvfrom( nip_udp_sock_id_t sockid, uint8_t *buf, nip_mem_size_t size, struct nip_udp_sock_addr *from_addr )
00395 {
00396         struct nip_udp_sock   *sock;
00397         nip_mem_size_t        res;
00398         struct nip_udp_buffer *qbuf;
00399 
00400         do
00401         {
00402                 // as the socket may be shut down while the loop is running we'll have to
00403                 // check on it every time.
00404                 sock = nip_udp_sock_ptr( sockid );
00405                 if ( sock == NULL )
00406                 {
00407                         nip_error = NIP_E_INVALID_SOCK;
00408                         return 0;
00409                 }
00410 
00411                 // don't block for non-blocking sockets
00412                 if ( sock->rx_packet == NIP_UDP_EOQ && (sock->flags & NIP_UDP_SOCK_FLG_NON_BLOCK) )
00413                 {
00414                         nip_error = NIP_E_AGAIN;
00415                         return 0;
00416                 }
00417 
00418         } while ( sock->rx_packet == NIP_UDP_EOQ );
00419 
00420         qbuf = &udp_rx_queue[ sock->rx_packet ];
00421 
00422         // copy remote address data
00423         if ( from_addr != NULL )
00424                 nip_memcpy( from_addr, &qbuf->addr, sizeof( struct nip_udp_sock_addr ) );
00425 
00426         //copy bytes from packet to buffer
00427         size = nip_mem_read( qbuf->buf, buf, size );
00428 
00429         res = qbuf->size;
00430         qbuf->size -= size;
00431 
00432         // buffer has been emptied? remove item from queue
00433         if ( res <= size )
00434         {
00435                 nip_udp_cancel_recv( sockid );
00436         }
00437 
00438         return res;
00439 
00440 }
00441 
00442 /** Forwards current incoming buffer to outgoing queue. It will still have to
00443  * be transmitted using nip_udp_transmit().
00444  */
00445 void nip_udp_forward( nip_udp_sock_id_t sockid )
00446 {
00447         struct nip_udp_sock   *sock = nip_udp_sock_ptr( sockid );
00448         struct nip_udp_buffer *qbuf;
00449 
00450         if ( sock!= NULL && sock->rx_packet != NIP_UDP_EOQ )
00451         {
00452                 qbuf = &udp_rx_queue[ sock->rx_packet ];
00453                 // clear current transmission
00454                 nip_mem_free( sock->tx_packet );
00455                 sock->tx_packet = qbuf->buf;
00456                 qbuf->buf = NIP_MEM_NULL;
00457                 sock->rx_packet = qbuf->next;
00458         }
00459 }
00460 
00461 /** Cancel current packet reception. */
00462 void nip_udp_cancel_recv( nip_udp_sock_id_t sockid )
00463 {
00464         struct nip_udp_sock   *sock = nip_udp_sock_ptr( sockid );
00465         struct nip_udp_buffer *qbuf;
00466 
00467         if ( sock->rx_packet != NIP_UDP_EOQ )
00468         {
00469                 qbuf = &udp_rx_queue[ sock->rx_packet ];
00470                 // forward to next packet in queue
00471                 sock->rx_packet = qbuf->next;
00472                 // clear old queue item
00473                 nip_mem_free( qbuf->buf );
00474                 qbuf->buf = NIP_MEM_NULL;
00475         }
00476 }
00477 
00478 /** Dispatcher function to be called upon packet reception */
00479 void nip_udp_disp_receive( void )
00480 {
00481         struct nip_udp_header *head;
00482         struct nip_udp_sock   *sock;
00483         nip_net_if_trans_t    *trans;
00484         nip_udp_sock_id_t     sockid;
00485         uint8_t               check_cnt;
00486         nip_udp_queue_id_t    sock_qid;
00487         nip_udp_queue_id_t    ins_qid;
00488         struct nip_udp_buffer *qbuf;
00489         uint16_t              h_size;
00490 
00491         trans = nip_disp.next.common.trans;
00492 
00493         if ( trans->payload_size < sizeof( struct nip_udp_header) )
00494                 goto discard;
00495 
00496         head = nip_mem_obtain_ptr( trans->payload );
00497 
00498         if ( head == NULL )
00499         {
00500                 // something's wrong with the payload -> discard
00501                 goto discard;
00502         }
00503 
00504         // lookup socket
00505 #if (NIP_UDP_USE_FIXED_SOCKETS==1)
00506         sockid = 0;
00507                 #if (NIP_UDP_FIXED_SOCKETS > 1 )
00508         do
00509         {
00510         #endif
00511                 check_cnt = 0;
00512                 sock = &udp_sockets[ sockid ];
00513                 // check socket
00514                 if (((sock->flags & NIP_UDP_SOCK_FLG_USED) > 0)
00515                         && ( sock->addr.port == head->dst_port )
00516                         && ((nip_memcmp( sock->addr.ip, trans->params.ip.dst_nw_addr, 4 ) == 0 )
00517                           ||(sock->addr.ip[0]==0 && sock->addr.ip[1]==0 && sock->addr.ip[2]==0 && sock->addr.ip[3]==0)
00518                         #if NIP_MULTICAST_ENABLE == 1
00519                           ||(trans->params.ip.dst_nw_addr[0] >= 0xE0)
00520                         #endif
00521                                 ))
00522                 {
00523                         goto found;
00524                 }
00525         #if (NIP_UDP_FIXED_SOCKETS > 1 )
00526         } while ( ++sockid < NIP_UDP_FIXED_SOCKETS );
00527         #endif
00528 #else
00529         ///@todo implement not fixed sockets
00530 #endif // (NIP_UDP_USE_FIXED_SOCKETS==1)
00531         goto release;
00532 
00533         found:
00534         h_size = ntohs(head->length);
00535         // sanity-check of datagram size
00536         if ( nip_mem_buf_used( trans->payload ) < h_size )
00537         {
00538                 goto release;
00539         }
00540 
00541         // find slot in queue
00542         ins_qid = 0;
00543         do
00544         {
00545                 qbuf = &udp_rx_queue[ ins_qid ];
00546                 if ( qbuf->buf == NIP_MEM_NULL )
00547                         break;
00548         } while ( ++ins_qid < NIP_UDP_EOQ );
00549 
00550         // queue full? -> discard
00551         if ( ins_qid == NIP_UDP_EOQ )
00552                 goto release;
00553 
00554         // find end of socket queue
00555         sock_qid = sock->rx_packet;
00556         while ( sock_qid != NIP_UDP_EOQ )
00557         {
00558                 if ( udp_rx_queue[ sock_qid ].next == NIP_UDP_EOQ ) break;
00559                 sock_qid = udp_rx_queue[ sock_qid ].next;
00560         }
00561 
00562         // set up queue item
00563         qbuf->buf       = trans->payload;
00564         qbuf->next      = NIP_UDP_EOQ;
00565         qbuf->sockid    = sockid;
00566         qbuf->size      = h_size;
00567         qbuf->addr.port = head->src_port;
00568         nip_memcpy( qbuf->addr.ip, trans->params.ip.src_nw_addr, 4 );
00569         // trans->payload now managed by socket. Make sure it won't be freed
00570         // with the rest of the transmission
00571         trans->flags.free_payload = 0;
00572 
00573 
00574         // add to queue
00575         if ( sock->rx_packet == NIP_UDP_EOQ )
00576         {
00577                 sock->rx_packet = ins_qid;
00578         }
00579         else
00580         {
00581                 udp_rx_queue[ sock_qid ].next = ins_qid;
00582         }
00583         // else: queue full? -> Discard datagram
00584         ///@todo implement longer UDP receive Queue
00585 
00586         release:
00587                 nip_mem_release_block( trans->payload );
00588 
00589         discard:
00590                 trans->status = NIP_NET_IF_DONE;
00591                 nip_reset_trans( trans );
00592                 return;
00593 }
00594 
00595 
00596 #endif // (NIP_UDP_ENABLE == 1 )

Generated on Thu Jul 10 01:09:29 2008 for NIP by  doxygen 1.5.5