mirror of
https://github.com/pvvx/RTL00_WEB.git
synced 2024-11-22 05:54:19 +00:00
update
This commit is contained in:
parent
a9ef4ff5c0
commit
b8c699eb1c
243 changed files with 1850 additions and 76723 deletions
216
USDK/component/common/network/httpc/httpc.h
Normal file
216
USDK/component/common/network/httpc/httpc.h
Normal file
|
@ -0,0 +1,216 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* @file httpc.h
|
||||||
|
* @author
|
||||||
|
* @version
|
||||||
|
* @brief This file provides user interface for HTTP/HTTPS client.
|
||||||
|
******************************************************************************
|
||||||
|
* @attention
|
||||||
|
*
|
||||||
|
* This module is a confidential and proprietary property of RealTek and possession or use of this module requires written permission of RealTek.
|
||||||
|
*
|
||||||
|
* Copyright(c) 2016, Realtek Semiconductor Corporation. All rights reserved.
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
#ifndef _HTTPC_H_
|
||||||
|
#define _HTTPC_H_
|
||||||
|
|
||||||
|
/** @addtogroup httpc HTTPC
|
||||||
|
* @ingroup network
|
||||||
|
* @brief HTTP/HTTPS client functions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "platform_stdlib.h"
|
||||||
|
#include "platform_opts.h"
|
||||||
|
|
||||||
|
#define HTTPC_SECURE_NONE 0 /*!< Running with HTTP client */
|
||||||
|
#define HTTPC_SECURE_TLS 1 /*!< Running with HTTPS client */
|
||||||
|
|
||||||
|
#define HTTPC_DEBUG_OFF 0 /*!< Disable httpc debug log */
|
||||||
|
#define HTTPC_DEBUG_ON 1 /*!< Enable httpc debug log */
|
||||||
|
#define HTTPC_DEBUG_VERBOSE 2 /*!< Enable httpc verbose debug log */
|
||||||
|
|
||||||
|
#define HTTPC_TLS_POLARSSL 0 /*!< Use PolarSSL for TLS when HTTPS */
|
||||||
|
#define HTTPC_TLS_MBEDTLS 1 /*!< Use mbedTLS for TLS when HTTPS */
|
||||||
|
|
||||||
|
#if CONFIG_USE_POLARSSL
|
||||||
|
#define HTTPC_USE_TLS HTTPC_TLS_POLARSSL
|
||||||
|
#elif CONFIG_USE_MBEDTLS
|
||||||
|
#define HTTPC_USE_TLS HTTPC_TLS_MBEDTLS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The structure is the context used for HTTP response header parsing.
|
||||||
|
* @note Only header string includes string terminator.
|
||||||
|
*/
|
||||||
|
struct http_response {
|
||||||
|
uint8_t *header; /*!< HTTP header string parsed in HTTP response */
|
||||||
|
size_t header_len; /*!< HTTP header string length */
|
||||||
|
uint8_t *version; /*!< Pointer to HTTP version in the parsed HTTP header string */
|
||||||
|
size_t version_len; /*!< HTTP version data length */
|
||||||
|
uint8_t *status; /*!< Pointer to HTTP status code in the parsed HTTP header string */
|
||||||
|
size_t status_len; /*!< HTTP status code data length */
|
||||||
|
uint8_t *content_type; /*!< Pointer to Content-Type header field in the parsed HTTP header string */
|
||||||
|
size_t content_type_len; /*!< Content-Type header field data length */
|
||||||
|
size_t content_len; /*!< Value of Content-Length header field parsed in HTTP header string */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The structure is the context used for connection.
|
||||||
|
*/
|
||||||
|
struct httpc_conn {
|
||||||
|
int sock; /*!< Client socket descriptor for connection */
|
||||||
|
struct http_response response; /*!< Context for HTTP response */
|
||||||
|
void *tls; /*!< Context for TLS connection */
|
||||||
|
uint8_t *request_header; /*!< Pointer to transmission buffer of HTTP request header */
|
||||||
|
char *host; /*!< String of server host name or IP */
|
||||||
|
uint16_t port; /*!< Service port */
|
||||||
|
char *user_password; /*!< Base64 string for HTTP basic authorization */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function is used to generate connection context for an HTTP/HTTPS client.
|
||||||
|
* @param[in] secure: security mode for HTTP or HTTPS. Must be HTTPD_SECURE_NONE, HTTPD_SECURE_TLS.
|
||||||
|
* @param[in] client_cert: string of client certificate if required to be verified by server.
|
||||||
|
* @param[in] client_key: string of client private key if required to be verified by server.
|
||||||
|
* @param[in] ca_certs: string including certificates in CA trusted chain if want to verify server certificate.
|
||||||
|
* @return pointer to the generated connection context
|
||||||
|
*/
|
||||||
|
struct httpc_conn *httpc_conn_new(uint8_t secure, char *client_cert, char *client_key, char *ca_certs);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function is used to deallocate a connection context.
|
||||||
|
* @param[in] conn: pointer to connection context
|
||||||
|
* @return None
|
||||||
|
*/
|
||||||
|
void httpc_conn_free(struct httpc_conn *conn);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function is used to connect to a server.
|
||||||
|
* @param[in] conn: pointer to connection context
|
||||||
|
* @param[in] host: string of server host name or IP
|
||||||
|
* @param[in] port: service port
|
||||||
|
* @param[in] timeout: connection timeout in seconds
|
||||||
|
* @return 0 : if successful
|
||||||
|
* @return -1 : if error occurred
|
||||||
|
*/
|
||||||
|
int httpc_conn_connect(struct httpc_conn *conn, char *host, uint16_t port, uint32_t timeout);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function is used to close connection from a server.
|
||||||
|
* @param[in] conn: pointer to connection context
|
||||||
|
* @return None
|
||||||
|
*/
|
||||||
|
void httpc_conn_close(struct httpc_conn *conn);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function is used to setup authorization for connection.
|
||||||
|
* @param[in] conn: pointer to connection context
|
||||||
|
* @param[in] user: string of user name for authorization
|
||||||
|
* @param[in] password: string of password for authorization
|
||||||
|
* @return 0 : if successful
|
||||||
|
* @return -1 : if error occurred
|
||||||
|
* @note Must be used before httpc_conn_connect() if basic authorization is used
|
||||||
|
*/
|
||||||
|
int httpc_conn_setup_user_password(struct httpc_conn *conn, char *user, char *password);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function is used to setup httpc debug.
|
||||||
|
* @param[in] debug: flag to enable/disable httpc debug. Must be HTTPC_DEBUG_OFF, HTTPC_DEBUG_ON, HTTPC_DEBUG_VERBOSE.
|
||||||
|
* @return None
|
||||||
|
*/
|
||||||
|
void httpc_setup_debug(uint8_t debug);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function is used to free memory allocated by httpc API, such as httpc_response_get_header_field().
|
||||||
|
* @param[in] ptr: pointer to memory to be deallocated
|
||||||
|
* @return None
|
||||||
|
*/
|
||||||
|
void httpc_free(void *ptr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function is used to dump the parsed HTTP header of response in connection context.
|
||||||
|
* @param[in] conn: pointer to connection context
|
||||||
|
* @return None
|
||||||
|
*/
|
||||||
|
void httpc_conn_dump_header(struct httpc_conn *conn);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function is used to start a HTTP request in connection.
|
||||||
|
* @param[in] conn: pointer to connection context
|
||||||
|
* @param[in] method: string of HTTP method in HTTP request
|
||||||
|
* @param[in] resource: string including path and query string to identify a resource
|
||||||
|
* @param[in] content_type: string of Content-Type header field written to HTTP request. No Content-Type in HTTP request if NULL.
|
||||||
|
* @param[in] content_len: value of Content-Length header field written to HTTP request. No Content-Length in HTTP request if NULL.
|
||||||
|
* @return 0 : if successful
|
||||||
|
* @return -1 : if error occurred
|
||||||
|
*/
|
||||||
|
int httpc_request_write_header_start(struct httpc_conn *conn, char *method, char *resource, char *content_type, size_t content_len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function is used to add an HTTP header field to HTTP request.
|
||||||
|
* @param[in] conn: pointer to connection context
|
||||||
|
* @param[in] name: HTTP header field name string
|
||||||
|
* @param[in] value: HTTP header field value
|
||||||
|
* @return 0 : if successful
|
||||||
|
* @return -1 : if error occurred
|
||||||
|
*/
|
||||||
|
int httpc_request_write_header(struct httpc_conn *conn, char *name, char *value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function is used to write HTTP request header data to connection.
|
||||||
|
* @param[in] conn: pointer to connection context
|
||||||
|
* @return return value of lwip socket write() for HTTP and PolarSSL ssl_write() for HTTPS
|
||||||
|
*/
|
||||||
|
int httpc_request_write_header_finish(struct httpc_conn *conn);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function is used to write HTTP request body data to connection.
|
||||||
|
* @param[in] conn: pointer to connection context
|
||||||
|
* @param[in] data: data to be written
|
||||||
|
* @param[in] data_len: data length
|
||||||
|
* @return return value of lwip socket write() for HTTP and PolarSSL ssl_write() for HTTPS
|
||||||
|
*/
|
||||||
|
int httpc_request_write_data(struct httpc_conn *conn, uint8_t *data, size_t data_len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function is used to check HTTP status of response in connection context.
|
||||||
|
* @param[in] conn: pointer to connection context
|
||||||
|
* @param[in] status: HTTP status string to compare with
|
||||||
|
* @return 0 : if different
|
||||||
|
* @return 1 : if matched
|
||||||
|
*/
|
||||||
|
int httpc_response_is_status(struct httpc_conn *conn, char *status);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function is used to read HTTP header from client socket descriptor and parse content to connection context.
|
||||||
|
* @param[in] conn: pointer to connection context
|
||||||
|
* @return 0 : if successful
|
||||||
|
* @return -1 : if error occurred
|
||||||
|
*/
|
||||||
|
int httpc_response_read_header(struct httpc_conn *conn);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function is used to read data from HTTP/HTTPS connection.
|
||||||
|
* @param[in] conn: pointer to connection context
|
||||||
|
* @param[out] data: buffer for data read
|
||||||
|
* @param[in] data_len: buffer length
|
||||||
|
* @return return value of lwip socket read() for HTTP and PolarSSL ssl_read() for HTTPS
|
||||||
|
*/
|
||||||
|
int httpc_response_read_data(struct httpc_conn *conn, uint8_t *data, size_t data_len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function is used to get a header field from HTTP header of connection context.
|
||||||
|
* @param[in] conn: pointer to connection context
|
||||||
|
* @param[in] field: header field string to search
|
||||||
|
* @param[out] value: search result stored in memory allocated
|
||||||
|
* @return 0 : if found
|
||||||
|
* @return -1 : if not found
|
||||||
|
* @note The search result memory should be free by httpc_free().
|
||||||
|
*/
|
||||||
|
int httpc_response_get_header_field(struct httpc_conn *conn, char *field, char **value);
|
||||||
|
|
||||||
|
/*\@}*/
|
||||||
|
|
||||||
|
#endif /* _HTTPC_H_ */
|
355
USDK/component/common/network/httpc/httpc_tls.c
Normal file
355
USDK/component/common/network/httpc/httpc_tls.c
Normal file
|
@ -0,0 +1,355 @@
|
||||||
|
#include "FreeRTOS.h"
|
||||||
|
#include "task.h"
|
||||||
|
#include "platform_stdlib.h"
|
||||||
|
|
||||||
|
#include "httpc.h"
|
||||||
|
|
||||||
|
#if (HTTPC_USE_TLS == HTTPC_TLS_POLARSSL)
|
||||||
|
#include "polarssl/ssl.h"
|
||||||
|
#include "polarssl/memory.h"
|
||||||
|
#include "polarssl/base64.h"
|
||||||
|
|
||||||
|
struct httpc_tls {
|
||||||
|
ssl_context ctx; /*!< Context for PolarSSL */
|
||||||
|
x509_crt ca; /*!< CA certificates */
|
||||||
|
x509_crt cert; /*!< Certificate */
|
||||||
|
pk_context key; /*!< Private key */
|
||||||
|
};
|
||||||
|
|
||||||
|
static int _verify_func(void *data, x509_crt *crt, int depth, int *flags)
|
||||||
|
{
|
||||||
|
char buf[1024];
|
||||||
|
x509_crt_info(buf, sizeof(buf) - 1, "", crt);
|
||||||
|
|
||||||
|
if(*flags)
|
||||||
|
printf("\n[HTTPC] ERROR: certificate verify\n%s\n", buf);
|
||||||
|
else
|
||||||
|
printf("\n[HTTPC] Certificate verified\n%s\n", buf);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif (HTTPC_USE_TLS == HTTPC_TLS_MBEDTLS)
|
||||||
|
#include "mbedtls/ssl.h"
|
||||||
|
#include "mbedtls/platform.h"
|
||||||
|
#include "mbedtls/net_sockets.h"
|
||||||
|
#include "mbedtls/base64.h"
|
||||||
|
|
||||||
|
struct httpc_tls {
|
||||||
|
mbedtls_ssl_context ctx; /*!< Context for mbedTLS */
|
||||||
|
mbedtls_ssl_config conf; /*!< Configuration for mbedTLS */
|
||||||
|
mbedtls_x509_crt ca; /*!< CA certificates */
|
||||||
|
mbedtls_x509_crt cert; /*!< Certificate */
|
||||||
|
mbedtls_pk_context key; /*!< Private key */
|
||||||
|
};
|
||||||
|
|
||||||
|
static int _verify_func(void *data, mbedtls_x509_crt *crt, int depth, uint32_t *flags)
|
||||||
|
{
|
||||||
|
char buf[1024];
|
||||||
|
mbedtls_x509_crt_info(buf, sizeof(buf) - 1, "", crt);
|
||||||
|
|
||||||
|
if(*flags)
|
||||||
|
printf("\n[HTTPC] ERROR: certificate verify\n%s\n", buf);
|
||||||
|
else
|
||||||
|
printf("\n[HTTPC] Certificate verified\n%s\n", buf);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void* _calloc_func(size_t nmemb, size_t size)
|
||||||
|
{
|
||||||
|
size_t mem_size;
|
||||||
|
void *ptr = NULL;
|
||||||
|
|
||||||
|
mem_size = nmemb * size;
|
||||||
|
ptr = pvPortMalloc(mem_size);
|
||||||
|
|
||||||
|
if(ptr)
|
||||||
|
memset(ptr, 0, mem_size);
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
#endif /* HTTPC_USE_POLARSSL */
|
||||||
|
|
||||||
|
static int _random_func(void *p_rng, unsigned char *output, size_t output_len)
|
||||||
|
{
|
||||||
|
rtw_get_random_bytes(output, output_len);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *httpc_tls_new(int *sock, char *client_cert, char *client_key, char *ca_certs)
|
||||||
|
{
|
||||||
|
#if (HTTPC_USE_TLS == HTTPC_TLS_POLARSSL)
|
||||||
|
int ret = 0;
|
||||||
|
struct httpc_tls *tls = NULL;
|
||||||
|
|
||||||
|
memory_set_own(pvPortMalloc, vPortFree);
|
||||||
|
tls = (struct httpc_tls *) malloc(sizeof(struct httpc_tls));
|
||||||
|
|
||||||
|
if(tls) {
|
||||||
|
ssl_context *ssl = &tls->ctx;
|
||||||
|
|
||||||
|
memset(tls, 0, sizeof(struct httpc_tls));
|
||||||
|
x509_crt_init(&tls->ca);
|
||||||
|
x509_crt_init(&tls->cert);
|
||||||
|
pk_init(&tls->key);
|
||||||
|
ssl_init(ssl);
|
||||||
|
ssl_set_endpoint(ssl, SSL_IS_CLIENT);
|
||||||
|
ssl_set_authmode(ssl, SSL_VERIFY_NONE);
|
||||||
|
ssl_set_rng(ssl, _random_func, NULL);
|
||||||
|
ssl_set_bio(ssl, net_recv, sock, net_send, sock);
|
||||||
|
|
||||||
|
if(client_cert && client_key) {
|
||||||
|
if((ret = x509_crt_parse(&tls->cert, (const unsigned char *) client_cert, strlen(client_cert))) != 0) {
|
||||||
|
printf("\n[HTTPC] ERROR: x509_crt_parse %d\n", ret);
|
||||||
|
ret = -1;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((ret = pk_parse_key(&tls->key, (const unsigned char *) client_key, strlen(client_key), NULL, 0)) != 0) {
|
||||||
|
printf("\n[HTTPC] ERROR: pk_parse_key %d\n", ret);
|
||||||
|
ret = -1;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((ret = ssl_set_own_cert(ssl, &tls->cert, &tls->key)) != 0) {
|
||||||
|
printf("\n[HTTPC] ERROR: ssl_set_own_cert %d\n", ret);
|
||||||
|
ret = -1;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ca_certs) {
|
||||||
|
// set trusted ca certificates next to client certificate
|
||||||
|
if((ret = x509_crt_parse(&tls->ca, (const unsigned char *) ca_certs, strlen(ca_certs))) != 0) {
|
||||||
|
printf("\n[HTTPC] ERROR: x509_crt_parse %d\n", ret);
|
||||||
|
ret = -1;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssl_set_ca_chain(ssl, &tls->ca, NULL, NULL);
|
||||||
|
ssl_set_authmode(ssl, SSL_VERIFY_REQUIRED);
|
||||||
|
ssl_set_verify(ssl, _verify_func, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printf("\n[HTTPC] ERROR: malloc\n");
|
||||||
|
ret = -1;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
|
if(ret && tls) {
|
||||||
|
ssl_free(&tls->ctx);
|
||||||
|
x509_crt_free(&tls->ca);
|
||||||
|
x509_crt_free(&tls->cert);
|
||||||
|
pk_free(&tls->key);
|
||||||
|
free(tls);
|
||||||
|
tls = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (void *) tls;
|
||||||
|
#elif (HTTPC_USE_TLS == HTTPC_TLS_MBEDTLS)
|
||||||
|
int ret = 0;
|
||||||
|
struct httpc_tls *tls = NULL;
|
||||||
|
|
||||||
|
mbedtls_platform_set_calloc_free(_calloc_func, vPortFree);
|
||||||
|
tls = (struct httpc_tls *) malloc(sizeof(struct httpc_tls));
|
||||||
|
|
||||||
|
if(tls) {
|
||||||
|
mbedtls_ssl_context *ssl = &tls->ctx;
|
||||||
|
mbedtls_ssl_config *conf = &tls->conf;
|
||||||
|
|
||||||
|
memset(tls, 0, sizeof(struct httpc_tls));
|
||||||
|
mbedtls_x509_crt_init(&tls->ca);
|
||||||
|
mbedtls_x509_crt_init(&tls->cert);
|
||||||
|
mbedtls_pk_init(&tls->key);
|
||||||
|
mbedtls_ssl_init(ssl);
|
||||||
|
mbedtls_ssl_config_init(conf);
|
||||||
|
|
||||||
|
if((ret = mbedtls_ssl_config_defaults(conf,
|
||||||
|
MBEDTLS_SSL_IS_CLIENT,
|
||||||
|
MBEDTLS_SSL_TRANSPORT_STREAM,
|
||||||
|
MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
|
||||||
|
|
||||||
|
printf("\n[HTTPC] ERROR: mbedtls_ssl_config_defaults %d\n", ret);
|
||||||
|
ret = -1;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
mbedtls_ssl_conf_authmode(conf, MBEDTLS_SSL_VERIFY_NONE);
|
||||||
|
mbedtls_ssl_conf_rng(conf, _random_func, NULL);
|
||||||
|
|
||||||
|
if(client_cert && client_key) {
|
||||||
|
if((ret = mbedtls_x509_crt_parse(&tls->cert, (const unsigned char *) client_cert, strlen(client_cert) + 1)) != 0) {
|
||||||
|
printf("\n[HTTPC] ERROR: mbedtls_x509_crt_parse %d\n", ret);
|
||||||
|
ret = -1;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((ret = mbedtls_pk_parse_key(&tls->key, (const unsigned char *) client_key, strlen(client_key) + 1, NULL, 0)) != 0) {
|
||||||
|
printf("\n[HTTPC] ERROR: mbedtls_pk_parse_key %d\n", ret);
|
||||||
|
ret = -1;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((ret = mbedtls_ssl_conf_own_cert(conf, &tls->cert, &tls->key)) != 0) {
|
||||||
|
printf("\n[HTTPC] ERROR: mbedtls_ssl_conf_own_cert %d\n", ret);
|
||||||
|
ret = -1;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ca_certs) {
|
||||||
|
// set trusted ca certificates next to client certificate
|
||||||
|
if((ret = mbedtls_x509_crt_parse(&tls->ca, (const unsigned char *) ca_certs, strlen(ca_certs) + 1)) != 0) {
|
||||||
|
printf("\n[HTTPC] ERROR: mbedtls_x509_crt_parse %d\n", ret);
|
||||||
|
ret = -1;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
mbedtls_ssl_conf_ca_chain(conf, &tls->ca, NULL);
|
||||||
|
mbedtls_ssl_conf_authmode(conf, MBEDTLS_SSL_VERIFY_REQUIRED);
|
||||||
|
mbedtls_ssl_conf_verify(conf, _verify_func, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if((ret = mbedtls_ssl_setup(ssl, conf)) != 0) {
|
||||||
|
printf("\n[HTTPC] ERROR: mbedtls_ssl_setup %d\n", ret);
|
||||||
|
ret = -1;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
mbedtls_ssl_set_bio(ssl, sock, mbedtls_net_send, mbedtls_net_recv, NULL);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printf("\n[HTTPC] ERROR: malloc\n");
|
||||||
|
ret = -1;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
|
if(ret && tls) {
|
||||||
|
mbedtls_ssl_free(&tls->ctx);
|
||||||
|
mbedtls_ssl_config_free(&tls->conf);
|
||||||
|
mbedtls_x509_crt_free(&tls->ca);
|
||||||
|
mbedtls_x509_crt_free(&tls->cert);
|
||||||
|
mbedtls_pk_free(&tls->key);
|
||||||
|
free(tls);
|
||||||
|
tls = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (void *) tls;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void httpc_tls_free(void *tls_in)
|
||||||
|
{
|
||||||
|
struct httpc_tls *tls = (struct httpc_tls *) tls_in;
|
||||||
|
|
||||||
|
#if (HTTPC_USE_TLS == HTTPC_TLS_POLARSSL)
|
||||||
|
ssl_free(&tls->ctx);
|
||||||
|
x509_crt_free(&tls->ca);
|
||||||
|
x509_crt_free(&tls->cert);
|
||||||
|
pk_free(&tls->key);
|
||||||
|
free(tls);
|
||||||
|
#elif (HTTPC_USE_TLS == HTTPC_TLS_MBEDTLS)
|
||||||
|
mbedtls_ssl_free(&tls->ctx);
|
||||||
|
mbedtls_ssl_config_free(&tls->conf);
|
||||||
|
mbedtls_x509_crt_free(&tls->ca);
|
||||||
|
mbedtls_x509_crt_free(&tls->cert);
|
||||||
|
mbedtls_pk_free(&tls->key);
|
||||||
|
free(tls);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int httpc_tls_handshake(void *tls_in, char *host)
|
||||||
|
{
|
||||||
|
struct httpc_tls *tls = (struct httpc_tls *) tls_in;
|
||||||
|
|
||||||
|
#if (HTTPC_USE_TLS == HTTPC_TLS_POLARSSL)
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
ssl_set_hostname(&tls->ctx, host);
|
||||||
|
|
||||||
|
if((ret = ssl_handshake(&tls->ctx)) != 0) {
|
||||||
|
printf("\n[HTTPC] ERROR: ssl_handshake %d\n", ret);
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printf("\n[HTTPC] Use ciphersuite %s\n", ssl_get_ciphersuite(&tls->ctx));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
#elif (HTTPC_USE_TLS == HTTPC_TLS_MBEDTLS)
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
mbedtls_ssl_set_hostname(&tls->ctx, host);
|
||||||
|
|
||||||
|
if((ret = mbedtls_ssl_handshake(&tls->ctx)) != 0) {
|
||||||
|
printf("\n[HTTPC] ERROR: mbedtls_ssl_handshake %d\n", ret);
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printf("\n[HTTPC] Use ciphersuite %s\n", mbedtls_ssl_get_ciphersuite(&tls->ctx));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void httpc_tls_close(void *tls_in)
|
||||||
|
{
|
||||||
|
struct httpc_tls *tls = (struct httpc_tls *) tls_in;
|
||||||
|
|
||||||
|
#if (HTTPC_USE_TLS == HTTPC_TLS_POLARSSL)
|
||||||
|
ssl_close_notify(&tls->ctx);
|
||||||
|
#elif (HTTPC_USE_TLS == HTTPC_TLS_MBEDTLS)
|
||||||
|
mbedtls_ssl_close_notify(&tls->ctx);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int httpc_tls_read(void *tls_in, uint8_t *buf, size_t buf_len)
|
||||||
|
{
|
||||||
|
struct httpc_tls *tls = (struct httpc_tls *) tls_in;
|
||||||
|
|
||||||
|
#if (HTTPC_USE_TLS == HTTPC_TLS_POLARSSL)
|
||||||
|
return ssl_read(&tls->ctx, buf, buf_len);
|
||||||
|
#elif (HTTPC_USE_TLS == HTTPC_TLS_MBEDTLS)
|
||||||
|
return mbedtls_ssl_read(&tls->ctx, buf, buf_len);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int httpc_tls_write(void *tls_in, uint8_t *buf, size_t buf_len)
|
||||||
|
{
|
||||||
|
struct httpc_tls *tls = (struct httpc_tls *) tls_in;
|
||||||
|
|
||||||
|
#if (HTTPC_USE_TLS == HTTPC_TLS_POLARSSL)
|
||||||
|
return ssl_write(&tls->ctx, buf, buf_len);
|
||||||
|
#elif (HTTPC_USE_TLS == HTTPC_TLS_MBEDTLS)
|
||||||
|
return mbedtls_ssl_write(&tls->ctx, buf, buf_len);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int httpc_base64_encode(uint8_t *data, size_t data_len, char *base64_buf, size_t buf_len)
|
||||||
|
{
|
||||||
|
#if (HTTPC_USE_TLS == HTTPC_TLS_POLARSSL)
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if((ret = base64_encode(base64_buf, &buf_len, data, data_len)) != 0) {
|
||||||
|
printf("\n[HTTPC] ERROR: base64_encode %d\n", ret);
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
#elif (HTTPC_USE_TLS == HTTPC_TLS_MBEDTLS)
|
||||||
|
int ret = 0;
|
||||||
|
size_t output_len = 0;
|
||||||
|
|
||||||
|
if((ret = mbedtls_base64_encode(base64_buf, buf_len, &output_len, data, data_len)) != 0) {
|
||||||
|
printf("\n[HTTPC] ERROR: mbedtls_base64_encode %d\n", ret);
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
#endif
|
||||||
|
}
|
299
USDK/component/common/network/httpd/httpd.h
Normal file
299
USDK/component/common/network/httpd/httpd.h
Normal file
|
@ -0,0 +1,299 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* @file httpd.h
|
||||||
|
* @author
|
||||||
|
* @version
|
||||||
|
* @brief This file provides user interface for HTTP/HTTPS server.
|
||||||
|
******************************************************************************
|
||||||
|
* @attention
|
||||||
|
*
|
||||||
|
* This module is a confidential and proprietary property of RealTek and possession or use of this module requires written permission of RealTek.
|
||||||
|
*
|
||||||
|
* Copyright(c) 2016, Realtek Semiconductor Corporation. All rights reserved.
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
#ifndef _HTTPD_H_
|
||||||
|
#define _HTTPD_H_
|
||||||
|
|
||||||
|
/** @addtogroup httpd HTTPD
|
||||||
|
* @ingroup network
|
||||||
|
* @brief HTTP/HTTPS server functions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "platform_stdlib.h"
|
||||||
|
#include "platform_opts.h"
|
||||||
|
|
||||||
|
#define HTTPD_SECURE_NONE 0 /*!< Running with HTTP server */
|
||||||
|
#define HTTPD_SECURE_TLS 1 /*!< Running with HTTPS server */
|
||||||
|
#define HTTPD_SECURE_TLS_VERIFY 2 /*!< Running with HTTPS server and verify client */
|
||||||
|
|
||||||
|
#define HTTPD_THREAD_SINGLE 0 /*!< Multi-thread mode for request handling */
|
||||||
|
#define HTTPD_THREAD_MULTIPLE 1 /*!< Single-thread mode for request handling */
|
||||||
|
|
||||||
|
#define HTTPD_DEBUG_OFF 0 /*!< Disable httpd debug log */
|
||||||
|
#define HTTPD_DEBUG_ON 1 /*!< Enable httpd debug log */
|
||||||
|
#define HTTPD_DEBUG_VERBOSE 2 /*!< Enable httpd verbose debug log */
|
||||||
|
|
||||||
|
#define HTTPD_TLS_POLARSSL 0 /*!< Use PolarSSL for TLS when HTTPS */
|
||||||
|
#define HTTPD_TLS_MBEDTLS 1 /*!< Use mbedTLS for TLS when HTTPS */
|
||||||
|
|
||||||
|
#if CONFIG_USE_POLARSSL
|
||||||
|
#define HTTPD_USE_TLS HTTPD_TLS_POLARSSL
|
||||||
|
#elif CONFIG_USE_MBEDTLS
|
||||||
|
#define HTTPD_USE_TLS HTTPD_TLS_MBEDTLS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The structure is the context used for HTTP request header parsing.
|
||||||
|
* @note Only header string includes string terminator.
|
||||||
|
*/
|
||||||
|
struct http_request {
|
||||||
|
uint8_t *header; /*!< HTTP header string parsed in HTTP request */
|
||||||
|
size_t header_len; /*!< HTTP header string length */
|
||||||
|
uint8_t *method; /*!< Pointer to HTTP method in the parsed HTTP header string */
|
||||||
|
size_t method_len; /*!< HTTP method data length */
|
||||||
|
uint8_t *path; /*!< Pointer to resource path in the parsed HTTP header string */
|
||||||
|
size_t path_len; /*!< Resource path data length */
|
||||||
|
uint8_t *query; /*!< Pointer to query string in the parsed HTTP header string */
|
||||||
|
size_t query_len; /*!< Query string data length */
|
||||||
|
uint8_t *version; /*!< Pointer to HTTP version in the parsed HTTP header string */
|
||||||
|
size_t version_len; /*!< HTTP version data length */
|
||||||
|
uint8_t *host; /*!< Pointer to Host header field in the parsed HTTP header string */
|
||||||
|
size_t host_len; /*!< Host header field data length */
|
||||||
|
uint8_t *content_type; /*!< Pointer to Content-Type header field in the parsed HTTP header string */
|
||||||
|
size_t content_type_len; /*!< Content-Type header field data length */
|
||||||
|
size_t content_len; /*!< Value of Content-Length header field parsed in HTTP header string */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The structure is the context used for client connection.
|
||||||
|
*/
|
||||||
|
struct httpd_conn {
|
||||||
|
int sock; /*!< Client socket descriptor for connection */
|
||||||
|
struct http_request request; /*!< Context for HTTP request */
|
||||||
|
void *tls; /*!< Context for TLS connection */
|
||||||
|
uint8_t *response_header; /*!< Pointer to transmission buffer of HTTP response header */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function is used to start an HTTP or HTTPS server.
|
||||||
|
* @param[in] port: service port
|
||||||
|
* @param[in] max_conn: max client connections allowed
|
||||||
|
* @param[in] stack_bytes: thread stack size in bytes
|
||||||
|
* @param[in] thread_mode: server running thread mode. Must be HTTPD_THREAD_SINGLE, HTTPD_THREAD_MULTIPLE.
|
||||||
|
* @param[in] secure: security mode for HTTP or HTTPS. Must be HTTPD_SECURE_NONE, HTTPD_SECURE_TLS, HTTPD_SECURE_TLS_VERIFY.
|
||||||
|
* @return 0 : if successful
|
||||||
|
* @return -1 : if error occurred
|
||||||
|
*/
|
||||||
|
int httpd_start(uint16_t port, uint8_t max_conn, uint32_t stack_bytes, uint8_t thread_mode, uint8_t secure);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function is used to stop a running server
|
||||||
|
* @return None
|
||||||
|
*/
|
||||||
|
void httpd_stop(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function is used to register a callback function for a Web page request handling.
|
||||||
|
* @param[in] path: resource path for a page
|
||||||
|
* @param[in] callback: callback function to handle the request to page
|
||||||
|
* @return 0 : if successful
|
||||||
|
* @return -1 : if error occurred
|
||||||
|
*/
|
||||||
|
int httpd_reg_page_callback(char *path, void (*callback)(struct httpd_conn *conn));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function is used to clear all registered page callback functions.
|
||||||
|
* @return None
|
||||||
|
* @note All page callback will be cleared automatically if httpd_stop().
|
||||||
|
*/
|
||||||
|
void httpd_clear_page_callbacks(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function is used to setup httpd debug.
|
||||||
|
* @param[in] debug: flag to enable/disable httpd debug. Must be HTTPD_DEBUG_OFF, HTTPD_DEBUG_ON, HTTPD_DEBUG_VERBOSE.
|
||||||
|
* @return None
|
||||||
|
*/
|
||||||
|
void httpd_setup_debug(uint8_t debug);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function is used to setup certificate and key for server before starting with HTTPS.
|
||||||
|
* @param[in] server_cert: string of server certificate
|
||||||
|
* @param[in] server_key: string of server private key
|
||||||
|
* @param[in] ca_certs: string including certificates in CA trusted chain
|
||||||
|
* @return 0 : if successful
|
||||||
|
* @return -1 : if error occurred
|
||||||
|
* @note Must be used before httpd_start() if staring HTTPS server
|
||||||
|
*/
|
||||||
|
int httpd_setup_cert(const char *server_cert, const char *server_key, const char *ca_certs);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function is used to setup authorization for server.
|
||||||
|
* @param[in] user: string of user name for authorization
|
||||||
|
* @param[in] password: string of password for authorization
|
||||||
|
* @return 0 : if successful
|
||||||
|
* @return -1 : if error occurred
|
||||||
|
* @note Must be used before httpd_start() if basic authorization is used
|
||||||
|
*/
|
||||||
|
int httpd_setup_user_password(char *user, char *password);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function is used to free memory allocated by httpd API, such as httpd_request_get_header_field() and httpd_request_get_query_key().
|
||||||
|
* @param[in] ptr: pointer to memory to be deallocated
|
||||||
|
* @return None
|
||||||
|
*/
|
||||||
|
void httpd_free(void *ptr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function is used to close a client connection and release context resource.
|
||||||
|
* @param[in] conn: pointer to connection context
|
||||||
|
* @return None
|
||||||
|
* @note Multiple requests/response can be handled in a connection before connection closed. All connections will be closed automatically if httpd_stop().
|
||||||
|
*/
|
||||||
|
void httpd_conn_close(struct httpd_conn *conn);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function is used to dump the parsed HTTP header of request in connection context.
|
||||||
|
* @param[in] conn: pointer to connection context
|
||||||
|
* @return None
|
||||||
|
*/
|
||||||
|
void httpd_conn_dump_header(struct httpd_conn *conn);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function is used to check HTTP method of request in connection context.
|
||||||
|
* @param[in] conn: pointer to connection context
|
||||||
|
* @param[in] method: HTTP method string to compare with
|
||||||
|
* @return 0 : if different
|
||||||
|
* @return 1 : if matched
|
||||||
|
*/
|
||||||
|
int httpd_request_is_method(struct httpd_conn *conn, char *method);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function is used to read HTTP header from client socket descriptor and parse content to connection context.
|
||||||
|
* @param[in] conn: pointer to connection context
|
||||||
|
* @return 0 : if successful
|
||||||
|
* @return -1 : if error occurred
|
||||||
|
* @note httpd_request_read_header() is automatically invoked by httpd server to parse request before executing page callback
|
||||||
|
*/
|
||||||
|
int httpd_request_read_header(struct httpd_conn *conn);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function is used to read data from HTTP/HTTPS connection.
|
||||||
|
* @param[in] conn: pointer to connection context
|
||||||
|
* @param[out] data: buffer for data read
|
||||||
|
* @param[in] data_len: buffer length
|
||||||
|
* @return return value of lwip socket read() for HTTP and PolarSSL ssl_read() for HTTPS
|
||||||
|
*/
|
||||||
|
int httpd_request_read_data(struct httpd_conn *conn, uint8_t *data, size_t data_len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function is used to get a header field from HTTP header of connection context.
|
||||||
|
* @param[in] conn: pointer to connection context
|
||||||
|
* @param[in] field: header field string to search
|
||||||
|
* @param[out] value: search result stored in memory allocated
|
||||||
|
* @return 0 : if found
|
||||||
|
* @return -1 : if not found
|
||||||
|
* @note The search result memory should be free by httpd_free().
|
||||||
|
*/
|
||||||
|
int httpd_request_get_header_field(struct httpd_conn *conn, char *field, char **value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function is used to get a key value from query string in HTTP header of connection context.
|
||||||
|
* @param[in] conn: pointer to connection context
|
||||||
|
* @param[in] key: key name string to search
|
||||||
|
* @param[out] value: search result stored in memory allocated
|
||||||
|
* @return 0 : if found
|
||||||
|
* @return -1 : if not found
|
||||||
|
* @note The search result memory should be free by httpd_free().
|
||||||
|
*/
|
||||||
|
int httpd_request_get_query_key(struct httpd_conn *conn, char *key, char **value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function is used to start a HTTP response in connection.
|
||||||
|
* @param[in] conn: pointer to connection context
|
||||||
|
* @param[in] status: string of status code in HTTP response
|
||||||
|
* @param[in] content_type: string of Content-Type header field written to HTTP response. No Content-Type in HTTP response if NULL.
|
||||||
|
* @param[in] content_len: value of Content-Length header field written to HTTP response. No Content-Length in HTTP response if NULL.
|
||||||
|
* @return 0 : if successful
|
||||||
|
* @return -1 : if error occurred
|
||||||
|
*/
|
||||||
|
int httpd_response_write_header_start(struct httpd_conn *conn, char *status, char *content_type, size_t content_len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function is used to add an HTTP header field to HTTP response.
|
||||||
|
* @param[in] conn: pointer to connection context
|
||||||
|
* @param[in] name: HTTP header field name string
|
||||||
|
* @param[in] value: HTTP header field value
|
||||||
|
* @return 0 : if successful
|
||||||
|
* @return -1 : if error occurred
|
||||||
|
*/
|
||||||
|
int httpd_response_write_header(struct httpd_conn *conn, char *name, char *value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function is used to write HTTP response header data to connection.
|
||||||
|
* @param[in] conn: pointer to connection context
|
||||||
|
* @return return value of lwip socket write() for HTTP and PolarSSL ssl_write() for HTTPS
|
||||||
|
*/
|
||||||
|
int httpd_response_write_header_finish(struct httpd_conn *conn);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function is used to write HTTP response body data to connection.
|
||||||
|
* @param[in] conn: pointer to connection context
|
||||||
|
* @param[in] data: data to be written
|
||||||
|
* @param[in] data_len: data length
|
||||||
|
* @return return value of lwip socket write() for HTTP and PolarSSL ssl_write() for HTTPS
|
||||||
|
*/
|
||||||
|
int httpd_response_write_data(struct httpd_conn *conn, uint8_t *data, size_t data_len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function is used to write a default HTTP response for error of 400 Bad Request.
|
||||||
|
* @param[in] conn: pointer to connection context
|
||||||
|
* @param[in] msg: message write to HTTP response body. A default message will be used if NULL.
|
||||||
|
* @return None
|
||||||
|
*/
|
||||||
|
void httpd_response_bad_request(struct httpd_conn *conn, char *msg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function is used to write a default HTTP response for error of 401 Unauthorized.
|
||||||
|
* @param[in] conn: pointer to connection context
|
||||||
|
* @param[in] msg: message write to HTTP response body. A default message will be used if NULL.
|
||||||
|
* @return None
|
||||||
|
*/
|
||||||
|
void httpd_response_unauthorized(struct httpd_conn *conn, char *msg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function is used to write a default HTTP response for error of 404 Not Found.
|
||||||
|
* @param[in] conn: pointer to connection context
|
||||||
|
* @param[in] msg: message write to HTTP response body. A default message will be used if NULL.
|
||||||
|
* @return None
|
||||||
|
*/
|
||||||
|
void httpd_response_not_found(struct httpd_conn *conn, char *msg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function is used to write a default HTTP response for error of 405 Method Not Allowed.
|
||||||
|
* @param[in] conn: pointer to connection context
|
||||||
|
* @param[in] msg: message write to HTTP response body. A default message will be used if NULL.
|
||||||
|
* @return None
|
||||||
|
*/
|
||||||
|
void httpd_response_method_not_allowed(struct httpd_conn *conn, char *msg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function is used to write a default HTTP response for error of 429 Too Many Requests.
|
||||||
|
* @param[in] conn: pointer to connection context
|
||||||
|
* @param[in] msg: message write to HTTP response body. A default message will be used if NULL.
|
||||||
|
* @return None
|
||||||
|
*/
|
||||||
|
void httpd_response_too_many_requests(struct httpd_conn *conn, char *msg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function is used to write a default HTTP response for error of 500 Internal Server Error.
|
||||||
|
* @param[in] conn: pointer to connection context
|
||||||
|
* @param[in] msg: message write to HTTP response body. A default message will be used if NULL.
|
||||||
|
* @return None
|
||||||
|
*/
|
||||||
|
void httpd_response_internal_server_error(struct httpd_conn *conn, char *msg);
|
||||||
|
|
||||||
|
/*\@}*/
|
||||||
|
|
||||||
|
#endif /* _HTTPD_H_ */
|
372
USDK/component/common/network/httpd/httpd_tls.c
Normal file
372
USDK/component/common/network/httpd/httpd_tls.c
Normal file
|
@ -0,0 +1,372 @@
|
||||||
|
#include "FreeRTOS.h"
|
||||||
|
#include "task.h"
|
||||||
|
#include "platform_stdlib.h"
|
||||||
|
|
||||||
|
#include "httpd.h"
|
||||||
|
|
||||||
|
#if (HTTPD_USE_TLS == HTTPD_TLS_POLARSSL)
|
||||||
|
#include "polarssl/ssl.h"
|
||||||
|
#include "polarssl/memory.h"
|
||||||
|
#include "polarssl/base64.h"
|
||||||
|
|
||||||
|
struct httpd_tls {
|
||||||
|
ssl_context ctx; /*!< Context for PolarSSL */
|
||||||
|
};
|
||||||
|
|
||||||
|
static x509_crt httpd_certs; /*!< Certificates of server and CA */
|
||||||
|
static pk_context httpd_key; /*!< Private key of server */
|
||||||
|
|
||||||
|
static int _verify_func(void *data, x509_crt *crt, int depth, int *flags)
|
||||||
|
{
|
||||||
|
char buf[1024];
|
||||||
|
x509_crt_info(buf, sizeof(buf) - 1, "", crt);
|
||||||
|
|
||||||
|
if(*flags)
|
||||||
|
printf("\n[HTTPD] ERROR: certificate verify\n%s\n", buf);
|
||||||
|
else
|
||||||
|
printf("\n[HTTPD] Certificate verified\n%s\n", buf);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif (HTTPD_USE_TLS == HTTPD_TLS_MBEDTLS)
|
||||||
|
#include "mbedtls/ssl.h"
|
||||||
|
#include "mbedtls/platform.h"
|
||||||
|
#include "mbedtls/net_sockets.h"
|
||||||
|
#include "mbedtls/base64.h"
|
||||||
|
|
||||||
|
struct httpd_tls {
|
||||||
|
mbedtls_ssl_context ctx; /*!< Context for mbedTLS */
|
||||||
|
mbedtls_ssl_config conf; /*!< Configuration for mbedTLS */
|
||||||
|
};
|
||||||
|
|
||||||
|
static mbedtls_x509_crt httpd_certs; /*!< Certificates of server and CA */
|
||||||
|
static mbedtls_pk_context httpd_key; /*!< Private key of server */
|
||||||
|
|
||||||
|
static int _verify_func(void *data, mbedtls_x509_crt *crt, int depth, uint32_t *flags)
|
||||||
|
{
|
||||||
|
char buf[1024];
|
||||||
|
mbedtls_x509_crt_info(buf, sizeof(buf) - 1, "", crt);
|
||||||
|
|
||||||
|
if(*flags)
|
||||||
|
printf("\n[HTTPD] ERROR: certificate verify\n%s\n", buf);
|
||||||
|
else
|
||||||
|
printf("\n[HTTPD] Certificate verified\n%s\n", buf);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void* _calloc_func(size_t nmemb, size_t size)
|
||||||
|
{
|
||||||
|
size_t mem_size;
|
||||||
|
void *ptr = NULL;
|
||||||
|
|
||||||
|
mem_size = nmemb * size;
|
||||||
|
ptr = pvPortMalloc(mem_size);
|
||||||
|
|
||||||
|
if(ptr)
|
||||||
|
memset(ptr, 0, mem_size);
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
#endif /* HTTPC_USE_POLARSSL */
|
||||||
|
|
||||||
|
static int _random_func(void *p_rng, unsigned char *output, size_t output_len)
|
||||||
|
{
|
||||||
|
rtw_get_random_bytes(output, output_len);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int httpd_tls_setup_init(const char *server_cert, const char *server_key, const char *ca_certs)
|
||||||
|
{
|
||||||
|
#if (HTTPD_USE_TLS == HTTPD_TLS_POLARSSL)
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
memory_set_own(pvPortMalloc, vPortFree);
|
||||||
|
memset(&httpd_certs, 0, sizeof(x509_crt));
|
||||||
|
memset(&httpd_key, 0, sizeof(pk_context));
|
||||||
|
x509_crt_init(&httpd_certs);
|
||||||
|
pk_init(&httpd_key);
|
||||||
|
|
||||||
|
// set server certificate for the first certificate
|
||||||
|
if((ret = x509_crt_parse(&httpd_certs, (const unsigned char *) server_cert, strlen(server_cert))) != 0) {
|
||||||
|
printf("\n[HTTPD] ERROR: x509_crt_parse %d\n", ret);
|
||||||
|
ret = -1;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set trusted ca certificates next to server certificate
|
||||||
|
if((ret = x509_crt_parse(&httpd_certs, (const unsigned char *) ca_certs, strlen(ca_certs))) != 0) {
|
||||||
|
printf("\n[HTTPD] ERROR: x509_crt_parse %d\n", ret);
|
||||||
|
ret = -1;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((ret = pk_parse_key(&httpd_key, (const unsigned char *) server_key, strlen(server_key), NULL, 0)) != 0) {
|
||||||
|
printf("\n[HTTPD] ERROR: pk_parse_key %d\n", ret);
|
||||||
|
ret = -1;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
|
if(ret) {
|
||||||
|
x509_crt_free(&httpd_certs);
|
||||||
|
pk_free(&httpd_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
#elif (HTTPD_USE_TLS == HTTPD_TLS_MBEDTLS)
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
mbedtls_platform_set_calloc_free(_calloc_func, vPortFree);
|
||||||
|
memset(&httpd_certs, 0, sizeof(mbedtls_x509_crt));
|
||||||
|
memset(&httpd_key, 0, sizeof(mbedtls_pk_context));
|
||||||
|
mbedtls_x509_crt_init(&httpd_certs);
|
||||||
|
mbedtls_pk_init(&httpd_key);
|
||||||
|
|
||||||
|
// set server certificate for the first certificate
|
||||||
|
if((ret = mbedtls_x509_crt_parse(&httpd_certs, (const unsigned char *) server_cert, strlen(server_cert) + 1)) != 0) {
|
||||||
|
printf("\n[HTTPD] ERROR: mbedtls_x509_crt_parse %d\n", ret);
|
||||||
|
ret = -1;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set trusted ca certificates next to server certificate
|
||||||
|
if((ret = mbedtls_x509_crt_parse(&httpd_certs, (const unsigned char *) ca_certs, strlen(ca_certs) + 1)) != 0) {
|
||||||
|
printf("\n[HTTPD] ERROR: mbedtls_x509_crt_parse %d\n", ret);
|
||||||
|
ret = -1;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((ret = mbedtls_pk_parse_key(&httpd_key, (const unsigned char *) server_key, strlen(server_key) + 1, NULL, 0)) != 0) {
|
||||||
|
printf("\n[HTTPD] ERROR: mbedtls_pk_parse_key %d\n", ret);
|
||||||
|
ret = -1;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
|
if(ret) {
|
||||||
|
mbedtls_x509_crt_free(&httpd_certs);
|
||||||
|
mbedtls_pk_free(&httpd_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void httpd_tls_setup_free(void)
|
||||||
|
{
|
||||||
|
#if (HTTPD_USE_TLS == HTTPD_TLS_POLARSSL)
|
||||||
|
x509_crt_free(&httpd_certs);
|
||||||
|
pk_free(&httpd_key);
|
||||||
|
#elif (HTTPD_USE_TLS == HTTPD_TLS_MBEDTLS)
|
||||||
|
mbedtls_x509_crt_free(&httpd_certs);
|
||||||
|
mbedtls_pk_free(&httpd_key);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void *httpd_tls_new_handshake(int *sock, uint8_t secure)
|
||||||
|
{
|
||||||
|
#if (HTTPD_USE_TLS == HTTPD_TLS_POLARSSL)
|
||||||
|
int ret = 0;
|
||||||
|
struct httpd_tls *tls = NULL;
|
||||||
|
ssl_context *ssl = NULL;
|
||||||
|
|
||||||
|
if((tls = (struct httpd_tls *) malloc(sizeof(struct httpd_tls))) != NULL) {
|
||||||
|
memset(tls, 0, sizeof(struct httpd_tls));
|
||||||
|
ssl = &tls->ctx;
|
||||||
|
|
||||||
|
if((ret = ssl_init(ssl)) != 0) {
|
||||||
|
printf("\n[HTTPD] ERROR: ssl_init %d\n", ret);
|
||||||
|
ret = -1;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssl_set_endpoint(ssl, SSL_IS_SERVER);
|
||||||
|
ssl_set_authmode(ssl, SSL_VERIFY_NONE);
|
||||||
|
ssl_set_rng(ssl, _random_func, NULL);
|
||||||
|
ssl_set_bio(ssl, net_recv, sock, net_send, sock);
|
||||||
|
ssl_set_ca_chain(ssl, httpd_certs.next, NULL, NULL);
|
||||||
|
|
||||||
|
if(secure == HTTPD_SECURE_TLS_VERIFY) {
|
||||||
|
ssl_set_authmode(ssl, SSL_VERIFY_REQUIRED);
|
||||||
|
ssl_set_verify(ssl, _verify_func, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if((ret = ssl_set_own_cert(ssl, &httpd_certs, &httpd_key)) != 0) {
|
||||||
|
printf("\n[HTTPD] ERROR: ssl_set_own_cert %d\n", ret);
|
||||||
|
ret = -1;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((ret = ssl_handshake(ssl)) != 0) {
|
||||||
|
printf("\n[HTTPD] ERROR: ssl_handshake %d\n", ret);
|
||||||
|
ret = -1;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printf("\n[HTTPD] Use ciphersuite %s\n", ssl_get_ciphersuite(ssl));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printf("\n[HTTPD] ERROR: httpd_malloc\n");
|
||||||
|
ret = -1;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
|
if(ret && tls) {
|
||||||
|
ssl_close_notify(ssl);
|
||||||
|
ssl_free(ssl);
|
||||||
|
free(tls);
|
||||||
|
tls = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (void *) tls;
|
||||||
|
#elif (HTTPD_USE_TLS == HTTPD_TLS_MBEDTLS)
|
||||||
|
int ret = 0;
|
||||||
|
struct httpd_tls *tls = NULL;
|
||||||
|
mbedtls_ssl_context *ssl;
|
||||||
|
mbedtls_ssl_config *conf;
|
||||||
|
|
||||||
|
if((tls = (struct httpd_tls *) malloc(sizeof(struct httpd_tls))) != NULL) {
|
||||||
|
memset(tls, 0, sizeof(struct httpd_tls));
|
||||||
|
ssl = &tls->ctx;
|
||||||
|
conf = &tls->conf;
|
||||||
|
|
||||||
|
mbedtls_ssl_init(ssl);
|
||||||
|
mbedtls_ssl_config_init(conf);
|
||||||
|
|
||||||
|
if((ret = mbedtls_ssl_config_defaults(conf,
|
||||||
|
MBEDTLS_SSL_IS_SERVER,
|
||||||
|
MBEDTLS_SSL_TRANSPORT_STREAM,
|
||||||
|
MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
|
||||||
|
|
||||||
|
printf("\n[HTTPD] ERROR: mbedtls_ssl_config_defaults %d\n", ret);
|
||||||
|
ret = -1;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
mbedtls_ssl_conf_authmode(conf, MBEDTLS_SSL_VERIFY_NONE);
|
||||||
|
mbedtls_ssl_conf_rng(conf, _random_func, NULL);
|
||||||
|
mbedtls_ssl_conf_ca_chain(conf, httpd_certs.next, NULL);
|
||||||
|
|
||||||
|
if(secure == HTTPD_SECURE_TLS_VERIFY) {
|
||||||
|
mbedtls_ssl_conf_authmode(conf, MBEDTLS_SSL_VERIFY_REQUIRED);
|
||||||
|
mbedtls_ssl_conf_verify(conf, _verify_func, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if((ret = mbedtls_ssl_conf_own_cert(conf, &httpd_certs, &httpd_key)) != 0) {
|
||||||
|
printf("\n[HTTPD] ERROR: mbedtls_ssl_conf_own_cert %d\n", ret);
|
||||||
|
ret = -1;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((ret = mbedtls_ssl_setup(ssl, conf)) != 0) {
|
||||||
|
printf("\n[HTTPD] ERROR: mbedtls_ssl_setup %d\n", ret);
|
||||||
|
ret = -1;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
mbedtls_ssl_set_bio(ssl, sock, mbedtls_net_send, mbedtls_net_recv, NULL);
|
||||||
|
|
||||||
|
if((ret = mbedtls_ssl_handshake(ssl)) != 0) {
|
||||||
|
printf("\n[HTTPD] ERROR: mbedtls_ssl_handshake %d\n", ret);
|
||||||
|
ret = -1;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printf("\n[HTTPD] Use ciphersuite %s\n", mbedtls_ssl_get_ciphersuite(ssl));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printf("\n[HTTPD] ERROR: httpd_malloc\n");
|
||||||
|
ret = -1;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
|
if(ret && tls) {
|
||||||
|
mbedtls_ssl_close_notify(ssl);
|
||||||
|
mbedtls_ssl_free(ssl);
|
||||||
|
mbedtls_ssl_config_free(conf);
|
||||||
|
free(tls);
|
||||||
|
tls = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (void *) tls;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void httpd_tls_free(void *tls_in)
|
||||||
|
{
|
||||||
|
struct httpd_tls *tls = (struct httpd_tls *) tls_in;
|
||||||
|
|
||||||
|
#if (HTTPD_USE_TLS == HTTPD_TLS_POLARSSL)
|
||||||
|
ssl_free(&tls->ctx);
|
||||||
|
free(tls);
|
||||||
|
#elif (HTTPD_USE_TLS == HTTPD_TLS_MBEDTLS)
|
||||||
|
mbedtls_ssl_free(&tls->ctx);
|
||||||
|
mbedtls_ssl_config_free(&tls->conf);
|
||||||
|
free(tls);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void httpd_tls_close(void *tls_in)
|
||||||
|
{
|
||||||
|
struct httpd_tls *tls = (struct httpd_tls *) tls_in;
|
||||||
|
|
||||||
|
#if (HTTPD_USE_TLS == HTTPD_TLS_POLARSSL)
|
||||||
|
ssl_close_notify(&tls->ctx);
|
||||||
|
#elif (HTTPD_USE_TLS == HTTPD_TLS_MBEDTLS)
|
||||||
|
mbedtls_ssl_close_notify(&tls->ctx);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int httpd_tls_read(void *tls_in, uint8_t *buf, size_t buf_len)
|
||||||
|
{
|
||||||
|
struct httpd_tls *tls = (struct httpd_tls *) tls_in;
|
||||||
|
|
||||||
|
#if (HTTPD_USE_TLS == HTTPD_TLS_POLARSSL)
|
||||||
|
return ssl_read(&tls->ctx, buf, buf_len);
|
||||||
|
#elif (HTTPD_USE_TLS == HTTPD_TLS_MBEDTLS)
|
||||||
|
return mbedtls_ssl_read(&tls->ctx, buf, buf_len);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int httpd_tls_write(void *tls_in, uint8_t *buf, size_t buf_len)
|
||||||
|
{
|
||||||
|
struct httpd_tls *tls = (struct httpd_tls *) tls_in;
|
||||||
|
|
||||||
|
#if (HTTPD_USE_TLS == HTTPD_TLS_POLARSSL)
|
||||||
|
return ssl_write(&tls->ctx, buf, buf_len);
|
||||||
|
#elif (HTTPD_USE_TLS == HTTPD_TLS_MBEDTLS)
|
||||||
|
return mbedtls_ssl_write(&tls->ctx, buf, buf_len);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int httpd_base64_encode(uint8_t *data, size_t data_len, char *base64_buf, size_t buf_len)
|
||||||
|
{
|
||||||
|
#if (HTTPD_USE_TLS == HTTPD_TLS_POLARSSL)
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if((ret = base64_encode(base64_buf, &buf_len, data, data_len)) != 0) {
|
||||||
|
printf("\n[HTTPD] ERROR: base64_encode %d\n", ret);
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
#elif (HTTPD_USE_TLS == HTTPD_TLS_MBEDTLS)
|
||||||
|
int ret = 0;
|
||||||
|
size_t output_len = 0;
|
||||||
|
|
||||||
|
if((ret = mbedtls_base64_encode(base64_buf, buf_len, &output_len, data, data_len)) != 0) {
|
||||||
|
printf("\n[HTTPD] ERROR: mbedtls_base64_encode %d\n", ret);
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
#endif
|
||||||
|
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,33 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2001, 2002 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
src/ - The source code for the lwIP TCP/IP stack.
|
|
||||||
doc/ - The documentation for lwIP.
|
|
||||||
|
|
||||||
See also the FILES file in each subdirectory.
|
|
|
@ -1,89 +0,0 @@
|
||||||
INTRODUCTION
|
|
||||||
|
|
||||||
lwIP is a small independent implementation of the TCP/IP protocol
|
|
||||||
suite that has been developed by Adam Dunkels at the Computer and
|
|
||||||
Networks Architectures (CNA) lab at the Swedish Institute of Computer
|
|
||||||
Science (SICS).
|
|
||||||
|
|
||||||
The focus of the lwIP TCP/IP implementation is to reduce the RAM usage
|
|
||||||
while still having a full scale TCP. This making lwIP suitable for use
|
|
||||||
in embedded systems with tens of kilobytes of free RAM and room for
|
|
||||||
around 40 kilobytes of code ROM.
|
|
||||||
|
|
||||||
FEATURES
|
|
||||||
|
|
||||||
* IP (Internet Protocol) including packet forwarding over multiple network
|
|
||||||
interfaces
|
|
||||||
* ICMP (Internet Control Message Protocol) for network maintenance and debugging
|
|
||||||
* IGMP (Internet Group Management Protocol) for multicast traffic management
|
|
||||||
* UDP (User Datagram Protocol) including experimental UDP-lite extensions
|
|
||||||
* TCP (Transmission Control Protocol) with congestion control, RTT estimation
|
|
||||||
and fast recovery/fast retransmit
|
|
||||||
* Specialized raw/native API for enhanced performance
|
|
||||||
* Optional Berkeley-like socket API
|
|
||||||
* DNS (Domain names resolver)
|
|
||||||
* SNMP (Simple Network Management Protocol)
|
|
||||||
* DHCP (Dynamic Host Configuration Protocol)
|
|
||||||
* AUTOIP (for IPv4, conform with RFC 3927)
|
|
||||||
* PPP (Point-to-Point Protocol)
|
|
||||||
* ARP (Address Resolution Protocol) for Ethernet
|
|
||||||
|
|
||||||
LICENSE
|
|
||||||
|
|
||||||
lwIP is freely available under a BSD license.
|
|
||||||
|
|
||||||
DEVELOPMENT
|
|
||||||
|
|
||||||
lwIP has grown into an excellent TCP/IP stack for embedded devices,
|
|
||||||
and developers using the stack often submit bug fixes, improvements,
|
|
||||||
and additions to the stack to further increase its usefulness.
|
|
||||||
|
|
||||||
Development of lwIP is hosted on Savannah, a central point for
|
|
||||||
software development, maintenance and distribution. Everyone can
|
|
||||||
help improve lwIP by use of Savannah's interface, CVS and the
|
|
||||||
mailing list. A core team of developers will commit changes to the
|
|
||||||
CVS source tree.
|
|
||||||
|
|
||||||
The lwIP TCP/IP stack is maintained in the 'lwip' CVS module and
|
|
||||||
contributions (such as platform ports) are in the 'contrib' module.
|
|
||||||
|
|
||||||
See doc/savannah.txt for details on CVS server access for users and
|
|
||||||
developers.
|
|
||||||
|
|
||||||
Last night's CVS tar ball can be downloaded from:
|
|
||||||
http://savannah.gnu.org/cvs.backups/lwip.tar.gz [CHANGED - NEEDS FIXING]
|
|
||||||
|
|
||||||
The current CVS trees are web-browsable:
|
|
||||||
http://savannah.nongnu.org/cgi-bin/viewcvs/lwip/lwip/
|
|
||||||
http://savannah.nongnu.org/cgi-bin/viewcvs/lwip/contrib/
|
|
||||||
|
|
||||||
Submit patches and bugs via the lwIP project page:
|
|
||||||
http://savannah.nongnu.org/projects/lwip/
|
|
||||||
|
|
||||||
|
|
||||||
DOCUMENTATION
|
|
||||||
|
|
||||||
The original out-dated homepage of lwIP and Adam Dunkels' papers on
|
|
||||||
lwIP are at the official lwIP home page:
|
|
||||||
http://www.sics.se/~adam/lwip/
|
|
||||||
|
|
||||||
Self documentation of the source code is regularly extracted from the
|
|
||||||
current CVS sources and is available from this web page:
|
|
||||||
http://www.nongnu.org/lwip/
|
|
||||||
|
|
||||||
There is now a constantly growin wiki about lwIP at
|
|
||||||
http://lwip.wikia.com/wiki/LwIP_Wiki
|
|
||||||
|
|
||||||
Also, there are mailing lists you can subscribe at
|
|
||||||
http://savannah.nongnu.org/mail/?group=lwip
|
|
||||||
plus searchable archives:
|
|
||||||
http://lists.nongnu.org/archive/html/lwip-users/
|
|
||||||
http://lists.nongnu.org/archive/html/lwip-devel/
|
|
||||||
|
|
||||||
Reading Adam's papers, the files in docs/, browsing the source code
|
|
||||||
documentation and browsing the mailing list archives is a good way to
|
|
||||||
become familiar with the design of lwIP.
|
|
||||||
|
|
||||||
Adam Dunkels <adam@sics.se>
|
|
||||||
Leon Woestenberg <leon.woestenberg@gmx.net>
|
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
savannah.txt - How to obtain the current development source code.
|
|
||||||
contrib.txt - How to contribute to lwIP as a developer.
|
|
||||||
rawapi.txt - The documentation for the core API of lwIP.
|
|
||||||
Also provides an overview about the other APIs and multithreading.
|
|
||||||
snmp_agent.txt - The documentation for the lwIP SNMP agent.
|
|
||||||
sys_arch.txt - The documentation for a system abstraction layer of lwIP.
|
|
|
@ -1,63 +0,0 @@
|
||||||
1 Introduction
|
|
||||||
|
|
||||||
This document describes some guidelines for people participating
|
|
||||||
in lwIP development.
|
|
||||||
|
|
||||||
2 How to contribute to lwIP
|
|
||||||
|
|
||||||
Here is a short list of suggestions to anybody working with lwIP and
|
|
||||||
trying to contribute bug reports, fixes, enhancements, platform ports etc.
|
|
||||||
First of all as you may already know lwIP is a volunteer project so feedback
|
|
||||||
to fixes or questions might often come late. Hopefully the bug and patch tracking
|
|
||||||
features of Savannah help us not lose users' input.
|
|
||||||
|
|
||||||
2.1 Source code style:
|
|
||||||
|
|
||||||
1. do not use tabs.
|
|
||||||
2. indentation is two spaces per level (i.e. per tab).
|
|
||||||
3. end debug messages with a trailing newline (\n).
|
|
||||||
4. one space between keyword and opening bracket.
|
|
||||||
5. no space between function and opening bracket.
|
|
||||||
6. one space and no newline before opening curly braces of a block.
|
|
||||||
7. closing curly brace on a single line.
|
|
||||||
8. spaces surrounding assignment and comparisons.
|
|
||||||
9. don't initialize static and/or global variables to zero, the compiler takes care of that.
|
|
||||||
10. use current source code style as further reference.
|
|
||||||
|
|
||||||
2.2 Source code documentation style:
|
|
||||||
|
|
||||||
1. JavaDoc compliant and Doxygen compatible.
|
|
||||||
2. Function documentation above functions in .c files, not .h files.
|
|
||||||
(This forces you to synchronize documentation and implementation.)
|
|
||||||
3. Use current documentation style as further reference.
|
|
||||||
|
|
||||||
2.3 Bug reports and patches:
|
|
||||||
|
|
||||||
1. Make sure you are reporting bugs or send patches against the latest
|
|
||||||
sources. (From the latest release and/or the current CVS sources.)
|
|
||||||
2. If you think you found a bug make sure it's not already filed in the
|
|
||||||
bugtracker at Savannah.
|
|
||||||
3. If you have a fix put the patch on Savannah. If it is a patch that affects
|
|
||||||
both core and arch specific stuff please separate them so that the core can
|
|
||||||
be applied separately while leaving the other patch 'open'. The prefered way
|
|
||||||
is to NOT touch archs you can't test and let maintainers take care of them.
|
|
||||||
This is a good way to see if they are used at all - the same goes for unix
|
|
||||||
netifs except tapif.
|
|
||||||
4. Do not file a bug and post a fix to it to the patch area. Either a bug report
|
|
||||||
or a patch will be enough.
|
|
||||||
If you correct an existing bug then attach the patch to the bug rather than creating a new entry in the patch area.
|
|
||||||
5. Trivial patches (compiler warning, indentation and spelling fixes or anything obvious which takes a line or two)
|
|
||||||
can go to the lwip-users list. This is still the fastest way of interaction and the list is not so crowded
|
|
||||||
as to allow for loss of fixes. Putting bugs on Savannah and subsequently closing them is too much an overhead
|
|
||||||
for reporting a compiler warning fix.
|
|
||||||
6. Patches should be specific to a single change or to related changes.Do not mix bugfixes with spelling and other
|
|
||||||
trivial fixes unless the bugfix is trivial too.Do not reorganize code and rename identifiers in the same patch you
|
|
||||||
change behaviour if not necessary.A patch is easier to read and understand if it's to the point and short than
|
|
||||||
if it's not to the point and long :) so the chances for it to be applied are greater.
|
|
||||||
|
|
||||||
2.4 Platform porters:
|
|
||||||
|
|
||||||
1. If you have ported lwIP to a platform (an OS, a uC/processor or a combination of these) and
|
|
||||||
you think it could benefit others[1] you might want discuss this on the mailing list. You
|
|
||||||
can also ask for CVS access to submit and maintain your port in the contrib CVS module.
|
|
||||||
|
|
|
@ -1,478 +0,0 @@
|
||||||
Raw TCP/IP interface for lwIP
|
|
||||||
|
|
||||||
Authors: Adam Dunkels, Leon Woestenberg, Christiaan Simons
|
|
||||||
|
|
||||||
lwIP provides three Application Program's Interfaces (APIs) for programs
|
|
||||||
to use for communication with the TCP/IP code:
|
|
||||||
* low-level "core" / "callback" or "raw" API.
|
|
||||||
* higher-level "sequential" API.
|
|
||||||
* BSD-style socket API.
|
|
||||||
|
|
||||||
The sequential API provides a way for ordinary, sequential, programs
|
|
||||||
to use the lwIP stack. It is quite similar to the BSD socket API. The
|
|
||||||
model of execution is based on the blocking open-read-write-close
|
|
||||||
paradigm. Since the TCP/IP stack is event based by nature, the TCP/IP
|
|
||||||
code and the application program must reside in different execution
|
|
||||||
contexts (threads).
|
|
||||||
|
|
||||||
The socket API is a compatibility API for existing applications,
|
|
||||||
currently it is built on top of the sequential API. It is meant to
|
|
||||||
provide all functions needed to run socket API applications running
|
|
||||||
on other platforms (e.g. unix / windows etc.). However, due to limitations
|
|
||||||
in the specification of this API, there might be incompatibilities
|
|
||||||
that require small modifications of existing programs.
|
|
||||||
|
|
||||||
** Threading
|
|
||||||
|
|
||||||
lwIP started targeting single-threaded environments. When adding multi-
|
|
||||||
threading support, instead of making the core thread-safe, another
|
|
||||||
approach was chosen: there is one main thread running the lwIP core
|
|
||||||
(also known as the "tcpip_thread"). The raw API may only be used from
|
|
||||||
this thread! Application threads using the sequential- or socket API
|
|
||||||
communicate with this main thread through message passing.
|
|
||||||
|
|
||||||
As such, the list of functions that may be called from
|
|
||||||
other threads or an ISR is very limited! Only functions
|
|
||||||
from these API header files are thread-safe:
|
|
||||||
- api.h
|
|
||||||
- netbuf.h
|
|
||||||
- netdb.h
|
|
||||||
- netifapi.h
|
|
||||||
- sockets.h
|
|
||||||
- sys.h
|
|
||||||
|
|
||||||
Additionaly, memory (de-)allocation functions may be
|
|
||||||
called from multiple threads (not ISR!) with NO_SYS=0
|
|
||||||
since they are protected by SYS_LIGHTWEIGHT_PROT and/or
|
|
||||||
semaphores.
|
|
||||||
|
|
||||||
Only since 1.3.0, if SYS_LIGHTWEIGHT_PROT is set to 1
|
|
||||||
and LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT is set to 1,
|
|
||||||
pbuf_free() may also be called from another thread or
|
|
||||||
an ISR (since only then, mem_free - for PBUF_RAM - may
|
|
||||||
be called from an ISR: otherwise, the HEAP is only
|
|
||||||
protected by semaphores).
|
|
||||||
|
|
||||||
|
|
||||||
** The remainder of this document discusses the "raw" API. **
|
|
||||||
|
|
||||||
The raw TCP/IP interface allows the application program to integrate
|
|
||||||
better with the TCP/IP code. Program execution is event based by
|
|
||||||
having callback functions being called from within the TCP/IP
|
|
||||||
code. The TCP/IP code and the application program both run in the same
|
|
||||||
thread. The sequential API has a much higher overhead and is not very
|
|
||||||
well suited for small systems since it forces a multithreaded paradigm
|
|
||||||
on the application.
|
|
||||||
|
|
||||||
The raw TCP/IP interface is not only faster in terms of code execution
|
|
||||||
time but is also less memory intensive. The drawback is that program
|
|
||||||
development is somewhat harder and application programs written for
|
|
||||||
the raw TCP/IP interface are more difficult to understand. Still, this
|
|
||||||
is the preferred way of writing applications that should be small in
|
|
||||||
code size and memory usage.
|
|
||||||
|
|
||||||
Both APIs can be used simultaneously by different application
|
|
||||||
programs. In fact, the sequential API is implemented as an application
|
|
||||||
program using the raw TCP/IP interface.
|
|
||||||
|
|
||||||
--- Callbacks
|
|
||||||
|
|
||||||
Program execution is driven by callbacks. Each callback is an ordinary
|
|
||||||
C function that is called from within the TCP/IP code. Every callback
|
|
||||||
function is passed the current TCP or UDP connection state as an
|
|
||||||
argument. Also, in order to be able to keep program specific state,
|
|
||||||
the callback functions are called with a program specified argument
|
|
||||||
that is independent of the TCP/IP state.
|
|
||||||
|
|
||||||
The function for setting the application connection state is:
|
|
||||||
|
|
||||||
- void tcp_arg(struct tcp_pcb *pcb, void *arg)
|
|
||||||
|
|
||||||
Specifies the program specific state that should be passed to all
|
|
||||||
other callback functions. The "pcb" argument is the current TCP
|
|
||||||
connection control block, and the "arg" argument is the argument
|
|
||||||
that will be passed to the callbacks.
|
|
||||||
|
|
||||||
|
|
||||||
--- TCP connection setup
|
|
||||||
|
|
||||||
The functions used for setting up connections is similar to that of
|
|
||||||
the sequential API and of the BSD socket API. A new TCP connection
|
|
||||||
identifier (i.e., a protocol control block - PCB) is created with the
|
|
||||||
tcp_new() function. This PCB can then be either set to listen for new
|
|
||||||
incoming connections or be explicitly connected to another host.
|
|
||||||
|
|
||||||
- struct tcp_pcb *tcp_new(void)
|
|
||||||
|
|
||||||
Creates a new connection identifier (PCB). If memory is not
|
|
||||||
available for creating the new pcb, NULL is returned.
|
|
||||||
|
|
||||||
- err_t tcp_bind(struct tcp_pcb *pcb, struct ip_addr *ipaddr,
|
|
||||||
u16_t port)
|
|
||||||
|
|
||||||
Binds the pcb to a local IP address and port number. The IP address
|
|
||||||
can be specified as IP_ADDR_ANY in order to bind the connection to
|
|
||||||
all local IP addresses.
|
|
||||||
|
|
||||||
If another connection is bound to the same port, the function will
|
|
||||||
return ERR_USE, otherwise ERR_OK is returned.
|
|
||||||
|
|
||||||
- struct tcp_pcb *tcp_listen(struct tcp_pcb *pcb)
|
|
||||||
|
|
||||||
Commands a pcb to start listening for incoming connections. When an
|
|
||||||
incoming connection is accepted, the function specified with the
|
|
||||||
tcp_accept() function will be called. The pcb will have to be bound
|
|
||||||
to a local port with the tcp_bind() function.
|
|
||||||
|
|
||||||
The tcp_listen() function returns a new connection identifier, and
|
|
||||||
the one passed as an argument to the function will be
|
|
||||||
deallocated. The reason for this behavior is that less memory is
|
|
||||||
needed for a connection that is listening, so tcp_listen() will
|
|
||||||
reclaim the memory needed for the original connection and allocate a
|
|
||||||
new smaller memory block for the listening connection.
|
|
||||||
|
|
||||||
tcp_listen() may return NULL if no memory was available for the
|
|
||||||
listening connection. If so, the memory associated with the pcb
|
|
||||||
passed as an argument to tcp_listen() will not be deallocated.
|
|
||||||
|
|
||||||
- struct tcp_pcb *tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog)
|
|
||||||
|
|
||||||
Same as tcp_listen, but limits the number of outstanding connections
|
|
||||||
in the listen queue to the value specified by the backlog argument.
|
|
||||||
To use it, your need to set TCP_LISTEN_BACKLOG=1 in your lwipopts.h.
|
|
||||||
|
|
||||||
- void tcp_accepted(struct tcp_pcb *pcb)
|
|
||||||
|
|
||||||
Inform lwIP that an incoming connection has been accepted. This would
|
|
||||||
usually be called from the accept callback. This allows lwIP to perform
|
|
||||||
housekeeping tasks, such as allowing further incoming connections to be
|
|
||||||
queued in the listen backlog.
|
|
||||||
|
|
||||||
- void tcp_accept(struct tcp_pcb *pcb,
|
|
||||||
err_t (* accept)(void *arg, struct tcp_pcb *newpcb,
|
|
||||||
err_t err))
|
|
||||||
|
|
||||||
Specified the callback function that should be called when a new
|
|
||||||
connection arrives on a listening connection.
|
|
||||||
|
|
||||||
- err_t tcp_connect(struct tcp_pcb *pcb, struct ip_addr *ipaddr,
|
|
||||||
u16_t port, err_t (* connected)(void *arg,
|
|
||||||
struct tcp_pcb *tpcb,
|
|
||||||
err_t err));
|
|
||||||
|
|
||||||
Sets up the pcb to connect to the remote host and sends the
|
|
||||||
initial SYN segment which opens the connection.
|
|
||||||
|
|
||||||
The tcp_connect() function returns immediately; it does not wait for
|
|
||||||
the connection to be properly setup. Instead, it will call the
|
|
||||||
function specified as the fourth argument (the "connected" argument)
|
|
||||||
when the connection is established. If the connection could not be
|
|
||||||
properly established, either because the other host refused the
|
|
||||||
connection or because the other host didn't answer, the "err"
|
|
||||||
callback function of this pcb (registered with tcp_err, see below)
|
|
||||||
will be called.
|
|
||||||
|
|
||||||
The tcp_connect() function can return ERR_MEM if no memory is
|
|
||||||
available for enqueueing the SYN segment. If the SYN indeed was
|
|
||||||
enqueued successfully, the tcp_connect() function returns ERR_OK.
|
|
||||||
|
|
||||||
|
|
||||||
--- Sending TCP data
|
|
||||||
|
|
||||||
TCP data is sent by enqueueing the data with a call to
|
|
||||||
tcp_write(). When the data is successfully transmitted to the remote
|
|
||||||
host, the application will be notified with a call to a specified
|
|
||||||
callback function.
|
|
||||||
|
|
||||||
- err_t tcp_write(struct tcp_pcb *pcb, void *dataptr, u16_t len,
|
|
||||||
u8_t copy)
|
|
||||||
|
|
||||||
Enqueues the data pointed to by the argument dataptr. The length of
|
|
||||||
the data is passed as the len parameter. The copy argument is either
|
|
||||||
0 or 1 and indicates whether the new memory should be allocated for
|
|
||||||
the data to be copied into. If the argument is 0, no new memory
|
|
||||||
should be allocated and the data should only be referenced by
|
|
||||||
pointer.
|
|
||||||
|
|
||||||
The tcp_write() function will fail and return ERR_MEM if the length
|
|
||||||
of the data exceeds the current send buffer size or if the length of
|
|
||||||
the queue of outgoing segment is larger than the upper limit defined
|
|
||||||
in lwipopts.h. The number of bytes available in the output queue can
|
|
||||||
be retrieved with the tcp_sndbuf() function.
|
|
||||||
|
|
||||||
The proper way to use this function is to call the function with at
|
|
||||||
most tcp_sndbuf() bytes of data. If the function returns ERR_MEM,
|
|
||||||
the application should wait until some of the currently enqueued
|
|
||||||
data has been successfully received by the other host and try again.
|
|
||||||
|
|
||||||
- void tcp_sent(struct tcp_pcb *pcb,
|
|
||||||
err_t (* sent)(void *arg, struct tcp_pcb *tpcb,
|
|
||||||
u16_t len))
|
|
||||||
|
|
||||||
Specifies the callback function that should be called when data has
|
|
||||||
successfully been received (i.e., acknowledged) by the remote
|
|
||||||
host. The len argument passed to the callback function gives the
|
|
||||||
amount bytes that was acknowledged by the last acknowledgment.
|
|
||||||
|
|
||||||
|
|
||||||
--- Receiving TCP data
|
|
||||||
|
|
||||||
TCP data reception is callback based - an application specified
|
|
||||||
callback function is called when new data arrives. When the
|
|
||||||
application has taken the data, it has to call the tcp_recved()
|
|
||||||
function to indicate that TCP can advertise increase the receive
|
|
||||||
window.
|
|
||||||
|
|
||||||
- void tcp_recv(struct tcp_pcb *pcb,
|
|
||||||
err_t (* recv)(void *arg, struct tcp_pcb *tpcb,
|
|
||||||
struct pbuf *p, err_t err))
|
|
||||||
|
|
||||||
Sets the callback function that will be called when new data
|
|
||||||
arrives. The callback function will be passed a NULL pbuf to
|
|
||||||
indicate that the remote host has closed the connection. If
|
|
||||||
there are no errors and the callback function is to return
|
|
||||||
ERR_OK, then it must free the pbuf. Otherwise, it must not
|
|
||||||
free the pbuf so that lwIP core code can store it.
|
|
||||||
|
|
||||||
- void tcp_recved(struct tcp_pcb *pcb, u16_t len)
|
|
||||||
|
|
||||||
Must be called when the application has received the data. The len
|
|
||||||
argument indicates the length of the received data.
|
|
||||||
|
|
||||||
|
|
||||||
--- Application polling
|
|
||||||
|
|
||||||
When a connection is idle (i.e., no data is either transmitted or
|
|
||||||
received), lwIP will repeatedly poll the application by calling a
|
|
||||||
specified callback function. This can be used either as a watchdog
|
|
||||||
timer for killing connections that have stayed idle for too long, or
|
|
||||||
as a method of waiting for memory to become available. For instance,
|
|
||||||
if a call to tcp_write() has failed because memory wasn't available,
|
|
||||||
the application may use the polling functionality to call tcp_write()
|
|
||||||
again when the connection has been idle for a while.
|
|
||||||
|
|
||||||
- void tcp_poll(struct tcp_pcb *pcb, u8_t interval,
|
|
||||||
err_t (* poll)(void *arg, struct tcp_pcb *tpcb))
|
|
||||||
|
|
||||||
Specifies the polling interval and the callback function that should
|
|
||||||
be called to poll the application. The interval is specified in
|
|
||||||
number of TCP coarse grained timer shots, which typically occurs
|
|
||||||
twice a second. An interval of 10 means that the application would
|
|
||||||
be polled every 5 seconds.
|
|
||||||
|
|
||||||
|
|
||||||
--- Closing and aborting connections
|
|
||||||
|
|
||||||
- err_t tcp_close(struct tcp_pcb *pcb)
|
|
||||||
|
|
||||||
Closes the connection. The function may return ERR_MEM if no memory
|
|
||||||
was available for closing the connection. If so, the application
|
|
||||||
should wait and try again either by using the acknowledgment
|
|
||||||
callback or the polling functionality. If the close succeeds, the
|
|
||||||
function returns ERR_OK.
|
|
||||||
|
|
||||||
The pcb is deallocated by the TCP code after a call to tcp_close().
|
|
||||||
|
|
||||||
- void tcp_abort(struct tcp_pcb *pcb)
|
|
||||||
|
|
||||||
Aborts the connection by sending a RST (reset) segment to the remote
|
|
||||||
host. The pcb is deallocated. This function never fails.
|
|
||||||
|
|
||||||
If a connection is aborted because of an error, the application is
|
|
||||||
alerted of this event by the err callback. Errors that might abort a
|
|
||||||
connection are when there is a shortage of memory. The callback
|
|
||||||
function to be called is set using the tcp_err() function.
|
|
||||||
|
|
||||||
- void tcp_err(struct tcp_pcb *pcb, void (* err)(void *arg,
|
|
||||||
err_t err))
|
|
||||||
|
|
||||||
The error callback function does not get the pcb passed to it as a
|
|
||||||
parameter since the pcb may already have been deallocated.
|
|
||||||
|
|
||||||
|
|
||||||
--- Lower layer TCP interface
|
|
||||||
|
|
||||||
TCP provides a simple interface to the lower layers of the
|
|
||||||
system. During system initialization, the function tcp_init() has
|
|
||||||
to be called before any other TCP function is called. When the system
|
|
||||||
is running, the two timer functions tcp_fasttmr() and tcp_slowtmr()
|
|
||||||
must be called with regular intervals. The tcp_fasttmr() should be
|
|
||||||
called every TCP_FAST_INTERVAL milliseconds (defined in tcp.h) and
|
|
||||||
tcp_slowtmr() should be called every TCP_SLOW_INTERVAL milliseconds.
|
|
||||||
|
|
||||||
|
|
||||||
--- UDP interface
|
|
||||||
|
|
||||||
The UDP interface is similar to that of TCP, but due to the lower
|
|
||||||
level of complexity of UDP, the interface is significantly simpler.
|
|
||||||
|
|
||||||
- struct udp_pcb *udp_new(void)
|
|
||||||
|
|
||||||
Creates a new UDP pcb which can be used for UDP communication. The
|
|
||||||
pcb is not active until it has either been bound to a local address
|
|
||||||
or connected to a remote address.
|
|
||||||
|
|
||||||
- void udp_remove(struct udp_pcb *pcb)
|
|
||||||
|
|
||||||
Removes and deallocates the pcb.
|
|
||||||
|
|
||||||
- err_t udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr,
|
|
||||||
u16_t port)
|
|
||||||
|
|
||||||
Binds the pcb to a local address. The IP-address argument "ipaddr"
|
|
||||||
can be IP_ADDR_ANY to indicate that it should listen to any local IP
|
|
||||||
address. The function currently always return ERR_OK.
|
|
||||||
|
|
||||||
- err_t udp_connect(struct udp_pcb *pcb, struct ip_addr *ipaddr,
|
|
||||||
u16_t port)
|
|
||||||
|
|
||||||
Sets the remote end of the pcb. This function does not generate any
|
|
||||||
network traffic, but only set the remote address of the pcb.
|
|
||||||
|
|
||||||
- err_t udp_disconnect(struct udp_pcb *pcb)
|
|
||||||
|
|
||||||
Remove the remote end of the pcb. This function does not generate
|
|
||||||
any network traffic, but only removes the remote address of the pcb.
|
|
||||||
|
|
||||||
- err_t udp_send(struct udp_pcb *pcb, struct pbuf *p)
|
|
||||||
|
|
||||||
Sends the pbuf p. The pbuf is not deallocated.
|
|
||||||
|
|
||||||
- void udp_recv(struct udp_pcb *pcb,
|
|
||||||
void (* recv)(void *arg, struct udp_pcb *upcb,
|
|
||||||
struct pbuf *p,
|
|
||||||
struct ip_addr *addr,
|
|
||||||
u16_t port),
|
|
||||||
void *recv_arg)
|
|
||||||
|
|
||||||
Specifies a callback function that should be called when a UDP
|
|
||||||
datagram is received.
|
|
||||||
|
|
||||||
|
|
||||||
--- System initalization
|
|
||||||
|
|
||||||
A truly complete and generic sequence for initializing the lwip stack
|
|
||||||
cannot be given because it depends on the build configuration (lwipopts.h)
|
|
||||||
and additional initializations for your runtime environment (e.g. timers).
|
|
||||||
|
|
||||||
We can give you some idea on how to proceed when using the raw API.
|
|
||||||
We assume a configuration using a single Ethernet netif and the
|
|
||||||
UDP and TCP transport layers, IPv4 and the DHCP client.
|
|
||||||
|
|
||||||
Call these functions in the order of appearance:
|
|
||||||
|
|
||||||
- stats_init()
|
|
||||||
|
|
||||||
Clears the structure where runtime statistics are gathered.
|
|
||||||
|
|
||||||
- sys_init()
|
|
||||||
|
|
||||||
Not of much use since we set the NO_SYS 1 option in lwipopts.h,
|
|
||||||
to be called for easy configuration changes.
|
|
||||||
|
|
||||||
- mem_init()
|
|
||||||
|
|
||||||
Initializes the dynamic memory heap defined by MEM_SIZE.
|
|
||||||
|
|
||||||
- memp_init()
|
|
||||||
|
|
||||||
Initializes the memory pools defined by MEMP_NUM_x.
|
|
||||||
|
|
||||||
- pbuf_init()
|
|
||||||
|
|
||||||
Initializes the pbuf memory pool defined by PBUF_POOL_SIZE.
|
|
||||||
|
|
||||||
- etharp_init()
|
|
||||||
|
|
||||||
Initializes the ARP table and queue.
|
|
||||||
Note: you must call etharp_tmr at a ARP_TMR_INTERVAL (5 seconds) regular interval
|
|
||||||
after this initialization.
|
|
||||||
|
|
||||||
- ip_init()
|
|
||||||
|
|
||||||
Doesn't do much, it should be called to handle future changes.
|
|
||||||
|
|
||||||
- udp_init()
|
|
||||||
|
|
||||||
Clears the UDP PCB list.
|
|
||||||
|
|
||||||
- tcp_init()
|
|
||||||
|
|
||||||
Clears the TCP PCB list and clears some internal TCP timers.
|
|
||||||
Note: you must call tcp_fasttmr() and tcp_slowtmr() at the
|
|
||||||
predefined regular intervals after this initialization.
|
|
||||||
|
|
||||||
- netif_add(struct netif *netif, struct ip_addr *ipaddr,
|
|
||||||
struct ip_addr *netmask, struct ip_addr *gw,
|
|
||||||
void *state, err_t (* init)(struct netif *netif),
|
|
||||||
err_t (* input)(struct pbuf *p, struct netif *netif))
|
|
||||||
|
|
||||||
Adds your network interface to the netif_list. Allocate a struct
|
|
||||||
netif and pass a pointer to this structure as the first argument.
|
|
||||||
Give pointers to cleared ip_addr structures when using DHCP,
|
|
||||||
or fill them with sane numbers otherwise. The state pointer may be NULL.
|
|
||||||
|
|
||||||
The init function pointer must point to a initialization function for
|
|
||||||
your ethernet netif interface. The following code illustrates it's use.
|
|
||||||
|
|
||||||
err_t netif_if_init(struct netif *netif)
|
|
||||||
{
|
|
||||||
u8_t i;
|
|
||||||
|
|
||||||
for(i = 0; i < ETHARP_HWADDR_LEN; i++) netif->hwaddr[i] = some_eth_addr[i];
|
|
||||||
init_my_eth_device();
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
For ethernet drivers, the input function pointer must point to the lwip
|
|
||||||
function ethernet_input() declared in "netif/etharp.h". Other drivers
|
|
||||||
must use ip_input() declared in "lwip/ip.h".
|
|
||||||
|
|
||||||
- netif_set_default(struct netif *netif)
|
|
||||||
|
|
||||||
Registers the default network interface.
|
|
||||||
|
|
||||||
- netif_set_up(struct netif *netif)
|
|
||||||
|
|
||||||
When the netif is fully configured this function must be called.
|
|
||||||
|
|
||||||
- dhcp_start(struct netif *netif)
|
|
||||||
|
|
||||||
Creates a new DHCP client for this interface on the first call.
|
|
||||||
Note: you must call dhcp_fine_tmr() and dhcp_coarse_tmr() at
|
|
||||||
the predefined regular intervals after starting the client.
|
|
||||||
|
|
||||||
You can peek in the netif->dhcp struct for the actual DHCP status.
|
|
||||||
|
|
||||||
|
|
||||||
--- Optimalization hints
|
|
||||||
|
|
||||||
The first thing you want to optimize is the lwip_standard_checksum()
|
|
||||||
routine from src/core/inet.c. You can override this standard
|
|
||||||
function with the #define LWIP_CHKSUM <your_checksum_routine>.
|
|
||||||
|
|
||||||
There are C examples given in inet.c or you might want to
|
|
||||||
craft an assembly function for this. RFC1071 is a good
|
|
||||||
introduction to this subject.
|
|
||||||
|
|
||||||
Other significant improvements can be made by supplying
|
|
||||||
assembly or inline replacements for htons() and htonl()
|
|
||||||
if you're using a little-endian architecture.
|
|
||||||
#define LWIP_PLATFORM_BYTESWAP 1
|
|
||||||
#define LWIP_PLATFORM_HTONS(x) <your_htons>
|
|
||||||
#define LWIP_PLATFORM_HTONL(x) <your_htonl>
|
|
||||||
|
|
||||||
Check your network interface driver if it reads at
|
|
||||||
a higher speed than the maximum wire-speed. If the
|
|
||||||
hardware isn't serviced frequently and fast enough
|
|
||||||
buffer overflows are likely to occur.
|
|
||||||
|
|
||||||
E.g. when using the cs8900 driver, call cs8900if_service(ethif)
|
|
||||||
as frequently as possible. When using an RTOS let the cs8900 interrupt
|
|
||||||
wake a high priority task that services your driver using a binary
|
|
||||||
semaphore or event flag. Some drivers might allow additional tuning
|
|
||||||
to match your application and network.
|
|
||||||
|
|
||||||
For a production release it is recommended to set LWIP_STATS to 0.
|
|
||||||
Note that speed performance isn't influenced much by simply setting
|
|
||||||
high values to the memory options.
|
|
|
@ -1,135 +0,0 @@
|
||||||
Daily Use Guide for using Savannah for lwIP
|
|
||||||
|
|
||||||
Table of Contents:
|
|
||||||
|
|
||||||
1 - Obtaining lwIP from the CVS repository
|
|
||||||
2 - Committers/developers CVS access using SSH (to be written)
|
|
||||||
3 - Merging from DEVEL branch to main trunk (stable branch)
|
|
||||||
4 - How to release lwIP
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
1 Obtaining lwIP from the CVS repository
|
|
||||||
----------------------------------------
|
|
||||||
|
|
||||||
To perform an anonymous CVS checkout of the main trunk (this is where
|
|
||||||
bug fixes and incremental enhancements occur), do this:
|
|
||||||
|
|
||||||
cvs -z3 -d:pserver:anonymous@cvs.sv.gnu.org:/sources/lwip checkout lwip
|
|
||||||
|
|
||||||
Or, obtain a stable branch (updated with bug fixes only) as follows:
|
|
||||||
cvs -z3 -d:pserver:anonymous@cvs.sv.gnu.org:/sources/lwip checkout \
|
|
||||||
-r STABLE-0_7 -d lwip-0.7 lwip
|
|
||||||
|
|
||||||
Or, obtain a specific (fixed) release as follows:
|
|
||||||
cvs -z3 -d:pserver:anonymous@cvs.sv.gnu.org:/sources/lwip checkout \
|
|
||||||
-r STABLE-0_7_0 -d lwip-0.7.0 lwip
|
|
||||||
|
|
||||||
3 Committers/developers CVS access using SSH
|
|
||||||
--------------------------------------------
|
|
||||||
|
|
||||||
The Savannah server uses SSH (Secure Shell) protocol 2 authentication and encryption.
|
|
||||||
As such, CVS commits to the server occur through a SSH tunnel for project members.
|
|
||||||
To create a SSH2 key pair in UNIX-like environments, do this:
|
|
||||||
|
|
||||||
ssh-keygen -t dsa
|
|
||||||
|
|
||||||
Under Windows, a recommended SSH client is "PuTTY", freely available with good
|
|
||||||
documentation and a graphic user interface. Use its key generator.
|
|
||||||
|
|
||||||
Now paste the id_dsa.pub contents into your Savannah account public key list. Wait
|
|
||||||
a while so that Savannah can update its configuration (This can take minutes).
|
|
||||||
|
|
||||||
Try to login using SSH:
|
|
||||||
|
|
||||||
ssh -v your_login@cvs.sv.gnu.org
|
|
||||||
|
|
||||||
If it tells you:
|
|
||||||
|
|
||||||
Authenticating with public key "your_key_name"...
|
|
||||||
Server refused to allocate pty
|
|
||||||
|
|
||||||
then you could login; Savannah refuses to give you a shell - which is OK, as we
|
|
||||||
are allowed to use SSH for CVS only. Now, you should be able to do this:
|
|
||||||
|
|
||||||
export CVS_RSH=ssh
|
|
||||||
cvs -z3 -d:ext:your_login@cvs.sv.gnu.org:/sources/lwip co lwip
|
|
||||||
|
|
||||||
after which you can edit your local files with bug fixes or new features and
|
|
||||||
commit them. Make sure you know what you are doing when using CVS to make
|
|
||||||
changes on the repository. If in doubt, ask on the lwip-members mailing list.
|
|
||||||
|
|
||||||
(If SSH asks about authenticity of the host, you can check the key
|
|
||||||
fingerprint against http://savannah.nongnu.org/cvs/?group=lwip)
|
|
||||||
|
|
||||||
|
|
||||||
3 Merging from DEVEL branch to main trunk (stable)
|
|
||||||
--------------------------------------------------
|
|
||||||
|
|
||||||
Merging is a delicate process in CVS and requires the
|
|
||||||
following disciplined steps in order to prevent conflicts
|
|
||||||
in the future. Conflicts can be hard to solve!
|
|
||||||
|
|
||||||
Merging from branch A to branch B requires that the A branch
|
|
||||||
has a tag indicating the previous merger. This tag is called
|
|
||||||
'merged_from_A_to_B'. After merging, the tag is moved in the
|
|
||||||
A branch to remember this merger for future merge actions.
|
|
||||||
|
|
||||||
IMPORTANT: AFTER COMMITTING A SUCCESFUL MERGE IN THE
|
|
||||||
REPOSITORY, THE TAG MUST BE SET ON THE SOURCE BRANCH OF THE
|
|
||||||
MERGE ACTION (REPLACING EXISTING TAGS WITH THE SAME NAME).
|
|
||||||
|
|
||||||
Merge all changes in DEVEL since our last merge to main:
|
|
||||||
|
|
||||||
In the working copy of the main trunk:
|
|
||||||
cvs update -P -jmerged_from_DEVEL_to_main -jDEVEL
|
|
||||||
|
|
||||||
(This will apply the changes between 'merged_from_DEVEL_to_main'
|
|
||||||
and 'DEVEL' to your work set of files)
|
|
||||||
|
|
||||||
We can now commit the merge result.
|
|
||||||
cvs commit -R -m "Merged from DEVEL to main."
|
|
||||||
|
|
||||||
If this worked out OK, we now move the tag in the DEVEL branch
|
|
||||||
to this merge point, so we can use this point for future merges:
|
|
||||||
|
|
||||||
cvs rtag -F -r DEVEL merged_from_DEVEL_to_main lwip
|
|
||||||
|
|
||||||
4 How to release lwIP
|
|
||||||
---------------------
|
|
||||||
|
|
||||||
First, checkout a clean copy of the branch to be released. Tag this set with
|
|
||||||
tag name "STABLE-0_6_3". (I use release number 0.6.3 throughout this example).
|
|
||||||
|
|
||||||
Login CVS using pserver authentication, then export a clean copy of the
|
|
||||||
tagged tree. Export is similar to a checkout, except that the CVS metadata
|
|
||||||
is not created locally.
|
|
||||||
|
|
||||||
export CVS_RSH=ssh
|
|
||||||
cvs -z3 -d:pserver:anonymous@cvs.sv.gnu.org:/sources/lwip checkout \
|
|
||||||
-r STABLE-0_6_3 -d lwip-0.6.3 lwip
|
|
||||||
|
|
||||||
Archive this directory using tar, gzip'd, bzip2'd and zip'd.
|
|
||||||
|
|
||||||
tar czvf lwip-0.6.3.tar.gz lwip-0.6.3
|
|
||||||
tar cjvf lwip-0.6.3.tar.bz2 lwip-0.6.3
|
|
||||||
zip -r lwip-0.6.3.zip lwip-0.6.3
|
|
||||||
|
|
||||||
Now, sign the archives with a detached GPG binary signature as follows:
|
|
||||||
|
|
||||||
gpg -b lwip-0.6.3.tar.gz
|
|
||||||
gpg -b lwip-0.6.3.tar.bz2
|
|
||||||
gpg -b lwip-0.6.3.zip
|
|
||||||
|
|
||||||
Upload these files using anonymous FTP:
|
|
||||||
ncftp ftp://savannah.gnu.org/incoming/savannah/lwip
|
|
||||||
|
|
||||||
ncftp>mput *0.6.3.*
|
|
||||||
|
|
||||||
Additionally, you may post a news item on Savannah, like this:
|
|
||||||
|
|
||||||
A new 0.6.3 release is now available here:
|
|
||||||
http://savannah.nongnu.org/files/?group=lwip&highlight=0.6.3
|
|
||||||
|
|
||||||
You will have to submit this via the user News interface, then approve
|
|
||||||
this via the Administrator News interface.
|
|
|
@ -1,181 +0,0 @@
|
||||||
SNMPv1 agent for lwIP
|
|
||||||
|
|
||||||
Author: Christiaan Simons
|
|
||||||
|
|
||||||
This is a brief introduction how to use and configure the SNMP agent.
|
|
||||||
Note the agent uses the raw-API UDP interface so you may also want to
|
|
||||||
read rawapi.txt to gain a better understanding of the SNMP message handling.
|
|
||||||
|
|
||||||
0 Agent Capabilities
|
|
||||||
====================
|
|
||||||
|
|
||||||
SNMPv1 per RFC1157
|
|
||||||
This is an old(er) standard but is still widely supported.
|
|
||||||
For SNMPv2c and v3 have a greater complexity and need many
|
|
||||||
more lines of code. IMHO this breaks the idea of "lightweight IP".
|
|
||||||
|
|
||||||
Note the S in SNMP stands for "Simple". Note that "Simple" is
|
|
||||||
relative. SNMP is simple compared to the complex ISO network
|
|
||||||
management protocols CMIP (Common Management Information Protocol)
|
|
||||||
and CMOT (CMip Over Tcp).
|
|
||||||
|
|
||||||
MIB II per RFC1213
|
|
||||||
The standard lwIP stack management information base.
|
|
||||||
This is a required MIB, so this is always enabled.
|
|
||||||
When builing lwIP without TCP, the mib-2.tcp group is omitted.
|
|
||||||
The groups EGP, CMOT and transmission are disabled by default.
|
|
||||||
|
|
||||||
Most mib-2 objects are not writable except:
|
|
||||||
sysName, sysLocation, sysContact, snmpEnableAuthenTraps.
|
|
||||||
Writing to or changing the ARP and IP address and route
|
|
||||||
tables is not possible.
|
|
||||||
|
|
||||||
Note lwIP has a very limited notion of IP routing. It currently
|
|
||||||
doen't have a route table and doesn't have a notion of the U,G,H flags.
|
|
||||||
Instead lwIP uses the interface list with only one default interface
|
|
||||||
acting as a single gateway interface (G) for the default route.
|
|
||||||
|
|
||||||
The agent returns a "virtual table" with the default route 0.0.0.0
|
|
||||||
for the default interface and network routes (no H) for each
|
|
||||||
network interface in the netif_list.
|
|
||||||
All routes are considered to be up (U).
|
|
||||||
|
|
||||||
Loading additional MIBs
|
|
||||||
MIBs can only be added in compile-time, not in run-time.
|
|
||||||
There is no MIB compiler thus additional MIBs must be hand coded.
|
|
||||||
|
|
||||||
Large SNMP message support
|
|
||||||
The packet decoding and encoding routines are designed
|
|
||||||
to use pbuf-chains. Larger payloads then the minimum
|
|
||||||
SNMP requirement of 484 octets are supported if the
|
|
||||||
PBUF_POOL_SIZE and IP_REASS_BUFSIZE are set to match your
|
|
||||||
local requirement.
|
|
||||||
|
|
||||||
1 Building the Agent
|
|
||||||
====================
|
|
||||||
|
|
||||||
First of all you'll need to add the following define
|
|
||||||
to your local lwipopts.h:
|
|
||||||
|
|
||||||
#define LWIP_SNMP 1
|
|
||||||
|
|
||||||
and add the source files in lwip/src/core/snmp
|
|
||||||
and some snmp headers in lwip/src/include/lwip to your makefile.
|
|
||||||
|
|
||||||
Note you'll might need to adapt you network driver to update
|
|
||||||
the mib2 variables for your interface.
|
|
||||||
|
|
||||||
2 Running the Agent
|
|
||||||
===================
|
|
||||||
|
|
||||||
The following function calls must be made in your program to
|
|
||||||
actually get the SNMP agent running.
|
|
||||||
|
|
||||||
Before starting the agent you should supply pointers
|
|
||||||
to non-volatile memory for sysContact, sysLocation,
|
|
||||||
and snmpEnableAuthenTraps. You can do this by calling
|
|
||||||
|
|
||||||
snmp_set_syscontact()
|
|
||||||
snmp_set_syslocation()
|
|
||||||
snmp_set_snmpenableauthentraps()
|
|
||||||
|
|
||||||
Additionally you may want to set
|
|
||||||
|
|
||||||
snmp_set_sysdescr()
|
|
||||||
snmp_set_sysobjid() (if you have a private MIB)
|
|
||||||
snmp_set_sysname()
|
|
||||||
|
|
||||||
Also before starting the agent you need to setup
|
|
||||||
one or more trap destinations using these calls:
|
|
||||||
|
|
||||||
snmp_trap_dst_enable();
|
|
||||||
snmp_trap_dst_ip_set();
|
|
||||||
|
|
||||||
In the lwIP initialisation sequence call snmp_init() just after
|
|
||||||
the call to udp_init().
|
|
||||||
|
|
||||||
Exactly every 10 msec the SNMP uptime timestamp must be updated with
|
|
||||||
snmp_inc_sysuptime(). You should call this from a timer interrupt
|
|
||||||
or a timer signal handler depending on your runtime environment.
|
|
||||||
|
|
||||||
An alternative way to update the SNMP uptime timestamp is to do a call like
|
|
||||||
snmp_add_sysuptime(100) each 1000ms (which is bigger "step", but call to
|
|
||||||
a lower frequency). Another one is to not call snmp_inc_sysuptime() or
|
|
||||||
snmp_add_sysuptime(), and to define the SNMP_GET_SYSUPTIME(sysuptime) macro.
|
|
||||||
This one is undefined by default in mib2.c. SNMP_GET_SYSUPTIME is called inside
|
|
||||||
snmp_get_sysuptime(u32_t *value), and enable to change "sysuptime" value only
|
|
||||||
when it's queried (any function which need "sysuptime" have to call
|
|
||||||
snmp_get_sysuptime).
|
|
||||||
|
|
||||||
|
|
||||||
3 Private MIBs
|
|
||||||
==============
|
|
||||||
|
|
||||||
If want to extend the agent with your own private MIB you'll need to
|
|
||||||
add the following define to your local lwipopts.h:
|
|
||||||
|
|
||||||
#define SNMP_PRIVATE_MIB 1
|
|
||||||
|
|
||||||
You must provide the private_mib.h and associated files yourself.
|
|
||||||
Note we don't have a "MIB compiler" that generates C source from a MIB,
|
|
||||||
so you're required to do some serious coding if you enable this!
|
|
||||||
|
|
||||||
Note the lwIP enterprise ID (26381) is assigned to the lwIP project,
|
|
||||||
ALL OBJECT IDENTIFIERS LIVING UNDER THIS ID ARE ASSIGNED BY THE lwIP
|
|
||||||
MAINTAINERS!
|
|
||||||
|
|
||||||
If you need to create your own private MIB you'll need
|
|
||||||
to apply for your own enterprise ID with IANA: http://www.iana.org/numbers.html
|
|
||||||
|
|
||||||
You can set it by passing a struct snmp_obj_id to the agent
|
|
||||||
using snmp_set_sysobjid(&my_object_id), just before snmp_init().
|
|
||||||
|
|
||||||
Note the object identifiers for thes MIB-2 and your private MIB
|
|
||||||
tree must be kept in sorted ascending (lexicographical) order.
|
|
||||||
This to ensure correct getnext operation.
|
|
||||||
|
|
||||||
An example for a private MIB is part of the "minimal Unix" project:
|
|
||||||
contrib/ports/unix/proj/minimal/lwip_prvmib.c
|
|
||||||
|
|
||||||
The next chapter gives a more detailed description of the
|
|
||||||
MIB-2 tree and the optional private MIB.
|
|
||||||
|
|
||||||
4 The Gory Details
|
|
||||||
==================
|
|
||||||
|
|
||||||
4.0 Object identifiers and the MIB tree.
|
|
||||||
|
|
||||||
We have three distinct parts for all object identifiers:
|
|
||||||
|
|
||||||
The prefix
|
|
||||||
.iso.org.dod.internet
|
|
||||||
|
|
||||||
the middle part
|
|
||||||
.mgmt.mib-2.ip.ipNetToMediaTable.ipNetToMediaEntry.ipNetToMediaPhysAddress
|
|
||||||
|
|
||||||
and the index part
|
|
||||||
.1.192.168.0.1
|
|
||||||
|
|
||||||
Objects located above the .internet hierarchy aren't supported.
|
|
||||||
Currently only the .mgmt sub-tree is available and
|
|
||||||
when the SNMP_PRIVATE_MIB is enabled the .private tree
|
|
||||||
becomes available too.
|
|
||||||
|
|
||||||
Object identifiers from incoming requests are checked
|
|
||||||
for a matching prefix, middle part and index part
|
|
||||||
or are expanded(*) for GetNext requests with short
|
|
||||||
or inexisting names in the request.
|
|
||||||
(* we call this "expansion" but this also
|
|
||||||
resembles the "auto-completion" operation)
|
|
||||||
|
|
||||||
The middle part is usually located in ROM (const)
|
|
||||||
to preserve precious RAM on small microcontrollers.
|
|
||||||
However RAM location is possible for an dynamically
|
|
||||||
changing private tree.
|
|
||||||
|
|
||||||
The index part is handled by functions which in
|
|
||||||
turn use dynamically allocated index trees from RAM.
|
|
||||||
These trees are updated by e.g. the etharp code
|
|
||||||
when new entries are made or removed form the ARP cache.
|
|
||||||
|
|
||||||
/** @todo more gory details */
|
|
|
@ -1,228 +0,0 @@
|
||||||
sys_arch interface for lwIP 0.6++
|
|
||||||
|
|
||||||
Author: Adam Dunkels
|
|
||||||
|
|
||||||
The operating system emulation layer provides a common interface
|
|
||||||
between the lwIP code and the underlying operating system kernel. The
|
|
||||||
general idea is that porting lwIP to new architectures requires only
|
|
||||||
small changes to a few header files and a new sys_arch
|
|
||||||
implementation. It is also possible to do a sys_arch implementation
|
|
||||||
that does not rely on any underlying operating system.
|
|
||||||
|
|
||||||
The sys_arch provides semaphores and mailboxes to lwIP. For the full
|
|
||||||
lwIP functionality, multiple threads support can be implemented in the
|
|
||||||
sys_arch, but this is not required for the basic lwIP
|
|
||||||
functionality. Previous versions of lwIP required the sys_arch to
|
|
||||||
implement timer scheduling as well but as of lwIP 0.5 this is
|
|
||||||
implemented in a higher layer.
|
|
||||||
|
|
||||||
In addition to the source file providing the functionality of sys_arch,
|
|
||||||
the OS emulation layer must provide several header files defining
|
|
||||||
macros used throughout lwip. The files required and the macros they
|
|
||||||
must define are listed below the sys_arch description.
|
|
||||||
|
|
||||||
Semaphores can be either counting or binary - lwIP works with both
|
|
||||||
kinds. Mailboxes are used for message passing and can be implemented
|
|
||||||
either as a queue which allows multiple messages to be posted to a
|
|
||||||
mailbox, or as a rendez-vous point where only one message can be
|
|
||||||
posted at a time. lwIP works with both kinds, but the former type will
|
|
||||||
be more efficient. A message in a mailbox is just a pointer, nothing
|
|
||||||
more.
|
|
||||||
|
|
||||||
Semaphores are represented by the type "sys_sem_t" which is typedef'd
|
|
||||||
in the sys_arch.h file. Mailboxes are equivalently represented by the
|
|
||||||
type "sys_mbox_t". lwIP does not place any restrictions on how
|
|
||||||
sys_sem_t or sys_mbox_t are represented internally.
|
|
||||||
|
|
||||||
The following functions must be implemented by the sys_arch:
|
|
||||||
|
|
||||||
- void sys_init(void)
|
|
||||||
|
|
||||||
Is called to initialize the sys_arch layer.
|
|
||||||
|
|
||||||
- sys_sem_t sys_sem_new(u8_t count)
|
|
||||||
|
|
||||||
Creates and returns a new semaphore. The "count" argument specifies
|
|
||||||
the initial state of the semaphore.
|
|
||||||
|
|
||||||
- void sys_sem_free(sys_sem_t sem)
|
|
||||||
|
|
||||||
Deallocates a semaphore.
|
|
||||||
|
|
||||||
- void sys_sem_signal(sys_sem_t sem)
|
|
||||||
|
|
||||||
Signals a semaphore.
|
|
||||||
|
|
||||||
- u32_t sys_arch_sem_wait(sys_sem_t sem, u32_t timeout)
|
|
||||||
|
|
||||||
Blocks the thread while waiting for the semaphore to be
|
|
||||||
signaled. If the "timeout" argument is non-zero, the thread should
|
|
||||||
only be blocked for the specified time (measured in
|
|
||||||
milliseconds). If the "timeout" argument is zero, the thread should be
|
|
||||||
blocked until the semaphore is signalled.
|
|
||||||
|
|
||||||
If the timeout argument is non-zero, the return value is the number of
|
|
||||||
milliseconds spent waiting for the semaphore to be signaled. If the
|
|
||||||
semaphore wasn't signaled within the specified time, the return value is
|
|
||||||
SYS_ARCH_TIMEOUT. If the thread didn't have to wait for the semaphore
|
|
||||||
(i.e., it was already signaled), the function may return zero.
|
|
||||||
|
|
||||||
Notice that lwIP implements a function with a similar name,
|
|
||||||
sys_sem_wait(), that uses the sys_arch_sem_wait() function.
|
|
||||||
|
|
||||||
- sys_mbox_t sys_mbox_new(int size)
|
|
||||||
|
|
||||||
Creates an empty mailbox for maximum "size" elements. Elements stored
|
|
||||||
in mailboxes are pointers. You have to define macros "_MBOX_SIZE"
|
|
||||||
in your lwipopts.h, or ignore this parameter in your implementation
|
|
||||||
and use a default size.
|
|
||||||
|
|
||||||
- void sys_mbox_free(sys_mbox_t mbox)
|
|
||||||
|
|
||||||
Deallocates a mailbox. If there are messages still present in the
|
|
||||||
mailbox when the mailbox is deallocated, it is an indication of a
|
|
||||||
programming error in lwIP and the developer should be notified.
|
|
||||||
|
|
||||||
- void sys_mbox_post(sys_mbox_t mbox, void *msg)
|
|
||||||
|
|
||||||
Posts the "msg" to the mailbox. This function have to block until
|
|
||||||
the "msg" is really posted.
|
|
||||||
|
|
||||||
- err_t sys_mbox_trypost(sys_mbox_t mbox, void *msg)
|
|
||||||
|
|
||||||
Try to post the "msg" to the mailbox. Returns ERR_MEM if this one
|
|
||||||
is full, else, ERR_OK if the "msg" is posted.
|
|
||||||
|
|
||||||
- u32_t sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, u32_t timeout)
|
|
||||||
|
|
||||||
Blocks the thread until a message arrives in the mailbox, but does
|
|
||||||
not block the thread longer than "timeout" milliseconds (similar to
|
|
||||||
the sys_arch_sem_wait() function). If "timeout" is 0, the thread should
|
|
||||||
be blocked until a message arrives. The "msg" argument is a result
|
|
||||||
parameter that is set by the function (i.e., by doing "*msg =
|
|
||||||
ptr"). The "msg" parameter maybe NULL to indicate that the message
|
|
||||||
should be dropped.
|
|
||||||
|
|
||||||
The return values are the same as for the sys_arch_sem_wait() function:
|
|
||||||
Number of milliseconds spent waiting or SYS_ARCH_TIMEOUT if there was a
|
|
||||||
timeout.
|
|
||||||
|
|
||||||
Note that a function with a similar name, sys_mbox_fetch(), is
|
|
||||||
implemented by lwIP.
|
|
||||||
|
|
||||||
- u32_t sys_arch_mbox_tryfetch(sys_mbox_t mbox, void **msg)
|
|
||||||
|
|
||||||
This is similar to sys_arch_mbox_fetch, however if a message is not
|
|
||||||
present in the mailbox, it immediately returns with the code
|
|
||||||
SYS_MBOX_EMPTY. On success 0 is returned.
|
|
||||||
|
|
||||||
To allow for efficient implementations, this can be defined as a
|
|
||||||
function-like macro in sys_arch.h instead of a normal function. For
|
|
||||||
example, a naive implementation could be:
|
|
||||||
#define sys_arch_mbox_tryfetch(mbox,msg) \
|
|
||||||
sys_arch_mbox_fetch(mbox,msg,1)
|
|
||||||
although this would introduce unnecessary delays.
|
|
||||||
|
|
||||||
- struct sys_timeouts *sys_arch_timeouts(void)
|
|
||||||
|
|
||||||
Returns a pointer to the per-thread sys_timeouts structure. In lwIP,
|
|
||||||
each thread has a list of timeouts which is repressented as a linked
|
|
||||||
list of sys_timeout structures. The sys_timeouts structure holds a
|
|
||||||
pointer to a linked list of timeouts. This function is called by
|
|
||||||
the lwIP timeout scheduler and must not return a NULL value.
|
|
||||||
|
|
||||||
In a single thread sys_arch implementation, this function will
|
|
||||||
simply return a pointer to a global sys_timeouts variable stored in
|
|
||||||
the sys_arch module.
|
|
||||||
|
|
||||||
If threads are supported by the underlying operating system and if
|
|
||||||
such functionality is needed in lwIP, the following function will have
|
|
||||||
to be implemented as well:
|
|
||||||
|
|
||||||
- sys_thread_t sys_thread_new(char *name, void (* thread)(void *arg), void *arg, int stacksize, int prio)
|
|
||||||
|
|
||||||
Starts a new thread named "name" with priority "prio" that will begin its
|
|
||||||
execution in the function "thread()". The "arg" argument will be passed as an
|
|
||||||
argument to the thread() function. The stack size to used for this thread is
|
|
||||||
the "stacksize" parameter. The id of the new thread is returned. Both the id
|
|
||||||
and the priority are system dependent.
|
|
||||||
|
|
||||||
- sys_prot_t sys_arch_protect(void)
|
|
||||||
|
|
||||||
This optional function does a "fast" critical region protection and returns
|
|
||||||
the previous protection level. This function is only called during very short
|
|
||||||
critical regions. An embedded system which supports ISR-based drivers might
|
|
||||||
want to implement this function by disabling interrupts. Task-based systems
|
|
||||||
might want to implement this by using a mutex or disabling tasking. This
|
|
||||||
function should support recursive calls from the same task or interrupt. In
|
|
||||||
other words, sys_arch_protect() could be called while already protected. In
|
|
||||||
that case the return value indicates that it is already protected.
|
|
||||||
|
|
||||||
sys_arch_protect() is only required if your port is supporting an operating
|
|
||||||
system.
|
|
||||||
|
|
||||||
- void sys_arch_unprotect(sys_prot_t pval)
|
|
||||||
|
|
||||||
This optional function does a "fast" set of critical region protection to the
|
|
||||||
value specified by pval. See the documentation for sys_arch_protect() for
|
|
||||||
more information. This function is only required if your port is supporting
|
|
||||||
an operating system.
|
|
||||||
|
|
||||||
Note:
|
|
||||||
|
|
||||||
Be carefull with using mem_malloc() in sys_arch. When malloc() refers to
|
|
||||||
mem_malloc() you can run into a circular function call problem. In mem.c
|
|
||||||
mem_init() tries to allcate a semaphore using mem_malloc, which of course
|
|
||||||
can't be performed when sys_arch uses mem_malloc.
|
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
Additional files required for the "OS support" emulation layer:
|
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
cc.h - Architecture environment, some compiler specific, some
|
|
||||||
environment specific (probably should move env stuff
|
|
||||||
to sys_arch.h.)
|
|
||||||
|
|
||||||
Typedefs for the types used by lwip -
|
|
||||||
u8_t, s8_t, u16_t, s16_t, u32_t, s32_t, mem_ptr_t
|
|
||||||
|
|
||||||
Compiler hints for packing lwip's structures -
|
|
||||||
PACK_STRUCT_FIELD(x)
|
|
||||||
PACK_STRUCT_STRUCT
|
|
||||||
PACK_STRUCT_BEGIN
|
|
||||||
PACK_STRUCT_END
|
|
||||||
|
|
||||||
Platform specific diagnostic output -
|
|
||||||
LWIP_PLATFORM_DIAG(x) - non-fatal, print a message.
|
|
||||||
LWIP_PLATFORM_ASSERT(x) - fatal, print message and abandon execution.
|
|
||||||
Portability defines for printf formatters:
|
|
||||||
U16_F, S16_F, X16_F, U32_F, S32_F, X32_F, SZT_F
|
|
||||||
|
|
||||||
"lightweight" synchronization mechanisms -
|
|
||||||
SYS_ARCH_DECL_PROTECT(x) - declare a protection state variable.
|
|
||||||
SYS_ARCH_PROTECT(x) - enter protection mode.
|
|
||||||
SYS_ARCH_UNPROTECT(x) - leave protection mode.
|
|
||||||
|
|
||||||
If the compiler does not provide memset() this file must include a
|
|
||||||
definition of it, or include a file which defines it.
|
|
||||||
|
|
||||||
This file must either include a system-local <errno.h> which defines
|
|
||||||
the standard *nix error codes, or it should #define LWIP_PROVIDE_ERRNO
|
|
||||||
to make lwip/arch.h define the codes which are used throughout.
|
|
||||||
|
|
||||||
|
|
||||||
perf.h - Architecture specific performance measurement.
|
|
||||||
Measurement calls made throughout lwip, these can be defined to nothing.
|
|
||||||
PERF_START - start measuring something.
|
|
||||||
PERF_STOP(x) - stop measuring something, and record the result.
|
|
||||||
|
|
||||||
sys_arch.h - Tied to sys_arch.c
|
|
||||||
|
|
||||||
Arch dependent types for the following objects:
|
|
||||||
sys_sem_t, sys_mbox_t, sys_thread_t,
|
|
||||||
And, optionally:
|
|
||||||
sys_prot_t
|
|
||||||
|
|
||||||
Defines to set vars of sys_mbox_t and sys_sem_t to NULL.
|
|
||||||
SYS_MBOX_NULL NULL
|
|
||||||
SYS_SEM_NULL NULL
|
|
|
@ -1,36 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if defined(__IAR_SYSTEMS_ICC__)
|
|
||||||
#pragma pack(1)
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -1,100 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#ifndef __CC_H__
|
|
||||||
#define __CC_H__
|
|
||||||
|
|
||||||
#include "cpu.h"
|
|
||||||
|
|
||||||
typedef unsigned char u8_t;
|
|
||||||
typedef signed char s8_t;
|
|
||||||
typedef unsigned short u16_t;
|
|
||||||
typedef signed short s16_t;
|
|
||||||
typedef unsigned int u32_t;
|
|
||||||
typedef signed long s32_t;
|
|
||||||
typedef u32_t mem_ptr_t;
|
|
||||||
typedef int sys_prot_t;
|
|
||||||
|
|
||||||
#define U16_F "d"
|
|
||||||
#define S16_F "d"
|
|
||||||
#define X16_F "x"
|
|
||||||
#define U32_F "d"
|
|
||||||
#define S32_F "d"
|
|
||||||
#define X32_F "x"
|
|
||||||
#define SZT_F "uz"
|
|
||||||
|
|
||||||
/* define compiler specific symbols */
|
|
||||||
#if defined (__ICCARM__)
|
|
||||||
#if !defined (__IARSTDLIB__)
|
|
||||||
#define _STRING
|
|
||||||
#ifndef memcmp
|
|
||||||
#define memcmp(dst, src, sz) _memcmp(dst, src, sz)
|
|
||||||
#endif
|
|
||||||
#ifndef memset
|
|
||||||
#define memset(dst, val, sz) _memset(dst, val, sz)
|
|
||||||
#endif
|
|
||||||
#ifndef memcpy
|
|
||||||
#define memcpy(dst, src, sz) _memcpy(dst, src, sz)
|
|
||||||
#endif
|
|
||||||
#endif // __IARSTDLIB__
|
|
||||||
|
|
||||||
#define PACK_STRUCT_BEGIN
|
|
||||||
#define PACK_STRUCT_STRUCT
|
|
||||||
#define PACK_STRUCT_END
|
|
||||||
#define PACK_STRUCT_FIELD(x) x
|
|
||||||
#define PACK_STRUCT_USE_INCLUDES
|
|
||||||
|
|
||||||
#elif defined (__CC_ARM)
|
|
||||||
|
|
||||||
#define PACK_STRUCT_BEGIN __packed
|
|
||||||
#define PACK_STRUCT_STRUCT
|
|
||||||
#define PACK_STRUCT_END
|
|
||||||
#define PACK_STRUCT_FIELD(x) x
|
|
||||||
|
|
||||||
#elif defined (__GNUC__)
|
|
||||||
|
|
||||||
#define PACK_STRUCT_BEGIN
|
|
||||||
#define PACK_STRUCT_STRUCT __attribute__ ((__packed__))
|
|
||||||
#define PACK_STRUCT_END
|
|
||||||
#define PACK_STRUCT_FIELD(x) x
|
|
||||||
|
|
||||||
#elif defined (__TASKING__)
|
|
||||||
|
|
||||||
#define PACK_STRUCT_BEGIN
|
|
||||||
#define PACK_STRUCT_STRUCT
|
|
||||||
#define PACK_STRUCT_END
|
|
||||||
#define PACK_STRUCT_FIELD(x) x
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define LWIP_PLATFORM_ASSERT(x) //do { if(!(x)) while(1); } while(0)
|
|
||||||
|
|
||||||
#endif /* __CC_H__ */
|
|
|
@ -1,37 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#ifndef __CPU_H__
|
|
||||||
#define __CPU_H__
|
|
||||||
|
|
||||||
#define BYTE_ORDER LITTLE_ENDIAN
|
|
||||||
|
|
||||||
#endif /* __CPU_H__ */
|
|
|
@ -1,36 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if defined(__IAR_SYSTEMS_ICC__)
|
|
||||||
#pragma pack()
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -1,44 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#ifndef __ARCH_INIT_H__
|
|
||||||
#define __ARCH_INIT_H__
|
|
||||||
|
|
||||||
#define TCPIP_INIT_DONE(arg) tcpip_init_done(arg)
|
|
||||||
|
|
||||||
void tcpip_init_done(void *);
|
|
||||||
int wait_for_tcpip_init(void);
|
|
||||||
|
|
||||||
#endif /* __ARCH_INIT_H__ */
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#ifndef __LIB_H__
|
|
||||||
#define __LIB_H__
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* __LIB_H__ */
|
|
|
@ -1,38 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#ifndef __PERF_H__
|
|
||||||
#define __PERF_H__
|
|
||||||
|
|
||||||
#define PERF_START /* null definition */
|
|
||||||
#define PERF_STOP(x) /* null definition */
|
|
||||||
|
|
||||||
#endif /* __PERF_H__ */
|
|
|
@ -1,66 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#ifndef __SYS_RTXC_H__
|
|
||||||
#define __SYS_RTXC_H__
|
|
||||||
|
|
||||||
#include "FreeRTOS.h"
|
|
||||||
#include "task.h"
|
|
||||||
#include "queue.h"
|
|
||||||
#include "semphr.h"
|
|
||||||
|
|
||||||
#define SYS_MBOX_NULL (xQueueHandle)0
|
|
||||||
#define SYS_SEM_NULL (xSemaphoreHandle)0
|
|
||||||
#define SYS_DEFAULT_THREAD_STACK_DEPTH configMINIMAL_STACK_SIZE
|
|
||||||
|
|
||||||
typedef xSemaphoreHandle sys_sem_t;
|
|
||||||
typedef xQueueHandle sys_mbox_t;
|
|
||||||
typedef xTaskHandle sys_thread_t;
|
|
||||||
|
|
||||||
typedef struct _sys_arch_state_t
|
|
||||||
{
|
|
||||||
// Task creation data.
|
|
||||||
char cTaskName[configMAX_TASK_NAME_LEN];
|
|
||||||
unsigned short nStackDepth;
|
|
||||||
unsigned short nTaskCount;
|
|
||||||
} sys_arch_state_t;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//extern sys_arch_state_t s_sys_arch_state;
|
|
||||||
|
|
||||||
//void sys_set_default_state();
|
|
||||||
//void sys_set_state(signed char *pTaskName, unsigned short nStackSize);
|
|
||||||
|
|
||||||
/* Message queue constants. */
|
|
||||||
#define archMESG_QUEUE_LENGTH ( 6 )
|
|
||||||
#endif /* __SYS_RTXC_H__ */
|
|
||||||
|
|
|
@ -1,274 +0,0 @@
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
* Ethernet Interface Skeleton
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This file is a skeleton for developing Ethernet network interface
|
|
||||||
* drivers for lwIP. Add code to the low_level functions and do a
|
|
||||||
* search-and-replace for the word "ethernetif" to replace it with
|
|
||||||
* something that better describes your network interface.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "lwip/opt.h"
|
|
||||||
#include "lwip/def.h"
|
|
||||||
#include "lwip/mem.h"
|
|
||||||
#include "lwip/pbuf.h"
|
|
||||||
#include "lwip/sys.h"
|
|
||||||
#include "lwip/tcpip.h"
|
|
||||||
#include "netif/etharp.h"
|
|
||||||
#include "err.h"
|
|
||||||
#include "ethernetif.h"
|
|
||||||
#include "queue.h"
|
|
||||||
|
|
||||||
#include <lwip_intf.h>
|
|
||||||
#include <platform/platform_stdlib.h>
|
|
||||||
|
|
||||||
#define netifMTU (1500)
|
|
||||||
#define netifINTERFACE_TASK_STACK_SIZE ( 350 )
|
|
||||||
#define netifINTERFACE_TASK_PRIORITY ( configMAX_PRIORITIES - 1 )
|
|
||||||
#define netifGUARD_BLOCK_TIME ( 250 )
|
|
||||||
/* The time to block waiting for input. */
|
|
||||||
#define emacBLOCK_TIME_WAITING_FOR_INPUT ( ( portTickType ) 100 )
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef CONFIG_CONCURRENT_MODE
|
|
||||||
#define IF2NAME0 'r'
|
|
||||||
#define IF2NAME1 '2'
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void arp_timer(void *arg);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* In this function, the hardware should be initialized.
|
|
||||||
* Called from ethernetif_init().
|
|
||||||
*
|
|
||||||
* @param netif the already initialized lwip network interface structure
|
|
||||||
* for this ethernetif
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void low_level_init(struct netif *netif)
|
|
||||||
{
|
|
||||||
|
|
||||||
/* set netif MAC hardware address length */
|
|
||||||
netif->hwaddr_len = ETHARP_HWADDR_LEN;
|
|
||||||
|
|
||||||
/* set netif maximum transfer unit */
|
|
||||||
netif->mtu = 1500;
|
|
||||||
|
|
||||||
/* Accept broadcast address and ARP traffic */
|
|
||||||
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP;
|
|
||||||
|
|
||||||
/* Wlan interface is initialized later */
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This function should do the actual transmission of the packet. The packet is
|
|
||||||
* contained in the pbuf that is passed to the function. This pbuf
|
|
||||||
* might be chained.
|
|
||||||
*
|
|
||||||
* @param netif the lwip network interface structure for this ethernetif
|
|
||||||
* @param p the MAC packet to send (e.g. IP packet including MAC addresses and type)
|
|
||||||
* @return ERR_OK if the packet could be sent
|
|
||||||
* an err_t value if the packet couldn't be sent
|
|
||||||
*
|
|
||||||
* @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to
|
|
||||||
* strange results. You might consider waiting for space in the DMA queue
|
|
||||||
* to become availale since the stack doesn't retry to send a packet
|
|
||||||
* dropped because of memory failure (except for the TCP timers).
|
|
||||||
*/
|
|
||||||
|
|
||||||
static err_t low_level_output(struct netif *netif, struct pbuf *p)
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
/* Refer to eCos lwip eth_drv_send() */
|
|
||||||
struct eth_drv_sg sg_list[MAX_ETH_DRV_SG];
|
|
||||||
int sg_len = 0;
|
|
||||||
struct pbuf *q;
|
|
||||||
|
|
||||||
if(!rltk_wlan_running(netif_get_idx(netif)))
|
|
||||||
return ERR_IF;
|
|
||||||
|
|
||||||
for (q = p; q != NULL && sg_len < MAX_ETH_DRV_SG; q = q->next) {
|
|
||||||
sg_list[sg_len].buf = (unsigned int) q->payload;
|
|
||||||
sg_list[sg_len++].len = q->len;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sg_len)
|
|
||||||
rltk_wlan_send(netif_get_idx(netif), sg_list, sg_len, p->tot_len);
|
|
||||||
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Should allocate a pbuf and transfer the bytes of the incoming
|
|
||||||
* packet from the interface into the pbuf.
|
|
||||||
*
|
|
||||||
* @param netif the lwip network interface structure for this ethernetif
|
|
||||||
* @return a pbuf filled with the received packet (including MAC header)
|
|
||||||
* NULL on memory error
|
|
||||||
*/
|
|
||||||
//static struct pbuf * low_level_input(struct netif *netif){}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This function is the ethernetif_input task, it is processed when a packet
|
|
||||||
* is ready to be read from the interface. It uses the function low_level_input()
|
|
||||||
* that should handle the actual reception of bytes from the network
|
|
||||||
* interface. Then the type of the received packet is determined and
|
|
||||||
* the appropriate input function is called.
|
|
||||||
*
|
|
||||||
* @param netif the lwip network interface structure for this ethernetif
|
|
||||||
*/
|
|
||||||
//void ethernetif_input( void * pvParameters )
|
|
||||||
|
|
||||||
|
|
||||||
/* Refer to eCos eth_drv_recv to do similarly in ethernetif_input */
|
|
||||||
void ethernetif_recv(struct netif *netif, int total_len)
|
|
||||||
{
|
|
||||||
struct eth_drv_sg sg_list[MAX_ETH_DRV_SG];
|
|
||||||
struct pbuf *p, *q;
|
|
||||||
int sg_len = 0;
|
|
||||||
|
|
||||||
if(!rltk_wlan_running(netif_get_idx(netif)))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if ((total_len > MAX_ETH_MSG) || (total_len < 0))
|
|
||||||
total_len = MAX_ETH_MSG;
|
|
||||||
|
|
||||||
// Allocate buffer to store received packet
|
|
||||||
p = pbuf_alloc(PBUF_RAW, total_len, PBUF_POOL);
|
|
||||||
if (p == NULL) {
|
|
||||||
printf("\n\rCannot allocate pbuf to receive packet");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create scatter list
|
|
||||||
for (q = p; q != NULL && sg_len < MAX_ETH_DRV_SG; q = q->next) {
|
|
||||||
sg_list[sg_len].buf = (unsigned int) q->payload;
|
|
||||||
sg_list[sg_len++].len = q->len;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy received packet to scatter list from wrapper rx skb
|
|
||||||
//printf("\n\rwlan:%c: Recv sg_len: %d, tot_len:%d", netif->name[1],sg_len, total_len);
|
|
||||||
rltk_wlan_recv(netif_get_idx(netif), sg_list, sg_len);
|
|
||||||
|
|
||||||
// Pass received packet to the interface
|
|
||||||
if (ERR_OK != netif->input(p, netif))
|
|
||||||
pbuf_free(p);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Should be called at the beginning of the program to set up the
|
|
||||||
* network interface. It calls the function low_level_init() to do the
|
|
||||||
* actual setup of the hardware.
|
|
||||||
*
|
|
||||||
* This function should be passed as a parameter to netif_add().
|
|
||||||
*
|
|
||||||
* @param netif the lwip network interface structure for this ethernetif
|
|
||||||
* @return ERR_OK if the loopif is initialized
|
|
||||||
* ERR_MEM if private data couldn't be allocated
|
|
||||||
* any other err_t on error
|
|
||||||
*/
|
|
||||||
err_t ethernetif_init(struct netif *netif)
|
|
||||||
{
|
|
||||||
LWIP_ASSERT("netif != NULL", (netif != NULL));
|
|
||||||
|
|
||||||
#if LWIP_NETIF_HOSTNAME
|
|
||||||
/* Initialize interface hostname */
|
|
||||||
if(netif->name[1] == '0')
|
|
||||||
netif->hostname = "lwip0";
|
|
||||||
else if(netif->name[1] == '1')
|
|
||||||
netif->hostname = "lwip1";
|
|
||||||
#endif /* LWIP_NETIF_HOSTNAME */
|
|
||||||
|
|
||||||
netif->output = etharp_output;
|
|
||||||
netif->linkoutput = low_level_output;
|
|
||||||
|
|
||||||
/* initialize the hardware */
|
|
||||||
low_level_init(netif);
|
|
||||||
|
|
||||||
etharp_init();
|
|
||||||
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void arp_timer(void *arg)
|
|
||||||
{
|
|
||||||
etharp_tmr();
|
|
||||||
sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* For FreeRTOS tickless
|
|
||||||
*/
|
|
||||||
int lwip_tickless_used = 0;
|
|
||||||
|
|
||||||
int arp_timeout_exist(void)
|
|
||||||
{
|
|
||||||
struct sys_timeouts *timeouts;
|
|
||||||
struct sys_timeo *t;
|
|
||||||
|
|
||||||
timeouts = sys_arch_timeouts();
|
|
||||||
|
|
||||||
for(t = timeouts->next; t != NULL;t = t->next)
|
|
||||||
if(t->h == arp_timer)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Called by rltk_wlan_PRE_SLEEP_PROCESSING()
|
|
||||||
void lwip_PRE_SLEEP_PROCESSING(void)
|
|
||||||
{
|
|
||||||
if(arp_timeout_exist()) {
|
|
||||||
tcpip_untimeout(arp_timer, NULL);
|
|
||||||
}
|
|
||||||
lwip_tickless_used = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Called in ips_leave() path, support tickless when wifi power wakeup due to ioctl or deinit
|
|
||||||
void lwip_POST_SLEEP_PROCESSING(void)
|
|
||||||
{
|
|
||||||
if(lwip_tickless_used) {
|
|
||||||
tcpip_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
#ifndef __ETHERNETIF_H__
|
|
||||||
#define __ETHERNETIF_H__
|
|
||||||
|
|
||||||
|
|
||||||
#include "lwip/err.h"
|
|
||||||
#include "lwip/netif.h"
|
|
||||||
//----- ------------------------------------------------------------------
|
|
||||||
// Ethernet Buffer
|
|
||||||
//----- ------------------------------------------------------------------
|
|
||||||
struct eth_drv_sg {
|
|
||||||
unsigned int buf;
|
|
||||||
unsigned int len;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define MAX_ETH_DRV_SG 32
|
|
||||||
#define MAX_ETH_MSG 1540
|
|
||||||
|
|
||||||
void ethernetif_recv(struct netif *netif, int total_len);
|
|
||||||
err_t ethernetif_init(struct netif *netif);
|
|
||||||
void lwip_PRE_SLEEP_PROCESSING(void);
|
|
||||||
void lwip_POST_SLEEP_PROCESSING(void);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,446 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* lwIP includes. */
|
|
||||||
#include "lwip/debug.h"
|
|
||||||
#include "lwip/def.h"
|
|
||||||
#include "lwip/sys.h"
|
|
||||||
#include "lwip/mem.h"
|
|
||||||
#include "lwip/stats.h"
|
|
||||||
#include "FreeRTOS.h"
|
|
||||||
#include "task.h"
|
|
||||||
#include "queue.h"
|
|
||||||
|
|
||||||
xTaskHandle xTaskGetCurrentTaskHandle( void ) PRIVILEGED_FUNCTION;
|
|
||||||
|
|
||||||
struct timeoutlist
|
|
||||||
{
|
|
||||||
struct sys_timeouts timeouts;
|
|
||||||
xTaskHandle pid;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* This is the number of threads that can be started with sys_thread_new() */
|
|
||||||
#define SYS_THREAD_MAX 6
|
|
||||||
|
|
||||||
static struct timeoutlist s_timeoutlist[SYS_THREAD_MAX];
|
|
||||||
static u16_t s_nextthread = 0;
|
|
||||||
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------------*/
|
|
||||||
// Creates an empty mailbox.
|
|
||||||
sys_mbox_t sys_mbox_new(int size)
|
|
||||||
{
|
|
||||||
xQueueHandle mbox;
|
|
||||||
|
|
||||||
( void ) size;
|
|
||||||
|
|
||||||
mbox = xQueueCreate( archMESG_QUEUE_LENGTH, sizeof( void * ) );
|
|
||||||
|
|
||||||
#if SYS_STATS
|
|
||||||
++lwip_stats.sys.mbox.used;
|
|
||||||
if (lwip_stats.sys.mbox.max < lwip_stats.sys.mbox.used) {
|
|
||||||
lwip_stats.sys.mbox.max = lwip_stats.sys.mbox.used;
|
|
||||||
}
|
|
||||||
#endif /* SYS_STATS */
|
|
||||||
|
|
||||||
return mbox;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------------*/
|
|
||||||
/*
|
|
||||||
Deallocates a mailbox. If there are messages still present in the
|
|
||||||
mailbox when the mailbox is deallocated, it is an indication of a
|
|
||||||
programming error in lwIP and the developer should be notified.
|
|
||||||
*/
|
|
||||||
void sys_mbox_free(sys_mbox_t mbox)
|
|
||||||
{
|
|
||||||
if( uxQueueMessagesWaiting( mbox ) )
|
|
||||||
{
|
|
||||||
/* Line for breakpoint. Should never break here! */
|
|
||||||
portNOP();
|
|
||||||
#if SYS_STATS
|
|
||||||
lwip_stats.sys.mbox.err++;
|
|
||||||
#endif /* SYS_STATS */
|
|
||||||
|
|
||||||
// TODO notify the user of failure.
|
|
||||||
}
|
|
||||||
|
|
||||||
vQueueDelete( mbox );
|
|
||||||
|
|
||||||
#if SYS_STATS
|
|
||||||
--lwip_stats.sys.mbox.used;
|
|
||||||
#endif /* SYS_STATS */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------------*/
|
|
||||||
// Posts the "msg" to the mailbox.
|
|
||||||
void sys_mbox_post(sys_mbox_t mbox, void *data)
|
|
||||||
{
|
|
||||||
while ( xQueueSendToBack(mbox, &data, portMAX_DELAY ) != pdTRUE ){}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------------*/
|
|
||||||
// Try to post the "msg" to the mailbox.
|
|
||||||
err_t sys_mbox_trypost(sys_mbox_t mbox, void *msg)
|
|
||||||
{
|
|
||||||
err_t result;
|
|
||||||
|
|
||||||
if ( xQueueSend( mbox, &msg, 0 ) == pdPASS )
|
|
||||||
{
|
|
||||||
result = ERR_OK;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// could not post, queue must be full
|
|
||||||
result = ERR_MEM;
|
|
||||||
|
|
||||||
#if SYS_STATS
|
|
||||||
lwip_stats.sys.mbox.err++;
|
|
||||||
#endif /* SYS_STATS */
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------------*/
|
|
||||||
/*
|
|
||||||
Blocks the thread until a message arrives in the mailbox, but does
|
|
||||||
not block the thread longer than "timeout" milliseconds (similar to
|
|
||||||
the sys_arch_sem_wait() function). The "msg" argument is a result
|
|
||||||
parameter that is set by the function (i.e., by doing "*msg =
|
|
||||||
ptr"). The "msg" parameter maybe NULL to indicate that the message
|
|
||||||
should be dropped.
|
|
||||||
|
|
||||||
The return values are the same as for the sys_arch_sem_wait() function:
|
|
||||||
Number of milliseconds spent waiting or SYS_ARCH_TIMEOUT if there was a
|
|
||||||
timeout.
|
|
||||||
|
|
||||||
Note that a function with a similar name, sys_mbox_fetch(), is
|
|
||||||
implemented by lwIP.
|
|
||||||
*/
|
|
||||||
u32_t sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, u32_t timeout)
|
|
||||||
{
|
|
||||||
void *dummyptr;
|
|
||||||
portTickType StartTime, EndTime, Elapsed;
|
|
||||||
|
|
||||||
StartTime = xTaskGetTickCount();
|
|
||||||
|
|
||||||
if ( msg == NULL )
|
|
||||||
{
|
|
||||||
msg = &dummyptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( timeout != 0 )
|
|
||||||
{
|
|
||||||
if ( pdTRUE == xQueueReceive( mbox, &(*msg), timeout / portTICK_RATE_MS ) )
|
|
||||||
{
|
|
||||||
EndTime = xTaskGetTickCount();
|
|
||||||
Elapsed = (EndTime - StartTime) * portTICK_RATE_MS;
|
|
||||||
|
|
||||||
return ( Elapsed );
|
|
||||||
}
|
|
||||||
else // timed out blocking for message
|
|
||||||
{
|
|
||||||
*msg = NULL;
|
|
||||||
|
|
||||||
return SYS_ARCH_TIMEOUT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else // block forever for a message.
|
|
||||||
{
|
|
||||||
while( pdTRUE != xQueueReceive( mbox, &(*msg), portMAX_DELAY ) ){} // time is arbitrary
|
|
||||||
EndTime = xTaskGetTickCount();
|
|
||||||
Elapsed = (EndTime - StartTime) * portTICK_RATE_MS;
|
|
||||||
|
|
||||||
return ( Elapsed ); // return time blocked TODO test
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------------*/
|
|
||||||
/*
|
|
||||||
Similar to sys_arch_mbox_fetch, but if message is not ready immediately, we'll
|
|
||||||
return with SYS_MBOX_EMPTY. On success, 0 is returned.
|
|
||||||
*/
|
|
||||||
u32_t sys_arch_mbox_tryfetch(sys_mbox_t mbox, void **msg)
|
|
||||||
{
|
|
||||||
void *dummyptr;
|
|
||||||
|
|
||||||
if ( msg == NULL )
|
|
||||||
{
|
|
||||||
msg = &dummyptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( pdTRUE == xQueueReceive( mbox, &(*msg), 0 ) )
|
|
||||||
{
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return SYS_MBOX_EMPTY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------------*/
|
|
||||||
// Creates and returns a new semaphore. The "count" argument specifies
|
|
||||||
// the initial state of the semaphore.
|
|
||||||
sys_sem_t sys_sem_new(u8_t count)
|
|
||||||
{
|
|
||||||
xSemaphoreHandle xSemaphore;
|
|
||||||
|
|
||||||
vSemaphoreCreateBinary( xSemaphore );
|
|
||||||
|
|
||||||
if( xSemaphore == NULL )
|
|
||||||
{
|
|
||||||
|
|
||||||
#if SYS_STATS
|
|
||||||
++lwip_stats.sys.sem.err;
|
|
||||||
#endif /* SYS_STATS */
|
|
||||||
|
|
||||||
return SYS_SEM_NULL; // TODO need assert
|
|
||||||
}
|
|
||||||
|
|
||||||
if(count == 0) // Means it can't be taken
|
|
||||||
{
|
|
||||||
xSemaphoreTake(xSemaphore,1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if SYS_STATS
|
|
||||||
++lwip_stats.sys.sem.used;
|
|
||||||
if (lwip_stats.sys.sem.max < lwip_stats.sys.sem.used) {
|
|
||||||
lwip_stats.sys.sem.max = lwip_stats.sys.sem.used;
|
|
||||||
}
|
|
||||||
#endif /* SYS_STATS */
|
|
||||||
|
|
||||||
return xSemaphore;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------------*/
|
|
||||||
/*
|
|
||||||
Blocks the thread while waiting for the semaphore to be
|
|
||||||
signaled. If the "timeout" argument is non-zero, the thread should
|
|
||||||
only be blocked for the specified time (measured in
|
|
||||||
milliseconds).
|
|
||||||
|
|
||||||
If the timeout argument is non-zero, the return value is the number of
|
|
||||||
milliseconds spent waiting for the semaphore to be signaled. If the
|
|
||||||
semaphore wasn't signaled within the specified time, the return value is
|
|
||||||
SYS_ARCH_TIMEOUT. If the thread didn't have to wait for the semaphore
|
|
||||||
(i.e., it was already signaled), the function may return zero.
|
|
||||||
|
|
||||||
Notice that lwIP implements a function with a similar name,
|
|
||||||
sys_sem_wait(), that uses the sys_arch_sem_wait() function.
|
|
||||||
*/
|
|
||||||
u32_t sys_arch_sem_wait(sys_sem_t sem, u32_t timeout)
|
|
||||||
{
|
|
||||||
portTickType StartTime, EndTime, Elapsed;
|
|
||||||
|
|
||||||
StartTime = xTaskGetTickCount();
|
|
||||||
|
|
||||||
if( timeout != 0)
|
|
||||||
{
|
|
||||||
if( xSemaphoreTake( sem, timeout / portTICK_RATE_MS ) == pdTRUE )
|
|
||||||
{
|
|
||||||
EndTime = xTaskGetTickCount();
|
|
||||||
Elapsed = (EndTime - StartTime) * portTICK_RATE_MS;
|
|
||||||
|
|
||||||
return (Elapsed); // return time blocked TODO test
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return SYS_ARCH_TIMEOUT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else // must block without a timeout
|
|
||||||
{
|
|
||||||
while( xSemaphoreTake( sem, portMAX_DELAY ) != pdTRUE ){}
|
|
||||||
EndTime = xTaskGetTickCount();
|
|
||||||
Elapsed = (EndTime - StartTime) * portTICK_RATE_MS;
|
|
||||||
|
|
||||||
return ( Elapsed ); // return time blocked
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------------*/
|
|
||||||
// Signals a semaphore
|
|
||||||
void sys_sem_signal(sys_sem_t sem)
|
|
||||||
{
|
|
||||||
xSemaphoreGive( sem );
|
|
||||||
}
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------------*/
|
|
||||||
// Deallocates a semaphore
|
|
||||||
void sys_sem_free(sys_sem_t sem)
|
|
||||||
{
|
|
||||||
#if SYS_STATS
|
|
||||||
--lwip_stats.sys.sem.used;
|
|
||||||
#endif /* SYS_STATS */
|
|
||||||
|
|
||||||
vQueueDelete( sem );
|
|
||||||
}
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------------*/
|
|
||||||
// Initialize sys arch
|
|
||||||
void sys_init(void)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
// Initialize the the per-thread sys_timeouts structures
|
|
||||||
// make sure there are no valid pids in the list
|
|
||||||
for(i = 0; i < SYS_THREAD_MAX; i++)
|
|
||||||
{
|
|
||||||
s_timeoutlist[i].pid = 0;
|
|
||||||
s_timeoutlist[i].timeouts.next = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// keep track of how many threads have been created
|
|
||||||
s_nextthread = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------------*/
|
|
||||||
/*
|
|
||||||
Returns a pointer to the per-thread sys_timeouts structure. In lwIP,
|
|
||||||
each thread has a list of timeouts which is represented as a linked
|
|
||||||
list of sys_timeout structures. The sys_timeouts structure holds a
|
|
||||||
pointer to a linked list of timeouts. This function is called by
|
|
||||||
the lwIP timeout scheduler and must not return a NULL value.
|
|
||||||
|
|
||||||
In a single threaded sys_arch implementation, this function will
|
|
||||||
simply return a pointer to a global sys_timeouts variable stored in
|
|
||||||
the sys_arch module.
|
|
||||||
*/
|
|
||||||
struct sys_timeouts *sys_arch_timeouts(void)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
xTaskHandle pid;
|
|
||||||
struct timeoutlist *tl;
|
|
||||||
|
|
||||||
pid = xTaskGetCurrentTaskHandle();
|
|
||||||
|
|
||||||
for(i = 0; i < s_nextthread; i++)
|
|
||||||
{
|
|
||||||
tl = &(s_timeoutlist[i]);
|
|
||||||
if(tl->pid == pid)
|
|
||||||
{
|
|
||||||
return &(tl->timeouts);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Error
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------------*/
|
|
||||||
/*-----------------------------------------------------------------------------------*/
|
|
||||||
// TODO
|
|
||||||
/*-----------------------------------------------------------------------------------*/
|
|
||||||
/*
|
|
||||||
Starts a new thread with priority "prio" that will begin its execution in the
|
|
||||||
function "thread()". The "arg" argument will be passed as an argument to the
|
|
||||||
thread() function. The id of the new thread is returned. Both the id and
|
|
||||||
the priority are system dependent.
|
|
||||||
*/
|
|
||||||
sys_thread_t sys_thread_new(char *name, void (* thread)(void *arg), void *arg, int stacksize, int prio)
|
|
||||||
{
|
|
||||||
xTaskHandle CreatedTask;
|
|
||||||
int result;
|
|
||||||
|
|
||||||
if ( s_nextthread < SYS_THREAD_MAX )
|
|
||||||
{
|
|
||||||
vPortEnterCritical();
|
|
||||||
result = xTaskCreate( thread, ( const portCHAR * ) name, stacksize, arg, prio, &CreatedTask );
|
|
||||||
|
|
||||||
// For each task created, store the task handle (pid) in the timers array.
|
|
||||||
// This scheme doesn't allow for threads to be deleted
|
|
||||||
s_timeoutlist[s_nextthread++].pid = CreatedTask;
|
|
||||||
vPortExitCritical();
|
|
||||||
|
|
||||||
if(result == pdPASS)
|
|
||||||
{
|
|
||||||
return CreatedTask;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
This optional function does a "fast" critical region protection and returns
|
|
||||||
the previous protection level. This function is only called during very short
|
|
||||||
critical regions. An embedded system which supports ISR-based drivers might
|
|
||||||
want to implement this function by disabling interrupts. Task-based systems
|
|
||||||
might want to implement this by using a mutex or disabling tasking. This
|
|
||||||
function should support recursive calls from the same task or interrupt. In
|
|
||||||
other words, sys_arch_protect() could be called while already protected. In
|
|
||||||
that case the return value indicates that it is already protected.
|
|
||||||
|
|
||||||
sys_arch_protect() is only required if your port is supporting an operating
|
|
||||||
system.
|
|
||||||
*/
|
|
||||||
sys_prot_t sys_arch_protect(void)
|
|
||||||
{
|
|
||||||
vPortEnterCritical();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
This optional function does a "fast" set of critical region protection to the
|
|
||||||
value specified by pval. See the documentation for sys_arch_protect() for
|
|
||||||
more information. This function is only required if your port is supporting
|
|
||||||
an operating system.
|
|
||||||
*/
|
|
||||||
void sys_arch_unprotect(sys_prot_t pval)
|
|
||||||
{
|
|
||||||
( void ) pval;
|
|
||||||
vPortExitCritical();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Prints an assertion messages and aborts execution.
|
|
||||||
*/
|
|
||||||
void sys_assert( const char *msg )
|
|
||||||
{
|
|
||||||
( void ) msg;
|
|
||||||
/*FSL:only needed for debugging
|
|
||||||
printf(msg);
|
|
||||||
printf("\n\r");
|
|
||||||
*/
|
|
||||||
vPortEnterCritical( );
|
|
||||||
for(;;)
|
|
||||||
;
|
|
||||||
}
|
|
|
@ -1,66 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#ifndef __SYS_RTXC_H__
|
|
||||||
#define __SYS_RTXC_H__
|
|
||||||
|
|
||||||
#include "FreeRTOS.h"
|
|
||||||
#include "task.h"
|
|
||||||
#include "queue.h"
|
|
||||||
#include "semphr.h"
|
|
||||||
|
|
||||||
#define SYS_MBOX_NULL (xQueueHandle)0
|
|
||||||
#define SYS_SEM_NULL (xSemaphoreHandle)0
|
|
||||||
#define SYS_DEFAULT_THREAD_STACK_DEPTH configMINIMAL_STACK_SIZE
|
|
||||||
|
|
||||||
typedef xSemaphoreHandle sys_sem_t;
|
|
||||||
typedef xQueueHandle sys_mbox_t;
|
|
||||||
typedef xTaskHandle sys_thread_t;
|
|
||||||
|
|
||||||
typedef struct _sys_arch_state_t
|
|
||||||
{
|
|
||||||
// Task creation data.
|
|
||||||
char cTaskName[configMAX_TASK_NAME_LEN];
|
|
||||||
unsigned short nStackDepth;
|
|
||||||
unsigned short nTaskCount;
|
|
||||||
} sys_arch_state_t;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//extern sys_arch_state_t s_sys_arch_state;
|
|
||||||
|
|
||||||
//void sys_set_default_state();
|
|
||||||
//void sys_set_state(signed char *pTaskName, unsigned short nStackSize);
|
|
||||||
|
|
||||||
/* Message queue constants. */
|
|
||||||
#define archMESG_QUEUE_LENGTH ( 6 )
|
|
||||||
#endif /* __SYS_RTXC_H__ */
|
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if defined(__IAR_SYSTEMS_ICC__)
|
|
||||||
#pragma pack(1)
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -1,93 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#ifndef __CC_H__
|
|
||||||
#define __CC_H__
|
|
||||||
|
|
||||||
#include "cpu.h"
|
|
||||||
|
|
||||||
typedef unsigned char u8_t;
|
|
||||||
typedef signed char s8_t;
|
|
||||||
typedef unsigned short u16_t;
|
|
||||||
typedef signed short s16_t;
|
|
||||||
typedef unsigned long u32_t;
|
|
||||||
typedef signed long s32_t;
|
|
||||||
typedef u32_t mem_ptr_t;
|
|
||||||
typedef int sys_prot_t;
|
|
||||||
|
|
||||||
|
|
||||||
#define U16_F "hu"
|
|
||||||
#define S16_F "d"
|
|
||||||
#define X16_F "hx"
|
|
||||||
#define U32_F "u"
|
|
||||||
#define S32_F "d"
|
|
||||||
#define X32_F "x"
|
|
||||||
#define SZT_F "uz"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* define compiler specific symbols */
|
|
||||||
#if defined (__ICCARM__)
|
|
||||||
|
|
||||||
#define PACK_STRUCT_BEGIN
|
|
||||||
#define PACK_STRUCT_STRUCT
|
|
||||||
#define PACK_STRUCT_END
|
|
||||||
#define PACK_STRUCT_FIELD(x) x
|
|
||||||
#define PACK_STRUCT_USE_INCLUDES
|
|
||||||
|
|
||||||
#elif defined (__CC_ARM)
|
|
||||||
|
|
||||||
#define PACK_STRUCT_BEGIN __packed
|
|
||||||
#define PACK_STRUCT_STRUCT
|
|
||||||
#define PACK_STRUCT_END
|
|
||||||
#define PACK_STRUCT_FIELD(x) x
|
|
||||||
|
|
||||||
#elif defined (__GNUC__)
|
|
||||||
|
|
||||||
#define PACK_STRUCT_BEGIN
|
|
||||||
#define PACK_STRUCT_STRUCT __attribute__ ((__packed__))
|
|
||||||
#define PACK_STRUCT_END
|
|
||||||
#define PACK_STRUCT_FIELD(x) x
|
|
||||||
|
|
||||||
#elif defined (__TASKING__)
|
|
||||||
|
|
||||||
#define PACK_STRUCT_BEGIN
|
|
||||||
#define PACK_STRUCT_STRUCT
|
|
||||||
#define PACK_STRUCT_END
|
|
||||||
#define PACK_STRUCT_FIELD(x) x
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define LWIP_PLATFORM_ASSERT(x) //do { if(!(x)) while(1); } while(0)
|
|
||||||
|
|
||||||
#endif /* __CC_H__ */
|
|
|
@ -1,37 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#ifndef __CPU_H__
|
|
||||||
#define __CPU_H__
|
|
||||||
|
|
||||||
#define BYTE_ORDER LITTLE_ENDIAN
|
|
||||||
|
|
||||||
#endif /* __CPU_H__ */
|
|
|
@ -1,36 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if defined(__IAR_SYSTEMS_ICC__)
|
|
||||||
#pragma pack()
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -1,44 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#ifndef __ARCH_INIT_H__
|
|
||||||
#define __ARCH_INIT_H__
|
|
||||||
|
|
||||||
#define TCPIP_INIT_DONE(arg) tcpip_init_done(arg)
|
|
||||||
|
|
||||||
void tcpip_init_done(void *);
|
|
||||||
int wait_for_tcpip_init(void);
|
|
||||||
|
|
||||||
#endif /* __ARCH_INIT_H__ */
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#ifndef __LIB_H__
|
|
||||||
#define __LIB_H__
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* __LIB_H__ */
|
|
|
@ -1,38 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#ifndef __PERF_H__
|
|
||||||
#define __PERF_H__
|
|
||||||
|
|
||||||
#define PERF_START /* null definition */
|
|
||||||
#define PERF_STOP(x) /* null definition */
|
|
||||||
|
|
||||||
#endif /* __PERF_H__ */
|
|
|
@ -1,66 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#ifndef __SYS_RTXC_H__
|
|
||||||
#define __SYS_RTXC_H__
|
|
||||||
|
|
||||||
#include "FreeRTOS.h"
|
|
||||||
#include "task.h"
|
|
||||||
#include "queue.h"
|
|
||||||
#include "semphr.h"
|
|
||||||
|
|
||||||
#define SYS_MBOX_NULL (xQueueHandle)0
|
|
||||||
#define SYS_SEM_NULL (xSemaphoreHandle)0
|
|
||||||
#define SYS_DEFAULT_THREAD_STACK_DEPTH configMINIMAL_STACK_SIZE
|
|
||||||
|
|
||||||
typedef xSemaphoreHandle sys_sem_t;
|
|
||||||
typedef xQueueHandle sys_mbox_t;
|
|
||||||
typedef xTaskHandle sys_thread_t;
|
|
||||||
|
|
||||||
typedef struct _sys_arch_state_t
|
|
||||||
{
|
|
||||||
// Task creation data.
|
|
||||||
char cTaskName[configMAX_TASK_NAME_LEN];
|
|
||||||
unsigned short nStackDepth;
|
|
||||||
unsigned short nTaskCount;
|
|
||||||
} sys_arch_state_t;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//extern sys_arch_state_t s_sys_arch_state;
|
|
||||||
|
|
||||||
//void sys_set_default_state();
|
|
||||||
//void sys_set_state(signed char *pTaskName, unsigned short nStackSize);
|
|
||||||
|
|
||||||
/* Message queue constants. */
|
|
||||||
#define archMESG_QUEUE_LENGTH ( 6 )
|
|
||||||
#endif /* __SYS_RTXC_H__ */
|
|
||||||
|
|
|
@ -1,649 +0,0 @@
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
* Ethernet Interface Skeleton
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This file is a skeleton for developing Ethernet network interface
|
|
||||||
* drivers for lwIP. Add code to the low_level functions and do a
|
|
||||||
* search-and-replace for the word "ethernetif" to replace it with
|
|
||||||
* something that better describes your network interface.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "lwip/opt.h"
|
|
||||||
#include "lwip/def.h"
|
|
||||||
#include "lwip/mem.h"
|
|
||||||
#include "lwip/pbuf.h"
|
|
||||||
#include "lwip/sys.h"
|
|
||||||
#include "lwip/tcpip.h"
|
|
||||||
#include "lwip/icmp.h"
|
|
||||||
#include "netif/etharp.h"
|
|
||||||
#include "err.h"
|
|
||||||
#include "ethernetif.h"
|
|
||||||
#include "queue.h"
|
|
||||||
|
|
||||||
#include "main.h" // for the definition of CONFIG_WLAN
|
|
||||||
|
|
||||||
|
|
||||||
#if !CONFIG_WLAN
|
|
||||||
#include "stm32f2x7_eth.h"
|
|
||||||
#else
|
|
||||||
#include <lwip_intf.h>
|
|
||||||
#endif
|
|
||||||
#include <platform/platform_stdlib.h>
|
|
||||||
|
|
||||||
#ifdef CONFIG_DONT_CARE_TP
|
|
||||||
#define netifMTU (576)
|
|
||||||
#else
|
|
||||||
#define netifMTU (1500)
|
|
||||||
#endif
|
|
||||||
#define netifINTERFACE_TASK_STACK_SIZE ( 350 )
|
|
||||||
#define netifINTERFACE_TASK_PRIORITY ( configMAX_PRIORITIES - 1 )
|
|
||||||
#define netifGUARD_BLOCK_TIME ( 250 )
|
|
||||||
/* The time to block waiting for input. */
|
|
||||||
#define emacBLOCK_TIME_WAITING_FOR_INPUT ( ( portTickType ) 100 )
|
|
||||||
#define FAKE_PING_REPLY 0
|
|
||||||
|
|
||||||
#if !CONFIG_WLAN
|
|
||||||
/* Define those to better describe your network interface. */
|
|
||||||
#define IFNAME0 's'
|
|
||||||
#define IFNAME1 't'
|
|
||||||
|
|
||||||
static struct netif *s_pxNetIf = NULL;
|
|
||||||
xSemaphoreHandle s_xSemaphore = NULL;
|
|
||||||
|
|
||||||
|
|
||||||
/* Ethernet Rx & Tx DMA Descriptors */
|
|
||||||
extern ETH_DMADESCTypeDef DMARxDscrTab[ETH_RXBUFNB], DMATxDscrTab[ETH_TXBUFNB];
|
|
||||||
|
|
||||||
/* Ethernet Receive buffers */
|
|
||||||
extern uint8_t Rx_Buff[ETH_RXBUFNB][ETH_RX_BUF_SIZE];
|
|
||||||
|
|
||||||
/* Ethernet Transmit buffers */
|
|
||||||
extern uint8_t Tx_Buff[ETH_TXBUFNB][ETH_TX_BUF_SIZE];
|
|
||||||
|
|
||||||
/* Global pointers to track current transmit and receive descriptors */
|
|
||||||
extern ETH_DMADESCTypeDef *DMATxDescToSet;
|
|
||||||
extern ETH_DMADESCTypeDef *DMARxDescToGet;
|
|
||||||
|
|
||||||
/* Global pointer for last received frame infos */
|
|
||||||
extern ETH_DMA_Rx_Frame_infos *DMA_RX_FRAME_infos;
|
|
||||||
|
|
||||||
static void ethernetif_input( void * pvParameters );
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void arp_timer(void *arg);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* In this function, the hardware should be initialized.
|
|
||||||
* Called from ethernetif_init().
|
|
||||||
*
|
|
||||||
* @param netif the already initialized lwip network interface structure
|
|
||||||
* for this ethernetif
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void low_level_init(struct netif *netif)
|
|
||||||
{
|
|
||||||
|
|
||||||
/* set netif MAC hardware address length */
|
|
||||||
netif->hwaddr_len = ETHARP_HWADDR_LEN;
|
|
||||||
|
|
||||||
#if !CONFIG_WLAN
|
|
||||||
/* set netif MAC hardware address */
|
|
||||||
netif->hwaddr[0] = MAC_ADDR0;
|
|
||||||
netif->hwaddr[1] = MAC_ADDR1;
|
|
||||||
netif->hwaddr[2] = MAC_ADDR2;
|
|
||||||
netif->hwaddr[3] = MAC_ADDR3;
|
|
||||||
netif->hwaddr[4] = MAC_ADDR4;
|
|
||||||
netif->hwaddr[5] = MAC_ADDR5;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* set netif maximum transfer unit */
|
|
||||||
netif->mtu = netifMTU;
|
|
||||||
|
|
||||||
/* Accept broadcast address and ARP traffic */
|
|
||||||
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP;
|
|
||||||
|
|
||||||
#if !CONFIG_WLAN
|
|
||||||
s_pxNetIf =netif;
|
|
||||||
|
|
||||||
/* create binary semaphore used for informing ethernetif of frame reception */
|
|
||||||
if (s_xSemaphore == NULL)
|
|
||||||
{
|
|
||||||
s_xSemaphore= xSemaphoreCreateCounting(20,0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* initialize MAC address in ethernet MAC */
|
|
||||||
ETH_MACAddressConfig(ETH_MAC_Address0, netif->hwaddr);
|
|
||||||
|
|
||||||
/* Initialize Tx Descriptors list: Chain Mode */
|
|
||||||
ETH_DMATxDescChainInit(DMATxDscrTab, &Tx_Buff[0][0], ETH_TXBUFNB);
|
|
||||||
/* Initialize Rx Descriptors list: Chain Mode */
|
|
||||||
ETH_DMARxDescChainInit(DMARxDscrTab, &Rx_Buff[0][0], ETH_RXBUFNB);
|
|
||||||
|
|
||||||
/* Enable Ethernet Rx interrrupt */
|
|
||||||
{
|
|
||||||
uint32_t i;
|
|
||||||
for(i=0; i<ETH_RXBUFNB; i++)
|
|
||||||
{
|
|
||||||
ETH_DMARxDescReceiveITConfig(&DMARxDscrTab[i], ENABLE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef CHECKSUM_BY_HARDWARE
|
|
||||||
/* Enable the checksum insertion for the Tx frames */
|
|
||||||
{
|
|
||||||
uint32_t i;
|
|
||||||
for(i=0; i<ETH_TXBUFNB; i++)
|
|
||||||
{
|
|
||||||
ETH_DMATxDescChecksumInsertionConfig(&DMATxDscrTab[i], ETH_DMATxDesc_ChecksumTCPUDPICMPFull);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* create the task that handles the ETH_MAC */
|
|
||||||
xTaskCreate(ethernetif_input, (signed char*) "Eth_if", netifINTERFACE_TASK_STACK_SIZE, NULL,
|
|
||||||
netifINTERFACE_TASK_PRIORITY,NULL);
|
|
||||||
|
|
||||||
/* Enable MAC and DMA transmission and reception */
|
|
||||||
ETH_Start();
|
|
||||||
#else //#if !CONFIG_WLAN
|
|
||||||
/* WLAN interface is initialized later */
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#if FAKE_PING_REPLY
|
|
||||||
void fake_arp_reply(struct netif *netif, struct pbuf *p)
|
|
||||||
{
|
|
||||||
struct pbuf *q, *tq, *tp;
|
|
||||||
int q_len, p_len;
|
|
||||||
struct eth_hdr *p_eth, *q_eth;
|
|
||||||
struct etharp_hdr *p_arp, *q_arp;
|
|
||||||
struct eth_addr fake_src_mac = {0xb0, 0x48, 0x7a, 0xfe, 0xea, 0xe0};
|
|
||||||
|
|
||||||
// Allocate buffer to store received packet
|
|
||||||
q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_POOL);
|
|
||||||
if (p == NULL) {
|
|
||||||
printf("\n\rCannot allocate pbuf to receive packet");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (tq = q, tp = p, q_len = tq->len; tp != NULL ; tp = tp->next)
|
|
||||||
{
|
|
||||||
p_len = tp->len;
|
|
||||||
while(p_len)
|
|
||||||
{
|
|
||||||
if(q_len > p_len) {
|
|
||||||
memcpy((char*)tq->payload + (tq->len - q_len), (char*)tp->payload + (tp->len - p_len), p_len);
|
|
||||||
q_len -= p_len;
|
|
||||||
p_len = 0;
|
|
||||||
}else{
|
|
||||||
memcpy((char*)tq->payload + (tq->len - q_len), (char*)tp->payload + (tp->len - p_len), q_len);
|
|
||||||
p_len -= q_len;
|
|
||||||
tq = tq->next;
|
|
||||||
q_len = tq->len;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
p_eth = (struct eth_hdr *)p->payload;
|
|
||||||
q_eth = (struct eth_hdr *)q->payload;
|
|
||||||
p_arp = (struct etharp_hdr *)((char*)(p->payload) + sizeof(struct eth_hdr));
|
|
||||||
q_arp = (struct etharp_hdr *)((char*)(q->payload) + sizeof(struct eth_hdr));
|
|
||||||
|
|
||||||
q_eth->dest = p_eth->src;
|
|
||||||
q_eth->src = fake_src_mac;
|
|
||||||
q_arp->opcode = htons(ARP_REPLY);
|
|
||||||
q_arp->shwaddr = fake_src_mac;
|
|
||||||
q_arp->sipaddr = p_arp->dipaddr;
|
|
||||||
q_arp->dhwaddr = p_eth->src;
|
|
||||||
q_arp->dipaddr = p_arp->sipaddr;
|
|
||||||
|
|
||||||
if(0){
|
|
||||||
int i;
|
|
||||||
char *buf = q->payload;
|
|
||||||
printf("\n\r");
|
|
||||||
for(i=0;i<q->tot_len;i++)
|
|
||||||
printf("0x%02x, ", buf[i]);
|
|
||||||
printf("\n\r");
|
|
||||||
}
|
|
||||||
if (ERR_OK != netif->input(q, netif)){
|
|
||||||
printf("\n\rfake_arp_reply input error");
|
|
||||||
pbuf_free(q);
|
|
||||||
}else
|
|
||||||
printf("\n\rfake arp reply \n\r");
|
|
||||||
}
|
|
||||||
|
|
||||||
void fake_echo_reply(struct netif *netif, struct pbuf *p)
|
|
||||||
{
|
|
||||||
struct pbuf *q, *tq, *tp;
|
|
||||||
int q_len, p_len;
|
|
||||||
struct eth_hdr *p_eth, *q_eth;
|
|
||||||
struct ip_hdr *p_ip, *q_ip;
|
|
||||||
struct icmp_echo_hdr *p_echo, *q_echo;
|
|
||||||
|
|
||||||
// Allocate buffer to store received packet
|
|
||||||
q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_POOL);
|
|
||||||
if (p == NULL) {
|
|
||||||
printf("\n\rCannot allocate pbuf to receive packet");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (tq = q, tp = p, q_len = tq->len; tp != NULL ; tp = tp->next)
|
|
||||||
{
|
|
||||||
p_len = tp->len;
|
|
||||||
while(p_len)
|
|
||||||
{
|
|
||||||
if(q_len > p_len) {
|
|
||||||
memcpy((char*)tq->payload + (tq->len - q_len), (char*)tp->payload + (tp->len - p_len), p_len);
|
|
||||||
q_len -= p_len;
|
|
||||||
p_len = 0;
|
|
||||||
}else{
|
|
||||||
memcpy((char*)tq->payload + (tq->len - q_len), (char*)tp->payload + (tp->len - p_len), q_len);
|
|
||||||
p_len -= q_len;
|
|
||||||
tq = tq->next;
|
|
||||||
q_len = tq->len;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
p_eth = (struct eth_hdr *)p->payload;
|
|
||||||
q_eth = (struct eth_hdr *)q->payload;
|
|
||||||
p_ip = (struct ip_hdr *)((char*)(p->payload) + sizeof(struct eth_hdr));
|
|
||||||
q_ip = (struct ip_hdr *)((char*)(q->payload) + sizeof(struct eth_hdr));
|
|
||||||
p_echo = (struct icmp_echo_hdr *)((char*)(p->payload) + sizeof(struct eth_hdr) + sizeof(struct ip_hdr));
|
|
||||||
q_echo = (struct icmp_echo_hdr *)((char*)(q->payload) + sizeof(struct eth_hdr) + sizeof(struct ip_hdr));
|
|
||||||
|
|
||||||
q_eth->dest = p_eth->src;
|
|
||||||
q_eth->src = p_eth->dest;
|
|
||||||
q_ip->src.addr = p_ip->dest.addr;
|
|
||||||
q_ip->dest.addr = p_ip->src.addr;
|
|
||||||
q_ip->_chksum = 0;
|
|
||||||
q_ip->_chksum = inet_chksum(q_ip, sizeof(struct ip_hdr));
|
|
||||||
q_echo->type = ICMP_ER;
|
|
||||||
q_echo->code = 0;
|
|
||||||
q_echo->chksum = 0;
|
|
||||||
q_echo->chksum = inet_chksum(q_echo, q->tot_len - sizeof(struct eth_hdr) - sizeof(struct ip_hdr));
|
|
||||||
|
|
||||||
if(0){
|
|
||||||
int i;
|
|
||||||
char *buf = q->payload;
|
|
||||||
printf("\n\r");
|
|
||||||
for(i=0;i<q->tot_len;i++)
|
|
||||||
printf("0x%02x, ", buf[i]);
|
|
||||||
printf("\n\r");
|
|
||||||
}
|
|
||||||
if (ERR_OK != netif->input(q, netif)){
|
|
||||||
printf("\n\rfake_echo_reply input error");
|
|
||||||
pbuf_free(q);
|
|
||||||
}else
|
|
||||||
printf("\n\rfake echo reply \n\r");
|
|
||||||
}
|
|
||||||
#endif // #if FAKE_PING_REPLY
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This function should do the actual transmission of the packet. The packet is
|
|
||||||
* contained in the pbuf that is passed to the function. This pbuf
|
|
||||||
* might be chained.
|
|
||||||
*
|
|
||||||
* @param netif the lwip network interface structure for this ethernetif
|
|
||||||
* @param p the MAC packet to send (e.g. IP packet including MAC addresses and type)
|
|
||||||
* @return ERR_OK if the packet could be sent
|
|
||||||
* an err_t value if the packet couldn't be sent
|
|
||||||
*
|
|
||||||
* @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to
|
|
||||||
* strange results. You might consider waiting for space in the DMA queue
|
|
||||||
* to become availale since the stack doesn't retry to send a packet
|
|
||||||
* dropped because of memory failure (except for the TCP timers).
|
|
||||||
*/
|
|
||||||
|
|
||||||
static err_t low_level_output(struct netif *netif, struct pbuf *p)
|
|
||||||
{
|
|
||||||
#if !CONFIG_WLAN
|
|
||||||
static xSemaphoreHandle xTxSemaphore = NULL;
|
|
||||||
struct pbuf *q;
|
|
||||||
uint32_t l = 0;
|
|
||||||
u8 *buffer ;
|
|
||||||
|
|
||||||
if (xTxSemaphore == NULL)
|
|
||||||
{
|
|
||||||
vSemaphoreCreateBinary (xTxSemaphore);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (xSemaphoreTake(xTxSemaphore, netifGUARD_BLOCK_TIME))
|
|
||||||
{
|
|
||||||
buffer = (u8 *)(DMATxDescToSet->Buffer1Addr);
|
|
||||||
for(q = p; q != NULL; q = q->next)
|
|
||||||
{
|
|
||||||
memcpy((u8_t*)&buffer[l], q->payload, q->len);
|
|
||||||
l = l + q->len;
|
|
||||||
}
|
|
||||||
ETH_Prepare_Transmit_Descriptors(l);
|
|
||||||
xSemaphoreGive(xTxSemaphore);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
/* Refer to eCos lwip eth_drv_send() */
|
|
||||||
struct eth_drv_sg sg_list[MAX_ETH_DRV_SG];
|
|
||||||
int sg_len = 0;
|
|
||||||
struct pbuf *q;
|
|
||||||
|
|
||||||
if(!rltk_wlan_running(netif_get_idx(netif)))
|
|
||||||
return ERR_IF;
|
|
||||||
|
|
||||||
for (q = p; q != NULL && sg_len < MAX_ETH_DRV_SG; q = q->next) {
|
|
||||||
sg_list[sg_len].buf = (unsigned int) q->payload;
|
|
||||||
sg_list[sg_len++].len = q->len;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if FAKE_PING_REPLY
|
|
||||||
{
|
|
||||||
char *header = p->payload;
|
|
||||||
if(header[12] == 0x08 && header[13] == 0x06)
|
|
||||||
{ // arp packet
|
|
||||||
if(header[21] == 0x01)
|
|
||||||
{ // arp request packet
|
|
||||||
printf("\n\rfake_ping: arp request packet.");
|
|
||||||
if(0)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
printf("\n\r");
|
|
||||||
for (q = p; q != NULL; q = q->next)
|
|
||||||
{
|
|
||||||
char *buf = q->payload;
|
|
||||||
for(i=0;i<q->len;i++)
|
|
||||||
printf("0x%02x, ", buf[i]);
|
|
||||||
}
|
|
||||||
printf("\n\r");
|
|
||||||
}
|
|
||||||
fake_arp_reply(netif, p);
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
|
||||||
}else if(header[12] == 0x08 && header[13] == 0x00)
|
|
||||||
{ // ip packet
|
|
||||||
if(header[15] == 0x00 && header[23] == 0x01)
|
|
||||||
{ // icmp packet
|
|
||||||
printf("\n\rfake_ping: icmp packet.");
|
|
||||||
if(0){
|
|
||||||
int i;
|
|
||||||
printf("\n\r");
|
|
||||||
for (q = p; q != NULL; q = q->next)
|
|
||||||
{
|
|
||||||
char *buf = q->payload;
|
|
||||||
for(i=0;i<q->len;i++)
|
|
||||||
printf("0x%02x, ", buf[i]);
|
|
||||||
}
|
|
||||||
printf("\n\r");
|
|
||||||
}
|
|
||||||
fake_echo_reply(netif, p);
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif // #if FAKE_PING_REPLY
|
|
||||||
if (sg_len)
|
|
||||||
rltk_wlan_send(netif_get_idx(netif), sg_list, sg_len, p->tot_len);
|
|
||||||
#endif // #if !CONFIG_WLAN
|
|
||||||
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#if !CONFIG_WLAN
|
|
||||||
/**
|
|
||||||
* Should allocate a pbuf and transfer the bytes of the incoming
|
|
||||||
* packet from the interface into the pbuf.
|
|
||||||
*
|
|
||||||
* @param netif the lwip network interface structure for this ethernetif
|
|
||||||
* @return a pbuf filled with the received packet (including MAC header)
|
|
||||||
* NULL on memory error
|
|
||||||
*/
|
|
||||||
static struct pbuf * low_level_input(struct netif *netif)
|
|
||||||
{
|
|
||||||
struct pbuf *p, *q;
|
|
||||||
u16_t len;
|
|
||||||
uint32_t l=0,i =0;
|
|
||||||
FrameTypeDef frame;
|
|
||||||
u8 *buffer;
|
|
||||||
__IO ETH_DMADESCTypeDef *DMARxNextDesc;
|
|
||||||
|
|
||||||
p = NULL;
|
|
||||||
|
|
||||||
/* Get received frame */
|
|
||||||
frame = ETH_Get_Received_Frame_interrupt();
|
|
||||||
|
|
||||||
/* check that frame has no error */
|
|
||||||
if ((frame.descriptor->Status & ETH_DMARxDesc_ES) == (uint32_t)RESET)
|
|
||||||
{
|
|
||||||
|
|
||||||
/* Obtain the size of the packet and put it into the "len" variable. */
|
|
||||||
len = frame.length;
|
|
||||||
buffer = (u8 *)frame.buffer;
|
|
||||||
|
|
||||||
/* We allocate a pbuf chain of pbufs from the pool. */
|
|
||||||
p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
|
|
||||||
|
|
||||||
/* Copy received frame from ethernet driver buffer to stack buffer */
|
|
||||||
if (p != NULL)
|
|
||||||
{
|
|
||||||
for (q = p; q != NULL; q = q->next)
|
|
||||||
{
|
|
||||||
memcpy((u8_t*)q->payload, (u8_t*)&buffer[l], q->len);
|
|
||||||
l = l + q->len;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Release descriptors to DMA */
|
|
||||||
/* Check if received frame with multiple DMA buffer segments */
|
|
||||||
if (DMA_RX_FRAME_infos->Seg_Count > 1)
|
|
||||||
{
|
|
||||||
DMARxNextDesc = DMA_RX_FRAME_infos->FS_Rx_Desc;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DMARxNextDesc = frame.descriptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set Own bit in Rx descriptors: gives the buffers back to DMA */
|
|
||||||
for (i=0; i<DMA_RX_FRAME_infos->Seg_Count; i++)
|
|
||||||
{
|
|
||||||
DMARxNextDesc->Status = ETH_DMARxDesc_OWN;
|
|
||||||
DMARxNextDesc = (ETH_DMADESCTypeDef *)(DMARxNextDesc->Buffer2NextDescAddr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Clear Segment_Count */
|
|
||||||
DMA_RX_FRAME_infos->Seg_Count =0;
|
|
||||||
|
|
||||||
|
|
||||||
/* When Rx Buffer unavailable flag is set: clear it and resume reception */
|
|
||||||
if ((ETH->DMASR & ETH_DMASR_RBUS) != (u32)RESET)
|
|
||||||
{
|
|
||||||
/* Clear RBUS ETHERNET DMA flag */
|
|
||||||
ETH->DMASR = ETH_DMASR_RBUS;
|
|
||||||
|
|
||||||
/* Resume DMA reception */
|
|
||||||
ETH->DMARPDR = 0;
|
|
||||||
}
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This function is the ethernetif_input task, it is processed when a packet
|
|
||||||
* is ready to be read from the interface. It uses the function low_level_input()
|
|
||||||
* that should handle the actual reception of bytes from the network
|
|
||||||
* interface. Then the type of the received packet is determined and
|
|
||||||
* the appropriate input function is called.
|
|
||||||
*
|
|
||||||
* @param netif the lwip network interface structure for this ethernetif
|
|
||||||
*/
|
|
||||||
void ethernetif_input( void * pvParameters )
|
|
||||||
{
|
|
||||||
struct pbuf *p;
|
|
||||||
|
|
||||||
for( ;; )
|
|
||||||
{
|
|
||||||
if (xSemaphoreTake( s_xSemaphore, emacBLOCK_TIME_WAITING_FOR_INPUT)==pdTRUE)
|
|
||||||
{
|
|
||||||
p = low_level_input( s_pxNetIf );
|
|
||||||
if (ERR_OK != s_pxNetIf->input( p, s_pxNetIf))
|
|
||||||
{
|
|
||||||
pbuf_free(p);
|
|
||||||
p=NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Refer to eCos eth_drv_recv to do similarly in ethernetif_input */
|
|
||||||
void ethernetif_recv(struct netif *netif, int total_len)
|
|
||||||
{
|
|
||||||
#if CONFIG_WLAN
|
|
||||||
struct eth_drv_sg sg_list[MAX_ETH_DRV_SG];
|
|
||||||
struct pbuf *p, *q;
|
|
||||||
int sg_len = 0;
|
|
||||||
|
|
||||||
if(!rltk_wlan_running(netif_get_idx(netif)))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if ((total_len > MAX_ETH_MSG) || (total_len < 0))
|
|
||||||
total_len = MAX_ETH_MSG;
|
|
||||||
|
|
||||||
// Allocate buffer to store received packet
|
|
||||||
p = pbuf_alloc(PBUF_RAW, total_len, PBUF_POOL);
|
|
||||||
if (p == NULL) {
|
|
||||||
printf("\n\rCannot allocate pbuf to receive packet");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create scatter list
|
|
||||||
for (q = p; q != NULL && sg_len < MAX_ETH_DRV_SG; q = q->next) {
|
|
||||||
sg_list[sg_len].buf = (unsigned int) q->payload;
|
|
||||||
sg_list[sg_len++].len = q->len;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy received packet to scatter list from wrapper rx skb
|
|
||||||
//printf("\n\rwlan:%c: Recv sg_len: %d, tot_len:%d", netif->name[1],sg_len, total_len);
|
|
||||||
rltk_wlan_recv(netif_get_idx(netif), sg_list, sg_len);
|
|
||||||
|
|
||||||
// Pass received packet to the interface
|
|
||||||
if (ERR_OK != netif->input(p, netif))
|
|
||||||
pbuf_free(p);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Should be called at the beginning of the program to set up the
|
|
||||||
* network interface. It calls the function low_level_init() to do the
|
|
||||||
* actual setup of the hardware.
|
|
||||||
*
|
|
||||||
* This function should be passed as a parameter to netif_add().
|
|
||||||
*
|
|
||||||
* @param netif the lwip network interface structure for this ethernetif
|
|
||||||
* @return ERR_OK if the loopif is initialized
|
|
||||||
* ERR_MEM if private data couldn't be allocated
|
|
||||||
* any other err_t on error
|
|
||||||
*/
|
|
||||||
err_t ethernetif_init(struct netif *netif)
|
|
||||||
{
|
|
||||||
LWIP_ASSERT("netif != NULL", (netif != NULL));
|
|
||||||
|
|
||||||
#if !CONFIG_WLAN
|
|
||||||
/* ethernet */
|
|
||||||
netif->name[0] = IFNAME0;
|
|
||||||
netif->name[1] = IFNAME1;
|
|
||||||
#else
|
|
||||||
/* wlan interface*/
|
|
||||||
#if LWIP_NETIF_HOSTNAME
|
|
||||||
/* Initialize interface hostname */
|
|
||||||
if(netif->name[1] == '0')
|
|
||||||
netif->hostname = "lwip0";
|
|
||||||
else if(netif->name[1] == '1')
|
|
||||||
netif->hostname = "lwip1";
|
|
||||||
#endif /* LWIP_NETIF_HOSTNAME */
|
|
||||||
|
|
||||||
#endif // WLAN
|
|
||||||
netif->output = etharp_output;
|
|
||||||
netif->linkoutput = low_level_output;
|
|
||||||
|
|
||||||
/* initialize the hardware */
|
|
||||||
low_level_init(netif);
|
|
||||||
|
|
||||||
etharp_init();
|
|
||||||
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void arp_timer(void *arg)
|
|
||||||
{
|
|
||||||
etharp_tmr();
|
|
||||||
sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* For FreeRTOS tickless
|
|
||||||
*/
|
|
||||||
int lwip_tickless_used = 0;
|
|
||||||
|
|
||||||
int arp_timeout_exist(void)
|
|
||||||
{
|
|
||||||
struct sys_timeouts *timeouts;
|
|
||||||
struct sys_timeo *t;
|
|
||||||
|
|
||||||
timeouts = sys_arch_timeouts();
|
|
||||||
|
|
||||||
for(t = timeouts->next; t != NULL;t = t->next)
|
|
||||||
if(t->h == arp_timer)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Called by rltk_wlan_PRE_SLEEP_PROCESSING()
|
|
||||||
void lwip_PRE_SLEEP_PROCESSING(void)
|
|
||||||
{
|
|
||||||
if(arp_timeout_exist()) {
|
|
||||||
tcpip_untimeout(arp_timer, NULL);
|
|
||||||
}
|
|
||||||
lwip_tickless_used = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Called in ips_leave() path, support tickless when wifi power wakeup due to ioctl or deinit
|
|
||||||
void lwip_POST_SLEEP_PROCESSING(void)
|
|
||||||
{
|
|
||||||
if(lwip_tickless_used) {
|
|
||||||
tcpip_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
#ifndef __ETHERNETIF_H__
|
|
||||||
#define __ETHERNETIF_H__
|
|
||||||
|
|
||||||
|
|
||||||
#include "lwip/err.h"
|
|
||||||
#include "lwip/netif.h"
|
|
||||||
|
|
||||||
void ethernetif_recv(struct netif *netif, int total_len);
|
|
||||||
err_t ethernetif_init(struct netif *netif);
|
|
||||||
void lwip_PRE_SLEEP_PROCESSING(void);
|
|
||||||
void lwip_POST_SLEEP_PROCESSING(void);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,446 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* lwIP includes. */
|
|
||||||
#include "lwip/debug.h"
|
|
||||||
#include "lwip/def.h"
|
|
||||||
#include "lwip/sys.h"
|
|
||||||
#include "lwip/mem.h"
|
|
||||||
#include "lwip/stats.h"
|
|
||||||
#include "FreeRTOS.h"
|
|
||||||
#include "task.h"
|
|
||||||
#include "queue.h"
|
|
||||||
|
|
||||||
xTaskHandle xTaskGetCurrentTaskHandle( void ) PRIVILEGED_FUNCTION;
|
|
||||||
|
|
||||||
struct timeoutlist
|
|
||||||
{
|
|
||||||
struct sys_timeouts timeouts;
|
|
||||||
xTaskHandle pid;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* This is the number of threads that can be started with sys_thread_new() */
|
|
||||||
#define SYS_THREAD_MAX 6
|
|
||||||
|
|
||||||
static struct timeoutlist s_timeoutlist[SYS_THREAD_MAX];
|
|
||||||
static u16_t s_nextthread = 0;
|
|
||||||
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------------*/
|
|
||||||
// Creates an empty mailbox.
|
|
||||||
sys_mbox_t sys_mbox_new(int size)
|
|
||||||
{
|
|
||||||
xQueueHandle mbox;
|
|
||||||
|
|
||||||
( void ) size;
|
|
||||||
|
|
||||||
mbox = xQueueCreate( archMESG_QUEUE_LENGTH, sizeof( void * ) );
|
|
||||||
|
|
||||||
#if SYS_STATS
|
|
||||||
++lwip_stats.sys.mbox.used;
|
|
||||||
if (lwip_stats.sys.mbox.max < lwip_stats.sys.mbox.used) {
|
|
||||||
lwip_stats.sys.mbox.max = lwip_stats.sys.mbox.used;
|
|
||||||
}
|
|
||||||
#endif /* SYS_STATS */
|
|
||||||
|
|
||||||
return mbox;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------------*/
|
|
||||||
/*
|
|
||||||
Deallocates a mailbox. If there are messages still present in the
|
|
||||||
mailbox when the mailbox is deallocated, it is an indication of a
|
|
||||||
programming error in lwIP and the developer should be notified.
|
|
||||||
*/
|
|
||||||
void sys_mbox_free(sys_mbox_t mbox)
|
|
||||||
{
|
|
||||||
if( uxQueueMessagesWaiting( mbox ) )
|
|
||||||
{
|
|
||||||
/* Line for breakpoint. Should never break here! */
|
|
||||||
portNOP();
|
|
||||||
#if SYS_STATS
|
|
||||||
lwip_stats.sys.mbox.err++;
|
|
||||||
#endif /* SYS_STATS */
|
|
||||||
|
|
||||||
// TODO notify the user of failure.
|
|
||||||
}
|
|
||||||
|
|
||||||
vQueueDelete( mbox );
|
|
||||||
|
|
||||||
#if SYS_STATS
|
|
||||||
--lwip_stats.sys.mbox.used;
|
|
||||||
#endif /* SYS_STATS */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------------*/
|
|
||||||
// Posts the "msg" to the mailbox.
|
|
||||||
void sys_mbox_post(sys_mbox_t mbox, void *data)
|
|
||||||
{
|
|
||||||
while ( xQueueSendToBack(mbox, &data, portMAX_DELAY ) != pdTRUE ){}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------------*/
|
|
||||||
// Try to post the "msg" to the mailbox.
|
|
||||||
err_t sys_mbox_trypost(sys_mbox_t mbox, void *msg)
|
|
||||||
{
|
|
||||||
err_t result;
|
|
||||||
|
|
||||||
if ( xQueueSend( mbox, &msg, 0 ) == pdPASS )
|
|
||||||
{
|
|
||||||
result = ERR_OK;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// could not post, queue must be full
|
|
||||||
result = ERR_MEM;
|
|
||||||
|
|
||||||
#if SYS_STATS
|
|
||||||
lwip_stats.sys.mbox.err++;
|
|
||||||
#endif /* SYS_STATS */
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------------*/
|
|
||||||
/*
|
|
||||||
Blocks the thread until a message arrives in the mailbox, but does
|
|
||||||
not block the thread longer than "timeout" milliseconds (similar to
|
|
||||||
the sys_arch_sem_wait() function). The "msg" argument is a result
|
|
||||||
parameter that is set by the function (i.e., by doing "*msg =
|
|
||||||
ptr"). The "msg" parameter maybe NULL to indicate that the message
|
|
||||||
should be dropped.
|
|
||||||
|
|
||||||
The return values are the same as for the sys_arch_sem_wait() function:
|
|
||||||
Number of milliseconds spent waiting or SYS_ARCH_TIMEOUT if there was a
|
|
||||||
timeout.
|
|
||||||
|
|
||||||
Note that a function with a similar name, sys_mbox_fetch(), is
|
|
||||||
implemented by lwIP.
|
|
||||||
*/
|
|
||||||
u32_t sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, u32_t timeout)
|
|
||||||
{
|
|
||||||
void *dummyptr;
|
|
||||||
portTickType StartTime, EndTime, Elapsed;
|
|
||||||
|
|
||||||
StartTime = xTaskGetTickCount();
|
|
||||||
|
|
||||||
if ( msg == NULL )
|
|
||||||
{
|
|
||||||
msg = &dummyptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( timeout != 0 )
|
|
||||||
{
|
|
||||||
if ( pdTRUE == xQueueReceive( mbox, &(*msg), timeout / portTICK_RATE_MS ) )
|
|
||||||
{
|
|
||||||
EndTime = xTaskGetTickCount();
|
|
||||||
Elapsed = (EndTime - StartTime) * portTICK_RATE_MS;
|
|
||||||
|
|
||||||
return ( Elapsed );
|
|
||||||
}
|
|
||||||
else // timed out blocking for message
|
|
||||||
{
|
|
||||||
*msg = NULL;
|
|
||||||
|
|
||||||
return SYS_ARCH_TIMEOUT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else // block forever for a message.
|
|
||||||
{
|
|
||||||
while( pdTRUE != xQueueReceive( mbox, &(*msg), portMAX_DELAY ) ){} // time is arbitrary
|
|
||||||
EndTime = xTaskGetTickCount();
|
|
||||||
Elapsed = (EndTime - StartTime) * portTICK_RATE_MS;
|
|
||||||
|
|
||||||
return ( Elapsed ); // return time blocked TODO test
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------------*/
|
|
||||||
/*
|
|
||||||
Similar to sys_arch_mbox_fetch, but if message is not ready immediately, we'll
|
|
||||||
return with SYS_MBOX_EMPTY. On success, 0 is returned.
|
|
||||||
*/
|
|
||||||
u32_t sys_arch_mbox_tryfetch(sys_mbox_t mbox, void **msg)
|
|
||||||
{
|
|
||||||
void *dummyptr;
|
|
||||||
|
|
||||||
if ( msg == NULL )
|
|
||||||
{
|
|
||||||
msg = &dummyptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( pdTRUE == xQueueReceive( mbox, &(*msg), 0 ) )
|
|
||||||
{
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return SYS_MBOX_EMPTY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------------*/
|
|
||||||
// Creates and returns a new semaphore. The "count" argument specifies
|
|
||||||
// the initial state of the semaphore.
|
|
||||||
sys_sem_t sys_sem_new(u8_t count)
|
|
||||||
{
|
|
||||||
xSemaphoreHandle xSemaphore;
|
|
||||||
|
|
||||||
vSemaphoreCreateBinary( xSemaphore );
|
|
||||||
|
|
||||||
if( xSemaphore == NULL )
|
|
||||||
{
|
|
||||||
|
|
||||||
#if SYS_STATS
|
|
||||||
++lwip_stats.sys.sem.err;
|
|
||||||
#endif /* SYS_STATS */
|
|
||||||
|
|
||||||
return SYS_SEM_NULL; // TODO need assert
|
|
||||||
}
|
|
||||||
|
|
||||||
if(count == 0) // Means it can't be taken
|
|
||||||
{
|
|
||||||
xSemaphoreTake(xSemaphore,1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if SYS_STATS
|
|
||||||
++lwip_stats.sys.sem.used;
|
|
||||||
if (lwip_stats.sys.sem.max < lwip_stats.sys.sem.used) {
|
|
||||||
lwip_stats.sys.sem.max = lwip_stats.sys.sem.used;
|
|
||||||
}
|
|
||||||
#endif /* SYS_STATS */
|
|
||||||
|
|
||||||
return xSemaphore;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------------*/
|
|
||||||
/*
|
|
||||||
Blocks the thread while waiting for the semaphore to be
|
|
||||||
signaled. If the "timeout" argument is non-zero, the thread should
|
|
||||||
only be blocked for the specified time (measured in
|
|
||||||
milliseconds).
|
|
||||||
|
|
||||||
If the timeout argument is non-zero, the return value is the number of
|
|
||||||
milliseconds spent waiting for the semaphore to be signaled. If the
|
|
||||||
semaphore wasn't signaled within the specified time, the return value is
|
|
||||||
SYS_ARCH_TIMEOUT. If the thread didn't have to wait for the semaphore
|
|
||||||
(i.e., it was already signaled), the function may return zero.
|
|
||||||
|
|
||||||
Notice that lwIP implements a function with a similar name,
|
|
||||||
sys_sem_wait(), that uses the sys_arch_sem_wait() function.
|
|
||||||
*/
|
|
||||||
u32_t sys_arch_sem_wait(sys_sem_t sem, u32_t timeout)
|
|
||||||
{
|
|
||||||
portTickType StartTime, EndTime, Elapsed;
|
|
||||||
|
|
||||||
StartTime = xTaskGetTickCount();
|
|
||||||
|
|
||||||
if( timeout != 0)
|
|
||||||
{
|
|
||||||
if( xSemaphoreTake( sem, timeout / portTICK_RATE_MS ) == pdTRUE )
|
|
||||||
{
|
|
||||||
EndTime = xTaskGetTickCount();
|
|
||||||
Elapsed = (EndTime - StartTime) * portTICK_RATE_MS;
|
|
||||||
|
|
||||||
return (Elapsed); // return time blocked TODO test
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return SYS_ARCH_TIMEOUT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else // must block without a timeout
|
|
||||||
{
|
|
||||||
while( xSemaphoreTake( sem, portMAX_DELAY ) != pdTRUE ){}
|
|
||||||
EndTime = xTaskGetTickCount();
|
|
||||||
Elapsed = (EndTime - StartTime) * portTICK_RATE_MS;
|
|
||||||
|
|
||||||
return ( Elapsed ); // return time blocked
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------------*/
|
|
||||||
// Signals a semaphore
|
|
||||||
void sys_sem_signal(sys_sem_t sem)
|
|
||||||
{
|
|
||||||
xSemaphoreGive( sem );
|
|
||||||
}
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------------*/
|
|
||||||
// Deallocates a semaphore
|
|
||||||
void sys_sem_free(sys_sem_t sem)
|
|
||||||
{
|
|
||||||
#if SYS_STATS
|
|
||||||
--lwip_stats.sys.sem.used;
|
|
||||||
#endif /* SYS_STATS */
|
|
||||||
|
|
||||||
vQueueDelete( sem );
|
|
||||||
}
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------------*/
|
|
||||||
// Initialize sys arch
|
|
||||||
void sys_init(void)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
// Initialize the the per-thread sys_timeouts structures
|
|
||||||
// make sure there are no valid pids in the list
|
|
||||||
for(i = 0; i < SYS_THREAD_MAX; i++)
|
|
||||||
{
|
|
||||||
s_timeoutlist[i].pid = 0;
|
|
||||||
s_timeoutlist[i].timeouts.next = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// keep track of how many threads have been created
|
|
||||||
s_nextthread = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------------*/
|
|
||||||
/*
|
|
||||||
Returns a pointer to the per-thread sys_timeouts structure. In lwIP,
|
|
||||||
each thread has a list of timeouts which is represented as a linked
|
|
||||||
list of sys_timeout structures. The sys_timeouts structure holds a
|
|
||||||
pointer to a linked list of timeouts. This function is called by
|
|
||||||
the lwIP timeout scheduler and must not return a NULL value.
|
|
||||||
|
|
||||||
In a single threaded sys_arch implementation, this function will
|
|
||||||
simply return a pointer to a global sys_timeouts variable stored in
|
|
||||||
the sys_arch module.
|
|
||||||
*/
|
|
||||||
struct sys_timeouts *sys_arch_timeouts(void)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
xTaskHandle pid;
|
|
||||||
struct timeoutlist *tl;
|
|
||||||
|
|
||||||
pid = xTaskGetCurrentTaskHandle();
|
|
||||||
|
|
||||||
for(i = 0; i < s_nextthread; i++)
|
|
||||||
{
|
|
||||||
tl = &(s_timeoutlist[i]);
|
|
||||||
if(tl->pid == pid)
|
|
||||||
{
|
|
||||||
return &(tl->timeouts);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Error
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------------*/
|
|
||||||
/*-----------------------------------------------------------------------------------*/
|
|
||||||
// TODO
|
|
||||||
/*-----------------------------------------------------------------------------------*/
|
|
||||||
/*
|
|
||||||
Starts a new thread with priority "prio" that will begin its execution in the
|
|
||||||
function "thread()". The "arg" argument will be passed as an argument to the
|
|
||||||
thread() function. The id of the new thread is returned. Both the id and
|
|
||||||
the priority are system dependent.
|
|
||||||
*/
|
|
||||||
sys_thread_t sys_thread_new(char *name, void (* thread)(void *arg), void *arg, int stacksize, int prio)
|
|
||||||
{
|
|
||||||
xTaskHandle CreatedTask;
|
|
||||||
int result;
|
|
||||||
|
|
||||||
if ( s_nextthread < SYS_THREAD_MAX )
|
|
||||||
{
|
|
||||||
vPortEnterCritical();
|
|
||||||
result = xTaskCreate( thread, ( char const * ) name, stacksize, arg, prio, &CreatedTask );
|
|
||||||
|
|
||||||
// For each task created, store the task handle (pid) in the timers array.
|
|
||||||
// This scheme doesn't allow for threads to be deleted
|
|
||||||
s_timeoutlist[s_nextthread++].pid = CreatedTask;
|
|
||||||
vPortExitCritical();
|
|
||||||
|
|
||||||
if(result == pdPASS)
|
|
||||||
{
|
|
||||||
return CreatedTask;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
This optional function does a "fast" critical region protection and returns
|
|
||||||
the previous protection level. This function is only called during very short
|
|
||||||
critical regions. An embedded system which supports ISR-based drivers might
|
|
||||||
want to implement this function by disabling interrupts. Task-based systems
|
|
||||||
might want to implement this by using a mutex or disabling tasking. This
|
|
||||||
function should support recursive calls from the same task or interrupt. In
|
|
||||||
other words, sys_arch_protect() could be called while already protected. In
|
|
||||||
that case the return value indicates that it is already protected.
|
|
||||||
|
|
||||||
sys_arch_protect() is only required if your port is supporting an operating
|
|
||||||
system.
|
|
||||||
*/
|
|
||||||
sys_prot_t sys_arch_protect(void)
|
|
||||||
{
|
|
||||||
vPortEnterCritical();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
This optional function does a "fast" set of critical region protection to the
|
|
||||||
value specified by pval. See the documentation for sys_arch_protect() for
|
|
||||||
more information. This function is only required if your port is supporting
|
|
||||||
an operating system.
|
|
||||||
*/
|
|
||||||
void sys_arch_unprotect(sys_prot_t pval)
|
|
||||||
{
|
|
||||||
( void ) pval;
|
|
||||||
vPortExitCritical();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Prints an assertion messages and aborts execution.
|
|
||||||
*/
|
|
||||||
void sys_assert( const char *msg )
|
|
||||||
{
|
|
||||||
( void ) msg;
|
|
||||||
/*FSL:only needed for debugging
|
|
||||||
printf(msg);
|
|
||||||
printf("\n\r");
|
|
||||||
*/
|
|
||||||
vPortEnterCritical( );
|
|
||||||
for(;;)
|
|
||||||
;
|
|
||||||
}
|
|
|
@ -1,66 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#ifndef __SYS_RTXC_H__
|
|
||||||
#define __SYS_RTXC_H__
|
|
||||||
|
|
||||||
#include "FreeRTOS.h"
|
|
||||||
#include "task.h"
|
|
||||||
#include "queue.h"
|
|
||||||
#include "semphr.h"
|
|
||||||
|
|
||||||
#define SYS_MBOX_NULL (xQueueHandle)0
|
|
||||||
#define SYS_SEM_NULL (xSemaphoreHandle)0
|
|
||||||
#define SYS_DEFAULT_THREAD_STACK_DEPTH configMINIMAL_STACK_SIZE
|
|
||||||
|
|
||||||
typedef xSemaphoreHandle sys_sem_t;
|
|
||||||
typedef xQueueHandle sys_mbox_t;
|
|
||||||
typedef xTaskHandle sys_thread_t;
|
|
||||||
|
|
||||||
typedef struct _sys_arch_state_t
|
|
||||||
{
|
|
||||||
// Task creation data.
|
|
||||||
char cTaskName[configMAX_TASK_NAME_LEN];
|
|
||||||
unsigned short nStackDepth;
|
|
||||||
unsigned short nTaskCount;
|
|
||||||
} sys_arch_state_t;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//extern sys_arch_state_t s_sys_arch_state;
|
|
||||||
|
|
||||||
//void sys_set_default_state();
|
|
||||||
//void sys_set_state(signed char *pTaskName, unsigned short nStackSize);
|
|
||||||
|
|
||||||
/* Message queue constants. */
|
|
||||||
#define archMESG_QUEUE_LENGTH ( 6 )
|
|
||||||
#endif /* __SYS_RTXC_H__ */
|
|
||||||
|
|
|
@ -1,304 +0,0 @@
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
* Ethernet Interface for standalone applications (without RTOS) - works only for
|
|
||||||
* ethernet polling mode (polling for ethernet frame reception)
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "lwip/mem.h"
|
|
||||||
#include "netif/etharp.h"
|
|
||||||
#include "ethernetif.h"
|
|
||||||
#include "stm32f2x7_eth.h"
|
|
||||||
#include "main.h"
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
/* Network interface name */
|
|
||||||
#define IFNAME0 's'
|
|
||||||
#define IFNAME1 't'
|
|
||||||
|
|
||||||
|
|
||||||
/* Ethernet Rx & Tx DMA Descriptors */
|
|
||||||
extern ETH_DMADESCTypeDef DMARxDscrTab[ETH_RXBUFNB], DMATxDscrTab[ETH_TXBUFNB];
|
|
||||||
|
|
||||||
/* Ethernet Driver Receive buffers */
|
|
||||||
extern uint8_t Rx_Buff[ETH_RXBUFNB][ETH_RX_BUF_SIZE];
|
|
||||||
|
|
||||||
/* Ethernet Driver Transmit buffers */
|
|
||||||
extern uint8_t Tx_Buff[ETH_TXBUFNB][ETH_TX_BUF_SIZE];
|
|
||||||
|
|
||||||
/* Global pointers to track current transmit and receive descriptors */
|
|
||||||
extern ETH_DMADESCTypeDef *DMATxDescToSet;
|
|
||||||
extern ETH_DMADESCTypeDef *DMARxDescToGet;
|
|
||||||
|
|
||||||
/* Global pointer for last received frame infos */
|
|
||||||
extern ETH_DMA_Rx_Frame_infos *DMA_RX_FRAME_infos;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* In this function, the hardware should be initialized.
|
|
||||||
* Called from ethernetif_init().
|
|
||||||
*
|
|
||||||
* @param netif the already initialized lwip network interface structure
|
|
||||||
* for this ethernetif
|
|
||||||
*/
|
|
||||||
static void low_level_init(struct netif *netif)
|
|
||||||
{
|
|
||||||
#ifdef CHECKSUM_BY_HARDWARE
|
|
||||||
int i;
|
|
||||||
#endif
|
|
||||||
/* set MAC hardware address length */
|
|
||||||
netif->hwaddr_len = ETHARP_HWADDR_LEN;
|
|
||||||
|
|
||||||
/* set MAC hardware address */
|
|
||||||
netif->hwaddr[0] = MAC_ADDR0;
|
|
||||||
netif->hwaddr[1] = MAC_ADDR1;
|
|
||||||
netif->hwaddr[2] = MAC_ADDR2;
|
|
||||||
netif->hwaddr[3] = MAC_ADDR3;
|
|
||||||
netif->hwaddr[4] = MAC_ADDR4;
|
|
||||||
netif->hwaddr[5] = MAC_ADDR5;
|
|
||||||
|
|
||||||
/* initialize MAC address in ethernet MAC */
|
|
||||||
ETH_MACAddressConfig(ETH_MAC_Address0, netif->hwaddr);
|
|
||||||
|
|
||||||
/* maximum transfer unit */
|
|
||||||
netif->mtu = 1500;
|
|
||||||
|
|
||||||
/* device capabilities */
|
|
||||||
/* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */
|
|
||||||
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
|
|
||||||
|
|
||||||
/* Initialize Tx Descriptors list: Chain Mode */
|
|
||||||
ETH_DMATxDescChainInit(DMATxDscrTab, &Tx_Buff[0][0], ETH_TXBUFNB);
|
|
||||||
/* Initialize Rx Descriptors list: Chain Mode */
|
|
||||||
ETH_DMARxDescChainInit(DMARxDscrTab, &Rx_Buff[0][0], ETH_RXBUFNB);
|
|
||||||
|
|
||||||
#ifdef CHECKSUM_BY_HARDWARE
|
|
||||||
/* Enable the TCP, UDP and ICMP checksum insertion for the Tx frames */
|
|
||||||
for(i=0; i<ETH_TXBUFNB; i++)
|
|
||||||
{
|
|
||||||
ETH_DMATxDescChecksumInsertionConfig(&DMATxDscrTab[i], ETH_DMATxDesc_ChecksumTCPUDPICMPFull);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Note: TCP, UDP, ICMP checksum checking for received frame are enabled in DMA config */
|
|
||||||
|
|
||||||
/* Enable MAC and DMA transmission and reception */
|
|
||||||
ETH_Start();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This function should do the actual transmission of the packet. The packet is
|
|
||||||
* contained in the pbuf that is passed to the function. This pbuf
|
|
||||||
* might be chained.
|
|
||||||
*
|
|
||||||
* @param netif the lwip network interface structure for this ethernetif
|
|
||||||
* @param p the MAC packet to send (e.g. IP packet including MAC addresses and type)
|
|
||||||
* @return ERR_OK if the packet could be sent
|
|
||||||
* an err_t value if the packet couldn't be sent
|
|
||||||
*
|
|
||||||
* @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to
|
|
||||||
* strange results. You might consider waiting for space in the DMA queue
|
|
||||||
* to become availale since the stack doesn't retry to send a packet
|
|
||||||
* dropped because of memory failure (except for the TCP timers).
|
|
||||||
*/
|
|
||||||
|
|
||||||
static err_t low_level_output(struct netif *netif, struct pbuf *p)
|
|
||||||
{
|
|
||||||
struct pbuf *q;
|
|
||||||
int framelength = 0;
|
|
||||||
u8 *buffer = (u8 *)(DMATxDescToSet->Buffer1Addr);
|
|
||||||
|
|
||||||
/* copy frame from pbufs to driver buffers */
|
|
||||||
for(q = p; q != NULL; q = q->next)
|
|
||||||
{
|
|
||||||
memcpy((u8_t*)&buffer[framelength], q->payload, q->len);
|
|
||||||
framelength = framelength + q->len;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Note: padding and CRC for transmitted frame
|
|
||||||
are automatically inserted by DMA */
|
|
||||||
|
|
||||||
/* Prepare transmit descriptors to give to DMA*/
|
|
||||||
ETH_Prepare_Transmit_Descriptors(framelength);
|
|
||||||
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Should allocate a pbuf and transfer the bytes of the incoming
|
|
||||||
* packet from the interface into the pbuf.
|
|
||||||
*
|
|
||||||
* @param netif the lwip network interface structure for this ethernetif
|
|
||||||
* @return a pbuf filled with the received packet (including MAC header)
|
|
||||||
* NULL on memory error
|
|
||||||
*/
|
|
||||||
static struct pbuf * low_level_input(struct netif *netif)
|
|
||||||
{
|
|
||||||
struct pbuf *p, *q;
|
|
||||||
u16_t len;
|
|
||||||
int l =0;
|
|
||||||
FrameTypeDef frame;
|
|
||||||
u8 *buffer;
|
|
||||||
uint32_t i=0;
|
|
||||||
__IO ETH_DMADESCTypeDef *DMARxNextDesc;
|
|
||||||
|
|
||||||
|
|
||||||
p = NULL;
|
|
||||||
|
|
||||||
/* get received frame */
|
|
||||||
frame = ETH_Get_Received_Frame();
|
|
||||||
|
|
||||||
/* Obtain the size of the packet and put it into the "len" variable. */
|
|
||||||
len = frame.length;
|
|
||||||
buffer = (u8 *)frame.buffer;
|
|
||||||
|
|
||||||
/* We allocate a pbuf chain of pbufs from the Lwip buffer pool */
|
|
||||||
p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
|
|
||||||
|
|
||||||
/* copy received frame to pbuf chain */
|
|
||||||
if (p != NULL)
|
|
||||||
{
|
|
||||||
for (q = p; q != NULL; q = q->next)
|
|
||||||
{
|
|
||||||
memcpy((u8_t*)q->payload, (u8_t*)&buffer[l], q->len);
|
|
||||||
l = l + q->len;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Release descriptors to DMA */
|
|
||||||
/* Check if frame with multiple DMA buffer segments */
|
|
||||||
if (DMA_RX_FRAME_infos->Seg_Count > 1)
|
|
||||||
{
|
|
||||||
DMARxNextDesc = DMA_RX_FRAME_infos->FS_Rx_Desc;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DMARxNextDesc = frame.descriptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set Own bit in Rx descriptors: gives the buffers back to DMA */
|
|
||||||
for (i=0; i<DMA_RX_FRAME_infos->Seg_Count; i++)
|
|
||||||
{
|
|
||||||
DMARxNextDesc->Status = ETH_DMARxDesc_OWN;
|
|
||||||
DMARxNextDesc = (ETH_DMADESCTypeDef *)(DMARxNextDesc->Buffer2NextDescAddr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Clear Segment_Count */
|
|
||||||
DMA_RX_FRAME_infos->Seg_Count =0;
|
|
||||||
|
|
||||||
/* When Rx Buffer unavailable flag is set: clear it and resume reception */
|
|
||||||
if ((ETH->DMASR & ETH_DMASR_RBUS) != (u32)RESET)
|
|
||||||
{
|
|
||||||
/* Clear RBUS ETHERNET DMA flag */
|
|
||||||
ETH->DMASR = ETH_DMASR_RBUS;
|
|
||||||
/* Resume DMA reception */
|
|
||||||
ETH->DMARPDR = 0;
|
|
||||||
}
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This function should be called when a packet is ready to be read
|
|
||||||
* from the interface. It uses the function low_level_input() that
|
|
||||||
* should handle the actual reception of bytes from the network
|
|
||||||
* interface. Then the type of the received packet is determined and
|
|
||||||
* the appropriate input function is called.
|
|
||||||
*
|
|
||||||
* @param netif the lwip network interface structure for this ethernetif
|
|
||||||
*/
|
|
||||||
err_t ethernetif_input(struct netif *netif)
|
|
||||||
{
|
|
||||||
err_t err;
|
|
||||||
struct pbuf *p;
|
|
||||||
|
|
||||||
/* move received packet into a new pbuf */
|
|
||||||
p = low_level_input(netif);
|
|
||||||
|
|
||||||
/* no packet could be read, silently ignore this */
|
|
||||||
if (p == NULL) return ERR_MEM;
|
|
||||||
|
|
||||||
/* entry point to the LwIP stack */
|
|
||||||
err = netif->input(p, netif);
|
|
||||||
|
|
||||||
if (err != ERR_OK)
|
|
||||||
{
|
|
||||||
LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));
|
|
||||||
pbuf_free(p);
|
|
||||||
p = NULL;
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Should be called at the beginning of the program to set up the
|
|
||||||
* network interface. It calls the function low_level_init() to do the
|
|
||||||
* actual setup of the hardware.
|
|
||||||
*
|
|
||||||
* This function should be passed as a parameter to netif_add().
|
|
||||||
*
|
|
||||||
* @param netif the lwip network interface structure for this ethernetif
|
|
||||||
* @return ERR_OK if the loopif is initialized
|
|
||||||
* ERR_MEM if private data couldn't be allocated
|
|
||||||
* any other err_t on error
|
|
||||||
*/
|
|
||||||
err_t ethernetif_init(struct netif *netif)
|
|
||||||
{
|
|
||||||
LWIP_ASSERT("netif != NULL", (netif != NULL));
|
|
||||||
|
|
||||||
#if LWIP_NETIF_HOSTNAME
|
|
||||||
/* Initialize interface hostname */
|
|
||||||
netif->hostname = "lwip";
|
|
||||||
#endif /* LWIP_NETIF_HOSTNAME */
|
|
||||||
|
|
||||||
netif->name[0] = IFNAME0;
|
|
||||||
netif->name[1] = IFNAME1;
|
|
||||||
/* We directly use etharp_output() here to save a function call.
|
|
||||||
* You can instead declare your own function an call etharp_output()
|
|
||||||
* from it if you have to do some checks before sending (e.g. if link
|
|
||||||
* is available...) */
|
|
||||||
netif->output = etharp_output;
|
|
||||||
netif->linkoutput = low_level_output;
|
|
||||||
|
|
||||||
/* initialize the hardware */
|
|
||||||
low_level_init(netif);
|
|
||||||
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
#ifndef __ETHERNETIF_H__
|
|
||||||
#define __ETHERNETIF_H__
|
|
||||||
|
|
||||||
|
|
||||||
#include "lwip/err.h"
|
|
||||||
#include "lwip/netif.h"
|
|
||||||
|
|
||||||
err_t ethernetif_init(struct netif *netif);
|
|
||||||
err_t ethernetif_input(struct netif *netif);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,568 +0,0 @@
|
||||||
/*
|
|
||||||
* @file
|
|
||||||
* Sequential API External module
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* This is the part of the API that is linked with
|
|
||||||
the application */
|
|
||||||
|
|
||||||
#include "lwip/opt.h"
|
|
||||||
|
|
||||||
#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
|
|
||||||
|
|
||||||
#include "lwip/api.h"
|
|
||||||
#include "lwip/tcpip.h"
|
|
||||||
#include "lwip/memp.h"
|
|
||||||
|
|
||||||
#include "lwip/ip.h"
|
|
||||||
#include "lwip/raw.h"
|
|
||||||
#include "lwip/udp.h"
|
|
||||||
#include "lwip/tcp.h"
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new netconn (of a specific type) that has a callback function.
|
|
||||||
* The corresponding pcb is also created.
|
|
||||||
*
|
|
||||||
* @param t the type of 'connection' to create (@see enum netconn_type)
|
|
||||||
* @param proto the IP protocol for RAW IP pcbs
|
|
||||||
* @param callback a function to call on status changes (RX available, TX'ed)
|
|
||||||
* @return a newly allocated struct netconn or
|
|
||||||
* NULL on memory error
|
|
||||||
*/
|
|
||||||
struct netconn*
|
|
||||||
netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, netconn_callback callback)
|
|
||||||
{
|
|
||||||
struct netconn *conn;
|
|
||||||
struct api_msg msg;
|
|
||||||
|
|
||||||
conn = netconn_alloc(t, callback);
|
|
||||||
if (conn != NULL ) {
|
|
||||||
msg.function = do_newconn;
|
|
||||||
msg.msg.msg.n.proto = proto;
|
|
||||||
msg.msg.conn = conn;
|
|
||||||
TCPIP_APIMSG(&msg);
|
|
||||||
|
|
||||||
if (conn->err != ERR_OK) {
|
|
||||||
LWIP_ASSERT("freeing conn without freeing pcb", conn->pcb.tcp == NULL);
|
|
||||||
LWIP_ASSERT("conn has no op_completed", conn->op_completed != SYS_SEM_NULL);
|
|
||||||
LWIP_ASSERT("conn has no recvmbox", conn->recvmbox != SYS_MBOX_NULL);
|
|
||||||
LWIP_ASSERT("conn->acceptmbox shouldn't exist", conn->acceptmbox == SYS_MBOX_NULL);
|
|
||||||
sys_sem_free(conn->op_completed);
|
|
||||||
sys_mbox_free(conn->recvmbox);
|
|
||||||
memp_free(MEMP_NETCONN, conn);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return conn;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Close a netconn 'connection' and free its resources.
|
|
||||||
* UDP and RAW connection are completely closed, TCP pcbs might still be in a waitstate
|
|
||||||
* after this returns.
|
|
||||||
*
|
|
||||||
* @param conn the netconn to delete
|
|
||||||
* @return ERR_OK if the connection was deleted
|
|
||||||
*/
|
|
||||||
err_t
|
|
||||||
netconn_delete(struct netconn *conn)
|
|
||||||
{
|
|
||||||
struct api_msg msg;
|
|
||||||
|
|
||||||
/* No ASSERT here because possible to get a (conn == NULL) if we got an accept error */
|
|
||||||
if (conn == NULL) {
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
msg.function = do_delconn;
|
|
||||||
msg.msg.conn = conn;
|
|
||||||
tcpip_apimsg(&msg);
|
|
||||||
|
|
||||||
conn->pcb.tcp = NULL;
|
|
||||||
netconn_free(conn);
|
|
||||||
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the local or remote IP address and port of a netconn.
|
|
||||||
* For RAW netconns, this returns the protocol instead of a port!
|
|
||||||
*
|
|
||||||
* @param conn the netconn to query
|
|
||||||
* @param addr a pointer to which to save the IP address
|
|
||||||
* @param port a pointer to which to save the port (or protocol for RAW)
|
|
||||||
* @param local 1 to get the local IP address, 0 to get the remote one
|
|
||||||
* @return ERR_CONN for invalid connections
|
|
||||||
* ERR_OK if the information was retrieved
|
|
||||||
*/
|
|
||||||
err_t
|
|
||||||
netconn_getaddr(struct netconn *conn, struct ip_addr *addr, u16_t *port, u8_t local)
|
|
||||||
{
|
|
||||||
struct api_msg msg;
|
|
||||||
|
|
||||||
LWIP_ERROR("netconn_getaddr: invalid conn", (conn != NULL), return ERR_ARG;);
|
|
||||||
LWIP_ERROR("netconn_getaddr: invalid addr", (addr != NULL), return ERR_ARG;);
|
|
||||||
LWIP_ERROR("netconn_getaddr: invalid port", (port != NULL), return ERR_ARG;);
|
|
||||||
|
|
||||||
msg.function = do_getaddr;
|
|
||||||
msg.msg.conn = conn;
|
|
||||||
msg.msg.msg.ad.ipaddr = addr;
|
|
||||||
msg.msg.msg.ad.port = port;
|
|
||||||
msg.msg.msg.ad.local = local;
|
|
||||||
TCPIP_APIMSG(&msg);
|
|
||||||
|
|
||||||
return conn->err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Bind a netconn to a specific local IP address and port.
|
|
||||||
* Binding one netconn twice might not always be checked correctly!
|
|
||||||
*
|
|
||||||
* @param conn the netconn to bind
|
|
||||||
* @param addr the local IP address to bind the netconn to (use IP_ADDR_ANY
|
|
||||||
* to bind to all addresses)
|
|
||||||
* @param port the local port to bind the netconn to (not used for RAW)
|
|
||||||
* @return ERR_OK if bound, any other err_t on failure
|
|
||||||
*/
|
|
||||||
err_t
|
|
||||||
netconn_bind(struct netconn *conn, struct ip_addr *addr, u16_t port)
|
|
||||||
{
|
|
||||||
struct api_msg msg;
|
|
||||||
|
|
||||||
LWIP_ERROR("netconn_bind: invalid conn", (conn != NULL), return ERR_ARG;);
|
|
||||||
|
|
||||||
msg.function = do_bind;
|
|
||||||
msg.msg.conn = conn;
|
|
||||||
msg.msg.msg.bc.ipaddr = addr;
|
|
||||||
msg.msg.msg.bc.port = port;
|
|
||||||
TCPIP_APIMSG(&msg);
|
|
||||||
return conn->err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Connect a netconn to a specific remote IP address and port.
|
|
||||||
*
|
|
||||||
* @param conn the netconn to connect
|
|
||||||
* @param addr the remote IP address to connect to
|
|
||||||
* @param port the remote port to connect to (no used for RAW)
|
|
||||||
* @return ERR_OK if connected, return value of tcp_/udp_/raw_connect otherwise
|
|
||||||
*/
|
|
||||||
err_t
|
|
||||||
netconn_connect(struct netconn *conn, struct ip_addr *addr, u16_t port)
|
|
||||||
{
|
|
||||||
struct api_msg msg;
|
|
||||||
|
|
||||||
LWIP_ERROR("netconn_connect: invalid conn", (conn != NULL), return ERR_ARG;);
|
|
||||||
|
|
||||||
msg.function = do_connect;
|
|
||||||
msg.msg.conn = conn;
|
|
||||||
msg.msg.msg.bc.ipaddr = addr;
|
|
||||||
msg.msg.msg.bc.port = port;
|
|
||||||
/* This is the only function which need to not block tcpip_thread */
|
|
||||||
tcpip_apimsg(&msg);
|
|
||||||
return conn->err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Disconnect a netconn from its current peer (only valid for UDP netconns).
|
|
||||||
*
|
|
||||||
* @param conn the netconn to disconnect
|
|
||||||
* @return TODO: return value is not set here...
|
|
||||||
*/
|
|
||||||
err_t
|
|
||||||
netconn_disconnect(struct netconn *conn)
|
|
||||||
{
|
|
||||||
struct api_msg msg;
|
|
||||||
|
|
||||||
LWIP_ERROR("netconn_disconnect: invalid conn", (conn != NULL), return ERR_ARG;);
|
|
||||||
|
|
||||||
msg.function = do_disconnect;
|
|
||||||
msg.msg.conn = conn;
|
|
||||||
TCPIP_APIMSG(&msg);
|
|
||||||
return conn->err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set a TCP netconn into listen mode
|
|
||||||
*
|
|
||||||
* @param conn the tcp netconn to set to listen mode
|
|
||||||
* @param backlog the listen backlog, only used if TCP_LISTEN_BACKLOG==1
|
|
||||||
* @return ERR_OK if the netconn was set to listen (UDP and RAW netconns
|
|
||||||
* don't return any error (yet?))
|
|
||||||
*/
|
|
||||||
err_t
|
|
||||||
netconn_listen_with_backlog(struct netconn *conn, u8_t backlog)
|
|
||||||
{
|
|
||||||
struct api_msg msg;
|
|
||||||
|
|
||||||
/* This does no harm. If TCP_LISTEN_BACKLOG is off, backlog is unused. */
|
|
||||||
LWIP_UNUSED_ARG(backlog);
|
|
||||||
|
|
||||||
LWIP_ERROR("netconn_listen: invalid conn", (conn != NULL), return ERR_ARG;);
|
|
||||||
|
|
||||||
msg.function = do_listen;
|
|
||||||
msg.msg.conn = conn;
|
|
||||||
#if TCP_LISTEN_BACKLOG
|
|
||||||
msg.msg.msg.lb.backlog = backlog;
|
|
||||||
#endif /* TCP_LISTEN_BACKLOG */
|
|
||||||
TCPIP_APIMSG(&msg);
|
|
||||||
return conn->err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Accept a new connection on a TCP listening netconn.
|
|
||||||
*
|
|
||||||
* @param conn the TCP listen netconn
|
|
||||||
* @return the newly accepted netconn or NULL on timeout
|
|
||||||
*/
|
|
||||||
struct netconn *
|
|
||||||
netconn_accept(struct netconn *conn)
|
|
||||||
{
|
|
||||||
struct netconn *newconn;
|
|
||||||
|
|
||||||
LWIP_ERROR("netconn_accept: invalid conn", (conn != NULL), return NULL;);
|
|
||||||
LWIP_ERROR("netconn_accept: invalid acceptmbox", (conn->acceptmbox != SYS_MBOX_NULL), return NULL;);
|
|
||||||
|
|
||||||
#if LWIP_SO_RCVTIMEO
|
|
||||||
if (sys_arch_mbox_fetch(conn->acceptmbox, (void *)&newconn, conn->recv_timeout) == SYS_ARCH_TIMEOUT) {
|
|
||||||
newconn = NULL;
|
|
||||||
} else
|
|
||||||
#else
|
|
||||||
sys_arch_mbox_fetch(conn->acceptmbox, (void *)&newconn, 0);
|
|
||||||
#endif /* LWIP_SO_RCVTIMEO*/
|
|
||||||
{
|
|
||||||
/* Register event with callback */
|
|
||||||
API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);
|
|
||||||
|
|
||||||
#if TCP_LISTEN_BACKLOG
|
|
||||||
if (newconn != NULL) {
|
|
||||||
/* Let the stack know that we have accepted the connection. */
|
|
||||||
struct api_msg msg;
|
|
||||||
msg.function = do_recv;
|
|
||||||
msg.msg.conn = conn;
|
|
||||||
TCPIP_APIMSG(&msg);
|
|
||||||
}
|
|
||||||
#endif /* TCP_LISTEN_BACKLOG */
|
|
||||||
}
|
|
||||||
|
|
||||||
return newconn;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Receive data (in form of a netbuf containing a packet buffer) from a netconn
|
|
||||||
*
|
|
||||||
* @param conn the netconn from which to receive data
|
|
||||||
* @return a new netbuf containing received data or NULL on memory error or timeout
|
|
||||||
*/
|
|
||||||
struct netbuf *
|
|
||||||
netconn_recv(struct netconn *conn)
|
|
||||||
{
|
|
||||||
struct api_msg msg;
|
|
||||||
struct netbuf *buf = NULL;
|
|
||||||
struct pbuf *p;
|
|
||||||
u16_t len;
|
|
||||||
|
|
||||||
LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return NULL;);
|
|
||||||
|
|
||||||
if (conn->recvmbox == SYS_MBOX_NULL) {
|
|
||||||
/* @todo: should calling netconn_recv on a TCP listen conn be fatal (ERR_CONN)?? */
|
|
||||||
/* TCP listen conns don't have a recvmbox! */
|
|
||||||
conn->err = ERR_CONN;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ERR_IS_FATAL(conn->err)) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (conn->type == NETCONN_TCP) {
|
|
||||||
#if LWIP_TCP
|
|
||||||
if (conn->state == NETCONN_LISTEN) {
|
|
||||||
/* @todo: should calling netconn_recv on a TCP listen conn be fatal?? */
|
|
||||||
conn->err = ERR_CONN;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
buf = memp_malloc(MEMP_NETBUF);
|
|
||||||
|
|
||||||
if (buf == NULL) {
|
|
||||||
conn->err = ERR_MEM;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if LWIP_SO_RCVTIMEO
|
|
||||||
if (sys_arch_mbox_fetch(conn->recvmbox, (void *)&p, conn->recv_timeout)==SYS_ARCH_TIMEOUT) {
|
|
||||||
memp_free(MEMP_NETBUF, buf);
|
|
||||||
conn->err = ERR_TIMEOUT;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
sys_arch_mbox_fetch(conn->recvmbox, (void *)&p, 0);
|
|
||||||
#endif /* LWIP_SO_RCVTIMEO*/
|
|
||||||
|
|
||||||
if (p != NULL) {
|
|
||||||
len = p->tot_len;
|
|
||||||
SYS_ARCH_DEC(conn->recv_avail, len);
|
|
||||||
} else {
|
|
||||||
len = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Register event with callback */
|
|
||||||
API_EVENT(conn, NETCONN_EVT_RCVMINUS, len);
|
|
||||||
|
|
||||||
/* If we are closed, we indicate that we no longer wish to use the socket */
|
|
||||||
if (p == NULL) {
|
|
||||||
memp_free(MEMP_NETBUF, buf);
|
|
||||||
/* Avoid to lose any previous error code */
|
|
||||||
if (conn->err == ERR_OK) {
|
|
||||||
conn->err = ERR_CLSD;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
buf->p = p;
|
|
||||||
buf->ptr = p;
|
|
||||||
buf->port = 0;
|
|
||||||
buf->addr = NULL;
|
|
||||||
|
|
||||||
/* Let the stack know that we have taken the data. */
|
|
||||||
msg.function = do_recv;
|
|
||||||
msg.msg.conn = conn;
|
|
||||||
if (buf != NULL) {
|
|
||||||
msg.msg.msg.r.len = buf->p->tot_len;
|
|
||||||
} else {
|
|
||||||
msg.msg.msg.r.len = 1;
|
|
||||||
}
|
|
||||||
TCPIP_APIMSG(&msg);
|
|
||||||
#endif /* LWIP_TCP */
|
|
||||||
} else {
|
|
||||||
#if (LWIP_UDP || LWIP_RAW)
|
|
||||||
#if LWIP_SO_RCVTIMEO
|
|
||||||
if (sys_arch_mbox_fetch(conn->recvmbox, (void *)&buf, conn->recv_timeout)==SYS_ARCH_TIMEOUT) {
|
|
||||||
buf = NULL;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
sys_arch_mbox_fetch(conn->recvmbox, (void *)&buf, 0);
|
|
||||||
#endif /* LWIP_SO_RCVTIMEO*/
|
|
||||||
if (buf!=NULL) {
|
|
||||||
SYS_ARCH_DEC(conn->recv_avail, buf->p->tot_len);
|
|
||||||
/* Register event with callback */
|
|
||||||
API_EVENT(conn, NETCONN_EVT_RCVMINUS, buf->p->tot_len);
|
|
||||||
}
|
|
||||||
#endif /* (LWIP_UDP || LWIP_RAW) */
|
|
||||||
}
|
|
||||||
|
|
||||||
LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv: received %p (err %d)\n", (void *)buf, conn->err));
|
|
||||||
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send data (in form of a netbuf) to a specific remote IP address and port.
|
|
||||||
* Only to be used for UDP and RAW netconns (not TCP).
|
|
||||||
*
|
|
||||||
* @param conn the netconn over which to send data
|
|
||||||
* @param buf a netbuf containing the data to send
|
|
||||||
* @param addr the remote IP address to which to send the data
|
|
||||||
* @param port the remote port to which to send the data
|
|
||||||
* @return ERR_OK if data was sent, any other err_t on error
|
|
||||||
*/
|
|
||||||
err_t
|
|
||||||
netconn_sendto(struct netconn *conn, struct netbuf *buf, struct ip_addr *addr, u16_t port)
|
|
||||||
{
|
|
||||||
if (buf != NULL) {
|
|
||||||
buf->addr = addr;
|
|
||||||
buf->port = port;
|
|
||||||
return netconn_send(conn, buf);
|
|
||||||
}
|
|
||||||
return ERR_VAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send data over a UDP or RAW netconn (that is already connected).
|
|
||||||
*
|
|
||||||
* @param conn the UDP or RAW netconn over which to send data
|
|
||||||
* @param buf a netbuf containing the data to send
|
|
||||||
* @return ERR_OK if data was sent, any other err_t on error
|
|
||||||
*/
|
|
||||||
err_t
|
|
||||||
netconn_send(struct netconn *conn, struct netbuf *buf)
|
|
||||||
{
|
|
||||||
struct api_msg msg;
|
|
||||||
|
|
||||||
LWIP_ERROR("netconn_send: invalid conn", (conn != NULL), return ERR_ARG;);
|
|
||||||
|
|
||||||
LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %"U16_F" bytes\n", buf->p->tot_len));
|
|
||||||
msg.function = do_send;
|
|
||||||
msg.msg.conn = conn;
|
|
||||||
msg.msg.msg.b = buf;
|
|
||||||
TCPIP_APIMSG(&msg);
|
|
||||||
return conn->err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send data over a TCP netconn.
|
|
||||||
*
|
|
||||||
* @param conn the TCP netconn over which to send data
|
|
||||||
* @param dataptr pointer to the application buffer that contains the data to send
|
|
||||||
* @param size size of the application data to send
|
|
||||||
* @param apiflags combination of following flags :
|
|
||||||
* - NETCONN_COPY (0x01) data will be copied into memory belonging to the stack
|
|
||||||
* - NETCONN_MORE (0x02) for TCP connection, PSH flag will be set on last segment sent
|
|
||||||
* @return ERR_OK if data was sent, any other err_t on error
|
|
||||||
*/
|
|
||||||
err_t
|
|
||||||
netconn_write(struct netconn *conn, const void *dataptr, size_t size, u8_t apiflags)
|
|
||||||
{
|
|
||||||
struct api_msg msg;
|
|
||||||
|
|
||||||
LWIP_ERROR("netconn_write: invalid conn", (conn != NULL), return ERR_ARG;);
|
|
||||||
LWIP_ERROR("netconn_write: invalid conn->type", (conn->type == NETCONN_TCP), return ERR_VAL;);
|
|
||||||
|
|
||||||
msg.function = do_write;
|
|
||||||
msg.msg.conn = conn;
|
|
||||||
msg.msg.msg.w.dataptr = dataptr;
|
|
||||||
msg.msg.msg.w.apiflags = apiflags;
|
|
||||||
msg.msg.msg.w.len = size;
|
|
||||||
/* For locking the core: this _can_ be delayed on low memory/low send buffer,
|
|
||||||
but if it is, this is done inside api_msg.c:do_write(), so we can use the
|
|
||||||
non-blocking version here. */
|
|
||||||
TCPIP_APIMSG(&msg);
|
|
||||||
return conn->err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Close a TCP netconn (doesn't delete it).
|
|
||||||
*
|
|
||||||
* @param conn the TCP netconn to close
|
|
||||||
* @return ERR_OK if the netconn was closed, any other err_t on error
|
|
||||||
*/
|
|
||||||
err_t
|
|
||||||
netconn_close(struct netconn *conn)
|
|
||||||
{
|
|
||||||
struct api_msg msg;
|
|
||||||
|
|
||||||
LWIP_ERROR("netconn_close: invalid conn", (conn != NULL), return ERR_ARG;);
|
|
||||||
|
|
||||||
msg.function = do_close;
|
|
||||||
msg.msg.conn = conn;
|
|
||||||
tcpip_apimsg(&msg);
|
|
||||||
return conn->err;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if LWIP_IGMP
|
|
||||||
/**
|
|
||||||
* Join multicast groups for UDP netconns.
|
|
||||||
*
|
|
||||||
* @param conn the UDP netconn for which to change multicast addresses
|
|
||||||
* @param multiaddr IP address of the multicast group to join or leave
|
|
||||||
* @param interface the IP address of the network interface on which to send
|
|
||||||
* the igmp message
|
|
||||||
* @param join_or_leave flag whether to send a join- or leave-message
|
|
||||||
* @return ERR_OK if the action was taken, any err_t on error
|
|
||||||
*/
|
|
||||||
err_t
|
|
||||||
netconn_join_leave_group(struct netconn *conn,
|
|
||||||
struct ip_addr *multiaddr,
|
|
||||||
struct ip_addr *interface,
|
|
||||||
enum netconn_igmp join_or_leave)
|
|
||||||
{
|
|
||||||
struct api_msg msg;
|
|
||||||
|
|
||||||
LWIP_ERROR("netconn_join_leave_group: invalid conn", (conn != NULL), return ERR_ARG;);
|
|
||||||
|
|
||||||
msg.function = do_join_leave_group;
|
|
||||||
msg.msg.conn = conn;
|
|
||||||
msg.msg.msg.jl.multiaddr = multiaddr;
|
|
||||||
msg.msg.msg.jl.interface = interface;
|
|
||||||
msg.msg.msg.jl.join_or_leave = join_or_leave;
|
|
||||||
TCPIP_APIMSG(&msg);
|
|
||||||
return conn->err;
|
|
||||||
}
|
|
||||||
#endif /* LWIP_IGMP */
|
|
||||||
|
|
||||||
#if LWIP_DNS
|
|
||||||
/**
|
|
||||||
* Execute a DNS query, only one IP address is returned
|
|
||||||
*
|
|
||||||
* @param name a string representation of the DNS host name to query
|
|
||||||
* @param addr a preallocated struct ip_addr where to store the resolved IP address
|
|
||||||
* @return ERR_OK: resolving succeeded
|
|
||||||
* ERR_MEM: memory error, try again later
|
|
||||||
* ERR_ARG: dns client not initialized or invalid hostname
|
|
||||||
* ERR_VAL: dns server response was invalid
|
|
||||||
*/
|
|
||||||
err_t
|
|
||||||
netconn_gethostbyname(const char *name, struct ip_addr *addr)
|
|
||||||
{
|
|
||||||
struct dns_api_msg msg;
|
|
||||||
err_t err;
|
|
||||||
sys_sem_t sem;
|
|
||||||
|
|
||||||
LWIP_ERROR("netconn_gethostbyname: invalid name", (name != NULL), return ERR_ARG;);
|
|
||||||
LWIP_ERROR("netconn_gethostbyname: invalid addr", (addr != NULL), return ERR_ARG;);
|
|
||||||
|
|
||||||
sem = sys_sem_new(0);
|
|
||||||
if (sem == SYS_SEM_NULL) {
|
|
||||||
return ERR_MEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
msg.name = name;
|
|
||||||
msg.addr = addr;
|
|
||||||
msg.err = &err;
|
|
||||||
msg.sem = sem;
|
|
||||||
|
|
||||||
tcpip_callback(do_gethostbyname, &msg);
|
|
||||||
sys_sem_wait(sem);
|
|
||||||
sys_sem_free(sem);
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
#endif /* LWIP_DNS*/
|
|
||||||
|
|
||||||
err_t netconn_abort(struct netconn *conn)
|
|
||||||
{
|
|
||||||
if (conn->acceptmbox != SYS_MBOX_NULL) {
|
|
||||||
/* Register event with callback */
|
|
||||||
API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
|
|
||||||
sys_mbox_post(conn->acceptmbox, NULL);
|
|
||||||
}
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* LWIP_NETCONN */
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,74 +0,0 @@
|
||||||
/*
|
|
||||||
* @file
|
|
||||||
* Error Management module
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "lwip/err.h"
|
|
||||||
|
|
||||||
#ifdef LWIP_DEBUG
|
|
||||||
|
|
||||||
static const char *err_strerr[] = {
|
|
||||||
"Ok.", /* ERR_OK 0 */
|
|
||||||
"Out of memory error.", /* ERR_MEM -1 */
|
|
||||||
"Buffer error.", /* ERR_BUF -2 */
|
|
||||||
"Timeout.", /* ERR_TIMEOUT -3 */
|
|
||||||
"Routing problem.", /* ERR_RTE -4 */
|
|
||||||
"Connection aborted.", /* ERR_ABRT -5 */
|
|
||||||
"Connection reset.", /* ERR_RST -6 */
|
|
||||||
"Connection closed.", /* ERR_CLSD -7 */
|
|
||||||
"Not connected.", /* ERR_CONN -8 */
|
|
||||||
"Illegal value.", /* ERR_VAL -9 */
|
|
||||||
"Illegal argument.", /* ERR_ARG -10 */
|
|
||||||
"Address in use.", /* ERR_USE -11 */
|
|
||||||
"Low-level netif error.", /* ERR_IF -12 */
|
|
||||||
"Already connected.", /* ERR_ISCONN -13 */
|
|
||||||
"Operation in progress." /* ERR_INPROGRESS -14 */
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert an lwip internal error to a string representation.
|
|
||||||
*
|
|
||||||
* @param err an lwip internal err_t
|
|
||||||
* @return a string representation for err
|
|
||||||
*/
|
|
||||||
const char *
|
|
||||||
lwip_strerr(err_t err)
|
|
||||||
{
|
|
||||||
return err_strerr[-err];
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* LWIP_DEBUG */
|
|
|
@ -1,240 +0,0 @@
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
* Network buffer management
|
|
||||||
*
|
|
||||||
**/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "lwip/opt.h"
|
|
||||||
|
|
||||||
#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
|
|
||||||
|
|
||||||
#include "lwip/netbuf.h"
|
|
||||||
#include "lwip/memp.h"
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create (allocate) and initialize a new netbuf.
|
|
||||||
* The netbuf doesn't yet contain a packet buffer!
|
|
||||||
*
|
|
||||||
* @return a pointer to a new netbuf
|
|
||||||
* NULL on lack of memory
|
|
||||||
*/
|
|
||||||
struct
|
|
||||||
netbuf *netbuf_new(void)
|
|
||||||
{
|
|
||||||
struct netbuf *buf;
|
|
||||||
|
|
||||||
buf = memp_malloc(MEMP_NETBUF);
|
|
||||||
if (buf != NULL) {
|
|
||||||
buf->p = NULL;
|
|
||||||
buf->ptr = NULL;
|
|
||||||
buf->addr = NULL;
|
|
||||||
buf->port = 0;
|
|
||||||
#if LWIP_NETBUF_RECVINFO
|
|
||||||
buf->toaddr = NULL;
|
|
||||||
buf->toport = 0;
|
|
||||||
#endif /* LWIP_NETBUF_RECVINFO */
|
|
||||||
return buf;
|
|
||||||
} else {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deallocate a netbuf allocated by netbuf_new().
|
|
||||||
*
|
|
||||||
* @param buf pointer to a netbuf allocated by netbuf_new()
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
netbuf_delete(struct netbuf *buf)
|
|
||||||
{
|
|
||||||
if (buf != NULL) {
|
|
||||||
if (buf->p != NULL) {
|
|
||||||
pbuf_free(buf->p);
|
|
||||||
buf->p = buf->ptr = NULL;
|
|
||||||
}
|
|
||||||
memp_free(MEMP_NETBUF, buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Allocate memory for a packet buffer for a given netbuf.
|
|
||||||
*
|
|
||||||
* @param buf the netbuf for which to allocate a packet buffer
|
|
||||||
* @param size the size of the packet buffer to allocate
|
|
||||||
* @return pointer to the allocated memory
|
|
||||||
* NULL if no memory could be allocated
|
|
||||||
*/
|
|
||||||
void *
|
|
||||||
netbuf_alloc(struct netbuf *buf, u16_t size)
|
|
||||||
{
|
|
||||||
LWIP_ERROR("netbuf_alloc: invalid buf", (buf != NULL), return NULL;);
|
|
||||||
|
|
||||||
/* Deallocate any previously allocated memory. */
|
|
||||||
if (buf->p != NULL) {
|
|
||||||
pbuf_free(buf->p);
|
|
||||||
}
|
|
||||||
buf->p = pbuf_alloc(PBUF_TRANSPORT, size, PBUF_RAM);
|
|
||||||
if (buf->p == NULL) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
LWIP_ASSERT("check that first pbuf can hold size",
|
|
||||||
(buf->p->len >= size));
|
|
||||||
buf->ptr = buf->p;
|
|
||||||
return buf->p->payload;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Free the packet buffer included in a netbuf
|
|
||||||
*
|
|
||||||
* @param buf pointer to the netbuf which contains the packet buffer to free
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
netbuf_free(struct netbuf *buf)
|
|
||||||
{
|
|
||||||
LWIP_ERROR("netbuf_free: invalid buf", (buf != NULL), return;);
|
|
||||||
if (buf->p != NULL) {
|
|
||||||
pbuf_free(buf->p);
|
|
||||||
}
|
|
||||||
buf->p = buf->ptr = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Let a netbuf reference existing (non-volatile) data.
|
|
||||||
*
|
|
||||||
* @param buf netbuf which should reference the data
|
|
||||||
* @param dataptr pointer to the data to reference
|
|
||||||
* @param size size of the data
|
|
||||||
* @return ERR_OK if data is referenced
|
|
||||||
* ERR_MEM if data couldn't be referenced due to lack of memory
|
|
||||||
*/
|
|
||||||
err_t
|
|
||||||
netbuf_ref(struct netbuf *buf, const void *dataptr, u16_t size)
|
|
||||||
{
|
|
||||||
LWIP_ERROR("netbuf_ref: invalid buf", (buf != NULL), return ERR_ARG;);
|
|
||||||
if (buf->p != NULL) {
|
|
||||||
pbuf_free(buf->p);
|
|
||||||
}
|
|
||||||
buf->p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF);
|
|
||||||
if (buf->p == NULL) {
|
|
||||||
buf->ptr = NULL;
|
|
||||||
return ERR_MEM;
|
|
||||||
}
|
|
||||||
buf->p->payload = (void*)dataptr;
|
|
||||||
buf->p->len = buf->p->tot_len = size;
|
|
||||||
buf->ptr = buf->p;
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Chain one netbuf to another (@see pbuf_chain)
|
|
||||||
*
|
|
||||||
* @param head the first netbuf
|
|
||||||
* @param tail netbuf to chain after head, freed by this function, may not be reference after returning
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
netbuf_chain(struct netbuf *head, struct netbuf *tail)
|
|
||||||
{
|
|
||||||
LWIP_ERROR("netbuf_ref: invalid head", (head != NULL), return;);
|
|
||||||
LWIP_ERROR("netbuf_chain: invalid tail", (tail != NULL), return;);
|
|
||||||
pbuf_cat(head->p, tail->p);
|
|
||||||
head->ptr = head->p;
|
|
||||||
memp_free(MEMP_NETBUF, tail);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the data pointer and length of the data inside a netbuf.
|
|
||||||
*
|
|
||||||
* @param buf netbuf to get the data from
|
|
||||||
* @param dataptr pointer to a void pointer where to store the data pointer
|
|
||||||
* @param len pointer to an u16_t where the length of the data is stored
|
|
||||||
* @return ERR_OK if the information was retreived,
|
|
||||||
* ERR_BUF on error.
|
|
||||||
*/
|
|
||||||
err_t
|
|
||||||
netbuf_data(struct netbuf *buf, void **dataptr, u16_t *len)
|
|
||||||
{
|
|
||||||
LWIP_ERROR("netbuf_data: invalid buf", (buf != NULL), return ERR_ARG;);
|
|
||||||
LWIP_ERROR("netbuf_data: invalid dataptr", (dataptr != NULL), return ERR_ARG;);
|
|
||||||
LWIP_ERROR("netbuf_data: invalid len", (len != NULL), return ERR_ARG;);
|
|
||||||
|
|
||||||
if (buf->ptr == NULL) {
|
|
||||||
return ERR_BUF;
|
|
||||||
}
|
|
||||||
*dataptr = buf->ptr->payload;
|
|
||||||
*len = buf->ptr->len;
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Move the current data pointer of a packet buffer contained in a netbuf
|
|
||||||
* to the next part.
|
|
||||||
* The packet buffer itself is not modified.
|
|
||||||
*
|
|
||||||
* @param buf the netbuf to modify
|
|
||||||
* @return -1 if there is no next part
|
|
||||||
* 1 if moved to the next part but now there is no next part
|
|
||||||
* 0 if moved to the next part and there are still more parts
|
|
||||||
*/
|
|
||||||
s8_t
|
|
||||||
netbuf_next(struct netbuf *buf)
|
|
||||||
{
|
|
||||||
LWIP_ERROR("netbuf_free: invalid buf", (buf != NULL), return -1;);
|
|
||||||
if (buf->ptr->next == NULL) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
buf->ptr = buf->ptr->next;
|
|
||||||
if (buf->ptr->next == NULL) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Move the current data pointer of a packet buffer contained in a netbuf
|
|
||||||
* to the beginning of the packet.
|
|
||||||
* The packet buffer itself is not modified.
|
|
||||||
*
|
|
||||||
* @param buf the netbuf to modify
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
netbuf_first(struct netbuf *buf)
|
|
||||||
{
|
|
||||||
LWIP_ERROR("netbuf_free: invalid buf", (buf != NULL), return;);
|
|
||||||
buf->ptr = buf->p;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* LWIP_NETCONN */
|
|
|
@ -1,346 +0,0 @@
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
* API functions for name resolving
|
|
||||||
*
|
|
||||||
**/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Simon Goldschmidt
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "lwip/netdb.h"
|
|
||||||
|
|
||||||
#if LWIP_DNS && LWIP_SOCKET
|
|
||||||
|
|
||||||
#include "lwip/err.h"
|
|
||||||
#include "lwip/mem.h"
|
|
||||||
#include "lwip/ip_addr.h"
|
|
||||||
#include "lwip/api.h"
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
/** helper struct for gethostbyname_r to access the char* buffer */
|
|
||||||
struct gethostbyname_r_helper {
|
|
||||||
struct ip_addr *addrs;
|
|
||||||
struct ip_addr addr;
|
|
||||||
char *aliases;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** h_errno is exported in netdb.h for access by applications. */
|
|
||||||
#if LWIP_DNS_API_DECLARE_H_ERRNO
|
|
||||||
int h_errno;
|
|
||||||
#endif /* LWIP_DNS_API_DECLARE_H_ERRNO */
|
|
||||||
|
|
||||||
/** define "hostent" variables storage: 0 if we use a static (but unprotected)
|
|
||||||
* set of variables for lwip_gethostbyname, 1 if we use a local storage */
|
|
||||||
#ifndef LWIP_DNS_API_HOSTENT_STORAGE
|
|
||||||
#define LWIP_DNS_API_HOSTENT_STORAGE 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** define "hostent" variables storage */
|
|
||||||
#if LWIP_DNS_API_HOSTENT_STORAGE
|
|
||||||
#define HOSTENT_STORAGE
|
|
||||||
#else
|
|
||||||
#define HOSTENT_STORAGE static
|
|
||||||
#endif /* LWIP_DNS_API_STATIC_HOSTENT */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an entry containing addresses of address family AF_INET
|
|
||||||
* for the host with name name.
|
|
||||||
* Due to dns_gethostbyname limitations, only one address is returned.
|
|
||||||
*
|
|
||||||
* @param name the hostname to resolve
|
|
||||||
* @return an entry containing addresses of address family AF_INET
|
|
||||||
* for the host with name name
|
|
||||||
*/
|
|
||||||
struct hostent*
|
|
||||||
lwip_gethostbyname(const char *name)
|
|
||||||
{
|
|
||||||
err_t err;
|
|
||||||
struct ip_addr addr;
|
|
||||||
|
|
||||||
/* buffer variables for lwip_gethostbyname() */
|
|
||||||
HOSTENT_STORAGE struct hostent s_hostent;
|
|
||||||
HOSTENT_STORAGE char *s_aliases;
|
|
||||||
HOSTENT_STORAGE struct ip_addr s_hostent_addr;
|
|
||||||
HOSTENT_STORAGE struct ip_addr *s_phostent_addr;
|
|
||||||
|
|
||||||
/* query host IP address */
|
|
||||||
err = netconn_gethostbyname(name, &addr);
|
|
||||||
if (err != ERR_OK) {
|
|
||||||
LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err));
|
|
||||||
h_errno = HOST_NOT_FOUND;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* fill hostent */
|
|
||||||
s_hostent_addr = addr;
|
|
||||||
s_phostent_addr = &s_hostent_addr;
|
|
||||||
s_hostent.h_name = (char*)name;
|
|
||||||
s_hostent.h_aliases = &s_aliases;
|
|
||||||
s_hostent.h_addrtype = AF_INET;
|
|
||||||
s_hostent.h_length = sizeof(struct ip_addr);
|
|
||||||
s_hostent.h_addr_list = (char**)&s_phostent_addr;
|
|
||||||
|
|
||||||
#if DNS_DEBUG
|
|
||||||
/* dump hostent */
|
|
||||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_name == %s\n", s_hostent.h_name));
|
|
||||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases == %p\n", s_hostent.h_aliases));
|
|
||||||
if (s_hostent.h_aliases != NULL) {
|
|
||||||
u8_t idx;
|
|
||||||
for ( idx=0; s_hostent.h_aliases[idx]; idx++) {
|
|
||||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases[%i]-> == %p\n", idx, s_hostent.h_aliases[idx]));
|
|
||||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases[%i]-> == %s\n", idx, s_hostent.h_aliases[idx]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addrtype == %d\n", s_hostent.h_addrtype));
|
|
||||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_length == %d\n", s_hostent.h_length));
|
|
||||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list == %p\n", s_hostent.h_addr_list));
|
|
||||||
if (s_hostent.h_addr_list != NULL) {
|
|
||||||
u8_t idx;
|
|
||||||
for ( idx=0; s_hostent.h_addr_list[idx]; idx++) {
|
|
||||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i] == %p\n", idx, s_hostent.h_addr_list[idx]));
|
|
||||||
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i]-> == %s\n", idx, ip_ntoa(s_hostent.h_addr_list[idx])));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif /* DNS_DEBUG */
|
|
||||||
|
|
||||||
#if LWIP_DNS_API_HOSTENT_STORAGE
|
|
||||||
/* this function should return the "per-thread" hostent after copy from s_hostent */
|
|
||||||
return sys_thread_hostent(&s_hostent);
|
|
||||||
#else
|
|
||||||
return &s_hostent;
|
|
||||||
#endif /* LWIP_DNS_API_HOSTENT_STORAGE */
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Thread-safe variant of lwip_gethostbyname: instead of using a static
|
|
||||||
* buffer, this function takes buffer and errno pointers as arguments
|
|
||||||
* and uses these for the result.
|
|
||||||
*
|
|
||||||
* @param name the hostname to resolve
|
|
||||||
* @param ret pre-allocated struct where to store the result
|
|
||||||
* @param buf pre-allocated buffer where to store additional data
|
|
||||||
* @param buflen the size of buf
|
|
||||||
* @param result pointer to a hostent pointer that is set to ret on success
|
|
||||||
* and set to zero on error
|
|
||||||
* @param h_errnop pointer to an int where to store errors (instead of modifying
|
|
||||||
* the global h_errno)
|
|
||||||
* @return 0 on success, non-zero on error, additional error information
|
|
||||||
* is stored in *h_errnop instead of h_errno to be thread-safe
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf,
|
|
||||||
size_t buflen, struct hostent **result, int *h_errnop)
|
|
||||||
{
|
|
||||||
err_t err;
|
|
||||||
struct gethostbyname_r_helper *h;
|
|
||||||
char *hostname;
|
|
||||||
size_t namelen;
|
|
||||||
int lh_errno;
|
|
||||||
|
|
||||||
if (h_errnop == NULL) {
|
|
||||||
/* ensure h_errnop is never NULL */
|
|
||||||
h_errnop = &lh_errno;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result == NULL) {
|
|
||||||
/* not all arguments given */
|
|
||||||
*h_errnop = EINVAL;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
/* first thing to do: set *result to nothing */
|
|
||||||
*result = NULL;
|
|
||||||
if ((name == NULL) || (ret == NULL) || (buf == 0)) {
|
|
||||||
/* not all arguments given */
|
|
||||||
*h_errnop = EINVAL;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
namelen = strlen(name);
|
|
||||||
if (buflen < (sizeof(struct gethostbyname_r_helper) + namelen + 1 + (MEM_ALIGNMENT - 1))) {
|
|
||||||
/* buf can't hold the data needed + a copy of name */
|
|
||||||
*h_errnop = ERANGE;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
h = (struct gethostbyname_r_helper*)LWIP_MEM_ALIGN(buf);
|
|
||||||
hostname = ((char*)h) + sizeof(struct gethostbyname_r_helper);
|
|
||||||
|
|
||||||
/* query host IP address */
|
|
||||||
err = netconn_gethostbyname(name, &(h->addr));
|
|
||||||
if (err != ERR_OK) {
|
|
||||||
LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err));
|
|
||||||
*h_errnop = ENSRNOTFOUND;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* copy the hostname into buf */
|
|
||||||
MEMCPY(hostname, name, namelen);
|
|
||||||
hostname[namelen] = 0;
|
|
||||||
|
|
||||||
/* fill hostent */
|
|
||||||
h->addrs = &(h->addr);
|
|
||||||
h->aliases = NULL;
|
|
||||||
ret->h_name = (char*)hostname;
|
|
||||||
ret->h_aliases = &(h->aliases);
|
|
||||||
ret->h_addrtype = AF_INET;
|
|
||||||
ret->h_length = sizeof(struct ip_addr);
|
|
||||||
ret->h_addr_list = (char**)&(h->addrs);
|
|
||||||
|
|
||||||
/* set result != NULL */
|
|
||||||
*result = ret;
|
|
||||||
|
|
||||||
/* return success */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Frees one or more addrinfo structures returned by getaddrinfo(), along with
|
|
||||||
* any additional storage associated with those structures. If the ai_next field
|
|
||||||
* of the structure is not null, the entire list of structures is freed.
|
|
||||||
*
|
|
||||||
* @param ai struct addrinfo to free
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
lwip_freeaddrinfo(struct addrinfo *ai)
|
|
||||||
{
|
|
||||||
struct addrinfo *next;
|
|
||||||
|
|
||||||
while (ai != NULL) {
|
|
||||||
next = ai->ai_next;
|
|
||||||
mem_free(ai);
|
|
||||||
ai = next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Translates the name of a service location (for example, a host name) and/or
|
|
||||||
* a service name and returns a set of socket addresses and associated
|
|
||||||
* information to be used in creating a socket with which to address the
|
|
||||||
* specified service.
|
|
||||||
* Memory for the result is allocated internally and must be freed by calling
|
|
||||||
* lwip_freeaddrinfo()!
|
|
||||||
*
|
|
||||||
* Due to a limitation in dns_gethostbyname, only the first address of a
|
|
||||||
* host is returned.
|
|
||||||
* Also, service names are not supported (only port numbers)!
|
|
||||||
*
|
|
||||||
* @param nodename descriptive name or address string of the host
|
|
||||||
* (may be NULL -> local address)
|
|
||||||
* @param servname port number as string of NULL
|
|
||||||
* @param hints structure containing input values that set socktype and protocol
|
|
||||||
* @param res pointer to a pointer where to store the result (set to NULL on failure)
|
|
||||||
* @return 0 on success, non-zero on failure
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
lwip_getaddrinfo(const char *nodename, const char *servname,
|
|
||||||
const struct addrinfo *hints, struct addrinfo **res)
|
|
||||||
{
|
|
||||||
err_t err;
|
|
||||||
struct ip_addr addr;
|
|
||||||
struct addrinfo *ai;
|
|
||||||
struct sockaddr_in *sa = NULL;
|
|
||||||
int port_nr = 0;
|
|
||||||
size_t total_size;
|
|
||||||
size_t namelen = 0;
|
|
||||||
|
|
||||||
if (res == NULL) {
|
|
||||||
return EAI_FAIL;
|
|
||||||
}
|
|
||||||
*res = NULL;
|
|
||||||
if ((nodename == NULL) && (servname == NULL)) {
|
|
||||||
return EAI_NONAME;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (servname != NULL) {
|
|
||||||
/* service name specified: convert to port number
|
|
||||||
* @todo?: currently, only ASCII integers (port numbers) are supported! */
|
|
||||||
port_nr = atoi(servname);
|
|
||||||
if ((port_nr <= 0) || (port_nr > 0xffff)) {
|
|
||||||
return EAI_SERVICE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nodename != NULL) {
|
|
||||||
/* service location specified, try to resolve */
|
|
||||||
err = netconn_gethostbyname(nodename, &addr);
|
|
||||||
if (err != ERR_OK) {
|
|
||||||
return EAI_FAIL;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* service location specified, use loopback address */
|
|
||||||
addr.addr = htonl(INADDR_LOOPBACK);
|
|
||||||
}
|
|
||||||
|
|
||||||
total_size = sizeof(struct addrinfo) + sizeof(struct sockaddr_in);
|
|
||||||
if (nodename != NULL) {
|
|
||||||
namelen = strlen(nodename);
|
|
||||||
LWIP_ASSERT("namelen is too long", (namelen + 1) <= (mem_size_t)-1);
|
|
||||||
total_size += namelen + 1;
|
|
||||||
}
|
|
||||||
ai = mem_malloc(total_size);
|
|
||||||
if (ai == NULL) {
|
|
||||||
goto memerr;
|
|
||||||
}
|
|
||||||
memset(ai, 0, total_size);
|
|
||||||
sa = (struct sockaddr_in*)((u8_t*)ai + sizeof(struct addrinfo));
|
|
||||||
/* set up sockaddr */
|
|
||||||
sa->sin_addr.s_addr = addr.addr;
|
|
||||||
sa->sin_family = AF_INET;
|
|
||||||
sa->sin_len = sizeof(struct sockaddr_in);
|
|
||||||
sa->sin_port = htons(port_nr);
|
|
||||||
|
|
||||||
/* set up addrinfo */
|
|
||||||
ai->ai_family = AF_INET;
|
|
||||||
if (hints != NULL) {
|
|
||||||
/* copy socktype & protocol from hints if specified */
|
|
||||||
ai->ai_socktype = hints->ai_socktype;
|
|
||||||
ai->ai_protocol = hints->ai_protocol;
|
|
||||||
}
|
|
||||||
if (nodename != NULL) {
|
|
||||||
/* copy nodename to canonname if specified */
|
|
||||||
ai->ai_canonname = ((char*)ai + sizeof(struct addrinfo) + sizeof(struct sockaddr_in));
|
|
||||||
MEMCPY(ai->ai_canonname, nodename, namelen);
|
|
||||||
ai->ai_canonname[namelen] = 0;
|
|
||||||
}
|
|
||||||
ai->ai_addrlen = sizeof(struct sockaddr_in);
|
|
||||||
ai->ai_addr = (struct sockaddr*)sa;
|
|
||||||
|
|
||||||
*res = ai;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
memerr:
|
|
||||||
if (ai != NULL) {
|
|
||||||
mem_free(ai);
|
|
||||||
}
|
|
||||||
return EAI_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* LWIP_DNS && LWIP_SOCKET */
|
|
|
@ -1,162 +0,0 @@
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
* Network Interface Sequential API module
|
|
||||||
*
|
|
||||||
**/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "lwip/opt.h"
|
|
||||||
|
|
||||||
#if LWIP_NETIF_API /* don't build if not configured for use in lwipopts.h */
|
|
||||||
|
|
||||||
#include "lwip/netifapi.h"
|
|
||||||
#include "lwip/tcpip.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Call netif_add() inside the tcpip_thread context.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
do_netifapi_netif_add( struct netifapi_msg_msg *msg)
|
|
||||||
{
|
|
||||||
if (!netif_add( msg->netif,
|
|
||||||
msg->msg.add.ipaddr,
|
|
||||||
msg->msg.add.netmask,
|
|
||||||
msg->msg.add.gw,
|
|
||||||
msg->msg.add.state,
|
|
||||||
msg->msg.add.init,
|
|
||||||
msg->msg.add.input)) {
|
|
||||||
msg->err = ERR_IF;
|
|
||||||
} else {
|
|
||||||
msg->err = ERR_OK;
|
|
||||||
}
|
|
||||||
TCPIP_NETIFAPI_ACK(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Call netif_set_addr() inside the tcpip_thread context.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
do_netifapi_netif_set_addr( struct netifapi_msg_msg *msg)
|
|
||||||
{
|
|
||||||
netif_set_addr( msg->netif,
|
|
||||||
msg->msg.add.ipaddr,
|
|
||||||
msg->msg.add.netmask,
|
|
||||||
msg->msg.add.gw);
|
|
||||||
msg->err = ERR_OK;
|
|
||||||
TCPIP_NETIFAPI_ACK(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Call the "errtfunc" (or the "voidfunc" if "errtfunc" is NULL) inside the
|
|
||||||
* tcpip_thread context.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
do_netifapi_netif_common( struct netifapi_msg_msg *msg)
|
|
||||||
{
|
|
||||||
if (msg->msg.common.errtfunc!=NULL) {
|
|
||||||
msg->err =
|
|
||||||
msg->msg.common.errtfunc(msg->netif);
|
|
||||||
} else {
|
|
||||||
msg->err = ERR_OK;
|
|
||||||
msg->msg.common.voidfunc(msg->netif);
|
|
||||||
}
|
|
||||||
TCPIP_NETIFAPI_ACK(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Call netif_add() in a thread-safe way by running that function inside the
|
|
||||||
* tcpip_thread context.
|
|
||||||
*
|
|
||||||
* @note for params @see netif_add()
|
|
||||||
*/
|
|
||||||
err_t
|
|
||||||
netifapi_netif_add(struct netif *netif,
|
|
||||||
struct ip_addr *ipaddr,
|
|
||||||
struct ip_addr *netmask,
|
|
||||||
struct ip_addr *gw,
|
|
||||||
void *state,
|
|
||||||
err_t (* init)(struct netif *netif),
|
|
||||||
err_t (* input)(struct pbuf *p, struct netif *netif))
|
|
||||||
{
|
|
||||||
struct netifapi_msg msg;
|
|
||||||
msg.function = do_netifapi_netif_add;
|
|
||||||
msg.msg.netif = netif;
|
|
||||||
msg.msg.msg.add.ipaddr = ipaddr;
|
|
||||||
msg.msg.msg.add.netmask = netmask;
|
|
||||||
msg.msg.msg.add.gw = gw;
|
|
||||||
msg.msg.msg.add.state = state;
|
|
||||||
msg.msg.msg.add.init = init;
|
|
||||||
msg.msg.msg.add.input = input;
|
|
||||||
TCPIP_NETIFAPI(&msg);
|
|
||||||
return msg.msg.err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Call netif_set_addr() in a thread-safe way by running that function inside the
|
|
||||||
* tcpip_thread context.
|
|
||||||
*
|
|
||||||
* @note for params @see netif_set_addr()
|
|
||||||
*/
|
|
||||||
err_t
|
|
||||||
netifapi_netif_set_addr(struct netif *netif,
|
|
||||||
struct ip_addr *ipaddr,
|
|
||||||
struct ip_addr *netmask,
|
|
||||||
struct ip_addr *gw)
|
|
||||||
{
|
|
||||||
struct netifapi_msg msg;
|
|
||||||
msg.function = do_netifapi_netif_set_addr;
|
|
||||||
msg.msg.netif = netif;
|
|
||||||
msg.msg.msg.add.ipaddr = ipaddr;
|
|
||||||
msg.msg.msg.add.netmask = netmask;
|
|
||||||
msg.msg.msg.add.gw = gw;
|
|
||||||
TCPIP_NETIFAPI(&msg);
|
|
||||||
return msg.msg.err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* call the "errtfunc" (or the "voidfunc" if "errtfunc" is NULL) in a thread-safe
|
|
||||||
* way by running that function inside the tcpip_thread context.
|
|
||||||
*
|
|
||||||
* @note use only for functions where there is only "netif" parameter.
|
|
||||||
*/
|
|
||||||
err_t
|
|
||||||
netifapi_netif_common( struct netif *netif,
|
|
||||||
void (* voidfunc)(struct netif *netif),
|
|
||||||
err_t (* errtfunc)(struct netif *netif) )
|
|
||||||
{
|
|
||||||
struct netifapi_msg msg;
|
|
||||||
msg.function = do_netifapi_netif_common;
|
|
||||||
msg.msg.netif = netif;
|
|
||||||
msg.msg.msg.common.voidfunc = voidfunc;
|
|
||||||
msg.msg.msg.common.errtfunc = errtfunc;
|
|
||||||
TCPIP_NETIFAPI(&msg);
|
|
||||||
return msg.msg.err;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* LWIP_NETIF_API */
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,596 +0,0 @@
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
* Sequential API Main thread module
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "lwip/opt.h"
|
|
||||||
|
|
||||||
#if !NO_SYS /* don't build if not configured for use in lwipopts.h */
|
|
||||||
|
|
||||||
#include "lwip/sys.h"
|
|
||||||
#include "lwip/memp.h"
|
|
||||||
#include "lwip/pbuf.h"
|
|
||||||
#include "lwip/ip_frag.h"
|
|
||||||
#include "lwip/tcp.h"
|
|
||||||
#include "lwip/autoip.h"
|
|
||||||
#include "lwip/dhcp.h"
|
|
||||||
#include "lwip/igmp.h"
|
|
||||||
#include "lwip/dns.h"
|
|
||||||
#include "lwip/tcpip.h"
|
|
||||||
#include "lwip/init.h"
|
|
||||||
#include "netif/etharp.h"
|
|
||||||
#include "netif/ppp_oe.h"
|
|
||||||
|
|
||||||
/* global variables */
|
|
||||||
static void (* tcpip_init_done)(void *arg);
|
|
||||||
static void *tcpip_init_done_arg;
|
|
||||||
static sys_mbox_t mbox = SYS_MBOX_NULL;
|
|
||||||
|
|
||||||
#if LWIP_TCPIP_CORE_LOCKING
|
|
||||||
/** The global semaphore to lock the stack. */
|
|
||||||
sys_sem_t lock_tcpip_core;
|
|
||||||
#endif /* LWIP_TCPIP_CORE_LOCKING */
|
|
||||||
|
|
||||||
#if LWIP_TCP
|
|
||||||
/* global variable that shows if the tcp timer is currently scheduled or not */
|
|
||||||
static int tcpip_tcp_timer_active;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Timer callback function that calls tcp_tmr() and reschedules itself.
|
|
||||||
*
|
|
||||||
* @param arg unused argument
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
tcpip_tcp_timer(void *arg)
|
|
||||||
{
|
|
||||||
LWIP_UNUSED_ARG(arg);
|
|
||||||
|
|
||||||
/* call TCP timer handler */
|
|
||||||
tcp_tmr();
|
|
||||||
/* timer still needed? */
|
|
||||||
if (tcp_active_pcbs || tcp_tw_pcbs) {
|
|
||||||
/* restart timer */
|
|
||||||
sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);
|
|
||||||
} else {
|
|
||||||
/* disable timer */
|
|
||||||
tcpip_tcp_timer_active = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if !NO_SYS
|
|
||||||
/**
|
|
||||||
* Called from TCP_REG when registering a new PCB:
|
|
||||||
* the reason is to have the TCP timer only running when
|
|
||||||
* there are active (or time-wait) PCBs.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
tcp_timer_needed(void)
|
|
||||||
{
|
|
||||||
/* timer is off but needed again? */
|
|
||||||
if (!tcpip_tcp_timer_active && (tcp_active_pcbs || tcp_tw_pcbs)) {
|
|
||||||
/* enable and start timer */
|
|
||||||
tcpip_tcp_timer_active = 1;
|
|
||||||
sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif /* !NO_SYS */
|
|
||||||
#endif /* LWIP_TCP */
|
|
||||||
|
|
||||||
#if IP_REASSEMBLY
|
|
||||||
/**
|
|
||||||
* Timer callback function that calls ip_reass_tmr() and reschedules itself.
|
|
||||||
*
|
|
||||||
* @param arg unused argument
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
ip_reass_timer(void *arg)
|
|
||||||
{
|
|
||||||
LWIP_UNUSED_ARG(arg);
|
|
||||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: ip_reass_tmr()\n"));
|
|
||||||
ip_reass_tmr();
|
|
||||||
sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL);
|
|
||||||
}
|
|
||||||
#endif /* IP_REASSEMBLY */
|
|
||||||
|
|
||||||
#if LWIP_ARP
|
|
||||||
/**
|
|
||||||
* Timer callback function that calls etharp_tmr() and reschedules itself.
|
|
||||||
*
|
|
||||||
* @param arg unused argument
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
arp_timer(void *arg)
|
|
||||||
{
|
|
||||||
LWIP_UNUSED_ARG(arg);
|
|
||||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: etharp_tmr()\n"));
|
|
||||||
etharp_tmr();
|
|
||||||
sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
|
|
||||||
}
|
|
||||||
#endif /* LWIP_ARP */
|
|
||||||
|
|
||||||
#if LWIP_DHCP
|
|
||||||
/**
|
|
||||||
* Timer callback function that calls dhcp_coarse_tmr() and reschedules itself.
|
|
||||||
*
|
|
||||||
* @param arg unused argument
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
dhcp_timer_coarse(void *arg)
|
|
||||||
{
|
|
||||||
LWIP_UNUSED_ARG(arg);
|
|
||||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: dhcp_coarse_tmr()\n"));
|
|
||||||
dhcp_coarse_tmr();
|
|
||||||
sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Timer callback function that calls dhcp_fine_tmr() and reschedules itself.
|
|
||||||
*
|
|
||||||
* @param arg unused argument
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
dhcp_timer_fine(void *arg)
|
|
||||||
{
|
|
||||||
LWIP_UNUSED_ARG(arg);
|
|
||||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: dhcp_fine_tmr()\n"));
|
|
||||||
dhcp_fine_tmr();
|
|
||||||
sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL);
|
|
||||||
}
|
|
||||||
#endif /* LWIP_DHCP */
|
|
||||||
|
|
||||||
#if LWIP_AUTOIP
|
|
||||||
/**
|
|
||||||
* Timer callback function that calls autoip_tmr() and reschedules itself.
|
|
||||||
*
|
|
||||||
* @param arg unused argument
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
autoip_timer(void *arg)
|
|
||||||
{
|
|
||||||
LWIP_UNUSED_ARG(arg);
|
|
||||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: autoip_tmr()\n"));
|
|
||||||
autoip_tmr();
|
|
||||||
sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL);
|
|
||||||
}
|
|
||||||
#endif /* LWIP_AUTOIP */
|
|
||||||
|
|
||||||
#if LWIP_IGMP
|
|
||||||
/**
|
|
||||||
* Timer callback function that calls igmp_tmr() and reschedules itself.
|
|
||||||
*
|
|
||||||
* @param arg unused argument
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
igmp_timer(void *arg)
|
|
||||||
{
|
|
||||||
LWIP_UNUSED_ARG(arg);
|
|
||||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: igmp_tmr()\n"));
|
|
||||||
igmp_tmr();
|
|
||||||
sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL);
|
|
||||||
}
|
|
||||||
#endif /* LWIP_IGMP */
|
|
||||||
|
|
||||||
#if LWIP_DNS
|
|
||||||
/**
|
|
||||||
* Timer callback function that calls dns_tmr() and reschedules itself.
|
|
||||||
*
|
|
||||||
* @param arg unused argument
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
dns_timer(void *arg)
|
|
||||||
{
|
|
||||||
LWIP_UNUSED_ARG(arg);
|
|
||||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: dns_tmr()\n"));
|
|
||||||
dns_tmr();
|
|
||||||
sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL);
|
|
||||||
}
|
|
||||||
#endif /* LWIP_DNS */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The main lwIP thread. This thread has exclusive access to lwIP core functions
|
|
||||||
* (unless access to them is not locked). Other threads communicate with this
|
|
||||||
* thread using message boxes.
|
|
||||||
*
|
|
||||||
* It also starts all the timers to make sure they are running in the right
|
|
||||||
* thread context.
|
|
||||||
*
|
|
||||||
* @param arg unused argument
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
tcpip_thread(void *arg)
|
|
||||||
{
|
|
||||||
struct tcpip_msg *msg;
|
|
||||||
LWIP_UNUSED_ARG(arg);
|
|
||||||
|
|
||||||
#if IP_REASSEMBLY
|
|
||||||
sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL);
|
|
||||||
#endif /* IP_REASSEMBLY */
|
|
||||||
#if LWIP_ARP
|
|
||||||
sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
|
|
||||||
#endif /* LWIP_ARP */
|
|
||||||
#if LWIP_DHCP
|
|
||||||
sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL);
|
|
||||||
sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL);
|
|
||||||
#endif /* LWIP_DHCP */
|
|
||||||
#if LWIP_AUTOIP
|
|
||||||
sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL);
|
|
||||||
#endif /* LWIP_AUTOIP */
|
|
||||||
#if LWIP_IGMP
|
|
||||||
sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL);
|
|
||||||
#endif /* LWIP_IGMP */
|
|
||||||
#if LWIP_DNS
|
|
||||||
sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL);
|
|
||||||
#endif /* LWIP_DNS */
|
|
||||||
|
|
||||||
if (tcpip_init_done != NULL) {
|
|
||||||
tcpip_init_done(tcpip_init_done_arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
LOCK_TCPIP_CORE();
|
|
||||||
while (1) { /* MAIN Loop */
|
|
||||||
sys_mbox_fetch(mbox, (void *)&msg);
|
|
||||||
switch (msg->type) {
|
|
||||||
#if LWIP_NETCONN
|
|
||||||
case TCPIP_MSG_API:
|
|
||||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API message %p\n", (void *)msg));
|
|
||||||
msg->msg.apimsg->function(&(msg->msg.apimsg->msg));
|
|
||||||
break;
|
|
||||||
#endif /* LWIP_NETCONN */
|
|
||||||
|
|
||||||
case TCPIP_MSG_INPKT:
|
|
||||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: PACKET %p\n", (void *)msg));
|
|
||||||
#if LWIP_ARP
|
|
||||||
if (msg->msg.inp.netif->flags & NETIF_FLAG_ETHARP) {
|
|
||||||
ethernet_input(msg->msg.inp.p, msg->msg.inp.netif);
|
|
||||||
} else
|
|
||||||
#endif /* LWIP_ARP */
|
|
||||||
{ ip_input(msg->msg.inp.p, msg->msg.inp.netif);
|
|
||||||
}
|
|
||||||
memp_free(MEMP_TCPIP_MSG_INPKT, msg);
|
|
||||||
break;
|
|
||||||
|
|
||||||
#if LWIP_NETIF_API
|
|
||||||
case TCPIP_MSG_NETIFAPI:
|
|
||||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: Netif API message %p\n", (void *)msg));
|
|
||||||
msg->msg.netifapimsg->function(&(msg->msg.netifapimsg->msg));
|
|
||||||
break;
|
|
||||||
#endif /* LWIP_NETIF_API */
|
|
||||||
|
|
||||||
case TCPIP_MSG_CALLBACK:
|
|
||||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg));
|
|
||||||
msg->msg.cb.f(msg->msg.cb.ctx);
|
|
||||||
memp_free(MEMP_TCPIP_MSG_API, msg);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TCPIP_MSG_TIMEOUT:
|
|
||||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: TIMEOUT %p\n", (void *)msg));
|
|
||||||
sys_timeout(msg->msg.tmo.msecs, msg->msg.tmo.h, msg->msg.tmo.arg);
|
|
||||||
memp_free(MEMP_TCPIP_MSG_API, msg);
|
|
||||||
break;
|
|
||||||
case TCPIP_MSG_UNTIMEOUT:
|
|
||||||
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: UNTIMEOUT %p\n", (void *)msg));
|
|
||||||
sys_untimeout(msg->msg.tmo.h, msg->msg.tmo.arg);
|
|
||||||
memp_free(MEMP_TCPIP_MSG_API, msg);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pass a received packet to tcpip_thread for input processing
|
|
||||||
*
|
|
||||||
* @param p the received packet, p->payload pointing to the Ethernet header or
|
|
||||||
* to an IP header (if netif doesn't got NETIF_FLAG_ETHARP flag)
|
|
||||||
* @param inp the network interface on which the packet was received
|
|
||||||
*/
|
|
||||||
err_t
|
|
||||||
tcpip_input(struct pbuf *p, struct netif *inp)
|
|
||||||
{
|
|
||||||
struct tcpip_msg *msg;
|
|
||||||
|
|
||||||
if (mbox != SYS_MBOX_NULL) {
|
|
||||||
msg = memp_malloc(MEMP_TCPIP_MSG_INPKT);
|
|
||||||
if (msg == NULL) {
|
|
||||||
return ERR_MEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
msg->type = TCPIP_MSG_INPKT;
|
|
||||||
msg->msg.inp.p = p;
|
|
||||||
msg->msg.inp.netif = inp;
|
|
||||||
if (sys_mbox_trypost(mbox, msg) != ERR_OK) {
|
|
||||||
memp_free(MEMP_TCPIP_MSG_INPKT, msg);
|
|
||||||
return ERR_MEM;
|
|
||||||
}
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
|
||||||
return ERR_VAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Call a specific function in the thread context of
|
|
||||||
* tcpip_thread for easy access synchronization.
|
|
||||||
* A function called in that way may access lwIP core code
|
|
||||||
* without fearing concurrent access.
|
|
||||||
*
|
|
||||||
* @param f the function to call
|
|
||||||
* @param ctx parameter passed to f
|
|
||||||
* @param block 1 to block until the request is posted, 0 to non-blocking mode
|
|
||||||
* @return ERR_OK if the function was called, another err_t if not
|
|
||||||
*/
|
|
||||||
err_t
|
|
||||||
tcpip_callback_with_block(void (*f)(void *ctx), void *ctx, u8_t block)
|
|
||||||
{
|
|
||||||
struct tcpip_msg *msg;
|
|
||||||
|
|
||||||
if (mbox != SYS_MBOX_NULL) {
|
|
||||||
msg = memp_malloc(MEMP_TCPIP_MSG_API);
|
|
||||||
if (msg == NULL) {
|
|
||||||
return ERR_MEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
msg->type = TCPIP_MSG_CALLBACK;
|
|
||||||
msg->msg.cb.f = f;
|
|
||||||
msg->msg.cb.ctx = ctx;
|
|
||||||
if (block) {
|
|
||||||
sys_mbox_post(mbox, msg);
|
|
||||||
} else {
|
|
||||||
if (sys_mbox_trypost(mbox, msg) != ERR_OK) {
|
|
||||||
memp_free(MEMP_TCPIP_MSG_API, msg);
|
|
||||||
return ERR_MEM;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
|
||||||
return ERR_VAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* call sys_timeout in tcpip_thread
|
|
||||||
*
|
|
||||||
* @param msec time in miliseconds for timeout
|
|
||||||
* @param h function to be called on timeout
|
|
||||||
* @param arg argument to pass to timeout function h
|
|
||||||
* @return ERR_MEM on memory error, ERR_OK otherwise
|
|
||||||
*/
|
|
||||||
err_t
|
|
||||||
tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg)
|
|
||||||
{
|
|
||||||
struct tcpip_msg *msg;
|
|
||||||
|
|
||||||
if (mbox != SYS_MBOX_NULL) {
|
|
||||||
msg = memp_malloc(MEMP_TCPIP_MSG_API);
|
|
||||||
if (msg == NULL) {
|
|
||||||
return ERR_MEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
msg->type = TCPIP_MSG_TIMEOUT;
|
|
||||||
msg->msg.tmo.msecs = msecs;
|
|
||||||
msg->msg.tmo.h = h;
|
|
||||||
msg->msg.tmo.arg = arg;
|
|
||||||
sys_mbox_post(mbox, msg);
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
|
||||||
return ERR_VAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* call sys_untimeout in tcpip_thread
|
|
||||||
*
|
|
||||||
* @param msec time in miliseconds for timeout
|
|
||||||
* @param h function to be called on timeout
|
|
||||||
* @param arg argument to pass to timeout function h
|
|
||||||
* @return ERR_MEM on memory error, ERR_OK otherwise
|
|
||||||
*/
|
|
||||||
err_t
|
|
||||||
tcpip_untimeout(sys_timeout_handler h, void *arg)
|
|
||||||
{
|
|
||||||
struct tcpip_msg *msg;
|
|
||||||
|
|
||||||
if (mbox != SYS_MBOX_NULL) {
|
|
||||||
msg = memp_malloc(MEMP_TCPIP_MSG_API);
|
|
||||||
if (msg == NULL) {
|
|
||||||
return ERR_MEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
msg->type = TCPIP_MSG_UNTIMEOUT;
|
|
||||||
msg->msg.tmo.h = h;
|
|
||||||
msg->msg.tmo.arg = arg;
|
|
||||||
sys_mbox_post(mbox, msg);
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
|
||||||
return ERR_VAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if LWIP_NETCONN
|
|
||||||
/**
|
|
||||||
* Call the lower part of a netconn_* function
|
|
||||||
* This function is then running in the thread context
|
|
||||||
* of tcpip_thread and has exclusive access to lwIP core code.
|
|
||||||
*
|
|
||||||
* @param apimsg a struct containing the function to call and its parameters
|
|
||||||
* @return ERR_OK if the function was called, another err_t if not
|
|
||||||
*/
|
|
||||||
err_t
|
|
||||||
tcpip_apimsg(struct api_msg *apimsg)
|
|
||||||
{
|
|
||||||
struct tcpip_msg msg;
|
|
||||||
|
|
||||||
if (mbox != SYS_MBOX_NULL) {
|
|
||||||
msg.type = TCPIP_MSG_API;
|
|
||||||
msg.msg.apimsg = apimsg;
|
|
||||||
sys_mbox_post(mbox, &msg);
|
|
||||||
sys_arch_sem_wait(apimsg->msg.conn->op_completed, 0);
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
|
||||||
return ERR_VAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if LWIP_TCPIP_CORE_LOCKING
|
|
||||||
/**
|
|
||||||
* Call the lower part of a netconn_* function
|
|
||||||
* This function has exclusive access to lwIP core code by locking it
|
|
||||||
* before the function is called.
|
|
||||||
*
|
|
||||||
* @param apimsg a struct containing the function to call and its parameters
|
|
||||||
* @return ERR_OK (only for compatibility fo tcpip_apimsg())
|
|
||||||
*/
|
|
||||||
err_t
|
|
||||||
tcpip_apimsg_lock(struct api_msg *apimsg)
|
|
||||||
{
|
|
||||||
LOCK_TCPIP_CORE();
|
|
||||||
apimsg->function(&(apimsg->msg));
|
|
||||||
UNLOCK_TCPIP_CORE();
|
|
||||||
return ERR_OK;
|
|
||||||
|
|
||||||
}
|
|
||||||
#endif /* LWIP_TCPIP_CORE_LOCKING */
|
|
||||||
#endif /* LWIP_NETCONN */
|
|
||||||
|
|
||||||
#if LWIP_NETIF_API
|
|
||||||
#if !LWIP_TCPIP_CORE_LOCKING
|
|
||||||
/**
|
|
||||||
* Much like tcpip_apimsg, but calls the lower part of a netifapi_*
|
|
||||||
* function.
|
|
||||||
*
|
|
||||||
* @param netifapimsg a struct containing the function to call and its parameters
|
|
||||||
* @return error code given back by the function that was called
|
|
||||||
*/
|
|
||||||
err_t
|
|
||||||
tcpip_netifapi(struct netifapi_msg* netifapimsg)
|
|
||||||
{
|
|
||||||
struct tcpip_msg msg;
|
|
||||||
|
|
||||||
if (mbox != SYS_MBOX_NULL) {
|
|
||||||
netifapimsg->msg.sem = sys_sem_new(0);
|
|
||||||
if (netifapimsg->msg.sem == SYS_SEM_NULL) {
|
|
||||||
netifapimsg->msg.err = ERR_MEM;
|
|
||||||
return netifapimsg->msg.err;
|
|
||||||
}
|
|
||||||
|
|
||||||
msg.type = TCPIP_MSG_NETIFAPI;
|
|
||||||
msg.msg.netifapimsg = netifapimsg;
|
|
||||||
sys_mbox_post(mbox, &msg);
|
|
||||||
sys_sem_wait(netifapimsg->msg.sem);
|
|
||||||
sys_sem_free(netifapimsg->msg.sem);
|
|
||||||
return netifapimsg->msg.err;
|
|
||||||
}
|
|
||||||
return ERR_VAL;
|
|
||||||
}
|
|
||||||
#else /* !LWIP_TCPIP_CORE_LOCKING */
|
|
||||||
/**
|
|
||||||
* Call the lower part of a netifapi_* function
|
|
||||||
* This function has exclusive access to lwIP core code by locking it
|
|
||||||
* before the function is called.
|
|
||||||
*
|
|
||||||
* @param netifapimsg a struct containing the function to call and its parameters
|
|
||||||
* @return ERR_OK (only for compatibility fo tcpip_netifapi())
|
|
||||||
*/
|
|
||||||
err_t
|
|
||||||
tcpip_netifapi_lock(struct netifapi_msg* netifapimsg)
|
|
||||||
{
|
|
||||||
LOCK_TCPIP_CORE();
|
|
||||||
netifapimsg->function(&(netifapimsg->msg));
|
|
||||||
UNLOCK_TCPIP_CORE();
|
|
||||||
return netifapimsg->msg.err;
|
|
||||||
}
|
|
||||||
#endif /* !LWIP_TCPIP_CORE_LOCKING */
|
|
||||||
#endif /* LWIP_NETIF_API */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize this module:
|
|
||||||
* - initialize all sub modules
|
|
||||||
* - start the tcpip_thread
|
|
||||||
*
|
|
||||||
* @param initfunc a function to call when tcpip_thread is running and finished initializing
|
|
||||||
* @param arg argument to pass to initfunc
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
tcpip_init(void (* initfunc)(void *), void *arg)
|
|
||||||
{
|
|
||||||
lwip_init();
|
|
||||||
|
|
||||||
tcpip_init_done = initfunc;
|
|
||||||
tcpip_init_done_arg = arg;
|
|
||||||
mbox = sys_mbox_new(TCPIP_MBOX_SIZE);
|
|
||||||
#if LWIP_TCPIP_CORE_LOCKING
|
|
||||||
lock_tcpip_core = sys_sem_new(1);
|
|
||||||
#endif /* LWIP_TCPIP_CORE_LOCKING */
|
|
||||||
|
|
||||||
sys_thread_new(TCPIP_THREAD_NAME, tcpip_thread, NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Simple callback function used with tcpip_callback to free a pbuf
|
|
||||||
* (pbuf_free has a wrong signature for tcpip_callback)
|
|
||||||
*
|
|
||||||
* @param p The pbuf (chain) to be dereferenced.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
pbuf_free_int(void *p)
|
|
||||||
{
|
|
||||||
struct pbuf *q = p;
|
|
||||||
pbuf_free(q);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A simple wrapper function that allows you to free a pbuf from interrupt context.
|
|
||||||
*
|
|
||||||
* @param p The pbuf (chain) to be dereferenced.
|
|
||||||
* @return ERR_OK if callback could be enqueued, an err_t if not
|
|
||||||
*/
|
|
||||||
err_t
|
|
||||||
pbuf_free_callback(struct pbuf *p)
|
|
||||||
{
|
|
||||||
return tcpip_callback_with_block(pbuf_free_int, p, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A simple wrapper function that allows you to free heap memory from
|
|
||||||
* interrupt context.
|
|
||||||
*
|
|
||||||
* @param m the heap memory to free
|
|
||||||
* @return ERR_OK if callback could be enqueued, an err_t if not
|
|
||||||
*/
|
|
||||||
err_t
|
|
||||||
mem_free_callback(void *m)
|
|
||||||
{
|
|
||||||
return tcpip_callback_with_block(mem_free, m, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* !NO_SYS */
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,980 +0,0 @@
|
||||||
/*
|
|
||||||
* @file
|
|
||||||
* DNS - host name to IP address resolver.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
|
|
||||||
* This file implements a DNS host name to IP address resolver.
|
|
||||||
|
|
||||||
* Port to lwIP from uIP
|
|
||||||
* by Jim Pettinato April 2007
|
|
||||||
|
|
||||||
* uIP version Copyright (c) 2002-2003, Adam Dunkels.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote
|
|
||||||
* products derived from this software without specific prior
|
|
||||||
* written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
|
||||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
|
||||||
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
||||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* DNS.C
|
|
||||||
*
|
|
||||||
* The lwIP DNS resolver functions are used to lookup a host name and
|
|
||||||
* map it to a numerical IP address. It maintains a list of resolved
|
|
||||||
* hostnames that can be queried with the dns_lookup() function.
|
|
||||||
* New hostnames can be resolved using the dns_query() function.
|
|
||||||
*
|
|
||||||
* The lwIP version of the resolver also adds a non-blocking version of
|
|
||||||
* gethostbyname() that will work with a raw API application. This function
|
|
||||||
* checks for an IP address string first and converts it if it is valid.
|
|
||||||
* gethostbyname() then does a dns_lookup() to see if the name is
|
|
||||||
* already in the table. If so, the IP is returned. If not, a query is
|
|
||||||
* issued and the function returns with a ERR_INPROGRESS status. The app
|
|
||||||
* using the dns client must then go into a waiting state.
|
|
||||||
*
|
|
||||||
* Once a hostname has been resolved (or found to be non-existent),
|
|
||||||
* the resolver code calls a specified callback function (which
|
|
||||||
* must be implemented by the module that uses the resolver).
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------
|
|
||||||
* RFC 1035 - Domain names - implementation and specification
|
|
||||||
* RFC 2181 - Clarifications to the DNS Specification
|
|
||||||
*----------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
/** @todo: define good default values (rfc compliance) */
|
|
||||||
/** @todo: improve answer parsing, more checkings... */
|
|
||||||
/** @todo: check RFC1035 - 7.3. Processing responses */
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------
|
|
||||||
* Includes
|
|
||||||
*----------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
#include "lwip/opt.h"
|
|
||||||
|
|
||||||
#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */
|
|
||||||
|
|
||||||
#include "lwip/udp.h"
|
|
||||||
#include "lwip/mem.h"
|
|
||||||
#include "lwip/dns.h"
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
/** DNS server IP address */
|
|
||||||
#ifndef DNS_SERVER_ADDRESS
|
|
||||||
#define DNS_SERVER_ADDRESS inet_addr("208.67.222.222") /* resolver1.opendns.com */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** DNS server port address */
|
|
||||||
#ifndef DNS_SERVER_PORT
|
|
||||||
#define DNS_SERVER_PORT 53
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** DNS maximum number of retries when asking for a name, before "timeout". */
|
|
||||||
#ifndef DNS_MAX_RETRIES
|
|
||||||
#define DNS_MAX_RETRIES 4
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** DNS resource record max. TTL (one week as default) */
|
|
||||||
#ifndef DNS_MAX_TTL
|
|
||||||
#define DNS_MAX_TTL 604800
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* DNS protocol flags */
|
|
||||||
#define DNS_FLAG1_RESPONSE 0x80
|
|
||||||
#define DNS_FLAG1_OPCODE_STATUS 0x10
|
|
||||||
#define DNS_FLAG1_OPCODE_INVERSE 0x08
|
|
||||||
#define DNS_FLAG1_OPCODE_STANDARD 0x00
|
|
||||||
#define DNS_FLAG1_AUTHORATIVE 0x04
|
|
||||||
#define DNS_FLAG1_TRUNC 0x02
|
|
||||||
#define DNS_FLAG1_RD 0x01
|
|
||||||
#define DNS_FLAG2_RA 0x80
|
|
||||||
#define DNS_FLAG2_ERR_MASK 0x0f
|
|
||||||
#define DNS_FLAG2_ERR_NONE 0x00
|
|
||||||
#define DNS_FLAG2_ERR_NAME 0x03
|
|
||||||
|
|
||||||
/* DNS protocol states */
|
|
||||||
#define DNS_STATE_UNUSED 0
|
|
||||||
#define DNS_STATE_NEW 1
|
|
||||||
#define DNS_STATE_ASKING 2
|
|
||||||
#define DNS_STATE_DONE 3
|
|
||||||
|
|
||||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
|
||||||
# include "arch/bpstruct.h"
|
|
||||||
#endif
|
|
||||||
PACK_STRUCT_BEGIN
|
|
||||||
/** DNS message header */
|
|
||||||
struct dns_hdr {
|
|
||||||
PACK_STRUCT_FIELD(u16_t id);
|
|
||||||
PACK_STRUCT_FIELD(u8_t flags1);
|
|
||||||
PACK_STRUCT_FIELD(u8_t flags2);
|
|
||||||
PACK_STRUCT_FIELD(u16_t numquestions);
|
|
||||||
PACK_STRUCT_FIELD(u16_t numanswers);
|
|
||||||
PACK_STRUCT_FIELD(u16_t numauthrr);
|
|
||||||
PACK_STRUCT_FIELD(u16_t numextrarr);
|
|
||||||
} PACK_STRUCT_STRUCT;
|
|
||||||
PACK_STRUCT_END
|
|
||||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
|
||||||
# include "arch/epstruct.h"
|
|
||||||
#endif
|
|
||||||
#define SIZEOF_DNS_HDR 12
|
|
||||||
|
|
||||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
|
||||||
# include "arch/bpstruct.h"
|
|
||||||
#endif
|
|
||||||
PACK_STRUCT_BEGIN
|
|
||||||
/** DNS query message structure */
|
|
||||||
struct dns_query {
|
|
||||||
/* DNS query record starts with either a domain name or a pointer
|
|
||||||
to a name already present somewhere in the packet. */
|
|
||||||
PACK_STRUCT_FIELD(u16_t type);
|
|
||||||
PACK_STRUCT_FIELD(u16_t class);
|
|
||||||
} PACK_STRUCT_STRUCT;
|
|
||||||
PACK_STRUCT_END
|
|
||||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
|
||||||
# include "arch/epstruct.h"
|
|
||||||
#endif
|
|
||||||
#define SIZEOF_DNS_QUERY 4
|
|
||||||
|
|
||||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
|
||||||
# include "arch/bpstruct.h"
|
|
||||||
#endif
|
|
||||||
PACK_STRUCT_BEGIN
|
|
||||||
/** DNS answer message structure */
|
|
||||||
struct dns_answer {
|
|
||||||
/* DNS answer record starts with either a domain name or a pointer
|
|
||||||
to a name already present somewhere in the packet. */
|
|
||||||
PACK_STRUCT_FIELD(u16_t type);
|
|
||||||
PACK_STRUCT_FIELD(u16_t class);
|
|
||||||
PACK_STRUCT_FIELD(u32_t ttl);
|
|
||||||
PACK_STRUCT_FIELD(u16_t len);
|
|
||||||
} PACK_STRUCT_STRUCT;
|
|
||||||
PACK_STRUCT_END
|
|
||||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
|
||||||
# include "arch/epstruct.h"
|
|
||||||
#endif
|
|
||||||
#define SIZEOF_DNS_ANSWER 10
|
|
||||||
|
|
||||||
/** DNS table entry */
|
|
||||||
struct dns_table_entry {
|
|
||||||
u8_t state;
|
|
||||||
u8_t numdns;
|
|
||||||
u8_t tmr;
|
|
||||||
u8_t retries;
|
|
||||||
u8_t seqno;
|
|
||||||
u8_t err;
|
|
||||||
u32_t ttl;
|
|
||||||
char name[DNS_MAX_NAME_LENGTH];
|
|
||||||
struct ip_addr ipaddr;
|
|
||||||
/* pointer to callback on DNS query done */
|
|
||||||
dns_found_callback found;
|
|
||||||
void *arg;
|
|
||||||
};
|
|
||||||
|
|
||||||
#if DNS_LOCAL_HOSTLIST
|
|
||||||
/** struct used for local host-list */
|
|
||||||
struct local_hostlist_entry {
|
|
||||||
/** static hostname */
|
|
||||||
const char *name;
|
|
||||||
/** static host address in network byteorder */
|
|
||||||
u32_t addr;
|
|
||||||
struct local_hostlist_entry *next;
|
|
||||||
};
|
|
||||||
|
|
||||||
#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
|
|
||||||
/** Local host-list. For hostnames in this list, no
|
|
||||||
* external name resolution is performed */
|
|
||||||
static struct local_hostlist_entry *local_hostlist_dynamic;
|
|
||||||
#else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
|
|
||||||
|
|
||||||
/** Defining this allows the local_hostlist_static to be placed in a different
|
|
||||||
* linker section (e.g. FLASH) */
|
|
||||||
#ifndef DNS_LOCAL_HOSTLIST_STORAGE_PRE
|
|
||||||
#define DNS_LOCAL_HOSTLIST_STORAGE_PRE static
|
|
||||||
#endif /* DNS_LOCAL_HOSTLIST_STORAGE_PRE */
|
|
||||||
/** Defining this allows the local_hostlist_static to be placed in a different
|
|
||||||
* linker section (e.g. FLASH) */
|
|
||||||
#ifndef DNS_LOCAL_HOSTLIST_STORAGE_POST
|
|
||||||
#define DNS_LOCAL_HOSTLIST_STORAGE_POST
|
|
||||||
#endif /* DNS_LOCAL_HOSTLIST_STORAGE_POST */
|
|
||||||
DNS_LOCAL_HOSTLIST_STORAGE_PRE struct local_hostlist_entry local_hostlist_static[]
|
|
||||||
DNS_LOCAL_HOSTLIST_STORAGE_POST = DNS_LOCAL_HOSTLIST_INIT;
|
|
||||||
|
|
||||||
#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
|
|
||||||
|
|
||||||
static void dns_init_local();
|
|
||||||
#endif /* DNS_LOCAL_HOSTLIST */
|
|
||||||
|
|
||||||
|
|
||||||
/* forward declarations */
|
|
||||||
static void dns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port);
|
|
||||||
static void dns_check_entries(void);
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------
|
|
||||||
* Globales
|
|
||||||
*----------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
/* DNS variables */
|
|
||||||
static struct udp_pcb *dns_pcb;
|
|
||||||
static u8_t dns_seqno;
|
|
||||||
static struct dns_table_entry dns_table[DNS_TABLE_SIZE];
|
|
||||||
static struct ip_addr dns_servers[DNS_MAX_SERVERS];
|
|
||||||
|
|
||||||
#if (DNS_USES_STATIC_BUF == 1)
|
|
||||||
static u8_t dns_payload[DNS_MSG_SIZE];
|
|
||||||
#endif /* (DNS_USES_STATIC_BUF == 1) */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize the resolver: set up the UDP pcb and configure the default server
|
|
||||||
* (DNS_SERVER_ADDRESS).
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
dns_init()
|
|
||||||
{
|
|
||||||
struct ip_addr dnsserver;
|
|
||||||
|
|
||||||
/* initialize default DNS server address */
|
|
||||||
dnsserver.addr = DNS_SERVER_ADDRESS;
|
|
||||||
|
|
||||||
LWIP_DEBUGF(DNS_DEBUG, ("dns_init: initializing\n"));
|
|
||||||
|
|
||||||
/* if dns client not yet initialized... */
|
|
||||||
if (dns_pcb == NULL) {
|
|
||||||
dns_pcb = udp_new();
|
|
||||||
|
|
||||||
if (dns_pcb != NULL) {
|
|
||||||
/* initialize DNS table not needed (initialized to zero since it is a
|
|
||||||
* global variable) */
|
|
||||||
LWIP_ASSERT("For implicit initialization to work, DNS_STATE_UNUSED needs to be 0",
|
|
||||||
DNS_STATE_UNUSED == 0);
|
|
||||||
|
|
||||||
/* initialize DNS client */
|
|
||||||
udp_bind(dns_pcb, IP_ADDR_ANY, 0);
|
|
||||||
udp_recv(dns_pcb, dns_recv, NULL);
|
|
||||||
|
|
||||||
/* initialize default DNS primary server */
|
|
||||||
dns_setserver(0, &dnsserver);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#if DNS_LOCAL_HOSTLIST
|
|
||||||
dns_init_local();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize one of the DNS servers.
|
|
||||||
*
|
|
||||||
* @param numdns the index of the DNS server to set must be < DNS_MAX_SERVERS
|
|
||||||
* @param dnsserver IP address of the DNS server to set
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
dns_setserver(u8_t numdns, struct ip_addr *dnsserver)
|
|
||||||
{
|
|
||||||
if ((numdns < DNS_MAX_SERVERS) && (dns_pcb != NULL) &&
|
|
||||||
(dnsserver != NULL) && (dnsserver->addr !=0 )) {
|
|
||||||
dns_servers[numdns] = (*dnsserver);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Obtain one of the currently configured DNS server.
|
|
||||||
*
|
|
||||||
* @param numdns the index of the DNS server
|
|
||||||
* @return IP address of the indexed DNS server or "ip_addr_any" if the DNS
|
|
||||||
* server has not been configured.
|
|
||||||
*/
|
|
||||||
struct ip_addr
|
|
||||||
dns_getserver(u8_t numdns)
|
|
||||||
{
|
|
||||||
if (numdns < DNS_MAX_SERVERS) {
|
|
||||||
return dns_servers[numdns];
|
|
||||||
} else {
|
|
||||||
return *IP_ADDR_ANY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The DNS resolver client timer - handle retries and timeouts and should
|
|
||||||
* be called every DNS_TMR_INTERVAL milliseconds (every second by default).
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
dns_tmr(void)
|
|
||||||
{
|
|
||||||
if (dns_pcb != NULL) {
|
|
||||||
LWIP_DEBUGF(DNS_DEBUG, ("dns_tmr: dns_check_entries\n"));
|
|
||||||
dns_check_entries();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if DNS_LOCAL_HOSTLIST
|
|
||||||
static void
|
|
||||||
dns_init_local()
|
|
||||||
{
|
|
||||||
#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT)
|
|
||||||
int i;
|
|
||||||
struct local_hostlist_entry *entry;
|
|
||||||
/* Dynamic: copy entries from DNS_LOCAL_HOSTLIST_INIT to list */
|
|
||||||
struct local_hostlist_entry local_hostlist_init[] = DNS_LOCAL_HOSTLIST_INIT;
|
|
||||||
for (i = 0; i < sizeof(local_hostlist_init) / sizeof(struct local_hostlist_entry); i++) {
|
|
||||||
entry = mem_malloc(sizeof(struct local_hostlist_entry));
|
|
||||||
LWIP_ASSERT("mem-error in dns_init_local", entry != NULL);
|
|
||||||
if (entry != NULL) {
|
|
||||||
struct local_hostlist_entry *init_entry = &local_hostlist_init[i];
|
|
||||||
entry->name = init_entry->name;
|
|
||||||
entry->addr = init_entry->addr;
|
|
||||||
entry->next = local_hostlist_dynamic;
|
|
||||||
local_hostlist_dynamic = entry;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT) */
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Scans the local host-list for a hostname.
|
|
||||||
*
|
|
||||||
* @param hostname Hostname to look for in the local host-list
|
|
||||||
* @return The first IP address for the hostname in the local host-list or
|
|
||||||
* INADDR_NONE if not found.
|
|
||||||
*/
|
|
||||||
static u32_t
|
|
||||||
dns_lookup_local(const char *hostname)
|
|
||||||
{
|
|
||||||
#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
|
|
||||||
struct local_hostlist_entry *entry = local_hostlist_dynamic;
|
|
||||||
while(entry != NULL) {
|
|
||||||
if(strcmp(entry->name, hostname) == 0) {
|
|
||||||
return entry->addr;
|
|
||||||
}
|
|
||||||
entry = entry->next;
|
|
||||||
}
|
|
||||||
#else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < sizeof(local_hostlist_static) / sizeof(struct local_hostlist_entry); i++) {
|
|
||||||
if(strcmp(local_hostlist_static[i].name, hostname) == 0) {
|
|
||||||
return local_hostlist_static[i].addr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
|
|
||||||
return INADDR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
|
|
||||||
/** Remove all entries from the local host-list for a specific hostname
|
|
||||||
* and/or IP addess
|
|
||||||
*
|
|
||||||
* @param hostname hostname for which entries shall be removed from the local
|
|
||||||
* host-list
|
|
||||||
* @param addr address for which entries shall be removed from the local host-list
|
|
||||||
* @return the number of removed entries
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
dns_local_removehost(const char *hostname, const struct ip_addr *addr)
|
|
||||||
{
|
|
||||||
int removed = 0;
|
|
||||||
struct local_hostlist_entry *entry = local_hostlist_dynamic;
|
|
||||||
struct local_hostlist_entry *last_entry = NULL;
|
|
||||||
while (entry != NULL) {
|
|
||||||
if (((hostname == NULL) || !strcmp(entry->name, hostname)) &&
|
|
||||||
((addr == NULL) || (entry->addr == addr->addr))) {
|
|
||||||
struct local_hostlist_entry *free_entry;
|
|
||||||
if (last_entry != NULL) {
|
|
||||||
last_entry->next = entry->next;
|
|
||||||
} else {
|
|
||||||
local_hostlist_dynamic = entry->next;
|
|
||||||
}
|
|
||||||
free_entry = entry;
|
|
||||||
entry = entry->next;
|
|
||||||
mem_free(free_entry);
|
|
||||||
removed++;
|
|
||||||
} else {
|
|
||||||
last_entry = entry;
|
|
||||||
entry = entry->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return removed;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a hostname/IP address pair to the local host-list.
|
|
||||||
* Duplicates are not checked.
|
|
||||||
*
|
|
||||||
* @param hostname hostname of the new entry
|
|
||||||
* @param addr IP address of the new entry
|
|
||||||
* @return ERR_OK if succeeded or ERR_MEM on memory error
|
|
||||||
*/
|
|
||||||
err_t
|
|
||||||
dns_local_addhost(const char *hostname, const struct ip_addr *addr)
|
|
||||||
{
|
|
||||||
struct local_hostlist_entry *entry;
|
|
||||||
entry = mem_malloc(sizeof(struct local_hostlist_entry));
|
|
||||||
if (entry == NULL) {
|
|
||||||
return ERR_MEM;
|
|
||||||
}
|
|
||||||
entry->name = hostname;
|
|
||||||
entry->addr = addr->addr;
|
|
||||||
entry->next = local_hostlist_dynamic;
|
|
||||||
local_hostlist_dynamic = entry;
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
|
||||||
#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC*/
|
|
||||||
#endif /* DNS_LOCAL_HOSTLIST */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Look up a hostname in the array of known hostnames.
|
|
||||||
*
|
|
||||||
* @note This function only looks in the internal array of known
|
|
||||||
* hostnames, it does not send out a query for the hostname if none
|
|
||||||
* was found. The function dns_enqueue() can be used to send a query
|
|
||||||
* for a hostname.
|
|
||||||
*
|
|
||||||
* @param name the hostname to look up
|
|
||||||
* @return the hostname's IP address, as u32_t (instead of struct ip_addr to
|
|
||||||
* better check for failure: != INADDR_NONE) or INADDR_NONE if the hostname
|
|
||||||
* was not found in the cached dns_table.
|
|
||||||
*/
|
|
||||||
static u32_t
|
|
||||||
dns_lookup(const char *name)
|
|
||||||
{
|
|
||||||
u8_t i;
|
|
||||||
#if DNS_LOCAL_HOSTLIST || defined(DNS_LOOKUP_LOCAL_EXTERN)
|
|
||||||
u32_t addr;
|
|
||||||
#endif /* DNS_LOCAL_HOSTLIST || defined(DNS_LOOKUP_LOCAL_EXTERN) */
|
|
||||||
#if DNS_LOCAL_HOSTLIST
|
|
||||||
if ((addr = dns_lookup_local(name)) != INADDR_NONE) {
|
|
||||||
return addr;
|
|
||||||
}
|
|
||||||
#endif /* DNS_LOCAL_HOSTLIST */
|
|
||||||
#ifdef DNS_LOOKUP_LOCAL_EXTERN
|
|
||||||
if((addr = DNS_LOOKUP_LOCAL_EXTERN(name)) != INADDR_NONE) {
|
|
||||||
return addr;
|
|
||||||
}
|
|
||||||
#endif /* DNS_LOOKUP_LOCAL_EXTERN */
|
|
||||||
|
|
||||||
/* Walk through name list, return entry if found. If not, return NULL. */
|
|
||||||
for (i = 0; i < DNS_TABLE_SIZE; ++i) {
|
|
||||||
if ((dns_table[i].state == DNS_STATE_DONE) &&
|
|
||||||
(strcmp(name, dns_table[i].name) == 0)) {
|
|
||||||
LWIP_DEBUGF(DNS_DEBUG, ("dns_lookup: \"%s\": found = ", name));
|
|
||||||
ip_addr_debug_print(DNS_DEBUG, &(dns_table[i].ipaddr));
|
|
||||||
LWIP_DEBUGF(DNS_DEBUG, ("\n"));
|
|
||||||
return dns_table[i].ipaddr.addr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return INADDR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if DNS_DOES_NAME_CHECK
|
|
||||||
/**
|
|
||||||
* Compare the "dotted" name "query" with the encoded name "response"
|
|
||||||
* to make sure an answer from the DNS server matches the current dns_table
|
|
||||||
* entry (otherwise, answers might arrive late for hostname not on the list
|
|
||||||
* any more).
|
|
||||||
*
|
|
||||||
* @param query hostname (not encoded) from the dns_table
|
|
||||||
* @param response encoded hostname in the DNS response
|
|
||||||
* @return 0: names equal; 1: names differ
|
|
||||||
*/
|
|
||||||
static u8_t
|
|
||||||
dns_compare_name(unsigned char *query, unsigned char *response)
|
|
||||||
{
|
|
||||||
unsigned char n;
|
|
||||||
|
|
||||||
do {
|
|
||||||
n = *response++;
|
|
||||||
/** @see RFC 1035 - 4.1.4. Message compression */
|
|
||||||
if ((n & 0xc0) == 0xc0) {
|
|
||||||
/* Compressed name */
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
/* Not compressed name */
|
|
||||||
while (n > 0) {
|
|
||||||
if ((*query) != (*response)) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
++response;
|
|
||||||
++query;
|
|
||||||
--n;
|
|
||||||
};
|
|
||||||
++query;
|
|
||||||
}
|
|
||||||
} while (*response != 0);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif /* DNS_DOES_NAME_CHECK */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Walk through a compact encoded DNS name and return the end of the name.
|
|
||||||
*
|
|
||||||
* @param query encoded DNS name in the DNS server response
|
|
||||||
* @return end of the name
|
|
||||||
*/
|
|
||||||
static unsigned char *
|
|
||||||
dns_parse_name(unsigned char *query)
|
|
||||||
{
|
|
||||||
unsigned char n;
|
|
||||||
|
|
||||||
do {
|
|
||||||
n = *query++;
|
|
||||||
/** @see RFC 1035 - 4.1.4. Message compression */
|
|
||||||
if ((n & 0xc0) == 0xc0) {
|
|
||||||
/* Compressed name */
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
/* Not compressed name */
|
|
||||||
while (n > 0) {
|
|
||||||
++query;
|
|
||||||
--n;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
} while (*query != 0);
|
|
||||||
|
|
||||||
return query + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a DNS query packet.
|
|
||||||
*
|
|
||||||
* @param numdns index of the DNS server in the dns_servers table
|
|
||||||
* @param name hostname to query
|
|
||||||
* @param id index of the hostname in dns_table, used as transaction ID in the
|
|
||||||
* DNS query packet
|
|
||||||
* @return ERR_OK if packet is sent; an err_t indicating the problem otherwise
|
|
||||||
*/
|
|
||||||
static err_t
|
|
||||||
dns_send(u8_t numdns, const char* name, u8_t id)
|
|
||||||
{
|
|
||||||
err_t err;
|
|
||||||
struct dns_hdr *hdr;
|
|
||||||
struct dns_query qry;
|
|
||||||
struct pbuf *p;
|
|
||||||
char *query, *nptr;
|
|
||||||
const char *pHostname;
|
|
||||||
u8_t n;
|
|
||||||
|
|
||||||
LWIP_DEBUGF(DNS_DEBUG, ("dns_send: dns_servers[%"U16_F"] \"%s\": request\n",
|
|
||||||
(u16_t)(numdns), name));
|
|
||||||
LWIP_ASSERT("dns server out of array", numdns < DNS_MAX_SERVERS);
|
|
||||||
LWIP_ASSERT("dns server has no IP address set", dns_servers[numdns].addr != 0);
|
|
||||||
|
|
||||||
/* if here, we have either a new query or a retry on a previous query to process */
|
|
||||||
p = pbuf_alloc(PBUF_TRANSPORT, SIZEOF_DNS_HDR + DNS_MAX_NAME_LENGTH +
|
|
||||||
SIZEOF_DNS_QUERY, PBUF_RAM);
|
|
||||||
if (p != NULL) {
|
|
||||||
LWIP_ASSERT("pbuf must be in one piece", p->next == NULL);
|
|
||||||
/* fill dns header */
|
|
||||||
hdr = (struct dns_hdr*)p->payload;
|
|
||||||
memset(hdr, 0, SIZEOF_DNS_HDR);
|
|
||||||
hdr->id = htons(id);
|
|
||||||
hdr->flags1 = DNS_FLAG1_RD;
|
|
||||||
hdr->numquestions = htons(1);
|
|
||||||
query = (char*)hdr + SIZEOF_DNS_HDR;
|
|
||||||
pHostname = name;
|
|
||||||
--pHostname;
|
|
||||||
|
|
||||||
/* convert hostname into suitable query format. */
|
|
||||||
do {
|
|
||||||
++pHostname;
|
|
||||||
nptr = query;
|
|
||||||
++query;
|
|
||||||
for(n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) {
|
|
||||||
*query = *pHostname;
|
|
||||||
++query;
|
|
||||||
++n;
|
|
||||||
}
|
|
||||||
*nptr = n;
|
|
||||||
} while(*pHostname != 0);
|
|
||||||
*query++='\0';
|
|
||||||
|
|
||||||
/* fill dns query */
|
|
||||||
qry.type = htons(DNS_RRTYPE_A);
|
|
||||||
qry.class = htons(DNS_RRCLASS_IN);
|
|
||||||
MEMCPY( query, &qry, SIZEOF_DNS_QUERY);
|
|
||||||
|
|
||||||
/* resize pbuf to the exact dns query */
|
|
||||||
pbuf_realloc(p, (query + SIZEOF_DNS_QUERY) - ((char*)(p->payload)));
|
|
||||||
|
|
||||||
/* connect to the server for faster receiving */
|
|
||||||
udp_connect(dns_pcb, &dns_servers[numdns], DNS_SERVER_PORT);
|
|
||||||
/* send dns packet */
|
|
||||||
err = udp_sendto(dns_pcb, p, &dns_servers[numdns], DNS_SERVER_PORT);
|
|
||||||
|
|
||||||
/* free pbuf */
|
|
||||||
pbuf_free(p);
|
|
||||||
} else {
|
|
||||||
err = ERR_MEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* dns_check_entry() - see if pEntry has not yet been queried and, if so, sends out a query.
|
|
||||||
* Check an entry in the dns_table:
|
|
||||||
* - send out query for new entries
|
|
||||||
* - retry old pending entries on timeout (also with different servers)
|
|
||||||
* - remove completed entries from the table if their TTL has expired
|
|
||||||
*
|
|
||||||
* @param i index of the dns_table entry to check
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
dns_check_entry(u8_t i)
|
|
||||||
{
|
|
||||||
struct dns_table_entry *pEntry = &dns_table[i];
|
|
||||||
|
|
||||||
LWIP_ASSERT("array index out of bounds", i < DNS_TABLE_SIZE);
|
|
||||||
|
|
||||||
switch(pEntry->state) {
|
|
||||||
|
|
||||||
case DNS_STATE_NEW: {
|
|
||||||
/* initialize new entry */
|
|
||||||
pEntry->state = DNS_STATE_ASKING;
|
|
||||||
pEntry->numdns = 0;
|
|
||||||
pEntry->tmr = 1;
|
|
||||||
pEntry->retries = 0;
|
|
||||||
|
|
||||||
/* send DNS packet for this entry */
|
|
||||||
dns_send(pEntry->numdns, pEntry->name, i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case DNS_STATE_ASKING: {
|
|
||||||
if (--pEntry->tmr == 0) {
|
|
||||||
if (++pEntry->retries == DNS_MAX_RETRIES) {
|
|
||||||
if ((pEntry->numdns+1<DNS_MAX_SERVERS) && (dns_servers[pEntry->numdns+1].addr!=0)) {
|
|
||||||
/* change of server */
|
|
||||||
pEntry->numdns++;
|
|
||||||
pEntry->tmr = 1;
|
|
||||||
pEntry->retries = 0;
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": timeout\n", pEntry->name));
|
|
||||||
/* call specified callback function if provided */
|
|
||||||
if (pEntry->found)
|
|
||||||
(*pEntry->found)(pEntry->name, NULL, pEntry->arg);
|
|
||||||
/* flush this entry */
|
|
||||||
pEntry->state = DNS_STATE_UNUSED;
|
|
||||||
pEntry->found = NULL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* wait longer for the next retry */
|
|
||||||
pEntry->tmr = pEntry->retries;
|
|
||||||
|
|
||||||
/* send DNS packet for this entry */
|
|
||||||
dns_send(pEntry->numdns, pEntry->name, i);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case DNS_STATE_DONE: {
|
|
||||||
/* if the time to live is nul */
|
|
||||||
if (--pEntry->ttl == 0) {
|
|
||||||
LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": flush\n", pEntry->name));
|
|
||||||
/* flush this entry */
|
|
||||||
pEntry->state = DNS_STATE_UNUSED;
|
|
||||||
pEntry->found = NULL;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case DNS_STATE_UNUSED:
|
|
||||||
/* nothing to do */
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
LWIP_ASSERT("unknown dns_table entry state:", 0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Call dns_check_entry for each entry in dns_table - check all entries.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
dns_check_entries(void)
|
|
||||||
{
|
|
||||||
u8_t i;
|
|
||||||
|
|
||||||
for (i = 0; i < DNS_TABLE_SIZE; ++i) {
|
|
||||||
dns_check_entry(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Receive input function for DNS response packets arriving for the dns UDP pcb.
|
|
||||||
*
|
|
||||||
* @params see udp.h
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port)
|
|
||||||
{
|
|
||||||
u8_t i;
|
|
||||||
char *pHostname;
|
|
||||||
struct dns_hdr *hdr;
|
|
||||||
struct dns_answer ans;
|
|
||||||
struct dns_table_entry *pEntry;
|
|
||||||
u8_t nquestions, nanswers;
|
|
||||||
#if (DNS_USES_STATIC_BUF == 0)
|
|
||||||
u8_t dns_payload[DNS_MSG_SIZE];
|
|
||||||
#endif /* (DNS_USES_STATIC_BUF == 0) */
|
|
||||||
#if (DNS_USES_STATIC_BUF == 2)
|
|
||||||
u8_t* dns_payload;
|
|
||||||
#endif /* (DNS_USES_STATIC_BUF == 2) */
|
|
||||||
|
|
||||||
LWIP_UNUSED_ARG(arg);
|
|
||||||
LWIP_UNUSED_ARG(pcb);
|
|
||||||
LWIP_UNUSED_ARG(addr);
|
|
||||||
LWIP_UNUSED_ARG(port);
|
|
||||||
|
|
||||||
/* is the dns message too big ? */
|
|
||||||
if (p->tot_len > DNS_MSG_SIZE) {
|
|
||||||
LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too big\n"));
|
|
||||||
/* free pbuf and return */
|
|
||||||
goto memerr1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* is the dns message big enough ? */
|
|
||||||
if (p->tot_len < (SIZEOF_DNS_HDR + SIZEOF_DNS_QUERY + SIZEOF_DNS_ANSWER)) {
|
|
||||||
LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too small\n"));
|
|
||||||
/* free pbuf and return */
|
|
||||||
goto memerr1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if (DNS_USES_STATIC_BUF == 2)
|
|
||||||
dns_payload = mem_malloc(p->tot_len);
|
|
||||||
if (dns_payload == NULL) {
|
|
||||||
LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: mem_malloc error\n"));
|
|
||||||
/* free pbuf and return */
|
|
||||||
goto memerr1;
|
|
||||||
}
|
|
||||||
#endif /* (DNS_USES_STATIC_BUF == 2) */
|
|
||||||
|
|
||||||
/* copy dns payload inside static buffer for processing */
|
|
||||||
if (pbuf_copy_partial(p, dns_payload, p->tot_len, 0) == p->tot_len) {
|
|
||||||
/* The ID in the DNS header should be our entry into the name table. */
|
|
||||||
hdr = (struct dns_hdr*)dns_payload;
|
|
||||||
i = htons(hdr->id);
|
|
||||||
if (i < DNS_TABLE_SIZE) {
|
|
||||||
pEntry = &dns_table[i];
|
|
||||||
if(pEntry->state == DNS_STATE_ASKING) {
|
|
||||||
/* This entry is now completed. */
|
|
||||||
pEntry->state = DNS_STATE_DONE;
|
|
||||||
pEntry->err = hdr->flags2 & DNS_FLAG2_ERR_MASK;
|
|
||||||
|
|
||||||
/* We only care about the question(s) and the answers. The authrr
|
|
||||||
and the extrarr are simply discarded. */
|
|
||||||
nquestions = htons(hdr->numquestions);
|
|
||||||
nanswers = htons(hdr->numanswers);
|
|
||||||
|
|
||||||
/* Check for error. If so, call callback to inform. */
|
|
||||||
if (((hdr->flags1 & DNS_FLAG1_RESPONSE) == 0) || (pEntry->err != 0) || (nquestions != 1)) {
|
|
||||||
LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in flags\n", pEntry->name));
|
|
||||||
/* call callback to indicate error, clean up memory and return */
|
|
||||||
goto responseerr;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if DNS_DOES_NAME_CHECK
|
|
||||||
/* Check if the name in the "question" part match with the name in the entry. */
|
|
||||||
if (dns_compare_name((unsigned char *)(pEntry->name), (unsigned char *)dns_payload + SIZEOF_DNS_HDR) != 0) {
|
|
||||||
LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to query\n", pEntry->name));
|
|
||||||
/* call callback to indicate error, clean up memory and return */
|
|
||||||
goto responseerr;
|
|
||||||
}
|
|
||||||
#endif /* DNS_DOES_NAME_CHECK */
|
|
||||||
|
|
||||||
/* Skip the name in the "question" part */
|
|
||||||
pHostname = (char *) dns_parse_name((unsigned char *)dns_payload + SIZEOF_DNS_HDR) + SIZEOF_DNS_QUERY;
|
|
||||||
|
|
||||||
while(nanswers > 0) {
|
|
||||||
/* skip answer resource record's host name */
|
|
||||||
pHostname = (char *) dns_parse_name((unsigned char *)pHostname);
|
|
||||||
|
|
||||||
/* Check for IP address type and Internet class. Others are discarded. */
|
|
||||||
MEMCPY(&ans, pHostname, SIZEOF_DNS_ANSWER);
|
|
||||||
if((ntohs(ans.type) == DNS_RRTYPE_A) && (ntohs(ans.class) == DNS_RRCLASS_IN) && (ntohs(ans.len) == sizeof(struct ip_addr)) ) {
|
|
||||||
/* read the answer resource record's TTL, and maximize it if needed */
|
|
||||||
pEntry->ttl = ntohl(ans.ttl);
|
|
||||||
if (pEntry->ttl > DNS_MAX_TTL) {
|
|
||||||
pEntry->ttl = DNS_MAX_TTL;
|
|
||||||
}
|
|
||||||
/* read the IP address after answer resource record's header */
|
|
||||||
MEMCPY( &(pEntry->ipaddr), (pHostname+SIZEOF_DNS_ANSWER), sizeof(struct ip_addr));
|
|
||||||
LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response = ", pEntry->name));
|
|
||||||
ip_addr_debug_print(DNS_DEBUG, (&(pEntry->ipaddr)));
|
|
||||||
LWIP_DEBUGF(DNS_DEBUG, ("\n"));
|
|
||||||
/* call specified callback function if provided */
|
|
||||||
if (pEntry->found) {
|
|
||||||
(*pEntry->found)(pEntry->name, &pEntry->ipaddr, pEntry->arg);
|
|
||||||
}
|
|
||||||
/* deallocate memory and return */
|
|
||||||
goto memerr2;
|
|
||||||
} else {
|
|
||||||
pHostname = pHostname + SIZEOF_DNS_ANSWER + htons(ans.len);
|
|
||||||
}
|
|
||||||
--nanswers;
|
|
||||||
}
|
|
||||||
LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in response\n", pEntry->name));
|
|
||||||
/* call callback to indicate error, clean up memory and return */
|
|
||||||
goto responseerr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* deallocate memory and return */
|
|
||||||
goto memerr2;
|
|
||||||
|
|
||||||
responseerr:
|
|
||||||
/* ERROR: call specified callback function with NULL as name to indicate an error */
|
|
||||||
if (pEntry->found) {
|
|
||||||
(*pEntry->found)(pEntry->name, NULL, pEntry->arg);
|
|
||||||
}
|
|
||||||
/* flush this entry */
|
|
||||||
pEntry->state = DNS_STATE_UNUSED;
|
|
||||||
pEntry->found = NULL;
|
|
||||||
|
|
||||||
memerr2:
|
|
||||||
#if (DNS_USES_STATIC_BUF == 2)
|
|
||||||
/* free dns buffer */
|
|
||||||
mem_free(dns_payload);
|
|
||||||
#endif /* (DNS_USES_STATIC_BUF == 2) */
|
|
||||||
|
|
||||||
memerr1:
|
|
||||||
/* free pbuf */
|
|
||||||
pbuf_free(p);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Queues a new hostname to resolve and sends out a DNS query for that hostname
|
|
||||||
*
|
|
||||||
* @param name the hostname that is to be queried
|
|
||||||
* @param found a callback founction to be called on success, failure or timeout
|
|
||||||
* @param callback_arg argument to pass to the callback function
|
|
||||||
* @return @return a err_t return code.
|
|
||||||
*/
|
|
||||||
static err_t
|
|
||||||
dns_enqueue(const char *name, dns_found_callback found, void *callback_arg)
|
|
||||||
{
|
|
||||||
u8_t i;
|
|
||||||
u8_t lseq, lseqi;
|
|
||||||
struct dns_table_entry *pEntry = NULL;
|
|
||||||
|
|
||||||
/* search an unused entry, or the oldest one */
|
|
||||||
lseq = lseqi = 0;
|
|
||||||
for (i = 0; i < DNS_TABLE_SIZE; ++i) {
|
|
||||||
pEntry = &dns_table[i];
|
|
||||||
/* is it an unused entry ? */
|
|
||||||
if (pEntry->state == DNS_STATE_UNUSED)
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* check if this is the oldest completed entry */
|
|
||||||
if (pEntry->state == DNS_STATE_DONE) {
|
|
||||||
if ((dns_seqno - pEntry->seqno) > lseq) {
|
|
||||||
lseq = dns_seqno - pEntry->seqno;
|
|
||||||
lseqi = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if we don't have found an unused entry, use the oldest completed one */
|
|
||||||
if (i == DNS_TABLE_SIZE) {
|
|
||||||
if ((lseqi >= DNS_TABLE_SIZE) || (dns_table[lseqi].state != DNS_STATE_DONE)) {
|
|
||||||
/* no entry can't be used now, table is full */
|
|
||||||
LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": DNS entries table is full\n", name));
|
|
||||||
return ERR_MEM;
|
|
||||||
} else {
|
|
||||||
/* use the oldest completed one */
|
|
||||||
i = lseqi;
|
|
||||||
pEntry = &dns_table[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* use this entry */
|
|
||||||
LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": use DNS entry %"U16_F"\n", name, (u16_t)(i)));
|
|
||||||
|
|
||||||
/* fill the entry */
|
|
||||||
pEntry->state = DNS_STATE_NEW;
|
|
||||||
pEntry->seqno = dns_seqno++;
|
|
||||||
pEntry->found = found;
|
|
||||||
pEntry->arg = callback_arg;
|
|
||||||
strcpy(pEntry->name, name);
|
|
||||||
|
|
||||||
/* force to send query without waiting timer */
|
|
||||||
dns_check_entry(i);
|
|
||||||
|
|
||||||
/* dns query is enqueued */
|
|
||||||
return ERR_INPROGRESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resolve a hostname (string) into an IP address.
|
|
||||||
* NON-BLOCKING callback version for use with raw API!!!
|
|
||||||
*
|
|
||||||
* Returns immediately with one of err_t return codes:
|
|
||||||
* - ERR_OK if hostname is a valid IP address string or the host
|
|
||||||
* name is already in the local names table.
|
|
||||||
* - ERR_INPROGRESS enqueue a request to be sent to the DNS server
|
|
||||||
* for resolution if no errors are present.
|
|
||||||
*
|
|
||||||
* @param hostname the hostname that is to be queried
|
|
||||||
* @param addr pointer to a struct ip_addr where to store the address if it is already
|
|
||||||
* cached in the dns_table (only valid if ERR_OK is returned!)
|
|
||||||
* @param found a callback function to be called on success, failure or timeout (only if
|
|
||||||
* ERR_INPROGRESS is returned!)
|
|
||||||
* @param callback_arg argument to pass to the callback function
|
|
||||||
* @return a err_t return code.
|
|
||||||
*/
|
|
||||||
err_t
|
|
||||||
dns_gethostbyname(const char *hostname, struct ip_addr *addr, dns_found_callback found,
|
|
||||||
void *callback_arg)
|
|
||||||
{
|
|
||||||
/* not initialized or no valid server yet, or invalid addr pointer
|
|
||||||
* or invalid hostname or invalid hostname length */
|
|
||||||
if ((dns_pcb == NULL) || (addr == NULL) ||
|
|
||||||
(!hostname) || (!hostname[0]) ||
|
|
||||||
(strlen(hostname) >= DNS_MAX_NAME_LENGTH)) {
|
|
||||||
return ERR_VAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if LWIP_HAVE_LOOPIF
|
|
||||||
if (strcmp(hostname,"localhost")==0) {
|
|
||||||
addr->addr = htonl(INADDR_LOOPBACK);
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
|
||||||
#endif /* LWIP_HAVE_LOOPIF */
|
|
||||||
|
|
||||||
/* host name already in octet notation? set ip addr and return ERR_OK
|
|
||||||
* already have this address cached? */
|
|
||||||
if (((addr->addr = inet_addr(hostname)) != INADDR_NONE) ||
|
|
||||||
((addr->addr = dns_lookup(hostname)) != INADDR_NONE)) {
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* queue query with specified callback */
|
|
||||||
return dns_enqueue(hostname, found, callback_arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* LWIP_DNS */
|
|
|
@ -1,274 +0,0 @@
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
* Modules initialization
|
|
||||||
*
|
|
||||||
**/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "lwip/opt.h"
|
|
||||||
|
|
||||||
#include "lwip/init.h"
|
|
||||||
#include "lwip/stats.h"
|
|
||||||
#include "lwip/sys.h"
|
|
||||||
#include "lwip/mem.h"
|
|
||||||
#include "lwip/memp.h"
|
|
||||||
#include "lwip/pbuf.h"
|
|
||||||
#include "lwip/netif.h"
|
|
||||||
#include "lwip/sockets.h"
|
|
||||||
#include "lwip/ip.h"
|
|
||||||
#include "lwip/raw.h"
|
|
||||||
#include "lwip/udp.h"
|
|
||||||
#include "lwip/tcp.h"
|
|
||||||
#include "lwip/snmp_msg.h"
|
|
||||||
#include "lwip/autoip.h"
|
|
||||||
#include "lwip/igmp.h"
|
|
||||||
#include "lwip/dns.h"
|
|
||||||
#include "netif/etharp.h"
|
|
||||||
|
|
||||||
/* Compile-time sanity checks for configuration errors.
|
|
||||||
* These can be done independently of LWIP_DEBUG, without penalty.
|
|
||||||
*/
|
|
||||||
#ifndef BYTE_ORDER
|
|
||||||
#error "BYTE_ORDER is not defined, you have to define it in your cc.h"
|
|
||||||
#endif
|
|
||||||
#if (!IP_SOF_BROADCAST && IP_SOF_BROADCAST_RECV)
|
|
||||||
#error "If you want to use broadcast filter per pcb on recv operations, you have to define IP_SOF_BROADCAST=1 in your lwipopts.h"
|
|
||||||
#endif
|
|
||||||
#if (!LWIP_ARP && ARP_QUEUEING)
|
|
||||||
#error "If you want to use ARP Queueing, you have to define LWIP_ARP=1 in your lwipopts.h"
|
|
||||||
#endif
|
|
||||||
#if (!LWIP_UDP && LWIP_UDPLITE)
|
|
||||||
#error "If you want to use UDP Lite, you have to define LWIP_UDP=1 in your lwipopts.h"
|
|
||||||
#endif
|
|
||||||
#if (!LWIP_UDP && LWIP_SNMP)
|
|
||||||
#error "If you want to use SNMP, you have to define LWIP_UDP=1 in your lwipopts.h"
|
|
||||||
#endif
|
|
||||||
#if (!LWIP_UDP && LWIP_DHCP)
|
|
||||||
#error "If you want to use DHCP, you have to define LWIP_UDP=1 in your lwipopts.h"
|
|
||||||
#endif
|
|
||||||
#if (!LWIP_UDP && LWIP_IGMP)
|
|
||||||
#error "If you want to use IGMP, you have to define LWIP_UDP=1 in your lwipopts.h"
|
|
||||||
#endif
|
|
||||||
#if (!LWIP_UDP && LWIP_DNS)
|
|
||||||
#error "If you want to use DNS, you have to define LWIP_UDP=1 in your lwipopts.h"
|
|
||||||
#endif
|
|
||||||
#if (LWIP_ARP && (ARP_TABLE_SIZE > 0x7f))
|
|
||||||
#error "If you want to use ARP, ARP_TABLE_SIZE must fit in an s8_t, so, you have to reduce it in your lwipopts.h"
|
|
||||||
#endif
|
|
||||||
#if (LWIP_ARP && ARP_QUEUEING && (MEMP_NUM_ARP_QUEUE<=0))
|
|
||||||
#error "If you want to use ARP Queueing, you have to define MEMP_NUM_ARP_QUEUE>=1 in your lwipopts.h"
|
|
||||||
#endif
|
|
||||||
#if (LWIP_RAW && (MEMP_NUM_RAW_PCB<=0))
|
|
||||||
#error "If you want to use RAW, you have to define MEMP_NUM_RAW_PCB>=1 in your lwipopts.h"
|
|
||||||
#endif
|
|
||||||
#if (LWIP_UDP && (MEMP_NUM_UDP_PCB<=0))
|
|
||||||
#error "If you want to use UDP, you have to define MEMP_NUM_UDP_PCB>=1 in your lwipopts.h"
|
|
||||||
#endif
|
|
||||||
#if (LWIP_TCP && (MEMP_NUM_TCP_PCB<=0))
|
|
||||||
#error "If you want to use TCP, you have to define MEMP_NUM_TCP_PCB>=1 in your lwipopts.h"
|
|
||||||
#endif
|
|
||||||
#if (LWIP_TCP && (TCP_WND > 0xffff))
|
|
||||||
#error "If you want to use TCP, TCP_WND must fit in an u16_t, so, you have to reduce it in your lwipopts.h"
|
|
||||||
#endif
|
|
||||||
#if (LWIP_TCP && (TCP_SND_QUEUELEN > 0xffff))
|
|
||||||
#error "If you want to use TCP, TCP_SND_QUEUELEN must fit in an u16_t, so, you have to reduce it in your lwipopts.h"
|
|
||||||
#endif
|
|
||||||
#if (LWIP_TCP && ((TCP_MAXRTX > 12) || (TCP_SYNMAXRTX > 12)))
|
|
||||||
#error "If you want to use TCP, TCP_MAXRTX and TCP_SYNMAXRTX must less or equal to 12 (due to tcp_backoff table), so, you have to reduce them in your lwipopts.h"
|
|
||||||
#endif
|
|
||||||
#if (LWIP_TCP && TCP_LISTEN_BACKLOG && (TCP_DEFAULT_LISTEN_BACKLOG < 0) || (TCP_DEFAULT_LISTEN_BACKLOG > 0xff))
|
|
||||||
#error "If you want to use TCP backlog, TCP_DEFAULT_LISTEN_BACKLOG must fit into an u8_t"
|
|
||||||
#endif
|
|
||||||
#if (LWIP_IGMP && (MEMP_NUM_IGMP_GROUP<=1))
|
|
||||||
#error "If you want to use IGMP, you have to define MEMP_NUM_IGMP_GROUP>1 in your lwipopts.h"
|
|
||||||
#endif
|
|
||||||
#if (PPP_SUPPORT && (NO_SYS==1))
|
|
||||||
#error "If you want to use PPP, you have to define NO_SYS=0 in your lwipopts.h"
|
|
||||||
#endif
|
|
||||||
#if (LWIP_NETIF_API && (NO_SYS==1))
|
|
||||||
#error "If you want to use NETIF API, you have to define NO_SYS=0 in your lwipopts.h"
|
|
||||||
#endif
|
|
||||||
#if ((LWIP_SOCKET || LWIP_NETCONN) && (NO_SYS==1))
|
|
||||||
#error "If you want to use Sequential API, you have to define NO_SYS=0 in your lwipopts.h"
|
|
||||||
#endif
|
|
||||||
#if ((LWIP_NETCONN || LWIP_SOCKET) && (MEMP_NUM_TCPIP_MSG_API<=0))
|
|
||||||
#error "If you want to use Sequential API, you have to define MEMP_NUM_TCPIP_MSG_API>=1 in your lwipopts.h"
|
|
||||||
#endif
|
|
||||||
#if (!LWIP_NETCONN && LWIP_SOCKET)
|
|
||||||
#error "If you want to use Socket API, you have to define LWIP_NETCONN=1 in your lwipopts.h"
|
|
||||||
#endif
|
|
||||||
#if (((!LWIP_DHCP) || (!LWIP_AUTOIP)) && LWIP_DHCP_AUTOIP_COOP)
|
|
||||||
#error "If you want to use DHCP/AUTOIP cooperation mode, you have to define LWIP_DHCP=1 and LWIP_AUTOIP=1 in your lwipopts.h"
|
|
||||||
#endif
|
|
||||||
#if (((!LWIP_DHCP) || (!LWIP_ARP)) && DHCP_DOES_ARP_CHECK)
|
|
||||||
#error "If you want to use DHCP ARP checking, you have to define LWIP_DHCP=1 and LWIP_ARP=1 in your lwipopts.h"
|
|
||||||
#endif
|
|
||||||
#if (!LWIP_ARP && LWIP_AUTOIP)
|
|
||||||
#error "If you want to use AUTOIP, you have to define LWIP_ARP=1 in your lwipopts.h"
|
|
||||||
#endif
|
|
||||||
#if (LWIP_SNMP && (SNMP_CONCURRENT_REQUESTS<=0))
|
|
||||||
#error "If you want to use SNMP, you have to define SNMP_CONCURRENT_REQUESTS>=1 in your lwipopts.h"
|
|
||||||
#endif
|
|
||||||
#if (LWIP_SNMP && (SNMP_TRAP_DESTINATIONS<=0))
|
|
||||||
#error "If you want to use SNMP, you have to define SNMP_TRAP_DESTINATIONS>=1 in your lwipopts.h"
|
|
||||||
#endif
|
|
||||||
#if (LWIP_TCP && ((LWIP_EVENT_API && LWIP_CALLBACK_API) || (!LWIP_EVENT_API && !LWIP_CALLBACK_API)))
|
|
||||||
#error "One and exactly one of LWIP_EVENT_API and LWIP_CALLBACK_API has to be enabled in your lwipopts.h"
|
|
||||||
#endif
|
|
||||||
/* There must be sufficient timeouts, taking into account requirements of the subsystems. */
|
|
||||||
#if ((NO_SYS==0) && (MEMP_NUM_SYS_TIMEOUT < (LWIP_TCP + IP_REASSEMBLY + LWIP_ARP + (2*LWIP_DHCP) + LWIP_AUTOIP + LWIP_IGMP + LWIP_DNS + PPP_SUPPORT)))
|
|
||||||
#error "MEMP_NUM_SYS_TIMEOUT is too low to accomodate all required timeouts"
|
|
||||||
#endif
|
|
||||||
#if (IP_REASSEMBLY && (MEMP_NUM_REASSDATA > IP_REASS_MAX_PBUFS))
|
|
||||||
#error "MEMP_NUM_REASSDATA > IP_REASS_MAX_PBUFS doesn't make sense since each struct ip_reassdata must hold 2 pbufs at least!"
|
|
||||||
#endif
|
|
||||||
#if (MEM_LIBC_MALLOC && MEM_USE_POOLS)
|
|
||||||
#error "MEM_LIBC_MALLOC and MEM_USE_POOLS may not both be simultaneously enabled in your lwipopts.h"
|
|
||||||
#endif
|
|
||||||
#if (MEM_USE_POOLS && !MEMP_USE_CUSTOM_POOLS)
|
|
||||||
#error "MEM_USE_POOLS requires custom pools (MEMP_USE_CUSTOM_POOLS) to be enabled in your lwipopts.h"
|
|
||||||
#endif
|
|
||||||
#if (PBUF_POOL_BUFSIZE <= MEM_ALIGNMENT)
|
|
||||||
#error "PBUF_POOL_BUFSIZE must be greater than MEM_ALIGNMENT or the offset may take the full first pbuf"
|
|
||||||
#endif
|
|
||||||
#if (TCP_QUEUE_OOSEQ && !LWIP_TCP)
|
|
||||||
#error "TCP_QUEUE_OOSEQ requires LWIP_TCP"
|
|
||||||
#endif
|
|
||||||
#if (DNS_LOCAL_HOSTLIST && !DNS_LOCAL_HOSTLIST_IS_DYNAMIC && !(defined(DNS_LOCAL_HOSTLIST_INIT)))
|
|
||||||
#error "you have to define define DNS_LOCAL_HOSTLIST_INIT {{'host1', 0x123}, {'host2', 0x234}} to initialize DNS_LOCAL_HOSTLIST"
|
|
||||||
#endif
|
|
||||||
#if PPP_SUPPORT && !PPPOS_SUPPORT & !PPPOE_SUPPORT
|
|
||||||
#error "PPP_SUPPORT needs either PPPOS_SUPPORT or PPPOE_SUPPORT turned on"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/* Compile-time checks for deprecated options.
|
|
||||||
*/
|
|
||||||
#ifdef MEMP_NUM_TCPIP_MSG
|
|
||||||
#error "MEMP_NUM_TCPIP_MSG option is deprecated. Remove it from your lwipopts.h."
|
|
||||||
#endif
|
|
||||||
#ifdef MEMP_NUM_API_MSG
|
|
||||||
#error "MEMP_NUM_API_MSG option is deprecated. Remove it from your lwipopts.h."
|
|
||||||
#endif
|
|
||||||
#ifdef TCP_REXMIT_DEBUG
|
|
||||||
#error "TCP_REXMIT_DEBUG option is deprecated. Remove it from your lwipopts.h."
|
|
||||||
#endif
|
|
||||||
#ifdef RAW_STATS
|
|
||||||
#error "RAW_STATS option is deprecated. Remove it from your lwipopts.h."
|
|
||||||
#endif
|
|
||||||
#ifdef ETHARP_QUEUE_FIRST
|
|
||||||
#error "ETHARP_QUEUE_FIRST option is deprecated. Remove it from your lwipopts.h."
|
|
||||||
#endif
|
|
||||||
#ifdef ETHARP_ALWAYS_INSERT
|
|
||||||
#error "ETHARP_ALWAYS_INSERT option is deprecated. Remove it from your lwipopts.h."
|
|
||||||
#endif
|
|
||||||
#if SO_REUSE
|
|
||||||
/* I removed the lot since this was an ugly hack. It broke the raw-API.
|
|
||||||
It also came with many ugly goto's, Christiaan Simons. */
|
|
||||||
#error "SO_REUSE currently unavailable, this was a hack"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef LWIP_DEBUG
|
|
||||||
static void
|
|
||||||
lwip_sanity_check(void)
|
|
||||||
{
|
|
||||||
/* Warnings */
|
|
||||||
#if LWIP_NETCONN
|
|
||||||
if (MEMP_NUM_NETCONN > (MEMP_NUM_TCP_PCB+MEMP_NUM_TCP_PCB_LISTEN+MEMP_NUM_UDP_PCB+MEMP_NUM_RAW_PCB))
|
|
||||||
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: MEMP_NUM_NETCONN should be less than the sum of MEMP_NUM_{TCP,RAW,UDP}_PCB+MEMP_NUM_TCP_PCB_LISTEN\n"));
|
|
||||||
#endif /* LWIP_NETCONN */
|
|
||||||
#if LWIP_TCP
|
|
||||||
if (MEMP_NUM_TCP_SEG < TCP_SND_QUEUELEN)
|
|
||||||
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: MEMP_NUM_TCP_SEG should be at least as big as TCP_SND_QUEUELEN\n"));
|
|
||||||
if (TCP_SND_BUF < 2 * TCP_MSS)
|
|
||||||
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SND_BUF must be at least as much as (2 * TCP_MSS) for things to work smoothly\n"));
|
|
||||||
if (TCP_SND_QUEUELEN < (2 * (TCP_SND_BUF/TCP_MSS)))
|
|
||||||
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SND_QUEUELEN must be at least as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work\n"));
|
|
||||||
if (TCP_SNDLOWAT > TCP_SND_BUF)
|
|
||||||
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SNDLOWAT must be less than or equal to TCP_SND_BUF.\n"));
|
|
||||||
if (TCP_WND > (PBUF_POOL_SIZE*PBUF_POOL_BUFSIZE))
|
|
||||||
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_WND is larger than space provided by PBUF_POOL_SIZE*PBUF_POOL_BUFSIZE\n"));
|
|
||||||
if (TCP_WND < TCP_MSS)
|
|
||||||
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_WND is smaller than MSS\n"));
|
|
||||||
#endif /* LWIP_TCP */
|
|
||||||
}
|
|
||||||
#else /* LWIP_DEBUG */
|
|
||||||
#define lwip_sanity_check()
|
|
||||||
#endif /* LWIP_DEBUG */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform Sanity check of user-configurable values, and initialize all modules.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
lwip_init(void)
|
|
||||||
{
|
|
||||||
/* Sanity check user-configurable values */
|
|
||||||
lwip_sanity_check();
|
|
||||||
|
|
||||||
/* Modules initialization */
|
|
||||||
stats_init();
|
|
||||||
sys_init();
|
|
||||||
mem_init();
|
|
||||||
memp_init();
|
|
||||||
pbuf_init();
|
|
||||||
netif_init();
|
|
||||||
#if LWIP_SOCKET
|
|
||||||
lwip_socket_init();
|
|
||||||
#endif /* LWIP_SOCKET */
|
|
||||||
ip_init();
|
|
||||||
#if LWIP_ARP
|
|
||||||
etharp_init();
|
|
||||||
#endif /* LWIP_ARP */
|
|
||||||
#if LWIP_RAW
|
|
||||||
raw_init();
|
|
||||||
#endif /* LWIP_RAW */
|
|
||||||
#if LWIP_UDP
|
|
||||||
udp_init();
|
|
||||||
#endif /* LWIP_UDP */
|
|
||||||
#if LWIP_TCP
|
|
||||||
tcp_init();
|
|
||||||
#endif /* LWIP_TCP */
|
|
||||||
#if LWIP_SNMP
|
|
||||||
snmp_init();
|
|
||||||
#endif /* LWIP_SNMP */
|
|
||||||
#if LWIP_AUTOIP
|
|
||||||
autoip_init();
|
|
||||||
#endif /* LWIP_AUTOIP */
|
|
||||||
#if LWIP_IGMP
|
|
||||||
igmp_init();
|
|
||||||
#endif /* LWIP_IGMP */
|
|
||||||
#if LWIP_DNS
|
|
||||||
dns_init();
|
|
||||||
#endif /* LWIP_DNS */
|
|
||||||
}
|
|
|
@ -1,497 +0,0 @@
|
||||||
/*
|
|
||||||
* @file
|
|
||||||
* AutoIP Automatic LinkLocal IP Configuration
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
*
|
|
||||||
* Copyright (c) 2007 Dominik Spies <kontakt@dspies.de>
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* Author: Dominik Spies <kontakt@dspies.de>
|
|
||||||
*
|
|
||||||
* This is a AutoIP implementation for the lwIP TCP/IP stack. It aims to conform
|
|
||||||
* with RFC 3927.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* Please coordinate changes and requests with Dominik Spies
|
|
||||||
* <kontakt@dspies.de>
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*******************************************************************************
|
|
||||||
* USAGE:
|
|
||||||
*
|
|
||||||
* define LWIP_AUTOIP 1 in your lwipopts.h
|
|
||||||
*
|
|
||||||
* If you don't use tcpip.c (so, don't call, you don't call tcpip_init):
|
|
||||||
* - First, call autoip_init().
|
|
||||||
* - call autoip_tmr() all AUTOIP_TMR_INTERVAL msces,
|
|
||||||
* that should be defined in autoip.h.
|
|
||||||
* I recommend a value of 100. The value must divide 1000 with a remainder almost 0.
|
|
||||||
* Possible values are 1000, 500, 333, 250, 200, 166, 142, 125, 111, 100 ....
|
|
||||||
*
|
|
||||||
* Without DHCP:
|
|
||||||
* - Call autoip_start() after netif_add().
|
|
||||||
*
|
|
||||||
* With DHCP:
|
|
||||||
* - define LWIP_DHCP_AUTOIP_COOP 1 in your lwipopts.h.
|
|
||||||
* - Configure your DHCP Client.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "lwip/opt.h"
|
|
||||||
|
|
||||||
#if LWIP_AUTOIP /* don't build if not configured for use in lwipopts.h */
|
|
||||||
|
|
||||||
#include "lwip/mem.h"
|
|
||||||
#include "lwip/udp.h"
|
|
||||||
#include "lwip/ip_addr.h"
|
|
||||||
#include "lwip/netif.h"
|
|
||||||
#include "lwip/autoip.h"
|
|
||||||
#include "netif/etharp.h"
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
/* 169.254.0.0 */
|
|
||||||
#define AUTOIP_NET 0xA9FE0000
|
|
||||||
/* 169.254.1.0 */
|
|
||||||
#define AUTOIP_RANGE_START (AUTOIP_NET | 0x0100)
|
|
||||||
/* 169.254.254.255 */
|
|
||||||
#define AUTOIP_RANGE_END (AUTOIP_NET | 0xFEFF)
|
|
||||||
|
|
||||||
|
|
||||||
/** Pseudo random macro based on netif informations.
|
|
||||||
* You could use "rand()" from the C Library if you define LWIP_AUTOIP_RAND in lwipopts.h */
|
|
||||||
#ifndef LWIP_AUTOIP_RAND
|
|
||||||
#define LWIP_AUTOIP_RAND(netif) ( (((u32_t)((netif->hwaddr[5]) & 0xff) << 24) | \
|
|
||||||
((u32_t)((netif->hwaddr[3]) & 0xff) << 16) | \
|
|
||||||
((u32_t)((netif->hwaddr[2]) & 0xff) << 8) | \
|
|
||||||
((u32_t)((netif->hwaddr[4]) & 0xff))) + \
|
|
||||||
(netif->autoip?netif->autoip->tried_llipaddr:0))
|
|
||||||
#endif /* LWIP_AUTOIP_RAND */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Macro that generates the initial IP address to be tried by AUTOIP.
|
|
||||||
* If you want to override this, define it to something else in lwipopts.h.
|
|
||||||
*/
|
|
||||||
#ifndef LWIP_AUTOIP_CREATE_SEED_ADDR
|
|
||||||
#define LWIP_AUTOIP_CREATE_SEED_ADDR(netif) \
|
|
||||||
htonl(AUTOIP_RANGE_START + ((u32_t)(((u8_t)(netif->hwaddr[4])) | \
|
|
||||||
((u32_t)((u8_t)(netif->hwaddr[5]))) << 8)))
|
|
||||||
#endif /* LWIP_AUTOIP_CREATE_SEED_ADDR */
|
|
||||||
|
|
||||||
/* static functions */
|
|
||||||
static void autoip_handle_arp_conflict(struct netif *netif);
|
|
||||||
|
|
||||||
/* creates a pseudo random LL IP-Address for a network interface */
|
|
||||||
static void autoip_create_addr(struct netif *netif, struct ip_addr *ipaddr);
|
|
||||||
|
|
||||||
/* sends an ARP probe */
|
|
||||||
static err_t autoip_arp_probe(struct netif *netif);
|
|
||||||
|
|
||||||
/* sends an ARP announce */
|
|
||||||
static err_t autoip_arp_announce(struct netif *netif);
|
|
||||||
|
|
||||||
/* configure interface for use with current LL IP-Address */
|
|
||||||
static err_t autoip_bind(struct netif *netif);
|
|
||||||
|
|
||||||
/* start sending probes for llipaddr */
|
|
||||||
static void autoip_start_probing(struct netif *netif);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize this module
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
autoip_init(void)
|
|
||||||
{
|
|
||||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_init()\n"));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle a IP address conflict after an ARP conflict detection
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
autoip_handle_arp_conflict(struct netif *netif)
|
|
||||||
{
|
|
||||||
/* Somehow detect if we are defending or retreating */
|
|
||||||
unsigned char defend = 1; /* tbd */
|
|
||||||
|
|
||||||
if(defend) {
|
|
||||||
if(netif->autoip->lastconflict > 0) {
|
|
||||||
/* retreat, there was a conflicting ARP in the last
|
|
||||||
* DEFEND_INTERVAL seconds
|
|
||||||
*/
|
|
||||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
|
|
||||||
("autoip_handle_arp_conflict(): we are defending, but in DEFEND_INTERVAL, retreating\n"));
|
|
||||||
|
|
||||||
/* TODO: close all TCP sessions */
|
|
||||||
autoip_start(netif);
|
|
||||||
} else {
|
|
||||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
|
|
||||||
("autoip_handle_arp_conflict(): we are defend, send ARP Announce\n"));
|
|
||||||
autoip_arp_announce(netif);
|
|
||||||
netif->autoip->lastconflict = DEFEND_INTERVAL * AUTOIP_TICKS_PER_SECOND;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
|
|
||||||
("autoip_handle_arp_conflict(): we do not defend, retreating\n"));
|
|
||||||
/* TODO: close all TCP sessions */
|
|
||||||
autoip_start(netif);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an IP-Address out of range 169.254.1.0 to 169.254.254.255
|
|
||||||
*
|
|
||||||
* @param netif network interface on which create the IP-Address
|
|
||||||
* @param ipaddr ip address to initialize
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
autoip_create_addr(struct netif *netif, struct ip_addr *ipaddr)
|
|
||||||
{
|
|
||||||
/* Here we create an IP-Address out of range 169.254.1.0 to 169.254.254.255
|
|
||||||
* compliant to RFC 3927 Section 2.1
|
|
||||||
* We have 254 * 256 possibilities */
|
|
||||||
|
|
||||||
u32_t addr = ntohl(LWIP_AUTOIP_CREATE_SEED_ADDR(netif));
|
|
||||||
addr += netif->autoip->tried_llipaddr;
|
|
||||||
addr = AUTOIP_NET | (addr & 0xffff);
|
|
||||||
/* Now, 169.254.0.0 <= addr <= 169.254.255.255 */
|
|
||||||
|
|
||||||
if (addr < AUTOIP_RANGE_START) {
|
|
||||||
addr += AUTOIP_RANGE_END - AUTOIP_RANGE_START + 1;
|
|
||||||
}
|
|
||||||
if (addr > AUTOIP_RANGE_END) {
|
|
||||||
addr -= AUTOIP_RANGE_END - AUTOIP_RANGE_START + 1;
|
|
||||||
}
|
|
||||||
LWIP_ASSERT("AUTOIP address not in range", (addr >= AUTOIP_RANGE_START) &&
|
|
||||||
(addr <= AUTOIP_RANGE_END));
|
|
||||||
ipaddr->addr = htonl(addr);
|
|
||||||
|
|
||||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
|
|
||||||
("autoip_create_addr(): tried_llipaddr=%"U16_F", 0x%08"X32_F"\n",
|
|
||||||
(u16_t)(netif->autoip->tried_llipaddr), (u32_t)(ipaddr->addr)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends an ARP probe from a network interface
|
|
||||||
*
|
|
||||||
* @param netif network interface used to send the probe
|
|
||||||
*/
|
|
||||||
static err_t
|
|
||||||
autoip_arp_probe(struct netif *netif)
|
|
||||||
{
|
|
||||||
return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, ðbroadcast,
|
|
||||||
(struct eth_addr *)netif->hwaddr, IP_ADDR_ANY, ðzero,
|
|
||||||
&netif->autoip->llipaddr, ARP_REQUEST);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends an ARP announce from a network interface
|
|
||||||
*
|
|
||||||
* @param netif network interface used to send the announce
|
|
||||||
*/
|
|
||||||
static err_t
|
|
||||||
autoip_arp_announce(struct netif *netif)
|
|
||||||
{
|
|
||||||
return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, ðbroadcast,
|
|
||||||
(struct eth_addr *)netif->hwaddr, &netif->autoip->llipaddr, ðzero,
|
|
||||||
&netif->autoip->llipaddr, ARP_REQUEST);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configure interface for use with current LL IP-Address
|
|
||||||
*
|
|
||||||
* @param netif network interface to configure with current LL IP-Address
|
|
||||||
*/
|
|
||||||
static err_t
|
|
||||||
autoip_bind(struct netif *netif)
|
|
||||||
{
|
|
||||||
struct autoip *autoip = netif->autoip;
|
|
||||||
struct ip_addr sn_mask, gw_addr;
|
|
||||||
|
|
||||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
|
|
||||||
("autoip_bind(netif=%p) %c%c%"U16_F" 0x%08"X32_F"\n",
|
|
||||||
(void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num, autoip->llipaddr.addr));
|
|
||||||
|
|
||||||
IP4_ADDR(&sn_mask, 255, 255, 0, 0);
|
|
||||||
IP4_ADDR(&gw_addr, 0, 0, 0, 0);
|
|
||||||
|
|
||||||
netif_set_ipaddr(netif, &autoip->llipaddr);
|
|
||||||
netif_set_netmask(netif, &sn_mask);
|
|
||||||
netif_set_gw(netif, &gw_addr);
|
|
||||||
|
|
||||||
/* bring the interface up */
|
|
||||||
netif_set_up(netif);
|
|
||||||
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start AutoIP client
|
|
||||||
*
|
|
||||||
* @param netif network interface on which start the AutoIP client
|
|
||||||
*/
|
|
||||||
err_t
|
|
||||||
autoip_start(struct netif *netif)
|
|
||||||
{
|
|
||||||
struct autoip *autoip = netif->autoip;
|
|
||||||
err_t result = ERR_OK;
|
|
||||||
|
|
||||||
if(netif_is_up(netif)) {
|
|
||||||
netif_set_down(netif);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set IP-Address, Netmask and Gateway to 0 to make sure that
|
|
||||||
* ARP Packets are formed correctly
|
|
||||||
*/
|
|
||||||
netif->ip_addr.addr = 0;
|
|
||||||
netif->netmask.addr = 0;
|
|
||||||
netif->gw.addr = 0;
|
|
||||||
|
|
||||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
|
|
||||||
("autoip_start(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0],
|
|
||||||
netif->name[1], (u16_t)netif->num));
|
|
||||||
if(autoip == NULL) {
|
|
||||||
/* no AutoIP client attached yet? */
|
|
||||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
|
|
||||||
("autoip_start(): starting new AUTOIP client\n"));
|
|
||||||
autoip = mem_malloc(sizeof(struct autoip));
|
|
||||||
if(autoip == NULL) {
|
|
||||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
|
|
||||||
("autoip_start(): could not allocate autoip\n"));
|
|
||||||
return ERR_MEM;
|
|
||||||
}
|
|
||||||
memset( autoip, 0, sizeof(struct autoip));
|
|
||||||
/* store this AutoIP client in the netif */
|
|
||||||
netif->autoip = autoip;
|
|
||||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_start(): allocated autoip"));
|
|
||||||
} else {
|
|
||||||
autoip->state = AUTOIP_STATE_OFF;
|
|
||||||
autoip->ttw = 0;
|
|
||||||
autoip->sent_num = 0;
|
|
||||||
memset(&autoip->llipaddr, 0, sizeof(struct ip_addr));
|
|
||||||
autoip->lastconflict = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
autoip_create_addr(netif, &(autoip->llipaddr));
|
|
||||||
autoip->tried_llipaddr++;
|
|
||||||
autoip_start_probing(netif);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
autoip_start_probing(struct netif *netif)
|
|
||||||
{
|
|
||||||
struct autoip *autoip = netif->autoip;
|
|
||||||
|
|
||||||
autoip->state = AUTOIP_STATE_PROBING;
|
|
||||||
autoip->sent_num = 0;
|
|
||||||
|
|
||||||
/* time to wait to first probe, this is randomly
|
|
||||||
* choosen out of 0 to PROBE_WAIT seconds.
|
|
||||||
* compliant to RFC 3927 Section 2.2.1
|
|
||||||
*/
|
|
||||||
autoip->ttw = (u16_t)(LWIP_AUTOIP_RAND(netif) % (PROBE_WAIT * AUTOIP_TICKS_PER_SECOND));
|
|
||||||
|
|
||||||
/*
|
|
||||||
* if we tried more then MAX_CONFLICTS we must limit our rate for
|
|
||||||
* accquiring and probing address
|
|
||||||
* compliant to RFC 3927 Section 2.2.1
|
|
||||||
*/
|
|
||||||
if(autoip->tried_llipaddr > MAX_CONFLICTS) {
|
|
||||||
autoip->ttw = RATE_LIMIT_INTERVAL * AUTOIP_TICKS_PER_SECOND;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle a possible change in the network configuration.
|
|
||||||
*
|
|
||||||
* If there is an AutoIP address configured, take the interface down
|
|
||||||
* and begin probing with the same address.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
autoip_network_changed(struct netif *netif)
|
|
||||||
{
|
|
||||||
if (netif->autoip && netif->autoip->state != AUTOIP_STATE_OFF) {
|
|
||||||
netif_set_down(netif);
|
|
||||||
autoip_start_probing(netif);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stop AutoIP client
|
|
||||||
*
|
|
||||||
* @param netif network interface on which stop the AutoIP client
|
|
||||||
*/
|
|
||||||
err_t
|
|
||||||
autoip_stop(struct netif *netif)
|
|
||||||
{
|
|
||||||
netif->autoip->state = AUTOIP_STATE_OFF;
|
|
||||||
netif_set_down(netif);
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Has to be called in loop every AUTOIP_TMR_INTERVAL milliseconds
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
autoip_tmr()
|
|
||||||
{
|
|
||||||
struct netif *netif = netif_list;
|
|
||||||
/* loop through netif's */
|
|
||||||
while (netif != NULL) {
|
|
||||||
/* only act on AutoIP configured interfaces */
|
|
||||||
if (netif->autoip != NULL) {
|
|
||||||
if(netif->autoip->lastconflict > 0) {
|
|
||||||
netif->autoip->lastconflict--;
|
|
||||||
}
|
|
||||||
|
|
||||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
|
|
||||||
("autoip_tmr() AutoIP-State: %"U16_F", ttw=%"U16_F"\n",
|
|
||||||
(u16_t)(netif->autoip->state), netif->autoip->ttw));
|
|
||||||
|
|
||||||
switch(netif->autoip->state) {
|
|
||||||
case AUTOIP_STATE_PROBING:
|
|
||||||
if(netif->autoip->ttw > 0) {
|
|
||||||
netif->autoip->ttw--;
|
|
||||||
} else {
|
|
||||||
if(netif->autoip->sent_num >= PROBE_NUM) {
|
|
||||||
netif->autoip->state = AUTOIP_STATE_ANNOUNCING;
|
|
||||||
netif->autoip->sent_num = 0;
|
|
||||||
netif->autoip->ttw = ANNOUNCE_WAIT * AUTOIP_TICKS_PER_SECOND;
|
|
||||||
} else {
|
|
||||||
autoip_arp_probe(netif);
|
|
||||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
|
|
||||||
("autoip_tmr() PROBING Sent Probe\n"));
|
|
||||||
netif->autoip->sent_num++;
|
|
||||||
/* calculate time to wait to next probe */
|
|
||||||
netif->autoip->ttw = (u16_t)((LWIP_AUTOIP_RAND(netif) %
|
|
||||||
((PROBE_MAX - PROBE_MIN) * AUTOIP_TICKS_PER_SECOND) ) +
|
|
||||||
PROBE_MIN * AUTOIP_TICKS_PER_SECOND);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case AUTOIP_STATE_ANNOUNCING:
|
|
||||||
if(netif->autoip->ttw > 0) {
|
|
||||||
netif->autoip->ttw--;
|
|
||||||
} else {
|
|
||||||
if(netif->autoip->sent_num == 0) {
|
|
||||||
/* We are here the first time, so we waited ANNOUNCE_WAIT seconds
|
|
||||||
* Now we can bind to an IP address and use it.
|
|
||||||
*
|
|
||||||
* autoip_bind calls netif_set_up. This triggers a gratuitous ARP
|
|
||||||
* which counts as an announcement.
|
|
||||||
*/
|
|
||||||
autoip_bind(netif);
|
|
||||||
} else {
|
|
||||||
autoip_arp_announce(netif);
|
|
||||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
|
|
||||||
("autoip_tmr() ANNOUNCING Sent Announce\n"));
|
|
||||||
}
|
|
||||||
netif->autoip->ttw = ANNOUNCE_INTERVAL * AUTOIP_TICKS_PER_SECOND;
|
|
||||||
netif->autoip->sent_num++;
|
|
||||||
|
|
||||||
if(netif->autoip->sent_num >= ANNOUNCE_NUM) {
|
|
||||||
netif->autoip->state = AUTOIP_STATE_BOUND;
|
|
||||||
netif->autoip->sent_num = 0;
|
|
||||||
netif->autoip->ttw = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* proceed to next network interface */
|
|
||||||
netif = netif->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles every incoming ARP Packet, called by etharp_arp_input.
|
|
||||||
*
|
|
||||||
* @param netif network interface to use for autoip processing
|
|
||||||
* @param hdr Incoming ARP packet
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr)
|
|
||||||
{
|
|
||||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_arp_reply()\n"));
|
|
||||||
if ((netif->autoip != NULL) && (netif->autoip->state != AUTOIP_STATE_OFF)) {
|
|
||||||
/* when ip.src == llipaddr && hw.src != netif->hwaddr
|
|
||||||
*
|
|
||||||
* when probing ip.dst == llipaddr && hw.src != netif->hwaddr
|
|
||||||
* we have a conflict and must solve it
|
|
||||||
*/
|
|
||||||
struct ip_addr sipaddr, dipaddr;
|
|
||||||
struct eth_addr netifaddr;
|
|
||||||
netifaddr.addr[0] = netif->hwaddr[0];
|
|
||||||
netifaddr.addr[1] = netif->hwaddr[1];
|
|
||||||
netifaddr.addr[2] = netif->hwaddr[2];
|
|
||||||
netifaddr.addr[3] = netif->hwaddr[3];
|
|
||||||
netifaddr.addr[4] = netif->hwaddr[4];
|
|
||||||
netifaddr.addr[5] = netif->hwaddr[5];
|
|
||||||
|
|
||||||
/* Copy struct ip_addr2 to aligned ip_addr, to support compilers without
|
|
||||||
* structure packing (not using structure copy which breaks strict-aliasing rules).
|
|
||||||
*/
|
|
||||||
SMEMCPY(&sipaddr, &hdr->sipaddr, sizeof(sipaddr));
|
|
||||||
SMEMCPY(&dipaddr, &hdr->dipaddr, sizeof(dipaddr));
|
|
||||||
|
|
||||||
if ((netif->autoip->state == AUTOIP_STATE_PROBING) ||
|
|
||||||
((netif->autoip->state == AUTOIP_STATE_ANNOUNCING) &&
|
|
||||||
(netif->autoip->sent_num == 0))) {
|
|
||||||
/* RFC 3927 Section 2.2.1:
|
|
||||||
* from beginning to after ANNOUNCE_WAIT
|
|
||||||
* seconds we have a conflict if
|
|
||||||
* ip.src == llipaddr OR
|
|
||||||
* ip.dst == llipaddr && hw.src != own hwaddr
|
|
||||||
*/
|
|
||||||
if ((ip_addr_cmp(&sipaddr, &netif->autoip->llipaddr)) ||
|
|
||||||
(ip_addr_cmp(&dipaddr, &netif->autoip->llipaddr) &&
|
|
||||||
!eth_addr_cmp(&netifaddr, &hdr->shwaddr))) {
|
|
||||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING,
|
|
||||||
("autoip_arp_reply(): Probe Conflict detected\n"));
|
|
||||||
autoip_start(netif);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* RFC 3927 Section 2.5:
|
|
||||||
* in any state we have a conflict if
|
|
||||||
* ip.src == llipaddr && hw.src != own hwaddr
|
|
||||||
*/
|
|
||||||
if (ip_addr_cmp(&sipaddr, &netif->autoip->llipaddr) &&
|
|
||||||
!eth_addr_cmp(&netifaddr, &hdr->shwaddr)) {
|
|
||||||
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING,
|
|
||||||
("autoip_arp_reply(): Conflicting ARP-Packet detected\n"));
|
|
||||||
autoip_handle_arp_conflict(netif);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* LWIP_AUTOIP */
|
|
|
@ -1,340 +0,0 @@
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
* ICMP - Internet Control Message Protocol
|
|
||||||
*
|
|
||||||
**/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Some ICMP messages should be passed to the transport protocols. This
|
|
||||||
is not implemented. */
|
|
||||||
|
|
||||||
#include "lwip/opt.h"
|
|
||||||
|
|
||||||
#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */
|
|
||||||
|
|
||||||
#include "lwip/icmp.h"
|
|
||||||
#include "lwip/inet.h"
|
|
||||||
#include "lwip/inet_chksum.h"
|
|
||||||
#include "lwip/ip.h"
|
|
||||||
#include "lwip/def.h"
|
|
||||||
#include "lwip/stats.h"
|
|
||||||
#include "lwip/snmp.h"
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
/** Small optimization: set to 0 if incoming PBUF_POOL pbuf always can be
|
|
||||||
* used to modify and send a response packet (and to 1 if this is not the case,
|
|
||||||
* e.g. when link header is stripped of when receiving) */
|
|
||||||
#ifndef LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN
|
|
||||||
#define LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN 1
|
|
||||||
#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */
|
|
||||||
|
|
||||||
/* The amount of data from the original packet to return in a dest-unreachable */
|
|
||||||
#define ICMP_DEST_UNREACH_DATASIZE 8
|
|
||||||
|
|
||||||
static void icmp_send_response(struct pbuf *p, u8_t type, u8_t code);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Processes ICMP input packets, called from ip_input().
|
|
||||||
*
|
|
||||||
* Currently only processes icmp echo requests and sends
|
|
||||||
* out the echo response.
|
|
||||||
*
|
|
||||||
* @param p the icmp echo request packet, p->payload pointing to the ip header
|
|
||||||
* @param inp the netif on which this packet was received
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
icmp_input(struct pbuf *p, struct netif *inp)
|
|
||||||
{
|
|
||||||
u8_t type;
|
|
||||||
#ifdef LWIP_DEBUG
|
|
||||||
u8_t code;
|
|
||||||
#endif /* LWIP_DEBUG */
|
|
||||||
struct icmp_echo_hdr *iecho;
|
|
||||||
struct ip_hdr *iphdr;
|
|
||||||
struct ip_addr tmpaddr;
|
|
||||||
s16_t hlen;
|
|
||||||
|
|
||||||
ICMP_STATS_INC(icmp.recv);
|
|
||||||
snmp_inc_icmpinmsgs();
|
|
||||||
|
|
||||||
|
|
||||||
iphdr = p->payload;
|
|
||||||
hlen = IPH_HL(iphdr) * 4;
|
|
||||||
if (pbuf_header(p, -hlen) || (p->tot_len < sizeof(u16_t)*2)) {
|
|
||||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: short ICMP (%"U16_F" bytes) received\n", p->tot_len));
|
|
||||||
goto lenerr;
|
|
||||||
}
|
|
||||||
|
|
||||||
type = *((u8_t *)p->payload);
|
|
||||||
#ifdef LWIP_DEBUG
|
|
||||||
code = *(((u8_t *)p->payload)+1);
|
|
||||||
#endif /* LWIP_DEBUG */
|
|
||||||
switch (type) {
|
|
||||||
case ICMP_ECHO:
|
|
||||||
#if !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING
|
|
||||||
{
|
|
||||||
int accepted = 1;
|
|
||||||
#if !LWIP_MULTICAST_PING
|
|
||||||
/* multicast destination address? */
|
|
||||||
if (ip_addr_ismulticast(&iphdr->dest)) {
|
|
||||||
accepted = 0;
|
|
||||||
}
|
|
||||||
#endif /* LWIP_MULTICAST_PING */
|
|
||||||
#if !LWIP_BROADCAST_PING
|
|
||||||
/* broadcast destination address? */
|
|
||||||
if (ip_addr_isbroadcast(&iphdr->dest, inp)) {
|
|
||||||
accepted = 0;
|
|
||||||
}
|
|
||||||
#endif /* LWIP_BROADCAST_PING */
|
|
||||||
/* broadcast or multicast destination address not acceptd? */
|
|
||||||
if (!accepted) {
|
|
||||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: Not echoing to multicast or broadcast pings\n"));
|
|
||||||
ICMP_STATS_INC(icmp.err);
|
|
||||||
pbuf_free(p);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif /* !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING */
|
|
||||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ping\n"));
|
|
||||||
if (p->tot_len < sizeof(struct icmp_echo_hdr)) {
|
|
||||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: bad ICMP echo received\n"));
|
|
||||||
goto lenerr;
|
|
||||||
}
|
|
||||||
if (inet_chksum_pbuf(p) != 0) {
|
|
||||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo\n"));
|
|
||||||
pbuf_free(p);
|
|
||||||
ICMP_STATS_INC(icmp.chkerr);
|
|
||||||
snmp_inc_icmpinerrors();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN
|
|
||||||
if (pbuf_header(p, (PBUF_IP_HLEN + PBUF_LINK_HLEN))) {
|
|
||||||
/* p is not big enough to contain link headers
|
|
||||||
* allocate a new one and copy p into it
|
|
||||||
*/
|
|
||||||
struct pbuf *r;
|
|
||||||
/* switch p->payload to ip header */
|
|
||||||
if (pbuf_header(p, hlen)) {
|
|
||||||
LWIP_ASSERT("icmp_input: moving p->payload to ip header failed\n", 0);
|
|
||||||
goto memerr;
|
|
||||||
}
|
|
||||||
/* allocate new packet buffer with space for link headers */
|
|
||||||
r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM);
|
|
||||||
if (r == NULL) {
|
|
||||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: allocating new pbuf failed\n"));
|
|
||||||
goto memerr;
|
|
||||||
}
|
|
||||||
LWIP_ASSERT("check that first pbuf can hold struct the ICMP header",
|
|
||||||
(r->len >= hlen + sizeof(struct icmp_echo_hdr)));
|
|
||||||
/* copy the whole packet including ip header */
|
|
||||||
if (pbuf_copy(r, p) != ERR_OK) {
|
|
||||||
LWIP_ASSERT("icmp_input: copying to new pbuf failed\n", 0);
|
|
||||||
goto memerr;
|
|
||||||
}
|
|
||||||
iphdr = r->payload;
|
|
||||||
/* switch r->payload back to icmp header */
|
|
||||||
if (pbuf_header(r, -hlen)) {
|
|
||||||
LWIP_ASSERT("icmp_input: restoring original p->payload failed\n", 0);
|
|
||||||
goto memerr;
|
|
||||||
}
|
|
||||||
/* free the original p */
|
|
||||||
pbuf_free(p);
|
|
||||||
/* we now have an identical copy of p that has room for link headers */
|
|
||||||
p = r;
|
|
||||||
} else {
|
|
||||||
/* restore p->payload to point to icmp header */
|
|
||||||
if (pbuf_header(p, -(s16_t)(PBUF_IP_HLEN + PBUF_LINK_HLEN))) {
|
|
||||||
LWIP_ASSERT("icmp_input: restoring original p->payload failed\n", 0);
|
|
||||||
goto memerr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */
|
|
||||||
/* At this point, all checks are OK. */
|
|
||||||
/* We generate an answer by switching the dest and src ip addresses,
|
|
||||||
* setting the icmp type to ECHO_RESPONSE and updating the checksum. */
|
|
||||||
iecho = p->payload;
|
|
||||||
tmpaddr.addr = iphdr->src.addr;
|
|
||||||
iphdr->src.addr = iphdr->dest.addr;
|
|
||||||
iphdr->dest.addr = tmpaddr.addr;
|
|
||||||
ICMPH_TYPE_SET(iecho, ICMP_ER);
|
|
||||||
|
|
||||||
|
|
||||||
/* This part of code has been modified by ST's MCD Application Team */
|
|
||||||
/* To use the Checksum Offload Engine for the putgoing ICMP packets,
|
|
||||||
the ICMP checksum field should be set to 0, this is required only for Tx ICMP*/
|
|
||||||
#ifdef CHECKSUM_BY_HARDWARE
|
|
||||||
iecho->chksum = 0;
|
|
||||||
#else
|
|
||||||
/* adjust the checksum */
|
|
||||||
if (iecho->chksum >= htons(0xffff - (ICMP_ECHO << 8))) {
|
|
||||||
iecho->chksum += htons(ICMP_ECHO << 8) + 1;
|
|
||||||
} else {
|
|
||||||
iecho->chksum += htons(ICMP_ECHO << 8);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Set the correct TTL and recalculate the header checksum. */
|
|
||||||
IPH_TTL_SET(iphdr, ICMP_TTL);
|
|
||||||
IPH_CHKSUM_SET(iphdr, 0);
|
|
||||||
#if CHECKSUM_GEN_IP
|
|
||||||
IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
|
|
||||||
#endif /* CHECKSUM_GEN_IP */
|
|
||||||
|
|
||||||
ICMP_STATS_INC(icmp.xmit);
|
|
||||||
/* increase number of messages attempted to send */
|
|
||||||
snmp_inc_icmpoutmsgs();
|
|
||||||
/* increase number of echo replies attempted to send */
|
|
||||||
snmp_inc_icmpoutechoreps();
|
|
||||||
|
|
||||||
if(pbuf_header(p, hlen)) {
|
|
||||||
LWIP_ASSERT("Can't move over header in packet", 0);
|
|
||||||
} else {
|
|
||||||
err_t ret;
|
|
||||||
ret = ip_output_if(p, &(iphdr->src), IP_HDRINCL,
|
|
||||||
ICMP_TTL, 0, IP_PROTO_ICMP, inp);
|
|
||||||
if (ret != ERR_OK) {
|
|
||||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ip_output_if returned an error: %c.\n", ret));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ICMP type %"S16_F" code %"S16_F" not supported.\n",
|
|
||||||
(s16_t)type, (s16_t)code));
|
|
||||||
ICMP_STATS_INC(icmp.proterr);
|
|
||||||
ICMP_STATS_INC(icmp.drop);
|
|
||||||
}
|
|
||||||
pbuf_free(p);
|
|
||||||
return;
|
|
||||||
lenerr:
|
|
||||||
pbuf_free(p);
|
|
||||||
ICMP_STATS_INC(icmp.lenerr);
|
|
||||||
snmp_inc_icmpinerrors();
|
|
||||||
return;
|
|
||||||
#if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN
|
|
||||||
memerr:
|
|
||||||
pbuf_free(p);
|
|
||||||
ICMP_STATS_INC(icmp.err);
|
|
||||||
snmp_inc_icmpinerrors();
|
|
||||||
return;
|
|
||||||
#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send an icmp 'destination unreachable' packet, called from ip_input() if
|
|
||||||
* the transport layer protocol is unknown and from udp_input() if the local
|
|
||||||
* port is not bound.
|
|
||||||
*
|
|
||||||
* @param p the input packet for which the 'unreachable' should be sent,
|
|
||||||
* p->payload pointing to the IP header
|
|
||||||
* @param t type of the 'unreachable' packet
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t)
|
|
||||||
{
|
|
||||||
icmp_send_response(p, ICMP_DUR, t);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if IP_FORWARD || IP_REASSEMBLY
|
|
||||||
/**
|
|
||||||
* Send a 'time exceeded' packet, called from ip_forward() if TTL is 0.
|
|
||||||
*
|
|
||||||
* @param p the input packet for which the 'time exceeded' should be sent,
|
|
||||||
* p->payload pointing to the IP header
|
|
||||||
* @param t type of the 'time exceeded' packet
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t)
|
|
||||||
{
|
|
||||||
icmp_send_response(p, ICMP_TE, t);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* IP_FORWARD || IP_REASSEMBLY */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send an icmp packet in response to an incoming packet.
|
|
||||||
*
|
|
||||||
* @param p the input packet for which the 'unreachable' should be sent,
|
|
||||||
* p->payload pointing to the IP header
|
|
||||||
* @param type Type of the ICMP header
|
|
||||||
* @param code Code of the ICMP header
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
icmp_send_response(struct pbuf *p, u8_t type, u8_t code)
|
|
||||||
{
|
|
||||||
struct pbuf *q;
|
|
||||||
struct ip_hdr *iphdr;
|
|
||||||
/* we can use the echo header here */
|
|
||||||
struct icmp_echo_hdr *icmphdr;
|
|
||||||
|
|
||||||
/* ICMP header + IP header + 8 bytes of data */
|
|
||||||
q = pbuf_alloc(PBUF_IP, sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE,
|
|
||||||
PBUF_RAM);
|
|
||||||
if (q == NULL) {
|
|
||||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMP packet.\n"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
LWIP_ASSERT("check that first pbuf can hold icmp message",
|
|
||||||
(q->len >= (sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE)));
|
|
||||||
|
|
||||||
iphdr = p->payload;
|
|
||||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded from "));
|
|
||||||
ip_addr_debug_print(ICMP_DEBUG, &(iphdr->src));
|
|
||||||
LWIP_DEBUGF(ICMP_DEBUG, (" to "));
|
|
||||||
ip_addr_debug_print(ICMP_DEBUG, &(iphdr->dest));
|
|
||||||
LWIP_DEBUGF(ICMP_DEBUG, ("\n"));
|
|
||||||
|
|
||||||
icmphdr = q->payload;
|
|
||||||
icmphdr->type = type;
|
|
||||||
icmphdr->code = code;
|
|
||||||
icmphdr->id = 0;
|
|
||||||
icmphdr->seqno = 0;
|
|
||||||
|
|
||||||
/* copy fields from original packet */
|
|
||||||
SMEMCPY((u8_t *)q->payload + sizeof(struct icmp_echo_hdr), (u8_t *)p->payload,
|
|
||||||
IP_HLEN + ICMP_DEST_UNREACH_DATASIZE);
|
|
||||||
|
|
||||||
/* calculate checksum */
|
|
||||||
icmphdr->chksum = 0;
|
|
||||||
icmphdr->chksum = inet_chksum(icmphdr, q->len);
|
|
||||||
ICMP_STATS_INC(icmp.xmit);
|
|
||||||
/* increase number of messages attempted to send */
|
|
||||||
snmp_inc_icmpoutmsgs();
|
|
||||||
/* increase number of destination unreachable messages attempted to send */
|
|
||||||
snmp_inc_icmpouttimeexcds();
|
|
||||||
ip_output(q, NULL, &(iphdr->src), ICMP_TTL, 0, IP_PROTO_ICMP);
|
|
||||||
pbuf_free(q);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* LWIP_ICMP */
|
|
|
@ -1,757 +0,0 @@
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
* IGMP - Internet Group Management Protocol
|
|
||||||
*
|
|
||||||
**/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2002 CITEL Technologies Ltd.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of CITEL Technologies Ltd nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY CITEL TECHNOLOGIES AND CONTRIBUTORS ``AS IS''
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL CITEL TECHNOLOGIES OR CONTRIBUTORS BE LIABLE
|
|
||||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
||||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
||||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
||||||
* SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is a contribution to the lwIP TCP/IP stack.
|
|
||||||
* The Swedish Institute of Computer Science and Adam Dunkels
|
|
||||||
* are specifically granted permission to redistribute this
|
|
||||||
* source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*-------------------------------------------------------------
|
|
||||||
Note 1)
|
|
||||||
Although the rfc requires V1 AND V2 capability
|
|
||||||
we will only support v2 since now V1 is very old (August 1989)
|
|
||||||
V1 can be added if required
|
|
||||||
|
|
||||||
a debug print and statistic have been implemented to
|
|
||||||
show this up.
|
|
||||||
-------------------------------------------------------------
|
|
||||||
-------------------------------------------------------------
|
|
||||||
Note 2)
|
|
||||||
A query for a specific group address (as opposed to ALLHOSTS)
|
|
||||||
has now been implemented as I am unsure if it is required
|
|
||||||
|
|
||||||
a debug print and statistic have been implemented to
|
|
||||||
show this up.
|
|
||||||
-------------------------------------------------------------
|
|
||||||
-------------------------------------------------------------
|
|
||||||
Note 3)
|
|
||||||
The router alert rfc 2113 is implemented in outgoing packets
|
|
||||||
but not checked rigorously incoming
|
|
||||||
-------------------------------------------------------------
|
|
||||||
Steve Reynolds
|
|
||||||
------------------------------------------------------------*/
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------
|
|
||||||
* RFC 988 - Host extensions for IP multicasting - V0
|
|
||||||
* RFC 1054 - Host extensions for IP multicasting -
|
|
||||||
* RFC 1112 - Host extensions for IP multicasting - V1
|
|
||||||
* RFC 2236 - Internet Group Management Protocol, Version 2 - V2 <- this code is based on this RFC (it's the "de facto" standard)
|
|
||||||
* RFC 3376 - Internet Group Management Protocol, Version 3 - V3
|
|
||||||
* RFC 4604 - Using Internet Group Management Protocol Version 3... - V3+
|
|
||||||
* RFC 2113 - IP Router Alert Option -
|
|
||||||
*----------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------
|
|
||||||
* Includes
|
|
||||||
*----------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
#include "lwip/opt.h"
|
|
||||||
|
|
||||||
#if LWIP_IGMP /* don't build if not configured for use in lwipopts.h */
|
|
||||||
|
|
||||||
#include "lwip/igmp.h"
|
|
||||||
#include "lwip/debug.h"
|
|
||||||
#include "lwip/def.h"
|
|
||||||
#include "lwip/mem.h"
|
|
||||||
#include "lwip/ip.h"
|
|
||||||
#include "lwip/inet.h"
|
|
||||||
#include "lwip/inet_chksum.h"
|
|
||||||
#include "lwip/netif.h"
|
|
||||||
#include "lwip/icmp.h"
|
|
||||||
#include "lwip/udp.h"
|
|
||||||
#include "lwip/tcp.h"
|
|
||||||
#include "lwip/stats.h"
|
|
||||||
|
|
||||||
#include "string.h"
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------
|
|
||||||
* Globales
|
|
||||||
*----------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
static struct igmp_group* igmp_group_list;
|
|
||||||
static struct ip_addr allsystems;
|
|
||||||
static struct ip_addr allrouters;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize the IGMP module
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
igmp_init(void)
|
|
||||||
{
|
|
||||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_init: initializing\n"));
|
|
||||||
|
|
||||||
IP4_ADDR(&allsystems, 224, 0, 0, 1);
|
|
||||||
IP4_ADDR(&allrouters, 224, 0, 0, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef LWIP_DEBUG
|
|
||||||
/**
|
|
||||||
* Dump global IGMP groups list
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
igmp_dump_group_list()
|
|
||||||
{
|
|
||||||
struct igmp_group *group = igmp_group_list;
|
|
||||||
|
|
||||||
while (group != NULL) {
|
|
||||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_dump_group_list: [%"U32_F"] ", (u32_t)(group->group_state)));
|
|
||||||
ip_addr_debug_print(IGMP_DEBUG, &group->group_address);
|
|
||||||
LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->interface));
|
|
||||||
group = group->next;
|
|
||||||
}
|
|
||||||
LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
#define igmp_dump_group_list()
|
|
||||||
#endif /* LWIP_DEBUG */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start IGMP processing on interface
|
|
||||||
*
|
|
||||||
* @param netif network interface on which start IGMP processing
|
|
||||||
*/
|
|
||||||
err_t
|
|
||||||
igmp_start(struct netif *netif)
|
|
||||||
{
|
|
||||||
struct igmp_group* group;
|
|
||||||
|
|
||||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: starting IGMP processing on if %p\n", netif));
|
|
||||||
|
|
||||||
group = igmp_lookup_group(netif, &allsystems);
|
|
||||||
|
|
||||||
if (group != NULL) {
|
|
||||||
group->group_state = IGMP_GROUP_IDLE_MEMBER;
|
|
||||||
group->use++;
|
|
||||||
|
|
||||||
/* Allow the igmp messages at the MAC level */
|
|
||||||
if (netif->igmp_mac_filter != NULL) {
|
|
||||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: igmp_mac_filter(ADD "));
|
|
||||||
ip_addr_debug_print(IGMP_DEBUG, &allsystems);
|
|
||||||
LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
|
|
||||||
netif->igmp_mac_filter( netif, &allsystems, IGMP_ADD_MAC_FILTER);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ERR_MEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stop IGMP processing on interface
|
|
||||||
*
|
|
||||||
* @param netif network interface on which stop IGMP processing
|
|
||||||
*/
|
|
||||||
err_t
|
|
||||||
igmp_stop(struct netif *netif)
|
|
||||||
{
|
|
||||||
struct igmp_group *group = igmp_group_list;
|
|
||||||
struct igmp_group *prev = NULL;
|
|
||||||
struct igmp_group *next;
|
|
||||||
|
|
||||||
/* look for groups joined on this interface further down the list */
|
|
||||||
while (group != NULL) {
|
|
||||||
next = group->next;
|
|
||||||
/* is it a group joined on this interface? */
|
|
||||||
if (group->interface == netif) {
|
|
||||||
/* is it the first group of the list? */
|
|
||||||
if (group == igmp_group_list) {
|
|
||||||
igmp_group_list = next;
|
|
||||||
}
|
|
||||||
/* is there a "previous" group defined? */
|
|
||||||
if (prev != NULL) {
|
|
||||||
prev->next = next;
|
|
||||||
}
|
|
||||||
/* disable the group at the MAC level */
|
|
||||||
if (netif->igmp_mac_filter != NULL) {
|
|
||||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_stop: igmp_mac_filter(DEL "));
|
|
||||||
ip_addr_debug_print(IGMP_DEBUG, &group->group_address);
|
|
||||||
LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
|
|
||||||
netif->igmp_mac_filter(netif, &(group->group_address), IGMP_DEL_MAC_FILTER);
|
|
||||||
}
|
|
||||||
/* free group */
|
|
||||||
memp_free(MEMP_IGMP_GROUP, group);
|
|
||||||
} else {
|
|
||||||
/* change the "previous" */
|
|
||||||
prev = group;
|
|
||||||
}
|
|
||||||
/* move to "next" */
|
|
||||||
group = next;
|
|
||||||
}
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Report IGMP memberships for this interface
|
|
||||||
*
|
|
||||||
* @param netif network interface on which report IGMP memberships
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
igmp_report_groups( struct netif *netif)
|
|
||||||
{
|
|
||||||
struct igmp_group *group = igmp_group_list;
|
|
||||||
|
|
||||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_report_groups: sending IGMP reports on if %p\n", netif));
|
|
||||||
|
|
||||||
while (group != NULL) {
|
|
||||||
if (group->interface == netif) {
|
|
||||||
igmp_delaying_member( group, IGMP_JOIN_DELAYING_MEMBER_TMR);
|
|
||||||
}
|
|
||||||
group = group->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Search for a group in the global igmp_group_list
|
|
||||||
*
|
|
||||||
* @param ifp the network interface for which to look
|
|
||||||
* @param addr the group ip address to search for
|
|
||||||
* @return a struct igmp_group* if the group has been found,
|
|
||||||
* NULL if the group wasn't found.
|
|
||||||
*/
|
|
||||||
struct igmp_group *
|
|
||||||
igmp_lookfor_group(struct netif *ifp, struct ip_addr *addr)
|
|
||||||
{
|
|
||||||
struct igmp_group *group = igmp_group_list;
|
|
||||||
|
|
||||||
while (group != NULL) {
|
|
||||||
if ((group->interface == ifp) && (ip_addr_cmp(&(group->group_address), addr))) {
|
|
||||||
return group;
|
|
||||||
}
|
|
||||||
group = group->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* to be clearer, we return NULL here instead of
|
|
||||||
* 'group' (which is also NULL at this point).
|
|
||||||
*/
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Search for a specific igmp group and create a new one if not found-
|
|
||||||
*
|
|
||||||
* @param ifp the network interface for which to look
|
|
||||||
* @param addr the group ip address to search
|
|
||||||
* @return a struct igmp_group*,
|
|
||||||
* NULL on memory error.
|
|
||||||
*/
|
|
||||||
struct igmp_group *
|
|
||||||
igmp_lookup_group(struct netif *ifp, struct ip_addr *addr)
|
|
||||||
{
|
|
||||||
struct igmp_group *group = igmp_group_list;
|
|
||||||
|
|
||||||
/* Search if the group already exists */
|
|
||||||
group = igmp_lookfor_group(ifp, addr);
|
|
||||||
if (group != NULL) {
|
|
||||||
/* Group already exists. */
|
|
||||||
return group;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Group doesn't exist yet, create a new one */
|
|
||||||
group = memp_malloc(MEMP_IGMP_GROUP);
|
|
||||||
if (group != NULL) {
|
|
||||||
group->interface = ifp;
|
|
||||||
ip_addr_set(&(group->group_address), addr);
|
|
||||||
group->timer = 0; /* Not running */
|
|
||||||
group->group_state = IGMP_GROUP_NON_MEMBER;
|
|
||||||
group->last_reporter_flag = 0;
|
|
||||||
group->use = 0;
|
|
||||||
group->next = igmp_group_list;
|
|
||||||
|
|
||||||
igmp_group_list = group;
|
|
||||||
}
|
|
||||||
|
|
||||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_lookup_group: %sallocated a new group with address ", (group?"":"impossible to ")));
|
|
||||||
ip_addr_debug_print(IGMP_DEBUG, addr);
|
|
||||||
LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", ifp));
|
|
||||||
|
|
||||||
return group;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove a group in the global igmp_group_list
|
|
||||||
*
|
|
||||||
* @param group the group to remove from the global igmp_group_list
|
|
||||||
* @return ERR_OK if group was removed from the list, an err_t otherwise
|
|
||||||
*/
|
|
||||||
err_t
|
|
||||||
igmp_remove_group(struct igmp_group *group)
|
|
||||||
{
|
|
||||||
err_t err = ERR_OK;
|
|
||||||
|
|
||||||
/* Is it the first group? */
|
|
||||||
if (igmp_group_list == group) {
|
|
||||||
igmp_group_list = group->next;
|
|
||||||
} else {
|
|
||||||
/* look for group further down the list */
|
|
||||||
struct igmp_group *tmpGroup;
|
|
||||||
for (tmpGroup = igmp_group_list; tmpGroup != NULL; tmpGroup = tmpGroup->next) {
|
|
||||||
if (tmpGroup->next == group) {
|
|
||||||
tmpGroup->next = group->next;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Group not found in the global igmp_group_list */
|
|
||||||
if (tmpGroup == NULL)
|
|
||||||
err = ERR_ARG;
|
|
||||||
}
|
|
||||||
/* free group */
|
|
||||||
memp_free(MEMP_IGMP_GROUP, group);
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called from ip_input() if a new IGMP packet is received.
|
|
||||||
*
|
|
||||||
* @param p received igmp packet, p->payload pointing to the ip header
|
|
||||||
* @param inp network interface on which the packet was received
|
|
||||||
* @param dest destination ip address of the igmp packet
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
igmp_input(struct pbuf *p, struct netif *inp, struct ip_addr *dest)
|
|
||||||
{
|
|
||||||
struct ip_hdr * iphdr;
|
|
||||||
struct igmp_msg* igmp;
|
|
||||||
struct igmp_group* group;
|
|
||||||
struct igmp_group* groupref;
|
|
||||||
|
|
||||||
/* Note that the length CAN be greater than 8 but only 8 are used - All are included in the checksum */
|
|
||||||
iphdr = p->payload;
|
|
||||||
if (pbuf_header(p, -(s16_t)(IPH_HL(iphdr) * 4)) || (p->len < IGMP_MINLEN)) {
|
|
||||||
pbuf_free(p);
|
|
||||||
IGMP_STATS_INC(igmp.lenerr);
|
|
||||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: length error\n"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: message from "));
|
|
||||||
ip_addr_debug_print(IGMP_DEBUG, &(iphdr->src));
|
|
||||||
LWIP_DEBUGF(IGMP_DEBUG, (" to address "));
|
|
||||||
ip_addr_debug_print(IGMP_DEBUG, &(iphdr->dest));
|
|
||||||
LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", inp));
|
|
||||||
|
|
||||||
/* Now calculate and check the checksum */
|
|
||||||
igmp = (struct igmp_msg *)p->payload;
|
|
||||||
if (inet_chksum(igmp, p->len)) {
|
|
||||||
pbuf_free(p);
|
|
||||||
IGMP_STATS_INC(igmp.chkerr);
|
|
||||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: checksum error\n"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Packet is ok so find an existing group */
|
|
||||||
group = igmp_lookfor_group(inp, dest); /* use the incoming IP address! */
|
|
||||||
|
|
||||||
/* If group can be found or create... */
|
|
||||||
if (!group) {
|
|
||||||
pbuf_free(p);
|
|
||||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP frame not for us\n"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* NOW ACT ON THE INCOMING MESSAGE TYPE... */
|
|
||||||
switch (igmp->igmp_msgtype) {
|
|
||||||
case IGMP_MEMB_QUERY: {
|
|
||||||
/* IGMP_MEMB_QUERY to the "all systems" address ? */
|
|
||||||
if ((ip_addr_cmp(dest, &allsystems)) && (igmp->igmp_group_address.addr == 0)) {
|
|
||||||
/* THIS IS THE GENERAL QUERY */
|
|
||||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: General IGMP_MEMB_QUERY on \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));
|
|
||||||
|
|
||||||
if (igmp->igmp_maxresp == 0) {
|
|
||||||
IGMP_STATS_INC(igmp.v1_rxed);
|
|
||||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: got an all hosts query with time== 0 - this is V1 and not implemented - treat as v2\n"));
|
|
||||||
igmp->igmp_maxresp = IGMP_V1_DELAYING_MEMBER_TMR;
|
|
||||||
}
|
|
||||||
|
|
||||||
IGMP_STATS_INC(igmp.group_query_rxed);
|
|
||||||
groupref = igmp_group_list;
|
|
||||||
while (groupref) {
|
|
||||||
/* Do not send messages on the all systems group address! */
|
|
||||||
if ((groupref->interface == inp) && (!(ip_addr_cmp(&(groupref->group_address), &allsystems)))) {
|
|
||||||
igmp_delaying_member( groupref, igmp->igmp_maxresp);
|
|
||||||
}
|
|
||||||
groupref = groupref->next;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* IGMP_MEMB_QUERY to a specific group ? */
|
|
||||||
if (group->group_address.addr != 0) {
|
|
||||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_MEMB_QUERY to a specific group "));
|
|
||||||
ip_addr_debug_print(IGMP_DEBUG, &group->group_address);
|
|
||||||
if (ip_addr_cmp (dest, &allsystems)) {
|
|
||||||
LWIP_DEBUGF(IGMP_DEBUG, (" using \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));
|
|
||||||
/* we first need to re-lookfor the group since we used dest last time */
|
|
||||||
group = igmp_lookfor_group(inp, &igmp->igmp_group_address);
|
|
||||||
} else {
|
|
||||||
LWIP_DEBUGF(IGMP_DEBUG, (" with the group address as destination [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (group != NULL) {
|
|
||||||
IGMP_STATS_INC(igmp.unicast_query);
|
|
||||||
igmp_delaying_member( group, igmp->igmp_maxresp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case IGMP_V2_MEMB_REPORT: {
|
|
||||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_V2_MEMB_REPORT\n"));
|
|
||||||
|
|
||||||
IGMP_STATS_INC(igmp.report_rxed);
|
|
||||||
if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) {
|
|
||||||
/* This is on a specific group we have already looked up */
|
|
||||||
group->timer = 0; /* stopped */
|
|
||||||
group->group_state = IGMP_GROUP_IDLE_MEMBER;
|
|
||||||
group->last_reporter_flag = 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: unexpected msg %d in state %d on group %p on if %p\n",
|
|
||||||
igmp->igmp_msgtype, group->group_state, &group, group->interface));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pbuf_free(p);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Join a group on one network interface.
|
|
||||||
*
|
|
||||||
* @param ifaddr ip address of the network interface which should join a new group
|
|
||||||
* @param groupaddr the ip address of the group which to join
|
|
||||||
* @return ERR_OK if group was joined on the netif(s), an err_t otherwise
|
|
||||||
*/
|
|
||||||
err_t
|
|
||||||
igmp_joingroup(struct ip_addr *ifaddr, struct ip_addr *groupaddr)
|
|
||||||
{
|
|
||||||
err_t err = ERR_VAL; /* no matching interface */
|
|
||||||
struct igmp_group *group;
|
|
||||||
struct netif *netif;
|
|
||||||
|
|
||||||
/* make sure it is multicast address */
|
|
||||||
LWIP_ERROR("igmp_joingroup: attempt to join non-multicast address", ip_addr_ismulticast(groupaddr), return ERR_VAL;);
|
|
||||||
LWIP_ERROR("igmp_joingroup: attempt to join allsystems address", (!ip_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;);
|
|
||||||
|
|
||||||
/* loop through netif's */
|
|
||||||
netif = netif_list;
|
|
||||||
while (netif != NULL) {
|
|
||||||
/* Should we join this interface ? */
|
|
||||||
if ((netif->flags & NETIF_FLAG_IGMP) && ((ip_addr_isany(ifaddr) || ip_addr_cmp(&(netif->ip_addr), ifaddr)))) {
|
|
||||||
/* find group or create a new one if not found */
|
|
||||||
group = igmp_lookup_group(netif, groupaddr);
|
|
||||||
|
|
||||||
if (group != NULL) {
|
|
||||||
/* This should create a new group, check the state to make sure */
|
|
||||||
if (group->group_state != IGMP_GROUP_NON_MEMBER) {
|
|
||||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: join to group not in state IGMP_GROUP_NON_MEMBER\n"));
|
|
||||||
} else {
|
|
||||||
/* OK - it was new group */
|
|
||||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: join to new group: "));
|
|
||||||
ip_addr_debug_print(IGMP_DEBUG, groupaddr);
|
|
||||||
LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
|
|
||||||
|
|
||||||
/* If first use of the group, allow the group at the MAC level */
|
|
||||||
if ((group->use==0) && (netif->igmp_mac_filter != NULL)) {
|
|
||||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: igmp_mac_filter(ADD "));
|
|
||||||
ip_addr_debug_print(IGMP_DEBUG, groupaddr);
|
|
||||||
LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
|
|
||||||
netif->igmp_mac_filter(netif, groupaddr, IGMP_ADD_MAC_FILTER);
|
|
||||||
}
|
|
||||||
|
|
||||||
IGMP_STATS_INC(igmp.join_sent);
|
|
||||||
igmp_send(group, IGMP_V2_MEMB_REPORT);
|
|
||||||
|
|
||||||
igmp_start_timer(group, IGMP_JOIN_DELAYING_MEMBER_TMR);
|
|
||||||
|
|
||||||
/* Need to work out where this timer comes from */
|
|
||||||
group->group_state = IGMP_GROUP_DELAYING_MEMBER;
|
|
||||||
}
|
|
||||||
/* Increment group use */
|
|
||||||
group->use++;
|
|
||||||
/* Join on this interface */
|
|
||||||
err = ERR_OK;
|
|
||||||
} else {
|
|
||||||
/* Return an error even if some network interfaces are joined */
|
|
||||||
/** @todo undo any other netif already joined */
|
|
||||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: Not enought memory to join to group\n"));
|
|
||||||
return ERR_MEM;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* proceed to next network interface */
|
|
||||||
netif = netif->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Leave a group on one network interface.
|
|
||||||
*
|
|
||||||
* @param ifaddr ip address of the network interface which should leave a group
|
|
||||||
* @param groupaddr the ip address of the group which to leave
|
|
||||||
* @return ERR_OK if group was left on the netif(s), an err_t otherwise
|
|
||||||
*/
|
|
||||||
err_t
|
|
||||||
igmp_leavegroup(struct ip_addr *ifaddr, struct ip_addr *groupaddr)
|
|
||||||
{
|
|
||||||
err_t err = ERR_VAL; /* no matching interface */
|
|
||||||
struct igmp_group *group;
|
|
||||||
struct netif *netif;
|
|
||||||
|
|
||||||
/* make sure it is multicast address */
|
|
||||||
LWIP_ERROR("igmp_leavegroup: attempt to leave non-multicast address", ip_addr_ismulticast(groupaddr), return ERR_VAL;);
|
|
||||||
LWIP_ERROR("igmp_leavegroup: attempt to leave allsystems address", (!ip_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;);
|
|
||||||
|
|
||||||
/* loop through netif's */
|
|
||||||
netif = netif_list;
|
|
||||||
while (netif != NULL) {
|
|
||||||
/* Should we leave this interface ? */
|
|
||||||
if ((netif->flags & NETIF_FLAG_IGMP) && ((ip_addr_isany(ifaddr) || ip_addr_cmp(&(netif->ip_addr), ifaddr)))) {
|
|
||||||
/* find group */
|
|
||||||
group = igmp_lookfor_group(netif, groupaddr);
|
|
||||||
|
|
||||||
if (group != NULL) {
|
|
||||||
/* Only send a leave if the flag is set according to the state diagram */
|
|
||||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: Leaving group: "));
|
|
||||||
ip_addr_debug_print(IGMP_DEBUG, groupaddr);
|
|
||||||
LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
|
|
||||||
|
|
||||||
/* If there is no other use of the group */
|
|
||||||
if (group->use <= 1) {
|
|
||||||
/* If we are the last reporter for this group */
|
|
||||||
if (group->last_reporter_flag) {
|
|
||||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: sending leaving group\n"));
|
|
||||||
IGMP_STATS_INC(igmp.leave_sent);
|
|
||||||
igmp_send(group, IGMP_LEAVE_GROUP);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Disable the group at the MAC level */
|
|
||||||
if (netif->igmp_mac_filter != NULL) {
|
|
||||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: igmp_mac_filter(DEL "));
|
|
||||||
ip_addr_debug_print(IGMP_DEBUG, groupaddr);
|
|
||||||
LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
|
|
||||||
netif->igmp_mac_filter(netif, groupaddr, IGMP_DEL_MAC_FILTER);
|
|
||||||
}
|
|
||||||
|
|
||||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: remove group: "));
|
|
||||||
ip_addr_debug_print(IGMP_DEBUG, groupaddr);
|
|
||||||
LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
|
|
||||||
|
|
||||||
/* Free the group */
|
|
||||||
igmp_remove_group(group);
|
|
||||||
} else {
|
|
||||||
/* Decrement group use */
|
|
||||||
group->use--;
|
|
||||||
}
|
|
||||||
/* Leave on this interface */
|
|
||||||
err = ERR_OK;
|
|
||||||
} else {
|
|
||||||
/* It's not a fatal error on "leavegroup" */
|
|
||||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: not member of group\n"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* proceed to next network interface */
|
|
||||||
netif = netif->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The igmp timer function (both for NO_SYS=1 and =0)
|
|
||||||
* Should be called every IGMP_TMR_INTERVAL milliseconds (100 ms is default).
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
igmp_tmr(void)
|
|
||||||
{
|
|
||||||
struct igmp_group *group = igmp_group_list;
|
|
||||||
|
|
||||||
while (group != NULL) {
|
|
||||||
if (group->timer != 0) {
|
|
||||||
group->timer -= 1;
|
|
||||||
if (group->timer == 0) {
|
|
||||||
igmp_timeout(group);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
group = group->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called if a timeout for one group is reached.
|
|
||||||
* Sends a report for this group.
|
|
||||||
*
|
|
||||||
* @param group an igmp_group for which a timeout is reached
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
igmp_timeout(struct igmp_group *group)
|
|
||||||
{
|
|
||||||
/* If the state is IGMP_GROUP_DELAYING_MEMBER then we send a report for this group */
|
|
||||||
if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) {
|
|
||||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_timeout: report membership for group with address "));
|
|
||||||
ip_addr_debug_print(IGMP_DEBUG, &(group->group_address));
|
|
||||||
LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->interface));
|
|
||||||
|
|
||||||
igmp_send(group, IGMP_V2_MEMB_REPORT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start a timer for an igmp group
|
|
||||||
*
|
|
||||||
* @param group the igmp_group for which to start a timer
|
|
||||||
* @param max_time the time in multiples of IGMP_TMR_INTERVAL (decrease with
|
|
||||||
* every call to igmp_tmr())
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
igmp_start_timer(struct igmp_group *group, u8_t max_time)
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @todo Important !! this should be random 0 -> max_time. Find out how to do this
|
|
||||||
*/
|
|
||||||
group->timer = max_time;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stop a timer for an igmp_group
|
|
||||||
*
|
|
||||||
* @param group the igmp_group for which to stop the timer
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
igmp_stop_timer(struct igmp_group *group)
|
|
||||||
{
|
|
||||||
group->timer = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delaying membership report for a group if necessary
|
|
||||||
*
|
|
||||||
* @param group the igmp_group for which "delaying" membership report
|
|
||||||
* @param maxresp query delay
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
igmp_delaying_member( struct igmp_group *group, u8_t maxresp)
|
|
||||||
{
|
|
||||||
if ((group->group_state == IGMP_GROUP_IDLE_MEMBER) ||
|
|
||||||
((group->group_state == IGMP_GROUP_DELAYING_MEMBER) && (maxresp > group->timer))) {
|
|
||||||
igmp_start_timer(group, (maxresp)/2);
|
|
||||||
group->group_state = IGMP_GROUP_DELAYING_MEMBER;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends an IP packet on a network interface. This function constructs the IP header
|
|
||||||
* and calculates the IP header checksum. If the source IP address is NULL,
|
|
||||||
* the IP address of the outgoing network interface is filled in as source address.
|
|
||||||
*
|
|
||||||
* @param p the packet to send (p->payload points to the data, e.g. next
|
|
||||||
protocol header; if dest == IP_HDRINCL, p already includes an IP
|
|
||||||
header and p->payload points to that IP header)
|
|
||||||
* @param src the source IP address to send from (if src == IP_ADDR_ANY, the
|
|
||||||
* IP address of the netif used to send is used as source address)
|
|
||||||
* @param dest the destination IP address to send the packet to
|
|
||||||
* @param ttl the TTL value to be set in the IP header
|
|
||||||
* @param proto the PROTOCOL to be set in the IP header
|
|
||||||
* @param netif the netif on which to send this packet
|
|
||||||
* @return ERR_OK if the packet was sent OK
|
|
||||||
* ERR_BUF if p doesn't have enough space for IP/LINK headers
|
|
||||||
* returns errors returned by netif->output
|
|
||||||
*/
|
|
||||||
err_t
|
|
||||||
igmp_ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
|
|
||||||
u8_t ttl, u8_t proto, struct netif *netif)
|
|
||||||
{
|
|
||||||
/* This is the "router alert" option */
|
|
||||||
u16_t ra[2];
|
|
||||||
ra[0] = htons (ROUTER_ALERT);
|
|
||||||
ra[1] = 0x0000; /* Router shall examine packet */
|
|
||||||
return ip_output_if_opt(p, src, dest, ttl, 0, proto, netif, ra, ROUTER_ALERTLEN);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send an igmp packet to a specific group.
|
|
||||||
*
|
|
||||||
* @param group the group to which to send the packet
|
|
||||||
* @param type the type of igmp packet to send
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
igmp_send(struct igmp_group *group, u8_t type)
|
|
||||||
{
|
|
||||||
struct pbuf* p = NULL;
|
|
||||||
struct igmp_msg* igmp = NULL;
|
|
||||||
struct ip_addr src = {0};
|
|
||||||
struct ip_addr* dest = NULL;
|
|
||||||
|
|
||||||
/* IP header + "router alert" option + IGMP header */
|
|
||||||
p = pbuf_alloc(PBUF_TRANSPORT, IGMP_MINLEN, PBUF_RAM);
|
|
||||||
|
|
||||||
if (p) {
|
|
||||||
igmp = p->payload;
|
|
||||||
LWIP_ASSERT("igmp_send: check that first pbuf can hold struct igmp_msg",
|
|
||||||
(p->len >= sizeof(struct igmp_msg)));
|
|
||||||
ip_addr_set(&src, &((group->interface)->ip_addr));
|
|
||||||
|
|
||||||
if (type == IGMP_V2_MEMB_REPORT) {
|
|
||||||
dest = &(group->group_address);
|
|
||||||
IGMP_STATS_INC(igmp.report_sent);
|
|
||||||
ip_addr_set(&(igmp->igmp_group_address), &(group->group_address));
|
|
||||||
group->last_reporter_flag = 1; /* Remember we were the last to report */
|
|
||||||
} else {
|
|
||||||
if (type == IGMP_LEAVE_GROUP) {
|
|
||||||
dest = &allrouters;
|
|
||||||
ip_addr_set(&(igmp->igmp_group_address), &(group->group_address));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((type == IGMP_V2_MEMB_REPORT) || (type == IGMP_LEAVE_GROUP)) {
|
|
||||||
igmp->igmp_msgtype = type;
|
|
||||||
igmp->igmp_maxresp = 0;
|
|
||||||
igmp->igmp_checksum = 0;
|
|
||||||
igmp->igmp_checksum = inet_chksum( igmp, IGMP_MINLEN);
|
|
||||||
|
|
||||||
igmp_ip_output_if(p, &src, dest, IGMP_TTL, IP_PROTO_IGMP, group->interface);
|
|
||||||
}
|
|
||||||
|
|
||||||
pbuf_free(p);
|
|
||||||
} else {
|
|
||||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_send: not enough memory for igmp_send\n"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* LWIP_IGMP */
|
|
|
@ -1,278 +0,0 @@
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
* Functions common to all TCP/IPv4 modules, such as the byte order functions.
|
|
||||||
*
|
|
||||||
**/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "lwip/opt.h"
|
|
||||||
|
|
||||||
#include "lwip/inet.h"
|
|
||||||
|
|
||||||
/* Here for now until needed in other places in lwIP */
|
|
||||||
#ifndef isprint
|
|
||||||
#define in_range(c, lo, up) ((u8_t)c >= lo && (u8_t)c <= up)
|
|
||||||
#define isprint(c) in_range(c, 0x20, 0x7f)
|
|
||||||
#define isdigit(c) in_range(c, '0', '9')
|
|
||||||
#define isxdigit(c) (isdigit(c) || in_range(c, 'a', 'f') || in_range(c, 'A', 'F'))
|
|
||||||
#define islower(c) in_range(c, 'a', 'z')
|
|
||||||
#define isspace(c) (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v')
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ascii internet address interpretation routine.
|
|
||||||
* The value returned is in network order.
|
|
||||||
*
|
|
||||||
* @param cp IP address in ascii represenation (e.g. "127.0.0.1")
|
|
||||||
* @return ip address in network order
|
|
||||||
*/
|
|
||||||
u32_t
|
|
||||||
inet_addr(const char *cp)
|
|
||||||
{
|
|
||||||
struct in_addr val;
|
|
||||||
|
|
||||||
if (inet_aton(cp, &val)) {
|
|
||||||
return (val.s_addr);
|
|
||||||
}
|
|
||||||
return (INADDR_NONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check whether "cp" is a valid ascii representation
|
|
||||||
* of an Internet address and convert to a binary address.
|
|
||||||
* Returns 1 if the address is valid, 0 if not.
|
|
||||||
* This replaces inet_addr, the return value from which
|
|
||||||
* cannot distinguish between failure and a local broadcast address.
|
|
||||||
*
|
|
||||||
* @param cp IP address in ascii represenation (e.g. "127.0.0.1")
|
|
||||||
* @param addr pointer to which to save the ip address in network order
|
|
||||||
* @return 1 if cp could be converted to addr, 0 on failure
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
inet_aton(const char *cp, struct in_addr *addr)
|
|
||||||
{
|
|
||||||
u32_t val;
|
|
||||||
u8_t base;
|
|
||||||
char c;
|
|
||||||
u32_t parts[4];
|
|
||||||
u32_t *pp = parts;
|
|
||||||
|
|
||||||
c = *cp;
|
|
||||||
for (;;) {
|
|
||||||
/*
|
|
||||||
* Collect number up to ``.''.
|
|
||||||
* Values are specified as for C:
|
|
||||||
* 0x=hex, 0=octal, 1-9=decimal.
|
|
||||||
*/
|
|
||||||
if (!isdigit(c))
|
|
||||||
return (0);
|
|
||||||
val = 0;
|
|
||||||
base = 10;
|
|
||||||
if (c == '0') {
|
|
||||||
c = *++cp;
|
|
||||||
if (c == 'x' || c == 'X') {
|
|
||||||
base = 16;
|
|
||||||
c = *++cp;
|
|
||||||
} else
|
|
||||||
base = 8;
|
|
||||||
}
|
|
||||||
for (;;) {
|
|
||||||
if (isdigit(c)) {
|
|
||||||
val = (val * base) + (int)(c - '0');
|
|
||||||
c = *++cp;
|
|
||||||
} else if (base == 16 && isxdigit(c)) {
|
|
||||||
val = (val << 4) | (int)(c + 10 - (islower(c) ? 'a' : 'A'));
|
|
||||||
c = *++cp;
|
|
||||||
} else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (c == '.') {
|
|
||||||
/*
|
|
||||||
* Internet format:
|
|
||||||
* a.b.c.d
|
|
||||||
* a.b.c (with c treated as 16 bits)
|
|
||||||
* a.b (with b treated as 24 bits)
|
|
||||||
*/
|
|
||||||
if (pp >= parts + 3)
|
|
||||||
return (0);
|
|
||||||
*pp++ = val;
|
|
||||||
c = *++cp;
|
|
||||||
} else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Check for trailing characters.
|
|
||||||
*/
|
|
||||||
if (c != '\0' && !isspace(c))
|
|
||||||
return (0);
|
|
||||||
/*
|
|
||||||
* Concoct the address according to
|
|
||||||
* the number of parts specified.
|
|
||||||
*/
|
|
||||||
switch (pp - parts + 1) {
|
|
||||||
|
|
||||||
case 0:
|
|
||||||
return (0); /* initial nondigit */
|
|
||||||
|
|
||||||
case 1: /* a -- 32 bits */
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2: /* a.b -- 8.24 bits */
|
|
||||||
if (val > 0xffffffUL)
|
|
||||||
return (0);
|
|
||||||
val |= parts[0] << 24;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 3: /* a.b.c -- 8.8.16 bits */
|
|
||||||
if (val > 0xffff)
|
|
||||||
return (0);
|
|
||||||
val |= (parts[0] << 24) | (parts[1] << 16);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 4: /* a.b.c.d -- 8.8.8.8 bits */
|
|
||||||
if (val > 0xff)
|
|
||||||
return (0);
|
|
||||||
val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (addr)
|
|
||||||
addr->s_addr = htonl(val);
|
|
||||||
return (1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert numeric IP address into decimal dotted ASCII representation.
|
|
||||||
* returns ptr to static buffer; not reentrant!
|
|
||||||
*
|
|
||||||
* @param addr ip address in network order to convert
|
|
||||||
* @return pointer to a global static (!) buffer that holds the ASCII
|
|
||||||
* represenation of addr
|
|
||||||
*/
|
|
||||||
char *
|
|
||||||
inet_ntoa(struct in_addr addr)
|
|
||||||
{
|
|
||||||
static char str[16];
|
|
||||||
u32_t s_addr = addr.s_addr;
|
|
||||||
char inv[3];
|
|
||||||
char *rp;
|
|
||||||
u8_t *ap;
|
|
||||||
u8_t rem;
|
|
||||||
u8_t n;
|
|
||||||
u8_t i;
|
|
||||||
|
|
||||||
rp = str;
|
|
||||||
ap = (u8_t *)&s_addr;
|
|
||||||
for(n = 0; n < 4; n++) {
|
|
||||||
i = 0;
|
|
||||||
do {
|
|
||||||
rem = *ap % (u8_t)10;
|
|
||||||
*ap /= (u8_t)10;
|
|
||||||
inv[i++] = '0' + rem;
|
|
||||||
} while(*ap);
|
|
||||||
while(i--)
|
|
||||||
*rp++ = inv[i];
|
|
||||||
*rp++ = '.';
|
|
||||||
ap++;
|
|
||||||
}
|
|
||||||
*--rp = 0;
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* These are reference implementations of the byte swapping functions.
|
|
||||||
* Again with the aim of being simple, correct and fully portable.
|
|
||||||
* Byte swapping is the second thing you would want to optimize. You will
|
|
||||||
* need to port it to your architecture and in your cc.h:
|
|
||||||
*
|
|
||||||
* #define LWIP_PLATFORM_BYTESWAP 1
|
|
||||||
* #define LWIP_PLATFORM_HTONS(x) <your_htons>
|
|
||||||
* #define LWIP_PLATFORM_HTONL(x) <your_htonl>
|
|
||||||
*
|
|
||||||
* Note ntohs() and ntohl() are merely references to the htonx counterparts.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert an u16_t from host- to network byte order.
|
|
||||||
*
|
|
||||||
* @param n u16_t in host byte order
|
|
||||||
* @return n in network byte order
|
|
||||||
*/
|
|
||||||
u16_t
|
|
||||||
htons(u16_t n)
|
|
||||||
{
|
|
||||||
return ((n & 0xff) << 8) | ((n & 0xff00) >> 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert an u16_t from network- to host byte order.
|
|
||||||
*
|
|
||||||
* @param n u16_t in network byte order
|
|
||||||
* @return n in host byte order
|
|
||||||
*/
|
|
||||||
u16_t
|
|
||||||
ntohs(u16_t n)
|
|
||||||
{
|
|
||||||
return htons(n);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert an u32_t from host- to network byte order.
|
|
||||||
*
|
|
||||||
* @param n u32_t in host byte order
|
|
||||||
* @return n in network byte order
|
|
||||||
*/
|
|
||||||
u32_t
|
|
||||||
htonl(u32_t n)
|
|
||||||
{
|
|
||||||
return ((n & 0xff) << 24) |
|
|
||||||
((n & 0xff00) << 8) |
|
|
||||||
((n & 0xff0000UL) >> 8) |
|
|
||||||
((n & 0xff000000UL) >> 24);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert an u32_t from network- to host byte order.
|
|
||||||
*
|
|
||||||
* @param n u32_t in network byte order
|
|
||||||
* @return n in host byte order
|
|
||||||
*/
|
|
||||||
u32_t
|
|
||||||
ntohl(u32_t n)
|
|
||||||
{
|
|
||||||
return htonl(n);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN) */
|
|
|
@ -1,438 +0,0 @@
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
* Incluse internet checksum functions.
|
|
||||||
*
|
|
||||||
**/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "lwip/opt.h"
|
|
||||||
|
|
||||||
#include "lwip/inet_chksum.h"
|
|
||||||
#include "lwip/inet.h"
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
/* These are some reference implementations of the checksum algorithm, with the
|
|
||||||
* aim of being simple, correct and fully portable. Checksumming is the
|
|
||||||
* first thing you would want to optimize for your platform. If you create
|
|
||||||
* your own version, link it in and in your cc.h put:
|
|
||||||
*
|
|
||||||
* #define LWIP_CHKSUM <your_checksum_routine>
|
|
||||||
*
|
|
||||||
* Or you can select from the implementations below by defining
|
|
||||||
* LWIP_CHKSUM_ALGORITHM to 1, 2 or 3.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef LWIP_CHKSUM
|
|
||||||
# define LWIP_CHKSUM lwip_standard_chksum
|
|
||||||
# ifndef LWIP_CHKSUM_ALGORITHM
|
|
||||||
# define LWIP_CHKSUM_ALGORITHM 1
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
/* If none set: */
|
|
||||||
#ifndef LWIP_CHKSUM_ALGORITHM
|
|
||||||
# define LWIP_CHKSUM_ALGORITHM 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** Like the name says... */
|
|
||||||
#if LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN)
|
|
||||||
/* little endian and PLATFORM_BYTESWAP defined */
|
|
||||||
#define SWAP_BYTES_IN_WORD(w) LWIP_PLATFORM_HTONS(w)
|
|
||||||
#else
|
|
||||||
/* can't use htons on big endian (or PLATFORM_BYTESWAP not defined)... */
|
|
||||||
#define SWAP_BYTES_IN_WORD(w) ((w & 0xff) << 8) | ((w & 0xff00) >> 8)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** Split an u32_t in two u16_ts and add them up */
|
|
||||||
#define FOLD_U32T(u) ((u >> 16) + (u & 0x0000ffffUL))
|
|
||||||
|
|
||||||
#if (LWIP_CHKSUM_ALGORITHM == 1) /* Version #1 */
|
|
||||||
/**
|
|
||||||
* lwip checksum
|
|
||||||
*
|
|
||||||
* @param dataptr points to start of data to be summed at any boundary
|
|
||||||
* @param len length of data to be summed
|
|
||||||
* @return host order (!) lwip checksum (non-inverted Internet sum)
|
|
||||||
*
|
|
||||||
* @note accumulator size limits summable length to 64k
|
|
||||||
* @note host endianess is irrelevant (p3 RFC1071)
|
|
||||||
*/
|
|
||||||
static u16_t
|
|
||||||
lwip_standard_chksum(void *dataptr, u16_t len)
|
|
||||||
{
|
|
||||||
u32_t acc;
|
|
||||||
u16_t src;
|
|
||||||
u8_t *octetptr;
|
|
||||||
|
|
||||||
acc = 0;
|
|
||||||
/* dataptr may be at odd or even addresses */
|
|
||||||
octetptr = (u8_t*)dataptr;
|
|
||||||
while (len > 1) {
|
|
||||||
/* declare first octet as most significant
|
|
||||||
thus assume network order, ignoring host order */
|
|
||||||
src = (*octetptr) << 8;
|
|
||||||
octetptr++;
|
|
||||||
/* declare second octet as least significant */
|
|
||||||
src |= (*octetptr);
|
|
||||||
octetptr++;
|
|
||||||
acc += src;
|
|
||||||
len -= 2;
|
|
||||||
}
|
|
||||||
if (len > 0) {
|
|
||||||
/* accumulate remaining octet */
|
|
||||||
src = (*octetptr) << 8;
|
|
||||||
acc += src;
|
|
||||||
}
|
|
||||||
/* add deferred carry bits */
|
|
||||||
acc = (acc >> 16) + (acc & 0x0000ffffUL);
|
|
||||||
if ((acc & 0xffff0000UL) != 0) {
|
|
||||||
acc = (acc >> 16) + (acc & 0x0000ffffUL);
|
|
||||||
}
|
|
||||||
/* This maybe a little confusing: reorder sum using htons()
|
|
||||||
instead of ntohs() since it has a little less call overhead.
|
|
||||||
The caller must invert bits for Internet sum ! */
|
|
||||||
return htons((u16_t)acc);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if (LWIP_CHKSUM_ALGORITHM == 2) /* Alternative version #2 */
|
|
||||||
/*
|
|
||||||
* Curt McDowell
|
|
||||||
* Broadcom Corp.
|
|
||||||
* csm@broadcom.com
|
|
||||||
*
|
|
||||||
* IP checksum two bytes at a time with support for
|
|
||||||
* unaligned buffer.
|
|
||||||
* Works for len up to and including 0x20000.
|
|
||||||
* by Curt McDowell, Broadcom Corp. 12/08/2005
|
|
||||||
*
|
|
||||||
* @param dataptr points to start of data to be summed at any boundary
|
|
||||||
* @param len length of data to be summed
|
|
||||||
* @return host order (!) lwip checksum (non-inverted Internet sum)
|
|
||||||
*/
|
|
||||||
|
|
||||||
static u16_t
|
|
||||||
lwip_standard_chksum(void *dataptr, int len)
|
|
||||||
{
|
|
||||||
u8_t *pb = dataptr;
|
|
||||||
u16_t *ps, t = 0;
|
|
||||||
u32_t sum = 0;
|
|
||||||
int odd = ((u32_t)pb & 1);
|
|
||||||
|
|
||||||
/* Get aligned to u16_t */
|
|
||||||
if (odd && len > 0) {
|
|
||||||
((u8_t *)&t)[1] = *pb++;
|
|
||||||
len--;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add the bulk of the data */
|
|
||||||
ps = (u16_t *)pb;
|
|
||||||
while (len > 1) {
|
|
||||||
sum += *ps++;
|
|
||||||
len -= 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Consume left-over byte, if any */
|
|
||||||
if (len > 0) {
|
|
||||||
((u8_t *)&t)[0] = *(u8_t *)ps;;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add end bytes */
|
|
||||||
sum += t;
|
|
||||||
|
|
||||||
/* Fold 32-bit sum to 16 bits
|
|
||||||
calling this twice is propably faster than if statements... */
|
|
||||||
sum = FOLD_U32T(sum);
|
|
||||||
sum = FOLD_U32T(sum);
|
|
||||||
|
|
||||||
/* Swap if alignment was odd */
|
|
||||||
if (odd) {
|
|
||||||
sum = SWAP_BYTES_IN_WORD(sum);
|
|
||||||
}
|
|
||||||
|
|
||||||
return sum;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if (LWIP_CHKSUM_ALGORITHM == 3) /* Alternative version #3 */
|
|
||||||
/**
|
|
||||||
* An optimized checksum routine. Basically, it uses loop-unrolling on
|
|
||||||
* the checksum loop, treating the head and tail bytes specially, whereas
|
|
||||||
* the inner loop acts on 8 bytes at a time.
|
|
||||||
*
|
|
||||||
* @arg start of buffer to be checksummed. May be an odd byte address.
|
|
||||||
* @len number of bytes in the buffer to be checksummed.
|
|
||||||
* @return host order (!) lwip checksum (non-inverted Internet sum)
|
|
||||||
*
|
|
||||||
* by Curt McDowell, Broadcom Corp. December 8th, 2005
|
|
||||||
*/
|
|
||||||
|
|
||||||
static u16_t
|
|
||||||
lwip_standard_chksum(void *dataptr, int len)
|
|
||||||
{
|
|
||||||
u8_t *pb = dataptr;
|
|
||||||
u16_t *ps, t = 0;
|
|
||||||
u32_t *pl;
|
|
||||||
u32_t sum = 0, tmp;
|
|
||||||
/* starts at odd byte address? */
|
|
||||||
int odd = ((u32_t)pb & 1);
|
|
||||||
|
|
||||||
if (odd && len > 0) {
|
|
||||||
((u8_t *)&t)[1] = *pb++;
|
|
||||||
len--;
|
|
||||||
}
|
|
||||||
|
|
||||||
ps = (u16_t *)pb;
|
|
||||||
|
|
||||||
if (((u32_t)ps & 3) && len > 1) {
|
|
||||||
sum += *ps++;
|
|
||||||
len -= 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
pl = (u32_t *)ps;
|
|
||||||
|
|
||||||
while (len > 7) {
|
|
||||||
tmp = sum + *pl++; /* ping */
|
|
||||||
if (tmp < sum) {
|
|
||||||
tmp++; /* add back carry */
|
|
||||||
}
|
|
||||||
|
|
||||||
sum = tmp + *pl++; /* pong */
|
|
||||||
if (sum < tmp) {
|
|
||||||
sum++; /* add back carry */
|
|
||||||
}
|
|
||||||
|
|
||||||
len -= 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* make room in upper bits */
|
|
||||||
sum = FOLD_U32T(sum);
|
|
||||||
|
|
||||||
ps = (u16_t *)pl;
|
|
||||||
|
|
||||||
/* 16-bit aligned word remaining? */
|
|
||||||
while (len > 1) {
|
|
||||||
sum += *ps++;
|
|
||||||
len -= 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* dangling tail byte remaining? */
|
|
||||||
if (len > 0) { /* include odd byte */
|
|
||||||
((u8_t *)&t)[0] = *(u8_t *)ps;
|
|
||||||
}
|
|
||||||
|
|
||||||
sum += t; /* add end bytes */
|
|
||||||
|
|
||||||
/* Fold 32-bit sum to 16 bits
|
|
||||||
calling this twice is propably faster than if statements... */
|
|
||||||
sum = FOLD_U32T(sum);
|
|
||||||
sum = FOLD_U32T(sum);
|
|
||||||
|
|
||||||
if (odd) {
|
|
||||||
sum = SWAP_BYTES_IN_WORD(sum);
|
|
||||||
}
|
|
||||||
|
|
||||||
return sum;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* inet_chksum_pseudo:
|
|
||||||
*
|
|
||||||
* Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.
|
|
||||||
* IP addresses are expected to be in network byte order.
|
|
||||||
*
|
|
||||||
* @param p chain of pbufs over that a checksum should be calculated (ip data part)
|
|
||||||
* @param src source ip address (used for checksum of pseudo header)
|
|
||||||
* @param dst destination ip address (used for checksum of pseudo header)
|
|
||||||
* @param proto ip protocol (used for checksum of pseudo header)
|
|
||||||
* @param proto_len length of the ip data part (used for checksum of pseudo header)
|
|
||||||
* @return checksum (as u16_t) to be saved directly in the protocol header
|
|
||||||
*/
|
|
||||||
u16_t
|
|
||||||
inet_chksum_pseudo(struct pbuf *p,
|
|
||||||
struct ip_addr *src, struct ip_addr *dest,
|
|
||||||
u8_t proto, u16_t proto_len)
|
|
||||||
{
|
|
||||||
u32_t acc;
|
|
||||||
struct pbuf *q;
|
|
||||||
u8_t swapped;
|
|
||||||
|
|
||||||
acc = 0;
|
|
||||||
swapped = 0;
|
|
||||||
/* iterate through all pbuf in chain */
|
|
||||||
for(q = p; q != NULL; q = q->next) {
|
|
||||||
LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n",
|
|
||||||
(void *)q, (void *)q->next));
|
|
||||||
acc += LWIP_CHKSUM(q->payload, q->len);
|
|
||||||
/*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/
|
|
||||||
/* just executing this next line is probably faster that the if statement needed
|
|
||||||
to check whether we really need to execute it, and does no harm */
|
|
||||||
acc = FOLD_U32T(acc);
|
|
||||||
if (q->len % 2 != 0) {
|
|
||||||
swapped = 1 - swapped;
|
|
||||||
acc = SWAP_BYTES_IN_WORD(acc);
|
|
||||||
}
|
|
||||||
/*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/
|
|
||||||
}
|
|
||||||
|
|
||||||
if (swapped) {
|
|
||||||
acc = SWAP_BYTES_IN_WORD(acc);
|
|
||||||
}
|
|
||||||
acc += (src->addr & 0xffffUL);
|
|
||||||
acc += ((src->addr >> 16) & 0xffffUL);
|
|
||||||
acc += (dest->addr & 0xffffUL);
|
|
||||||
acc += ((dest->addr >> 16) & 0xffffUL);
|
|
||||||
acc += (u32_t)htons((u16_t)proto);
|
|
||||||
acc += (u32_t)htons(proto_len);
|
|
||||||
|
|
||||||
/* Fold 32-bit sum to 16 bits
|
|
||||||
calling this twice is propably faster than if statements... */
|
|
||||||
acc = FOLD_U32T(acc);
|
|
||||||
acc = FOLD_U32T(acc);
|
|
||||||
LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc));
|
|
||||||
return (u16_t)~(acc & 0xffffUL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* inet_chksum_pseudo:
|
|
||||||
*
|
|
||||||
* Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.
|
|
||||||
* IP addresses are expected to be in network byte order.
|
|
||||||
*
|
|
||||||
* @param p chain of pbufs over that a checksum should be calculated (ip data part)
|
|
||||||
* @param src source ip address (used for checksum of pseudo header)
|
|
||||||
* @param dst destination ip address (used for checksum of pseudo header)
|
|
||||||
* @param proto ip protocol (used for checksum of pseudo header)
|
|
||||||
* @param proto_len length of the ip data part (used for checksum of pseudo header)
|
|
||||||
* @return checksum (as u16_t) to be saved directly in the protocol header
|
|
||||||
*/
|
|
||||||
/* Currently only used by UDPLITE, although this could change in the future. */
|
|
||||||
#if LWIP_UDPLITE
|
|
||||||
u16_t
|
|
||||||
inet_chksum_pseudo_partial(struct pbuf *p,
|
|
||||||
struct ip_addr *src, struct ip_addr *dest,
|
|
||||||
u8_t proto, u16_t proto_len, u16_t chksum_len)
|
|
||||||
{
|
|
||||||
u32_t acc;
|
|
||||||
struct pbuf *q;
|
|
||||||
u8_t swapped;
|
|
||||||
u16_t chklen;
|
|
||||||
|
|
||||||
acc = 0;
|
|
||||||
swapped = 0;
|
|
||||||
/* iterate through all pbuf in chain */
|
|
||||||
for(q = p; (q != NULL) && (chksum_len > 0); q = q->next) {
|
|
||||||
LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n",
|
|
||||||
(void *)q, (void *)q->next));
|
|
||||||
chklen = q->len;
|
|
||||||
if (chklen > chksum_len) {
|
|
||||||
chklen = chksum_len;
|
|
||||||
}
|
|
||||||
acc += LWIP_CHKSUM(q->payload, chklen);
|
|
||||||
chksum_len -= chklen;
|
|
||||||
LWIP_ASSERT("delete me", chksum_len < 0x7fff);
|
|
||||||
/*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/
|
|
||||||
/* fold the upper bit down */
|
|
||||||
acc = FOLD_U32T(acc);
|
|
||||||
if (q->len % 2 != 0) {
|
|
||||||
swapped = 1 - swapped;
|
|
||||||
acc = SWAP_BYTES_IN_WORD(acc);
|
|
||||||
}
|
|
||||||
/*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/
|
|
||||||
}
|
|
||||||
|
|
||||||
if (swapped) {
|
|
||||||
acc = SWAP_BYTES_IN_WORD(acc);
|
|
||||||
}
|
|
||||||
acc += (src->addr & 0xffffUL);
|
|
||||||
acc += ((src->addr >> 16) & 0xffffUL);
|
|
||||||
acc += (dest->addr & 0xffffUL);
|
|
||||||
acc += ((dest->addr >> 16) & 0xffffUL);
|
|
||||||
acc += (u32_t)htons((u16_t)proto);
|
|
||||||
acc += (u32_t)htons(proto_len);
|
|
||||||
|
|
||||||
/* Fold 32-bit sum to 16 bits
|
|
||||||
calling this twice is propably faster than if statements... */
|
|
||||||
acc = FOLD_U32T(acc);
|
|
||||||
acc = FOLD_U32T(acc);
|
|
||||||
LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc));
|
|
||||||
return (u16_t)~(acc & 0xffffUL);
|
|
||||||
}
|
|
||||||
#endif /* LWIP_UDPLITE */
|
|
||||||
|
|
||||||
/* inet_chksum:
|
|
||||||
*
|
|
||||||
* Calculates the Internet checksum over a portion of memory. Used primarily for IP
|
|
||||||
* and ICMP.
|
|
||||||
*
|
|
||||||
* @param dataptr start of the buffer to calculate the checksum (no alignment needed)
|
|
||||||
* @param len length of the buffer to calculate the checksum
|
|
||||||
* @return checksum (as u16_t) to be saved directly in the protocol header
|
|
||||||
*/
|
|
||||||
|
|
||||||
u16_t
|
|
||||||
inet_chksum(void *dataptr, u16_t len)
|
|
||||||
{
|
|
||||||
return ~LWIP_CHKSUM(dataptr, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculate a checksum over a chain of pbufs (without pseudo-header, much like
|
|
||||||
* inet_chksum only pbufs are used).
|
|
||||||
*
|
|
||||||
* @param p pbuf chain over that the checksum should be calculated
|
|
||||||
* @return checksum (as u16_t) to be saved directly in the protocol header
|
|
||||||
*/
|
|
||||||
u16_t
|
|
||||||
inet_chksum_pbuf(struct pbuf *p)
|
|
||||||
{
|
|
||||||
u32_t acc;
|
|
||||||
struct pbuf *q;
|
|
||||||
u8_t swapped;
|
|
||||||
|
|
||||||
acc = 0;
|
|
||||||
swapped = 0;
|
|
||||||
for(q = p; q != NULL; q = q->next) {
|
|
||||||
acc += LWIP_CHKSUM(q->payload, q->len);
|
|
||||||
acc = FOLD_U32T(acc);
|
|
||||||
if (q->len % 2 != 0) {
|
|
||||||
swapped = 1 - swapped;
|
|
||||||
acc = SWAP_BYTES_IN_WORD(acc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (swapped) {
|
|
||||||
acc = SWAP_BYTES_IN_WORD(acc);
|
|
||||||
}
|
|
||||||
return (u16_t)~(acc & 0xffffUL);
|
|
||||||
}
|
|
|
@ -1,768 +0,0 @@
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
* This is the IPv4 layer implementation for incoming and outgoing IP traffic.
|
|
||||||
*
|
|
||||||
* @see ip_frag.c
|
|
||||||
*
|
|
||||||
**/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "lwip/opt.h"
|
|
||||||
#include "lwip/ip.h"
|
|
||||||
#include "lwip/def.h"
|
|
||||||
#include "lwip/mem.h"
|
|
||||||
#include "lwip/ip_frag.h"
|
|
||||||
#include "lwip/inet.h"
|
|
||||||
#include "lwip/inet_chksum.h"
|
|
||||||
#include "lwip/netif.h"
|
|
||||||
#include "lwip/icmp.h"
|
|
||||||
#include "lwip/igmp.h"
|
|
||||||
#include "lwip/raw.h"
|
|
||||||
#include "lwip/udp.h"
|
|
||||||
#include "lwip/tcp.h"
|
|
||||||
#include "lwip/snmp.h"
|
|
||||||
#include "lwip/dhcp.h"
|
|
||||||
#include "lwip/stats.h"
|
|
||||||
#include "arch/perf.h"
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The interface that provided the packet for the current callback
|
|
||||||
* invocation.
|
|
||||||
*/
|
|
||||||
struct netif *current_netif;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Header of the input packet currently being processed.
|
|
||||||
*/
|
|
||||||
const struct ip_hdr *current_header;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Finds the appropriate network interface for a given IP address. It
|
|
||||||
* searches the list of network interfaces linearly. A match is found
|
|
||||||
* if the masked IP address of the network interface equals the masked
|
|
||||||
* IP address given to the function.
|
|
||||||
*
|
|
||||||
* @param dest the destination IP address for which to find the route
|
|
||||||
* @return the netif on which to send to reach dest
|
|
||||||
*/
|
|
||||||
struct netif *
|
|
||||||
ip_route(struct ip_addr *dest)
|
|
||||||
{
|
|
||||||
struct netif *netif;
|
|
||||||
|
|
||||||
/* iterate through netifs */
|
|
||||||
for(netif = netif_list; netif != NULL; netif = netif->next) {
|
|
||||||
/* network mask matches? */
|
|
||||||
if (netif_is_up(netif)) {
|
|
||||||
if (ip_addr_netcmp(dest, &(netif->ip_addr), &(netif->netmask))) {
|
|
||||||
/* return netif on which to forward IP packet */
|
|
||||||
return netif;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((netif_default == NULL) || (!netif_is_up(netif_default))) {
|
|
||||||
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_route: No route to 0x%"X32_F"\n", dest->addr));
|
|
||||||
IP_STATS_INC(ip.rterr);
|
|
||||||
snmp_inc_ipoutnoroutes();
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
/* no matching netif found, use default netif */
|
|
||||||
return netif_default;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if IP_FORWARD
|
|
||||||
/**
|
|
||||||
* Forwards an IP packet. It finds an appropriate route for the
|
|
||||||
* packet, decrements the TTL value of the packet, adjusts the
|
|
||||||
* checksum and outputs the packet on the appropriate interface.
|
|
||||||
*
|
|
||||||
* @param p the packet to forward (p->payload points to IP header)
|
|
||||||
* @param iphdr the IP header of the input packet
|
|
||||||
* @param inp the netif on which this packet was received
|
|
||||||
* @return the netif on which the packet was sent (NULL if it wasn't sent)
|
|
||||||
*/
|
|
||||||
static struct netif *
|
|
||||||
ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp)
|
|
||||||
{
|
|
||||||
struct netif *netif;
|
|
||||||
|
|
||||||
PERF_START;
|
|
||||||
/* Find network interface where to forward this IP packet to. */
|
|
||||||
netif = ip_route((struct ip_addr *)&(iphdr->dest));
|
|
||||||
if (netif == NULL) {
|
|
||||||
LWIP_DEBUGF(IP_DEBUG, ("ip_forward: no forwarding route for 0x%"X32_F" found\n",
|
|
||||||
iphdr->dest.addr));
|
|
||||||
snmp_inc_ipoutnoroutes();
|
|
||||||
return (struct netif *)NULL;
|
|
||||||
}
|
|
||||||
/* Do not forward packets onto the same network interface on which
|
|
||||||
* they arrived. */
|
|
||||||
/* Realtek Modified Start */
|
|
||||||
#ifdef CONFIG_DONT_CARE_TP
|
|
||||||
if(netif->flags & NETIF_FLAG_IPSWITCH == 0) {
|
|
||||||
if (netif == inp) {
|
|
||||||
LWIP_DEBUGF(IP_DEBUG, ("ip_forward: not bouncing packets back on incoming interface.\n"));
|
|
||||||
snmp_inc_ipoutnoroutes();
|
|
||||||
return (struct netif *)NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
/* Realtek Modified End */
|
|
||||||
|
|
||||||
/* decrement TTL */
|
|
||||||
IPH_TTL_SET(iphdr, IPH_TTL(iphdr) - 1);
|
|
||||||
/* send ICMP if TTL == 0 */
|
|
||||||
if (IPH_TTL(iphdr) == 0) {
|
|
||||||
snmp_inc_ipinhdrerrors();
|
|
||||||
#if LWIP_ICMP
|
|
||||||
/* Don't send ICMP messages in response to ICMP messages */
|
|
||||||
if (IPH_PROTO(iphdr) != IP_PROTO_ICMP) {
|
|
||||||
icmp_time_exceeded(p, ICMP_TE_TTL);
|
|
||||||
}
|
|
||||||
#endif /* LWIP_ICMP */
|
|
||||||
return (struct netif *)NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Incrementally update the IP checksum. */
|
|
||||||
if (IPH_CHKSUM(iphdr) >= htons(0xffff - 0x100)) {
|
|
||||||
IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + htons(0x100) + 1);
|
|
||||||
} else {
|
|
||||||
IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + htons(0x100));
|
|
||||||
}
|
|
||||||
|
|
||||||
LWIP_DEBUGF(IP_DEBUG, ("ip_forward: forwarding packet to 0x%"X32_F"\n",
|
|
||||||
iphdr->dest.addr));
|
|
||||||
|
|
||||||
IP_STATS_INC(ip.fw);
|
|
||||||
IP_STATS_INC(ip.xmit);
|
|
||||||
snmp_inc_ipforwdatagrams();
|
|
||||||
|
|
||||||
PERF_STOP("ip_forward");
|
|
||||||
/* Realtek Modified Start */
|
|
||||||
#ifdef CONFIG_DONT_CARE_TP
|
|
||||||
#if IP_FRAG
|
|
||||||
/* don't fragment if interface has mtu set to 0 [loopif] */
|
|
||||||
if ((netif->flags & NETIF_FLAG_IPSWITCH) && netif->mtu && (p->tot_len > netif->mtu)) {
|
|
||||||
ip_frag(p,netif,(struct ip_addr *)&(iphdr->dest));
|
|
||||||
return netif;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
/* Realtek Modified End */
|
|
||||||
/* transmit pbuf on chosen interface */
|
|
||||||
netif->output(netif, p, (struct ip_addr *)&(iphdr->dest));
|
|
||||||
return netif;
|
|
||||||
}
|
|
||||||
#endif /* IP_FORWARD */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This function is called by the network interface device driver when
|
|
||||||
* an IP packet is received. The function does the basic checks of the
|
|
||||||
* IP header such as packet size being at least larger than the header
|
|
||||||
* size etc. If the packet was not destined for us, the packet is
|
|
||||||
* forwarded (using ip_forward). The IP checksum is always checked.
|
|
||||||
*
|
|
||||||
* Finally, the packet is sent to the upper layer protocol input function.
|
|
||||||
*
|
|
||||||
* @param p the received IP packet (p->payload points to IP header)
|
|
||||||
* @param inp the netif on which this packet was received
|
|
||||||
* @return ERR_OK if the packet was processed (could return ERR_* if it wasn't
|
|
||||||
* processed, but currently always returns ERR_OK)
|
|
||||||
*/
|
|
||||||
err_t
|
|
||||||
ip_input(struct pbuf *p, struct netif *inp)
|
|
||||||
{
|
|
||||||
struct ip_hdr *iphdr;
|
|
||||||
struct netif *netif;
|
|
||||||
u16_t iphdr_hlen;
|
|
||||||
u16_t iphdr_len;
|
|
||||||
#if LWIP_DHCP || LWIP_UPNP
|
|
||||||
int check_ip_src=1;
|
|
||||||
#endif /* LWIP_DHCP || LWIP_UPNP */
|
|
||||||
|
|
||||||
IP_STATS_INC(ip.recv);
|
|
||||||
snmp_inc_ipinreceives();
|
|
||||||
|
|
||||||
/* identify the IP header */
|
|
||||||
iphdr = p->payload;
|
|
||||||
if (IPH_V(iphdr) != 4) {
|
|
||||||
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_WARNING, ("IP packet dropped due to bad version number %"U16_F"\n", IPH_V(iphdr)));
|
|
||||||
ip_debug_print(p);
|
|
||||||
pbuf_free(p);
|
|
||||||
IP_STATS_INC(ip.err);
|
|
||||||
IP_STATS_INC(ip.drop);
|
|
||||||
snmp_inc_ipinhdrerrors();
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* obtain IP header length in number of 32-bit words */
|
|
||||||
iphdr_hlen = IPH_HL(iphdr);
|
|
||||||
/* calculate IP header length in bytes */
|
|
||||||
iphdr_hlen *= 4;
|
|
||||||
/* obtain ip length in bytes */
|
|
||||||
iphdr_len = ntohs(IPH_LEN(iphdr));
|
|
||||||
|
|
||||||
/* header length exceeds first pbuf length, or ip length exceeds total pbuf length? */
|
|
||||||
if ((iphdr_hlen > p->len) || (iphdr_len > p->tot_len)) {
|
|
||||||
if (iphdr_hlen > p->len) {
|
|
||||||
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
|
|
||||||
("IP header (len %"U16_F") does not fit in first pbuf (len %"U16_F"), IP packet dropped.\n",
|
|
||||||
iphdr_hlen, p->len));
|
|
||||||
}
|
|
||||||
if (iphdr_len > p->tot_len) {
|
|
||||||
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
|
|
||||||
("IP (len %"U16_F") is longer than pbuf (len %"U16_F"), IP packet dropped.\n",
|
|
||||||
iphdr_len, p->tot_len));
|
|
||||||
}
|
|
||||||
/* free (drop) packet pbufs */
|
|
||||||
pbuf_free(p);
|
|
||||||
IP_STATS_INC(ip.lenerr);
|
|
||||||
IP_STATS_INC(ip.drop);
|
|
||||||
snmp_inc_ipindiscards();
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* verify checksum */
|
|
||||||
#if CHECKSUM_CHECK_IP
|
|
||||||
if (inet_chksum(iphdr, iphdr_hlen) != 0) {
|
|
||||||
|
|
||||||
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
|
|
||||||
("Checksum (0x%"X16_F") failed, IP packet dropped.\n", inet_chksum(iphdr, iphdr_hlen)));
|
|
||||||
ip_debug_print(p);
|
|
||||||
pbuf_free(p);
|
|
||||||
IP_STATS_INC(ip.chkerr);
|
|
||||||
IP_STATS_INC(ip.drop);
|
|
||||||
snmp_inc_ipinhdrerrors();
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Trim pbuf. This should have been done at the netif layer,
|
|
||||||
* but we'll do it anyway just to be sure that its done. */
|
|
||||||
pbuf_realloc(p, iphdr_len);
|
|
||||||
|
|
||||||
/* match packet against an interface, i.e. is this packet for us? */
|
|
||||||
#if LWIP_IGMP
|
|
||||||
if (ip_addr_ismulticast(&(iphdr->dest))) {
|
|
||||||
if ((inp->flags & NETIF_FLAG_IGMP) && (igmp_lookfor_group(inp, &(iphdr->dest)))) {
|
|
||||||
netif = inp;
|
|
||||||
} else {
|
|
||||||
netif = NULL;
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
#endif /* LWIP_IGMP */
|
|
||||||
{
|
|
||||||
/* start trying with inp. if that's not acceptable, start walking the
|
|
||||||
list of configured netifs.
|
|
||||||
'first' is used as a boolean to mark whether we started walking the list */
|
|
||||||
int first = 1;
|
|
||||||
netif = inp;
|
|
||||||
do {
|
|
||||||
LWIP_DEBUGF(IP_DEBUG, ("ip_input: iphdr->dest 0x%"X32_F" netif->ip_addr 0x%"X32_F" (0x%"X32_F", 0x%"X32_F", 0x%"X32_F")\n",
|
|
||||||
iphdr->dest.addr, netif->ip_addr.addr,
|
|
||||||
iphdr->dest.addr & netif->netmask.addr,
|
|
||||||
netif->ip_addr.addr & netif->netmask.addr,
|
|
||||||
iphdr->dest.addr & ~(netif->netmask.addr)));
|
|
||||||
|
|
||||||
/* interface is up and configured? */
|
|
||||||
if ((netif_is_up(netif)) && (!ip_addr_isany(&(netif->ip_addr)))) {
|
|
||||||
/* unicast to this interface address? */
|
|
||||||
if (ip_addr_cmp(&(iphdr->dest), &(netif->ip_addr)) ||
|
|
||||||
/* or broadcast on this interface network address? */
|
|
||||||
ip_addr_isbroadcast(&(iphdr->dest), netif)) {
|
|
||||||
LWIP_DEBUGF(IP_DEBUG, ("ip_input: packet accepted on interface %c%c\n",
|
|
||||||
netif->name[0], netif->name[1]));
|
|
||||||
/* break out of for loop */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (first) {
|
|
||||||
first = 0;
|
|
||||||
netif = netif_list;
|
|
||||||
} else {
|
|
||||||
netif = netif->next;
|
|
||||||
}
|
|
||||||
if (netif == inp) {
|
|
||||||
netif = netif->next;
|
|
||||||
}
|
|
||||||
} while(netif != NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if LWIP_DHCP
|
|
||||||
/* Pass DHCP messages regardless of destination address. DHCP traffic is addressed
|
|
||||||
* using link layer addressing (such as Ethernet MAC) so we must not filter on IP.
|
|
||||||
* According to RFC 1542 section 3.1.1, referred by RFC 2131).
|
|
||||||
*/
|
|
||||||
if (netif == NULL) {
|
|
||||||
/* remote port is DHCP server? */
|
|
||||||
if (IPH_PROTO(iphdr) == IP_PROTO_UDP) {
|
|
||||||
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: UDP packet to DHCP client port %"U16_F"\n",
|
|
||||||
ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen))->dest)));
|
|
||||||
if (ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen))->dest) == DHCP_CLIENT_PORT) {
|
|
||||||
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: DHCP packet accepted.\n"));
|
|
||||||
netif = inp;
|
|
||||||
check_ip_src = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif /* LWIP_DHCP */
|
|
||||||
|
|
||||||
/* This part of code has been modified by ST's MCD Application Team */
|
|
||||||
/* To use the UPnP responder for device discovery */
|
|
||||||
#if LWIP_UPNP
|
|
||||||
/* Pass UPNP messages regardless of destination address. UPNP traffic is addressed
|
|
||||||
* using multicast addressing so we must not filter on IP.
|
|
||||||
*/
|
|
||||||
if (netif == NULL) {
|
|
||||||
/* remote port is DHCP server? */
|
|
||||||
if (IPH_PROTO(iphdr) == IP_PROTO_UDP) {
|
|
||||||
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | 1, ("ip_input: UDP packet to UPNP client port %"U16_F"\n",
|
|
||||||
ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen))->dest)));
|
|
||||||
if (ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen))->dest) == 1900) {
|
|
||||||
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | 1, ("ip_input: UPNP packet accepted.\n"));
|
|
||||||
netif = inp;
|
|
||||||
check_ip_src = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif /* LWIP_UPNP */
|
|
||||||
|
|
||||||
/* broadcast or multicast packet source address? Compliant with RFC 1122: 3.2.1.3 */
|
|
||||||
#if LWIP_DHCP || LWIP_UPNP
|
|
||||||
/* DHCP servers need 0.0.0.0 to be allowed as source address (RFC 1.1.2.2: 3.2.1.3/a) */
|
|
||||||
if (check_ip_src && (iphdr->src.addr != 0))
|
|
||||||
#endif /* LWIP_DHCP || LWIP_UPNP */
|
|
||||||
{ if ((ip_addr_isbroadcast(&(iphdr->src), inp)) ||
|
|
||||||
(ip_addr_ismulticast(&(iphdr->src)))) {
|
|
||||||
/* packet source is not valid */
|
|
||||||
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("ip_input: packet source is not valid.\n"));
|
|
||||||
/* free (drop) packet pbufs */
|
|
||||||
pbuf_free(p);
|
|
||||||
IP_STATS_INC(ip.drop);
|
|
||||||
snmp_inc_ipinaddrerrors();
|
|
||||||
snmp_inc_ipindiscards();
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* packet not for us? */
|
|
||||||
if (netif == NULL) {
|
|
||||||
/* packet not for us, route or discard */
|
|
||||||
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: packet not for us.\n"));
|
|
||||||
#if IP_FORWARD
|
|
||||||
/* Realtek Modified Start */
|
|
||||||
#ifdef CONFIG_DONT_CARE_TP
|
|
||||||
if(inp->flags & NETIF_FLAG_IPSWITCH)
|
|
||||||
#else
|
|
||||||
/* Realtek Modified End */
|
|
||||||
if (!ip_addr_isbroadcast(&(iphdr->dest), inp))
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
/* try to forward IP packet on (other) interfaces */
|
|
||||||
ip_forward(p, iphdr, inp);
|
|
||||||
}
|
|
||||||
/* non-broadcast packet? */
|
|
||||||
else
|
|
||||||
#endif /* IP_FORWARD */
|
|
||||||
{
|
|
||||||
snmp_inc_ipinaddrerrors();
|
|
||||||
snmp_inc_ipindiscards();
|
|
||||||
}
|
|
||||||
pbuf_free(p);
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
|
||||||
/* packet consists of multiple fragments? */
|
|
||||||
if ((IPH_OFFSET(iphdr) & htons(IP_OFFMASK | IP_MF)) != 0) {
|
|
||||||
#if IP_REASSEMBLY /* packet fragment reassembly code present? */
|
|
||||||
LWIP_DEBUGF(IP_DEBUG, ("IP packet is a fragment (id=0x%04"X16_F" tot_len=%"U16_F" len=%"U16_F" MF=%"U16_F" offset=%"U16_F"), calling ip_reass()\n",
|
|
||||||
ntohs(IPH_ID(iphdr)), p->tot_len, ntohs(IPH_LEN(iphdr)), !!(IPH_OFFSET(iphdr) & htons(IP_MF)), (ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)*8));
|
|
||||||
/* reassemble the packet*/
|
|
||||||
p = ip_reass(p);
|
|
||||||
/* packet not fully reassembled yet? */
|
|
||||||
if (p == NULL) {
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
|
||||||
iphdr = p->payload;
|
|
||||||
#else /* IP_REASSEMBLY == 0, no packet fragment reassembly code present */
|
|
||||||
pbuf_free(p);
|
|
||||||
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP packet dropped since it was fragmented (0x%"X16_F") (while IP_REASSEMBLY == 0).\n",
|
|
||||||
ntohs(IPH_OFFSET(iphdr))));
|
|
||||||
IP_STATS_INC(ip.opterr);
|
|
||||||
IP_STATS_INC(ip.drop);
|
|
||||||
/* unsupported protocol feature */
|
|
||||||
snmp_inc_ipinunknownprotos();
|
|
||||||
return ERR_OK;
|
|
||||||
#endif /* IP_REASSEMBLY */
|
|
||||||
}
|
|
||||||
|
|
||||||
#if IP_OPTIONS_ALLOWED == 0 /* no support for IP options in the IP header? */
|
|
||||||
|
|
||||||
#if LWIP_IGMP
|
|
||||||
/* there is an extra "router alert" option in IGMP messages which we allow for but do not police */
|
|
||||||
if((iphdr_hlen > IP_HLEN && (IPH_PROTO(iphdr) != IP_PROTO_IGMP)) {
|
|
||||||
#else
|
|
||||||
if (iphdr_hlen > IP_HLEN) {
|
|
||||||
#endif /* LWIP_IGMP */
|
|
||||||
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP packet dropped since there were IP options (while IP_OPTIONS_ALLOWED == 0).\n"));
|
|
||||||
pbuf_free(p);
|
|
||||||
IP_STATS_INC(ip.opterr);
|
|
||||||
IP_STATS_INC(ip.drop);
|
|
||||||
/* unsupported protocol feature */
|
|
||||||
snmp_inc_ipinunknownprotos();
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
|
||||||
#endif /* IP_OPTIONS_ALLOWED == 0 */
|
|
||||||
|
|
||||||
/* send to upper layers */
|
|
||||||
LWIP_DEBUGF(IP_DEBUG, ("ip_input: \n"));
|
|
||||||
ip_debug_print(p);
|
|
||||||
LWIP_DEBUGF(IP_DEBUG, ("ip_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len));
|
|
||||||
|
|
||||||
current_netif = inp;
|
|
||||||
current_header = iphdr;
|
|
||||||
|
|
||||||
#if LWIP_RAW
|
|
||||||
/* raw input did not eat the packet? */
|
|
||||||
if (raw_input(p, inp) == 0)
|
|
||||||
#endif /* LWIP_RAW */
|
|
||||||
{
|
|
||||||
|
|
||||||
switch (IPH_PROTO(iphdr)) {
|
|
||||||
#if LWIP_UDP
|
|
||||||
case IP_PROTO_UDP:
|
|
||||||
#if LWIP_UDPLITE
|
|
||||||
case IP_PROTO_UDPLITE:
|
|
||||||
#endif /* LWIP_UDPLITE */
|
|
||||||
snmp_inc_ipindelivers();
|
|
||||||
udp_input(p, inp);
|
|
||||||
break;
|
|
||||||
#endif /* LWIP_UDP */
|
|
||||||
#if LWIP_TCP
|
|
||||||
case IP_PROTO_TCP:
|
|
||||||
snmp_inc_ipindelivers();
|
|
||||||
tcp_input(p, inp);
|
|
||||||
break;
|
|
||||||
#endif /* LWIP_TCP */
|
|
||||||
#if LWIP_ICMP
|
|
||||||
case IP_PROTO_ICMP:
|
|
||||||
snmp_inc_ipindelivers();
|
|
||||||
icmp_input(p, inp);
|
|
||||||
break;
|
|
||||||
#endif /* LWIP_ICMP */
|
|
||||||
#if LWIP_IGMP
|
|
||||||
case IP_PROTO_IGMP:
|
|
||||||
igmp_input(p,inp,&(iphdr->dest));
|
|
||||||
break;
|
|
||||||
#endif /* LWIP_IGMP */
|
|
||||||
default:
|
|
||||||
#if LWIP_ICMP
|
|
||||||
/* send ICMP destination protocol unreachable unless is was a broadcast */
|
|
||||||
if (!ip_addr_isbroadcast(&(iphdr->dest), inp) &&
|
|
||||||
!ip_addr_ismulticast(&(iphdr->dest))) {
|
|
||||||
p->payload = iphdr;
|
|
||||||
icmp_dest_unreach(p, ICMP_DUR_PROTO);
|
|
||||||
}
|
|
||||||
#endif /* LWIP_ICMP */
|
|
||||||
pbuf_free(p);
|
|
||||||
|
|
||||||
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("Unsupported transport protocol %"U16_F"\n", IPH_PROTO(iphdr)));
|
|
||||||
|
|
||||||
IP_STATS_INC(ip.proterr);
|
|
||||||
IP_STATS_INC(ip.drop);
|
|
||||||
snmp_inc_ipinunknownprotos();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
current_netif = NULL;
|
|
||||||
current_header = NULL;
|
|
||||||
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends an IP packet on a network interface. This function constructs
|
|
||||||
* the IP header and calculates the IP header checksum. If the source
|
|
||||||
* IP address is NULL, the IP address of the outgoing network
|
|
||||||
* interface is filled in as source address.
|
|
||||||
* If the destination IP address is IP_HDRINCL, p is assumed to already
|
|
||||||
* include an IP header and p->payload points to it instead of the data.
|
|
||||||
*
|
|
||||||
* @param p the packet to send (p->payload points to the data, e.g. next
|
|
||||||
protocol header; if dest == IP_HDRINCL, p already includes an IP
|
|
||||||
header and p->payload points to that IP header)
|
|
||||||
* @param src the source IP address to send from (if src == IP_ADDR_ANY, the
|
|
||||||
* IP address of the netif used to send is used as source address)
|
|
||||||
* @param dest the destination IP address to send the packet to
|
|
||||||
* @param ttl the TTL value to be set in the IP header
|
|
||||||
* @param tos the TOS value to be set in the IP header
|
|
||||||
* @param proto the PROTOCOL to be set in the IP header
|
|
||||||
* @param netif the netif on which to send this packet
|
|
||||||
* @return ERR_OK if the packet was sent OK
|
|
||||||
* ERR_BUF if p doesn't have enough space for IP/LINK headers
|
|
||||||
* returns errors returned by netif->output
|
|
||||||
*
|
|
||||||
* @note ip_id: RFC791 "some host may be able to simply use
|
|
||||||
* unique identifiers independent of destination"
|
|
||||||
*/
|
|
||||||
err_t
|
|
||||||
ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
|
|
||||||
u8_t ttl, u8_t tos,
|
|
||||||
u8_t proto, struct netif *netif)
|
|
||||||
{
|
|
||||||
#if IP_OPTIONS_SEND
|
|
||||||
return ip_output_if_opt(p, src, dest, ttl, tos, proto, netif, NULL, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Same as ip_output_if() but with the possibility to include IP options:
|
|
||||||
*
|
|
||||||
* @ param ip_options pointer to the IP options, copied into the IP header
|
|
||||||
* @ param optlen length of ip_options
|
|
||||||
*/
|
|
||||||
err_t ip_output_if_opt(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
|
|
||||||
u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options,
|
|
||||||
u16_t optlen)
|
|
||||||
{
|
|
||||||
#endif /* IP_OPTIONS_SEND */
|
|
||||||
struct ip_hdr *iphdr;
|
|
||||||
static u16_t ip_id = 0;
|
|
||||||
|
|
||||||
snmp_inc_ipoutrequests();
|
|
||||||
|
|
||||||
/* Should the IP header be generated or is it already included in p? */
|
|
||||||
if (dest != IP_HDRINCL) {
|
|
||||||
u16_t ip_hlen = IP_HLEN;
|
|
||||||
#if IP_OPTIONS_SEND
|
|
||||||
u16_t optlen_aligned = 0;
|
|
||||||
if (optlen != 0) {
|
|
||||||
/* round up to a multiple of 4 */
|
|
||||||
optlen_aligned = ((optlen + 3) & ~3);
|
|
||||||
ip_hlen += optlen_aligned;
|
|
||||||
/* First write in the IP options */
|
|
||||||
if (pbuf_header(p, optlen_aligned)) {
|
|
||||||
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_output_if_opt: not enough room for IP options in pbuf\n"));
|
|
||||||
IP_STATS_INC(ip.err);
|
|
||||||
snmp_inc_ipoutdiscards();
|
|
||||||
return ERR_BUF;
|
|
||||||
}
|
|
||||||
MEMCPY(p->payload, ip_options, optlen);
|
|
||||||
if (optlen < optlen_aligned) {
|
|
||||||
/* zero the remaining bytes */
|
|
||||||
memset(((char*)p->payload) + optlen, 0, optlen_aligned - optlen);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif /* IP_OPTIONS_SEND */
|
|
||||||
/* generate IP header */
|
|
||||||
if (pbuf_header(p, IP_HLEN)) {
|
|
||||||
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_output: not enough room for IP header in pbuf\n"));
|
|
||||||
|
|
||||||
IP_STATS_INC(ip.err);
|
|
||||||
snmp_inc_ipoutdiscards();
|
|
||||||
return ERR_BUF;
|
|
||||||
}
|
|
||||||
|
|
||||||
iphdr = p->payload;
|
|
||||||
LWIP_ASSERT("check that first pbuf can hold struct ip_hdr",
|
|
||||||
(p->len >= sizeof(struct ip_hdr)));
|
|
||||||
|
|
||||||
IPH_TTL_SET(iphdr, ttl);
|
|
||||||
IPH_PROTO_SET(iphdr, proto);
|
|
||||||
|
|
||||||
ip_addr_set(&(iphdr->dest), dest);
|
|
||||||
|
|
||||||
IPH_VHLTOS_SET(iphdr, 4, ip_hlen / 4, tos);
|
|
||||||
IPH_LEN_SET(iphdr, htons(p->tot_len));
|
|
||||||
IPH_OFFSET_SET(iphdr, 0);
|
|
||||||
IPH_ID_SET(iphdr, htons(ip_id));
|
|
||||||
++ip_id;
|
|
||||||
|
|
||||||
if (ip_addr_isany(src)) {
|
|
||||||
ip_addr_set(&(iphdr->src), &(netif->ip_addr));
|
|
||||||
} else {
|
|
||||||
ip_addr_set(&(iphdr->src), src);
|
|
||||||
}
|
|
||||||
|
|
||||||
IPH_CHKSUM_SET(iphdr, 0);
|
|
||||||
#if CHECKSUM_GEN_IP
|
|
||||||
IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, ip_hlen));
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
/* IP header already included in p */
|
|
||||||
iphdr = p->payload;
|
|
||||||
dest = &(iphdr->dest);
|
|
||||||
}
|
|
||||||
|
|
||||||
IP_STATS_INC(ip.xmit);
|
|
||||||
|
|
||||||
LWIP_DEBUGF(IP_DEBUG, ("ip_output_if: %c%c%"U16_F"\n", netif->name[0], netif->name[1], netif->num));
|
|
||||||
ip_debug_print(p);
|
|
||||||
|
|
||||||
#if ENABLE_LOOPBACK
|
|
||||||
if (ip_addr_cmp(dest, &netif->ip_addr)) {
|
|
||||||
/* Packet to self, enqueue it for loopback */
|
|
||||||
LWIP_DEBUGF(IP_DEBUG, ("netif_loop_output()"));
|
|
||||||
return netif_loop_output(netif, p, dest);
|
|
||||||
}
|
|
||||||
#endif /* ENABLE_LOOPBACK */
|
|
||||||
#if IP_FRAG
|
|
||||||
/* don't fragment if interface has mtu set to 0 [loopif] */
|
|
||||||
if (netif->mtu && (p->tot_len > netif->mtu)) {
|
|
||||||
return ip_frag(p,netif,dest);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
LWIP_DEBUGF(IP_DEBUG, ("netif->output()"));
|
|
||||||
return netif->output(netif, p, dest);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Simple interface to ip_output_if. It finds the outgoing network
|
|
||||||
* interface and calls upon ip_output_if to do the actual work.
|
|
||||||
*
|
|
||||||
* @param p the packet to send (p->payload points to the data, e.g. next
|
|
||||||
protocol header; if dest == IP_HDRINCL, p already includes an IP
|
|
||||||
header and p->payload points to that IP header)
|
|
||||||
* @param src the source IP address to send from (if src == IP_ADDR_ANY, the
|
|
||||||
* IP address of the netif used to send is used as source address)
|
|
||||||
* @param dest the destination IP address to send the packet to
|
|
||||||
* @param ttl the TTL value to be set in the IP header
|
|
||||||
* @param tos the TOS value to be set in the IP header
|
|
||||||
* @param proto the PROTOCOL to be set in the IP header
|
|
||||||
*
|
|
||||||
* @return ERR_RTE if no route is found
|
|
||||||
* see ip_output_if() for more return values
|
|
||||||
*/
|
|
||||||
err_t
|
|
||||||
ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
|
|
||||||
u8_t ttl, u8_t tos, u8_t proto)
|
|
||||||
{
|
|
||||||
struct netif *netif;
|
|
||||||
|
|
||||||
if ((netif = ip_route(dest)) == NULL) {
|
|
||||||
LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to 0x%"X32_F"\n", dest->addr));
|
|
||||||
IP_STATS_INC(ip.rterr);
|
|
||||||
return ERR_RTE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ip_output_if(p, src, dest, ttl, tos, proto, netif);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if LWIP_NETIF_HWADDRHINT
|
|
||||||
/** Like ip_output, but takes and addr_hint pointer that is passed on to netif->addr_hint
|
|
||||||
* before calling ip_output_if.
|
|
||||||
*
|
|
||||||
* @param p the packet to send (p->payload points to the data, e.g. next
|
|
||||||
protocol header; if dest == IP_HDRINCL, p already includes an IP
|
|
||||||
header and p->payload points to that IP header)
|
|
||||||
* @param src the source IP address to send from (if src == IP_ADDR_ANY, the
|
|
||||||
* IP address of the netif used to send is used as source address)
|
|
||||||
* @param dest the destination IP address to send the packet to
|
|
||||||
* @param ttl the TTL value to be set in the IP header
|
|
||||||
* @param tos the TOS value to be set in the IP header
|
|
||||||
* @param proto the PROTOCOL to be set in the IP header
|
|
||||||
* @param addr_hint address hint pointer set to netif->addr_hint before
|
|
||||||
* calling ip_output_if()
|
|
||||||
*
|
|
||||||
* @return ERR_RTE if no route is found
|
|
||||||
* see ip_output_if() for more return values
|
|
||||||
*/
|
|
||||||
err_t
|
|
||||||
ip_output_hinted(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
|
|
||||||
u8_t ttl, u8_t tos, u8_t proto, u8_t *addr_hint)
|
|
||||||
{
|
|
||||||
struct netif *netif;
|
|
||||||
err_t err;
|
|
||||||
|
|
||||||
if ((netif = ip_route(dest)) == NULL) {
|
|
||||||
LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to 0x%"X32_F"\n", dest->addr));
|
|
||||||
IP_STATS_INC(ip.rterr);
|
|
||||||
return ERR_RTE;
|
|
||||||
}
|
|
||||||
|
|
||||||
netif->addr_hint = addr_hint;
|
|
||||||
err = ip_output_if(p, src, dest, ttl, tos, proto, netif);
|
|
||||||
netif->addr_hint = NULL;
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
#endif /* LWIP_NETIF_HWADDRHINT*/
|
|
||||||
|
|
||||||
#if IP_DEBUG
|
|
||||||
/* Print an IP header by using LWIP_DEBUGF
|
|
||||||
* @param p an IP packet, p->payload pointing to the IP header
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
ip_debug_print(struct pbuf *p)
|
|
||||||
{
|
|
||||||
struct ip_hdr *iphdr = p->payload;
|
|
||||||
u8_t *payload;
|
|
||||||
|
|
||||||
payload = (u8_t *)iphdr + IP_HLEN;
|
|
||||||
|
|
||||||
LWIP_DEBUGF(IP_DEBUG, ("IP header:\n"));
|
|
||||||
LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
|
|
||||||
LWIP_DEBUGF(IP_DEBUG, ("|%2"S16_F" |%2"S16_F" | 0x%02"X16_F" | %5"U16_F" | (v, hl, tos, len)\n",
|
|
||||||
IPH_V(iphdr),
|
|
||||||
IPH_HL(iphdr),
|
|
||||||
IPH_TOS(iphdr),
|
|
||||||
ntohs(IPH_LEN(iphdr))));
|
|
||||||
LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
|
|
||||||
LWIP_DEBUGF(IP_DEBUG, ("| %5"U16_F" |%"U16_F"%"U16_F"%"U16_F"| %4"U16_F" | (id, flags, offset)\n",
|
|
||||||
ntohs(IPH_ID(iphdr)),
|
|
||||||
ntohs(IPH_OFFSET(iphdr)) >> 15 & 1,
|
|
||||||
ntohs(IPH_OFFSET(iphdr)) >> 14 & 1,
|
|
||||||
ntohs(IPH_OFFSET(iphdr)) >> 13 & 1,
|
|
||||||
ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK));
|
|
||||||
LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
|
|
||||||
LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | 0x%04"X16_F" | (ttl, proto, chksum)\n",
|
|
||||||
IPH_TTL(iphdr),
|
|
||||||
IPH_PROTO(iphdr),
|
|
||||||
ntohs(IPH_CHKSUM(iphdr))));
|
|
||||||
LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
|
|
||||||
LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | %3"U16_F" | %3"U16_F" | (src)\n",
|
|
||||||
ip4_addr1(&iphdr->src),
|
|
||||||
ip4_addr2(&iphdr->src),
|
|
||||||
ip4_addr3(&iphdr->src),
|
|
||||||
ip4_addr4(&iphdr->src)));
|
|
||||||
LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
|
|
||||||
LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | %3"U16_F" | %3"U16_F" | (dest)\n",
|
|
||||||
ip4_addr1(&iphdr->dest),
|
|
||||||
ip4_addr2(&iphdr->dest),
|
|
||||||
ip4_addr3(&iphdr->dest),
|
|
||||||
ip4_addr4(&iphdr->dest)));
|
|
||||||
LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));
|
|
||||||
}
|
|
||||||
#endif /* IP_DEBUG */
|
|
|
@ -1,84 +0,0 @@
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
* This is the IPv4 address tools implementation.
|
|
||||||
*
|
|
||||||
**/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "lwip/opt.h"
|
|
||||||
#include "lwip/ip_addr.h"
|
|
||||||
#include "lwip/inet.h"
|
|
||||||
#include "lwip/netif.h"
|
|
||||||
|
|
||||||
#define IP_ADDR_ANY_VALUE 0x00000000UL
|
|
||||||
#define IP_ADDR_BROADCAST_VALUE 0xffffffffUL
|
|
||||||
|
|
||||||
/* used by IP_ADDR_ANY and IP_ADDR_BROADCAST in ip_addr.h */
|
|
||||||
const struct ip_addr ip_addr_any = { IP_ADDR_ANY_VALUE };
|
|
||||||
const struct ip_addr ip_addr_broadcast = { IP_ADDR_BROADCAST_VALUE };
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine if an address is a broadcast address on a network interface
|
|
||||||
*
|
|
||||||
* @param addr address to be checked
|
|
||||||
* @param netif the network interface against which the address is checked
|
|
||||||
* @return returns non-zero if the address is a broadcast address
|
|
||||||
*/
|
|
||||||
u8_t ip_addr_isbroadcast(struct ip_addr *addr, struct netif *netif)
|
|
||||||
{
|
|
||||||
u32_t addr2test;
|
|
||||||
|
|
||||||
addr2test = addr->addr;
|
|
||||||
/* all ones (broadcast) or all zeroes (old skool broadcast) */
|
|
||||||
if ((~addr2test == IP_ADDR_ANY_VALUE) ||
|
|
||||||
(addr2test == IP_ADDR_ANY_VALUE))
|
|
||||||
return 1;
|
|
||||||
/* no broadcast support on this network interface? */
|
|
||||||
else if ((netif->flags & NETIF_FLAG_BROADCAST) == 0)
|
|
||||||
/* the given address cannot be a broadcast address
|
|
||||||
* nor can we check against any broadcast addresses */
|
|
||||||
return 0;
|
|
||||||
/* address matches network interface address exactly? => no broadcast */
|
|
||||||
else if (addr2test == netif->ip_addr.addr)
|
|
||||||
return 0;
|
|
||||||
/* on the same (sub) network... */
|
|
||||||
else if (ip_addr_netcmp(addr, &(netif->ip_addr), &(netif->netmask))
|
|
||||||
/* ...and host identifier bits are all ones? =>... */
|
|
||||||
&& ((addr2test & ~netif->netmask.addr) ==
|
|
||||||
(IP_ADDR_BROADCAST_VALUE & ~netif->netmask.addr)))
|
|
||||||
/* => network broadcast address */
|
|
||||||
return 1;
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -1,792 +0,0 @@
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
* This is the IPv4 packet segmentation and reassembly implementation.
|
|
||||||
*
|
|
||||||
**/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Jani Monoses <jani@iv.ro>
|
|
||||||
* Simon Goldschmidt
|
|
||||||
* original reassembly code by Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "lwip/opt.h"
|
|
||||||
#include "lwip/ip_frag.h"
|
|
||||||
#include "lwip/ip.h"
|
|
||||||
#include "lwip/inet.h"
|
|
||||||
#include "lwip/inet_chksum.h"
|
|
||||||
#include "lwip/netif.h"
|
|
||||||
#include "lwip/snmp.h"
|
|
||||||
#include "lwip/stats.h"
|
|
||||||
#include "lwip/icmp.h"
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#if IP_REASSEMBLY
|
|
||||||
/**
|
|
||||||
* The IP reassembly code currently has the following limitations:
|
|
||||||
* - IP header options are not supported
|
|
||||||
* - fragments must not overlap (e.g. due to different routes),
|
|
||||||
* currently, overlapping or duplicate fragments are thrown away
|
|
||||||
* if IP_REASS_CHECK_OVERLAP=1 (the default)!
|
|
||||||
*
|
|
||||||
* @todo: work with IP header options
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** Setting this to 0, you can turn off checking the fragments for overlapping
|
|
||||||
* regions. The code gets a little smaller. Only use this if you know that
|
|
||||||
* overlapping won't occur on your network! */
|
|
||||||
#ifndef IP_REASS_CHECK_OVERLAP
|
|
||||||
#define IP_REASS_CHECK_OVERLAP 1
|
|
||||||
#endif /* IP_REASS_CHECK_OVERLAP */
|
|
||||||
|
|
||||||
/** Set to 0 to prevent freeing the oldest datagram when the reassembly buffer is
|
|
||||||
* full (IP_REASS_MAX_PBUFS pbufs are enqueued). The code gets a little smaller.
|
|
||||||
* Datagrams will be freed by timeout only. Especially useful when MEMP_NUM_REASSDATA
|
|
||||||
* is set to 1, so one datagram can be reassembled at a time, only. */
|
|
||||||
#ifndef IP_REASS_FREE_OLDEST
|
|
||||||
#define IP_REASS_FREE_OLDEST 1
|
|
||||||
#endif /* IP_REASS_FREE_OLDEST */
|
|
||||||
|
|
||||||
#define IP_REASS_FLAG_LASTFRAG 0x01
|
|
||||||
|
|
||||||
/** This is a helper struct which holds the starting
|
|
||||||
* offset and the ending offset of this fragment to
|
|
||||||
* easily chain the fragments.
|
|
||||||
* It has to be packed since it has to fit inside the IP header.
|
|
||||||
*/
|
|
||||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
|
||||||
# include "arch/bpstruct.h"
|
|
||||||
#endif
|
|
||||||
PACK_STRUCT_BEGIN
|
|
||||||
struct ip_reass_helper {
|
|
||||||
PACK_STRUCT_FIELD(struct pbuf *next_pbuf);
|
|
||||||
PACK_STRUCT_FIELD(u16_t start);
|
|
||||||
PACK_STRUCT_FIELD(u16_t end);
|
|
||||||
} PACK_STRUCT_STRUCT;
|
|
||||||
PACK_STRUCT_END
|
|
||||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
|
||||||
# include "arch/epstruct.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define IP_ADDRESSES_AND_ID_MATCH(iphdrA, iphdrB) \
|
|
||||||
(ip_addr_cmp(&(iphdrA)->src, &(iphdrB)->src) && \
|
|
||||||
ip_addr_cmp(&(iphdrA)->dest, &(iphdrB)->dest) && \
|
|
||||||
IPH_ID(iphdrA) == IPH_ID(iphdrB)) ? 1 : 0
|
|
||||||
|
|
||||||
/* global variables */
|
|
||||||
static struct ip_reassdata *reassdatagrams;
|
|
||||||
static u16_t ip_reass_pbufcount;
|
|
||||||
|
|
||||||
/* function prototypes */
|
|
||||||
static void ip_reass_dequeue_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev);
|
|
||||||
static int ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reassembly timer base function
|
|
||||||
* for both NO_SYS == 0 and 1 (!).
|
|
||||||
*
|
|
||||||
* Should be called every 1000 msec (defined by IP_TMR_INTERVAL).
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
ip_reass_tmr(void)
|
|
||||||
{
|
|
||||||
struct ip_reassdata *r, *prev = NULL;
|
|
||||||
|
|
||||||
r = reassdatagrams;
|
|
||||||
while (r != NULL) {
|
|
||||||
/* Decrement the timer. Once it reaches 0,
|
|
||||||
* clean up the incomplete fragment assembly */
|
|
||||||
if (r->timer > 0) {
|
|
||||||
r->timer--;
|
|
||||||
LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass_tmr: timer dec %"U16_F"\n",(u16_t)r->timer));
|
|
||||||
prev = r;
|
|
||||||
r = r->next;
|
|
||||||
} else {
|
|
||||||
/* reassembly timed out */
|
|
||||||
struct ip_reassdata *tmp;
|
|
||||||
LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass_tmr: timer timed out\n"));
|
|
||||||
tmp = r;
|
|
||||||
/* get the next pointer before freeing */
|
|
||||||
r = r->next;
|
|
||||||
/* free the helper struct and all enqueued pbufs */
|
|
||||||
ip_reass_free_complete_datagram(tmp, prev);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Free a datagram (struct ip_reassdata) and all its pbufs.
|
|
||||||
* Updates the total count of enqueued pbufs (ip_reass_pbufcount),
|
|
||||||
* SNMP counters and sends an ICMP time exceeded packet.
|
|
||||||
*
|
|
||||||
* @param ipr datagram to free
|
|
||||||
* @param prev the previous datagram in the linked list
|
|
||||||
* @return the number of pbufs freed
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev)
|
|
||||||
{
|
|
||||||
int pbufs_freed = 0;
|
|
||||||
struct pbuf *p;
|
|
||||||
struct ip_reass_helper *iprh;
|
|
||||||
|
|
||||||
LWIP_ASSERT("prev != ipr", prev != ipr);
|
|
||||||
if (prev != NULL) {
|
|
||||||
LWIP_ASSERT("prev->next == ipr", prev->next == ipr);
|
|
||||||
}
|
|
||||||
|
|
||||||
snmp_inc_ipreasmfails();
|
|
||||||
#if LWIP_ICMP
|
|
||||||
iprh = (struct ip_reass_helper *)ipr->p->payload;
|
|
||||||
if (iprh->start == 0) {
|
|
||||||
/* The first fragment was received, send ICMP time exceeded. */
|
|
||||||
/* First, de-queue the first pbuf from r->p. */
|
|
||||||
p = ipr->p;
|
|
||||||
ipr->p = iprh->next_pbuf;
|
|
||||||
/* Then, copy the original header into it. */
|
|
||||||
SMEMCPY(p->payload, &ipr->iphdr, IP_HLEN);
|
|
||||||
icmp_time_exceeded(p, ICMP_TE_FRAG);
|
|
||||||
pbufs_freed += pbuf_clen(p);
|
|
||||||
pbuf_free(p);
|
|
||||||
}
|
|
||||||
#endif /* LWIP_ICMP */
|
|
||||||
|
|
||||||
/* First, free all received pbufs. The individual pbufs need to be released
|
|
||||||
separately as they have not yet been chained */
|
|
||||||
p = ipr->p;
|
|
||||||
while (p != NULL) {
|
|
||||||
struct pbuf *pcur;
|
|
||||||
iprh = (struct ip_reass_helper *)p->payload;
|
|
||||||
pcur = p;
|
|
||||||
/* get the next pointer before freeing */
|
|
||||||
p = iprh->next_pbuf;
|
|
||||||
pbufs_freed += pbuf_clen(pcur);
|
|
||||||
pbuf_free(pcur);
|
|
||||||
}
|
|
||||||
/* Then, unchain the struct ip_reassdata from the list and free it. */
|
|
||||||
ip_reass_dequeue_datagram(ipr, prev);
|
|
||||||
LWIP_ASSERT("ip_reass_pbufcount >= clen", ip_reass_pbufcount >= pbufs_freed);
|
|
||||||
ip_reass_pbufcount -= pbufs_freed;
|
|
||||||
|
|
||||||
return pbufs_freed;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if IP_REASS_FREE_OLDEST
|
|
||||||
/**
|
|
||||||
* Free the oldest datagram to make room for enqueueing new fragments.
|
|
||||||
* The datagram 'fraghdr' belongs to is not freed!
|
|
||||||
*
|
|
||||||
* @param fraghdr IP header of the current fragment
|
|
||||||
* @param pbufs_needed number of pbufs needed to enqueue
|
|
||||||
* (used for freeing other datagrams if not enough space)
|
|
||||||
* @return the number of pbufs freed
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
ip_reass_remove_oldest_datagram(struct ip_hdr *fraghdr, int pbufs_needed)
|
|
||||||
{
|
|
||||||
/* @todo Can't we simply remove the last datagram in the
|
|
||||||
* linked list behind reassdatagrams?
|
|
||||||
*/
|
|
||||||
struct ip_reassdata *r, *oldest, *prev;
|
|
||||||
int pbufs_freed = 0, pbufs_freed_current;
|
|
||||||
int other_datagrams;
|
|
||||||
|
|
||||||
/* Free datagrams until being allowed to enqueue 'pbufs_needed' pbufs,
|
|
||||||
* but don't free the datagram that 'fraghdr' belongs to! */
|
|
||||||
do {
|
|
||||||
oldest = NULL;
|
|
||||||
prev = NULL;
|
|
||||||
other_datagrams = 0;
|
|
||||||
r = reassdatagrams;
|
|
||||||
while (r != NULL) {
|
|
||||||
if (!IP_ADDRESSES_AND_ID_MATCH(&r->iphdr, fraghdr)) {
|
|
||||||
/* Not the same datagram as fraghdr */
|
|
||||||
other_datagrams++;
|
|
||||||
if (oldest == NULL) {
|
|
||||||
oldest = r;
|
|
||||||
} else if (r->timer <= oldest->timer) {
|
|
||||||
/* older than the previous oldest */
|
|
||||||
oldest = r;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (r->next != NULL) {
|
|
||||||
prev = r;
|
|
||||||
}
|
|
||||||
r = r->next;
|
|
||||||
}
|
|
||||||
if (oldest != NULL) {
|
|
||||||
pbufs_freed_current = ip_reass_free_complete_datagram(oldest, prev);
|
|
||||||
pbufs_freed += pbufs_freed_current;
|
|
||||||
}
|
|
||||||
} while ((pbufs_freed < pbufs_needed) && (other_datagrams > 1));
|
|
||||||
return pbufs_freed;
|
|
||||||
}
|
|
||||||
#endif /* IP_REASS_FREE_OLDEST */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enqueues a new fragment into the fragment queue
|
|
||||||
* @param fraghdr points to the new fragments IP hdr
|
|
||||||
* @param clen number of pbufs needed to enqueue (used for freeing other datagrams if not enough space)
|
|
||||||
* @return A pointer to the queue location into which the fragment was enqueued
|
|
||||||
*/
|
|
||||||
static struct ip_reassdata*
|
|
||||||
ip_reass_enqueue_new_datagram(struct ip_hdr *fraghdr, int clen)
|
|
||||||
{
|
|
||||||
struct ip_reassdata* ipr;
|
|
||||||
/* No matching previous fragment found, allocate a new reassdata struct */
|
|
||||||
ipr = memp_malloc(MEMP_REASSDATA);
|
|
||||||
if (ipr == NULL) {
|
|
||||||
#if IP_REASS_FREE_OLDEST
|
|
||||||
if (ip_reass_remove_oldest_datagram(fraghdr, clen) >= clen) {
|
|
||||||
ipr = memp_malloc(MEMP_REASSDATA);
|
|
||||||
}
|
|
||||||
if (ipr == NULL)
|
|
||||||
#endif /* IP_REASS_FREE_OLDEST */
|
|
||||||
{
|
|
||||||
IPFRAG_STATS_INC(ip_frag.memerr);
|
|
||||||
LWIP_DEBUGF(IP_REASS_DEBUG,("Failed to alloc reassdata struct\n"));
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
memset(ipr, 0, sizeof(struct ip_reassdata));
|
|
||||||
ipr->timer = IP_REASS_MAXAGE;
|
|
||||||
|
|
||||||
/* enqueue the new structure to the front of the list */
|
|
||||||
ipr->next = reassdatagrams;
|
|
||||||
reassdatagrams = ipr;
|
|
||||||
/* copy the ip header for later tests and input */
|
|
||||||
/* @todo: no ip options supported? */
|
|
||||||
SMEMCPY(&(ipr->iphdr), fraghdr, IP_HLEN);
|
|
||||||
return ipr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Dequeues a datagram from the datagram queue. Doesn't deallocate the pbufs.
|
|
||||||
* @param ipr points to the queue entry to dequeue
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
ip_reass_dequeue_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev)
|
|
||||||
{
|
|
||||||
|
|
||||||
/* dequeue the reass struct */
|
|
||||||
if (reassdatagrams == ipr) {
|
|
||||||
/* it was the first in the list */
|
|
||||||
reassdatagrams = ipr->next;
|
|
||||||
} else {
|
|
||||||
/* it wasn't the first, so it must have a valid 'prev' */
|
|
||||||
LWIP_ASSERT("sanity check linked list", prev != NULL);
|
|
||||||
prev->next = ipr->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* now we can free the ip_reass struct */
|
|
||||||
memp_free(MEMP_REASSDATA, ipr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Chain a new pbuf into the pbuf list that composes the datagram. The pbuf list
|
|
||||||
* will grow over time as new pbufs are rx.
|
|
||||||
* Also checks that the datagram passes basic continuity checks (if the last
|
|
||||||
* fragment was received at least once).
|
|
||||||
* @param root_p points to the 'root' pbuf for the current datagram being assembled.
|
|
||||||
* @param new_p points to the pbuf for the current fragment
|
|
||||||
* @return 0 if invalid, >0 otherwise
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
ip_reass_chain_frag_into_datagram_and_validate(struct ip_reassdata *ipr, struct pbuf *new_p)
|
|
||||||
{
|
|
||||||
struct ip_reass_helper *iprh, *iprh_tmp, *iprh_prev=NULL;
|
|
||||||
struct pbuf *q;
|
|
||||||
u16_t offset,len;
|
|
||||||
struct ip_hdr *fraghdr;
|
|
||||||
int valid = 1;
|
|
||||||
|
|
||||||
/* Extract length and fragment offset from current fragment */
|
|
||||||
fraghdr = (struct ip_hdr*)new_p->payload;
|
|
||||||
len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;
|
|
||||||
offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;
|
|
||||||
|
|
||||||
/* overwrite the fragment's ip header from the pbuf with our helper struct,
|
|
||||||
* and setup the embedded helper structure. */
|
|
||||||
/* make sure the struct ip_reass_helper fits into the IP header */
|
|
||||||
LWIP_ASSERT("sizeof(struct ip_reass_helper) <= IP_HLEN",
|
|
||||||
sizeof(struct ip_reass_helper) <= IP_HLEN);
|
|
||||||
iprh = (struct ip_reass_helper*)new_p->payload;
|
|
||||||
iprh->next_pbuf = NULL;
|
|
||||||
iprh->start = offset;
|
|
||||||
iprh->end = offset + len;
|
|
||||||
|
|
||||||
/* Iterate through until we either get to the end of the list (append),
|
|
||||||
* or we find on with a larger offset (insert). */
|
|
||||||
for (q = ipr->p; q != NULL;) {
|
|
||||||
iprh_tmp = (struct ip_reass_helper*)q->payload;
|
|
||||||
if (iprh->start < iprh_tmp->start) {
|
|
||||||
/* the new pbuf should be inserted before this */
|
|
||||||
iprh->next_pbuf = q;
|
|
||||||
if (iprh_prev != NULL) {
|
|
||||||
/* not the fragment with the lowest offset */
|
|
||||||
#if IP_REASS_CHECK_OVERLAP
|
|
||||||
if ((iprh->start < iprh_prev->end) || (iprh->end > iprh_tmp->start)) {
|
|
||||||
/* fragment overlaps with previous or following, throw away */
|
|
||||||
goto freepbuf;
|
|
||||||
}
|
|
||||||
#endif /* IP_REASS_CHECK_OVERLAP */
|
|
||||||
iprh_prev->next_pbuf = new_p;
|
|
||||||
} else {
|
|
||||||
/* fragment with the lowest offset */
|
|
||||||
ipr->p = new_p;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
} else if(iprh->start == iprh_tmp->start) {
|
|
||||||
/* received the same datagram twice: no need to keep the datagram */
|
|
||||||
goto freepbuf;
|
|
||||||
#if IP_REASS_CHECK_OVERLAP
|
|
||||||
} else if(iprh->start < iprh_tmp->end) {
|
|
||||||
/* overlap: no need to keep the new datagram */
|
|
||||||
goto freepbuf;
|
|
||||||
#endif /* IP_REASS_CHECK_OVERLAP */
|
|
||||||
} else {
|
|
||||||
/* Check if the fragments received so far have no wholes. */
|
|
||||||
if (iprh_prev != NULL) {
|
|
||||||
if (iprh_prev->end != iprh_tmp->start) {
|
|
||||||
/* There is a fragment missing between the current
|
|
||||||
* and the previous fragment */
|
|
||||||
valid = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
q = iprh_tmp->next_pbuf;
|
|
||||||
iprh_prev = iprh_tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If q is NULL, then we made it to the end of the list. Determine what to do now */
|
|
||||||
if (q == NULL) {
|
|
||||||
if (iprh_prev != NULL) {
|
|
||||||
/* this is (for now), the fragment with the highest offset:
|
|
||||||
* chain it to the last fragment */
|
|
||||||
#if IP_REASS_CHECK_OVERLAP
|
|
||||||
LWIP_ASSERT("check fragments don't overlap", iprh_prev->end <= iprh->start);
|
|
||||||
#endif /* IP_REASS_CHECK_OVERLAP */
|
|
||||||
iprh_prev->next_pbuf = new_p;
|
|
||||||
if (iprh_prev->end != iprh->start) {
|
|
||||||
valid = 0;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
#if IP_REASS_CHECK_OVERLAP
|
|
||||||
LWIP_ASSERT("no previous fragment, this must be the first fragment!",
|
|
||||||
ipr->p == NULL);
|
|
||||||
#endif /* IP_REASS_CHECK_OVERLAP */
|
|
||||||
/* this is the first fragment we ever received for this ip datagram */
|
|
||||||
ipr->p = new_p;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* At this point, the validation part begins: */
|
|
||||||
/* If we already received the last fragment */
|
|
||||||
if ((ipr->flags & IP_REASS_FLAG_LASTFRAG) != 0) {
|
|
||||||
/* and had no wholes so far */
|
|
||||||
if (valid) {
|
|
||||||
/* then check if the rest of the fragments is here */
|
|
||||||
/* Check if the queue starts with the first datagram */
|
|
||||||
if (((struct ip_reass_helper*)ipr->p->payload)->start != 0) {
|
|
||||||
valid = 0;
|
|
||||||
} else {
|
|
||||||
/* and check that there are no wholes after this datagram */
|
|
||||||
iprh_prev = iprh;
|
|
||||||
q = iprh->next_pbuf;
|
|
||||||
while (q != NULL) {
|
|
||||||
iprh = (struct ip_reass_helper*)q->payload;
|
|
||||||
if (iprh_prev->end != iprh->start) {
|
|
||||||
valid = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
iprh_prev = iprh;
|
|
||||||
q = iprh->next_pbuf;
|
|
||||||
}
|
|
||||||
/* if still valid, all fragments are received
|
|
||||||
* (because to the MF==0 already arrived */
|
|
||||||
if (valid) {
|
|
||||||
LWIP_ASSERT("sanity check", ipr->p != NULL);
|
|
||||||
LWIP_ASSERT("sanity check",
|
|
||||||
((struct ip_reass_helper*)ipr->p->payload) != iprh);
|
|
||||||
LWIP_ASSERT("validate_datagram:next_pbuf!=NULL",
|
|
||||||
iprh->next_pbuf == NULL);
|
|
||||||
LWIP_ASSERT("validate_datagram:datagram end!=datagram len",
|
|
||||||
iprh->end == ipr->datagram_len);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* If valid is 0 here, there are some fragments missing in the middle
|
|
||||||
* (since MF == 0 has already arrived). Such datagrams simply time out if
|
|
||||||
* no more fragments are received... */
|
|
||||||
return valid;
|
|
||||||
}
|
|
||||||
/* If we come here, not all fragments were received, yet! */
|
|
||||||
return 0; /* not yet valid! */
|
|
||||||
#if IP_REASS_CHECK_OVERLAP
|
|
||||||
freepbuf:
|
|
||||||
ip_reass_pbufcount -= pbuf_clen(new_p);
|
|
||||||
pbuf_free(new_p);
|
|
||||||
return 0;
|
|
||||||
#endif /* IP_REASS_CHECK_OVERLAP */
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reassembles incoming IP fragments into an IP datagram.
|
|
||||||
*
|
|
||||||
* @param p points to a pbuf chain of the fragment
|
|
||||||
* @return NULL if reassembly is incomplete, ? otherwise
|
|
||||||
*/
|
|
||||||
struct pbuf *
|
|
||||||
ip_reass(struct pbuf *p)
|
|
||||||
{
|
|
||||||
struct pbuf *r;
|
|
||||||
struct ip_hdr *fraghdr;
|
|
||||||
struct ip_reassdata *ipr;
|
|
||||||
struct ip_reass_helper *iprh;
|
|
||||||
u16_t offset, len;
|
|
||||||
u8_t clen;
|
|
||||||
struct ip_reassdata *ipr_prev = NULL;
|
|
||||||
|
|
||||||
IPFRAG_STATS_INC(ip_frag.recv);
|
|
||||||
snmp_inc_ipreasmreqds();
|
|
||||||
|
|
||||||
fraghdr = (struct ip_hdr*)p->payload;
|
|
||||||
|
|
||||||
if ((IPH_HL(fraghdr) * 4) != IP_HLEN) {
|
|
||||||
LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: IP options currently not supported!\n"));
|
|
||||||
IPFRAG_STATS_INC(ip_frag.err);
|
|
||||||
goto nullreturn;
|
|
||||||
}
|
|
||||||
|
|
||||||
offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;
|
|
||||||
len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;
|
|
||||||
|
|
||||||
/* Check if we are allowed to enqueue more datagrams. */
|
|
||||||
clen = pbuf_clen(p);
|
|
||||||
if ((ip_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS) {
|
|
||||||
#if IP_REASS_FREE_OLDEST
|
|
||||||
if (!ip_reass_remove_oldest_datagram(fraghdr, clen) ||
|
|
||||||
((ip_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS))
|
|
||||||
#endif /* IP_REASS_FREE_OLDEST */
|
|
||||||
{
|
|
||||||
/* No datagram could be freed and still too many pbufs enqueued */
|
|
||||||
LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: Overflow condition: pbufct=%d, clen=%d, MAX=%d\n",
|
|
||||||
ip_reass_pbufcount, clen, IP_REASS_MAX_PBUFS));
|
|
||||||
IPFRAG_STATS_INC(ip_frag.memerr);
|
|
||||||
/* @todo: send ICMP time exceeded here? */
|
|
||||||
/* drop this pbuf */
|
|
||||||
goto nullreturn;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Look for the datagram the fragment belongs to in the current datagram queue,
|
|
||||||
* remembering the previous in the queue for later dequeueing. */
|
|
||||||
for (ipr = reassdatagrams; ipr != NULL; ipr = ipr->next) {
|
|
||||||
/* Check if the incoming fragment matches the one currently present
|
|
||||||
in the reassembly buffer. If so, we proceed with copying the
|
|
||||||
fragment into the buffer. */
|
|
||||||
if (IP_ADDRESSES_AND_ID_MATCH(&ipr->iphdr, fraghdr)) {
|
|
||||||
LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass: matching previous fragment ID=%"X16_F"\n",
|
|
||||||
ntohs(IPH_ID(fraghdr))));
|
|
||||||
IPFRAG_STATS_INC(ip_frag.cachehit);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
ipr_prev = ipr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ipr == NULL) {
|
|
||||||
/* Enqueue a new datagram into the datagram queue */
|
|
||||||
ipr = ip_reass_enqueue_new_datagram(fraghdr, clen);
|
|
||||||
/* Bail if unable to enqueue */
|
|
||||||
if(ipr == NULL) {
|
|
||||||
goto nullreturn;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (((ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) == 0) &&
|
|
||||||
((ntohs(IPH_OFFSET(&ipr->iphdr)) & IP_OFFMASK) != 0)) {
|
|
||||||
/* ipr->iphdr is not the header from the first fragment, but fraghdr is
|
|
||||||
* -> copy fraghdr into ipr->iphdr since we want to have the header
|
|
||||||
* of the first fragment (for ICMP time exceeded and later, for copying
|
|
||||||
* all options, if supported)*/
|
|
||||||
SMEMCPY(&ipr->iphdr, fraghdr, IP_HLEN);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Track the current number of pbufs current 'in-flight', in order to limit
|
|
||||||
the number of fragments that may be enqueued at any one time */
|
|
||||||
ip_reass_pbufcount += clen;
|
|
||||||
|
|
||||||
/* At this point, we have either created a new entry or pointing
|
|
||||||
* to an existing one */
|
|
||||||
|
|
||||||
/* check for 'no more fragments', and update queue entry*/
|
|
||||||
if ((ntohs(IPH_OFFSET(fraghdr)) & IP_MF) == 0) {
|
|
||||||
ipr->flags |= IP_REASS_FLAG_LASTFRAG;
|
|
||||||
ipr->datagram_len = offset + len;
|
|
||||||
LWIP_DEBUGF(IP_REASS_DEBUG,
|
|
||||||
("ip_reass: last fragment seen, total len %"S16_F"\n",
|
|
||||||
ipr->datagram_len));
|
|
||||||
}
|
|
||||||
/* find the right place to insert this pbuf */
|
|
||||||
/* @todo: trim pbufs if fragments are overlapping */
|
|
||||||
if (ip_reass_chain_frag_into_datagram_and_validate(ipr, p)) {
|
|
||||||
/* the totally last fragment (flag more fragments = 0) was received at least
|
|
||||||
* once AND all fragments are received */
|
|
||||||
ipr->datagram_len += IP_HLEN;
|
|
||||||
|
|
||||||
/* save the second pbuf before copying the header over the pointer */
|
|
||||||
r = ((struct ip_reass_helper*)ipr->p->payload)->next_pbuf;
|
|
||||||
|
|
||||||
/* copy the original ip header back to the first pbuf */
|
|
||||||
fraghdr = (struct ip_hdr*)(ipr->p->payload);
|
|
||||||
SMEMCPY(fraghdr, &ipr->iphdr, IP_HLEN);
|
|
||||||
IPH_LEN_SET(fraghdr, htons(ipr->datagram_len));
|
|
||||||
IPH_OFFSET_SET(fraghdr, 0);
|
|
||||||
IPH_CHKSUM_SET(fraghdr, 0);
|
|
||||||
/* @todo: do we need to set calculate the correct checksum? */
|
|
||||||
IPH_CHKSUM_SET(fraghdr, inet_chksum(fraghdr, IP_HLEN));
|
|
||||||
|
|
||||||
p = ipr->p;
|
|
||||||
|
|
||||||
/* chain together the pbufs contained within the reass_data list. */
|
|
||||||
while(r != NULL) {
|
|
||||||
iprh = (struct ip_reass_helper*)r->payload;
|
|
||||||
|
|
||||||
/* hide the ip header for every succeding fragment */
|
|
||||||
pbuf_header(r, -IP_HLEN);
|
|
||||||
pbuf_cat(p, r);
|
|
||||||
r = iprh->next_pbuf;
|
|
||||||
}
|
|
||||||
/* release the sources allocate for the fragment queue entry */
|
|
||||||
ip_reass_dequeue_datagram(ipr, ipr_prev);
|
|
||||||
|
|
||||||
/* and adjust the number of pbufs currently queued for reassembly. */
|
|
||||||
ip_reass_pbufcount -= pbuf_clen(p);
|
|
||||||
|
|
||||||
/* Return the pbuf chain */
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
/* the datagram is not (yet?) reassembled completely */
|
|
||||||
LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass_pbufcount: %d out\n", ip_reass_pbufcount));
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
nullreturn:
|
|
||||||
LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: nullreturn\n"));
|
|
||||||
IPFRAG_STATS_INC(ip_frag.drop);
|
|
||||||
pbuf_free(p);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
#endif /* IP_REASSEMBLY */
|
|
||||||
|
|
||||||
#if IP_FRAG
|
|
||||||
#if IP_FRAG_USES_STATIC_BUF
|
|
||||||
static u8_t buf[LWIP_MEM_ALIGN_SIZE(IP_FRAG_MAX_MTU + MEM_ALIGNMENT - 1)];
|
|
||||||
#endif /* IP_FRAG_USES_STATIC_BUF */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fragment an IP datagram if too large for the netif.
|
|
||||||
*
|
|
||||||
* Chop the datagram in MTU sized chunks and send them in order
|
|
||||||
* by using a fixed size static memory buffer (PBUF_REF) or
|
|
||||||
* point PBUF_REFs into p (depending on IP_FRAG_USES_STATIC_BUF).
|
|
||||||
*
|
|
||||||
* @param p ip packet to send
|
|
||||||
* @param netif the netif on which to send
|
|
||||||
* @param dest destination ip address to which to send
|
|
||||||
*
|
|
||||||
* @return ERR_OK if sent successfully, err_t otherwise
|
|
||||||
*/
|
|
||||||
err_t
|
|
||||||
ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest)
|
|
||||||
{
|
|
||||||
struct pbuf *rambuf;
|
|
||||||
#if IP_FRAG_USES_STATIC_BUF
|
|
||||||
struct pbuf *header;
|
|
||||||
#else
|
|
||||||
struct pbuf *newpbuf;
|
|
||||||
struct ip_hdr *original_iphdr;
|
|
||||||
#endif
|
|
||||||
struct ip_hdr *iphdr;
|
|
||||||
u16_t nfb;
|
|
||||||
u16_t left, cop;
|
|
||||||
u16_t mtu = netif->mtu;
|
|
||||||
u16_t ofo, omf;
|
|
||||||
u16_t last;
|
|
||||||
u16_t poff = IP_HLEN;
|
|
||||||
u16_t tmp;
|
|
||||||
#if !IP_FRAG_USES_STATIC_BUF
|
|
||||||
u16_t newpbuflen = 0;
|
|
||||||
u16_t left_to_copy;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Get a RAM based MTU sized pbuf */
|
|
||||||
#if IP_FRAG_USES_STATIC_BUF
|
|
||||||
/* When using a static buffer, we use a PBUF_REF, which we will
|
|
||||||
* use to reference the packet (without link header).
|
|
||||||
* Layer and length is irrelevant.
|
|
||||||
*/
|
|
||||||
rambuf = pbuf_alloc(PBUF_LINK, 0, PBUF_REF);
|
|
||||||
if (rambuf == NULL) {
|
|
||||||
LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_frag: pbuf_alloc(PBUF_LINK, 0, PBUF_REF) failed\n"));
|
|
||||||
return ERR_MEM;
|
|
||||||
}
|
|
||||||
rambuf->tot_len = rambuf->len = mtu;
|
|
||||||
rambuf->payload = LWIP_MEM_ALIGN((void *)buf);
|
|
||||||
|
|
||||||
/* Copy the IP header in it */
|
|
||||||
iphdr = rambuf->payload;
|
|
||||||
SMEMCPY(iphdr, p->payload, IP_HLEN);
|
|
||||||
#else /* IP_FRAG_USES_STATIC_BUF */
|
|
||||||
original_iphdr = p->payload;
|
|
||||||
iphdr = original_iphdr;
|
|
||||||
#endif /* IP_FRAG_USES_STATIC_BUF */
|
|
||||||
|
|
||||||
/* Save original offset */
|
|
||||||
tmp = ntohs(IPH_OFFSET(iphdr));
|
|
||||||
ofo = tmp & IP_OFFMASK;
|
|
||||||
omf = tmp & IP_MF;
|
|
||||||
|
|
||||||
left = p->tot_len - IP_HLEN;
|
|
||||||
|
|
||||||
nfb = (mtu - IP_HLEN) / 8;
|
|
||||||
|
|
||||||
while (left) {
|
|
||||||
last = (left <= mtu - IP_HLEN);
|
|
||||||
|
|
||||||
/* Set new offset and MF flag */
|
|
||||||
tmp = omf | (IP_OFFMASK & (ofo));
|
|
||||||
if (!last)
|
|
||||||
tmp = tmp | IP_MF;
|
|
||||||
|
|
||||||
/* Fill this fragment */
|
|
||||||
cop = last ? left : nfb * 8;
|
|
||||||
|
|
||||||
#if IP_FRAG_USES_STATIC_BUF
|
|
||||||
poff += pbuf_copy_partial(p, (u8_t*)iphdr + IP_HLEN, cop, poff);
|
|
||||||
#else /* IP_FRAG_USES_STATIC_BUF */
|
|
||||||
/* When not using a static buffer, create a chain of pbufs.
|
|
||||||
* The first will be a PBUF_RAM holding the link and IP header.
|
|
||||||
* The rest will be PBUF_REFs mirroring the pbuf chain to be fragged,
|
|
||||||
* but limited to the size of an mtu.
|
|
||||||
*/
|
|
||||||
rambuf = pbuf_alloc(PBUF_LINK, IP_HLEN, PBUF_RAM);
|
|
||||||
if (rambuf == NULL) {
|
|
||||||
return ERR_MEM;
|
|
||||||
}
|
|
||||||
LWIP_ASSERT("this needs a pbuf in one piece!",
|
|
||||||
(p->len >= (IP_HLEN)));
|
|
||||||
SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN);
|
|
||||||
iphdr = rambuf->payload;
|
|
||||||
|
|
||||||
/* Can just adjust p directly for needed offset. */
|
|
||||||
p->payload = (u8_t *)p->payload + poff;
|
|
||||||
p->len -= poff;
|
|
||||||
|
|
||||||
left_to_copy = cop;
|
|
||||||
while (left_to_copy) {
|
|
||||||
newpbuflen = (left_to_copy < p->len) ? left_to_copy : p->len;
|
|
||||||
/* Is this pbuf already empty? */
|
|
||||||
if (!newpbuflen) {
|
|
||||||
p = p->next;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
newpbuf = pbuf_alloc(PBUF_RAW, 0, PBUF_REF);
|
|
||||||
if (newpbuf == NULL) {
|
|
||||||
pbuf_free(rambuf);
|
|
||||||
return ERR_MEM;
|
|
||||||
}
|
|
||||||
/* Mirror this pbuf, although we might not need all of it. */
|
|
||||||
newpbuf->payload = p->payload;
|
|
||||||
newpbuf->len = newpbuf->tot_len = newpbuflen;
|
|
||||||
/* Add it to end of rambuf's chain, but using pbuf_cat, not pbuf_chain
|
|
||||||
* so that it is removed when pbuf_dechain is later called on rambuf.
|
|
||||||
*/
|
|
||||||
pbuf_cat(rambuf, newpbuf);
|
|
||||||
left_to_copy -= newpbuflen;
|
|
||||||
if (left_to_copy)
|
|
||||||
p = p->next;
|
|
||||||
}
|
|
||||||
poff = newpbuflen;
|
|
||||||
#endif /* IP_FRAG_USES_STATIC_BUF */
|
|
||||||
|
|
||||||
/* Correct header */
|
|
||||||
IPH_OFFSET_SET(iphdr, htons(tmp));
|
|
||||||
IPH_LEN_SET(iphdr, htons(cop + IP_HLEN));
|
|
||||||
IPH_CHKSUM_SET(iphdr, 0);
|
|
||||||
IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
|
|
||||||
|
|
||||||
#if IP_FRAG_USES_STATIC_BUF
|
|
||||||
if (last)
|
|
||||||
pbuf_realloc(rambuf, left + IP_HLEN);
|
|
||||||
|
|
||||||
/* This part is ugly: we alloc a RAM based pbuf for
|
|
||||||
* the link level header for each chunk and then
|
|
||||||
* free it.A PBUF_ROM style pbuf for which pbuf_header
|
|
||||||
* worked would make things simpler.
|
|
||||||
*/
|
|
||||||
header = pbuf_alloc(PBUF_LINK, 0, PBUF_RAM);
|
|
||||||
if (header != NULL) {
|
|
||||||
pbuf_chain(header, rambuf);
|
|
||||||
netif->output(netif, header, dest);
|
|
||||||
IPFRAG_STATS_INC(ip_frag.xmit);
|
|
||||||
snmp_inc_ipfragcreates();
|
|
||||||
pbuf_free(header);
|
|
||||||
} else {
|
|
||||||
LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_frag: pbuf_alloc() for header failed\n"));
|
|
||||||
pbuf_free(rambuf);
|
|
||||||
return ERR_MEM;
|
|
||||||
}
|
|
||||||
#else /* IP_FRAG_USES_STATIC_BUF */
|
|
||||||
/* No need for separate header pbuf - we allowed room for it in rambuf
|
|
||||||
* when allocated.
|
|
||||||
*/
|
|
||||||
netif->output(netif, rambuf, dest);
|
|
||||||
IPFRAG_STATS_INC(ip_frag.xmit);
|
|
||||||
|
|
||||||
/* Unfortunately we can't reuse rambuf - the hardware may still be
|
|
||||||
* using the buffer. Instead we free it (and the ensuing chain) and
|
|
||||||
* recreate it next time round the loop. If we're lucky the hardware
|
|
||||||
* will have already sent the packet, the free will really free, and
|
|
||||||
* there will be zero memory penalty.
|
|
||||||
*/
|
|
||||||
|
|
||||||
pbuf_free(rambuf);
|
|
||||||
#endif /* IP_FRAG_USES_STATIC_BUF */
|
|
||||||
left -= cop;
|
|
||||||
ofo += nfb;
|
|
||||||
}
|
|
||||||
#if IP_FRAG_USES_STATIC_BUF
|
|
||||||
pbuf_free(rambuf);
|
|
||||||
#endif /* IP_FRAG_USES_STATIC_BUF */
|
|
||||||
snmp_inc_ipfragoks();
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
|
||||||
#endif /* IP_FRAG */
|
|
|
@ -1,633 +0,0 @@
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
* Dynamic memory manager
|
|
||||||
*
|
|
||||||
* This is a lightweight replacement for the standard C library malloc().
|
|
||||||
*
|
|
||||||
* If you want to use the standard C library malloc() instead, define
|
|
||||||
* MEM_LIBC_MALLOC to 1 in your lwipopts.h
|
|
||||||
*
|
|
||||||
* To let mem_malloc() use pools (prevents fragmentation and is much faster than
|
|
||||||
* a heap but might waste some memory), define MEM_USE_POOLS to 1, define
|
|
||||||
* MEM_USE_CUSTOM_POOLS to 1 and create a file "lwippools.h" that includes a list
|
|
||||||
* of pools like this (more pools can be added between _START and _END):
|
|
||||||
*
|
|
||||||
* Define three pools with sizes 256, 512, and 1512 bytes
|
|
||||||
* LWIP_MALLOC_MEMPOOL_START
|
|
||||||
* LWIP_MALLOC_MEMPOOL(20, 256)
|
|
||||||
* LWIP_MALLOC_MEMPOOL(10, 512)
|
|
||||||
* LWIP_MALLOC_MEMPOOL(5, 1512)
|
|
||||||
* LWIP_MALLOC_MEMPOOL_END
|
|
||||||
**/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
* Simon Goldschmidt
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "lwip/opt.h"
|
|
||||||
|
|
||||||
#if !MEM_LIBC_MALLOC /* don't build if not configured for use in lwipopts.h */
|
|
||||||
|
|
||||||
#include "lwip/def.h"
|
|
||||||
#include "lwip/mem.h"
|
|
||||||
#include "lwip/sys.h"
|
|
||||||
#include "lwip/stats.h"
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#if MEM_USE_POOLS
|
|
||||||
/* lwIP head implemented with different sized pools */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Allocate memory: determine the smallest pool that is big enough
|
|
||||||
* to contain an element of 'size' and get an element from that pool.
|
|
||||||
*
|
|
||||||
* @param size the size in bytes of the memory needed
|
|
||||||
* @return a pointer to the allocated memory or NULL if the pool is empty
|
|
||||||
*/
|
|
||||||
void *
|
|
||||||
mem_malloc(mem_size_t size)
|
|
||||||
{
|
|
||||||
struct memp_malloc_helper *element;
|
|
||||||
memp_t poolnr;
|
|
||||||
mem_size_t required_size = size + sizeof(struct memp_malloc_helper);
|
|
||||||
|
|
||||||
for (poolnr = MEMP_POOL_FIRST; poolnr <= MEMP_POOL_LAST; poolnr++) {
|
|
||||||
#if MEM_USE_POOLS_TRY_BIGGER_POOL
|
|
||||||
again:
|
|
||||||
#endif /* MEM_USE_POOLS_TRY_BIGGER_POOL */
|
|
||||||
/* is this pool big enough to hold an element of the required size
|
|
||||||
plus a struct memp_malloc_helper that saves the pool this element came from? */
|
|
||||||
if (required_size <= memp_sizes[poolnr]) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (poolnr > MEMP_POOL_LAST) {
|
|
||||||
LWIP_ASSERT("mem_malloc(): no pool is that big!", 0);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
element = (struct memp_malloc_helper*)memp_malloc(poolnr);
|
|
||||||
if (element == NULL) {
|
|
||||||
/* No need to DEBUGF or ASSERT: This error is already
|
|
||||||
taken care of in memp.c */
|
|
||||||
#if MEM_USE_POOLS_TRY_BIGGER_POOL
|
|
||||||
/** Try a bigger pool if this one is empty! */
|
|
||||||
if (poolnr < MEMP_POOL_LAST) {
|
|
||||||
poolnr++;
|
|
||||||
goto again;
|
|
||||||
}
|
|
||||||
#endif /* MEM_USE_POOLS_TRY_BIGGER_POOL */
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* save the pool number this element came from */
|
|
||||||
element->poolnr = poolnr;
|
|
||||||
/* and return a pointer to the memory directly after the struct memp_malloc_helper */
|
|
||||||
element++;
|
|
||||||
|
|
||||||
return element;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Free memory previously allocated by mem_malloc. Loads the pool number
|
|
||||||
* and calls memp_free with that pool number to put the element back into
|
|
||||||
* its pool
|
|
||||||
*
|
|
||||||
* @param rmem the memory element to free
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
mem_free(void *rmem)
|
|
||||||
{
|
|
||||||
struct memp_malloc_helper *hmem = (struct memp_malloc_helper*)rmem;
|
|
||||||
|
|
||||||
LWIP_ASSERT("rmem != NULL", (rmem != NULL));
|
|
||||||
LWIP_ASSERT("rmem == MEM_ALIGN(rmem)", (rmem == LWIP_MEM_ALIGN(rmem)));
|
|
||||||
|
|
||||||
/* get the original struct memp_malloc_helper */
|
|
||||||
hmem--;
|
|
||||||
|
|
||||||
LWIP_ASSERT("hmem != NULL", (hmem != NULL));
|
|
||||||
LWIP_ASSERT("hmem == MEM_ALIGN(hmem)", (hmem == LWIP_MEM_ALIGN(hmem)));
|
|
||||||
LWIP_ASSERT("hmem->poolnr < MEMP_MAX", (hmem->poolnr < MEMP_MAX));
|
|
||||||
|
|
||||||
/* and put it in the pool we saved earlier */
|
|
||||||
memp_free(hmem->poolnr, hmem);
|
|
||||||
}
|
|
||||||
|
|
||||||
#else /* MEM_USE_POOLS */
|
|
||||||
/* lwIP replacement for your libc malloc() */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The heap is made up as a list of structs of this type.
|
|
||||||
* This does not have to be aligned since for getting its size,
|
|
||||||
* we only use the macro SIZEOF_STRUCT_MEM, which automatically alignes.
|
|
||||||
*/
|
|
||||||
struct mem {
|
|
||||||
/** index (-> ram[next]) of the next struct */
|
|
||||||
mem_size_t next;
|
|
||||||
/** index (-> ram[next]) of the next struct */
|
|
||||||
mem_size_t prev;
|
|
||||||
/** 1: this area is used; 0: this area is unused */
|
|
||||||
u8_t used;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** All allocated blocks will be MIN_SIZE bytes big, at least!
|
|
||||||
* MIN_SIZE can be overridden to suit your needs. Smaller values save space,
|
|
||||||
* larger values could prevent too small blocks to fragment the RAM too much. */
|
|
||||||
#ifndef MIN_SIZE
|
|
||||||
#define MIN_SIZE 12
|
|
||||||
#endif /* MIN_SIZE */
|
|
||||||
/* some alignment macros: we define them here for better source code layout */
|
|
||||||
#define MIN_SIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(MIN_SIZE)
|
|
||||||
#define SIZEOF_STRUCT_MEM LWIP_MEM_ALIGN_SIZE(sizeof(struct mem))
|
|
||||||
#define MEM_SIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(MEM_SIZE)
|
|
||||||
|
|
||||||
/** the heap. we need one struct mem at the end and some room for alignment */
|
|
||||||
static u8_t ram_heap[MEM_SIZE_ALIGNED + (2*SIZEOF_STRUCT_MEM) + MEM_ALIGNMENT];
|
|
||||||
/** pointer to the heap (ram_heap): for alignment, ram is now a pointer instead of an array */
|
|
||||||
static u8_t *ram;
|
|
||||||
/** the last entry, always unused! */
|
|
||||||
static struct mem *ram_end;
|
|
||||||
/** pointer to the lowest free block, this is used for faster search */
|
|
||||||
static struct mem *lfree;
|
|
||||||
|
|
||||||
/** concurrent access protection */
|
|
||||||
static sys_sem_t mem_sem;
|
|
||||||
|
|
||||||
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
|
|
||||||
|
|
||||||
static volatile u8_t mem_free_count;
|
|
||||||
|
|
||||||
/* Allow mem_free from other (e.g. interrupt) context */
|
|
||||||
#define LWIP_MEM_FREE_DECL_PROTECT() SYS_ARCH_DECL_PROTECT(lev_free)
|
|
||||||
#define LWIP_MEM_FREE_PROTECT() SYS_ARCH_PROTECT(lev_free)
|
|
||||||
#define LWIP_MEM_FREE_UNPROTECT() SYS_ARCH_UNPROTECT(lev_free)
|
|
||||||
#define LWIP_MEM_ALLOC_DECL_PROTECT() SYS_ARCH_DECL_PROTECT(lev_alloc)
|
|
||||||
#define LWIP_MEM_ALLOC_PROTECT() SYS_ARCH_PROTECT(lev_alloc)
|
|
||||||
#define LWIP_MEM_ALLOC_UNPROTECT() SYS_ARCH_UNPROTECT(lev_alloc)
|
|
||||||
|
|
||||||
#else /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
|
|
||||||
|
|
||||||
/* Protect the heap only by using a semaphore */
|
|
||||||
#define LWIP_MEM_FREE_DECL_PROTECT()
|
|
||||||
#define LWIP_MEM_FREE_PROTECT() sys_arch_sem_wait(mem_sem, 0)
|
|
||||||
#define LWIP_MEM_FREE_UNPROTECT() sys_sem_signal(mem_sem)
|
|
||||||
/* mem_malloc is protected using semaphore AND LWIP_MEM_ALLOC_PROTECT */
|
|
||||||
#define LWIP_MEM_ALLOC_DECL_PROTECT()
|
|
||||||
#define LWIP_MEM_ALLOC_PROTECT()
|
|
||||||
#define LWIP_MEM_ALLOC_UNPROTECT()
|
|
||||||
|
|
||||||
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* "Plug holes" by combining adjacent empty struct mems.
|
|
||||||
* After this function is through, there should not exist
|
|
||||||
* one empty struct mem pointing to another empty struct mem.
|
|
||||||
*
|
|
||||||
* @param mem this points to a struct mem which just has been freed
|
|
||||||
* @internal this function is only called by mem_free() and mem_realloc()
|
|
||||||
*
|
|
||||||
* This assumes access to the heap is protected by the calling function
|
|
||||||
* already.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
plug_holes(struct mem *mem)
|
|
||||||
{
|
|
||||||
struct mem *nmem;
|
|
||||||
struct mem *pmem;
|
|
||||||
|
|
||||||
LWIP_ASSERT("plug_holes: mem >= ram", (u8_t *)mem >= ram);
|
|
||||||
LWIP_ASSERT("plug_holes: mem < ram_end", (u8_t *)mem < (u8_t *)ram_end);
|
|
||||||
LWIP_ASSERT("plug_holes: mem->used == 0", mem->used == 0);
|
|
||||||
|
|
||||||
/* plug hole forward */
|
|
||||||
LWIP_ASSERT("plug_holes: mem->next <= MEM_SIZE_ALIGNED", mem->next <= MEM_SIZE_ALIGNED);
|
|
||||||
|
|
||||||
nmem = (struct mem *)&ram[mem->next];
|
|
||||||
if (mem != nmem && nmem->used == 0 && (u8_t *)nmem != (u8_t *)ram_end) {
|
|
||||||
/* if mem->next is unused and not end of ram, combine mem and mem->next */
|
|
||||||
if (lfree == nmem) {
|
|
||||||
lfree = mem;
|
|
||||||
}
|
|
||||||
mem->next = nmem->next;
|
|
||||||
((struct mem *)&ram[nmem->next])->prev = (u8_t *)mem - ram;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* plug hole backward */
|
|
||||||
pmem = (struct mem *)&ram[mem->prev];
|
|
||||||
if (pmem != mem && pmem->used == 0) {
|
|
||||||
/* if mem->prev is unused, combine mem and mem->prev */
|
|
||||||
if (lfree == mem) {
|
|
||||||
lfree = pmem;
|
|
||||||
}
|
|
||||||
pmem->next = mem->next;
|
|
||||||
((struct mem *)&ram[mem->next])->prev = (u8_t *)pmem - ram;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Zero the heap and initialize start, end and lowest-free
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
mem_init(void)
|
|
||||||
{
|
|
||||||
struct mem *mem;
|
|
||||||
|
|
||||||
LWIP_ASSERT("Sanity check alignment",
|
|
||||||
(SIZEOF_STRUCT_MEM & (MEM_ALIGNMENT-1)) == 0);
|
|
||||||
|
|
||||||
/* align the heap */
|
|
||||||
ram = LWIP_MEM_ALIGN(ram_heap);
|
|
||||||
/* initialize the start of the heap */
|
|
||||||
mem = (struct mem *)ram;
|
|
||||||
mem->next = MEM_SIZE_ALIGNED;
|
|
||||||
mem->prev = 0;
|
|
||||||
mem->used = 0;
|
|
||||||
/* initialize the end of the heap */
|
|
||||||
ram_end = (struct mem *)&ram[MEM_SIZE_ALIGNED];
|
|
||||||
ram_end->used = 1;
|
|
||||||
ram_end->next = MEM_SIZE_ALIGNED;
|
|
||||||
ram_end->prev = MEM_SIZE_ALIGNED;
|
|
||||||
|
|
||||||
mem_sem = sys_sem_new(1);
|
|
||||||
|
|
||||||
/* initialize the lowest-free pointer to the start of the heap */
|
|
||||||
lfree = (struct mem *)ram;
|
|
||||||
|
|
||||||
MEM_STATS_AVAIL(avail, MEM_SIZE_ALIGNED);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Put a struct mem back on the heap
|
|
||||||
*
|
|
||||||
* @param rmem is the data portion of a struct mem as returned by a previous
|
|
||||||
* call to mem_malloc()
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
mem_free(void *rmem)
|
|
||||||
{
|
|
||||||
struct mem *mem;
|
|
||||||
LWIP_MEM_FREE_DECL_PROTECT();
|
|
||||||
|
|
||||||
if (rmem == NULL) {
|
|
||||||
LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("mem_free(p == NULL) was called.\n"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
LWIP_ASSERT("mem_free: sanity check alignment", (((mem_ptr_t)rmem) & (MEM_ALIGNMENT-1)) == 0);
|
|
||||||
|
|
||||||
LWIP_ASSERT("mem_free: legal memory", (u8_t *)rmem >= (u8_t *)ram &&
|
|
||||||
(u8_t *)rmem < (u8_t *)ram_end);
|
|
||||||
|
|
||||||
if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) {
|
|
||||||
SYS_ARCH_DECL_PROTECT(lev);
|
|
||||||
LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_free: illegal memory\n"));
|
|
||||||
/* protect mem stats from concurrent access */
|
|
||||||
SYS_ARCH_PROTECT(lev);
|
|
||||||
MEM_STATS_INC(illegal);
|
|
||||||
SYS_ARCH_UNPROTECT(lev);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
/* protect the heap from concurrent access */
|
|
||||||
LWIP_MEM_FREE_PROTECT();
|
|
||||||
/* Get the corresponding struct mem ... */
|
|
||||||
mem = (struct mem *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);
|
|
||||||
/* ... which has to be in a used state ... */
|
|
||||||
LWIP_ASSERT("mem_free: mem->used", mem->used);
|
|
||||||
/* ... and is now unused. */
|
|
||||||
mem->used = 0;
|
|
||||||
|
|
||||||
if (mem < lfree) {
|
|
||||||
/* the newly freed struct is now the lowest */
|
|
||||||
lfree = mem;
|
|
||||||
}
|
|
||||||
|
|
||||||
MEM_STATS_DEC_USED(used, mem->next - ((u8_t *)mem - ram));
|
|
||||||
|
|
||||||
/* finally, see if prev or next are free also */
|
|
||||||
plug_holes(mem);
|
|
||||||
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
|
|
||||||
mem_free_count = 1;
|
|
||||||
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
|
|
||||||
LWIP_MEM_FREE_UNPROTECT();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* In contrast to its name, mem_realloc can only shrink memory, not expand it.
|
|
||||||
* Since the only use (for now) is in pbuf_realloc (which also can only shrink),
|
|
||||||
* this shouldn't be a problem!
|
|
||||||
*
|
|
||||||
* @param rmem pointer to memory allocated by mem_malloc the is to be shrinked
|
|
||||||
* @param newsize required size after shrinking (needs to be smaller than or
|
|
||||||
* equal to the previous size)
|
|
||||||
* @return for compatibility reasons: is always == rmem, at the moment
|
|
||||||
* or NULL if newsize is > old size, in which case rmem is NOT touched
|
|
||||||
* or freed!
|
|
||||||
*/
|
|
||||||
void *
|
|
||||||
mem_realloc(void *rmem, mem_size_t newsize)
|
|
||||||
{
|
|
||||||
mem_size_t size;
|
|
||||||
mem_size_t ptr, ptr2;
|
|
||||||
struct mem *mem, *mem2;
|
|
||||||
/* use the FREE_PROTECT here: it protects with sem OR SYS_ARCH_PROTECT */
|
|
||||||
LWIP_MEM_FREE_DECL_PROTECT();
|
|
||||||
|
|
||||||
/* Expand the size of the allocated memory region so that we can
|
|
||||||
adjust for alignment. */
|
|
||||||
newsize = LWIP_MEM_ALIGN_SIZE(newsize);
|
|
||||||
|
|
||||||
if(newsize < MIN_SIZE_ALIGNED) {
|
|
||||||
/* every data block must be at least MIN_SIZE_ALIGNED long */
|
|
||||||
newsize = MIN_SIZE_ALIGNED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newsize > MEM_SIZE_ALIGNED) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
LWIP_ASSERT("mem_realloc: legal memory", (u8_t *)rmem >= (u8_t *)ram &&
|
|
||||||
(u8_t *)rmem < (u8_t *)ram_end);
|
|
||||||
|
|
||||||
if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) {
|
|
||||||
SYS_ARCH_DECL_PROTECT(lev);
|
|
||||||
LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_realloc: illegal memory\n"));
|
|
||||||
/* protect mem stats from concurrent access */
|
|
||||||
SYS_ARCH_PROTECT(lev);
|
|
||||||
MEM_STATS_INC(illegal);
|
|
||||||
SYS_ARCH_UNPROTECT(lev);
|
|
||||||
return rmem;
|
|
||||||
}
|
|
||||||
/* Get the corresponding struct mem ... */
|
|
||||||
mem = (struct mem *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);
|
|
||||||
/* ... and its offset pointer */
|
|
||||||
ptr = (u8_t *)mem - ram;
|
|
||||||
|
|
||||||
size = mem->next - ptr - SIZEOF_STRUCT_MEM;
|
|
||||||
LWIP_ASSERT("mem_realloc can only shrink memory", newsize <= size);
|
|
||||||
if (newsize > size) {
|
|
||||||
/* not supported */
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if (newsize == size) {
|
|
||||||
/* No change in size, simply return */
|
|
||||||
return rmem;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* protect the heap from concurrent access */
|
|
||||||
LWIP_MEM_FREE_PROTECT();
|
|
||||||
|
|
||||||
MEM_STATS_DEC_USED(used, (size - newsize));
|
|
||||||
|
|
||||||
mem2 = (struct mem *)&ram[mem->next];
|
|
||||||
if(mem2->used == 0) {
|
|
||||||
/* The next struct is unused, we can simply move it at little */
|
|
||||||
mem_size_t next;
|
|
||||||
/* remember the old next pointer */
|
|
||||||
next = mem2->next;
|
|
||||||
/* create new struct mem which is moved directly after the shrinked mem */
|
|
||||||
ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize;
|
|
||||||
if (lfree == mem2) {
|
|
||||||
lfree = (struct mem *)&ram[ptr2];
|
|
||||||
}
|
|
||||||
mem2 = (struct mem *)&ram[ptr2];
|
|
||||||
mem2->used = 0;
|
|
||||||
/* restore the next pointer */
|
|
||||||
mem2->next = next;
|
|
||||||
/* link it back to mem */
|
|
||||||
mem2->prev = ptr;
|
|
||||||
/* link mem to it */
|
|
||||||
mem->next = ptr2;
|
|
||||||
/* last thing to restore linked list: as we have moved mem2,
|
|
||||||
* let 'mem2->next->prev' point to mem2 again. but only if mem2->next is not
|
|
||||||
* the end of the heap */
|
|
||||||
if (mem2->next != MEM_SIZE_ALIGNED) {
|
|
||||||
((struct mem *)&ram[mem2->next])->prev = ptr2;
|
|
||||||
}
|
|
||||||
/* no need to plug holes, we've already done that */
|
|
||||||
} else if (newsize + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED <= size) {
|
|
||||||
/* Next struct is used but there's room for another struct mem with
|
|
||||||
* at least MIN_SIZE_ALIGNED of data.
|
|
||||||
* Old size ('size') must be big enough to contain at least 'newsize' plus a struct mem
|
|
||||||
* ('SIZEOF_STRUCT_MEM') with some data ('MIN_SIZE_ALIGNED').
|
|
||||||
* @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty
|
|
||||||
* region that couldn't hold data, but when mem->next gets freed,
|
|
||||||
* the 2 regions would be combined, resulting in more free memory */
|
|
||||||
ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize;
|
|
||||||
mem2 = (struct mem *)&ram[ptr2];
|
|
||||||
if (mem2 < lfree) {
|
|
||||||
lfree = mem2;
|
|
||||||
}
|
|
||||||
mem2->used = 0;
|
|
||||||
mem2->next = mem->next;
|
|
||||||
mem2->prev = ptr;
|
|
||||||
mem->next = ptr2;
|
|
||||||
if (mem2->next != MEM_SIZE_ALIGNED) {
|
|
||||||
((struct mem *)&ram[mem2->next])->prev = ptr2;
|
|
||||||
}
|
|
||||||
/* the original mem->next is used, so no need to plug holes! */
|
|
||||||
}
|
|
||||||
/* else {
|
|
||||||
next struct mem is used but size between mem and mem2 is not big enough
|
|
||||||
to create another struct mem
|
|
||||||
-> don't do anyhting.
|
|
||||||
-> the remaining space stays unused since it is too small
|
|
||||||
} */
|
|
||||||
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
|
|
||||||
mem_free_count = 1;
|
|
||||||
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
|
|
||||||
LWIP_MEM_FREE_UNPROTECT();
|
|
||||||
return rmem;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adam's mem_malloc() plus solution for bug #17922
|
|
||||||
* Allocate a block of memory with a minimum of 'size' bytes.
|
|
||||||
*
|
|
||||||
* @param size is the minimum size of the requested block in bytes.
|
|
||||||
* @return pointer to allocated memory or NULL if no free memory was found.
|
|
||||||
*
|
|
||||||
* Note that the returned value will always be aligned (as defined by MEM_ALIGNMENT).
|
|
||||||
*/
|
|
||||||
void *
|
|
||||||
mem_malloc(mem_size_t size)
|
|
||||||
{
|
|
||||||
mem_size_t ptr, ptr2;
|
|
||||||
struct mem *mem, *mem2;
|
|
||||||
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
|
|
||||||
u8_t local_mem_free_count = 0;
|
|
||||||
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
|
|
||||||
LWIP_MEM_ALLOC_DECL_PROTECT();
|
|
||||||
|
|
||||||
if (size == 0) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Expand the size of the allocated memory region so that we can
|
|
||||||
adjust for alignment. */
|
|
||||||
size = LWIP_MEM_ALIGN_SIZE(size);
|
|
||||||
|
|
||||||
if(size < MIN_SIZE_ALIGNED) {
|
|
||||||
/* every data block must be at least MIN_SIZE_ALIGNED long */
|
|
||||||
size = MIN_SIZE_ALIGNED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (size > MEM_SIZE_ALIGNED) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* protect the heap from concurrent access */
|
|
||||||
sys_arch_sem_wait(mem_sem, 0);
|
|
||||||
LWIP_MEM_ALLOC_PROTECT();
|
|
||||||
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
|
|
||||||
/* run as long as a mem_free disturbed mem_malloc */
|
|
||||||
do {
|
|
||||||
local_mem_free_count = 0;
|
|
||||||
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
|
|
||||||
|
|
||||||
/* Scan through the heap searching for a free block that is big enough,
|
|
||||||
* beginning with the lowest free block.
|
|
||||||
*/
|
|
||||||
for (ptr = (u8_t *)lfree - ram; ptr < MEM_SIZE_ALIGNED - size;
|
|
||||||
ptr = ((struct mem *)&ram[ptr])->next) {
|
|
||||||
mem = (struct mem *)&ram[ptr];
|
|
||||||
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
|
|
||||||
mem_free_count = 0;
|
|
||||||
LWIP_MEM_ALLOC_UNPROTECT();
|
|
||||||
/* allow mem_free to run */
|
|
||||||
LWIP_MEM_ALLOC_PROTECT();
|
|
||||||
if (mem_free_count != 0) {
|
|
||||||
local_mem_free_count = mem_free_count;
|
|
||||||
}
|
|
||||||
mem_free_count = 0;
|
|
||||||
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
|
|
||||||
|
|
||||||
if ((!mem->used) &&
|
|
||||||
(mem->next - (ptr + SIZEOF_STRUCT_MEM)) >= size) {
|
|
||||||
/* mem is not used and at least perfect fit is possible:
|
|
||||||
* mem->next - (ptr + SIZEOF_STRUCT_MEM) gives us the 'user data size' of mem */
|
|
||||||
|
|
||||||
if (mem->next - (ptr + SIZEOF_STRUCT_MEM) >= (size + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED)) {
|
|
||||||
/* (in addition to the above, we test if another struct mem (SIZEOF_STRUCT_MEM) containing
|
|
||||||
* at least MIN_SIZE_ALIGNED of data also fits in the 'user data space' of 'mem')
|
|
||||||
* -> split large block, create empty remainder,
|
|
||||||
* remainder must be large enough to contain MIN_SIZE_ALIGNED data: if
|
|
||||||
* mem->next - (ptr + (2*SIZEOF_STRUCT_MEM)) == size,
|
|
||||||
* struct mem would fit in but no data between mem2 and mem2->next
|
|
||||||
* @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty
|
|
||||||
* region that couldn't hold data, but when mem->next gets freed,
|
|
||||||
* the 2 regions would be combined, resulting in more free memory
|
|
||||||
*/
|
|
||||||
ptr2 = ptr + SIZEOF_STRUCT_MEM + size;
|
|
||||||
/* create mem2 struct */
|
|
||||||
mem2 = (struct mem *)&ram[ptr2];
|
|
||||||
mem2->used = 0;
|
|
||||||
mem2->next = mem->next;
|
|
||||||
mem2->prev = ptr;
|
|
||||||
/* and insert it between mem and mem->next */
|
|
||||||
mem->next = ptr2;
|
|
||||||
mem->used = 1;
|
|
||||||
|
|
||||||
if (mem2->next != MEM_SIZE_ALIGNED) {
|
|
||||||
((struct mem *)&ram[mem2->next])->prev = ptr2;
|
|
||||||
}
|
|
||||||
MEM_STATS_INC_USED(used, (size + SIZEOF_STRUCT_MEM));
|
|
||||||
} else {
|
|
||||||
/* (a mem2 struct does no fit into the user data space of mem and mem->next will always
|
|
||||||
* be used at this point: if not we have 2 unused structs in a row, plug_holes should have
|
|
||||||
* take care of this).
|
|
||||||
* -> near fit or excact fit: do not split, no mem2 creation
|
|
||||||
* also can't move mem->next directly behind mem, since mem->next
|
|
||||||
* will always be used at this point!
|
|
||||||
*/
|
|
||||||
mem->used = 1;
|
|
||||||
MEM_STATS_INC_USED(used, mem->next - ((u8_t *)mem - ram));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mem == lfree) {
|
|
||||||
/* Find next free block after mem and update lowest free pointer */
|
|
||||||
while (lfree->used && lfree != ram_end) {
|
|
||||||
LWIP_MEM_ALLOC_UNPROTECT();
|
|
||||||
/* prevent high interrupt latency... */
|
|
||||||
LWIP_MEM_ALLOC_PROTECT();
|
|
||||||
lfree = (struct mem *)&ram[lfree->next];
|
|
||||||
}
|
|
||||||
LWIP_ASSERT("mem_malloc: !lfree->used", ((lfree == ram_end) || (!lfree->used)));
|
|
||||||
}
|
|
||||||
LWIP_MEM_ALLOC_UNPROTECT();
|
|
||||||
sys_sem_signal(mem_sem);
|
|
||||||
LWIP_ASSERT("mem_malloc: allocated memory not above ram_end.",
|
|
||||||
(mem_ptr_t)mem + SIZEOF_STRUCT_MEM + size <= (mem_ptr_t)ram_end);
|
|
||||||
LWIP_ASSERT("mem_malloc: allocated memory properly aligned.",
|
|
||||||
((mem_ptr_t)mem + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT == 0);
|
|
||||||
LWIP_ASSERT("mem_malloc: sanity check alignment",
|
|
||||||
(((mem_ptr_t)mem) & (MEM_ALIGNMENT-1)) == 0);
|
|
||||||
|
|
||||||
return (u8_t *)mem + SIZEOF_STRUCT_MEM;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
|
|
||||||
/* if we got interrupted by a mem_free, try again */
|
|
||||||
} while(local_mem_free_count != 0);
|
|
||||||
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
|
|
||||||
LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("mem_malloc: could not allocate %"S16_F" bytes\n", (s16_t)size));
|
|
||||||
MEM_STATS_INC(err);
|
|
||||||
LWIP_MEM_ALLOC_UNPROTECT();
|
|
||||||
sys_sem_signal(mem_sem);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* MEM_USE_POOLS */
|
|
||||||
/**
|
|
||||||
* Contiguously allocates enough space for count objects that are size bytes
|
|
||||||
* of memory each and returns a pointer to the allocated memory.
|
|
||||||
*
|
|
||||||
* The allocated memory is filled with bytes of value zero.
|
|
||||||
*
|
|
||||||
* @param count number of objects to allocate
|
|
||||||
* @param size size of the objects to allocate
|
|
||||||
* @return pointer to allocated memory / NULL pointer if there is an error
|
|
||||||
*/
|
|
||||||
void *mem_calloc(mem_size_t count, mem_size_t size)
|
|
||||||
{
|
|
||||||
void *p;
|
|
||||||
|
|
||||||
/* allocate 'count' objects of size 'size' */
|
|
||||||
p = mem_malloc(count * size);
|
|
||||||
if (p) {
|
|
||||||
/* zero the memory */
|
|
||||||
memset(p, 0, count * size);
|
|
||||||
}
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* !MEM_LIBC_MALLOC */
|
|
|
@ -1,386 +0,0 @@
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
* Dynamic pool memory manager
|
|
||||||
*
|
|
||||||
* lwIP has dedicated pools for many structures (netconn, protocol control blocks,
|
|
||||||
* packet buffers, ...). All these pools are managed here.
|
|
||||||
**/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "lwip/opt.h"
|
|
||||||
|
|
||||||
#include "lwip/memp.h"
|
|
||||||
#include "lwip/pbuf.h"
|
|
||||||
#include "lwip/udp.h"
|
|
||||||
#include "lwip/raw.h"
|
|
||||||
#include "lwip/tcp.h"
|
|
||||||
#include "lwip/igmp.h"
|
|
||||||
#include "lwip/api.h"
|
|
||||||
#include "lwip/api_msg.h"
|
|
||||||
#include "lwip/tcpip.h"
|
|
||||||
#include "lwip/sys.h"
|
|
||||||
#include "lwip/stats.h"
|
|
||||||
#include "netif/etharp.h"
|
|
||||||
#include "lwip/ip_frag.h"
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#if !MEMP_MEM_MALLOC /* don't build if not configured for use in lwipopts.h */
|
|
||||||
|
|
||||||
struct memp {
|
|
||||||
struct memp *next;
|
|
||||||
#if MEMP_OVERFLOW_CHECK
|
|
||||||
const char *file;
|
|
||||||
int line;
|
|
||||||
#endif /* MEMP_OVERFLOW_CHECK */
|
|
||||||
};
|
|
||||||
|
|
||||||
#if MEMP_OVERFLOW_CHECK
|
|
||||||
/* if MEMP_OVERFLOW_CHECK is turned on, we reserve some bytes at the beginning
|
|
||||||
* and at the end of each element, initialize them as 0xcd and check
|
|
||||||
* them later. */
|
|
||||||
/* If MEMP_OVERFLOW_CHECK is >= 2, on every call to memp_malloc or memp_free,
|
|
||||||
* every single element in each pool is checked!
|
|
||||||
* This is VERY SLOW but also very helpful. */
|
|
||||||
/* MEMP_SANITY_REGION_BEFORE and MEMP_SANITY_REGION_AFTER can be overridden in
|
|
||||||
* lwipopts.h to change the amount reserved for checking. */
|
|
||||||
#ifndef MEMP_SANITY_REGION_BEFORE
|
|
||||||
#define MEMP_SANITY_REGION_BEFORE 16
|
|
||||||
#endif /* MEMP_SANITY_REGION_BEFORE*/
|
|
||||||
#if MEMP_SANITY_REGION_BEFORE > 0
|
|
||||||
#define MEMP_SANITY_REGION_BEFORE_ALIGNED LWIP_MEM_ALIGN_SIZE(MEMP_SANITY_REGION_BEFORE)
|
|
||||||
#else
|
|
||||||
#define MEMP_SANITY_REGION_BEFORE_ALIGNED 0
|
|
||||||
#endif /* MEMP_SANITY_REGION_BEFORE*/
|
|
||||||
#ifndef MEMP_SANITY_REGION_AFTER
|
|
||||||
#define MEMP_SANITY_REGION_AFTER 16
|
|
||||||
#endif /* MEMP_SANITY_REGION_AFTER*/
|
|
||||||
#if MEMP_SANITY_REGION_AFTER > 0
|
|
||||||
#define MEMP_SANITY_REGION_AFTER_ALIGNED LWIP_MEM_ALIGN_SIZE(MEMP_SANITY_REGION_AFTER)
|
|
||||||
#else
|
|
||||||
#define MEMP_SANITY_REGION_AFTER_ALIGNED 0
|
|
||||||
#endif /* MEMP_SANITY_REGION_AFTER*/
|
|
||||||
|
|
||||||
/* MEMP_SIZE: save space for struct memp and for sanity check */
|
|
||||||
#define MEMP_SIZE (LWIP_MEM_ALIGN_SIZE(sizeof(struct memp)) + MEMP_SANITY_REGION_BEFORE_ALIGNED)
|
|
||||||
#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x) + MEMP_SANITY_REGION_AFTER_ALIGNED)
|
|
||||||
|
|
||||||
#else /* MEMP_OVERFLOW_CHECK */
|
|
||||||
|
|
||||||
/* No sanity checks
|
|
||||||
* We don't need to preserve the struct memp while not allocated, so we
|
|
||||||
* can save a little space and set MEMP_SIZE to 0.
|
|
||||||
*/
|
|
||||||
#define MEMP_SIZE 0
|
|
||||||
#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x))
|
|
||||||
|
|
||||||
#endif /* MEMP_OVERFLOW_CHECK */
|
|
||||||
|
|
||||||
/** This array holds the first free element of each pool.
|
|
||||||
* Elements form a linked list. */
|
|
||||||
static struct memp *memp_tab[MEMP_MAX];
|
|
||||||
|
|
||||||
#else /* MEMP_MEM_MALLOC */
|
|
||||||
|
|
||||||
#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x))
|
|
||||||
|
|
||||||
#endif /* MEMP_MEM_MALLOC */
|
|
||||||
|
|
||||||
/** This array holds the element sizes of each pool. */
|
|
||||||
#if !MEM_USE_POOLS && !MEMP_MEM_MALLOC
|
|
||||||
static
|
|
||||||
#endif
|
|
||||||
const u16_t memp_sizes[MEMP_MAX] = {
|
|
||||||
#define LWIP_MEMPOOL(name,num,size,desc) LWIP_MEM_ALIGN_SIZE(size),
|
|
||||||
#include "lwip/memp_std.h"
|
|
||||||
};
|
|
||||||
|
|
||||||
#if !MEMP_MEM_MALLOC /* don't build if not configured for use in lwipopts.h */
|
|
||||||
|
|
||||||
/** This array holds the number of elements in each pool. */
|
|
||||||
static const u16_t memp_num[MEMP_MAX] = {
|
|
||||||
#define LWIP_MEMPOOL(name,num,size,desc) (num),
|
|
||||||
#include "lwip/memp_std.h"
|
|
||||||
};
|
|
||||||
|
|
||||||
/** This array holds a textual description of each pool. */
|
|
||||||
#ifdef LWIP_DEBUG
|
|
||||||
static const char *memp_desc[MEMP_MAX] = {
|
|
||||||
#define LWIP_MEMPOOL(name,num,size,desc) (desc),
|
|
||||||
#include "lwip/memp_std.h"
|
|
||||||
};
|
|
||||||
#endif /* LWIP_DEBUG */
|
|
||||||
|
|
||||||
/** This is the actual memory used by the pools. */
|
|
||||||
static u8_t memp_memory[MEM_ALIGNMENT - 1
|
|
||||||
#define LWIP_MEMPOOL(name,num,size,desc) + ( (num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size) ) )
|
|
||||||
#include "lwip/memp_std.h"
|
|
||||||
];
|
|
||||||
|
|
||||||
#if MEMP_SANITY_CHECK
|
|
||||||
/**
|
|
||||||
* Check that memp-lists don't form a circle
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
memp_sanity(void)
|
|
||||||
{
|
|
||||||
s16_t i, c;
|
|
||||||
struct memp *m, *n;
|
|
||||||
|
|
||||||
for (i = 0; i < MEMP_MAX; i++) {
|
|
||||||
for (m = memp_tab[i]; m != NULL; m = m->next) {
|
|
||||||
c = 1;
|
|
||||||
for (n = memp_tab[i]; n != NULL; n = n->next) {
|
|
||||||
if (n == m && --c < 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
#endif /* MEMP_SANITY_CHECK*/
|
|
||||||
#if MEMP_OVERFLOW_CHECK
|
|
||||||
/**
|
|
||||||
* Check if a memp element was victim of an overflow
|
|
||||||
* (e.g. the restricted area after it has been altered)
|
|
||||||
*
|
|
||||||
* @param p the memp element to check
|
|
||||||
* @param memp_size the element size of the pool p comes from
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
memp_overflow_check_element(struct memp *p, u16_t memp_size)
|
|
||||||
{
|
|
||||||
u16_t k;
|
|
||||||
u8_t *m;
|
|
||||||
#if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0
|
|
||||||
m = (u8_t*)p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE_ALIGNED;
|
|
||||||
for (k = 0; k < MEMP_SANITY_REGION_BEFORE_ALIGNED; k++) {
|
|
||||||
if (m[k] != 0xcd) {
|
|
||||||
LWIP_ASSERT("detected memp underflow!", 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0
|
|
||||||
m = (u8_t*)p + MEMP_SIZE + memp_size;
|
|
||||||
for (k = 0; k < MEMP_SANITY_REGION_AFTER_ALIGNED; k++) {
|
|
||||||
if (m[k] != 0xcd) {
|
|
||||||
LWIP_ASSERT("detected memp overflow!", 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Do an overflow check for all elements in every pool.
|
|
||||||
*
|
|
||||||
* @see memp_overflow_check_element for a description of the check
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
memp_overflow_check_all(void)
|
|
||||||
{
|
|
||||||
u16_t i, j;
|
|
||||||
struct memp *p;
|
|
||||||
|
|
||||||
p = LWIP_MEM_ALIGN(memp_memory);
|
|
||||||
for (i = 0; i < MEMP_MAX; ++i) {
|
|
||||||
p = p;
|
|
||||||
for (j = 0; j < memp_num[i]; ++j) {
|
|
||||||
memp_overflow_check_element(p, memp_sizes[i]);
|
|
||||||
p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize the restricted areas of all memp elements in every pool.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
memp_overflow_init(void)
|
|
||||||
{
|
|
||||||
u16_t i, j;
|
|
||||||
struct memp *p;
|
|
||||||
u8_t *m;
|
|
||||||
|
|
||||||
p = LWIP_MEM_ALIGN(memp_memory);
|
|
||||||
for (i = 0; i < MEMP_MAX; ++i) {
|
|
||||||
p = p;
|
|
||||||
for (j = 0; j < memp_num[i]; ++j) {
|
|
||||||
#if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0
|
|
||||||
m = (u8_t*)p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE_ALIGNED;
|
|
||||||
memset(m, 0xcd, MEMP_SANITY_REGION_BEFORE_ALIGNED);
|
|
||||||
#endif
|
|
||||||
#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0
|
|
||||||
m = (u8_t*)p + MEMP_SIZE + memp_sizes[i];
|
|
||||||
memset(m, 0xcd, MEMP_SANITY_REGION_AFTER_ALIGNED);
|
|
||||||
#endif
|
|
||||||
p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif /* MEMP_OVERFLOW_CHECK */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize this module.
|
|
||||||
*
|
|
||||||
* Carves out memp_memory into linked lists for each pool-type.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
memp_init(void)
|
|
||||||
{
|
|
||||||
struct memp *memp;
|
|
||||||
u16_t i, j;
|
|
||||||
|
|
||||||
for (i = 0; i < MEMP_MAX; ++i) {
|
|
||||||
MEMP_STATS_AVAIL(used, i, 0);
|
|
||||||
MEMP_STATS_AVAIL(max, i, 0);
|
|
||||||
MEMP_STATS_AVAIL(err, i, 0);
|
|
||||||
MEMP_STATS_AVAIL(avail, i, memp_num[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
memp = LWIP_MEM_ALIGN(memp_memory);
|
|
||||||
/* for every pool: */
|
|
||||||
for (i = 0; i < MEMP_MAX; ++i) {
|
|
||||||
memp_tab[i] = NULL;
|
|
||||||
/* create a linked list of memp elements */
|
|
||||||
for (j = 0; j < memp_num[i]; ++j) {
|
|
||||||
memp->next = memp_tab[i];
|
|
||||||
memp_tab[i] = memp;
|
|
||||||
memp = (struct memp *)((u8_t *)memp + MEMP_SIZE + memp_sizes[i]
|
|
||||||
#if MEMP_OVERFLOW_CHECK
|
|
||||||
+ MEMP_SANITY_REGION_AFTER_ALIGNED
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#if MEMP_OVERFLOW_CHECK
|
|
||||||
memp_overflow_init();
|
|
||||||
/* check everything a first time to see if it worked */
|
|
||||||
memp_overflow_check_all();
|
|
||||||
#endif /* MEMP_OVERFLOW_CHECK */
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get an element from a specific pool.
|
|
||||||
*
|
|
||||||
* @param type the pool to get an element from
|
|
||||||
*
|
|
||||||
* the debug version has two more parameters:
|
|
||||||
* @param file file name calling this function
|
|
||||||
* @param line number of line where this function is called
|
|
||||||
*
|
|
||||||
* @return a pointer to the allocated memory or a NULL pointer on error
|
|
||||||
*/
|
|
||||||
void *
|
|
||||||
#if !MEMP_OVERFLOW_CHECK
|
|
||||||
memp_malloc(memp_t type)
|
|
||||||
#else
|
|
||||||
memp_malloc_fn(memp_t type, const char* file, const int line)
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
struct memp *memp;
|
|
||||||
SYS_ARCH_DECL_PROTECT(old_level);
|
|
||||||
|
|
||||||
LWIP_ERROR("memp_malloc: type < MEMP_MAX", (type < MEMP_MAX), return NULL;);
|
|
||||||
|
|
||||||
SYS_ARCH_PROTECT(old_level);
|
|
||||||
#if MEMP_OVERFLOW_CHECK >= 2
|
|
||||||
memp_overflow_check_all();
|
|
||||||
#endif /* MEMP_OVERFLOW_CHECK >= 2 */
|
|
||||||
|
|
||||||
memp = memp_tab[type];
|
|
||||||
|
|
||||||
if (memp != NULL) {
|
|
||||||
memp_tab[type] = memp->next;
|
|
||||||
#if MEMP_OVERFLOW_CHECK
|
|
||||||
memp->next = NULL;
|
|
||||||
memp->file = file;
|
|
||||||
memp->line = line;
|
|
||||||
#endif /* MEMP_OVERFLOW_CHECK */
|
|
||||||
MEMP_STATS_INC_USED(used, type);
|
|
||||||
LWIP_ASSERT("memp_malloc: memp properly aligned",
|
|
||||||
((mem_ptr_t)memp % MEM_ALIGNMENT) == 0);
|
|
||||||
memp = (struct memp*)((u8_t*)memp + MEMP_SIZE);
|
|
||||||
} else {
|
|
||||||
LWIP_DEBUGF(MEMP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("memp_malloc: out of memory in pool %s\n", memp_desc[type]));
|
|
||||||
MEMP_STATS_INC(err, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
SYS_ARCH_UNPROTECT(old_level);
|
|
||||||
|
|
||||||
return memp;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Put an element back into its pool.
|
|
||||||
*
|
|
||||||
* @param type the pool where to put mem
|
|
||||||
* @param mem the memp element to free
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
memp_free(memp_t type, void *mem)
|
|
||||||
{
|
|
||||||
struct memp *memp;
|
|
||||||
SYS_ARCH_DECL_PROTECT(old_level);
|
|
||||||
|
|
||||||
if (mem == NULL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
LWIP_ASSERT("memp_free: mem properly aligned",
|
|
||||||
((mem_ptr_t)mem % MEM_ALIGNMENT) == 0);
|
|
||||||
|
|
||||||
memp = (struct memp *)((u8_t*)mem - MEMP_SIZE);
|
|
||||||
|
|
||||||
SYS_ARCH_PROTECT(old_level);
|
|
||||||
#if MEMP_OVERFLOW_CHECK
|
|
||||||
#if MEMP_OVERFLOW_CHECK >= 2
|
|
||||||
memp_overflow_check_all();
|
|
||||||
#else
|
|
||||||
memp_overflow_check_element(memp, memp_sizes[type]);
|
|
||||||
#endif /* MEMP_OVERFLOW_CHECK >= 2 */
|
|
||||||
#endif /* MEMP_OVERFLOW_CHECK */
|
|
||||||
|
|
||||||
MEMP_STATS_DEC(used, type);
|
|
||||||
|
|
||||||
memp->next = memp_tab[type];
|
|
||||||
memp_tab[type] = memp;
|
|
||||||
|
|
||||||
#if MEMP_SANITY_CHECK
|
|
||||||
LWIP_ASSERT("memp sanity", memp_sanity());
|
|
||||||
#endif /* MEMP_SANITY_CHECK */
|
|
||||||
|
|
||||||
SYS_ARCH_UNPROTECT(old_level);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* MEMP_MEM_MALLOC */
|
|
|
@ -1,687 +0,0 @@
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
* lwIP network interface abstraction
|
|
||||||
*
|
|
||||||
**/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "lwip/opt.h"
|
|
||||||
|
|
||||||
#include "lwip/def.h"
|
|
||||||
#include "lwip/ip_addr.h"
|
|
||||||
#include "lwip/netif.h"
|
|
||||||
#include "lwip/tcp.h"
|
|
||||||
#include "lwip/snmp.h"
|
|
||||||
#include "lwip/igmp.h"
|
|
||||||
#include "netif/etharp.h"
|
|
||||||
#if ENABLE_LOOPBACK
|
|
||||||
#include "lwip/sys.h"
|
|
||||||
#if LWIP_NETIF_LOOPBACK_MULTITHREADING
|
|
||||||
#include "lwip/tcpip.h"
|
|
||||||
#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */
|
|
||||||
#endif /* ENABLE_LOOPBACK */
|
|
||||||
|
|
||||||
#if LWIP_AUTOIP
|
|
||||||
#include "lwip/autoip.h"
|
|
||||||
#endif /* LWIP_AUTOIP */
|
|
||||||
#if LWIP_DHCP
|
|
||||||
#include "lwip/dhcp.h"
|
|
||||||
#endif /* LWIP_DHCP */
|
|
||||||
|
|
||||||
#if LWIP_NETIF_STATUS_CALLBACK
|
|
||||||
#define NETIF_STATUS_CALLBACK(n) { if (n->status_callback) (n->status_callback)(n); }
|
|
||||||
#else
|
|
||||||
#define NETIF_STATUS_CALLBACK(n) { /* NOP */ }
|
|
||||||
#endif /* LWIP_NETIF_STATUS_CALLBACK */
|
|
||||||
|
|
||||||
#if LWIP_NETIF_LINK_CALLBACK
|
|
||||||
#define NETIF_LINK_CALLBACK(n) { if (n->link_callback) (n->link_callback)(n); }
|
|
||||||
#else
|
|
||||||
#define NETIF_LINK_CALLBACK(n) { /* NOP */ }
|
|
||||||
#endif /* LWIP_NETIF_LINK_CALLBACK */
|
|
||||||
|
|
||||||
struct netif *netif_list;
|
|
||||||
struct netif *netif_default;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a network interface to the list of lwIP netifs.
|
|
||||||
*
|
|
||||||
* @param netif a pre-allocated netif structure
|
|
||||||
* @param ipaddr IP address for the new netif
|
|
||||||
* @param netmask network mask for the new netif
|
|
||||||
* @param gw default gateway IP address for the new netif
|
|
||||||
* @param state opaque data passed to the new netif
|
|
||||||
* @param init callback function that initializes the interface
|
|
||||||
* @param input callback function that is called to pass
|
|
||||||
* ingress packets up in the protocol layer stack.
|
|
||||||
*
|
|
||||||
* @return netif, or NULL if failed.
|
|
||||||
*/
|
|
||||||
struct netif *
|
|
||||||
netif_add(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask,
|
|
||||||
struct ip_addr *gw,
|
|
||||||
void *state,
|
|
||||||
err_t (* init)(struct netif *netif),
|
|
||||||
err_t (* input)(struct pbuf *p, struct netif *netif))
|
|
||||||
{
|
|
||||||
static u8_t netifnum = 0;
|
|
||||||
|
|
||||||
/* reset new interface configuration state */
|
|
||||||
netif->ip_addr.addr = 0;
|
|
||||||
netif->netmask.addr = 0;
|
|
||||||
netif->gw.addr = 0;
|
|
||||||
netif->flags = 0;
|
|
||||||
#if LWIP_DHCP
|
|
||||||
/* netif not under DHCP control by default */
|
|
||||||
netif->dhcp = NULL;
|
|
||||||
#endif /* LWIP_DHCP */
|
|
||||||
#if LWIP_AUTOIP
|
|
||||||
/* netif not under AutoIP control by default */
|
|
||||||
netif->autoip = NULL;
|
|
||||||
#endif /* LWIP_AUTOIP */
|
|
||||||
#if LWIP_NETIF_STATUS_CALLBACK
|
|
||||||
netif->status_callback = NULL;
|
|
||||||
#endif /* LWIP_NETIF_STATUS_CALLBACK */
|
|
||||||
#if LWIP_NETIF_LINK_CALLBACK
|
|
||||||
netif->link_callback = NULL;
|
|
||||||
#endif /* LWIP_NETIF_LINK_CALLBACK */
|
|
||||||
#if LWIP_IGMP
|
|
||||||
netif->igmp_mac_filter = NULL;
|
|
||||||
#endif /* LWIP_IGMP */
|
|
||||||
#if ENABLE_LOOPBACK
|
|
||||||
netif->loop_first = NULL;
|
|
||||||
netif->loop_last = NULL;
|
|
||||||
#endif /* ENABLE_LOOPBACK */
|
|
||||||
|
|
||||||
/* remember netif specific state information data */
|
|
||||||
netif->state = state;
|
|
||||||
netif->num = netifnum++;
|
|
||||||
netif->input = input;
|
|
||||||
#if LWIP_NETIF_HWADDRHINT
|
|
||||||
netif->addr_hint = NULL;
|
|
||||||
#endif /* LWIP_NETIF_HWADDRHINT*/
|
|
||||||
#if ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS
|
|
||||||
netif->loop_cnt_current = 0;
|
|
||||||
#endif /* ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS */
|
|
||||||
|
|
||||||
netif_set_addr(netif, ipaddr, netmask, gw);
|
|
||||||
|
|
||||||
/* call user specified initialization function for netif */
|
|
||||||
if (init(netif) != ERR_OK) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* add this netif to the list */
|
|
||||||
netif->next = netif_list;
|
|
||||||
netif_list = netif;
|
|
||||||
snmp_inc_iflist();
|
|
||||||
|
|
||||||
#if LWIP_IGMP
|
|
||||||
/* start IGMP processing */
|
|
||||||
if (netif->flags & NETIF_FLAG_IGMP) {
|
|
||||||
igmp_start( netif);
|
|
||||||
}
|
|
||||||
#endif /* LWIP_IGMP */
|
|
||||||
|
|
||||||
LWIP_DEBUGF(NETIF_DEBUG, ("netif: added interface %c%c IP addr ",
|
|
||||||
netif->name[0], netif->name[1]));
|
|
||||||
ip_addr_debug_print(NETIF_DEBUG, ipaddr);
|
|
||||||
LWIP_DEBUGF(NETIF_DEBUG, (" netmask "));
|
|
||||||
ip_addr_debug_print(NETIF_DEBUG, netmask);
|
|
||||||
LWIP_DEBUGF(NETIF_DEBUG, (" gw "));
|
|
||||||
ip_addr_debug_print(NETIF_DEBUG, gw);
|
|
||||||
LWIP_DEBUGF(NETIF_DEBUG, ("\n"));
|
|
||||||
return netif;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Change IP address configuration for a network interface (including netmask
|
|
||||||
* and default gateway).
|
|
||||||
*
|
|
||||||
* @param netif the network interface to change
|
|
||||||
* @param ipaddr the new IP address
|
|
||||||
* @param netmask the new netmask
|
|
||||||
* @param gw the new default gateway
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
netif_set_addr(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask,
|
|
||||||
struct ip_addr *gw)
|
|
||||||
{
|
|
||||||
netif_set_ipaddr(netif, ipaddr);
|
|
||||||
netif_set_netmask(netif, netmask);
|
|
||||||
netif_set_gw(netif, gw);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove a network interface from the list of lwIP netifs.
|
|
||||||
*
|
|
||||||
* @param netif the network interface to remove
|
|
||||||
*/
|
|
||||||
void netif_remove(struct netif * netif)
|
|
||||||
{
|
|
||||||
if ( netif == NULL ) return;
|
|
||||||
|
|
||||||
#if LWIP_IGMP
|
|
||||||
/* stop IGMP processing */
|
|
||||||
if (netif->flags & NETIF_FLAG_IGMP) {
|
|
||||||
igmp_stop( netif);
|
|
||||||
}
|
|
||||||
#endif /* LWIP_IGMP */
|
|
||||||
|
|
||||||
snmp_delete_ipaddridx_tree(netif);
|
|
||||||
|
|
||||||
/* is it the first netif? */
|
|
||||||
if (netif_list == netif) {
|
|
||||||
netif_list = netif->next;
|
|
||||||
snmp_dec_iflist();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* look for netif further down the list */
|
|
||||||
struct netif * tmpNetif;
|
|
||||||
for (tmpNetif = netif_list; tmpNetif != NULL; tmpNetif = tmpNetif->next) {
|
|
||||||
if (tmpNetif->next == netif) {
|
|
||||||
tmpNetif->next = netif->next;
|
|
||||||
snmp_dec_iflist();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (tmpNetif == NULL)
|
|
||||||
return; /* we didn't find any netif today */
|
|
||||||
}
|
|
||||||
/* this netif is default? */
|
|
||||||
if (netif_default == netif)
|
|
||||||
/* reset default netif */
|
|
||||||
netif_set_default(NULL);
|
|
||||||
LWIP_DEBUGF( NETIF_DEBUG, ("netif_remove: removed netif\n") );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find a network interface by searching for its name
|
|
||||||
*
|
|
||||||
* @param name the name of the netif (like netif->name) plus concatenated number
|
|
||||||
* in ascii representation (e.g. 'en0')
|
|
||||||
*/
|
|
||||||
struct netif *
|
|
||||||
netif_find(char *name)
|
|
||||||
{
|
|
||||||
struct netif *netif;
|
|
||||||
u8_t num;
|
|
||||||
|
|
||||||
if (name == NULL) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
num = name[2] - '0';
|
|
||||||
|
|
||||||
for(netif = netif_list; netif != NULL; netif = netif->next) {
|
|
||||||
if (num == netif->num &&
|
|
||||||
name[0] == netif->name[0] &&
|
|
||||||
name[1] == netif->name[1]) {
|
|
||||||
LWIP_DEBUGF(NETIF_DEBUG, ("netif_find: found %c%c\n", name[0], name[1]));
|
|
||||||
return netif;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
LWIP_DEBUGF(NETIF_DEBUG, ("netif_find: didn't find %c%c\n", name[0], name[1]));
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Change the IP address of a network interface
|
|
||||||
*
|
|
||||||
* @param netif the network interface to change
|
|
||||||
* @param ipaddr the new IP address
|
|
||||||
*
|
|
||||||
* @note call netif_set_addr() if you also want to change netmask and
|
|
||||||
* default gateway
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
netif_set_ipaddr(struct netif *netif, struct ip_addr *ipaddr)
|
|
||||||
{
|
|
||||||
/* TODO: Handling of obsolete pcbs */
|
|
||||||
/* See: http://mail.gnu.org/archive/html/lwip-users/2003-03/msg00118.html */
|
|
||||||
#if LWIP_TCP
|
|
||||||
struct tcp_pcb *pcb;
|
|
||||||
struct tcp_pcb_listen *lpcb;
|
|
||||||
|
|
||||||
/* address is actually being changed? */
|
|
||||||
if ((ip_addr_cmp(ipaddr, &(netif->ip_addr))) == 0)
|
|
||||||
{
|
|
||||||
/* extern struct tcp_pcb *tcp_active_pcbs; defined by tcp.h */
|
|
||||||
LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: netif address being changed\n"));
|
|
||||||
pcb = tcp_active_pcbs;
|
|
||||||
while (pcb != NULL) {
|
|
||||||
/* PCB bound to current local interface address? */
|
|
||||||
if (ip_addr_cmp(&(pcb->local_ip), &(netif->ip_addr))) {
|
|
||||||
/* this connection must be aborted */
|
|
||||||
struct tcp_pcb *next = pcb->next;
|
|
||||||
LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: aborting TCP pcb %p\n", (void *)pcb));
|
|
||||||
tcp_abort(pcb);
|
|
||||||
pcb = next;
|
|
||||||
} else {
|
|
||||||
pcb = pcb->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
|
|
||||||
/* PCB bound to current local interface address? */
|
|
||||||
if ((!(ip_addr_isany(&(lpcb->local_ip)))) &&
|
|
||||||
(ip_addr_cmp(&(lpcb->local_ip), &(netif->ip_addr)))) {
|
|
||||||
/* The PCB is listening to the old ipaddr and
|
|
||||||
* is set to listen to the new one instead */
|
|
||||||
ip_addr_set(&(lpcb->local_ip), ipaddr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
snmp_delete_ipaddridx_tree(netif);
|
|
||||||
snmp_delete_iprteidx_tree(0,netif);
|
|
||||||
/* set new IP address to netif */
|
|
||||||
ip_addr_set(&(netif->ip_addr), ipaddr);
|
|
||||||
snmp_insert_ipaddridx_tree(netif);
|
|
||||||
snmp_insert_iprteidx_tree(0,netif);
|
|
||||||
|
|
||||||
LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: IP address of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
|
|
||||||
netif->name[0], netif->name[1],
|
|
||||||
ip4_addr1(&netif->ip_addr),
|
|
||||||
ip4_addr2(&netif->ip_addr),
|
|
||||||
ip4_addr3(&netif->ip_addr),
|
|
||||||
ip4_addr4(&netif->ip_addr)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Change the default gateway for a network interface
|
|
||||||
*
|
|
||||||
* @param netif the network interface to change
|
|
||||||
* @param gw the new default gateway
|
|
||||||
*
|
|
||||||
* @note call netif_set_addr() if you also want to change ip address and netmask
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
netif_set_gw(struct netif *netif, struct ip_addr *gw)
|
|
||||||
{
|
|
||||||
ip_addr_set(&(netif->gw), gw);
|
|
||||||
LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: GW address of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
|
|
||||||
netif->name[0], netif->name[1],
|
|
||||||
ip4_addr1(&netif->gw),
|
|
||||||
ip4_addr2(&netif->gw),
|
|
||||||
ip4_addr3(&netif->gw),
|
|
||||||
ip4_addr4(&netif->gw)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Change the netmask of a network interface
|
|
||||||
*
|
|
||||||
* @param netif the network interface to change
|
|
||||||
* @param netmask the new netmask
|
|
||||||
*
|
|
||||||
* @note call netif_set_addr() if you also want to change ip address and
|
|
||||||
* default gateway
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
netif_set_netmask(struct netif *netif, struct ip_addr *netmask)
|
|
||||||
{
|
|
||||||
snmp_delete_iprteidx_tree(0, netif);
|
|
||||||
/* set new netmask to netif */
|
|
||||||
ip_addr_set(&(netif->netmask), netmask);
|
|
||||||
snmp_insert_iprteidx_tree(0, netif);
|
|
||||||
LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: netmask of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
|
|
||||||
netif->name[0], netif->name[1],
|
|
||||||
ip4_addr1(&netif->netmask),
|
|
||||||
ip4_addr2(&netif->netmask),
|
|
||||||
ip4_addr3(&netif->netmask),
|
|
||||||
ip4_addr4(&netif->netmask)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#if LWIP_NETIF_HOSTNAME
|
|
||||||
void netif_set_hostname(struct netif *netif, char* hostname){
|
|
||||||
netif->hostname = hostname;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set a network interface as the default network interface
|
|
||||||
* (used to output all packets for which no specific route is found)
|
|
||||||
*
|
|
||||||
* @param netif the default network interface
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
netif_set_default(struct netif *netif)
|
|
||||||
{
|
|
||||||
if (netif == NULL)
|
|
||||||
{
|
|
||||||
/* remove default route */
|
|
||||||
snmp_delete_iprteidx_tree(1, netif);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* install default route */
|
|
||||||
snmp_insert_iprteidx_tree(1, netif);
|
|
||||||
}
|
|
||||||
netif_default = netif;
|
|
||||||
LWIP_DEBUGF(NETIF_DEBUG, ("netif: setting default interface %c%c\n",
|
|
||||||
netif ? netif->name[0] : '\'', netif ? netif->name[1] : '\''));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Bring an interface up, available for processing
|
|
||||||
* traffic.
|
|
||||||
*
|
|
||||||
* @note: Enabling DHCP on a down interface will make it come
|
|
||||||
* up once configured.
|
|
||||||
*
|
|
||||||
* @see dhcp_start()
|
|
||||||
*/
|
|
||||||
void netif_set_up(struct netif *netif)
|
|
||||||
{
|
|
||||||
if ( !(netif->flags & NETIF_FLAG_UP )) {
|
|
||||||
netif->flags |= NETIF_FLAG_UP;
|
|
||||||
|
|
||||||
#if LWIP_SNMP
|
|
||||||
snmp_get_sysuptime(&netif->ts);
|
|
||||||
#endif /* LWIP_SNMP */
|
|
||||||
|
|
||||||
NETIF_LINK_CALLBACK(netif);
|
|
||||||
NETIF_STATUS_CALLBACK(netif);
|
|
||||||
|
|
||||||
#if LWIP_ARP
|
|
||||||
/* For Ethernet network interfaces, we would like to send a "gratuitous ARP" */
|
|
||||||
if (netif->flags & NETIF_FLAG_ETHARP) {
|
|
||||||
etharp_gratuitous(netif);
|
|
||||||
}
|
|
||||||
#endif /* LWIP_ARP */
|
|
||||||
|
|
||||||
#if LWIP_IGMP
|
|
||||||
/* resend IGMP memberships */
|
|
||||||
if (netif->flags & NETIF_FLAG_IGMP) {
|
|
||||||
igmp_report_groups( netif);
|
|
||||||
}
|
|
||||||
#endif /* LWIP_IGMP */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Bring an interface down, disabling any traffic processing.
|
|
||||||
*
|
|
||||||
* @note: Enabling DHCP on a down interface will make it come
|
|
||||||
* up once configured.
|
|
||||||
*
|
|
||||||
* @see dhcp_start()
|
|
||||||
*/
|
|
||||||
void netif_set_down(struct netif *netif)
|
|
||||||
{
|
|
||||||
if ( netif->flags & NETIF_FLAG_UP )
|
|
||||||
{
|
|
||||||
netif->flags &= ~NETIF_FLAG_UP;
|
|
||||||
#if LWIP_SNMP
|
|
||||||
snmp_get_sysuptime(&netif->ts);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
NETIF_LINK_CALLBACK(netif);
|
|
||||||
NETIF_STATUS_CALLBACK(netif);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ask if an interface is up
|
|
||||||
*/
|
|
||||||
u8_t netif_is_up(struct netif *netif)
|
|
||||||
{
|
|
||||||
return (netif->flags & NETIF_FLAG_UP)?1:0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if LWIP_NETIF_STATUS_CALLBACK
|
|
||||||
/**
|
|
||||||
* Set callback to be called when interface is brought up/down
|
|
||||||
*/
|
|
||||||
void netif_set_status_callback(struct netif *netif, void (* status_callback)(struct netif *netif ))
|
|
||||||
{
|
|
||||||
if ( netif )
|
|
||||||
netif->status_callback = status_callback;
|
|
||||||
}
|
|
||||||
#endif /* LWIP_NETIF_STATUS_CALLBACK */
|
|
||||||
|
|
||||||
#if LWIP_NETIF_LINK_CALLBACK
|
|
||||||
/**
|
|
||||||
* Called by a driver when its link goes up
|
|
||||||
*/
|
|
||||||
void netif_set_link_up(struct netif *netif )
|
|
||||||
{
|
|
||||||
netif->flags |= NETIF_FLAG_LINK_UP;
|
|
||||||
|
|
||||||
#if LWIP_DHCP
|
|
||||||
if (netif->dhcp) {
|
|
||||||
dhcp_network_changed(netif);
|
|
||||||
}
|
|
||||||
#endif /* LWIP_DHCP */
|
|
||||||
|
|
||||||
#if LWIP_AUTOIP
|
|
||||||
if (netif->autoip) {
|
|
||||||
autoip_network_changed(netif);
|
|
||||||
}
|
|
||||||
#endif /* LWIP_AUTOIP */
|
|
||||||
|
|
||||||
if (netif->flags & NETIF_FLAG_UP) {
|
|
||||||
#if LWIP_ARP
|
|
||||||
/* For Ethernet network interfaces, we would like to send a "gratuitous ARP" */
|
|
||||||
if (netif->flags & NETIF_FLAG_ETHARP) {
|
|
||||||
etharp_gratuitous(netif);
|
|
||||||
}
|
|
||||||
#endif /* LWIP_ARP */
|
|
||||||
|
|
||||||
#if LWIP_IGMP
|
|
||||||
/* resend IGMP memberships */
|
|
||||||
if (netif->flags & NETIF_FLAG_IGMP) {
|
|
||||||
igmp_report_groups( netif);
|
|
||||||
}
|
|
||||||
#endif /* LWIP_IGMP */
|
|
||||||
}
|
|
||||||
NETIF_LINK_CALLBACK(netif);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called by a driver when its link goes down
|
|
||||||
*/
|
|
||||||
void netif_set_link_down(struct netif *netif )
|
|
||||||
{
|
|
||||||
netif->flags &= ~NETIF_FLAG_LINK_UP;
|
|
||||||
NETIF_LINK_CALLBACK(netif);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ask if a link is up
|
|
||||||
*/
|
|
||||||
u8_t netif_is_link_up(struct netif *netif)
|
|
||||||
{
|
|
||||||
return (netif->flags & NETIF_FLAG_LINK_UP) ? 1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set callback to be called when link is brought up/down
|
|
||||||
*/
|
|
||||||
void netif_set_link_callback(struct netif *netif, void (* link_callback)(struct netif *netif ))
|
|
||||||
{
|
|
||||||
if (netif) {
|
|
||||||
netif->link_callback = link_callback;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif /* LWIP_NETIF_LINK_CALLBACK */
|
|
||||||
|
|
||||||
#if ENABLE_LOOPBACK
|
|
||||||
/**
|
|
||||||
* Send an IP packet to be received on the same netif (loopif-like).
|
|
||||||
* The pbuf is simply copied and handed back to netif->input.
|
|
||||||
* In multithreaded mode, this is done directly since netif->input must put
|
|
||||||
* the packet on a queue.
|
|
||||||
* In callback mode, the packet is put on an internal queue and is fed to
|
|
||||||
* netif->input by netif_poll().
|
|
||||||
*
|
|
||||||
* @param netif the lwip network interface structure
|
|
||||||
* @param p the (IP) packet to 'send'
|
|
||||||
* @param ipaddr the ip address to send the packet to (not used)
|
|
||||||
* @return ERR_OK if the packet has been sent
|
|
||||||
* ERR_MEM if the pbuf used to copy the packet couldn't be allocated
|
|
||||||
*/
|
|
||||||
err_t
|
|
||||||
netif_loop_output(struct netif *netif, struct pbuf *p,
|
|
||||||
struct ip_addr *ipaddr)
|
|
||||||
{
|
|
||||||
struct pbuf *r;
|
|
||||||
err_t err;
|
|
||||||
struct pbuf *last;
|
|
||||||
#if LWIP_LOOPBACK_MAX_PBUFS
|
|
||||||
u8_t clen = 0;
|
|
||||||
#endif /* LWIP_LOOPBACK_MAX_PBUFS */
|
|
||||||
SYS_ARCH_DECL_PROTECT(lev);
|
|
||||||
LWIP_UNUSED_ARG(ipaddr);
|
|
||||||
|
|
||||||
/* Allocate a new pbuf */
|
|
||||||
r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM);
|
|
||||||
if (r == NULL) {
|
|
||||||
return ERR_MEM;
|
|
||||||
}
|
|
||||||
#if LWIP_LOOPBACK_MAX_PBUFS
|
|
||||||
clen = pbuf_clen(r);
|
|
||||||
/* check for overflow or too many pbuf on queue */
|
|
||||||
if(((netif->loop_cnt_current + clen) < netif->loop_cnt_current) ||
|
|
||||||
((netif->loop_cnt_current + clen) > LWIP_LOOPBACK_MAX_PBUFS)) {
|
|
||||||
pbuf_free(r);
|
|
||||||
r = NULL;
|
|
||||||
return ERR_MEM;
|
|
||||||
}
|
|
||||||
netif->loop_cnt_current += clen;
|
|
||||||
#endif /* LWIP_LOOPBACK_MAX_PBUFS */
|
|
||||||
|
|
||||||
/* Copy the whole pbuf queue p into the single pbuf r */
|
|
||||||
if ((err = pbuf_copy(r, p)) != ERR_OK) {
|
|
||||||
pbuf_free(r);
|
|
||||||
r = NULL;
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Put the packet on a linked list which gets emptied through calling
|
|
||||||
netif_poll(). */
|
|
||||||
|
|
||||||
/* let last point to the last pbuf in chain r */
|
|
||||||
for (last = r; last->next != NULL; last = last->next);
|
|
||||||
|
|
||||||
SYS_ARCH_PROTECT(lev);
|
|
||||||
if(netif->loop_first != NULL) {
|
|
||||||
LWIP_ASSERT("if first != NULL, last must also be != NULL", netif->loop_last != NULL);
|
|
||||||
netif->loop_last->next = r;
|
|
||||||
netif->loop_last = last;
|
|
||||||
} else {
|
|
||||||
netif->loop_first = r;
|
|
||||||
netif->loop_last = last;
|
|
||||||
}
|
|
||||||
SYS_ARCH_UNPROTECT(lev);
|
|
||||||
|
|
||||||
#if LWIP_NETIF_LOOPBACK_MULTITHREADING
|
|
||||||
/* For multithreading environment, schedule a call to netif_poll */
|
|
||||||
tcpip_callback((void (*)(void *))(netif_poll), netif);
|
|
||||||
#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */
|
|
||||||
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Call netif_poll() in the main loop of your application. This is to prevent
|
|
||||||
* reentering non-reentrant functions like tcp_input(). Packets passed to
|
|
||||||
* netif_loop_output() are put on a list that is passed to netif->input() by
|
|
||||||
* netif_poll().
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
netif_poll(struct netif *netif)
|
|
||||||
{
|
|
||||||
struct pbuf *in;
|
|
||||||
SYS_ARCH_DECL_PROTECT(lev);
|
|
||||||
|
|
||||||
do {
|
|
||||||
/* Get a packet from the list. With SYS_LIGHTWEIGHT_PROT=1, this is protected */
|
|
||||||
SYS_ARCH_PROTECT(lev);
|
|
||||||
in = netif->loop_first;
|
|
||||||
if(in != NULL) {
|
|
||||||
struct pbuf *in_end = in;
|
|
||||||
#if LWIP_LOOPBACK_MAX_PBUFS
|
|
||||||
u8_t clen = pbuf_clen(in);
|
|
||||||
/* adjust the number of pbufs on queue */
|
|
||||||
LWIP_ASSERT("netif->loop_cnt_current underflow",
|
|
||||||
((netif->loop_cnt_current - clen) < netif->loop_cnt_current));
|
|
||||||
netif->loop_cnt_current -= clen;
|
|
||||||
#endif /* LWIP_LOOPBACK_MAX_PBUFS */
|
|
||||||
while(in_end->len != in_end->tot_len) {
|
|
||||||
LWIP_ASSERT("bogus pbuf: len != tot_len but next == NULL!", in_end->next != NULL);
|
|
||||||
in_end = in_end->next;
|
|
||||||
}
|
|
||||||
/* 'in_end' now points to the last pbuf from 'in' */
|
|
||||||
if(in_end == netif->loop_last) {
|
|
||||||
/* this was the last pbuf in the list */
|
|
||||||
netif->loop_first = netif->loop_last = NULL;
|
|
||||||
} else {
|
|
||||||
/* pop the pbuf off the list */
|
|
||||||
netif->loop_first = in_end->next;
|
|
||||||
LWIP_ASSERT("should not be null since first != last!", netif->loop_first != NULL);
|
|
||||||
}
|
|
||||||
/* De-queue the pbuf from its successors on the 'loop_' list. */
|
|
||||||
in_end->next = NULL;
|
|
||||||
}
|
|
||||||
SYS_ARCH_UNPROTECT(lev);
|
|
||||||
|
|
||||||
if(in != NULL) {
|
|
||||||
/* loopback packets are always IP packets! */
|
|
||||||
if(ip_input(in, netif) != ERR_OK) {
|
|
||||||
pbuf_free(in);
|
|
||||||
}
|
|
||||||
/* Don't reference the packet any more! */
|
|
||||||
in = NULL;
|
|
||||||
}
|
|
||||||
/* go on while there is a packet on the list */
|
|
||||||
} while(netif->loop_first != NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if !LWIP_NETIF_LOOPBACK_MULTITHREADING
|
|
||||||
/**
|
|
||||||
* Calls netif_poll() for every netif on the netif_list.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
netif_poll_all(void)
|
|
||||||
{
|
|
||||||
struct netif *netif = netif_list;
|
|
||||||
/* loop through netifs */
|
|
||||||
while (netif != NULL) {
|
|
||||||
netif_poll(netif);
|
|
||||||
/* proceed to next network interface */
|
|
||||||
netif = netif->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */
|
|
||||||
#endif /* ENABLE_LOOPBACK */
|
|
|
@ -1,929 +0,0 @@
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
* Packet buffer management
|
|
||||||
*
|
|
||||||
* Packets are built from the pbuf data structure. It supports dynamic
|
|
||||||
* memory allocation for packet contents or can reference externally
|
|
||||||
* managed packet contents both in RAM and ROM. Quick allocation for
|
|
||||||
* incoming packets is provided through pools with fixed sized pbufs.
|
|
||||||
*
|
|
||||||
* A packet may span over multiple pbufs, chained as a singly linked
|
|
||||||
* list. This is called a "pbuf chain".
|
|
||||||
*
|
|
||||||
* Multiple packets may be queued, also using this singly linked list.
|
|
||||||
* This is called a "packet queue".
|
|
||||||
*
|
|
||||||
* So, a packet queue consists of one or more pbuf chains, each of
|
|
||||||
* which consist of one or more pbufs. CURRENTLY, PACKET QUEUES ARE
|
|
||||||
* NOT SUPPORTED!!! Use helper structs to queue multiple packets.
|
|
||||||
*
|
|
||||||
* The differences between a pbuf chain and a packet queue are very
|
|
||||||
* precise but subtle.
|
|
||||||
*
|
|
||||||
* The last pbuf of a packet has a ->tot_len field that equals the
|
|
||||||
* ->len field. It can be found by traversing the list. If the last
|
|
||||||
* pbuf of a packet has a ->next field other than NULL, more packets
|
|
||||||
* are on the queue.
|
|
||||||
*
|
|
||||||
* Therefore, looping through a pbuf of a single packet, has an
|
|
||||||
* loop end condition (tot_len == p->len), NOT (next == NULL).
|
|
||||||
**/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "lwip/opt.h"
|
|
||||||
|
|
||||||
#include "lwip/stats.h"
|
|
||||||
#include "lwip/def.h"
|
|
||||||
#include "lwip/mem.h"
|
|
||||||
#include "lwip/memp.h"
|
|
||||||
#include "lwip/pbuf.h"
|
|
||||||
#include "lwip/sys.h"
|
|
||||||
#include "arch/perf.h"
|
|
||||||
#if TCP_QUEUE_OOSEQ
|
|
||||||
#include "lwip/tcp.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#define SIZEOF_STRUCT_PBUF LWIP_MEM_ALIGN_SIZE(sizeof(struct pbuf))
|
|
||||||
/* Since the pool is created in memp, PBUF_POOL_BUFSIZE will be automatically
|
|
||||||
aligned there. Therefore, PBUF_POOL_BUFSIZE_ALIGNED can be used here. */
|
|
||||||
#define PBUF_POOL_BUFSIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE)
|
|
||||||
|
|
||||||
#if !TCP_QUEUE_OOSEQ || NO_SYS
|
|
||||||
#define PBUF_POOL_IS_EMPTY()
|
|
||||||
#else /* !TCP_QUEUE_OOSEQ || NO_SYS */
|
|
||||||
/** Define this to 0 to prevent freeing ooseq pbufs when the PBUF_POOL is empty */
|
|
||||||
#ifndef PBUF_POOL_FREE_OOSEQ
|
|
||||||
#define PBUF_POOL_FREE_OOSEQ 1
|
|
||||||
#endif /* PBUF_POOL_FREE_OOSEQ */
|
|
||||||
|
|
||||||
#if PBUF_POOL_FREE_OOSEQ
|
|
||||||
#include "lwip/tcpip.h"
|
|
||||||
#define PBUF_POOL_IS_EMPTY() pbuf_pool_is_empty()
|
|
||||||
static u8_t pbuf_free_ooseq_queued;
|
|
||||||
/**
|
|
||||||
* Attempt to reclaim some memory from queued out-of-sequence TCP segments
|
|
||||||
* if we run out of pool pbufs. It's better to give priority to new packets
|
|
||||||
* if we're running out.
|
|
||||||
*
|
|
||||||
* This must be done in the correct thread context therefore this function
|
|
||||||
* can only be used with NO_SYS=0 and through tcpip_callback.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
pbuf_free_ooseq(void* arg)
|
|
||||||
{
|
|
||||||
struct tcp_pcb* pcb;
|
|
||||||
SYS_ARCH_DECL_PROTECT(old_level);
|
|
||||||
LWIP_UNUSED_ARG(arg);
|
|
||||||
|
|
||||||
SYS_ARCH_PROTECT(old_level);
|
|
||||||
pbuf_free_ooseq_queued = 0;
|
|
||||||
SYS_ARCH_UNPROTECT(old_level);
|
|
||||||
|
|
||||||
for (pcb = tcp_active_pcbs; NULL != pcb; pcb = pcb->next) {
|
|
||||||
if (NULL != pcb->ooseq) {
|
|
||||||
/** Free the ooseq pbufs of one PCB only */
|
|
||||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free_ooseq: freeing out-of-sequence pbufs\n"));
|
|
||||||
tcp_segs_free(pcb->ooseq);
|
|
||||||
pcb->ooseq = NULL;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Queue a call to pbuf_free_ooseq if not already queued. */
|
|
||||||
static void
|
|
||||||
pbuf_pool_is_empty(void)
|
|
||||||
{
|
|
||||||
u8_t queued;
|
|
||||||
SYS_ARCH_DECL_PROTECT(old_level);
|
|
||||||
|
|
||||||
SYS_ARCH_PROTECT(old_level);
|
|
||||||
queued = pbuf_free_ooseq_queued;
|
|
||||||
pbuf_free_ooseq_queued = 1;
|
|
||||||
SYS_ARCH_UNPROTECT(old_level);
|
|
||||||
|
|
||||||
if(!queued) {
|
|
||||||
/* queue a call to pbuf_free_ooseq if not already queued */
|
|
||||||
if(tcpip_callback_with_block(pbuf_free_ooseq, NULL, 0) != ERR_OK) {
|
|
||||||
SYS_ARCH_PROTECT(old_level);
|
|
||||||
pbuf_free_ooseq_queued = 0;
|
|
||||||
SYS_ARCH_UNPROTECT(old_level);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif /* PBUF_POOL_FREE_OOSEQ */
|
|
||||||
#endif /* !TCP_QUEUE_OOSEQ || NO_SYS */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Allocates a pbuf of the given type (possibly a chain for PBUF_POOL type).
|
|
||||||
*
|
|
||||||
* The actual memory allocated for the pbuf is determined by the
|
|
||||||
* layer at which the pbuf is allocated and the requested size
|
|
||||||
* (from the size parameter).
|
|
||||||
*
|
|
||||||
* @param layer flag to define header size
|
|
||||||
* @param length size of the pbuf's payload
|
|
||||||
* @param type this parameter decides how and where the pbuf
|
|
||||||
* should be allocated as follows:
|
|
||||||
*
|
|
||||||
* - PBUF_RAM: buffer memory for pbuf is allocated as one large
|
|
||||||
* chunk. This includes protocol headers as well.
|
|
||||||
* - PBUF_ROM: no buffer memory is allocated for the pbuf, even for
|
|
||||||
* protocol headers. Additional headers must be prepended
|
|
||||||
* by allocating another pbuf and chain in to the front of
|
|
||||||
* the ROM pbuf. It is assumed that the memory used is really
|
|
||||||
* similar to ROM in that it is immutable and will not be
|
|
||||||
* changed. Memory which is dynamic should generally not
|
|
||||||
* be attached to PBUF_ROM pbufs. Use PBUF_REF instead.
|
|
||||||
* - PBUF_REF: no buffer memory is allocated for the pbuf, even for
|
|
||||||
* protocol headers. It is assumed that the pbuf is only
|
|
||||||
* being used in a single thread. If the pbuf gets queued,
|
|
||||||
* then pbuf_take should be called to copy the buffer.
|
|
||||||
* - PBUF_POOL: the pbuf is allocated as a pbuf chain, with pbufs from
|
|
||||||
* the pbuf pool that is allocated during pbuf_init().
|
|
||||||
*
|
|
||||||
* @return the allocated pbuf. If multiple pbufs where allocated, this
|
|
||||||
* is the first pbuf of a pbuf chain.
|
|
||||||
*/
|
|
||||||
struct pbuf *
|
|
||||||
pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
|
|
||||||
{
|
|
||||||
struct pbuf *p, *q, *r;
|
|
||||||
u16_t offset;
|
|
||||||
s32_t rem_len; /* remaining length */
|
|
||||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F")\n", length));
|
|
||||||
|
|
||||||
/* determine header offset */
|
|
||||||
offset = 0;
|
|
||||||
switch (layer) {
|
|
||||||
case PBUF_TRANSPORT:
|
|
||||||
/* add room for transport (often TCP) layer header */
|
|
||||||
offset += PBUF_TRANSPORT_HLEN;
|
|
||||||
/* FALLTHROUGH */
|
|
||||||
case PBUF_IP:
|
|
||||||
/* add room for IP layer header */
|
|
||||||
offset += PBUF_IP_HLEN;
|
|
||||||
/* FALLTHROUGH */
|
|
||||||
case PBUF_LINK:
|
|
||||||
/* add room for link layer header */
|
|
||||||
offset += PBUF_LINK_HLEN;
|
|
||||||
break;
|
|
||||||
case PBUF_RAW:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
LWIP_ASSERT("pbuf_alloc: bad pbuf layer", 0);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
case PBUF_POOL:
|
|
||||||
/* allocate head of pbuf chain into p */
|
|
||||||
p = memp_malloc(MEMP_PBUF_POOL);
|
|
||||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc: allocated pbuf %p\n", (void *)p));
|
|
||||||
if (p == NULL) {
|
|
||||||
PBUF_POOL_IS_EMPTY();
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
p->type = type;
|
|
||||||
p->next = NULL;
|
|
||||||
|
|
||||||
/* make the payload pointer point 'offset' bytes into pbuf data memory */
|
|
||||||
p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + (SIZEOF_STRUCT_PBUF + offset)));
|
|
||||||
LWIP_ASSERT("pbuf_alloc: pbuf p->payload properly aligned",
|
|
||||||
((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0);
|
|
||||||
/* the total length of the pbuf chain is the requested size */
|
|
||||||
p->tot_len = length;
|
|
||||||
/* set the length of the first pbuf in the chain */
|
|
||||||
p->len = LWIP_MIN(length, PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset));
|
|
||||||
LWIP_ASSERT("check p->payload + p->len does not overflow pbuf",
|
|
||||||
((u8_t*)p->payload + p->len <=
|
|
||||||
(u8_t*)p + SIZEOF_STRUCT_PBUF + PBUF_POOL_BUFSIZE_ALIGNED));
|
|
||||||
LWIP_ASSERT("PBUF_POOL_BUFSIZE must be bigger than MEM_ALIGNMENT",
|
|
||||||
(PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset)) > 0 );
|
|
||||||
/* set reference count (needed here in case we fail) */
|
|
||||||
p->ref = 1;
|
|
||||||
|
|
||||||
/* now allocate the tail of the pbuf chain */
|
|
||||||
|
|
||||||
/* remember first pbuf for linkage in next iteration */
|
|
||||||
r = p;
|
|
||||||
/* remaining length to be allocated */
|
|
||||||
rem_len = length - p->len;
|
|
||||||
/* any remaining pbufs to be allocated? */
|
|
||||||
while (rem_len > 0) {
|
|
||||||
q = memp_malloc(MEMP_PBUF_POOL);
|
|
||||||
if (q == NULL) {
|
|
||||||
PBUF_POOL_IS_EMPTY();
|
|
||||||
/* free chain so far allocated */
|
|
||||||
pbuf_free(p);
|
|
||||||
/* bail out unsuccesfully */
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
q->type = type;
|
|
||||||
q->flags = 0;
|
|
||||||
q->next = NULL;
|
|
||||||
/* make previous pbuf point to this pbuf */
|
|
||||||
r->next = q;
|
|
||||||
/* set total length of this pbuf and next in chain */
|
|
||||||
LWIP_ASSERT("rem_len < max_u16_t", rem_len < 0xffff);
|
|
||||||
q->tot_len = (u16_t)rem_len;
|
|
||||||
/* this pbuf length is pool size, unless smaller sized tail */
|
|
||||||
q->len = LWIP_MIN((u16_t)rem_len, PBUF_POOL_BUFSIZE_ALIGNED);
|
|
||||||
q->payload = (void *)((u8_t *)q + SIZEOF_STRUCT_PBUF);
|
|
||||||
LWIP_ASSERT("pbuf_alloc: pbuf q->payload properly aligned",
|
|
||||||
((mem_ptr_t)q->payload % MEM_ALIGNMENT) == 0);
|
|
||||||
LWIP_ASSERT("check p->payload + p->len does not overflow pbuf",
|
|
||||||
((u8_t*)p->payload + p->len <=
|
|
||||||
(u8_t*)p + SIZEOF_STRUCT_PBUF + PBUF_POOL_BUFSIZE_ALIGNED));
|
|
||||||
q->ref = 1;
|
|
||||||
/* calculate remaining length to be allocated */
|
|
||||||
rem_len -= q->len;
|
|
||||||
/* remember this pbuf for linkage in next iteration */
|
|
||||||
r = q;
|
|
||||||
}
|
|
||||||
/* end of chain */
|
|
||||||
/*r->next = NULL;*/
|
|
||||||
|
|
||||||
break;
|
|
||||||
case PBUF_RAM:
|
|
||||||
/* If pbuf is to be allocated in RAM, allocate memory for it. */
|
|
||||||
p = (struct pbuf*)mem_malloc(LWIP_MEM_ALIGN_SIZE(SIZEOF_STRUCT_PBUF + offset) + LWIP_MEM_ALIGN_SIZE(length));
|
|
||||||
if (p == NULL) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
/* Set up internal structure of the pbuf. */
|
|
||||||
p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + SIZEOF_STRUCT_PBUF + offset));
|
|
||||||
p->len = p->tot_len = length;
|
|
||||||
p->next = NULL;
|
|
||||||
p->type = type;
|
|
||||||
|
|
||||||
LWIP_ASSERT("pbuf_alloc: pbuf->payload properly aligned",
|
|
||||||
((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0);
|
|
||||||
break;
|
|
||||||
/* pbuf references existing (non-volatile static constant) ROM payload? */
|
|
||||||
case PBUF_ROM:
|
|
||||||
/* pbuf references existing (externally allocated) RAM payload? */
|
|
||||||
case PBUF_REF:
|
|
||||||
/* only allocate memory for the pbuf structure */
|
|
||||||
p = memp_malloc(MEMP_PBUF);
|
|
||||||
if (p == NULL) {
|
|
||||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
|
|
||||||
("pbuf_alloc: Could not allocate MEMP_PBUF for PBUF_%s.\n",
|
|
||||||
(type == PBUF_ROM) ? "ROM" : "REF"));
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
/* caller must set this field properly, afterwards */
|
|
||||||
p->payload = NULL;
|
|
||||||
p->len = p->tot_len = length;
|
|
||||||
p->next = NULL;
|
|
||||||
p->type = type;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
LWIP_ASSERT("pbuf_alloc: erroneous type", 0);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
/* set reference count */
|
|
||||||
p->ref = 1;
|
|
||||||
/* set flags */
|
|
||||||
p->flags = 0;
|
|
||||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F") == %p\n", length, (void *)p));
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shrink a pbuf chain to a desired length.
|
|
||||||
*
|
|
||||||
* @param p pbuf to shrink.
|
|
||||||
* @param new_len desired new length of pbuf chain
|
|
||||||
*
|
|
||||||
* Depending on the desired length, the first few pbufs in a chain might
|
|
||||||
* be skipped and left unchanged. The new last pbuf in the chain will be
|
|
||||||
* resized, and any remaining pbufs will be freed.
|
|
||||||
*
|
|
||||||
* @note If the pbuf is ROM/REF, only the ->tot_len and ->len fields are adjusted.
|
|
||||||
* @note May not be called on a packet queue.
|
|
||||||
*
|
|
||||||
* @note Despite its name, pbuf_realloc cannot grow the size of a pbuf (chain).
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
pbuf_realloc(struct pbuf *p, u16_t new_len)
|
|
||||||
{
|
|
||||||
struct pbuf *q;
|
|
||||||
u16_t rem_len; /* remaining length */
|
|
||||||
s32_t grow;
|
|
||||||
|
|
||||||
LWIP_ASSERT("pbuf_realloc: p != NULL", p != NULL);
|
|
||||||
LWIP_ASSERT("pbuf_realloc: sane p->type", p->type == PBUF_POOL ||
|
|
||||||
p->type == PBUF_ROM ||
|
|
||||||
p->type == PBUF_RAM ||
|
|
||||||
p->type == PBUF_REF);
|
|
||||||
|
|
||||||
/* desired length larger than current length? */
|
|
||||||
if (new_len >= p->tot_len) {
|
|
||||||
/* enlarging not yet supported */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* the pbuf chain grows by (new_len - p->tot_len) bytes
|
|
||||||
* (which may be negative in case of shrinking) */
|
|
||||||
grow = new_len - p->tot_len;
|
|
||||||
|
|
||||||
/* first, step over any pbufs that should remain in the chain */
|
|
||||||
rem_len = new_len;
|
|
||||||
q = p;
|
|
||||||
/* should this pbuf be kept? */
|
|
||||||
while (rem_len > q->len) {
|
|
||||||
/* decrease remaining length by pbuf length */
|
|
||||||
rem_len -= q->len;
|
|
||||||
/* decrease total length indicator */
|
|
||||||
LWIP_ASSERT("grow < max_u16_t", grow < 0xffff);
|
|
||||||
q->tot_len += (u16_t)grow;
|
|
||||||
/* proceed to next pbuf in chain */
|
|
||||||
q = q->next;
|
|
||||||
LWIP_ASSERT("pbuf_realloc: q != NULL", q != NULL);
|
|
||||||
}
|
|
||||||
/* we have now reached the new last pbuf (in q) */
|
|
||||||
/* rem_len == desired length for pbuf q */
|
|
||||||
|
|
||||||
/* shrink allocated memory for PBUF_RAM */
|
|
||||||
/* (other types merely adjust their length fields */
|
|
||||||
if ((q->type == PBUF_RAM) && (rem_len != q->len)) {
|
|
||||||
/* reallocate and adjust the length of the pbuf that will be split */
|
|
||||||
q = mem_realloc(q, (u8_t *)q->payload - (u8_t *)q + rem_len);
|
|
||||||
LWIP_ASSERT("mem_realloc give q == NULL", q != NULL);
|
|
||||||
}
|
|
||||||
/* adjust length fields for new last pbuf */
|
|
||||||
q->len = rem_len;
|
|
||||||
q->tot_len = q->len;
|
|
||||||
|
|
||||||
/* any remaining pbufs in chain? */
|
|
||||||
if (q->next != NULL) {
|
|
||||||
/* free remaining pbufs in chain */
|
|
||||||
pbuf_free(q->next);
|
|
||||||
}
|
|
||||||
/* q is last packet in chain */
|
|
||||||
q->next = NULL;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adjusts the payload pointer to hide or reveal headers in the payload.
|
|
||||||
*
|
|
||||||
* Adjusts the ->payload pointer so that space for a header
|
|
||||||
* (dis)appears in the pbuf payload.
|
|
||||||
*
|
|
||||||
* The ->payload, ->tot_len and ->len fields are adjusted.
|
|
||||||
*
|
|
||||||
* @param p pbuf to change the header size.
|
|
||||||
* @param header_size_increment Number of bytes to increment header size which
|
|
||||||
* increases the size of the pbuf. New space is on the front.
|
|
||||||
* (Using a negative value decreases the header size.)
|
|
||||||
* If hdr_size_inc is 0, this function does nothing and returns succesful.
|
|
||||||
*
|
|
||||||
* PBUF_ROM and PBUF_REF type buffers cannot have their sizes increased, so
|
|
||||||
* the call will fail. A check is made that the increase in header size does
|
|
||||||
* not move the payload pointer in front of the start of the buffer.
|
|
||||||
* @return non-zero on failure, zero on success.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
u8_t
|
|
||||||
pbuf_header(struct pbuf *p, s16_t header_size_increment)
|
|
||||||
{
|
|
||||||
u16_t type;
|
|
||||||
void *payload;
|
|
||||||
u16_t increment_magnitude;
|
|
||||||
|
|
||||||
LWIP_ASSERT("p != NULL", p != NULL);
|
|
||||||
if ((header_size_increment == 0) || (p == NULL))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (header_size_increment < 0){
|
|
||||||
increment_magnitude = -header_size_increment;
|
|
||||||
/* Check that we aren't going to move off the end of the pbuf */
|
|
||||||
LWIP_ERROR("increment_magnitude <= p->len", (increment_magnitude <= p->len), return 1;);
|
|
||||||
} else {
|
|
||||||
increment_magnitude = header_size_increment;
|
|
||||||
#if 0
|
|
||||||
/* Can't assert these as some callers speculatively call
|
|
||||||
pbuf_header() to see if it's OK. Will return 1 below instead. */
|
|
||||||
/* Check that we've got the correct type of pbuf to work with */
|
|
||||||
LWIP_ASSERT("p->type == PBUF_RAM || p->type == PBUF_POOL",
|
|
||||||
p->type == PBUF_RAM || p->type == PBUF_POOL);
|
|
||||||
/* Check that we aren't going to move off the beginning of the pbuf */
|
|
||||||
LWIP_ASSERT("p->payload - increment_magnitude >= p + SIZEOF_STRUCT_PBUF",
|
|
||||||
(u8_t *)p->payload - increment_magnitude >= (u8_t *)p + SIZEOF_STRUCT_PBUF);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
type = p->type;
|
|
||||||
/* remember current payload pointer */
|
|
||||||
payload = p->payload;
|
|
||||||
|
|
||||||
/* pbuf types containing payloads? */
|
|
||||||
if (type == PBUF_RAM || type == PBUF_POOL) {
|
|
||||||
/* set new payload pointer */
|
|
||||||
p->payload = (u8_t *)p->payload - header_size_increment;
|
|
||||||
/* boundary check fails? */
|
|
||||||
if ((u8_t *)p->payload < (u8_t *)p + SIZEOF_STRUCT_PBUF) {
|
|
||||||
LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
|
|
||||||
("pbuf_header: failed as %p < %p (not enough space for new header size)\n",
|
|
||||||
(void *)p->payload, (void *)(p + 1)));
|
|
||||||
/* restore old payload pointer */
|
|
||||||
p->payload = payload;
|
|
||||||
/* bail out unsuccesfully */
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
/* pbuf types refering to external payloads? */
|
|
||||||
} else if (type == PBUF_REF || type == PBUF_ROM) {
|
|
||||||
/* hide a header in the payload? */
|
|
||||||
if ((header_size_increment < 0) && (increment_magnitude <= p->len)) {
|
|
||||||
/* increase payload pointer */
|
|
||||||
p->payload = (u8_t *)p->payload - header_size_increment;
|
|
||||||
} else {
|
|
||||||
/* cannot expand payload to front (yet!)
|
|
||||||
* bail out unsuccesfully */
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* Unknown type */
|
|
||||||
LWIP_ASSERT("bad pbuf type", 0);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
/* modify pbuf length fields */
|
|
||||||
p->len += header_size_increment;
|
|
||||||
p->tot_len += header_size_increment;
|
|
||||||
|
|
||||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_header: old %p new %p (%"S16_F")\n",
|
|
||||||
(void *)payload, (void *)p->payload, header_size_increment));
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Dereference a pbuf chain or queue and deallocate any no-longer-used
|
|
||||||
* pbufs at the head of this chain or queue.
|
|
||||||
*
|
|
||||||
* Decrements the pbuf reference count. If it reaches zero, the pbuf is
|
|
||||||
* deallocated.
|
|
||||||
*
|
|
||||||
* For a pbuf chain, this is repeated for each pbuf in the chain,
|
|
||||||
* up to the first pbuf which has a non-zero reference count after
|
|
||||||
* decrementing. So, when all reference counts are one, the whole
|
|
||||||
* chain is free'd.
|
|
||||||
*
|
|
||||||
* @param p The pbuf (chain) to be dereferenced.
|
|
||||||
*
|
|
||||||
* @return the number of pbufs that were de-allocated
|
|
||||||
* from the head of the chain.
|
|
||||||
*
|
|
||||||
* @note MUST NOT be called on a packet queue (Not verified to work yet).
|
|
||||||
* @note the reference counter of a pbuf equals the number of pointers
|
|
||||||
* that refer to the pbuf (or into the pbuf).
|
|
||||||
*
|
|
||||||
* @internal examples:
|
|
||||||
*
|
|
||||||
* Assuming existing chains a->b->c with the following reference
|
|
||||||
* counts, calling pbuf_free(a) results in:
|
|
||||||
*
|
|
||||||
* 1->2->3 becomes ...1->3
|
|
||||||
* 3->3->3 becomes 2->3->3
|
|
||||||
* 1->1->2 becomes ......1
|
|
||||||
* 2->1->1 becomes 1->1->1
|
|
||||||
* 1->1->1 becomes .......
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
u8_t
|
|
||||||
pbuf_free(struct pbuf *p)
|
|
||||||
{
|
|
||||||
u16_t type;
|
|
||||||
struct pbuf *q;
|
|
||||||
u8_t count;
|
|
||||||
|
|
||||||
if (p == NULL) {
|
|
||||||
LWIP_ASSERT("p != NULL", p != NULL);
|
|
||||||
/* if assertions are disabled, proceed with debug output */
|
|
||||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
|
|
||||||
("pbuf_free(p == NULL) was called.\n"));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free(%p)\n", (void *)p));
|
|
||||||
|
|
||||||
PERF_START;
|
|
||||||
|
|
||||||
LWIP_ASSERT("pbuf_free: sane type",
|
|
||||||
p->type == PBUF_RAM || p->type == PBUF_ROM ||
|
|
||||||
p->type == PBUF_REF || p->type == PBUF_POOL);
|
|
||||||
|
|
||||||
count = 0;
|
|
||||||
/* de-allocate all consecutive pbufs from the head of the chain that
|
|
||||||
* obtain a zero reference count after decrementing*/
|
|
||||||
while (p != NULL) {
|
|
||||||
u16_t ref;
|
|
||||||
SYS_ARCH_DECL_PROTECT(old_level);
|
|
||||||
/* Since decrementing ref cannot be guaranteed to be a single machine operation
|
|
||||||
* we must protect it. We put the new ref into a local variable to prevent
|
|
||||||
* further protection. */
|
|
||||||
SYS_ARCH_PROTECT(old_level);
|
|
||||||
/* all pbufs in a chain are referenced at least once */
|
|
||||||
LWIP_ASSERT("pbuf_free: p->ref > 0", p->ref > 0);
|
|
||||||
/* decrease reference count (number of pointers to pbuf) */
|
|
||||||
ref = --(p->ref);
|
|
||||||
SYS_ARCH_UNPROTECT(old_level);
|
|
||||||
/* this pbuf is no longer referenced to? */
|
|
||||||
if (ref == 0) {
|
|
||||||
/* remember next pbuf in chain for next iteration */
|
|
||||||
q = p->next;
|
|
||||||
LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free: deallocating %p\n", (void *)p));
|
|
||||||
type = p->type;
|
|
||||||
/* is this a pbuf from the pool? */
|
|
||||||
if (type == PBUF_POOL) {
|
|
||||||
memp_free(MEMP_PBUF_POOL, p);
|
|
||||||
/* is this a ROM or RAM referencing pbuf? */
|
|
||||||
} else if (type == PBUF_ROM || type == PBUF_REF) {
|
|
||||||
memp_free(MEMP_PBUF, p);
|
|
||||||
/* type == PBUF_RAM */
|
|
||||||
} else {
|
|
||||||
mem_free(p);
|
|
||||||
}
|
|
||||||
count++;
|
|
||||||
/* proceed to next pbuf */
|
|
||||||
p = q;
|
|
||||||
/* p->ref > 0, this pbuf is still referenced to */
|
|
||||||
/* (and so the remaining pbufs in chain as well) */
|
|
||||||
} else {
|
|
||||||
LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free: %p has ref %"U16_F", ending here.\n", (void *)p, ref));
|
|
||||||
/* stop walking through the chain */
|
|
||||||
p = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PERF_STOP("pbuf_free");
|
|
||||||
/* return number of de-allocated pbufs */
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Count number of pbufs in a chain
|
|
||||||
*
|
|
||||||
* @param p first pbuf of chain
|
|
||||||
* @return the number of pbufs in a chain
|
|
||||||
*/
|
|
||||||
|
|
||||||
u8_t
|
|
||||||
pbuf_clen(struct pbuf *p)
|
|
||||||
{
|
|
||||||
u8_t len;
|
|
||||||
|
|
||||||
len = 0;
|
|
||||||
while (p != NULL) {
|
|
||||||
++len;
|
|
||||||
p = p->next;
|
|
||||||
}
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Increment the reference count of the pbuf.
|
|
||||||
*
|
|
||||||
* @param p pbuf to increase reference counter of
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
pbuf_ref(struct pbuf *p)
|
|
||||||
{
|
|
||||||
SYS_ARCH_DECL_PROTECT(old_level);
|
|
||||||
/* pbuf given? */
|
|
||||||
if (p != NULL) {
|
|
||||||
SYS_ARCH_PROTECT(old_level);
|
|
||||||
++(p->ref);
|
|
||||||
SYS_ARCH_UNPROTECT(old_level);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Concatenate two pbufs (each may be a pbuf chain) and take over
|
|
||||||
* the caller's reference of the tail pbuf.
|
|
||||||
*
|
|
||||||
* @note The caller MAY NOT reference the tail pbuf afterwards.
|
|
||||||
* Use pbuf_chain() for that purpose.
|
|
||||||
*
|
|
||||||
* @see pbuf_chain()
|
|
||||||
*/
|
|
||||||
|
|
||||||
void
|
|
||||||
pbuf_cat(struct pbuf *h, struct pbuf *t)
|
|
||||||
{
|
|
||||||
struct pbuf *p;
|
|
||||||
|
|
||||||
LWIP_ERROR("(h != NULL) && (t != NULL) (programmer violates API)",
|
|
||||||
((h != NULL) && (t != NULL)), return;);
|
|
||||||
|
|
||||||
/* proceed to last pbuf of chain */
|
|
||||||
for (p = h; p->next != NULL; p = p->next) {
|
|
||||||
/* add total length of second chain to all totals of first chain */
|
|
||||||
p->tot_len += t->tot_len;
|
|
||||||
}
|
|
||||||
/* { p is last pbuf of first h chain, p->next == NULL } */
|
|
||||||
LWIP_ASSERT("p->tot_len == p->len (of last pbuf in chain)", p->tot_len == p->len);
|
|
||||||
LWIP_ASSERT("p->next == NULL", p->next == NULL);
|
|
||||||
/* add total length of second chain to last pbuf total of first chain */
|
|
||||||
p->tot_len += t->tot_len;
|
|
||||||
/* chain last pbuf of head (p) with first of tail (t) */
|
|
||||||
p->next = t;
|
|
||||||
/* p->next now references t, but the caller will drop its reference to t,
|
|
||||||
* so netto there is no change to the reference count of t.
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Chain two pbufs (or pbuf chains) together.
|
|
||||||
*
|
|
||||||
* The caller MUST call pbuf_free(t) once it has stopped
|
|
||||||
* using it. Use pbuf_cat() instead if you no longer use t.
|
|
||||||
*
|
|
||||||
* @param h head pbuf (chain)
|
|
||||||
* @param t tail pbuf (chain)
|
|
||||||
* @note The pbufs MUST belong to the same packet.
|
|
||||||
* @note MAY NOT be called on a packet queue.
|
|
||||||
*
|
|
||||||
* The ->tot_len fields of all pbufs of the head chain are adjusted.
|
|
||||||
* The ->next field of the last pbuf of the head chain is adjusted.
|
|
||||||
* The ->ref field of the first pbuf of the tail chain is adjusted.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
pbuf_chain(struct pbuf *h, struct pbuf *t)
|
|
||||||
{
|
|
||||||
pbuf_cat(h, t);
|
|
||||||
/* t is now referenced by h */
|
|
||||||
pbuf_ref(t);
|
|
||||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_chain: %p references %p\n", (void *)h, (void *)t));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Dechains the first pbuf from its succeeding pbufs in the chain.
|
|
||||||
*
|
|
||||||
* Makes p->tot_len field equal to p->len.
|
|
||||||
* @param p pbuf to dechain
|
|
||||||
* @return remainder of the pbuf chain, or NULL if it was de-allocated.
|
|
||||||
* @note May not be called on a packet queue.
|
|
||||||
*/
|
|
||||||
struct pbuf *
|
|
||||||
pbuf_dechain(struct pbuf *p)
|
|
||||||
{
|
|
||||||
struct pbuf *q;
|
|
||||||
u8_t tail_gone = 1;
|
|
||||||
/* tail */
|
|
||||||
q = p->next;
|
|
||||||
/* pbuf has successor in chain? */
|
|
||||||
if (q != NULL) {
|
|
||||||
/* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */
|
|
||||||
LWIP_ASSERT("p->tot_len == p->len + q->tot_len", q->tot_len == p->tot_len - p->len);
|
|
||||||
/* enforce invariant if assertion is disabled */
|
|
||||||
q->tot_len = p->tot_len - p->len;
|
|
||||||
/* decouple pbuf from remainder */
|
|
||||||
p->next = NULL;
|
|
||||||
/* total length of pbuf p is its own length only */
|
|
||||||
p->tot_len = p->len;
|
|
||||||
/* q is no longer referenced by p, free it */
|
|
||||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_dechain: unreferencing %p\n", (void *)q));
|
|
||||||
tail_gone = pbuf_free(q);
|
|
||||||
if (tail_gone > 0) {
|
|
||||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE,
|
|
||||||
("pbuf_dechain: deallocated %p (as it is no longer referenced)\n", (void *)q));
|
|
||||||
}
|
|
||||||
/* return remaining tail or NULL if deallocated */
|
|
||||||
}
|
|
||||||
/* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */
|
|
||||||
LWIP_ASSERT("p->tot_len == p->len", p->tot_len == p->len);
|
|
||||||
return ((tail_gone > 0) ? NULL : q);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* Create PBUF_RAM copies of pbufs.
|
|
||||||
*
|
|
||||||
* Used to queue packets on behalf of the lwIP stack, such as
|
|
||||||
* ARP based queueing.
|
|
||||||
*
|
|
||||||
* @note You MUST explicitly use p = pbuf_take(p);
|
|
||||||
*
|
|
||||||
* @note Only one packet is copied, no packet queue!
|
|
||||||
*
|
|
||||||
* @param p_to pbuf destination of the copy
|
|
||||||
* @param p_from pbuf source of the copy
|
|
||||||
*
|
|
||||||
* @return ERR_OK if pbuf was copied
|
|
||||||
* ERR_ARG if one of the pbufs is NULL or p_to is not big
|
|
||||||
* enough to hold p_from
|
|
||||||
*/
|
|
||||||
err_t
|
|
||||||
pbuf_copy(struct pbuf *p_to, struct pbuf *p_from)
|
|
||||||
{
|
|
||||||
u16_t offset_to=0, offset_from=0, len;
|
|
||||||
|
|
||||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy(%p, %p)\n",
|
|
||||||
(void*)p_to, (void*)p_from));
|
|
||||||
|
|
||||||
/* is the target big enough to hold the source? */
|
|
||||||
LWIP_ERROR("pbuf_copy: target not big enough to hold source", ((p_to != NULL) &&
|
|
||||||
(p_from != NULL) && (p_to->tot_len >= p_from->tot_len)), return ERR_ARG;);
|
|
||||||
|
|
||||||
/* iterate through pbuf chain */
|
|
||||||
do
|
|
||||||
{
|
|
||||||
LWIP_ASSERT("p_to != NULL", p_to != NULL);
|
|
||||||
/* copy one part of the original chain */
|
|
||||||
if ((p_to->len - offset_to) >= (p_from->len - offset_from)) {
|
|
||||||
/* complete current p_from fits into current p_to */
|
|
||||||
len = p_from->len - offset_from;
|
|
||||||
} else {
|
|
||||||
/* current p_from does not fit into current p_to */
|
|
||||||
len = p_to->len - offset_to;
|
|
||||||
}
|
|
||||||
MEMCPY((u8_t*)p_to->payload + offset_to, (u8_t*)p_from->payload + offset_from, len);
|
|
||||||
offset_to += len;
|
|
||||||
offset_from += len;
|
|
||||||
LWIP_ASSERT("offset_to <= p_to->len", offset_to <= p_to->len);
|
|
||||||
if (offset_to == p_to->len) {
|
|
||||||
/* on to next p_to (if any) */
|
|
||||||
offset_to = 0;
|
|
||||||
p_to = p_to->next;
|
|
||||||
}
|
|
||||||
LWIP_ASSERT("offset_from <= p_from->len", offset_from <= p_from->len);
|
|
||||||
if (offset_from >= p_from->len) {
|
|
||||||
/* on to next p_from (if any) */
|
|
||||||
offset_from = 0;
|
|
||||||
p_from = p_from->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
if((p_from != NULL) && (p_from->len == p_from->tot_len)) {
|
|
||||||
/* don't copy more than one packet! */
|
|
||||||
LWIP_ERROR("pbuf_copy() does not allow packet queues!\n",
|
|
||||||
(p_from->next == NULL), return ERR_VAL;);
|
|
||||||
}
|
|
||||||
if((p_to != NULL) && (p_to->len == p_to->tot_len)) {
|
|
||||||
/* don't copy more than one packet! */
|
|
||||||
LWIP_ERROR("pbuf_copy() does not allow packet queues!\n",
|
|
||||||
(p_to->next == NULL), return ERR_VAL;);
|
|
||||||
}
|
|
||||||
} while (p_from);
|
|
||||||
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy: end of chain reached.\n"));
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copy (part of) the contents of a packet buffer
|
|
||||||
* to an application supplied buffer.
|
|
||||||
*
|
|
||||||
* @param buf the pbuf from which to copy data
|
|
||||||
* @param dataptr the application supplied buffer
|
|
||||||
* @param len length of data to copy (dataptr must be big enough). No more
|
|
||||||
* than buf->tot_len will be copied, irrespective of len
|
|
||||||
* @param offset offset into the packet buffer from where to begin copying len bytes
|
|
||||||
* @return the number of bytes copied, or 0 on failure
|
|
||||||
*/
|
|
||||||
u16_t
|
|
||||||
pbuf_copy_partial(struct pbuf *buf, void *dataptr, u16_t len, u16_t offset)
|
|
||||||
{
|
|
||||||
struct pbuf *p;
|
|
||||||
u16_t left;
|
|
||||||
u16_t buf_copy_len;
|
|
||||||
u16_t copied_total = 0;
|
|
||||||
|
|
||||||
LWIP_ERROR("pbuf_copy_partial: invalid buf", (buf != NULL), return 0;);
|
|
||||||
LWIP_ERROR("pbuf_copy_partial: invalid dataptr", (dataptr != NULL), return 0;);
|
|
||||||
|
|
||||||
left = 0;
|
|
||||||
|
|
||||||
if((buf == NULL) || (dataptr == NULL)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */
|
|
||||||
for(p = buf; len != 0 && p != NULL; p = p->next) {
|
|
||||||
if ((offset != 0) && (offset >= p->len)) {
|
|
||||||
/* don't copy from this buffer -> on to the next */
|
|
||||||
offset -= p->len;
|
|
||||||
} else {
|
|
||||||
/* copy from this buffer. maybe only partially. */
|
|
||||||
buf_copy_len = p->len - offset;
|
|
||||||
if (buf_copy_len > len)
|
|
||||||
buf_copy_len = len;
|
|
||||||
/* copy the necessary parts of the buffer */
|
|
||||||
MEMCPY(&((char*)dataptr)[left], &((char*)p->payload)[offset], buf_copy_len);
|
|
||||||
copied_total += buf_copy_len;
|
|
||||||
left += buf_copy_len;
|
|
||||||
len -= buf_copy_len;
|
|
||||||
offset = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return copied_total;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copy application supplied data into a pbuf.
|
|
||||||
* This function can only be used to copy the equivalent of buf->tot_len data.
|
|
||||||
*
|
|
||||||
* @param buf pbuf to fill with data
|
|
||||||
* @param dataptr application supplied data buffer
|
|
||||||
* @param len length of the application supplied data buffer
|
|
||||||
*
|
|
||||||
* @return ERR_OK if successful, ERR_MEM if the pbuf is not big enough
|
|
||||||
*/
|
|
||||||
err_t
|
|
||||||
pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len)
|
|
||||||
{
|
|
||||||
struct pbuf *p;
|
|
||||||
u16_t buf_copy_len;
|
|
||||||
u16_t total_copy_len = len;
|
|
||||||
u16_t copied_total = 0;
|
|
||||||
|
|
||||||
LWIP_ERROR("pbuf_take: invalid buf", (buf != NULL), return 0;);
|
|
||||||
LWIP_ERROR("pbuf_take: invalid dataptr", (dataptr != NULL), return 0;);
|
|
||||||
|
|
||||||
if ((buf == NULL) || (dataptr == NULL) || (buf->tot_len < len)) {
|
|
||||||
return ERR_ARG;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */
|
|
||||||
for(p = buf; total_copy_len != 0; p = p->next) {
|
|
||||||
LWIP_ASSERT("pbuf_take: invalid pbuf", p != NULL);
|
|
||||||
buf_copy_len = total_copy_len;
|
|
||||||
if (buf_copy_len > p->len) {
|
|
||||||
/* this pbuf cannot hold all remaining data */
|
|
||||||
buf_copy_len = p->len;
|
|
||||||
}
|
|
||||||
/* copy the necessary parts of the buffer */
|
|
||||||
MEMCPY(p->payload, &((char*)dataptr)[copied_total], buf_copy_len);
|
|
||||||
total_copy_len -= buf_copy_len;
|
|
||||||
copied_total += buf_copy_len;
|
|
||||||
}
|
|
||||||
LWIP_ASSERT("did not copy all data", total_copy_len == 0 && copied_total == len);
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a single pbuf out of a queue of pbufs.
|
|
||||||
*
|
|
||||||
* @remark: The source pbuf 'p' is not freed by this function because that can
|
|
||||||
* be illegal in some places!
|
|
||||||
*
|
|
||||||
* @param p the source pbuf
|
|
||||||
* @param layer pbuf_layer of the new pbuf
|
|
||||||
*
|
|
||||||
* @return a new, single pbuf (p->next is NULL)
|
|
||||||
* or the old pbuf if allocation fails
|
|
||||||
*/
|
|
||||||
struct pbuf*
|
|
||||||
pbuf_coalesce(struct pbuf *p, pbuf_layer layer)
|
|
||||||
{
|
|
||||||
struct pbuf *q;
|
|
||||||
err_t err;
|
|
||||||
if (p->next == NULL) {
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
q = pbuf_alloc(layer, p->tot_len, PBUF_RAM);
|
|
||||||
if (q == NULL) {
|
|
||||||
/* @todo: what do we do now? */
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
err = pbuf_copy(q, p);
|
|
||||||
LWIP_ASSERT("pbuf_copy failed", err == ERR_OK);
|
|
||||||
pbuf_free(p);
|
|
||||||
return q;
|
|
||||||
}
|
|
|
@ -1,353 +0,0 @@
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
* Implementation of raw protocol PCBs for low-level handling of
|
|
||||||
* different types of protocols besides (or overriding) those
|
|
||||||
* already available in lwIP.
|
|
||||||
*
|
|
||||||
**/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "lwip/opt.h"
|
|
||||||
|
|
||||||
#if LWIP_RAW /* don't build if not configured for use in lwipopts.h */
|
|
||||||
|
|
||||||
#include "lwip/def.h"
|
|
||||||
#include "lwip/memp.h"
|
|
||||||
#include "lwip/inet.h"
|
|
||||||
#include "lwip/ip_addr.h"
|
|
||||||
#include "lwip/netif.h"
|
|
||||||
#include "lwip/raw.h"
|
|
||||||
#include "lwip/stats.h"
|
|
||||||
#include "lwip/snmp.h"
|
|
||||||
#include "arch/perf.h"
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
/** The list of RAW PCBs */
|
|
||||||
static struct raw_pcb *raw_pcbs;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine if in incoming IP packet is covered by a RAW PCB
|
|
||||||
* and if so, pass it to a user-provided receive callback function.
|
|
||||||
*
|
|
||||||
* Given an incoming IP datagram (as a chain of pbufs) this function
|
|
||||||
* finds a corresponding RAW PCB and calls the corresponding receive
|
|
||||||
* callback function.
|
|
||||||
*
|
|
||||||
* @param p pbuf to be demultiplexed to a RAW PCB.
|
|
||||||
* @param inp network interface on which the datagram was received.
|
|
||||||
* @return - 1 if the packet has been eaten by a RAW PCB receive
|
|
||||||
* callback function. The caller MAY NOT not reference the
|
|
||||||
* packet any longer, and MAY NOT call pbuf_free().
|
|
||||||
* @return - 0 if packet is not eaten (pbuf is still referenced by the
|
|
||||||
* caller).
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
u8_t
|
|
||||||
raw_input(struct pbuf *p, struct netif *inp)
|
|
||||||
{
|
|
||||||
struct raw_pcb *pcb, *prev;
|
|
||||||
struct ip_hdr *iphdr;
|
|
||||||
s16_t proto;
|
|
||||||
u8_t eaten = 0;
|
|
||||||
|
|
||||||
LWIP_UNUSED_ARG(inp);
|
|
||||||
|
|
||||||
iphdr = p->payload;
|
|
||||||
proto = IPH_PROTO(iphdr);
|
|
||||||
|
|
||||||
prev = NULL;
|
|
||||||
pcb = raw_pcbs;
|
|
||||||
/* loop through all raw pcbs until the packet is eaten by one */
|
|
||||||
/* this allows multiple pcbs to match against the packet by design */
|
|
||||||
while ((eaten == 0) && (pcb != NULL)) {
|
|
||||||
if (pcb->protocol == proto) {
|
|
||||||
#if IP_SOF_BROADCAST_RECV
|
|
||||||
/* broadcast filter? */
|
|
||||||
if ((pcb->so_options & SOF_BROADCAST) || !ip_addr_isbroadcast(&(iphdr->dest), inp))
|
|
||||||
#endif /* IP_SOF_BROADCAST_RECV */
|
|
||||||
{
|
|
||||||
/* receive callback function available? */
|
|
||||||
if (pcb->recv != NULL) {
|
|
||||||
/* the receive callback function did not eat the packet? */
|
|
||||||
if (pcb->recv(pcb->recv_arg, pcb, p, &(iphdr->src)) != 0) {
|
|
||||||
/* receive function ate the packet */
|
|
||||||
p = NULL;
|
|
||||||
eaten = 1;
|
|
||||||
if (prev != NULL) {
|
|
||||||
/* move the pcb to the front of raw_pcbs so that is
|
|
||||||
found faster next time */
|
|
||||||
prev->next = pcb->next;
|
|
||||||
pcb->next = raw_pcbs;
|
|
||||||
raw_pcbs = pcb;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* no receive callback function was set for this raw PCB */
|
|
||||||
}
|
|
||||||
/* drop the packet */
|
|
||||||
}
|
|
||||||
prev = pcb;
|
|
||||||
pcb = pcb->next;
|
|
||||||
}
|
|
||||||
return eaten;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Bind a RAW PCB.
|
|
||||||
*
|
|
||||||
* @param pcb RAW PCB to be bound with a local address ipaddr.
|
|
||||||
* @param ipaddr local IP address to bind with. Use IP_ADDR_ANY to
|
|
||||||
* bind to all local interfaces.
|
|
||||||
*
|
|
||||||
* @return lwIP error code.
|
|
||||||
* - ERR_OK. Successful. No error occured.
|
|
||||||
* - ERR_USE. The specified IP address is already bound to by
|
|
||||||
* another RAW PCB.
|
|
||||||
*
|
|
||||||
* @see raw_disconnect()
|
|
||||||
*/
|
|
||||||
err_t
|
|
||||||
raw_bind(struct raw_pcb *pcb, struct ip_addr *ipaddr)
|
|
||||||
{
|
|
||||||
ip_addr_set(&pcb->local_ip, ipaddr);
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Connect an RAW PCB. This function is required by upper layers
|
|
||||||
* of lwip. Using the raw api you could use raw_sendto() instead
|
|
||||||
*
|
|
||||||
* This will associate the RAW PCB with the remote address.
|
|
||||||
*
|
|
||||||
* @param pcb RAW PCB to be connected with remote address ipaddr and port.
|
|
||||||
* @param ipaddr remote IP address to connect with.
|
|
||||||
*
|
|
||||||
* @return lwIP error code
|
|
||||||
*
|
|
||||||
* @see raw_disconnect() and raw_sendto()
|
|
||||||
*/
|
|
||||||
err_t
|
|
||||||
raw_connect(struct raw_pcb *pcb, struct ip_addr *ipaddr)
|
|
||||||
{
|
|
||||||
ip_addr_set(&pcb->remote_ip, ipaddr);
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the callback function for received packets that match the
|
|
||||||
* raw PCB's protocol and binding.
|
|
||||||
*
|
|
||||||
* The callback function MUST either
|
|
||||||
* - eat the packet by calling pbuf_free() and returning non-zero. The
|
|
||||||
* packet will not be passed to other raw PCBs or other protocol layers.
|
|
||||||
* - not free the packet, and return zero. The packet will be matched
|
|
||||||
* against further PCBs and/or forwarded to another protocol layers.
|
|
||||||
*
|
|
||||||
* @return non-zero if the packet was free()d, zero if the packet remains
|
|
||||||
* available for others.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
raw_recv(struct raw_pcb *pcb,
|
|
||||||
u8_t (* recv)(void *arg, struct raw_pcb *upcb, struct pbuf *p,
|
|
||||||
struct ip_addr *addr),
|
|
||||||
void *recv_arg)
|
|
||||||
{
|
|
||||||
/* remember recv() callback and user data */
|
|
||||||
pcb->recv = recv;
|
|
||||||
pcb->recv_arg = recv_arg;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send the raw IP packet to the given address. Note that actually you cannot
|
|
||||||
* modify the IP headers (this is inconsistent with the receive callback where
|
|
||||||
* you actually get the IP headers), you can only specify the IP payload here.
|
|
||||||
* It requires some more changes in lwIP. (there will be a raw_send() function
|
|
||||||
* then.)
|
|
||||||
*
|
|
||||||
* @param pcb the raw pcb which to send
|
|
||||||
* @param p the IP payload to send
|
|
||||||
* @param ipaddr the destination address of the IP packet
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
err_t
|
|
||||||
raw_sendto(struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr)
|
|
||||||
{
|
|
||||||
err_t err;
|
|
||||||
struct netif *netif;
|
|
||||||
struct ip_addr *src_ip;
|
|
||||||
struct pbuf *q; /* q will be sent down the stack */
|
|
||||||
|
|
||||||
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_sendto\n"));
|
|
||||||
|
|
||||||
/* not enough space to add an IP header to first pbuf in given p chain? */
|
|
||||||
if (pbuf_header(p, IP_HLEN)) {
|
|
||||||
/* allocate header in new pbuf */
|
|
||||||
q = pbuf_alloc(PBUF_IP, 0, PBUF_RAM);
|
|
||||||
/* new header pbuf could not be allocated? */
|
|
||||||
if (q == NULL) {
|
|
||||||
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("raw_sendto: could not allocate header\n"));
|
|
||||||
return ERR_MEM;
|
|
||||||
}
|
|
||||||
/* chain header q in front of given pbuf p */
|
|
||||||
pbuf_chain(q, p);
|
|
||||||
/* { first pbuf q points to header pbuf } */
|
|
||||||
LWIP_DEBUGF(RAW_DEBUG, ("raw_sendto: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p));
|
|
||||||
} else {
|
|
||||||
/* first pbuf q equals given pbuf */
|
|
||||||
q = p;
|
|
||||||
if(pbuf_header(q, -IP_HLEN)) {
|
|
||||||
LWIP_ASSERT("Can't restore header we just removed!", 0);
|
|
||||||
return ERR_MEM;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((netif = ip_route(ipaddr)) == NULL) {
|
|
||||||
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: No route to 0x%"X32_F"\n", ipaddr->addr));
|
|
||||||
/* free any temporary header pbuf allocated by pbuf_header() */
|
|
||||||
if (q != p) {
|
|
||||||
pbuf_free(q);
|
|
||||||
}
|
|
||||||
return ERR_RTE;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if IP_SOF_BROADCAST
|
|
||||||
/* broadcast filter? */
|
|
||||||
if ( ((pcb->so_options & SOF_BROADCAST) == 0) && ip_addr_isbroadcast(ipaddr, netif) ) {
|
|
||||||
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb));
|
|
||||||
/* free any temporary header pbuf allocated by pbuf_header() */
|
|
||||||
if (q != p) {
|
|
||||||
pbuf_free(q);
|
|
||||||
}
|
|
||||||
return ERR_VAL;
|
|
||||||
}
|
|
||||||
#endif /* IP_SOF_BROADCAST */
|
|
||||||
|
|
||||||
if (ip_addr_isany(&pcb->local_ip)) {
|
|
||||||
/* use outgoing network interface IP address as source address */
|
|
||||||
src_ip = &(netif->ip_addr);
|
|
||||||
} else {
|
|
||||||
/* use RAW PCB local IP address as source address */
|
|
||||||
src_ip = &(pcb->local_ip);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if LWIP_NETIF_HWADDRHINT
|
|
||||||
netif->addr_hint = &(pcb->addr_hint);
|
|
||||||
#endif /* LWIP_NETIF_HWADDRHINT*/
|
|
||||||
err = ip_output_if (q, src_ip, ipaddr, pcb->ttl, pcb->tos, pcb->protocol, netif);
|
|
||||||
#if LWIP_NETIF_HWADDRHINT
|
|
||||||
netif->addr_hint = NULL;
|
|
||||||
#endif /* LWIP_NETIF_HWADDRHINT*/
|
|
||||||
|
|
||||||
/* did we chain a header earlier? */
|
|
||||||
if (q != p) {
|
|
||||||
/* free the header */
|
|
||||||
pbuf_free(q);
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send the raw IP packet to the address given by raw_connect()
|
|
||||||
*
|
|
||||||
* @param pcb the raw pcb which to send
|
|
||||||
* @param p the IP payload to send
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
err_t
|
|
||||||
raw_send(struct raw_pcb *pcb, struct pbuf *p)
|
|
||||||
{
|
|
||||||
return raw_sendto(pcb, p, &pcb->remote_ip);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove an RAW PCB.
|
|
||||||
*
|
|
||||||
* @param pcb RAW PCB to be removed. The PCB is removed from the list of
|
|
||||||
* RAW PCB's and the data structure is freed from memory.
|
|
||||||
*
|
|
||||||
* @see raw_new()
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
raw_remove(struct raw_pcb *pcb)
|
|
||||||
{
|
|
||||||
struct raw_pcb *pcb2;
|
|
||||||
/* pcb to be removed is first in list? */
|
|
||||||
if (raw_pcbs == pcb) {
|
|
||||||
/* make list start at 2nd pcb */
|
|
||||||
raw_pcbs = raw_pcbs->next;
|
|
||||||
/* pcb not 1st in list */
|
|
||||||
} else {
|
|
||||||
for(pcb2 = raw_pcbs; pcb2 != NULL; pcb2 = pcb2->next) {
|
|
||||||
/* find pcb in raw_pcbs list */
|
|
||||||
if (pcb2->next != NULL && pcb2->next == pcb) {
|
|
||||||
/* remove pcb from list */
|
|
||||||
pcb2->next = pcb->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
memp_free(MEMP_RAW_PCB, pcb);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a RAW PCB.
|
|
||||||
*
|
|
||||||
* @return The RAW PCB which was created. NULL if the PCB data structure
|
|
||||||
* could not be allocated.
|
|
||||||
*
|
|
||||||
* @param proto the protocol number of the IPs payload (e.g. IP_PROTO_ICMP)
|
|
||||||
*
|
|
||||||
* @see raw_remove()
|
|
||||||
*/
|
|
||||||
struct raw_pcb *
|
|
||||||
raw_new(u8_t proto) {
|
|
||||||
struct raw_pcb *pcb;
|
|
||||||
|
|
||||||
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_new\n"));
|
|
||||||
|
|
||||||
pcb = memp_malloc(MEMP_RAW_PCB);
|
|
||||||
/* could allocate RAW PCB? */
|
|
||||||
if (pcb != NULL) {
|
|
||||||
/* initialize PCB to all zeroes */
|
|
||||||
memset(pcb, 0, sizeof(struct raw_pcb));
|
|
||||||
pcb->protocol = proto;
|
|
||||||
pcb->ttl = RAW_TTL;
|
|
||||||
pcb->next = raw_pcbs;
|
|
||||||
raw_pcbs = pcb;
|
|
||||||
}
|
|
||||||
return pcb;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* LWIP_RAW */
|
|
|
@ -1,149 +0,0 @@
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
* Statistics module
|
|
||||||
*
|
|
||||||
**/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "lwip/opt.h"
|
|
||||||
|
|
||||||
#if LWIP_STATS /* don't build if not configured for use in lwipopts.h */
|
|
||||||
|
|
||||||
#include "lwip/def.h"
|
|
||||||
#include "lwip/stats.h"
|
|
||||||
#include "lwip/mem.h"
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
struct stats_ lwip_stats;
|
|
||||||
|
|
||||||
#if LWIP_STATS_DISPLAY
|
|
||||||
void
|
|
||||||
stats_display_proto(struct stats_proto *proto, char *name)
|
|
||||||
{
|
|
||||||
LWIP_PLATFORM_DIAG("\n\r%s\n\r\t", name);
|
|
||||||
LWIP_PLATFORM_DIAG("xmit: %"STAT_COUNTER_F"\n\r\t", proto->xmit);
|
|
||||||
LWIP_PLATFORM_DIAG("recv: %"STAT_COUNTER_F"\n\r\t", proto->recv);
|
|
||||||
LWIP_PLATFORM_DIAG("fw: %"STAT_COUNTER_F"\n\r\t", proto->fw);
|
|
||||||
LWIP_PLATFORM_DIAG("drop: %"STAT_COUNTER_F"\n\r\t", proto->drop);
|
|
||||||
LWIP_PLATFORM_DIAG("chkerr: %"STAT_COUNTER_F"\n\r\t", proto->chkerr);
|
|
||||||
LWIP_PLATFORM_DIAG("lenerr: %"STAT_COUNTER_F"\n\r\t", proto->lenerr);
|
|
||||||
LWIP_PLATFORM_DIAG("memerr: %"STAT_COUNTER_F"\n\r\t", proto->memerr);
|
|
||||||
LWIP_PLATFORM_DIAG("rterr: %"STAT_COUNTER_F"\n\r\t", proto->rterr);
|
|
||||||
LWIP_PLATFORM_DIAG("proterr: %"STAT_COUNTER_F"\n\r\t", proto->proterr);
|
|
||||||
LWIP_PLATFORM_DIAG("opterr: %"STAT_COUNTER_F"\n\r\t", proto->opterr);
|
|
||||||
LWIP_PLATFORM_DIAG("err: %"STAT_COUNTER_F"\n\r\t", proto->err);
|
|
||||||
LWIP_PLATFORM_DIAG("cachehit: %"STAT_COUNTER_F"\n\r", proto->cachehit);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if IGMP_STATS
|
|
||||||
void
|
|
||||||
stats_display_igmp(struct stats_igmp *igmp)
|
|
||||||
{
|
|
||||||
LWIP_PLATFORM_DIAG("\n\rIGMP\n\r\t"));
|
|
||||||
LWIP_PLATFORM_DIAG("lenerr: %"STAT_COUNTER_F"\n\r\t", igmp->lenerr);
|
|
||||||
LWIP_PLATFORM_DIAG("chkerr: %"STAT_COUNTER_F"\n\r\t", igmp->chkerr);
|
|
||||||
LWIP_PLATFORM_DIAG("v1_rxed: %"STAT_COUNTER_F"\n\r\t", igmp->v1_rxed);
|
|
||||||
LWIP_PLATFORM_DIAG("join_sent: %"STAT_COUNTER_F"\n\r\t", igmp->join_sent);
|
|
||||||
LWIP_PLATFORM_DIAG("leave_sent: %"STAT_COUNTER_F"\n\r\t", igmp->leave_sent);
|
|
||||||
LWIP_PLATFORM_DIAG("unicast_query: %"STAT_COUNTER_F"\n\r\t", igmp->unicast_query);
|
|
||||||
LWIP_PLATFORM_DIAG("report_sent: %"STAT_COUNTER_F"\n\r\t", igmp->report_sent);
|
|
||||||
LWIP_PLATFORM_DIAG("report_rxed: %"STAT_COUNTER_F"\n\r\t", igmp->report_rxed);
|
|
||||||
LWIP_PLATFORM_DIAG("group_query_rxed: %"STAT_COUNTER_F"\n\r", igmp->group_query_rxed);
|
|
||||||
}
|
|
||||||
#endif /* IGMP_STATS */
|
|
||||||
|
|
||||||
#if MEM_STATS || MEMP_STATS
|
|
||||||
void
|
|
||||||
stats_display_mem(struct stats_mem *mem, char *name)
|
|
||||||
{
|
|
||||||
LWIP_PLATFORM_DIAG("\n\rMEM %s\n\r\t", name);
|
|
||||||
LWIP_PLATFORM_DIAG("avail: %"U32_F"\n\r\t", (u32_t)mem->avail);
|
|
||||||
LWIP_PLATFORM_DIAG("used: %"U32_F"\n\r\t", (u32_t)mem->used);
|
|
||||||
LWIP_PLATFORM_DIAG("max: %"U32_F"\n\r\t", (u32_t)mem->max);
|
|
||||||
LWIP_PLATFORM_DIAG("err: %"U32_F"\n\r", (u32_t)mem->err);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if MEMP_STATS
|
|
||||||
void
|
|
||||||
stats_display_memp(struct stats_mem *mem, int index)
|
|
||||||
{
|
|
||||||
char * memp_names[] = {
|
|
||||||
#define LWIP_MEMPOOL(name,num,size,desc) desc,
|
|
||||||
#include "lwip/memp_std.h"
|
|
||||||
};
|
|
||||||
if(index < MEMP_MAX) {
|
|
||||||
stats_display_mem(mem, memp_names[index]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif /* MEMP_STATS */
|
|
||||||
#endif /* MEM_STATS || MEMP_STATS */
|
|
||||||
|
|
||||||
#if SYS_STATS
|
|
||||||
void
|
|
||||||
stats_display_sys(struct stats_sys *sys)
|
|
||||||
{
|
|
||||||
LWIP_PLATFORM_DIAG("\n\rSYS\n\r\t");
|
|
||||||
LWIP_PLATFORM_DIAG("sem.used: %"U32_F"\n\r\t", (u32_t)sys->sem.used);
|
|
||||||
LWIP_PLATFORM_DIAG("sem.max: %"U32_F"\n\r\t", (u32_t)sys->sem.max);
|
|
||||||
LWIP_PLATFORM_DIAG("sem.err: %"U32_F"\n\r\t", (u32_t)sys->sem.err);
|
|
||||||
LWIP_PLATFORM_DIAG("mbox.used: %"U32_F"\n\r\t", (u32_t)sys->mbox.used);
|
|
||||||
LWIP_PLATFORM_DIAG("mbox.max: %"U32_F"\n\r\t", (u32_t)sys->mbox.max);
|
|
||||||
LWIP_PLATFORM_DIAG("mbox.err: %"U32_F"\n\r\t", (u32_t)sys->mbox.err);
|
|
||||||
}
|
|
||||||
#endif /* SYS_STATS */
|
|
||||||
|
|
||||||
void
|
|
||||||
stats_display(void)
|
|
||||||
{
|
|
||||||
s16_t i;
|
|
||||||
|
|
||||||
LINK_STATS_DISPLAY();
|
|
||||||
ETHARP_STATS_DISPLAY();
|
|
||||||
IPFRAG_STATS_DISPLAY();
|
|
||||||
IP_STATS_DISPLAY();
|
|
||||||
IGMP_STATS_DISPLAY();
|
|
||||||
ICMP_STATS_DISPLAY();
|
|
||||||
UDP_STATS_DISPLAY();
|
|
||||||
TCP_STATS_DISPLAY();
|
|
||||||
MEM_STATS_DISPLAY();
|
|
||||||
for (i = 0; i < MEMP_MAX; i++) {
|
|
||||||
MEMP_STATS_DISPLAY(i);
|
|
||||||
}
|
|
||||||
SYS_STATS_DISPLAY();
|
|
||||||
}
|
|
||||||
#endif /* LWIP_STATS_DISPLAY */
|
|
||||||
|
|
||||||
#endif /* LWIP_STATS */
|
|
||||||
|
|
|
@ -1,346 +0,0 @@
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
* lwIP Operating System abstraction
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "lwip/opt.h"
|
|
||||||
|
|
||||||
#if (NO_SYS == 0) /* don't build if not configured for use in lwipopts.h */
|
|
||||||
|
|
||||||
#include "lwip/sys.h"
|
|
||||||
#include "lwip/def.h"
|
|
||||||
#include "lwip/memp.h"
|
|
||||||
#include "lwip/tcpip.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Struct used for sys_sem_wait_timeout() to tell wether the time
|
|
||||||
* has run out or the semaphore has really become available.
|
|
||||||
*/
|
|
||||||
struct sswt_cb
|
|
||||||
{
|
|
||||||
s16_t timeflag;
|
|
||||||
sys_sem_t *psem;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wait (forever) for a message to arrive in an mbox.
|
|
||||||
* While waiting, timeouts (for this thread) are processed.
|
|
||||||
*
|
|
||||||
* @param mbox the mbox to fetch the message from
|
|
||||||
* @param msg the place to store the message
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
sys_mbox_fetch(sys_mbox_t mbox, void **msg)
|
|
||||||
{
|
|
||||||
u32_t time_needed;
|
|
||||||
struct sys_timeouts *timeouts;
|
|
||||||
struct sys_timeo *tmptimeout;
|
|
||||||
sys_timeout_handler h;
|
|
||||||
void *arg;
|
|
||||||
|
|
||||||
again:
|
|
||||||
timeouts = sys_arch_timeouts();
|
|
||||||
|
|
||||||
if (!timeouts || !timeouts->next) {
|
|
||||||
UNLOCK_TCPIP_CORE();
|
|
||||||
time_needed = sys_arch_mbox_fetch(mbox, msg, 0);
|
|
||||||
LOCK_TCPIP_CORE();
|
|
||||||
} else {
|
|
||||||
if (timeouts->next->time > 0) {
|
|
||||||
UNLOCK_TCPIP_CORE();
|
|
||||||
time_needed = sys_arch_mbox_fetch(mbox, msg, timeouts->next->time);
|
|
||||||
LOCK_TCPIP_CORE();
|
|
||||||
} else {
|
|
||||||
time_needed = SYS_ARCH_TIMEOUT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (time_needed == SYS_ARCH_TIMEOUT) {
|
|
||||||
/* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message
|
|
||||||
could be fetched. We should now call the timeout handler and
|
|
||||||
deallocate the memory allocated for the timeout. */
|
|
||||||
tmptimeout = timeouts->next;
|
|
||||||
timeouts->next = tmptimeout->next;
|
|
||||||
h = tmptimeout->h;
|
|
||||||
arg = tmptimeout->arg;
|
|
||||||
memp_free(MEMP_SYS_TIMEOUT, tmptimeout);
|
|
||||||
if (h != NULL) {
|
|
||||||
LWIP_DEBUGF(SYS_DEBUG, ("smf calling h=%p(%p)\n", *(void**)&h, arg));
|
|
||||||
h(arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We try again to fetch a message from the mbox. */
|
|
||||||
goto again;
|
|
||||||
} else {
|
|
||||||
/* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout
|
|
||||||
occured. The time variable is set to the number of
|
|
||||||
milliseconds we waited for the message. */
|
|
||||||
if (time_needed < timeouts->next->time) {
|
|
||||||
timeouts->next->time -= time_needed;
|
|
||||||
} else {
|
|
||||||
timeouts->next->time = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wait (forever) for a semaphore to become available.
|
|
||||||
* While waiting, timeouts (for this thread) are processed.
|
|
||||||
*
|
|
||||||
* @param sem semaphore to wait for
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
sys_sem_wait(sys_sem_t sem)
|
|
||||||
{
|
|
||||||
u32_t time_needed;
|
|
||||||
struct sys_timeouts *timeouts;
|
|
||||||
struct sys_timeo *tmptimeout;
|
|
||||||
sys_timeout_handler h;
|
|
||||||
void *arg;
|
|
||||||
|
|
||||||
again:
|
|
||||||
|
|
||||||
timeouts = sys_arch_timeouts();
|
|
||||||
|
|
||||||
if (!timeouts || !timeouts->next) {
|
|
||||||
sys_arch_sem_wait(sem, 0);
|
|
||||||
} else {
|
|
||||||
if (timeouts->next->time > 0) {
|
|
||||||
time_needed = sys_arch_sem_wait(sem, timeouts->next->time);
|
|
||||||
} else {
|
|
||||||
time_needed = SYS_ARCH_TIMEOUT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (time_needed == SYS_ARCH_TIMEOUT) {
|
|
||||||
/* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message
|
|
||||||
could be fetched. We should now call the timeout handler and
|
|
||||||
deallocate the memory allocated for the timeout. */
|
|
||||||
tmptimeout = timeouts->next;
|
|
||||||
timeouts->next = tmptimeout->next;
|
|
||||||
h = tmptimeout->h;
|
|
||||||
arg = tmptimeout->arg;
|
|
||||||
memp_free(MEMP_SYS_TIMEOUT, tmptimeout);
|
|
||||||
if (h != NULL) {
|
|
||||||
LWIP_DEBUGF(SYS_DEBUG, ("ssw h=%p(%p)\n", *(void**)&h, (void *)arg));
|
|
||||||
h(arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We try again to fetch a message from the mbox. */
|
|
||||||
goto again;
|
|
||||||
} else {
|
|
||||||
/* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout
|
|
||||||
occured. The time variable is set to the number of
|
|
||||||
milliseconds we waited for the message. */
|
|
||||||
if (time_needed < timeouts->next->time) {
|
|
||||||
timeouts->next->time -= time_needed;
|
|
||||||
} else {
|
|
||||||
timeouts->next->time = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a one-shot timer (aka timeout). Timeouts are processed in the
|
|
||||||
* following cases:
|
|
||||||
* - while waiting for a message using sys_mbox_fetch()
|
|
||||||
* - while waiting for a semaphore using sys_sem_wait() or sys_sem_wait_timeout()
|
|
||||||
* - while sleeping using the inbuilt sys_msleep()
|
|
||||||
*
|
|
||||||
* @param msecs time in milliseconds after that the timer should expire
|
|
||||||
* @param h callback function to call when msecs have elapsed
|
|
||||||
* @param arg argument to pass to the callback function
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
sys_timeout(u32_t msecs, sys_timeout_handler h, void *arg)
|
|
||||||
{
|
|
||||||
struct sys_timeouts *timeouts;
|
|
||||||
struct sys_timeo *timeout, *t;
|
|
||||||
|
|
||||||
timeout = memp_malloc(MEMP_SYS_TIMEOUT);
|
|
||||||
if (timeout == NULL) {
|
|
||||||
LWIP_ASSERT("sys_timeout: timeout != NULL", timeout != NULL);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
timeout->next = NULL;
|
|
||||||
timeout->h = h;
|
|
||||||
timeout->arg = arg;
|
|
||||||
timeout->time = msecs;
|
|
||||||
|
|
||||||
timeouts = sys_arch_timeouts();
|
|
||||||
|
|
||||||
LWIP_DEBUGF(SYS_DEBUG, ("sys_timeout: %p msecs=%"U32_F" h=%p arg=%p\n",
|
|
||||||
(void *)timeout, msecs, *(void**)&h, (void *)arg));
|
|
||||||
|
|
||||||
if (timeouts == NULL) {
|
|
||||||
LWIP_ASSERT("sys_timeout: timeouts != NULL", timeouts != NULL);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (timeouts->next == NULL) {
|
|
||||||
timeouts->next = timeout;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (timeouts->next->time > msecs) {
|
|
||||||
timeouts->next->time -= msecs;
|
|
||||||
timeout->next = timeouts->next;
|
|
||||||
timeouts->next = timeout;
|
|
||||||
} else {
|
|
||||||
for(t = timeouts->next; t != NULL; t = t->next) {
|
|
||||||
timeout->time -= t->time;
|
|
||||||
if (t->next == NULL || t->next->time > timeout->time) {
|
|
||||||
if (t->next != NULL) {
|
|
||||||
t->next->time -= timeout->time;
|
|
||||||
}
|
|
||||||
timeout->next = t->next;
|
|
||||||
t->next = timeout;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Go through timeout list (for this task only) and remove the first matching
|
|
||||||
* entry, even though the timeout has not triggered yet.
|
|
||||||
*
|
|
||||||
* @note This function only works as expected if there is only one timeout
|
|
||||||
* calling 'h' in the list of timeouts.
|
|
||||||
*
|
|
||||||
* @param h callback function that would be called by the timeout
|
|
||||||
* @param arg callback argument that would be passed to h
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
sys_untimeout(sys_timeout_handler h, void *arg)
|
|
||||||
{
|
|
||||||
struct sys_timeouts *timeouts;
|
|
||||||
struct sys_timeo *prev_t, *t;
|
|
||||||
|
|
||||||
timeouts = sys_arch_timeouts();
|
|
||||||
|
|
||||||
if (timeouts == NULL) {
|
|
||||||
LWIP_ASSERT("sys_untimeout: timeouts != NULL", timeouts != NULL);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (timeouts->next == NULL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (t = timeouts->next, prev_t = NULL; t != NULL; prev_t = t, t = t->next) {
|
|
||||||
if ((t->h == h) && (t->arg == arg)) {
|
|
||||||
/* We have a match */
|
|
||||||
/* Unlink from previous in list */
|
|
||||||
if (prev_t == NULL) {
|
|
||||||
timeouts->next = t->next;
|
|
||||||
} else {
|
|
||||||
prev_t->next = t->next;
|
|
||||||
}
|
|
||||||
/* If not the last one, add time of this one back to next */
|
|
||||||
if (t->next != NULL) {
|
|
||||||
t->next->time += t->time;
|
|
||||||
}
|
|
||||||
memp_free(MEMP_SYS_TIMEOUT, t);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Timeout handler function for sys_sem_wait_timeout()
|
|
||||||
*
|
|
||||||
* @param arg struct sswt_cb* used to signal a semaphore and end waiting.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
sswt_handler(void *arg)
|
|
||||||
{
|
|
||||||
struct sswt_cb *sswt_cb = (struct sswt_cb *) arg;
|
|
||||||
|
|
||||||
/* Timeout. Set flag to TRUE and signal semaphore */
|
|
||||||
sswt_cb->timeflag = 1;
|
|
||||||
sys_sem_signal(*(sswt_cb->psem));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wait for a semaphore with timeout (specified in ms)
|
|
||||||
*
|
|
||||||
* @param sem semaphore to wait
|
|
||||||
* @param timeout timeout in ms (0: wait forever)
|
|
||||||
* @return 0 on timeout, 1 otherwise
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
sys_sem_wait_timeout(sys_sem_t sem, u32_t timeout)
|
|
||||||
{
|
|
||||||
struct sswt_cb sswt_cb;
|
|
||||||
|
|
||||||
sswt_cb.psem = &sem;
|
|
||||||
sswt_cb.timeflag = 0;
|
|
||||||
|
|
||||||
/* If timeout is zero, then just wait forever */
|
|
||||||
if (timeout > 0) {
|
|
||||||
/* Create a timer and pass it the address of our flag */
|
|
||||||
sys_timeout(timeout, sswt_handler, &sswt_cb);
|
|
||||||
}
|
|
||||||
sys_sem_wait(sem);
|
|
||||||
/* Was it a timeout? */
|
|
||||||
if (sswt_cb.timeflag) {
|
|
||||||
/* timeout */
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
/* Not a timeout. Remove timeout entry */
|
|
||||||
sys_untimeout(sswt_handler, &sswt_cb);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sleep for some ms. Timeouts are processed while sleeping.
|
|
||||||
*
|
|
||||||
* @param ms number of milliseconds to sleep
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
sys_msleep(u32_t ms)
|
|
||||||
{
|
|
||||||
sys_sem_t delaysem = sys_sem_new(0);
|
|
||||||
|
|
||||||
sys_sem_wait_timeout(delaysem, ms);
|
|
||||||
|
|
||||||
sys_sem_free(delaysem);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* NO_SYS */
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,848 +0,0 @@
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
* User Datagram Protocol module
|
|
||||||
*
|
|
||||||
**/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/* udp.c
|
|
||||||
*
|
|
||||||
* The code for the User Datagram Protocol UDP & UDPLite (RFC 3828).
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* @todo Check the use of '(struct udp_pcb).chksum_len_rx'!
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "lwip/opt.h"
|
|
||||||
|
|
||||||
#if LWIP_UDP /* don't build if not configured for use in lwipopts.h */
|
|
||||||
|
|
||||||
#include "lwip/udp.h"
|
|
||||||
#include "lwip/def.h"
|
|
||||||
#include "lwip/memp.h"
|
|
||||||
#include "lwip/inet.h"
|
|
||||||
#include "lwip/inet_chksum.h"
|
|
||||||
#include "lwip/ip_addr.h"
|
|
||||||
#include "lwip/netif.h"
|
|
||||||
#include "lwip/icmp.h"
|
|
||||||
#include "lwip/stats.h"
|
|
||||||
#include "lwip/snmp.h"
|
|
||||||
#include "arch/perf.h"
|
|
||||||
#include "lwip/dhcp.h"
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
/* The list of UDP PCBs */
|
|
||||||
/* exported in udp.h (was static) */
|
|
||||||
struct udp_pcb *udp_pcbs;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Process an incoming UDP datagram.
|
|
||||||
*
|
|
||||||
* Given an incoming UDP datagram (as a chain of pbufs) this function
|
|
||||||
* finds a corresponding UDP PCB and hands over the pbuf to the pcbs
|
|
||||||
* recv function. If no pcb is found or the datagram is incorrect, the
|
|
||||||
* pbuf is freed.
|
|
||||||
*
|
|
||||||
* @param p pbuf to be demultiplexed to a UDP PCB.
|
|
||||||
* @param inp network interface on which the datagram was received.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
udp_input(struct pbuf *p, struct netif *inp)
|
|
||||||
{
|
|
||||||
struct udp_hdr *udphdr;
|
|
||||||
struct udp_pcb *pcb, *prev;
|
|
||||||
struct udp_pcb *uncon_pcb;
|
|
||||||
struct ip_hdr *iphdr;
|
|
||||||
u16_t src, dest;
|
|
||||||
u8_t local_match;
|
|
||||||
u8_t broadcast;
|
|
||||||
|
|
||||||
PERF_START;
|
|
||||||
|
|
||||||
UDP_STATS_INC(udp.recv);
|
|
||||||
|
|
||||||
iphdr = p->payload;
|
|
||||||
|
|
||||||
/* Check minimum length (IP header + UDP header)
|
|
||||||
* and move payload pointer to UDP header */
|
|
||||||
if (p->tot_len < (IPH_HL(iphdr) * 4 + UDP_HLEN) || pbuf_header(p, -(s16_t)(IPH_HL(iphdr) * 4))) {
|
|
||||||
/* drop short packets */
|
|
||||||
LWIP_DEBUGF(UDP_DEBUG,
|
|
||||||
("udp_input: short UDP datagram (%"U16_F" bytes) discarded\n", p->tot_len));
|
|
||||||
UDP_STATS_INC(udp.lenerr);
|
|
||||||
UDP_STATS_INC(udp.drop);
|
|
||||||
snmp_inc_udpinerrors();
|
|
||||||
pbuf_free(p);
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
|
|
||||||
udphdr = (struct udp_hdr *)p->payload;
|
|
||||||
|
|
||||||
/* is broadcast packet ? */
|
|
||||||
broadcast = ip_addr_isbroadcast(&(iphdr->dest), inp);
|
|
||||||
|
|
||||||
LWIP_DEBUGF(UDP_DEBUG, ("udp_input: received datagram of length %"U16_F"\n", p->tot_len));
|
|
||||||
|
|
||||||
/* convert src and dest ports to host byte order */
|
|
||||||
src = ntohs(udphdr->src);
|
|
||||||
dest = ntohs(udphdr->dest);
|
|
||||||
|
|
||||||
udp_debug_print(udphdr);
|
|
||||||
|
|
||||||
/* print the UDP source and destination */
|
|
||||||
LWIP_DEBUGF(UDP_DEBUG,
|
|
||||||
("udp (%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F") <-- "
|
|
||||||
"(%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F")\n",
|
|
||||||
ip4_addr1(&iphdr->dest), ip4_addr2(&iphdr->dest),
|
|
||||||
ip4_addr3(&iphdr->dest), ip4_addr4(&iphdr->dest), ntohs(udphdr->dest),
|
|
||||||
ip4_addr1(&iphdr->src), ip4_addr2(&iphdr->src),
|
|
||||||
ip4_addr3(&iphdr->src), ip4_addr4(&iphdr->src), ntohs(udphdr->src)));
|
|
||||||
|
|
||||||
#if LWIP_DHCP
|
|
||||||
pcb = NULL;
|
|
||||||
/* when LWIP_DHCP is active, packets to DHCP_CLIENT_PORT may only be processed by
|
|
||||||
the dhcp module, no other UDP pcb may use the local UDP port DHCP_CLIENT_PORT */
|
|
||||||
if (dest == DHCP_CLIENT_PORT) {
|
|
||||||
/* all packets for DHCP_CLIENT_PORT not coming from DHCP_SERVER_PORT are dropped! */
|
|
||||||
if (src == DHCP_SERVER_PORT) {
|
|
||||||
if ((inp->dhcp != NULL) && (inp->dhcp->pcb != NULL)) {
|
|
||||||
/* accept the packe if
|
|
||||||
(- broadcast or directed to us) -> DHCP is link-layer-addressed, local ip is always ANY!
|
|
||||||
- inp->dhcp->pcb->remote == ANY or iphdr->src */
|
|
||||||
if ((ip_addr_isany(&inp->dhcp->pcb->remote_ip) ||
|
|
||||||
ip_addr_cmp(&(inp->dhcp->pcb->remote_ip), &(iphdr->src)))) {
|
|
||||||
pcb = inp->dhcp->pcb;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
#endif /* LWIP_DHCP */
|
|
||||||
{
|
|
||||||
prev = NULL;
|
|
||||||
local_match = 0;
|
|
||||||
uncon_pcb = NULL;
|
|
||||||
/* Iterate through the UDP pcb list for a matching pcb.
|
|
||||||
* 'Perfect match' pcbs (connected to the remote port & ip address) are
|
|
||||||
* preferred. If no perfect match is found, the first unconnected pcb that
|
|
||||||
* matches the local port and ip address gets the datagram. */
|
|
||||||
for (pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) {
|
|
||||||
local_match = 0;
|
|
||||||
/* print the PCB local and remote address */
|
|
||||||
LWIP_DEBUGF(UDP_DEBUG,
|
|
||||||
("pcb (%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F") --- "
|
|
||||||
"(%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F")\n",
|
|
||||||
ip4_addr1(&pcb->local_ip), ip4_addr2(&pcb->local_ip),
|
|
||||||
ip4_addr3(&pcb->local_ip), ip4_addr4(&pcb->local_ip), pcb->local_port,
|
|
||||||
ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip),
|
|
||||||
ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip), pcb->remote_port));
|
|
||||||
|
|
||||||
/* compare PCB local addr+port to UDP destination addr+port */
|
|
||||||
if ((pcb->local_port == dest) &&
|
|
||||||
((!broadcast && ip_addr_isany(&pcb->local_ip)) ||
|
|
||||||
ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)) ||
|
|
||||||
#if LWIP_IGMP
|
|
||||||
ip_addr_ismulticast(&(iphdr->dest)) ||
|
|
||||||
#endif /* LWIP_IGMP */
|
|
||||||
#if IP_SOF_BROADCAST_RECV
|
|
||||||
(broadcast && (pcb->so_options & SOF_BROADCAST)))) {
|
|
||||||
#else /* IP_SOF_BROADCAST_RECV */
|
|
||||||
(broadcast))) {
|
|
||||||
#endif /* IP_SOF_BROADCAST_RECV */
|
|
||||||
local_match = 1;
|
|
||||||
if ((uncon_pcb == NULL) &&
|
|
||||||
((pcb->flags & UDP_FLAGS_CONNECTED) == 0)) {
|
|
||||||
/* the first unconnected matching PCB */
|
|
||||||
uncon_pcb = pcb;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* compare PCB remote addr+port to UDP source addr+port */
|
|
||||||
if ((local_match != 0) &&
|
|
||||||
(pcb->remote_port == src) &&
|
|
||||||
(ip_addr_isany(&pcb->remote_ip) ||
|
|
||||||
ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src)))) {
|
|
||||||
/* the first fully matching PCB */
|
|
||||||
if (prev != NULL) {
|
|
||||||
/* move the pcb to the front of udp_pcbs so that is
|
|
||||||
found faster next time */
|
|
||||||
prev->next = pcb->next;
|
|
||||||
pcb->next = udp_pcbs;
|
|
||||||
udp_pcbs = pcb;
|
|
||||||
} else {
|
|
||||||
UDP_STATS_INC(udp.cachehit);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/* This part of code has been modified by ST's MCD Application Team */
|
|
||||||
/* To use the UPnP responder for device discovery */
|
|
||||||
#if LWIP_UPNP
|
|
||||||
if((local_match != 0) && (dest == 1900)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#endif /* LWIP_UPNP */
|
|
||||||
prev = pcb;
|
|
||||||
}
|
|
||||||
/* no fully matching pcb found? then look for an unconnected pcb */
|
|
||||||
if (pcb == NULL) {
|
|
||||||
pcb = uncon_pcb;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check checksum if this is a match or if it was directed at us. */
|
|
||||||
if (pcb != NULL || ip_addr_cmp(&inp->ip_addr, &iphdr->dest)) {
|
|
||||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: calculating checksum\n"));
|
|
||||||
#if LWIP_UDPLITE
|
|
||||||
if (IPH_PROTO(iphdr) == IP_PROTO_UDPLITE) {
|
|
||||||
/* Do the UDP Lite checksum */
|
|
||||||
#if CHECKSUM_CHECK_UDP
|
|
||||||
u16_t chklen = ntohs(udphdr->len);
|
|
||||||
if (chklen < sizeof(struct udp_hdr)) {
|
|
||||||
if (chklen == 0) {
|
|
||||||
/* For UDP-Lite, checksum length of 0 means checksum
|
|
||||||
over the complete packet (See RFC 3828 chap. 3.1) */
|
|
||||||
chklen = p->tot_len;
|
|
||||||
} else {
|
|
||||||
/* At least the UDP-Lite header must be covered by the
|
|
||||||
checksum! (Again, see RFC 3828 chap. 3.1) */
|
|
||||||
UDP_STATS_INC(udp.chkerr);
|
|
||||||
UDP_STATS_INC(udp.drop);
|
|
||||||
snmp_inc_udpinerrors();
|
|
||||||
pbuf_free(p);
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (inet_chksum_pseudo_partial(p, (struct ip_addr *)&(iphdr->src),
|
|
||||||
(struct ip_addr *)&(iphdr->dest),
|
|
||||||
IP_PROTO_UDPLITE, p->tot_len, chklen) != 0) {
|
|
||||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
|
|
||||||
("udp_input: UDP Lite datagram discarded due to failing checksum\n"));
|
|
||||||
UDP_STATS_INC(udp.chkerr);
|
|
||||||
UDP_STATS_INC(udp.drop);
|
|
||||||
snmp_inc_udpinerrors();
|
|
||||||
pbuf_free(p);
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
#endif /* CHECKSUM_CHECK_UDP */
|
|
||||||
} else
|
|
||||||
#endif /* LWIP_UDPLITE */
|
|
||||||
{
|
|
||||||
#if CHECKSUM_CHECK_UDP
|
|
||||||
if (udphdr->chksum != 0) {
|
|
||||||
if (inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src),
|
|
||||||
(struct ip_addr *)&(iphdr->dest),
|
|
||||||
IP_PROTO_UDP, p->tot_len) != 0) {
|
|
||||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
|
|
||||||
("udp_input: UDP datagram discarded due to failing checksum\n"));
|
|
||||||
UDP_STATS_INC(udp.chkerr);
|
|
||||||
UDP_STATS_INC(udp.drop);
|
|
||||||
snmp_inc_udpinerrors();
|
|
||||||
pbuf_free(p);
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif /* CHECKSUM_CHECK_UDP */
|
|
||||||
}
|
|
||||||
if(pbuf_header(p, -UDP_HLEN)) {
|
|
||||||
/* Can we cope with this failing? Just assert for now */
|
|
||||||
LWIP_ASSERT("pbuf_header failed\n", 0);
|
|
||||||
UDP_STATS_INC(udp.drop);
|
|
||||||
snmp_inc_udpinerrors();
|
|
||||||
pbuf_free(p);
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
if (pcb != NULL) {
|
|
||||||
snmp_inc_udpindatagrams();
|
|
||||||
/* callback */
|
|
||||||
if (pcb->recv != NULL) {
|
|
||||||
/* now the recv function is responsible for freeing p */
|
|
||||||
pcb->recv(pcb->recv_arg, pcb, p, &iphdr->src, src);
|
|
||||||
} else {
|
|
||||||
/* no recv function registered? then we have to free the pbuf! */
|
|
||||||
pbuf_free(p);
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: not for us.\n"));
|
|
||||||
|
|
||||||
#if LWIP_ICMP
|
|
||||||
/* No match was found, send ICMP destination port unreachable unless
|
|
||||||
destination address was broadcast/multicast. */
|
|
||||||
if (!broadcast &&
|
|
||||||
!ip_addr_ismulticast(&iphdr->dest)) {
|
|
||||||
/* move payload pointer back to ip header */
|
|
||||||
pbuf_header(p, (IPH_HL(iphdr) * 4) + UDP_HLEN);
|
|
||||||
LWIP_ASSERT("p->payload == iphdr", (p->payload == iphdr));
|
|
||||||
icmp_dest_unreach(p, ICMP_DUR_PORT);
|
|
||||||
}
|
|
||||||
#endif /* LWIP_ICMP */
|
|
||||||
UDP_STATS_INC(udp.proterr);
|
|
||||||
UDP_STATS_INC(udp.drop);
|
|
||||||
snmp_inc_udpnoports();
|
|
||||||
pbuf_free(p);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
pbuf_free(p);
|
|
||||||
}
|
|
||||||
end:
|
|
||||||
PERF_STOP("udp_input");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send data using UDP.
|
|
||||||
*
|
|
||||||
* @param pcb UDP PCB used to send the data.
|
|
||||||
* @param p chain of pbuf's to be sent.
|
|
||||||
*
|
|
||||||
* The datagram will be sent to the current remote_ip & remote_port
|
|
||||||
* stored in pcb. If the pcb is not bound to a port, it will
|
|
||||||
* automatically be bound to a random port.
|
|
||||||
*
|
|
||||||
* @return lwIP error code.
|
|
||||||
* - ERR_OK. Successful. No error occured.
|
|
||||||
* - ERR_MEM. Out of memory.
|
|
||||||
* - ERR_RTE. Could not find route to destination address.
|
|
||||||
* - More errors could be returned by lower protocol layers.
|
|
||||||
*
|
|
||||||
* @see udp_disconnect() udp_sendto()
|
|
||||||
*/
|
|
||||||
err_t
|
|
||||||
udp_send(struct udp_pcb *pcb, struct pbuf *p)
|
|
||||||
{
|
|
||||||
/* send to the packet using remote ip and port stored in the pcb */
|
|
||||||
return udp_sendto(pcb, p, &pcb->remote_ip, pcb->remote_port);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send data to a specified address using UDP.
|
|
||||||
*
|
|
||||||
* @param pcb UDP PCB used to send the data.
|
|
||||||
* @param p chain of pbuf's to be sent.
|
|
||||||
* @param dst_ip Destination IP address.
|
|
||||||
* @param dst_port Destination UDP port.
|
|
||||||
*
|
|
||||||
* dst_ip & dst_port are expected to be in the same byte order as in the pcb.
|
|
||||||
*
|
|
||||||
* If the PCB already has a remote address association, it will
|
|
||||||
* be restored after the data is sent.
|
|
||||||
*
|
|
||||||
* @return lwIP error code (@see udp_send for possible error codes)
|
|
||||||
*
|
|
||||||
* @see udp_disconnect() udp_send()
|
|
||||||
*/
|
|
||||||
err_t
|
|
||||||
udp_sendto(struct udp_pcb *pcb, struct pbuf *p,
|
|
||||||
struct ip_addr *dst_ip, u16_t dst_port)
|
|
||||||
{
|
|
||||||
struct netif *netif;
|
|
||||||
|
|
||||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send\n"));
|
|
||||||
|
|
||||||
/* find the outgoing network interface for this packet */
|
|
||||||
#if LWIP_IGMP
|
|
||||||
netif = ip_route((ip_addr_ismulticast(dst_ip))?(&(pcb->multicast_ip)):(dst_ip));
|
|
||||||
#else
|
|
||||||
netif = ip_route(dst_ip);
|
|
||||||
#endif /* LWIP_IGMP */
|
|
||||||
|
|
||||||
/* no outgoing network interface could be found? */
|
|
||||||
if (netif == NULL) {
|
|
||||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: No route to 0x%"X32_F"\n", dst_ip->addr));
|
|
||||||
UDP_STATS_INC(udp.rterr);
|
|
||||||
return ERR_RTE;
|
|
||||||
}
|
|
||||||
return udp_sendto_if(pcb, p, dst_ip, dst_port, netif);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send data to a specified address using UDP.
|
|
||||||
* The netif used for sending can be specified.
|
|
||||||
*
|
|
||||||
* This function exists mainly for DHCP, to be able to send UDP packets
|
|
||||||
* on a netif that is still down.
|
|
||||||
*
|
|
||||||
* @param pcb UDP PCB used to send the data.
|
|
||||||
* @param p chain of pbuf's to be sent.
|
|
||||||
* @param dst_ip Destination IP address.
|
|
||||||
* @param dst_port Destination UDP port.
|
|
||||||
* @param netif the netif used for sending.
|
|
||||||
*
|
|
||||||
* dst_ip & dst_port are expected to be in the same byte order as in the pcb.
|
|
||||||
*
|
|
||||||
* @return lwIP error code (@see udp_send for possible error codes)
|
|
||||||
*
|
|
||||||
* @see udp_disconnect() udp_send()
|
|
||||||
*/
|
|
||||||
err_t
|
|
||||||
udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p,
|
|
||||||
struct ip_addr *dst_ip, u16_t dst_port, struct netif *netif)
|
|
||||||
{
|
|
||||||
struct udp_hdr *udphdr;
|
|
||||||
struct ip_addr *src_ip;
|
|
||||||
err_t err;
|
|
||||||
struct pbuf *q; /* q will be sent down the stack */
|
|
||||||
|
|
||||||
#if IP_SOF_BROADCAST
|
|
||||||
/* broadcast filter? */
|
|
||||||
if ( ((pcb->so_options & SOF_BROADCAST) == 0) && ip_addr_isbroadcast(dst_ip, netif) ) {
|
|
||||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
|
|
||||||
("udp_sendto_if: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb));
|
|
||||||
return ERR_VAL;
|
|
||||||
}
|
|
||||||
#endif /* IP_SOF_BROADCAST */
|
|
||||||
|
|
||||||
/* if the PCB is not yet bound to a port, bind it here */
|
|
||||||
if (pcb->local_port == 0) {
|
|
||||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send: not yet bound to a port, binding now\n"));
|
|
||||||
err = udp_bind(pcb, &pcb->local_ip, pcb->local_port);
|
|
||||||
if (err != ERR_OK) {
|
|
||||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: forced port bind failed\n"));
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* not enough space to add an UDP header to first pbuf in given p chain? */
|
|
||||||
if (pbuf_header(p, UDP_HLEN)) {
|
|
||||||
/* allocate header in a separate new pbuf */
|
|
||||||
q = pbuf_alloc(PBUF_IP, UDP_HLEN, PBUF_RAM);
|
|
||||||
/* new header pbuf could not be allocated? */
|
|
||||||
if (q == NULL) {
|
|
||||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: could not allocate header\n"));
|
|
||||||
return ERR_MEM;
|
|
||||||
}
|
|
||||||
/* chain header q in front of given pbuf p */
|
|
||||||
pbuf_chain(q, p);
|
|
||||||
/* first pbuf q points to header pbuf */
|
|
||||||
LWIP_DEBUGF(UDP_DEBUG,
|
|
||||||
("udp_send: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p));
|
|
||||||
} else {
|
|
||||||
/* adding space for header within p succeeded */
|
|
||||||
/* first pbuf q equals given pbuf */
|
|
||||||
q = p;
|
|
||||||
LWIP_DEBUGF(UDP_DEBUG, ("udp_send: added header in given pbuf %p\n", (void *)p));
|
|
||||||
}
|
|
||||||
LWIP_ASSERT("check that first pbuf can hold struct udp_hdr",
|
|
||||||
(q->len >= sizeof(struct udp_hdr)));
|
|
||||||
/* q now represents the packet to be sent */
|
|
||||||
udphdr = q->payload;
|
|
||||||
udphdr->src = htons(pcb->local_port);
|
|
||||||
udphdr->dest = htons(dst_port);
|
|
||||||
/* in UDP, 0 checksum means 'no checksum' */
|
|
||||||
udphdr->chksum = 0x0000;
|
|
||||||
|
|
||||||
/* PCB local address is IP_ANY_ADDR? */
|
|
||||||
if (ip_addr_isany(&pcb->local_ip)) {
|
|
||||||
/* use outgoing network interface IP address as source address */
|
|
||||||
src_ip = &(netif->ip_addr);
|
|
||||||
} else {
|
|
||||||
/* check if UDP PCB local IP address is correct
|
|
||||||
* this could be an old address if netif->ip_addr has changed */
|
|
||||||
if (!ip_addr_cmp(&(pcb->local_ip), &(netif->ip_addr))) {
|
|
||||||
/* local_ip doesn't match, drop the packet */
|
|
||||||
if (q != p) {
|
|
||||||
/* free the header pbuf */
|
|
||||||
pbuf_free(q);
|
|
||||||
q = NULL;
|
|
||||||
/* p is still referenced by the caller, and will live on */
|
|
||||||
}
|
|
||||||
return ERR_VAL;
|
|
||||||
}
|
|
||||||
/* use UDP PCB local IP address as source address */
|
|
||||||
src_ip = &(pcb->local_ip);
|
|
||||||
}
|
|
||||||
|
|
||||||
LWIP_DEBUGF(UDP_DEBUG, ("udp_send: sending datagram of length %"U16_F"\n", q->tot_len));
|
|
||||||
|
|
||||||
#if LWIP_UDPLITE
|
|
||||||
/* UDP Lite protocol? */
|
|
||||||
if (pcb->flags & UDP_FLAGS_UDPLITE) {
|
|
||||||
u16_t chklen, chklen_hdr;
|
|
||||||
LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP LITE packet length %"U16_F"\n", q->tot_len));
|
|
||||||
/* set UDP message length in UDP header */
|
|
||||||
chklen_hdr = chklen = pcb->chksum_len_tx;
|
|
||||||
if ((chklen < sizeof(struct udp_hdr)) || (chklen > q->tot_len)) {
|
|
||||||
if (chklen != 0) {
|
|
||||||
LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP LITE pcb->chksum_len is illegal: %"U16_F"\n", chklen));
|
|
||||||
}
|
|
||||||
/* For UDP-Lite, checksum length of 0 means checksum
|
|
||||||
over the complete packet. (See RFC 3828 chap. 3.1)
|
|
||||||
At least the UDP-Lite header must be covered by the
|
|
||||||
checksum, therefore, if chksum_len has an illegal
|
|
||||||
value, we generate the checksum over the complete
|
|
||||||
packet to be safe. */
|
|
||||||
chklen_hdr = 0;
|
|
||||||
chklen = q->tot_len;
|
|
||||||
}
|
|
||||||
udphdr->len = htons(chklen_hdr);
|
|
||||||
/* calculate checksum */
|
|
||||||
#if CHECKSUM_GEN_UDP
|
|
||||||
udphdr->chksum = inet_chksum_pseudo_partial(q, src_ip, dst_ip,
|
|
||||||
IP_PROTO_UDPLITE, q->tot_len, chklen);
|
|
||||||
/* chksum zero must become 0xffff, as zero means 'no checksum' */
|
|
||||||
if (udphdr->chksum == 0x0000)
|
|
||||||
udphdr->chksum = 0xffff;
|
|
||||||
#endif /* CHECKSUM_CHECK_UDP */
|
|
||||||
/* output to IP */
|
|
||||||
LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDPLITE,)\n"));
|
|
||||||
#if LWIP_NETIF_HWADDRHINT
|
|
||||||
netif->addr_hint = &(pcb->addr_hint);
|
|
||||||
#endif /* LWIP_NETIF_HWADDRHINT*/
|
|
||||||
err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, IP_PROTO_UDPLITE, netif);
|
|
||||||
#if LWIP_NETIF_HWADDRHINT
|
|
||||||
netif->addr_hint = NULL;
|
|
||||||
#endif /* LWIP_NETIF_HWADDRHINT*/
|
|
||||||
} else
|
|
||||||
#endif /* LWIP_UDPLITE */
|
|
||||||
{ /* UDP */
|
|
||||||
LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP packet length %"U16_F"\n", q->tot_len));
|
|
||||||
udphdr->len = htons(q->tot_len);
|
|
||||||
/* calculate checksum */
|
|
||||||
#if CHECKSUM_GEN_UDP
|
|
||||||
if ((pcb->flags & UDP_FLAGS_NOCHKSUM) == 0) {
|
|
||||||
udphdr->chksum = inet_chksum_pseudo(q, src_ip, dst_ip, IP_PROTO_UDP, q->tot_len);
|
|
||||||
/* chksum zero must become 0xffff, as zero means 'no checksum' */
|
|
||||||
if (udphdr->chksum == 0x0000) udphdr->chksum = 0xffff;
|
|
||||||
}
|
|
||||||
#endif /* CHECKSUM_CHECK_UDP */
|
|
||||||
LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP checksum 0x%04"X16_F"\n", udphdr->chksum));
|
|
||||||
LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDP,)\n"));
|
|
||||||
/* output to IP */
|
|
||||||
#if LWIP_NETIF_HWADDRHINT
|
|
||||||
netif->addr_hint = &(pcb->addr_hint);
|
|
||||||
#endif /* LWIP_NETIF_HWADDRHINT*/
|
|
||||||
err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, IP_PROTO_UDP, netif);
|
|
||||||
#if LWIP_NETIF_HWADDRHINT
|
|
||||||
netif->addr_hint = NULL;
|
|
||||||
#endif /* LWIP_NETIF_HWADDRHINT*/
|
|
||||||
}
|
|
||||||
/* TODO: must this be increased even if error occured? */
|
|
||||||
snmp_inc_udpoutdatagrams();
|
|
||||||
|
|
||||||
/* did we chain a separate header pbuf earlier? */
|
|
||||||
if (q != p) {
|
|
||||||
/* free the header pbuf */
|
|
||||||
pbuf_free(q);
|
|
||||||
q = NULL;
|
|
||||||
/* p is still referenced by the caller, and will live on */
|
|
||||||
}
|
|
||||||
|
|
||||||
UDP_STATS_INC(udp.xmit);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Bind an UDP PCB.
|
|
||||||
*
|
|
||||||
* @param pcb UDP PCB to be bound with a local address ipaddr and port.
|
|
||||||
* @param ipaddr local IP address to bind with. Use IP_ADDR_ANY to
|
|
||||||
* bind to all local interfaces.
|
|
||||||
* @param port local UDP port to bind with. Use 0 to automatically bind
|
|
||||||
* to a random port between UDP_LOCAL_PORT_RANGE_START and
|
|
||||||
* UDP_LOCAL_PORT_RANGE_END.
|
|
||||||
*
|
|
||||||
* ipaddr & port are expected to be in the same byte order as in the pcb.
|
|
||||||
*
|
|
||||||
* @return lwIP error code.
|
|
||||||
* - ERR_OK. Successful. No error occured.
|
|
||||||
* - ERR_USE. The specified ipaddr and port are already bound to by
|
|
||||||
* another UDP PCB.
|
|
||||||
*
|
|
||||||
* @see udp_disconnect()
|
|
||||||
*/
|
|
||||||
err_t
|
|
||||||
udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
|
|
||||||
{
|
|
||||||
struct udp_pcb *ipcb;
|
|
||||||
u8_t rebind;
|
|
||||||
|
|
||||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_bind(ipaddr = "));
|
|
||||||
ip_addr_debug_print(UDP_DEBUG, ipaddr);
|
|
||||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, (", port = %"U16_F")\n", port));
|
|
||||||
|
|
||||||
rebind = 0;
|
|
||||||
/* Check for double bind and rebind of the same pcb */
|
|
||||||
for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) {
|
|
||||||
/* is this UDP PCB already on active list? */
|
|
||||||
if (pcb == ipcb) {
|
|
||||||
/* pcb may occur at most once in active list */
|
|
||||||
LWIP_ASSERT("rebind == 0", rebind == 0);
|
|
||||||
/* pcb already in list, just rebind */
|
|
||||||
rebind = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* this code does not allow upper layer to share a UDP port for
|
|
||||||
listening to broadcast or multicast traffic (See SO_REUSE_ADDR and
|
|
||||||
SO_REUSE_PORT under *BSD). TODO: See where it fits instead, OR
|
|
||||||
combine with implementation of UDP PCB flags. Leon Woestenberg. */
|
|
||||||
#ifdef LWIP_UDP_TODO
|
|
||||||
/* port matches that of PCB in list? */
|
|
||||||
else
|
|
||||||
if ((ipcb->local_port == port) &&
|
|
||||||
/* IP address matches, or one is IP_ADDR_ANY? */
|
|
||||||
(ip_addr_isany(&(ipcb->local_ip)) ||
|
|
||||||
ip_addr_isany(ipaddr) ||
|
|
||||||
ip_addr_cmp(&(ipcb->local_ip), ipaddr))) {
|
|
||||||
/* other PCB already binds to this local IP and port */
|
|
||||||
LWIP_DEBUGF(UDP_DEBUG,
|
|
||||||
("udp_bind: local port %"U16_F" already bound by another pcb\n", port));
|
|
||||||
return ERR_USE;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
ip_addr_set(&pcb->local_ip, ipaddr);
|
|
||||||
|
|
||||||
/* no port specified? */
|
|
||||||
if (port == 0) {
|
|
||||||
#ifndef UDP_LOCAL_PORT_RANGE_START
|
|
||||||
#define UDP_LOCAL_PORT_RANGE_START 4096
|
|
||||||
#define UDP_LOCAL_PORT_RANGE_END 0x7fff
|
|
||||||
#endif
|
|
||||||
port = UDP_LOCAL_PORT_RANGE_START;
|
|
||||||
ipcb = udp_pcbs;
|
|
||||||
while ((ipcb != NULL) && (port != UDP_LOCAL_PORT_RANGE_END)) {
|
|
||||||
if (ipcb->local_port == port) {
|
|
||||||
/* port is already used by another udp_pcb */
|
|
||||||
port++;
|
|
||||||
/* restart scanning all udp pcbs */
|
|
||||||
ipcb = udp_pcbs;
|
|
||||||
} else
|
|
||||||
/* go on with next udp pcb */
|
|
||||||
ipcb = ipcb->next;
|
|
||||||
}
|
|
||||||
if (ipcb != NULL) {
|
|
||||||
/* no more ports available in local range */
|
|
||||||
LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: out of free UDP ports\n"));
|
|
||||||
return ERR_USE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pcb->local_port = port;
|
|
||||||
snmp_insert_udpidx_tree(pcb);
|
|
||||||
/* pcb not active yet? */
|
|
||||||
if (rebind == 0) {
|
|
||||||
/* place the PCB on the active list if not already there */
|
|
||||||
pcb->next = udp_pcbs;
|
|
||||||
udp_pcbs = pcb;
|
|
||||||
}
|
|
||||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
|
|
||||||
("udp_bind: bound to %"U16_F".%"U16_F".%"U16_F".%"U16_F", port %"U16_F"\n",
|
|
||||||
(u16_t)((ntohl(pcb->local_ip.addr) >> 24) & 0xff),
|
|
||||||
(u16_t)((ntohl(pcb->local_ip.addr) >> 16) & 0xff),
|
|
||||||
(u16_t)((ntohl(pcb->local_ip.addr) >> 8) & 0xff),
|
|
||||||
(u16_t)(ntohl(pcb->local_ip.addr) & 0xff), pcb->local_port));
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Connect an UDP PCB.
|
|
||||||
*
|
|
||||||
* This will associate the UDP PCB with the remote address.
|
|
||||||
*
|
|
||||||
* @param pcb UDP PCB to be connected with remote address ipaddr and port.
|
|
||||||
* @param ipaddr remote IP address to connect with.
|
|
||||||
* @param port remote UDP port to connect with.
|
|
||||||
*
|
|
||||||
* @return lwIP error code
|
|
||||||
*
|
|
||||||
* ipaddr & port are expected to be in the same byte order as in the pcb.
|
|
||||||
*
|
|
||||||
* The udp pcb is bound to a random local port if not already bound.
|
|
||||||
*
|
|
||||||
* @see udp_disconnect()
|
|
||||||
*/
|
|
||||||
err_t
|
|
||||||
udp_connect(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
|
|
||||||
{
|
|
||||||
struct udp_pcb *ipcb;
|
|
||||||
|
|
||||||
if (pcb->local_port == 0) {
|
|
||||||
err_t err = udp_bind(pcb, &pcb->local_ip, pcb->local_port);
|
|
||||||
if (err != ERR_OK)
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
ip_addr_set(&pcb->remote_ip, ipaddr);
|
|
||||||
pcb->remote_port = port;
|
|
||||||
pcb->flags |= UDP_FLAGS_CONNECTED;
|
|
||||||
/** TODO: this functionality belongs in upper layers */
|
|
||||||
#ifdef LWIP_UDP_TODO
|
|
||||||
/* Nail down local IP for netconn_addr()/getsockname() */
|
|
||||||
if (ip_addr_isany(&pcb->local_ip) && !ip_addr_isany(&pcb->remote_ip)) {
|
|
||||||
struct netif *netif;
|
|
||||||
|
|
||||||
if ((netif = ip_route(&(pcb->remote_ip))) == NULL) {
|
|
||||||
LWIP_DEBUGF(UDP_DEBUG, ("udp_connect: No route to 0x%lx\n", pcb->remote_ip.addr));
|
|
||||||
UDP_STATS_INC(udp.rterr);
|
|
||||||
return ERR_RTE;
|
|
||||||
}
|
|
||||||
/** TODO: this will bind the udp pcb locally, to the interface which
|
|
||||||
is used to route output packets to the remote address. However, we
|
|
||||||
might want to accept incoming packets on any interface! */
|
|
||||||
pcb->local_ip = netif->ip_addr;
|
|
||||||
} else if (ip_addr_isany(&pcb->remote_ip)) {
|
|
||||||
pcb->local_ip.addr = 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
|
|
||||||
("udp_connect: connected to %"U16_F".%"U16_F".%"U16_F".%"U16_F",port %"U16_F"\n",
|
|
||||||
(u16_t)((ntohl(pcb->remote_ip.addr) >> 24) & 0xff),
|
|
||||||
(u16_t)((ntohl(pcb->remote_ip.addr) >> 16) & 0xff),
|
|
||||||
(u16_t)((ntohl(pcb->remote_ip.addr) >> 8) & 0xff),
|
|
||||||
(u16_t)(ntohl(pcb->remote_ip.addr) & 0xff), pcb->remote_port));
|
|
||||||
|
|
||||||
/* Insert UDP PCB into the list of active UDP PCBs. */
|
|
||||||
for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) {
|
|
||||||
if (pcb == ipcb) {
|
|
||||||
/* already on the list, just return */
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* PCB not yet on the list, add PCB now */
|
|
||||||
pcb->next = udp_pcbs;
|
|
||||||
udp_pcbs = pcb;
|
|
||||||
return ERR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Disconnect a UDP PCB
|
|
||||||
*
|
|
||||||
* @param pcb the udp pcb to disconnect.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
udp_disconnect(struct udp_pcb *pcb)
|
|
||||||
{
|
|
||||||
/* reset remote address association */
|
|
||||||
ip_addr_set(&pcb->remote_ip, IP_ADDR_ANY);
|
|
||||||
pcb->remote_port = 0;
|
|
||||||
/* mark PCB as unconnected */
|
|
||||||
pcb->flags &= ~UDP_FLAGS_CONNECTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set a receive callback for a UDP PCB
|
|
||||||
*
|
|
||||||
* This callback will be called when receiving a datagram for the pcb.
|
|
||||||
*
|
|
||||||
* @param pcb the pcb for wich to set the recv callback
|
|
||||||
* @param recv function pointer of the callback function
|
|
||||||
* @param recv_arg additional argument to pass to the callback function
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
udp_recv(struct udp_pcb *pcb,
|
|
||||||
void (* recv)(void *arg, struct udp_pcb *upcb, struct pbuf *p,
|
|
||||||
struct ip_addr *addr, u16_t port),
|
|
||||||
void *recv_arg)
|
|
||||||
{
|
|
||||||
/* remember recv() callback and user data */
|
|
||||||
pcb->recv = recv;
|
|
||||||
pcb->recv_arg = recv_arg;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove an UDP PCB.
|
|
||||||
*
|
|
||||||
* @param pcb UDP PCB to be removed. The PCB is removed from the list of
|
|
||||||
* UDP PCB's and the data structure is freed from memory.
|
|
||||||
*
|
|
||||||
* @see udp_new()
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
udp_remove(struct udp_pcb *pcb)
|
|
||||||
{
|
|
||||||
struct udp_pcb *pcb2;
|
|
||||||
|
|
||||||
snmp_delete_udpidx_tree(pcb);
|
|
||||||
/* pcb to be removed is first in list? */
|
|
||||||
if (udp_pcbs == pcb) {
|
|
||||||
/* make list start at 2nd pcb */
|
|
||||||
udp_pcbs = udp_pcbs->next;
|
|
||||||
/* pcb not 1st in list */
|
|
||||||
} else
|
|
||||||
for (pcb2 = udp_pcbs; pcb2 != NULL; pcb2 = pcb2->next) {
|
|
||||||
/* find pcb in udp_pcbs list */
|
|
||||||
if (pcb2->next != NULL && pcb2->next == pcb) {
|
|
||||||
/* remove pcb from list */
|
|
||||||
pcb2->next = pcb->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
memp_free(MEMP_UDP_PCB, pcb);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a UDP PCB.
|
|
||||||
*
|
|
||||||
* @return The UDP PCB which was created. NULL if the PCB data structure
|
|
||||||
* could not be allocated.
|
|
||||||
*
|
|
||||||
* @see udp_remove()
|
|
||||||
*/
|
|
||||||
struct udp_pcb *
|
|
||||||
udp_new(void)
|
|
||||||
{
|
|
||||||
struct udp_pcb *pcb;
|
|
||||||
pcb = memp_malloc(MEMP_UDP_PCB);
|
|
||||||
/* could allocate UDP PCB? */
|
|
||||||
if (pcb != NULL) {
|
|
||||||
/* UDP Lite: by initializing to all zeroes, chksum_len is set to 0
|
|
||||||
* which means checksum is generated over the whole datagram per default
|
|
||||||
* (recommended as default by RFC 3828). */
|
|
||||||
/* initialize PCB to all zeroes */
|
|
||||||
memset(pcb, 0, sizeof(struct udp_pcb));
|
|
||||||
pcb->ttl = UDP_TTL;
|
|
||||||
}
|
|
||||||
return pcb;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if UDP_DEBUG
|
|
||||||
/**
|
|
||||||
* Print UDP header information for debug purposes.
|
|
||||||
*
|
|
||||||
* @param udphdr pointer to the udp header in memory.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
udp_debug_print(struct udp_hdr *udphdr)
|
|
||||||
{
|
|
||||||
LWIP_DEBUGF(UDP_DEBUG, ("UDP header:\n"));
|
|
||||||
LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n"));
|
|
||||||
LWIP_DEBUGF(UDP_DEBUG, ("| %5"U16_F" | %5"U16_F" | (src port, dest port)\n",
|
|
||||||
ntohs(udphdr->src), ntohs(udphdr->dest)));
|
|
||||||
LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n"));
|
|
||||||
LWIP_DEBUGF(UDP_DEBUG, ("| %5"U16_F" | 0x%04"X16_F" | (len, chksum)\n",
|
|
||||||
ntohs(udphdr->len), ntohs(udphdr->chksum)));
|
|
||||||
LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n"));
|
|
||||||
}
|
|
||||||
#endif /* UDP_DEBUG */
|
|
||||||
|
|
||||||
#endif /* LWIP_UDP */
|
|
|
@ -1,116 +0,0 @@
|
||||||
/**
|
|
||||||
* @file
|
|
||||||
*
|
|
||||||
* AutoIP Automatic LinkLocal IP Configuration
|
|
||||||
**/
|
|
||||||
|
|
||||||
/*
|
|
||||||
*
|
|
||||||
* Copyright (c) 2007 Dominik Spies <kontakt@dspies.de>
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* Author: Dominik Spies <kontakt@dspies.de>
|
|
||||||
*
|
|
||||||
* This is a AutoIP implementation for the lwIP TCP/IP stack. It aims to conform
|
|
||||||
* with RFC 3927.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* Please coordinate changes and requests with Dominik Spies
|
|
||||||
* <kontakt@dspies.de>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __LWIP_AUTOIP_H__
|
|
||||||
#define __LWIP_AUTOIP_H__
|
|
||||||
|
|
||||||
#include "lwip/opt.h"
|
|
||||||
|
|
||||||
#if LWIP_AUTOIP /* don't build if not configured for use in lwipopts.h */
|
|
||||||
|
|
||||||
#include "lwip/netif.h"
|
|
||||||
#include "lwip/udp.h"
|
|
||||||
#include "netif/etharp.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* AutoIP Timing */
|
|
||||||
#define AUTOIP_TMR_INTERVAL 100
|
|
||||||
#define AUTOIP_TICKS_PER_SECOND (1000 / AUTOIP_TMR_INTERVAL)
|
|
||||||
|
|
||||||
/* RFC 3927 Constants */
|
|
||||||
#define PROBE_WAIT 1 /* second (initial random delay) */
|
|
||||||
#define PROBE_MIN 1 /* second (minimum delay till repeated probe) */
|
|
||||||
#define PROBE_MAX 2 /* seconds (maximum delay till repeated probe) */
|
|
||||||
#define PROBE_NUM 3 /* (number of probe packets) */
|
|
||||||
#define ANNOUNCE_NUM 2 /* (number of announcement packets) */
|
|
||||||
#define ANNOUNCE_INTERVAL 2 /* seconds (time between announcement packets) */
|
|
||||||
#define ANNOUNCE_WAIT 2 /* seconds (delay before announcing) */
|
|
||||||
#define MAX_CONFLICTS 10 /* (max conflicts before rate limiting) */
|
|
||||||
#define RATE_LIMIT_INTERVAL 60 /* seconds (delay between successive attempts) */
|
|
||||||
#define DEFEND_INTERVAL 10 /* seconds (min. wait between defensive ARPs) */
|
|
||||||
|
|
||||||
/* AutoIP client states */
|
|
||||||
#define AUTOIP_STATE_OFF 0
|
|
||||||
#define AUTOIP_STATE_PROBING 1
|
|
||||||
#define AUTOIP_STATE_ANNOUNCING 2
|
|
||||||
#define AUTOIP_STATE_BOUND 3
|
|
||||||
|
|
||||||
struct autoip
|
|
||||||
{
|
|
||||||
struct ip_addr llipaddr; /* the currently selected, probed, announced or used LL IP-Address */
|
|
||||||
u8_t state; /* current AutoIP state machine state */
|
|
||||||
u8_t sent_num; /* sent number of probes or announces, dependent on state */
|
|
||||||
u16_t ttw; /* ticks to wait, tick is AUTOIP_TMR_INTERVAL long */
|
|
||||||
u8_t lastconflict; /* ticks until a conflict can be solved by defending */
|
|
||||||
u8_t tried_llipaddr; /* total number of probed/used Link Local IP-Addresses */
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/** Init srand, has to be called before entering mainloop */
|
|
||||||
void autoip_init(void);
|
|
||||||
|
|
||||||
/** Start AutoIP client */
|
|
||||||
err_t autoip_start(struct netif *netif);
|
|
||||||
|
|
||||||
/** Stop AutoIP client */
|
|
||||||
err_t autoip_stop(struct netif *netif);
|
|
||||||
|
|
||||||
/** Handles every incoming ARP Packet, called by etharp_arp_input */
|
|
||||||
void autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr);
|
|
||||||
|
|
||||||
/** Has to be called in loop every AUTOIP_TMR_INTERVAL milliseconds */
|
|
||||||
void autoip_tmr(void);
|
|
||||||
|
|
||||||
/** Handle a possible change in the network configuration */
|
|
||||||
void autoip_network_changed(struct netif *netif);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* LWIP_AUTOIP */
|
|
||||||
|
|
||||||
#endif /* __LWIP_AUTOIP_H__ */
|
|
|
@ -1,111 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
**/
|
|
||||||
#ifndef __LWIP_ICMP_H__
|
|
||||||
#define __LWIP_ICMP_H__
|
|
||||||
|
|
||||||
#include "lwip/opt.h"
|
|
||||||
#include "lwip/pbuf.h"
|
|
||||||
#include "lwip/ip_addr.h"
|
|
||||||
#include "lwip/netif.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define ICMP_ER 0 /* echo reply */
|
|
||||||
#define ICMP_DUR 3 /* destination unreachable */
|
|
||||||
#define ICMP_SQ 4 /* source quench */
|
|
||||||
#define ICMP_RD 5 /* redirect */
|
|
||||||
#define ICMP_ECHO 8 /* echo */
|
|
||||||
#define ICMP_TE 11 /* time exceeded */
|
|
||||||
#define ICMP_PP 12 /* parameter problem */
|
|
||||||
#define ICMP_TS 13 /* timestamp */
|
|
||||||
#define ICMP_TSR 14 /* timestamp reply */
|
|
||||||
#define ICMP_IRQ 15 /* information request */
|
|
||||||
#define ICMP_IR 16 /* information reply */
|
|
||||||
|
|
||||||
enum icmp_dur_type {
|
|
||||||
ICMP_DUR_NET = 0, /* net unreachable */
|
|
||||||
ICMP_DUR_HOST = 1, /* host unreachable */
|
|
||||||
ICMP_DUR_PROTO = 2, /* protocol unreachable */
|
|
||||||
ICMP_DUR_PORT = 3, /* port unreachable */
|
|
||||||
ICMP_DUR_FRAG = 4, /* fragmentation needed and DF set */
|
|
||||||
ICMP_DUR_SR = 5 /* source route failed */
|
|
||||||
};
|
|
||||||
|
|
||||||
enum icmp_te_type {
|
|
||||||
ICMP_TE_TTL = 0, /* time to live exceeded in transit */
|
|
||||||
ICMP_TE_FRAG = 1 /* fragment reassembly time exceeded */
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
|
||||||
# include "arch/bpstruct.h"
|
|
||||||
#endif
|
|
||||||
/** This is the standard ICMP header only that the u32_t data
|
|
||||||
* is splitted to two u16_t like ICMP echo needs it.
|
|
||||||
* This header is also used for other ICMP types that do not
|
|
||||||
* use the data part.
|
|
||||||
*/
|
|
||||||
PACK_STRUCT_BEGIN
|
|
||||||
struct icmp_echo_hdr {
|
|
||||||
PACK_STRUCT_FIELD(u8_t type);
|
|
||||||
PACK_STRUCT_FIELD(u8_t code);
|
|
||||||
PACK_STRUCT_FIELD(u16_t chksum);
|
|
||||||
PACK_STRUCT_FIELD(u16_t id);
|
|
||||||
PACK_STRUCT_FIELD(u16_t seqno);
|
|
||||||
} PACK_STRUCT_STRUCT;
|
|
||||||
PACK_STRUCT_END
|
|
||||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
|
||||||
# include "arch/epstruct.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define ICMPH_TYPE(hdr) ((hdr)->type)
|
|
||||||
#define ICMPH_CODE(hdr) ((hdr)->code)
|
|
||||||
|
|
||||||
/** Combines type and code to an u16_t */
|
|
||||||
#define ICMPH_TYPE_SET(hdr, t) ((hdr)->type = (t))
|
|
||||||
#define ICMPH_CODE_SET(hdr, c) ((hdr)->code = (c))
|
|
||||||
|
|
||||||
|
|
||||||
#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */
|
|
||||||
|
|
||||||
void icmp_input(struct pbuf *p, struct netif *inp);
|
|
||||||
void icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t);
|
|
||||||
void icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t);
|
|
||||||
|
|
||||||
#endif /* LWIP_ICMP */
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* __LWIP_ICMP_H__ */
|
|
|
@ -1,162 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright (c) 2002 CITEL Technologies Ltd.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of CITEL Technologies Ltd nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY CITEL TECHNOLOGIES AND CONTRIBUTORS ``AS IS''
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL CITEL TECHNOLOGIES OR CONTRIBUTORS BE LIABLE
|
|
||||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
||||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
||||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
||||||
* SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is a contribution to the lwIP TCP/IP stack.
|
|
||||||
* The Swedish Institute of Computer Science and Adam Dunkels
|
|
||||||
* are specifically granted permission to redistribute this
|
|
||||||
* source code.
|
|
||||||
**/
|
|
||||||
|
|
||||||
#ifndef __LWIP_IGMP_H__
|
|
||||||
#define __LWIP_IGMP_H__
|
|
||||||
|
|
||||||
#include "lwip/opt.h"
|
|
||||||
#include "lwip/ip_addr.h"
|
|
||||||
#include "lwip/netif.h"
|
|
||||||
#include "lwip/pbuf.h"
|
|
||||||
|
|
||||||
#if LWIP_IGMP /* don't build if not configured for use in lwipopts.h */
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* IGMP constants
|
|
||||||
*/
|
|
||||||
#define IP_PROTO_IGMP 2
|
|
||||||
#define IGMP_TTL 1
|
|
||||||
#define IGMP_MINLEN 8
|
|
||||||
#define ROUTER_ALERT 0x9404
|
|
||||||
#define ROUTER_ALERTLEN 4
|
|
||||||
|
|
||||||
/*
|
|
||||||
* IGMP message types, including version number.
|
|
||||||
*/
|
|
||||||
#define IGMP_MEMB_QUERY 0x11 /* Membership query */
|
|
||||||
#define IGMP_V1_MEMB_REPORT 0x12 /* Ver. 1 membership report */
|
|
||||||
#define IGMP_V2_MEMB_REPORT 0x16 /* Ver. 2 membership report */
|
|
||||||
#define IGMP_LEAVE_GROUP 0x17 /* Leave-group message */
|
|
||||||
|
|
||||||
/* IGMP timer */
|
|
||||||
#define IGMP_TMR_INTERVAL 100 /* Milliseconds */
|
|
||||||
#define IGMP_V1_DELAYING_MEMBER_TMR (1000/IGMP_TMR_INTERVAL)
|
|
||||||
#define IGMP_JOIN_DELAYING_MEMBER_TMR (500 /IGMP_TMR_INTERVAL)
|
|
||||||
|
|
||||||
/* MAC Filter Actions */
|
|
||||||
#define IGMP_DEL_MAC_FILTER 0
|
|
||||||
#define IGMP_ADD_MAC_FILTER 1
|
|
||||||
|
|
||||||
/* Group membership states */
|
|
||||||
#define IGMP_GROUP_NON_MEMBER 0
|
|
||||||
#define IGMP_GROUP_DELAYING_MEMBER 1
|
|
||||||
#define IGMP_GROUP_IDLE_MEMBER 2
|
|
||||||
|
|
||||||
/*
|
|
||||||
* IGMP packet format.
|
|
||||||
*/
|
|
||||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
|
||||||
# include "arch/bpstruct.h"
|
|
||||||
#endif
|
|
||||||
PACK_STRUCT_BEGIN
|
|
||||||
struct igmp_msg {
|
|
||||||
PACK_STRUCT_FIELD(u8_t igmp_msgtype);
|
|
||||||
PACK_STRUCT_FIELD(u8_t igmp_maxresp);
|
|
||||||
PACK_STRUCT_FIELD(u16_t igmp_checksum);
|
|
||||||
PACK_STRUCT_FIELD(struct ip_addr igmp_group_address);
|
|
||||||
} PACK_STRUCT_STRUCT;
|
|
||||||
PACK_STRUCT_END
|
|
||||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
|
||||||
# include "arch/epstruct.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* now a group structure - there is
|
|
||||||
* a list of groups for each interface
|
|
||||||
* these should really be linked from the interface, but
|
|
||||||
* if we keep them separate we will not affect the lwip original code
|
|
||||||
* too much
|
|
||||||
*
|
|
||||||
* There will be a group for the all systems group address but this
|
|
||||||
* will not run the state machine as it is used to kick off reports
|
|
||||||
* from all the other groups
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct igmp_group {
|
|
||||||
struct igmp_group *next;
|
|
||||||
struct netif *interface;
|
|
||||||
struct ip_addr group_address;
|
|
||||||
u8_t last_reporter_flag; /* signifies we were the last person to report */
|
|
||||||
u8_t group_state;
|
|
||||||
u16_t timer;
|
|
||||||
u8_t use; /* counter of simultaneous uses */
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/* Prototypes */
|
|
||||||
void igmp_init(void);
|
|
||||||
|
|
||||||
err_t igmp_start( struct netif *netif);
|
|
||||||
|
|
||||||
err_t igmp_stop( struct netif *netif);
|
|
||||||
|
|
||||||
void igmp_report_groups( struct netif *netif);
|
|
||||||
|
|
||||||
struct igmp_group *igmp_lookfor_group( struct netif *ifp, struct ip_addr *addr);
|
|
||||||
|
|
||||||
struct igmp_group *igmp_lookup_group( struct netif *ifp, struct ip_addr *addr);
|
|
||||||
|
|
||||||
err_t igmp_remove_group( struct igmp_group *group);
|
|
||||||
|
|
||||||
void igmp_input( struct pbuf *p, struct netif *inp, struct ip_addr *dest);
|
|
||||||
|
|
||||||
err_t igmp_joingroup( struct ip_addr *ifaddr, struct ip_addr *groupaddr);
|
|
||||||
|
|
||||||
err_t igmp_leavegroup( struct ip_addr *ifaddr, struct ip_addr *groupaddr);
|
|
||||||
|
|
||||||
void igmp_tmr(void);
|
|
||||||
|
|
||||||
void igmp_timeout( struct igmp_group *group);
|
|
||||||
|
|
||||||
void igmp_start_timer( struct igmp_group *group, u8_t max_time);
|
|
||||||
|
|
||||||
void igmp_stop_timer( struct igmp_group *group);
|
|
||||||
|
|
||||||
void igmp_delaying_member( struct igmp_group *group, u8_t maxresp);
|
|
||||||
|
|
||||||
err_t igmp_ip_output_if( struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, u8_t ttl, u8_t proto, struct netif *netif);
|
|
||||||
|
|
||||||
void igmp_send( struct igmp_group *group, u8_t type);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* LWIP_IGMP */
|
|
||||||
|
|
||||||
#endif /* __LWIP_IGMP_H__ */
|
|
|
@ -1,103 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#ifndef __LWIP_INET_H__
|
|
||||||
#define __LWIP_INET_H__
|
|
||||||
|
|
||||||
#include "lwip/opt.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* For compatibility with BSD code */
|
|
||||||
struct in_addr {
|
|
||||||
u32_t s_addr;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define INADDR_NONE ((u32_t)0xffffffffUL) /* 255.255.255.255 */
|
|
||||||
#define INADDR_LOOPBACK ((u32_t)0x7f000001UL) /* 127.0.0.1 */
|
|
||||||
#define INADDR_ANY ((u32_t)0x00000000UL) /* 0.0.0.0 */
|
|
||||||
#define INADDR_BROADCAST ((u32_t)0xffffffffUL) /* 255.255.255.255 */
|
|
||||||
|
|
||||||
u32_t inet_addr(const char *cp);
|
|
||||||
int inet_aton(const char *cp, struct in_addr *addr);
|
|
||||||
char *inet_ntoa(struct in_addr addr); /* returns ptr to static buffer; not reentrant! */
|
|
||||||
|
|
||||||
#ifdef htons
|
|
||||||
#undef htons
|
|
||||||
#endif /* htons */
|
|
||||||
#ifdef htonl
|
|
||||||
#undef htonl
|
|
||||||
#endif /* htonl */
|
|
||||||
#ifdef ntohs
|
|
||||||
#undef ntohs
|
|
||||||
#endif /* ntohs */
|
|
||||||
#ifdef ntohl
|
|
||||||
#undef ntohl
|
|
||||||
#endif /* ntohl */
|
|
||||||
|
|
||||||
#ifndef LWIP_PLATFORM_BYTESWAP
|
|
||||||
#define LWIP_PLATFORM_BYTESWAP 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if BYTE_ORDER == BIG_ENDIAN
|
|
||||||
#define htons(x) (x)
|
|
||||||
#define ntohs(x) (x)
|
|
||||||
#define htonl(x) (x)
|
|
||||||
#define ntohl(x) (x)
|
|
||||||
#else /* BYTE_ORDER != BIG_ENDIAN */
|
|
||||||
#ifdef LWIP_PREFIX_BYTEORDER_FUNCS
|
|
||||||
/* workaround for naming collisions on some platforms */
|
|
||||||
#define htons lwip_htons
|
|
||||||
#define ntohs lwip_ntohs
|
|
||||||
#define htonl lwip_htonl
|
|
||||||
#define ntohl lwip_ntohl
|
|
||||||
#endif /* LWIP_PREFIX_BYTEORDER_FUNCS */
|
|
||||||
#if LWIP_PLATFORM_BYTESWAP
|
|
||||||
#define htons(x) LWIP_PLATFORM_HTONS(x)
|
|
||||||
#define ntohs(x) LWIP_PLATFORM_HTONS(x)
|
|
||||||
#define htonl(x) LWIP_PLATFORM_HTONL(x)
|
|
||||||
#define ntohl(x) LWIP_PLATFORM_HTONL(x)
|
|
||||||
#else /* LWIP_PLATFORM_BYTESWAP */
|
|
||||||
u16_t htons(u16_t x);
|
|
||||||
u16_t ntohs(u16_t x);
|
|
||||||
u32_t htonl(u32_t x);
|
|
||||||
u32_t ntohl(u32_t x);
|
|
||||||
#endif /* LWIP_PLATFORM_BYTESWAP */
|
|
||||||
|
|
||||||
#endif /* BYTE_ORDER == BIG_ENDIAN */
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* __LWIP_INET_H__ */
|
|
|
@ -1,60 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
**/
|
|
||||||
#ifndef __LWIP_INET_CHKSUM_H__
|
|
||||||
#define __LWIP_INET_CHKSUM_H__
|
|
||||||
|
|
||||||
#include "lwip/opt.h"
|
|
||||||
|
|
||||||
#include "lwip/pbuf.h"
|
|
||||||
#include "lwip/ip_addr.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
u16_t inet_chksum(void *dataptr, u16_t len);
|
|
||||||
u16_t inet_chksum_pbuf(struct pbuf *p);
|
|
||||||
u16_t inet_chksum_pseudo(struct pbuf *p,
|
|
||||||
struct ip_addr *src, struct ip_addr *dest,
|
|
||||||
u8_t proto, u16_t proto_len);
|
|
||||||
#if LWIP_UDPLITE
|
|
||||||
u16_t inet_chksum_pseudo_partial(struct pbuf *p,
|
|
||||||
struct ip_addr *src, struct ip_addr *dest,
|
|
||||||
u8_t proto, u16_t proto_len, u16_t chksum_len);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* __LWIP_INET_H__ */
|
|
||||||
|
|
|
@ -1,198 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#ifndef __LWIP_IP_H__
|
|
||||||
#define __LWIP_IP_H__
|
|
||||||
|
|
||||||
#include "lwip/opt.h"
|
|
||||||
|
|
||||||
#include "lwip/def.h"
|
|
||||||
#include "lwip/pbuf.h"
|
|
||||||
#include "lwip/ip_addr.h"
|
|
||||||
#include "lwip/err.h"
|
|
||||||
#include "lwip/netif.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** Currently, the function ip_output_if_opt() is only used with IGMP */
|
|
||||||
#define IP_OPTIONS_SEND LWIP_IGMP
|
|
||||||
|
|
||||||
#define IP_HLEN 20
|
|
||||||
|
|
||||||
#define IP_PROTO_ICMP 1
|
|
||||||
#define IP_PROTO_UDP 17
|
|
||||||
#define IP_PROTO_UDPLITE 136
|
|
||||||
#define IP_PROTO_TCP 6
|
|
||||||
|
|
||||||
/* This is passed as the destination address to ip_output_if (not
|
|
||||||
to ip_output), meaning that an IP header already is constructed
|
|
||||||
in the pbuf. This is used when TCP retransmits. */
|
|
||||||
#ifdef IP_HDRINCL
|
|
||||||
#undef IP_HDRINCL
|
|
||||||
#endif /* IP_HDRINCL */
|
|
||||||
#define IP_HDRINCL NULL
|
|
||||||
|
|
||||||
#if LWIP_NETIF_HWADDRHINT
|
|
||||||
#define IP_PCB_ADDRHINT ;u8_t addr_hint
|
|
||||||
#else
|
|
||||||
#define IP_PCB_ADDRHINT
|
|
||||||
#endif /* LWIP_NETIF_HWADDRHINT */
|
|
||||||
|
|
||||||
/* This is the common part of all PCB types. It needs to be at the
|
|
||||||
beginning of a PCB type definition. It is located here so that
|
|
||||||
changes to this common part are made in one location instead of
|
|
||||||
having to change all PCB structs. */
|
|
||||||
#define IP_PCB \
|
|
||||||
/* ip addresses in network byte order */ \
|
|
||||||
struct ip_addr local_ip; \
|
|
||||||
struct ip_addr remote_ip; \
|
|
||||||
/* Socket options */ \
|
|
||||||
u16_t so_options; \
|
|
||||||
/* Type Of Service */ \
|
|
||||||
u8_t tos; \
|
|
||||||
/* Time To Live */ \
|
|
||||||
u8_t ttl \
|
|
||||||
/* link layer address resolution hint */ \
|
|
||||||
IP_PCB_ADDRHINT
|
|
||||||
|
|
||||||
struct ip_pcb {
|
|
||||||
/* Common members of all PCB types */
|
|
||||||
IP_PCB;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Option flags per-socket. These are the same like SO_XXX.
|
|
||||||
*/
|
|
||||||
#define SOF_DEBUG (u16_t)0x0001U /* turn on debugging info recording */
|
|
||||||
#define SOF_ACCEPTCONN (u16_t)0x0002U /* socket has had listen() */
|
|
||||||
#define SOF_REUSEADDR (u16_t)0x0004U /* allow local address reuse */
|
|
||||||
#define SOF_KEEPALIVE (u16_t)0x0008U /* keep connections alive */
|
|
||||||
#define SOF_DONTROUTE (u16_t)0x0010U /* just use interface addresses */
|
|
||||||
#define SOF_BROADCAST (u16_t)0x0020U /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */
|
|
||||||
#define SOF_USELOOPBACK (u16_t)0x0040U /* bypass hardware when possible */
|
|
||||||
#define SOF_LINGER (u16_t)0x0080U /* linger on close if data present */
|
|
||||||
#define SOF_OOBINLINE (u16_t)0x0100U /* leave received OOB data in line */
|
|
||||||
#define SOF_REUSEPORT (u16_t)0x0200U /* allow local address & port reuse */
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
|
||||||
# include "arch/bpstruct.h"
|
|
||||||
#endif
|
|
||||||
PACK_STRUCT_BEGIN
|
|
||||||
struct ip_hdr {
|
|
||||||
/* version / header length / type of service */
|
|
||||||
PACK_STRUCT_FIELD(u16_t _v_hl_tos);
|
|
||||||
/* total length */
|
|
||||||
PACK_STRUCT_FIELD(u16_t _len);
|
|
||||||
/* identification */
|
|
||||||
PACK_STRUCT_FIELD(u16_t _id);
|
|
||||||
/* fragment offset field */
|
|
||||||
PACK_STRUCT_FIELD(u16_t _offset);
|
|
||||||
#define IP_RF 0x8000 /* reserved fragment flag */
|
|
||||||
#define IP_DF 0x4000 /* dont fragment flag */
|
|
||||||
#define IP_MF 0x2000 /* more fragments flag */
|
|
||||||
#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
|
|
||||||
/* time to live / protocol*/
|
|
||||||
PACK_STRUCT_FIELD(u16_t _ttl_proto);
|
|
||||||
/* checksum */
|
|
||||||
PACK_STRUCT_FIELD(u16_t _chksum);
|
|
||||||
/* source and destination IP addresses */
|
|
||||||
PACK_STRUCT_FIELD(struct ip_addr src);
|
|
||||||
PACK_STRUCT_FIELD(struct ip_addr dest);
|
|
||||||
} PACK_STRUCT_STRUCT;
|
|
||||||
PACK_STRUCT_END
|
|
||||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
|
||||||
# include "arch/epstruct.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define IPH_V(hdr) (ntohs((hdr)->_v_hl_tos) >> 12)
|
|
||||||
#define IPH_HL(hdr) ((ntohs((hdr)->_v_hl_tos) >> 8) & 0x0f)
|
|
||||||
#define IPH_TOS(hdr) (ntohs((hdr)->_v_hl_tos) & 0xff)
|
|
||||||
#define IPH_LEN(hdr) ((hdr)->_len)
|
|
||||||
#define IPH_ID(hdr) ((hdr)->_id)
|
|
||||||
#define IPH_OFFSET(hdr) ((hdr)->_offset)
|
|
||||||
#define IPH_TTL(hdr) (ntohs((hdr)->_ttl_proto) >> 8)
|
|
||||||
#define IPH_PROTO(hdr) (ntohs((hdr)->_ttl_proto) & 0xff)
|
|
||||||
#define IPH_CHKSUM(hdr) ((hdr)->_chksum)
|
|
||||||
|
|
||||||
#define IPH_VHLTOS_SET(hdr, v, hl, tos) (hdr)->_v_hl_tos = (htons(((v) << 12) | ((hl) << 8) | (tos)))
|
|
||||||
#define IPH_LEN_SET(hdr, len) (hdr)->_len = (len)
|
|
||||||
#define IPH_ID_SET(hdr, id) (hdr)->_id = (id)
|
|
||||||
#define IPH_OFFSET_SET(hdr, off) (hdr)->_offset = (off)
|
|
||||||
#define IPH_TTL_SET(hdr, ttl) (hdr)->_ttl_proto = (htons(IPH_PROTO(hdr) | ((u16_t)(ttl) << 8)))
|
|
||||||
#define IPH_PROTO_SET(hdr, proto) (hdr)->_ttl_proto = (htons((proto) | (IPH_TTL(hdr) << 8)))
|
|
||||||
#define IPH_CHKSUM_SET(hdr, chksum) (hdr)->_chksum = (chksum)
|
|
||||||
|
|
||||||
/** The interface that provided the packet for the current callback invocation. */
|
|
||||||
extern struct netif *current_netif;
|
|
||||||
/** Header of the input packet currently being processed. */
|
|
||||||
extern const struct ip_hdr *current_header;
|
|
||||||
|
|
||||||
#define ip_init() /* Compatibility define, not init needed. */
|
|
||||||
struct netif *ip_route(struct ip_addr *dest);
|
|
||||||
err_t ip_input(struct pbuf *p, struct netif *inp);
|
|
||||||
err_t ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
|
|
||||||
u8_t ttl, u8_t tos, u8_t proto);
|
|
||||||
err_t ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
|
|
||||||
u8_t ttl, u8_t tos, u8_t proto,
|
|
||||||
struct netif *netif);
|
|
||||||
#if LWIP_NETIF_HWADDRHINT
|
|
||||||
err_t ip_output_hinted(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
|
|
||||||
u8_t ttl, u8_t tos, u8_t proto, u8_t *addr_hint);
|
|
||||||
#endif /* LWIP_NETIF_HWADDRHINT */
|
|
||||||
#if IP_OPTIONS_SEND
|
|
||||||
err_t ip_output_if_opt(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
|
|
||||||
u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options,
|
|
||||||
u16_t optlen);
|
|
||||||
#endif /* IP_OPTIONS_SEND */
|
|
||||||
/** Get the interface that received the current packet.
|
|
||||||
* This function must only be called from a receive callback (udp_recv,
|
|
||||||
* raw_recv, tcp_accept). It will return NULL otherwise. */
|
|
||||||
#define ip_current_netif() (current_netif)
|
|
||||||
/** Get the IP header of the current packet.
|
|
||||||
* This function must only be called from a receive callback (udp_recv,
|
|
||||||
* raw_recv, tcp_accept). It will return NULL otherwise. */
|
|
||||||
#define ip_current_header() (current_header)
|
|
||||||
#if IP_DEBUG
|
|
||||||
void ip_debug_print(struct pbuf *p);
|
|
||||||
#else
|
|
||||||
#define ip_debug_print(p)
|
|
||||||
#endif /* IP_DEBUG */
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* __LWIP_IP_H__ */
|
|
||||||
|
|
||||||
|
|
|
@ -1,173 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
**/
|
|
||||||
#ifndef __LWIP_IP_ADDR_H__
|
|
||||||
#define __LWIP_IP_ADDR_H__
|
|
||||||
|
|
||||||
#include "lwip/opt.h"
|
|
||||||
|
|
||||||
#include "lwip/inet.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
|
||||||
# include "arch/bpstruct.h"
|
|
||||||
#endif
|
|
||||||
PACK_STRUCT_BEGIN
|
|
||||||
struct ip_addr {
|
|
||||||
PACK_STRUCT_FIELD(u32_t addr);
|
|
||||||
} PACK_STRUCT_STRUCT;
|
|
||||||
PACK_STRUCT_END
|
|
||||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
|
||||||
# include "arch/epstruct.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* struct ipaddr2 is used in the definition of the ARP packet format in
|
|
||||||
* order to support compilers that don't have structure packing.
|
|
||||||
*/
|
|
||||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
|
||||||
# include "arch/bpstruct.h"
|
|
||||||
#endif
|
|
||||||
PACK_STRUCT_BEGIN
|
|
||||||
struct ip_addr2 {
|
|
||||||
PACK_STRUCT_FIELD(u16_t addrw[2]);
|
|
||||||
} PACK_STRUCT_STRUCT;
|
|
||||||
PACK_STRUCT_END
|
|
||||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
|
||||||
# include "arch/epstruct.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct netif;
|
|
||||||
|
|
||||||
extern const struct ip_addr ip_addr_any;
|
|
||||||
extern const struct ip_addr ip_addr_broadcast;
|
|
||||||
|
|
||||||
/** IP_ADDR_ can be used as a fixed IP address
|
|
||||||
* for the wildcard and the broadcast address
|
|
||||||
*/
|
|
||||||
#define IP_ADDR_ANY ((struct ip_addr *)&ip_addr_any)
|
|
||||||
#define IP_ADDR_BROADCAST ((struct ip_addr *)&ip_addr_broadcast)
|
|
||||||
|
|
||||||
/* Definitions of the bits in an Internet address integer.
|
|
||||||
|
|
||||||
On subnets, host and network parts are found according to
|
|
||||||
the subnet mask, not these masks. */
|
|
||||||
|
|
||||||
#define IN_CLASSA(a) ((((u32_t)(a)) & 0x80000000UL) == 0)
|
|
||||||
#define IN_CLASSA_NET 0xff000000
|
|
||||||
#define IN_CLASSA_NSHIFT 24
|
|
||||||
#define IN_CLASSA_HOST (0xffffffff & ~IN_CLASSA_NET)
|
|
||||||
#define IN_CLASSA_MAX 128
|
|
||||||
|
|
||||||
#define IN_CLASSB(a) ((((u32_t)(a)) & 0xc0000000UL) == 0x80000000UL)
|
|
||||||
#define IN_CLASSB_NET 0xffff0000
|
|
||||||
#define IN_CLASSB_NSHIFT 16
|
|
||||||
#define IN_CLASSB_HOST (0xffffffff & ~IN_CLASSB_NET)
|
|
||||||
#define IN_CLASSB_MAX 65536
|
|
||||||
|
|
||||||
#define IN_CLASSC(a) ((((u32_t)(a)) & 0xe0000000UL) == 0xc0000000UL)
|
|
||||||
#define IN_CLASSC_NET 0xffffff00
|
|
||||||
#define IN_CLASSC_NSHIFT 8
|
|
||||||
#define IN_CLASSC_HOST (0xffffffff & ~IN_CLASSC_NET)
|
|
||||||
|
|
||||||
#define IN_CLASSD(a) (((u32_t)(a) & 0xf0000000UL) == 0xe0000000UL)
|
|
||||||
#define IN_CLASSD_NET 0xf0000000 /* These ones aren't really */
|
|
||||||
#define IN_CLASSD_NSHIFT 28 /* net and host fields, but */
|
|
||||||
#define IN_CLASSD_HOST 0x0fffffff /* routing needn't know. */
|
|
||||||
#define IN_MULTICAST(a) IN_CLASSD(a)
|
|
||||||
|
|
||||||
#define IN_EXPERIMENTAL(a) (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL)
|
|
||||||
#define IN_BADCLASS(a) (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL)
|
|
||||||
|
|
||||||
#define IN_LOOPBACKNET 127 /* official! */
|
|
||||||
|
|
||||||
#define IP4_ADDR(ipaddr, a,b,c,d) \
|
|
||||||
(ipaddr)->addr = htonl(((u32_t)((a) & 0xff) << 24) | \
|
|
||||||
((u32_t)((b) & 0xff) << 16) | \
|
|
||||||
((u32_t)((c) & 0xff) << 8) | \
|
|
||||||
(u32_t)((d) & 0xff))
|
|
||||||
|
|
||||||
#define ip_addr_set(dest, src) (dest)->addr = \
|
|
||||||
((src) == NULL? 0:\
|
|
||||||
(src)->addr)
|
|
||||||
/**
|
|
||||||
* Determine if two address are on the same network.
|
|
||||||
*
|
|
||||||
* @arg addr1 IP address 1
|
|
||||||
* @arg addr2 IP address 2
|
|
||||||
* @arg mask network identifier mask
|
|
||||||
* @return !0 if the network identifiers of both address match
|
|
||||||
*/
|
|
||||||
#define ip_addr_netcmp(addr1, addr2, mask) (((addr1)->addr & \
|
|
||||||
(mask)->addr) == \
|
|
||||||
((addr2)->addr & \
|
|
||||||
(mask)->addr))
|
|
||||||
#define ip_addr_cmp(addr1, addr2) ((addr1)->addr == (addr2)->addr)
|
|
||||||
|
|
||||||
#define ip_addr_isany(addr1) ((addr1) == NULL || (addr1)->addr == 0)
|
|
||||||
|
|
||||||
u8_t ip_addr_isbroadcast(struct ip_addr *, struct netif *);
|
|
||||||
|
|
||||||
#define ip_addr_ismulticast(addr1) (((addr1)->addr & ntohl(0xf0000000UL)) == ntohl(0xe0000000UL))
|
|
||||||
|
|
||||||
#define ip_addr_islinklocal(addr1) (((addr1)->addr & ntohl(0xffff0000UL)) == ntohl(0xa9fe0000UL))
|
|
||||||
|
|
||||||
#define ip_addr_debug_print(debug, ipaddr) \
|
|
||||||
LWIP_DEBUGF(debug, ("%"U16_F".%"U16_F".%"U16_F".%"U16_F, \
|
|
||||||
ipaddr != NULL ? \
|
|
||||||
(u16_t)(ntohl((ipaddr)->addr) >> 24) & 0xff : 0, \
|
|
||||||
ipaddr != NULL ? \
|
|
||||||
(u16_t)(ntohl((ipaddr)->addr) >> 16) & 0xff : 0, \
|
|
||||||
ipaddr != NULL ? \
|
|
||||||
(u16_t)(ntohl((ipaddr)->addr) >> 8) & 0xff : 0, \
|
|
||||||
ipaddr != NULL ? \
|
|
||||||
(u16_t)ntohl((ipaddr)->addr) & 0xff : 0))
|
|
||||||
|
|
||||||
/* These are cast to u16_t, with the intent that they are often arguments
|
|
||||||
* to printf using the U16_F format from cc.h. */
|
|
||||||
#define ip4_addr1(ipaddr) ((u16_t)(ntohl((ipaddr)->addr) >> 24) & 0xff)
|
|
||||||
#define ip4_addr2(ipaddr) ((u16_t)(ntohl((ipaddr)->addr) >> 16) & 0xff)
|
|
||||||
#define ip4_addr3(ipaddr) ((u16_t)(ntohl((ipaddr)->addr) >> 8) & 0xff)
|
|
||||||
#define ip4_addr4(ipaddr) ((u16_t)(ntohl((ipaddr)->addr)) & 0xff)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Same as inet_ntoa() but takes a struct ip_addr*
|
|
||||||
*/
|
|
||||||
#define ip_ntoa(addr) ((addr != NULL) ? inet_ntoa(*((struct in_addr*)(addr))) : "NULL")
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* __LWIP_IP_ADDR_H__ */
|
|
|
@ -1,76 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Jani Monoses <jani@iv.ro>
|
|
||||||
*
|
|
||||||
**/
|
|
||||||
|
|
||||||
#ifndef __LWIP_IP_FRAG_H__
|
|
||||||
#define __LWIP_IP_FRAG_H__
|
|
||||||
|
|
||||||
#include "lwip/opt.h"
|
|
||||||
#include "lwip/err.h"
|
|
||||||
#include "lwip/pbuf.h"
|
|
||||||
#include "lwip/netif.h"
|
|
||||||
#include "lwip/ip_addr.h"
|
|
||||||
#include "lwip/ip.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if IP_REASSEMBLY
|
|
||||||
/* The IP reassembly timer interval in milliseconds. */
|
|
||||||
#define IP_TMR_INTERVAL 1000
|
|
||||||
|
|
||||||
/* IP reassembly helper struct.
|
|
||||||
* This is exported because memp needs to know the size.
|
|
||||||
*/
|
|
||||||
struct ip_reassdata {
|
|
||||||
struct ip_reassdata *next;
|
|
||||||
struct pbuf *p;
|
|
||||||
struct ip_hdr iphdr;
|
|
||||||
u16_t datagram_len;
|
|
||||||
u8_t flags;
|
|
||||||
u8_t timer;
|
|
||||||
};
|
|
||||||
|
|
||||||
void ip_reass_init(void);
|
|
||||||
void ip_reass_tmr(void);
|
|
||||||
struct pbuf * ip_reass(struct pbuf *p);
|
|
||||||
#endif /* IP_REASSEMBLY */
|
|
||||||
|
|
||||||
#if IP_FRAG
|
|
||||||
err_t ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest);
|
|
||||||
#endif /* IP_FRAG */
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* __LWIP_IP_FRAG_H__ */
|
|
|
@ -1,100 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#ifndef __LWIP_ICMP_H__
|
|
||||||
#define __LWIP_ICMP_H__
|
|
||||||
|
|
||||||
#include "lwip/opt.h"
|
|
||||||
|
|
||||||
#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */
|
|
||||||
|
|
||||||
#include "lwip/pbuf.h"
|
|
||||||
#include "lwip/netif.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define ICMP6_DUR 1
|
|
||||||
#define ICMP6_TE 3
|
|
||||||
#define ICMP6_ECHO 128 /* echo */
|
|
||||||
#define ICMP6_ER 129 /* echo reply */
|
|
||||||
|
|
||||||
|
|
||||||
enum icmp_dur_type {
|
|
||||||
ICMP_DUR_NET = 0, /* net unreachable */
|
|
||||||
ICMP_DUR_HOST = 1, /* host unreachable */
|
|
||||||
ICMP_DUR_PROTO = 2, /* protocol unreachable */
|
|
||||||
ICMP_DUR_PORT = 3, /* port unreachable */
|
|
||||||
ICMP_DUR_FRAG = 4, /* fragmentation needed and DF set */
|
|
||||||
ICMP_DUR_SR = 5 /* source route failed */
|
|
||||||
};
|
|
||||||
|
|
||||||
enum icmp_te_type {
|
|
||||||
ICMP_TE_TTL = 0, /* time to live exceeded in transit */
|
|
||||||
ICMP_TE_FRAG = 1 /* fragment reassembly time exceeded */
|
|
||||||
};
|
|
||||||
|
|
||||||
void icmp_input(struct pbuf *p, struct netif *inp);
|
|
||||||
|
|
||||||
void icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t);
|
|
||||||
void icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t);
|
|
||||||
|
|
||||||
struct icmp_echo_hdr {
|
|
||||||
u8_t type;
|
|
||||||
u8_t icode;
|
|
||||||
u16_t chksum;
|
|
||||||
u16_t id;
|
|
||||||
u16_t seqno;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct icmp_dur_hdr {
|
|
||||||
u8_t type;
|
|
||||||
u8_t icode;
|
|
||||||
u16_t chksum;
|
|
||||||
u32_t unused;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct icmp_te_hdr {
|
|
||||||
u8_t type;
|
|
||||||
u8_t icode;
|
|
||||||
u16_t chksum;
|
|
||||||
u32_t unused;
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* LWIP_ICMP */
|
|
||||||
|
|
||||||
#endif /* __LWIP_ICMP_H__ */
|
|
||||||
|
|
|
@ -1,68 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#ifndef __LWIP_INET_H__
|
|
||||||
#define __LWIP_INET_H__
|
|
||||||
|
|
||||||
#include "lwip/opt.h"
|
|
||||||
#include "lwip/pbuf.h"
|
|
||||||
#include "lwip/ip_addr.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
u16_t inet_chksum(void *data, u16_t len);
|
|
||||||
u16_t inet_chksum_pbuf(struct pbuf *p);
|
|
||||||
u16_t inet_chksum_pseudo(struct pbuf *p,
|
|
||||||
struct ip_addr *src, struct ip_addr *dest,
|
|
||||||
u8_t proto, u32_t proto_len);
|
|
||||||
|
|
||||||
u32_t inet_addr(const char *cp);
|
|
||||||
s8_t inet_aton(const char *cp, struct in_addr *addr);
|
|
||||||
|
|
||||||
#ifndef _MACHINE_ENDIAN_H_
|
|
||||||
#ifndef _NETINET_IN_H
|
|
||||||
#ifndef _LINUX_BYTEORDER_GENERIC_H
|
|
||||||
u16_t htons(u16_t n);
|
|
||||||
u16_t ntohs(u16_t n);
|
|
||||||
u32_t htonl(u32_t n);
|
|
||||||
u32_t ntohl(u32_t n);
|
|
||||||
#endif /* _LINUX_BYTEORDER_GENERIC_H */
|
|
||||||
#endif /* _NETINET_IN_H */
|
|
||||||
#endif /* _MACHINE_ENDIAN_H_ */
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* __LWIP_INET_H__ */
|
|
||||||
|
|
|
@ -1,130 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#ifndef __LWIP_IP_H__
|
|
||||||
#define __LWIP_IP_H__
|
|
||||||
|
|
||||||
#include "lwip/opt.h"
|
|
||||||
#include "lwip/def.h"
|
|
||||||
#include "lwip/pbuf.h"
|
|
||||||
#include "lwip/ip_addr.h"
|
|
||||||
|
|
||||||
#include "lwip/err.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define IP_HLEN 40
|
|
||||||
|
|
||||||
#define IP_PROTO_ICMP 58
|
|
||||||
#define IP_PROTO_UDP 17
|
|
||||||
#define IP_PROTO_UDPLITE 136
|
|
||||||
#define IP_PROTO_TCP 6
|
|
||||||
|
|
||||||
/* This is passed as the destination address to ip_output_if (not
|
|
||||||
to ip_output), meaning that an IP header already is constructed
|
|
||||||
in the pbuf. This is used when TCP retransmits. */
|
|
||||||
#ifdef IP_HDRINCL
|
|
||||||
#undef IP_HDRINCL
|
|
||||||
#endif /* IP_HDRINCL */
|
|
||||||
#define IP_HDRINCL NULL
|
|
||||||
|
|
||||||
#if LWIP_NETIF_HWADDRHINT
|
|
||||||
#define IP_PCB_ADDRHINT ;u8_t addr_hint
|
|
||||||
#else
|
|
||||||
#define IP_PCB_ADDRHINT
|
|
||||||
#endif /* LWIP_NETIF_HWADDRHINT */
|
|
||||||
|
|
||||||
/* This is the common part of all PCB types. It needs to be at the
|
|
||||||
beginning of a PCB type definition. It is located here so that
|
|
||||||
changes to this common part are made in one location instead of
|
|
||||||
having to change all PCB structs. */
|
|
||||||
#define IP_PCB struct ip_addr local_ip; \
|
|
||||||
struct ip_addr remote_ip; \
|
|
||||||
/* Socket options */ \
|
|
||||||
u16_t so_options; \
|
|
||||||
/* Type Of Service */ \
|
|
||||||
u8_t tos; \
|
|
||||||
/* Time To Live */ \
|
|
||||||
u8_t ttl; \
|
|
||||||
/* link layer address resolution hint */ \
|
|
||||||
IP_PCB_ADDRHINT
|
|
||||||
|
|
||||||
|
|
||||||
/* The IPv6 header. */
|
|
||||||
struct ip_hdr {
|
|
||||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
|
||||||
u8_t tclass1:4, v:4;
|
|
||||||
u8_t flow1:4, tclass2:4;
|
|
||||||
#else
|
|
||||||
u8_t v:4, tclass1:4;
|
|
||||||
u8_t tclass2:8, flow1:4;
|
|
||||||
#endif
|
|
||||||
u16_t flow2;
|
|
||||||
u16_t len; /* payload length */
|
|
||||||
u8_t nexthdr; /* next header */
|
|
||||||
u8_t hoplim; /* hop limit (TTL) */
|
|
||||||
struct ip_addr src, dest; /* source and destination IP addresses */
|
|
||||||
};
|
|
||||||
|
|
||||||
#define IPH_PROTO(hdr) (iphdr->nexthdr)
|
|
||||||
|
|
||||||
void ip_init(void);
|
|
||||||
|
|
||||||
#include "lwip/netif.h"
|
|
||||||
|
|
||||||
struct netif *ip_route(struct ip_addr *dest);
|
|
||||||
|
|
||||||
void ip_input(struct pbuf *p, struct netif *inp);
|
|
||||||
|
|
||||||
/* source and destination addresses in network byte order, please */
|
|
||||||
err_t ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
|
|
||||||
u8_t ttl, u8_t proto);
|
|
||||||
|
|
||||||
err_t ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
|
|
||||||
u8_t ttl, u8_t proto,
|
|
||||||
struct netif *netif);
|
|
||||||
|
|
||||||
#define ip_current_netif() NULL
|
|
||||||
#define ip_current_header() NULL
|
|
||||||
|
|
||||||
#if IP_DEBUG
|
|
||||||
void ip_debug_print(struct pbuf *p);
|
|
||||||
#endif /* IP_DEBUG */
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* __LWIP_IP_H__ */
|
|
||||||
|
|
||||||
|
|
|
@ -1,97 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#ifndef __LWIP_IP_ADDR_H__
|
|
||||||
#define __LWIP_IP_ADDR_H__
|
|
||||||
|
|
||||||
#include "lwip/opt.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define IP_ADDR_ANY 0
|
|
||||||
|
|
||||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
|
||||||
# include "arch/bpstruct.h"
|
|
||||||
#endif
|
|
||||||
PACK_STRUCT_BEGIN
|
|
||||||
struct ip_addr {
|
|
||||||
PACK_STRUCT_FIELD(u32_t addr[4]);
|
|
||||||
} PACK_STRUCT_STRUCT;
|
|
||||||
PACK_STRUCT_END
|
|
||||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
|
||||||
# include "arch/epstruct.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* struct ipaddr2 is used in the definition of the ARP packet format in
|
|
||||||
* order to support compilers that don't have structure packing.
|
|
||||||
*/
|
|
||||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
|
||||||
# include "arch/bpstruct.h"
|
|
||||||
#endif
|
|
||||||
PACK_STRUCT_BEGIN
|
|
||||||
struct ip_addr2 {
|
|
||||||
PACK_STRUCT_FIELD(u16_t addrw[2]);
|
|
||||||
} PACK_STRUCT_STRUCT;
|
|
||||||
PACK_STRUCT_END
|
|
||||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
|
||||||
# include "arch/epstruct.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define IP6_ADDR(ipaddr, a,b,c,d,e,f,g,h) do { (ipaddr)->addr[0] = htonl((u32_t)((a & 0xffff) << 16) | (b & 0xffff)); \
|
|
||||||
(ipaddr)->addr[1] = htonl(((c & 0xffff) << 16) | (d & 0xffff)); \
|
|
||||||
(ipaddr)->addr[2] = htonl(((e & 0xffff) << 16) | (f & 0xffff)); \
|
|
||||||
(ipaddr)->addr[3] = htonl(((g & 0xffff) << 16) | (h & 0xffff)); } while(0)
|
|
||||||
|
|
||||||
u8_t ip_addr_netcmp(struct ip_addr *addr1, struct ip_addr *addr2,
|
|
||||||
struct ip_addr *mask);
|
|
||||||
u8_t ip_addr_cmp(struct ip_addr *addr1, struct ip_addr *addr2);
|
|
||||||
void ip_addr_set(struct ip_addr *dest, struct ip_addr *src);
|
|
||||||
u8_t ip_addr_isany(struct ip_addr *addr);
|
|
||||||
|
|
||||||
#define ip_addr_debug_print(debug, ipaddr) \
|
|
||||||
LWIP_DEBUGF(debug, ("%"X32_F":%"X32_F":%"X32_F":%"X32_F":%"X32_F":%"X32_F":%"X32_F":%"X32_F"\n", \
|
|
||||||
(ntohl(ipaddr->addr[0]) >> 16) & 0xffff, \
|
|
||||||
ntohl(ipaddr->addr[0]) & 0xffff, \
|
|
||||||
(ntohl(ipaddr->addr[1]) >> 16) & 0xffff, \
|
|
||||||
ntohl(ipaddr->addr[1]) & 0xffff, \
|
|
||||||
(ntohl(ipaddr->addr[2]) >> 16) & 0xffff, \
|
|
||||||
ntohl(ipaddr->addr[2]) & 0xffff, \
|
|
||||||
(ntohl(ipaddr->addr[3]) >> 16) & 0xffff, \
|
|
||||||
ntohl(ipaddr->addr[3]) & 0xffff));
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* __LWIP_IP_ADDR_H__ */
|
|
|
@ -1,227 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
**/
|
|
||||||
#ifndef __LWIP_API_H__
|
|
||||||
#define __LWIP_API_H__
|
|
||||||
|
|
||||||
#include "lwip/opt.h"
|
|
||||||
|
|
||||||
#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
|
|
||||||
|
|
||||||
#include <stddef.h> /* for size_t */
|
|
||||||
|
|
||||||
#include "lwip/netbuf.h"
|
|
||||||
#include "lwip/sys.h"
|
|
||||||
#include "lwip/ip_addr.h"
|
|
||||||
#include "lwip/err.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define port_netconn_recv(conn , buf, ret) do{buf = netconn_recv(conn);}while(0);
|
|
||||||
#define port_netconn_accept(conn , newconn, ret) do{newconn = netconn_accept(conn);}while(0);
|
|
||||||
|
|
||||||
/* Throughout this file, IP addresses and port numbers are expected to be in
|
|
||||||
* the same byte order as in the corresponding pcb.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Flags for netconn_write */
|
|
||||||
#define NETCONN_NOFLAG 0x00
|
|
||||||
#define NETCONN_NOCOPY 0x00 /* Only for source code compatibility */
|
|
||||||
#define NETCONN_COPY 0x01
|
|
||||||
#define NETCONN_MORE 0x02
|
|
||||||
|
|
||||||
/* Helpers to process several netconn_types by the same code */
|
|
||||||
#define NETCONNTYPE_GROUP(t) (t&0xF0)
|
|
||||||
#define NETCONNTYPE_DATAGRAM(t) (t&0xE0)
|
|
||||||
|
|
||||||
enum netconn_type {
|
|
||||||
NETCONN_INVALID = 0,
|
|
||||||
/* NETCONN_TCP Group */
|
|
||||||
NETCONN_TCP = 0x10,
|
|
||||||
/* NETCONN_UDP Group */
|
|
||||||
NETCONN_UDP = 0x20,
|
|
||||||
NETCONN_UDPLITE = 0x21,
|
|
||||||
NETCONN_UDPNOCHKSUM= 0x22,
|
|
||||||
/* NETCONN_RAW Group */
|
|
||||||
NETCONN_RAW = 0x40
|
|
||||||
};
|
|
||||||
|
|
||||||
enum netconn_state {
|
|
||||||
NETCONN_NONE,
|
|
||||||
NETCONN_WRITE,
|
|
||||||
NETCONN_LISTEN,
|
|
||||||
NETCONN_CONNECT,
|
|
||||||
NETCONN_CLOSE
|
|
||||||
};
|
|
||||||
|
|
||||||
enum netconn_evt {
|
|
||||||
NETCONN_EVT_RCVPLUS,
|
|
||||||
NETCONN_EVT_RCVMINUS,
|
|
||||||
NETCONN_EVT_SENDPLUS,
|
|
||||||
NETCONN_EVT_SENDMINUS
|
|
||||||
};
|
|
||||||
|
|
||||||
#if LWIP_IGMP
|
|
||||||
enum netconn_igmp {
|
|
||||||
NETCONN_JOIN,
|
|
||||||
NETCONN_LEAVE
|
|
||||||
};
|
|
||||||
#endif /* LWIP_IGMP */
|
|
||||||
|
|
||||||
/* forward-declare some structs to avoid to include their headers */
|
|
||||||
struct ip_pcb;
|
|
||||||
struct tcp_pcb;
|
|
||||||
struct udp_pcb;
|
|
||||||
struct raw_pcb;
|
|
||||||
struct netconn;
|
|
||||||
|
|
||||||
/** A callback prototype to inform about events for a netconn */
|
|
||||||
typedef void (* netconn_callback)(struct netconn *, enum netconn_evt, u16_t len);
|
|
||||||
|
|
||||||
/** A netconn descriptor */
|
|
||||||
struct netconn {
|
|
||||||
/** type of the netconn (TCP, UDP or RAW) */
|
|
||||||
enum netconn_type type;
|
|
||||||
/** current state of the netconn */
|
|
||||||
enum netconn_state state;
|
|
||||||
/** the lwIP internal protocol control block */
|
|
||||||
union {
|
|
||||||
struct ip_pcb *ip;
|
|
||||||
struct tcp_pcb *tcp;
|
|
||||||
struct udp_pcb *udp;
|
|
||||||
struct raw_pcb *raw;
|
|
||||||
} pcb;
|
|
||||||
/** the last error this netconn had */
|
|
||||||
err_t err;
|
|
||||||
/** sem that is used to synchroneously execute functions in the core context */
|
|
||||||
sys_sem_t op_completed;
|
|
||||||
/** mbox where received packets are stored until they are fetched
|
|
||||||
by the netconn application thread (can grow quite big) */
|
|
||||||
sys_mbox_t recvmbox;
|
|
||||||
/** mbox where new connections are stored until processed
|
|
||||||
by the application thread */
|
|
||||||
sys_mbox_t acceptmbox;
|
|
||||||
/** only used for socket layer */
|
|
||||||
int socket;
|
|
||||||
#if LWIP_SO_RCVTIMEO
|
|
||||||
/** timeout to wait for new data to be received
|
|
||||||
(or connections to arrive for listening netconns) */
|
|
||||||
int recv_timeout;
|
|
||||||
#endif /* LWIP_SO_RCVTIMEO */
|
|
||||||
#if LWIP_SO_RCVBUF
|
|
||||||
/** maximum amount of bytes queued in recvmbox */
|
|
||||||
int recv_bufsize;
|
|
||||||
#endif /* LWIP_SO_RCVBUF */
|
|
||||||
s16_t recv_avail;
|
|
||||||
#if LWIP_TCP
|
|
||||||
/** TCP: when data passed to netconn_write doesn't fit into the send buffer,
|
|
||||||
this temporarily stores the message. */
|
|
||||||
struct api_msg_msg *write_msg;
|
|
||||||
/** TCP: when data passed to netconn_write doesn't fit into the send buffer,
|
|
||||||
this temporarily stores how much is already sent. */
|
|
||||||
size_t write_offset;
|
|
||||||
#if LWIP_TCPIP_CORE_LOCKING
|
|
||||||
/** TCP: when data passed to netconn_write doesn't fit into the send buffer,
|
|
||||||
this temporarily stores whether to wake up the original application task
|
|
||||||
if data couldn't be sent in the first try. */
|
|
||||||
u8_t write_delayed;
|
|
||||||
#endif /* LWIP_TCPIP_CORE_LOCKING */
|
|
||||||
#endif /* LWIP_TCP */
|
|
||||||
/** A callback function that is informed about events for this netconn */
|
|
||||||
netconn_callback callback;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Register an Network connection event */
|
|
||||||
#define API_EVENT(c,e,l) if (c->callback) { \
|
|
||||||
(*c->callback)(c, e, l); \
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Network connection functions: */
|
|
||||||
#define netconn_new(t) netconn_new_with_proto_and_callback(t, 0, NULL)
|
|
||||||
#define netconn_new_with_callback(t, c) netconn_new_with_proto_and_callback(t, 0, c)
|
|
||||||
struct
|
|
||||||
netconn *netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto,
|
|
||||||
netconn_callback callback);
|
|
||||||
err_t netconn_delete (struct netconn *conn);
|
|
||||||
/** Get the type of a netconn (as enum netconn_type). */
|
|
||||||
#define netconn_type(conn) (conn->type)
|
|
||||||
|
|
||||||
err_t netconn_getaddr (struct netconn *conn,
|
|
||||||
struct ip_addr *addr,
|
|
||||||
u16_t *port,
|
|
||||||
u8_t local);
|
|
||||||
#define netconn_peer(c,i,p) netconn_getaddr(c,i,p,0)
|
|
||||||
#define netconn_addr(c,i,p) netconn_getaddr(c,i,p,1)
|
|
||||||
|
|
||||||
err_t netconn_bind (struct netconn *conn,
|
|
||||||
struct ip_addr *addr,
|
|
||||||
u16_t port);
|
|
||||||
err_t netconn_connect (struct netconn *conn,
|
|
||||||
struct ip_addr *addr,
|
|
||||||
u16_t port);
|
|
||||||
err_t netconn_disconnect (struct netconn *conn);
|
|
||||||
err_t netconn_listen_with_backlog(struct netconn *conn, u8_t backlog);
|
|
||||||
#define netconn_listen(conn) netconn_listen_with_backlog(conn, TCP_DEFAULT_LISTEN_BACKLOG)
|
|
||||||
struct netconn * netconn_accept (struct netconn *conn);
|
|
||||||
struct netbuf * netconn_recv (struct netconn *conn);
|
|
||||||
err_t netconn_sendto (struct netconn *conn,
|
|
||||||
struct netbuf *buf, struct ip_addr *addr, u16_t port);
|
|
||||||
err_t netconn_send (struct netconn *conn,
|
|
||||||
struct netbuf *buf);
|
|
||||||
err_t netconn_write (struct netconn *conn,
|
|
||||||
const void *dataptr, size_t size,
|
|
||||||
u8_t apiflags);
|
|
||||||
err_t netconn_close (struct netconn *conn);
|
|
||||||
|
|
||||||
err_t netconn_abort(struct netconn *conn);
|
|
||||||
|
|
||||||
#if LWIP_IGMP
|
|
||||||
err_t netconn_join_leave_group (struct netconn *conn,
|
|
||||||
struct ip_addr *multiaddr,
|
|
||||||
struct ip_addr *interface,
|
|
||||||
enum netconn_igmp join_or_leave);
|
|
||||||
#endif /* LWIP_IGMP */
|
|
||||||
#if LWIP_DNS
|
|
||||||
err_t netconn_gethostbyname(const char *name, struct ip_addr *addr);
|
|
||||||
#endif /* LWIP_DNS */
|
|
||||||
|
|
||||||
#define netconn_err(conn) ((conn)->err)
|
|
||||||
#define netconn_recv_bufsize(conn) ((conn)->recv_bufsize)
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* LWIP_NETCONN */
|
|
||||||
|
|
||||||
#endif /* __LWIP_API_H__ */
|
|
|
@ -1,162 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
**/
|
|
||||||
#ifndef __LWIP_API_MSG_H__
|
|
||||||
#define __LWIP_API_MSG_H__
|
|
||||||
|
|
||||||
#include "lwip/opt.h"
|
|
||||||
|
|
||||||
#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
|
|
||||||
|
|
||||||
#include <stddef.h> /* for size_t */
|
|
||||||
|
|
||||||
#include "lwip/ip_addr.h"
|
|
||||||
#include "lwip/err.h"
|
|
||||||
#include "lwip/sys.h"
|
|
||||||
#include "lwip/igmp.h"
|
|
||||||
#include "lwip/api.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* IP addresses and port numbers are expected to be in
|
|
||||||
* the same byte order as in the corresponding pcb.
|
|
||||||
*/
|
|
||||||
/** This struct includes everything that is necessary to execute a function
|
|
||||||
for a netconn in another thread context (mainly used to process netconns
|
|
||||||
in the tcpip_thread context to be thread safe). */
|
|
||||||
struct api_msg_msg {
|
|
||||||
/** The netconn which to process - always needed: it includes the semaphore
|
|
||||||
which is used to block the application thread until the function finished. */
|
|
||||||
struct netconn *conn;
|
|
||||||
/** Depending on the executed function, one of these union members is used */
|
|
||||||
union {
|
|
||||||
/** used for do_send */
|
|
||||||
struct netbuf *b;
|
|
||||||
/** used for do_newconn */
|
|
||||||
struct {
|
|
||||||
u8_t proto;
|
|
||||||
} n;
|
|
||||||
/** used for do_bind and do_connect */
|
|
||||||
struct {
|
|
||||||
struct ip_addr *ipaddr;
|
|
||||||
u16_t port;
|
|
||||||
} bc;
|
|
||||||
/** used for do_getaddr */
|
|
||||||
struct {
|
|
||||||
struct ip_addr *ipaddr;
|
|
||||||
u16_t *port;
|
|
||||||
u8_t local;
|
|
||||||
} ad;
|
|
||||||
/** used for do_write */
|
|
||||||
struct {
|
|
||||||
const void *dataptr;
|
|
||||||
size_t len;
|
|
||||||
u8_t apiflags;
|
|
||||||
} w;
|
|
||||||
/** used for do_recv */
|
|
||||||
struct {
|
|
||||||
u16_t len;
|
|
||||||
} r;
|
|
||||||
#if LWIP_IGMP
|
|
||||||
/** used for do_join_leave_group */
|
|
||||||
struct {
|
|
||||||
struct ip_addr *multiaddr;
|
|
||||||
struct ip_addr *interface;
|
|
||||||
enum netconn_igmp join_or_leave;
|
|
||||||
} jl;
|
|
||||||
#endif /* LWIP_IGMP */
|
|
||||||
#if TCP_LISTEN_BACKLOG
|
|
||||||
struct {
|
|
||||||
u8_t backlog;
|
|
||||||
} lb;
|
|
||||||
#endif /* TCP_LISTEN_BACKLOG */
|
|
||||||
} msg;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** This struct contains a function to execute in another thread context and
|
|
||||||
a struct api_msg_msg that serves as an argument for this function.
|
|
||||||
This is passed to tcpip_apimsg to execute functions in tcpip_thread context. */
|
|
||||||
struct api_msg {
|
|
||||||
/** function to execute in tcpip_thread context */
|
|
||||||
void (* function)(struct api_msg_msg *msg);
|
|
||||||
/** arguments for this function */
|
|
||||||
struct api_msg_msg msg;
|
|
||||||
};
|
|
||||||
|
|
||||||
#if LWIP_DNS
|
|
||||||
/** As do_gethostbyname requires more arguments but doesn't require a netconn,
|
|
||||||
it has its own struct (to avoid struct api_msg getting bigger than necessary).
|
|
||||||
do_gethostbyname must be called using tcpip_callback instead of tcpip_apimsg
|
|
||||||
(see netconn_gethostbyname). */
|
|
||||||
struct dns_api_msg {
|
|
||||||
/** Hostname to query or dotted IP address string */
|
|
||||||
const char *name;
|
|
||||||
/** Rhe resolved address is stored here */
|
|
||||||
struct ip_addr *addr;
|
|
||||||
/** This semaphore is posted when the name is resolved, the application thread
|
|
||||||
should wait on it. */
|
|
||||||
sys_sem_t sem;
|
|
||||||
/** Errors are given back here */
|
|
||||||
err_t *err;
|
|
||||||
};
|
|
||||||
#endif /* LWIP_DNS */
|
|
||||||
|
|
||||||
void do_newconn ( struct api_msg_msg *msg);
|
|
||||||
void do_delconn ( struct api_msg_msg *msg);
|
|
||||||
void do_bind ( struct api_msg_msg *msg);
|
|
||||||
void do_connect ( struct api_msg_msg *msg);
|
|
||||||
void do_disconnect ( struct api_msg_msg *msg);
|
|
||||||
void do_listen ( struct api_msg_msg *msg);
|
|
||||||
void do_send ( struct api_msg_msg *msg);
|
|
||||||
void do_recv ( struct api_msg_msg *msg);
|
|
||||||
void do_write ( struct api_msg_msg *msg);
|
|
||||||
void do_getaddr ( struct api_msg_msg *msg);
|
|
||||||
void do_close ( struct api_msg_msg *msg);
|
|
||||||
#if LWIP_IGMP
|
|
||||||
void do_join_leave_group( struct api_msg_msg *msg);
|
|
||||||
#endif /* LWIP_IGMP */
|
|
||||||
|
|
||||||
#if LWIP_DNS
|
|
||||||
void do_gethostbyname(void *arg);
|
|
||||||
#endif /* LWIP_DNS */
|
|
||||||
|
|
||||||
struct netconn* netconn_alloc(enum netconn_type t, netconn_callback callback);
|
|
||||||
void netconn_free(struct netconn *conn);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* LWIP_NETCONN */
|
|
||||||
|
|
||||||
#endif /* __LWIP_API_MSG_H__ */
|
|
|
@ -1,233 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#ifndef __LWIP_ARCH_H__
|
|
||||||
#define __LWIP_ARCH_H__
|
|
||||||
|
|
||||||
#ifndef LITTLE_ENDIAN
|
|
||||||
#define LITTLE_ENDIAN 1234
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef BIG_ENDIAN
|
|
||||||
#define BIG_ENDIAN 4321
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "arch/cc.h"
|
|
||||||
|
|
||||||
/** Temporary: define format string for size_t if not defined in cc.h */
|
|
||||||
#ifndef SZT_F
|
|
||||||
#define SZT_F U32_F
|
|
||||||
#endif /* SZT_F */
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef PACK_STRUCT_BEGIN
|
|
||||||
#define PACK_STRUCT_BEGIN
|
|
||||||
#endif /* PACK_STRUCT_BEGIN */
|
|
||||||
|
|
||||||
#ifndef PACK_STRUCT_END
|
|
||||||
#define PACK_STRUCT_END
|
|
||||||
#endif /* PACK_STRUCT_END */
|
|
||||||
|
|
||||||
#ifndef PACK_STRUCT_FIELD
|
|
||||||
#define PACK_STRUCT_FIELD(x) x
|
|
||||||
#endif /* PACK_STRUCT_FIELD */
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef LWIP_UNUSED_ARG
|
|
||||||
#define LWIP_UNUSED_ARG(x) (void)x
|
|
||||||
#endif /* LWIP_UNUSED_ARG */
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef LWIP_PROVIDE_ERRNO
|
|
||||||
|
|
||||||
#define EPERM 1 /* Operation not permitted */
|
|
||||||
#define ENOENT 2 /* No such file or directory */
|
|
||||||
#define ESRCH 3 /* No such process */
|
|
||||||
#define EINTR 4 /* Interrupted system call */
|
|
||||||
#define EIO 5 /* I/O error */
|
|
||||||
#define ENXIO 6 /* No such device or address */
|
|
||||||
#define E2BIG 7 /* Arg list too long */
|
|
||||||
#define ENOEXEC 8 /* Exec format error */
|
|
||||||
#define EBADF 9 /* Bad file number */
|
|
||||||
#define ECHILD 10 /* No child processes */
|
|
||||||
#define EAGAIN 11 /* Try again */
|
|
||||||
#define ENOMEM 12 /* Out of memory */
|
|
||||||
#define EACCES 13 /* Permission denied */
|
|
||||||
#define EFAULT 14 /* Bad address */
|
|
||||||
#define ENOTBLK 15 /* Block device required */
|
|
||||||
#define EBUSY 16 /* Device or resource busy */
|
|
||||||
#define EEXIST 17 /* File exists */
|
|
||||||
#define EXDEV 18 /* Cross-device link */
|
|
||||||
#define ENODEV 19 /* No such device */
|
|
||||||
#define ENOTDIR 20 /* Not a directory */
|
|
||||||
#define EISDIR 21 /* Is a directory */
|
|
||||||
#define EINVAL 22 /* Invalid argument */
|
|
||||||
#define ENFILE 23 /* File table overflow */
|
|
||||||
#define EMFILE 24 /* Too many open files */
|
|
||||||
#define ENOTTY 25 /* Not a typewriter */
|
|
||||||
#define ETXTBSY 26 /* Text file busy */
|
|
||||||
#define EFBIG 27 /* File too large */
|
|
||||||
#define ENOSPC 28 /* No space left on device */
|
|
||||||
#define ESPIPE 29 /* Illegal seek */
|
|
||||||
#define EROFS 30 /* Read-only file system */
|
|
||||||
#define EMLINK 31 /* Too many links */
|
|
||||||
#define EPIPE 32 /* Broken pipe */
|
|
||||||
#define EDOM 33 /* Math argument out of domain of func */
|
|
||||||
#define ERANGE 34 /* Math result not representable */
|
|
||||||
#define EDEADLK 35 /* Resource deadlock would occur */
|
|
||||||
#define ENAMETOOLONG 36 /* File name too long */
|
|
||||||
#define ENOLCK 37 /* No record locks available */
|
|
||||||
#define ENOSYS 38 /* Function not implemented */
|
|
||||||
#define ENOTEMPTY 39 /* Directory not empty */
|
|
||||||
#define ELOOP 40 /* Too many symbolic links encountered */
|
|
||||||
#define EWOULDBLOCK EAGAIN /* Operation would block */
|
|
||||||
#define ENOMSG 42 /* No message of desired type */
|
|
||||||
#define EIDRM 43 /* Identifier removed */
|
|
||||||
#define ECHRNG 44 /* Channel number out of range */
|
|
||||||
#define EL2NSYNC 45 /* Level 2 not synchronized */
|
|
||||||
#define EL3HLT 46 /* Level 3 halted */
|
|
||||||
#define EL3RST 47 /* Level 3 reset */
|
|
||||||
#define ELNRNG 48 /* Link number out of range */
|
|
||||||
#define EUNATCH 49 /* Protocol driver not attached */
|
|
||||||
#define ENOCSI 50 /* No CSI structure available */
|
|
||||||
#define EL2HLT 51 /* Level 2 halted */
|
|
||||||
#define EBADE 52 /* Invalid exchange */
|
|
||||||
#define EBADR 53 /* Invalid request descriptor */
|
|
||||||
#define EXFULL 54 /* Exchange full */
|
|
||||||
#define ENOANO 55 /* No anode */
|
|
||||||
#define EBADRQC 56 /* Invalid request code */
|
|
||||||
#define EBADSLT 57 /* Invalid slot */
|
|
||||||
|
|
||||||
#define EDEADLOCK EDEADLK
|
|
||||||
|
|
||||||
#define EBFONT 59 /* Bad font file format */
|
|
||||||
#define ENOSTR 60 /* Device not a stream */
|
|
||||||
#define ENODATA 61 /* No data available */
|
|
||||||
#define ETIME 62 /* Timer expired */
|
|
||||||
#define ENOSR 63 /* Out of streams resources */
|
|
||||||
#define ENONET 64 /* Machine is not on the network */
|
|
||||||
#define ENOPKG 65 /* Package not installed */
|
|
||||||
#define EREMOTE 66 /* Object is remote */
|
|
||||||
#define ENOLINK 67 /* Link has been severed */
|
|
||||||
#define EADV 68 /* Advertise error */
|
|
||||||
#define ESRMNT 69 /* Srmount error */
|
|
||||||
#define ECOMM 70 /* Communication error on send */
|
|
||||||
#define EPROTO 71 /* Protocol error */
|
|
||||||
#define EMULTIHOP 72 /* Multihop attempted */
|
|
||||||
#define EDOTDOT 73 /* RFS specific error */
|
|
||||||
#define EBADMSG 74 /* Not a data message */
|
|
||||||
#define EOVERFLOW 75 /* Value too large for defined data type */
|
|
||||||
#define ENOTUNIQ 76 /* Name not unique on network */
|
|
||||||
#define EBADFD 77 /* File descriptor in bad state */
|
|
||||||
#define EREMCHG 78 /* Remote address changed */
|
|
||||||
#define ELIBACC 79 /* Can not access a needed shared library */
|
|
||||||
#define ELIBBAD 80 /* Accessing a corrupted shared library */
|
|
||||||
#define ELIBSCN 81 /* .lib section in a.out corrupted */
|
|
||||||
#define ELIBMAX 82 /* Attempting to link in too many shared libraries */
|
|
||||||
#define ELIBEXEC 83 /* Cannot exec a shared library directly */
|
|
||||||
#define EILSEQ 84 /* Illegal byte sequence */
|
|
||||||
#define ERESTART 85 /* Interrupted system call should be restarted */
|
|
||||||
#define ESTRPIPE 86 /* Streams pipe error */
|
|
||||||
#define EUSERS 87 /* Too many users */
|
|
||||||
#define ENOTSOCK 88 /* Socket operation on non-socket */
|
|
||||||
#define EDESTADDRREQ 89 /* Destination address required */
|
|
||||||
#define EMSGSIZE 90 /* Message too long */
|
|
||||||
#define EPROTOTYPE 91 /* Protocol wrong type for socket */
|
|
||||||
#define ENOPROTOOPT 92 /* Protocol not available */
|
|
||||||
#define EPROTONOSUPPORT 93 /* Protocol not supported */
|
|
||||||
#define ESOCKTNOSUPPORT 94 /* Socket type not supported */
|
|
||||||
#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */
|
|
||||||
#define EPFNOSUPPORT 96 /* Protocol family not supported */
|
|
||||||
#define EAFNOSUPPORT 97 /* Address family not supported by protocol */
|
|
||||||
#define EADDRINUSE 98 /* Address already in use */
|
|
||||||
#define EADDRNOTAVAIL 99 /* Cannot assign requested address */
|
|
||||||
#define ENETDOWN 100 /* Network is down */
|
|
||||||
#define ENETUNREACH 101 /* Network is unreachable */
|
|
||||||
#define ENETRESET 102 /* Network dropped connection because of reset */
|
|
||||||
#define ECONNABORTED 103 /* Software caused connection abort */
|
|
||||||
#define ECONNRESET 104 /* Connection reset by peer */
|
|
||||||
#define ENOBUFS 105 /* No buffer space available */
|
|
||||||
#define EISCONN 106 /* Transport endpoint is already connected */
|
|
||||||
#define ENOTCONN 107 /* Transport endpoint is not connected */
|
|
||||||
#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */
|
|
||||||
#define ETOOMANYREFS 109 /* Too many references: cannot splice */
|
|
||||||
#define ETIMEDOUT 110 /* Connection timed out */
|
|
||||||
#define ECONNREFUSED 111 /* Connection refused */
|
|
||||||
#define EHOSTDOWN 112 /* Host is down */
|
|
||||||
#define EHOSTUNREACH 113 /* No route to host */
|
|
||||||
#define EALREADY 114 /* Operation already in progress */
|
|
||||||
#define EINPROGRESS 115 /* Operation now in progress */
|
|
||||||
#define ESTALE 116 /* Stale NFS file handle */
|
|
||||||
#define EUCLEAN 117 /* Structure needs cleaning */
|
|
||||||
#define ENOTNAM 118 /* Not a XENIX named type file */
|
|
||||||
#define ENAVAIL 119 /* No XENIX semaphores available */
|
|
||||||
#define EISNAM 120 /* Is a named type file */
|
|
||||||
#define EREMOTEIO 121 /* Remote I/O error */
|
|
||||||
#define EDQUOT 122 /* Quota exceeded */
|
|
||||||
|
|
||||||
#define ENOMEDIUM 123 /* No medium found */
|
|
||||||
#define EMEDIUMTYPE 124 /* Wrong medium type */
|
|
||||||
|
|
||||||
|
|
||||||
#define ENSROK 0 /* DNS server returned answer with no data */
|
|
||||||
#define ENSRNODATA 160 /* DNS server returned answer with no data */
|
|
||||||
#define ENSRFORMERR 161 /* DNS server claims query was misformatted */
|
|
||||||
#define ENSRSERVFAIL 162 /* DNS server returned general failure */
|
|
||||||
#define ENSRNOTFOUND 163 /* Domain name not found */
|
|
||||||
#define ENSRNOTIMP 164 /* DNS server does not implement requested operation */
|
|
||||||
#define ENSRREFUSED 165 /* DNS server refused query */
|
|
||||||
#define ENSRBADQUERY 166 /* Misformatted DNS query */
|
|
||||||
#define ENSRBADNAME 167 /* Misformatted domain name */
|
|
||||||
#define ENSRBADFAMILY 168 /* Unsupported address family */
|
|
||||||
#define ENSRBADRESP 169 /* Misformatted DNS reply */
|
|
||||||
#define ENSRCONNREFUSED 170 /* Could not contact DNS servers */
|
|
||||||
#define ENSRTIMEOUT 171 /* Timeout while contacting DNS servers */
|
|
||||||
#define ENSROF 172 /* End of file */
|
|
||||||
#define ENSRFILE 173 /* Error reading file */
|
|
||||||
#define ENSRNOMEM 174 /* Out of memory */
|
|
||||||
#define ENSRDESTRUCTION 175 /* Application terminated lookup */
|
|
||||||
#define ENSRQUERYDOMAINTOOLONG 176 /* Domain name is too long */
|
|
||||||
#define ENSRCNAMELOOP 177 /* Domain name is too long */
|
|
||||||
|
|
||||||
#ifndef errno
|
|
||||||
extern int errno;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* LWIP_PROVIDE_ERRNO */
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* __LWIP_ARCH_H__ */
|
|
|
@ -1,102 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#ifndef __LWIP_DEBUG_H__
|
|
||||||
#define __LWIP_DEBUG_H__
|
|
||||||
|
|
||||||
#include "lwip/arch.h"
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
/** lower two bits indicate debug level
|
|
||||||
* - 0 all
|
|
||||||
* - 1 warning
|
|
||||||
* - 2 serious
|
|
||||||
* - 3 severe
|
|
||||||
*/
|
|
||||||
#define LWIP_DBG_LEVEL_ALL 0x00
|
|
||||||
#define LWIP_DBG_LEVEL_OFF LWIP_DBG_LEVEL_ALL /* compatibility define only */
|
|
||||||
#define LWIP_DBG_LEVEL_WARNING 0x01 /* bad checksums, dropped packets, ... */
|
|
||||||
#define LWIP_DBG_LEVEL_SERIOUS 0x02 /* memory allocation failures, ... */
|
|
||||||
#define LWIP_DBG_LEVEL_SEVERE 0x03
|
|
||||||
#define LWIP_DBG_MASK_LEVEL 0x03
|
|
||||||
|
|
||||||
/** flag for LWIP_DEBUGF to enable that debug message */
|
|
||||||
#define LWIP_DBG_ON 0x80U
|
|
||||||
/** flag for LWIP_DEBUGF to disable that debug message */
|
|
||||||
#define LWIP_DBG_OFF 0x00U
|
|
||||||
|
|
||||||
/** flag for LWIP_DEBUGF indicating a tracing message (to follow program flow) */
|
|
||||||
#define LWIP_DBG_TRACE 0x40U
|
|
||||||
/** flag for LWIP_DEBUGF indicating a state debug message (to follow module states) */
|
|
||||||
#define LWIP_DBG_STATE 0x20U
|
|
||||||
/** flag for LWIP_DEBUGF indicating newly added code, not thoroughly tested yet */
|
|
||||||
#define LWIP_DBG_FRESH 0x10U
|
|
||||||
/** flag for LWIP_DEBUGF to halt after printing this debug message */
|
|
||||||
#define LWIP_DBG_HALT 0x08U
|
|
||||||
|
|
||||||
#ifndef LWIP_NOASSERT
|
|
||||||
#define LWIP_ASSERT(message, assertion) do { if(!(assertion)) \
|
|
||||||
LWIP_PLATFORM_ASSERT(message); } while(0)
|
|
||||||
#else /* LWIP_NOASSERT */
|
|
||||||
#define LWIP_ASSERT(message, assertion)
|
|
||||||
#endif /* LWIP_NOASSERT */
|
|
||||||
|
|
||||||
/** if "expression" isn't true, then print "message" and execute "handler" expression */
|
|
||||||
#ifndef LWIP_ERROR
|
|
||||||
#define LWIP_ERROR(message, expression, handler) do { if (!(expression)) { \
|
|
||||||
LWIP_PLATFORM_ASSERT(message); handler;}} while(0)
|
|
||||||
#endif /* LWIP_ERROR */
|
|
||||||
|
|
||||||
#ifdef LWIP_DEBUG
|
|
||||||
/** print debug message only if debug message type is enabled...
|
|
||||||
* AND is of correct type AND is at least LWIP_DBG_LEVEL
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#define LWIP_PLATFORM_DIAG printf
|
|
||||||
#define LWIP_DEBUGF(debug, message) do { \
|
|
||||||
if ( \
|
|
||||||
((debug) & LWIP_DBG_ON) && \
|
|
||||||
((debug) & LWIP_DBG_TYPES_ON) && \
|
|
||||||
((s16_t)((debug) & LWIP_DBG_MASK_LEVEL) >= LWIP_DBG_MIN_LEVEL)) { \
|
|
||||||
LWIP_PLATFORM_DIAG message; \
|
|
||||||
if ((debug) & LWIP_DBG_HALT) { \
|
|
||||||
while(1); \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
} while(0)
|
|
||||||
|
|
||||||
#else /* LWIP_DEBUG */
|
|
||||||
#define LWIP_DEBUGF(debug, message)
|
|
||||||
#endif /* LWIP_DEBUG */
|
|
||||||
|
|
||||||
#endif /* __LWIP_DEBUG_H__ */
|
|
||||||
|
|
|
@ -1,47 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#ifndef __LWIP_DEF_H__
|
|
||||||
#define __LWIP_DEF_H__
|
|
||||||
|
|
||||||
/* this might define NULL already */
|
|
||||||
#include "lwip/arch.h"
|
|
||||||
|
|
||||||
#define LWIP_MAX(x , y) (((x) > (y)) ? (x) : (y))
|
|
||||||
#define LWIP_MIN(x , y) (((x) < (y)) ? (x) : (y))
|
|
||||||
|
|
||||||
#ifndef NULL
|
|
||||||
#define NULL ((void *)0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* __LWIP_DEF_H__ */
|
|
||||||
|
|
|
@ -1,247 +0,0 @@
|
||||||
/** @file
|
|
||||||
**/
|
|
||||||
|
|
||||||
#ifndef __LWIP_DHCP_H__
|
|
||||||
#define __LWIP_DHCP_H__
|
|
||||||
|
|
||||||
#include "lwip/opt.h"
|
|
||||||
|
|
||||||
#if LWIP_DHCP /* don't build if not configured for use in lwipopts.h */
|
|
||||||
|
|
||||||
#include "lwip/netif.h"
|
|
||||||
#include "lwip/udp.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** period (in seconds) of the application calling dhcp_coarse_tmr() */
|
|
||||||
#define DHCP_COARSE_TIMER_SECS 60
|
|
||||||
/** period (in milliseconds) of the application calling dhcp_coarse_tmr() */
|
|
||||||
#define DHCP_COARSE_TIMER_MSECS (DHCP_COARSE_TIMER_SECS * 1000UL)
|
|
||||||
/** period (in milliseconds) of the application calling dhcp_fine_tmr() */
|
|
||||||
#define DHCP_FINE_TIMER_MSECS 500
|
|
||||||
|
|
||||||
struct dhcp
|
|
||||||
{
|
|
||||||
/** transaction identifier of last sent request */
|
|
||||||
u32_t xid;
|
|
||||||
/** our connection to the DHCP server */
|
|
||||||
struct udp_pcb *pcb;
|
|
||||||
/** incoming msg */
|
|
||||||
struct dhcp_msg *msg_in;
|
|
||||||
/** incoming msg options */
|
|
||||||
void *options_in;
|
|
||||||
/** ingoing msg options length */
|
|
||||||
u16_t options_in_len;
|
|
||||||
/** current DHCP state machine state */
|
|
||||||
u8_t state;
|
|
||||||
/** retries of current request */
|
|
||||||
u8_t tries;
|
|
||||||
|
|
||||||
struct pbuf *p_out; /* pbuf of outcoming msg */
|
|
||||||
struct dhcp_msg *msg_out; /* outgoing msg */
|
|
||||||
u16_t options_out_len; /* outgoing msg options length */
|
|
||||||
u16_t request_timeout; /* #ticks with period DHCP_FINE_TIMER_SECS for request timeout */
|
|
||||||
u16_t t1_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for renewal time */
|
|
||||||
u16_t t2_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for rebind time */
|
|
||||||
struct ip_addr server_ip_addr; /* dhcp server address that offered this lease */
|
|
||||||
struct ip_addr offered_ip_addr;
|
|
||||||
struct ip_addr offered_sn_mask;
|
|
||||||
struct ip_addr offered_gw_addr;
|
|
||||||
struct ip_addr offered_bc_addr;
|
|
||||||
#define DHCP_MAX_DNS 2
|
|
||||||
u32_t dns_count; /* actual number of DNS servers obtained */
|
|
||||||
struct ip_addr offered_dns_addr[DHCP_MAX_DNS]; /* DNS server addresses */
|
|
||||||
|
|
||||||
u32_t offered_t0_lease; /* lease period (in seconds) */
|
|
||||||
u32_t offered_t1_renew; /* recommended renew time (usually 50% of lease period) */
|
|
||||||
u32_t offered_t2_rebind; /* recommended rebind time (usually 66% of lease period) */
|
|
||||||
#if LWIP_DHCP_AUTOIP_COOP
|
|
||||||
u8_t autoip_coop_state;
|
|
||||||
#endif
|
|
||||||
/** Patch #1308
|
|
||||||
* TODO: See dhcp.c "TODO"s
|
|
||||||
*/
|
|
||||||
#if 0
|
|
||||||
struct ip_addr offered_si_addr;
|
|
||||||
u8_t *boot_file_name;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
/* MUST be compiled with "pack structs" or equivalent! */
|
|
||||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
|
||||||
# include "arch/bpstruct.h"
|
|
||||||
#endif
|
|
||||||
PACK_STRUCT_BEGIN
|
|
||||||
/** minimum set of fields of any DHCP message */
|
|
||||||
struct dhcp_msg
|
|
||||||
{
|
|
||||||
PACK_STRUCT_FIELD(u8_t op);
|
|
||||||
PACK_STRUCT_FIELD(u8_t htype);
|
|
||||||
PACK_STRUCT_FIELD(u8_t hlen);
|
|
||||||
PACK_STRUCT_FIELD(u8_t hops);
|
|
||||||
PACK_STRUCT_FIELD(u32_t xid);
|
|
||||||
PACK_STRUCT_FIELD(u16_t secs);
|
|
||||||
PACK_STRUCT_FIELD(u16_t flags);
|
|
||||||
PACK_STRUCT_FIELD(struct ip_addr ciaddr);
|
|
||||||
PACK_STRUCT_FIELD(struct ip_addr yiaddr);
|
|
||||||
PACK_STRUCT_FIELD(struct ip_addr siaddr);
|
|
||||||
PACK_STRUCT_FIELD(struct ip_addr giaddr);
|
|
||||||
#define DHCP_CHADDR_LEN 16U
|
|
||||||
PACK_STRUCT_FIELD(u8_t chaddr[DHCP_CHADDR_LEN]);
|
|
||||||
#define DHCP_SNAME_LEN 64U
|
|
||||||
PACK_STRUCT_FIELD(u8_t sname[DHCP_SNAME_LEN]);
|
|
||||||
#define DHCP_FILE_LEN 128U
|
|
||||||
PACK_STRUCT_FIELD(u8_t file[DHCP_FILE_LEN]);
|
|
||||||
PACK_STRUCT_FIELD(u32_t cookie);
|
|
||||||
#define DHCP_MIN_OPTIONS_LEN 68U
|
|
||||||
/** make sure user does not configure this too small */
|
|
||||||
#if ((defined(DHCP_OPTIONS_LEN)) && (DHCP_OPTIONS_LEN < DHCP_MIN_OPTIONS_LEN))
|
|
||||||
# undef DHCP_OPTIONS_LEN
|
|
||||||
#endif
|
|
||||||
/** allow this to be configured in lwipopts.h, but not too small */
|
|
||||||
#if (!defined(DHCP_OPTIONS_LEN))
|
|
||||||
/** set this to be sufficient for your options in outgoing DHCP msgs */
|
|
||||||
# define DHCP_OPTIONS_LEN DHCP_MIN_OPTIONS_LEN
|
|
||||||
#endif
|
|
||||||
PACK_STRUCT_FIELD(u8_t options[DHCP_OPTIONS_LEN]);
|
|
||||||
} PACK_STRUCT_STRUCT;
|
|
||||||
PACK_STRUCT_END
|
|
||||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
|
||||||
# include "arch/epstruct.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** start DHCP configuration */
|
|
||||||
err_t dhcp_start(struct netif *netif);
|
|
||||||
/** enforce early lease renewal (not needed normally)*/
|
|
||||||
err_t dhcp_renew(struct netif *netif);
|
|
||||||
/** release the DHCP lease, usually called before dhcp_stop()*/
|
|
||||||
err_t dhcp_release(struct netif *netif);
|
|
||||||
err_t dhcp_release_unicast(struct netif *netif);
|
|
||||||
/** stop DHCP configuration */
|
|
||||||
void dhcp_stop(struct netif *netif);
|
|
||||||
/** inform server of our manual IP address */
|
|
||||||
void dhcp_inform(struct netif *netif);
|
|
||||||
/** Handle a possible change in the network configuration */
|
|
||||||
void dhcp_network_changed(struct netif *netif);
|
|
||||||
|
|
||||||
/** if enabled, check whether the offered IP address is not in use, using ARP */
|
|
||||||
#if DHCP_DOES_ARP_CHECK
|
|
||||||
void dhcp_arp_reply(struct netif *netif, struct ip_addr *addr);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** to be called every minute */
|
|
||||||
void dhcp_coarse_tmr(void);
|
|
||||||
/** to be called every half second */
|
|
||||||
void dhcp_fine_tmr(void);
|
|
||||||
|
|
||||||
/** DHCP message item offsets and length */
|
|
||||||
#define DHCP_MSG_OFS (UDP_DATA_OFS)
|
|
||||||
#define DHCP_OP_OFS (DHCP_MSG_OFS + 0)
|
|
||||||
#define DHCP_HTYPE_OFS (DHCP_MSG_OFS + 1)
|
|
||||||
#define DHCP_HLEN_OFS (DHCP_MSG_OFS + 2)
|
|
||||||
#define DHCP_HOPS_OFS (DHCP_MSG_OFS + 3)
|
|
||||||
#define DHCP_XID_OFS (DHCP_MSG_OFS + 4)
|
|
||||||
#define DHCP_SECS_OFS (DHCP_MSG_OFS + 8)
|
|
||||||
#define DHCP_FLAGS_OFS (DHCP_MSG_OFS + 10)
|
|
||||||
#define DHCP_CIADDR_OFS (DHCP_MSG_OFS + 12)
|
|
||||||
#define DHCP_YIADDR_OFS (DHCP_MSG_OFS + 16)
|
|
||||||
#define DHCP_SIADDR_OFS (DHCP_MSG_OFS + 20)
|
|
||||||
#define DHCP_GIADDR_OFS (DHCP_MSG_OFS + 24)
|
|
||||||
#define DHCP_CHADDR_OFS (DHCP_MSG_OFS + 28)
|
|
||||||
#define DHCP_SNAME_OFS (DHCP_MSG_OFS + 44)
|
|
||||||
#define DHCP_FILE_OFS (DHCP_MSG_OFS + 108)
|
|
||||||
#define DHCP_MSG_LEN 236
|
|
||||||
|
|
||||||
#define DHCP_COOKIE_OFS (DHCP_MSG_OFS + DHCP_MSG_LEN)
|
|
||||||
#define DHCP_OPTIONS_OFS (DHCP_MSG_OFS + DHCP_MSG_LEN + 4)
|
|
||||||
|
|
||||||
#define DHCP_CLIENT_PORT 68
|
|
||||||
#define DHCP_SERVER_PORT 67
|
|
||||||
|
|
||||||
/** DHCP client states */
|
|
||||||
#define DHCP_REQUESTING 1
|
|
||||||
#define DHCP_INIT 2
|
|
||||||
#define DHCP_REBOOTING 3
|
|
||||||
#define DHCP_REBINDING 4
|
|
||||||
#define DHCP_RENEWING 5
|
|
||||||
#define DHCP_SELECTING 6
|
|
||||||
#define DHCP_INFORMING 7
|
|
||||||
#define DHCP_CHECKING 8
|
|
||||||
#define DHCP_PERMANENT 9
|
|
||||||
#define DHCP_BOUND 10
|
|
||||||
#define DHCP_RELEASING 11
|
|
||||||
#define DHCP_BACKING_OFF 12
|
|
||||||
#define DHCP_OFF 13
|
|
||||||
|
|
||||||
/** AUTOIP cooperatation flags */
|
|
||||||
#define DHCP_AUTOIP_COOP_STATE_OFF 0
|
|
||||||
#define DHCP_AUTOIP_COOP_STATE_ON 1
|
|
||||||
|
|
||||||
#define DHCP_BOOTREQUEST 1
|
|
||||||
#define DHCP_BOOTREPLY 2
|
|
||||||
|
|
||||||
#define DHCP_DISCOVER 1
|
|
||||||
#define DHCP_OFFER 2
|
|
||||||
#define DHCP_REQUEST 3
|
|
||||||
#define DHCP_DECLINE 4
|
|
||||||
#define DHCP_ACK 5
|
|
||||||
#define DHCP_NAK 6
|
|
||||||
#define DHCP_RELEASE 7
|
|
||||||
#define DHCP_INFORM 8
|
|
||||||
|
|
||||||
#define DHCP_HTYPE_ETH 1
|
|
||||||
|
|
||||||
#define DHCP_HLEN_ETH 6
|
|
||||||
|
|
||||||
#define DHCP_BROADCAST_FLAG 15
|
|
||||||
#define DHCP_BROADCAST_MASK (1 << DHCP_FLAG_BROADCAST)
|
|
||||||
|
|
||||||
/** BootP options */
|
|
||||||
#define DHCP_OPTION_PAD 0
|
|
||||||
#define DHCP_OPTION_SUBNET_MASK 1 /* RFC 2132 3.3 */
|
|
||||||
#define DHCP_OPTION_ROUTER 3
|
|
||||||
#define DHCP_OPTION_DNS_SERVER 6
|
|
||||||
#define DHCP_OPTION_HOSTNAME 12
|
|
||||||
#define DHCP_OPTION_IP_TTL 23
|
|
||||||
#define DHCP_OPTION_MTU 26
|
|
||||||
#define DHCP_OPTION_BROADCAST 28
|
|
||||||
#define DHCP_OPTION_TCP_TTL 37
|
|
||||||
#define DHCP_OPTION_END 255
|
|
||||||
|
|
||||||
/** DHCP options */
|
|
||||||
#define DHCP_OPTION_REQUESTED_IP 50 /* RFC 2132 9.1, requested IP address */
|
|
||||||
#define DHCP_OPTION_LEASE_TIME 51 /* RFC 2132 9.2, time in seconds, in 4 bytes */
|
|
||||||
#define DHCP_OPTION_OVERLOAD 52 /* RFC2132 9.3, use file and/or sname field for options */
|
|
||||||
|
|
||||||
#define DHCP_OPTION_MESSAGE_TYPE 53 /* RFC 2132 9.6, important for DHCP */
|
|
||||||
#define DHCP_OPTION_MESSAGE_TYPE_LEN 1
|
|
||||||
|
|
||||||
|
|
||||||
#define DHCP_OPTION_SERVER_ID 54 /* RFC 2132 9.7, server IP address */
|
|
||||||
#define DHCP_OPTION_PARAMETER_REQUEST_LIST 55 /* RFC 2132 9.8, requested option types */
|
|
||||||
|
|
||||||
#define DHCP_OPTION_MAX_MSG_SIZE 57 /* RFC 2132 9.10, message size accepted >= 576 */
|
|
||||||
#define DHCP_OPTION_MAX_MSG_SIZE_LEN 2
|
|
||||||
|
|
||||||
#define DHCP_OPTION_T1 58 /* T1 renewal time */
|
|
||||||
#define DHCP_OPTION_T2 59 /* T2 rebinding time */
|
|
||||||
#define DHCP_OPTION_US 60
|
|
||||||
#define DHCP_OPTION_CLIENT_ID 61
|
|
||||||
#define DHCP_OPTION_TFTP_SERVERNAME 66
|
|
||||||
#define DHCP_OPTION_BOOTFILE 67
|
|
||||||
|
|
||||||
/** possible combinations of overloading the file and sname fields with options */
|
|
||||||
#define DHCP_OVERLOAD_NONE 0
|
|
||||||
#define DHCP_OVERLOAD_FILE 1
|
|
||||||
#define DHCP_OVERLOAD_SNAME 2
|
|
||||||
#define DHCP_OVERLOAD_SNAME_FILE 3
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* LWIP_DHCP */
|
|
||||||
|
|
||||||
#endif /*__LWIP_DHCP_H__*/
|
|
|
@ -1,97 +0,0 @@
|
||||||
/**
|
|
||||||
* lwip DNS resolver header file.
|
|
||||||
|
|
||||||
* Author: Jim Pettinato
|
|
||||||
* April 2007
|
|
||||||
|
|
||||||
* ported from uIP resolv.c Copyright (c) 2002-2003, Adam Dunkels.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote
|
|
||||||
* products derived from this software without specific prior
|
|
||||||
* written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
|
||||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
||||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
|
||||||
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
||||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
**/
|
|
||||||
|
|
||||||
#ifndef __LWIP_DNS_H__
|
|
||||||
#define __LWIP_DNS_H__
|
|
||||||
|
|
||||||
#include "lwip/opt.h"
|
|
||||||
|
|
||||||
#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */
|
|
||||||
|
|
||||||
/** DNS timer period */
|
|
||||||
#define DNS_TMR_INTERVAL 1000
|
|
||||||
|
|
||||||
/** DNS field TYPE used for "Resource Records" */
|
|
||||||
#define DNS_RRTYPE_A 1 /* a host address */
|
|
||||||
#define DNS_RRTYPE_NS 2 /* an authoritative name server */
|
|
||||||
#define DNS_RRTYPE_MD 3 /* a mail destination (Obsolete - use MX) */
|
|
||||||
#define DNS_RRTYPE_MF 4 /* a mail forwarder (Obsolete - use MX) */
|
|
||||||
#define DNS_RRTYPE_CNAME 5 /* the canonical name for an alias */
|
|
||||||
#define DNS_RRTYPE_SOA 6 /* marks the start of a zone of authority */
|
|
||||||
#define DNS_RRTYPE_MB 7 /* a mailbox domain name (EXPERIMENTAL) */
|
|
||||||
#define DNS_RRTYPE_MG 8 /* a mail group member (EXPERIMENTAL) */
|
|
||||||
#define DNS_RRTYPE_MR 9 /* a mail rename domain name (EXPERIMENTAL) */
|
|
||||||
#define DNS_RRTYPE_NULL 10 /* a null RR (EXPERIMENTAL) */
|
|
||||||
#define DNS_RRTYPE_WKS 11 /* a well known service description */
|
|
||||||
#define DNS_RRTYPE_PTR 12 /* a domain name pointer */
|
|
||||||
#define DNS_RRTYPE_HINFO 13 /* host information */
|
|
||||||
#define DNS_RRTYPE_MINFO 14 /* mailbox or mail list information */
|
|
||||||
#define DNS_RRTYPE_MX 15 /* mail exchange */
|
|
||||||
#define DNS_RRTYPE_TXT 16 /* text strings */
|
|
||||||
|
|
||||||
/** DNS field CLASS used for "Resource Records" */
|
|
||||||
#define DNS_RRCLASS_IN 1 /* the Internet */
|
|
||||||
#define DNS_RRCLASS_CS 2 /* the CSNET class (Obsolete - used only for examples in some obsolete RFCs) */
|
|
||||||
#define DNS_RRCLASS_CH 3 /* the CHAOS class */
|
|
||||||
#define DNS_RRCLASS_HS 4 /* Hesiod [Dyer 87] */
|
|
||||||
#define DNS_RRCLASS_FLUSH 0x800 /* Flush bit */
|
|
||||||
|
|
||||||
/** Callback which is invoked when a hostname is found.
|
|
||||||
* A function of this type must be implemented by the application using the DNS resolver.
|
|
||||||
* @param name pointer to the name that was looked up.
|
|
||||||
* @param ipaddr pointer to a struct ip_addr containing the IP address of the hostname,
|
|
||||||
* or NULL if the name could not be found (or on any other error).
|
|
||||||
* @param callback_arg a user-specified callback argument passed to dns_gethostbyname
|
|
||||||
*/
|
|
||||||
typedef void (*dns_found_callback)(const char *name, struct ip_addr *ipaddr, void *callback_arg);
|
|
||||||
|
|
||||||
|
|
||||||
void dns_init(void);
|
|
||||||
|
|
||||||
void dns_tmr(void);
|
|
||||||
|
|
||||||
void dns_setserver(u8_t numdns, struct ip_addr *dnsserver);
|
|
||||||
|
|
||||||
struct ip_addr dns_getserver(u8_t numdns);
|
|
||||||
|
|
||||||
err_t dns_gethostbyname(const char *hostname, struct ip_addr *addr,
|
|
||||||
dns_found_callback found, void *callback_arg);
|
|
||||||
|
|
||||||
#if DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC
|
|
||||||
int dns_local_removehost(const char *hostname, const struct ip_addr *addr);
|
|
||||||
err_t dns_local_addhost(const char *hostname, const struct ip_addr *addr);
|
|
||||||
#endif /* DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
|
|
||||||
|
|
||||||
#endif /* LWIP_DNS */
|
|
||||||
|
|
||||||
#endif /* __LWIP_DNS_H__ */
|
|
|
@ -1,87 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#ifndef __LWIP_ERR_H__
|
|
||||||
#define __LWIP_ERR_H__
|
|
||||||
|
|
||||||
#include "lwip/opt.h"
|
|
||||||
#include "lwip/arch.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** Define LWIP_ERR_T in cc.h if you want to use
|
|
||||||
* a different type for your platform (must be signed). */
|
|
||||||
#ifdef LWIP_ERR_T
|
|
||||||
typedef LWIP_ERR_T err_t;
|
|
||||||
#else /* LWIP_ERR_T */
|
|
||||||
typedef s8_t err_t;
|
|
||||||
#endif /* LWIP_ERR_T*/
|
|
||||||
|
|
||||||
/* Definitions for error constants. */
|
|
||||||
|
|
||||||
#define ERR_OK 0 /* No error, everything OK. */
|
|
||||||
#define ERR_MEM -1 /* Out of memory error. */
|
|
||||||
#define ERR_BUF -2 /* Buffer error. */
|
|
||||||
#define ERR_TIMEOUT -3 /* Timeout. */
|
|
||||||
#define ERR_RTE -4 /* Routing problem. */
|
|
||||||
|
|
||||||
#define ERR_IS_FATAL(e) ((e) < ERR_RTE)
|
|
||||||
|
|
||||||
#define ERR_ABRT -5 /* Connection aborted. */
|
|
||||||
#define ERR_RST -6 /* Connection reset. */
|
|
||||||
#define ERR_CLSD -7 /* Connection closed. */
|
|
||||||
#define ERR_CONN -8 /* Not connected. */
|
|
||||||
|
|
||||||
#define ERR_VAL -9 /* Illegal value. */
|
|
||||||
|
|
||||||
#define ERR_ARG -10 /* Illegal argument. */
|
|
||||||
|
|
||||||
#define ERR_USE -11 /* Address in use. */
|
|
||||||
|
|
||||||
#define ERR_IF -12 /* Low-level netif error */
|
|
||||||
#define ERR_ISCONN -13 /* Already connected. */
|
|
||||||
|
|
||||||
#define ERR_INPROGRESS -14 /* Operation in progress */
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef LWIP_DEBUG
|
|
||||||
extern const char *lwip_strerr(err_t err);
|
|
||||||
#else
|
|
||||||
#define lwip_strerr(x) ""
|
|
||||||
#endif /* LWIP_DEBUG */
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* __LWIP_ERR_H__ */
|
|
|
@ -1,72 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
**/
|
|
||||||
#ifndef __LWIP_INIT_H__
|
|
||||||
#define __LWIP_INIT_H__
|
|
||||||
|
|
||||||
#include "lwip/opt.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** X.x.x: Major version of the stack */
|
|
||||||
#define LWIP_VERSION_MAJOR 1U
|
|
||||||
/** x.X.x: Minor version of the stack */
|
|
||||||
#define LWIP_VERSION_MINOR 3U
|
|
||||||
/** x.x.X: Revision of the stack */
|
|
||||||
#define LWIP_VERSION_REVISION 2U
|
|
||||||
/** For release candidates, this is set to 1..254
|
|
||||||
* For official releases, this is set to 255 (LWIP_RC_RELEASE)
|
|
||||||
* For development versions (CVS), this is set to 0 (LWIP_RC_DEVELOPMENT) */
|
|
||||||
#define LWIP_VERSION_RC 255U
|
|
||||||
|
|
||||||
/** LWIP_VERSION_RC is set to LWIP_RC_RELEASE for official releases */
|
|
||||||
#define LWIP_RC_RELEASE 255U
|
|
||||||
/** LWIP_VERSION_RC is set to LWIP_RC_DEVELOPMENT for CVS versions */
|
|
||||||
#define LWIP_RC_DEVELOPMENT 0U
|
|
||||||
|
|
||||||
#define LWIP_VERSION_IS_RELEASE (LWIP_VERSION_RC == LWIP_RC_RELEASE)
|
|
||||||
#define LWIP_VERSION_IS_DEVELOPMENT (LWIP_VERSION_RC == LWIP_RC_DEVELOPMENT)
|
|
||||||
#define LWIP_VERSION_IS_RC ((LWIP_VERSION_RC != LWIP_RC_RELEASE) && (LWIP_VERSION_RC != LWIP_RC_DEVELOPMENT))
|
|
||||||
|
|
||||||
/** Provides the version of the stack */
|
|
||||||
#define LWIP_VERSION (LWIP_VERSION_MAJOR << 24 | LWIP_VERSION_MINOR << 16 | \
|
|
||||||
LWIP_VERSION_REVISION << 8 | LWIP_VERSION_RC)
|
|
||||||
|
|
||||||
/* Modules initialization */
|
|
||||||
void lwip_init(void);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* __LWIP_INIT_H__ */
|
|
|
@ -1,107 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#ifndef __LWIP_MEM_H__
|
|
||||||
#define __LWIP_MEM_H__
|
|
||||||
|
|
||||||
#include "lwip/opt.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if MEM_LIBC_MALLOC
|
|
||||||
|
|
||||||
#include <stddef.h> /* for size_t */
|
|
||||||
|
|
||||||
typedef size_t mem_size_t;
|
|
||||||
|
|
||||||
/* aliases for C library malloc() */
|
|
||||||
#define mem_init()
|
|
||||||
/* in case C library malloc() needs extra protection,
|
|
||||||
* allow these defines to be overridden.
|
|
||||||
*/
|
|
||||||
#ifndef mem_free
|
|
||||||
#define mem_free free
|
|
||||||
#endif
|
|
||||||
#ifndef mem_malloc
|
|
||||||
#define mem_malloc malloc
|
|
||||||
#endif
|
|
||||||
#ifndef mem_calloc
|
|
||||||
#define mem_calloc calloc
|
|
||||||
#endif
|
|
||||||
#ifndef mem_realloc
|
|
||||||
static void *mem_realloc(void *mem, mem_size_t size)
|
|
||||||
{
|
|
||||||
LWIP_UNUSED_ARG(size);
|
|
||||||
return mem;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#else /* MEM_LIBC_MALLOC */
|
|
||||||
|
|
||||||
/* MEM_SIZE would have to be aligned, but using 64000 here instead of
|
|
||||||
* 65535 leaves some room for alignment...
|
|
||||||
*/
|
|
||||||
#if MEM_SIZE > 64000l
|
|
||||||
typedef u32_t mem_size_t;
|
|
||||||
#else
|
|
||||||
typedef u16_t mem_size_t;
|
|
||||||
#endif /* MEM_SIZE > 64000 */
|
|
||||||
|
|
||||||
#if MEM_USE_POOLS
|
|
||||||
/** mem_init is not used when using pools instead of a heap */
|
|
||||||
#define mem_init()
|
|
||||||
/** mem_realloc is not used when using pools instead of a heap:
|
|
||||||
we can't free part of a pool element and don't want to copy the rest */
|
|
||||||
#define mem_realloc(mem, size) (mem)
|
|
||||||
#else /* MEM_USE_POOLS */
|
|
||||||
/* lwIP alternative malloc */
|
|
||||||
void mem_init(void);
|
|
||||||
void *mem_realloc(void *mem, mem_size_t size);
|
|
||||||
#endif /* MEM_USE_POOLS */
|
|
||||||
void *mem_malloc(mem_size_t size);
|
|
||||||
void *mem_calloc(mem_size_t count, mem_size_t size);
|
|
||||||
void mem_free(void *mem);
|
|
||||||
#endif /* MEM_LIBC_MALLOC */
|
|
||||||
|
|
||||||
#ifndef LWIP_MEM_ALIGN_SIZE
|
|
||||||
#define LWIP_MEM_ALIGN_SIZE(size) (((size) + MEM_ALIGNMENT - 1) & ~(MEM_ALIGNMENT-1))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef LWIP_MEM_ALIGN
|
|
||||||
#define LWIP_MEM_ALIGN(addr) ((void *)(((mem_ptr_t)(addr) + MEM_ALIGNMENT - 1) & ~(mem_ptr_t)(MEM_ALIGNMENT-1)))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* __LWIP_MEM_H__ */
|
|
|
@ -1,116 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __LWIP_MEMP_H__
|
|
||||||
#define __LWIP_MEMP_H__
|
|
||||||
|
|
||||||
#include "lwip/opt.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Create the list of all memory pools managed by memp. MEMP_MAX represents a NULL pool at the end */
|
|
||||||
typedef enum {
|
|
||||||
#define LWIP_MEMPOOL(name,num,size,desc) MEMP_##name,
|
|
||||||
#include "lwip/memp_std.h"
|
|
||||||
MEMP_MAX
|
|
||||||
} memp_t;
|
|
||||||
|
|
||||||
#if MEM_USE_POOLS
|
|
||||||
/* Use a helper type to get the start and end of the user "memory pools" for mem_malloc */
|
|
||||||
typedef enum {
|
|
||||||
/* Get the first (via:
|
|
||||||
MEMP_POOL_HELPER_START = ((u8_t) 1*MEMP_POOL_A + 0*MEMP_POOL_B + 0*MEMP_POOL_C + 0)*/
|
|
||||||
MEMP_POOL_HELPER_FIRST = ((u8_t)
|
|
||||||
#define LWIP_MEMPOOL(name,num,size,desc)
|
|
||||||
#define LWIP_MALLOC_MEMPOOL_START 1
|
|
||||||
#define LWIP_MALLOC_MEMPOOL(num, size) * MEMP_POOL_##size + 0
|
|
||||||
#define LWIP_MALLOC_MEMPOOL_END
|
|
||||||
#include "lwip/memp_std.h"
|
|
||||||
) ,
|
|
||||||
/* Get the last (via:
|
|
||||||
MEMP_POOL_HELPER_END = ((u8_t) 0 + MEMP_POOL_A*0 + MEMP_POOL_B*0 + MEMP_POOL_C*1) */
|
|
||||||
MEMP_POOL_HELPER_LAST = ((u8_t)
|
|
||||||
#define LWIP_MEMPOOL(name,num,size,desc)
|
|
||||||
#define LWIP_MALLOC_MEMPOOL_START
|
|
||||||
#define LWIP_MALLOC_MEMPOOL(num, size) 0 + MEMP_POOL_##size *
|
|
||||||
#define LWIP_MALLOC_MEMPOOL_END 1
|
|
||||||
#include "lwip/memp_std.h"
|
|
||||||
)
|
|
||||||
} memp_pool_helper_t;
|
|
||||||
|
|
||||||
/* The actual start and stop values are here (cast them over)
|
|
||||||
We use this helper type and these defines so we can avoid using const memp_t values */
|
|
||||||
#define MEMP_POOL_FIRST ((memp_t) MEMP_POOL_HELPER_FIRST)
|
|
||||||
#define MEMP_POOL_LAST ((memp_t) MEMP_POOL_HELPER_LAST)
|
|
||||||
#endif /* MEM_USE_POOLS */
|
|
||||||
|
|
||||||
#if MEMP_MEM_MALLOC || MEM_USE_POOLS
|
|
||||||
extern const u16_t memp_sizes[MEMP_MAX];
|
|
||||||
#endif /* MEMP_MEM_MALLOC || MEM_USE_POOLS */
|
|
||||||
|
|
||||||
#if MEMP_MEM_MALLOC
|
|
||||||
|
|
||||||
#include "mem.h"
|
|
||||||
|
|
||||||
#define memp_init()
|
|
||||||
#define memp_malloc(type) mem_malloc(memp_sizes[type])
|
|
||||||
#define memp_free(type, mem) mem_free(mem)
|
|
||||||
|
|
||||||
#else /* MEMP_MEM_MALLOC */
|
|
||||||
|
|
||||||
#if MEM_USE_POOLS
|
|
||||||
/** This structure is used to save the pool one element came from. */
|
|
||||||
struct memp_malloc_helper
|
|
||||||
{
|
|
||||||
memp_t poolnr;
|
|
||||||
};
|
|
||||||
#endif /* MEM_USE_POOLS */
|
|
||||||
|
|
||||||
void memp_init(void);
|
|
||||||
|
|
||||||
#if MEMP_OVERFLOW_CHECK
|
|
||||||
void *memp_malloc_fn(memp_t type, const char* file, const int line);
|
|
||||||
#define memp_malloc(t) memp_malloc_fn((t), __FILE__, __LINE__)
|
|
||||||
#else
|
|
||||||
void *memp_malloc(memp_t type);
|
|
||||||
#endif
|
|
||||||
void memp_free(memp_t type, void *mem);
|
|
||||||
|
|
||||||
#endif /* MEMP_MEM_MALLOC */
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* __LWIP_MEMP_H__ */
|
|
|
@ -1,102 +0,0 @@
|
||||||
/**
|
|
||||||
* SETUP: Make sure we define everything we will need.
|
|
||||||
*
|
|
||||||
* We have create three types of pools:
|
|
||||||
* 1) MEMPOOL - standard pools
|
|
||||||
* 2) MALLOC_MEMPOOL - to be used by mem_malloc in mem.c
|
|
||||||
* 3) PBUF_MEMPOOL - a mempool of pbuf's, so include space for the pbuf struct
|
|
||||||
*
|
|
||||||
* If the include'r doesn't require any special treatment of each of the types
|
|
||||||
* above, then will declare #2 & #3 to be just standard mempools.
|
|
||||||
*/
|
|
||||||
#ifndef LWIP_MALLOC_MEMPOOL
|
|
||||||
/* This treats "malloc pools" just like any other pool.
|
|
||||||
The pools are a little bigger to provide 'size' as the amount of user data. */
|
|
||||||
#define LWIP_MALLOC_MEMPOOL(num, size) LWIP_MEMPOOL(POOL_##size, num, (size + sizeof(struct memp_malloc_helper)), "MALLOC_"#size)
|
|
||||||
#define LWIP_MALLOC_MEMPOOL_START
|
|
||||||
#define LWIP_MALLOC_MEMPOOL_END
|
|
||||||
#endif /* LWIP_MALLOC_MEMPOOL */
|
|
||||||
|
|
||||||
#ifndef LWIP_PBUF_MEMPOOL
|
|
||||||
/* This treats "pbuf pools" just like any other pool.
|
|
||||||
* Allocates buffers for a pbuf struct AND a payload size */
|
|
||||||
#define LWIP_PBUF_MEMPOOL(name, num, payload, desc) LWIP_MEMPOOL(name, num, (MEMP_ALIGN_SIZE(sizeof(struct pbuf)) + MEMP_ALIGN_SIZE(payload)), desc)
|
|
||||||
#endif /* LWIP_PBUF_MEMPOOL */
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* A list of internal pools used by LWIP.
|
|
||||||
*
|
|
||||||
* LWIP_MEMPOOL(pool_name, number_elements, element_size, pool_description)
|
|
||||||
* creates a pool name MEMP_pool_name. description is used in stats.c
|
|
||||||
*/
|
|
||||||
#if LWIP_RAW
|
|
||||||
LWIP_MEMPOOL(RAW_PCB, MEMP_NUM_RAW_PCB, sizeof(struct raw_pcb), "RAW_PCB")
|
|
||||||
#endif /* LWIP_RAW */
|
|
||||||
|
|
||||||
#if LWIP_UDP
|
|
||||||
LWIP_MEMPOOL(UDP_PCB, MEMP_NUM_UDP_PCB, sizeof(struct udp_pcb), "UDP_PCB")
|
|
||||||
#endif /* LWIP_UDP */
|
|
||||||
|
|
||||||
#if LWIP_TCP
|
|
||||||
LWIP_MEMPOOL(TCP_PCB, MEMP_NUM_TCP_PCB, sizeof(struct tcp_pcb), "TCP_PCB")
|
|
||||||
LWIP_MEMPOOL(TCP_PCB_LISTEN, MEMP_NUM_TCP_PCB_LISTEN, sizeof(struct tcp_pcb_listen), "TCP_PCB_LISTEN")
|
|
||||||
LWIP_MEMPOOL(TCP_SEG, MEMP_NUM_TCP_SEG, sizeof(struct tcp_seg), "TCP_SEG")
|
|
||||||
#endif /* LWIP_TCP */
|
|
||||||
|
|
||||||
#if IP_REASSEMBLY
|
|
||||||
LWIP_MEMPOOL(REASSDATA, MEMP_NUM_REASSDATA, sizeof(struct ip_reassdata), "REASSDATA")
|
|
||||||
#endif /* IP_REASSEMBLY */
|
|
||||||
|
|
||||||
#if LWIP_NETCONN
|
|
||||||
LWIP_MEMPOOL(NETBUF, MEMP_NUM_NETBUF, sizeof(struct netbuf), "NETBUF")
|
|
||||||
LWIP_MEMPOOL(NETCONN, MEMP_NUM_NETCONN, sizeof(struct netconn), "NETCONN")
|
|
||||||
#endif /* LWIP_NETCONN */
|
|
||||||
|
|
||||||
#if NO_SYS==0
|
|
||||||
LWIP_MEMPOOL(TCPIP_MSG_API, MEMP_NUM_TCPIP_MSG_API, sizeof(struct tcpip_msg), "TCPIP_MSG_API")
|
|
||||||
LWIP_MEMPOOL(TCPIP_MSG_INPKT,MEMP_NUM_TCPIP_MSG_INPKT, sizeof(struct tcpip_msg), "TCPIP_MSG_INPKT")
|
|
||||||
#endif /* NO_SYS==0 */
|
|
||||||
|
|
||||||
#if ARP_QUEUEING
|
|
||||||
LWIP_MEMPOOL(ARP_QUEUE, MEMP_NUM_ARP_QUEUE, sizeof(struct etharp_q_entry), "ARP_QUEUE")
|
|
||||||
#endif /* ARP_QUEUEING */
|
|
||||||
|
|
||||||
#if LWIP_IGMP
|
|
||||||
LWIP_MEMPOOL(IGMP_GROUP, MEMP_NUM_IGMP_GROUP, sizeof(struct igmp_group), "IGMP_GROUP")
|
|
||||||
#endif /* LWIP_IGMP */
|
|
||||||
|
|
||||||
#if NO_SYS==0
|
|
||||||
LWIP_MEMPOOL(SYS_TIMEOUT, MEMP_NUM_SYS_TIMEOUT, sizeof(struct sys_timeo), "SYS_TIMEOUT")
|
|
||||||
#endif /* NO_SYS==0 */
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* A list of pools of pbuf's used by LWIP.
|
|
||||||
*
|
|
||||||
* LWIP_PBUF_MEMPOOL(pool_name, number_elements, pbuf_payload_size, pool_description)
|
|
||||||
* creates a pool name MEMP_pool_name. description is used in stats.c
|
|
||||||
* This allocates enough space for the pbuf struct and a payload.
|
|
||||||
* (Example: pbuf_payload_size=0 allocates only size for the struct)
|
|
||||||
*/
|
|
||||||
LWIP_PBUF_MEMPOOL(PBUF, MEMP_NUM_PBUF, 0, "PBUF_REF/ROM")
|
|
||||||
LWIP_PBUF_MEMPOOL(PBUF_POOL, PBUF_POOL_SIZE, PBUF_POOL_BUFSIZE, "PBUF_POOL")
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Allow for user-defined pools; this must be explicitly set in lwipopts.h
|
|
||||||
* since the default is to NOT look for lwippools.h
|
|
||||||
*/
|
|
||||||
#if MEMP_USE_CUSTOM_POOLS
|
|
||||||
#include "lwippools.h"
|
|
||||||
#endif /* MEMP_USE_CUSTOM_POOLS */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* REQUIRED CLEANUP: Clear up so we don't get "multiply defined" error later
|
|
||||||
* (#undef is ignored for something that is not defined)
|
|
||||||
*/
|
|
||||||
#undef LWIP_MEMPOOL
|
|
||||||
#undef LWIP_MALLOC_MEMPOOL
|
|
||||||
#undef LWIP_MALLOC_MEMPOOL_START
|
|
||||||
#undef LWIP_MALLOC_MEMPOOL_END
|
|
||||||
#undef LWIP_PBUF_MEMPOOL
|
|
|
@ -1,86 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#ifndef __LWIP_NETBUF_H__
|
|
||||||
#define __LWIP_NETBUF_H__
|
|
||||||
|
|
||||||
#include "lwip/opt.h"
|
|
||||||
#include "lwip/pbuf.h"
|
|
||||||
#include "lwip/ip_addr.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct netbuf {
|
|
||||||
struct pbuf *p, *ptr;
|
|
||||||
struct ip_addr *addr;
|
|
||||||
u16_t port;
|
|
||||||
#if LWIP_NETBUF_RECVINFO
|
|
||||||
struct ip_addr *toaddr;
|
|
||||||
u16_t toport;
|
|
||||||
#endif /* LWIP_NETBUF_RECVINFO */
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Network buffer functions: */
|
|
||||||
struct netbuf * netbuf_new (void);
|
|
||||||
void netbuf_delete (struct netbuf *buf);
|
|
||||||
void * netbuf_alloc (struct netbuf *buf, u16_t size);
|
|
||||||
void netbuf_free (struct netbuf *buf);
|
|
||||||
err_t netbuf_ref (struct netbuf *buf,
|
|
||||||
const void *dataptr, u16_t size);
|
|
||||||
void netbuf_chain (struct netbuf *head,
|
|
||||||
struct netbuf *tail);
|
|
||||||
|
|
||||||
u16_t netbuf_len (struct netbuf *buf);
|
|
||||||
err_t netbuf_data (struct netbuf *buf,
|
|
||||||
void **dataptr, u16_t *len);
|
|
||||||
s8_t netbuf_next (struct netbuf *buf);
|
|
||||||
void netbuf_first (struct netbuf *buf);
|
|
||||||
|
|
||||||
|
|
||||||
#define netbuf_copy_partial(buf, dataptr, len, offset) \
|
|
||||||
pbuf_copy_partial((buf)->p, (dataptr), (len), (offset))
|
|
||||||
#define netbuf_copy(buf,dataptr,len) netbuf_copy_partial(buf, dataptr, len, 0)
|
|
||||||
#define netbuf_take(buf, dataptr, len) pbuf_take((buf)->p, dataptr, len)
|
|
||||||
#define netbuf_len(buf) ((buf)->p->tot_len)
|
|
||||||
#define netbuf_fromaddr(buf) ((buf)->addr)
|
|
||||||
#define netbuf_fromport(buf) ((buf)->port)
|
|
||||||
#if LWIP_NETBUF_RECVINFO
|
|
||||||
#define netbuf_destaddr(buf) ((buf)->toaddr)
|
|
||||||
#define netbuf_destport(buf) ((buf)->toport)
|
|
||||||
#endif /* LWIP_NETBUF_RECVINFO */
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* __LWIP_NETBUF_H__ */
|
|
|
@ -1,111 +0,0 @@
|
||||||
/**
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Simon Goldschmidt
|
|
||||||
*
|
|
||||||
**/
|
|
||||||
|
|
||||||
#include "lwip/opt.h"
|
|
||||||
|
|
||||||
#if LWIP_DNS && LWIP_SOCKET
|
|
||||||
|
|
||||||
#include <stddef.h> /* for size_t */
|
|
||||||
|
|
||||||
#include "lwip/sockets.h"
|
|
||||||
|
|
||||||
/* some rarely used options */
|
|
||||||
#ifndef LWIP_DNS_API_DECLARE_H_ERRNO
|
|
||||||
#define LWIP_DNS_API_DECLARE_H_ERRNO 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef LWIP_DNS_API_DEFINE_ERRORS
|
|
||||||
#define LWIP_DNS_API_DEFINE_ERRORS 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef LWIP_DNS_API_DECLARE_STRUCTS
|
|
||||||
#define LWIP_DNS_API_DECLARE_STRUCTS 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if LWIP_DNS_API_DEFINE_ERRORS
|
|
||||||
/** Errors used by the DNS API functions, h_errno can be one of them */
|
|
||||||
#define EAI_NONAME 200
|
|
||||||
#define EAI_SERVICE 201
|
|
||||||
#define EAI_FAIL 202
|
|
||||||
#define EAI_MEMORY 203
|
|
||||||
|
|
||||||
#define HOST_NOT_FOUND 210
|
|
||||||
#define NO_DATA 211
|
|
||||||
#define NO_RECOVERY 212
|
|
||||||
#define TRY_AGAIN 213
|
|
||||||
#endif /* LWIP_DNS_API_DEFINE_ERRORS */
|
|
||||||
|
|
||||||
#if LWIP_DNS_API_DECLARE_STRUCTS
|
|
||||||
struct hostent {
|
|
||||||
char *h_name; /* Official name of the host. */
|
|
||||||
char **h_aliases; /* A pointer to an array of pointers to alternative host names,
|
|
||||||
terminated by a null pointer. */
|
|
||||||
int h_addrtype; /* Address type. */
|
|
||||||
int h_length; /* The length, in bytes, of the address. */
|
|
||||||
char **h_addr_list; /* A pointer to an array of pointers to network addresses (in
|
|
||||||
network byte order) for the host, terminated by a null pointer. */
|
|
||||||
#define h_addr h_addr_list[0] /* for backward compatibility */
|
|
||||||
};
|
|
||||||
|
|
||||||
struct addrinfo {
|
|
||||||
int ai_flags; /* Input flags. */
|
|
||||||
int ai_family; /* Address family of socket. */
|
|
||||||
int ai_socktype; /* Socket type. */
|
|
||||||
int ai_protocol; /* Protocol of socket. */
|
|
||||||
socklen_t ai_addrlen; /* Length of socket address. */
|
|
||||||
struct sockaddr *ai_addr; /* Socket address of socket. */
|
|
||||||
char *ai_canonname; /* Canonical name of service location. */
|
|
||||||
struct addrinfo *ai_next; /* Pointer to next in list. */
|
|
||||||
};
|
|
||||||
#endif /* LWIP_DNS_API_DECLARE_STRUCTS */
|
|
||||||
|
|
||||||
#if LWIP_DNS_API_DECLARE_H_ERRNO
|
|
||||||
/* application accessable error code set by the DNS API functions */
|
|
||||||
extern int h_errno;
|
|
||||||
#endif /* LWIP_DNS_API_DECLARE_H_ERRNO*/
|
|
||||||
|
|
||||||
struct hostent *lwip_gethostbyname(const char *name);
|
|
||||||
int lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf,
|
|
||||||
size_t buflen, struct hostent **result, int *h_errnop);
|
|
||||||
void lwip_freeaddrinfo(struct addrinfo *ai);
|
|
||||||
int lwip_getaddrinfo(const char *nodename,
|
|
||||||
const char *servname,
|
|
||||||
const struct addrinfo *hints,
|
|
||||||
struct addrinfo **res);
|
|
||||||
|
|
||||||
#if LWIP_COMPAT_SOCKETS
|
|
||||||
#define gethostbyname(name) lwip_gethostbyname(name)
|
|
||||||
#define gethostbyname_r(name, ret, buf, buflen, result, h_errnop) \
|
|
||||||
lwip_gethostbyname_r(name, ret, buf, buflen, result, h_errnop)
|
|
||||||
#define freeaddrinfo(addrinfo) lwip_freeaddrinfo(addrinfo)
|
|
||||||
#define getaddrinfo(nodname, servname, hints, res) \
|
|
||||||
lwip_getaddrinfo(nodname, servname, hints, res)
|
|
||||||
#endif /* LWIP_COMPAT_SOCKETS */
|
|
||||||
|
|
||||||
#endif /* LWIP_DNS && LWIP_SOCKET */
|
|
|
@ -1,269 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#ifndef __LWIP_NETIF_H__
|
|
||||||
#define __LWIP_NETIF_H__
|
|
||||||
|
|
||||||
#include "lwip/opt.h"
|
|
||||||
|
|
||||||
#define ENABLE_LOOPBACK (LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF)
|
|
||||||
|
|
||||||
#include "lwip/err.h"
|
|
||||||
|
|
||||||
#include "lwip/ip_addr.h"
|
|
||||||
|
|
||||||
#include "lwip/inet.h"
|
|
||||||
#include "lwip/pbuf.h"
|
|
||||||
#if LWIP_DHCP
|
|
||||||
struct dhcp;
|
|
||||||
#endif
|
|
||||||
#if LWIP_AUTOIP
|
|
||||||
struct autoip;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Throughout this file, IP addresses are expected to be in
|
|
||||||
* the same byte order as in IP_PCB. */
|
|
||||||
|
|
||||||
/** must be the maximum of all used hardware address lengths
|
|
||||||
across all types of interfaces in use */
|
|
||||||
#define NETIF_MAX_HWADDR_LEN 6U
|
|
||||||
|
|
||||||
/** TODO: define the use (where, when, whom) of netif flags */
|
|
||||||
|
|
||||||
/** whether the network interface is 'up'. this is
|
|
||||||
* a software flag used to control whether this network
|
|
||||||
* interface is enabled and processes traffic.
|
|
||||||
*/
|
|
||||||
#define NETIF_FLAG_UP 0x01U
|
|
||||||
/** if set, the netif has broadcast capability */
|
|
||||||
#define NETIF_FLAG_BROADCAST 0x02U
|
|
||||||
/** if set, the netif is one end of a point-to-point connection */
|
|
||||||
#define NETIF_FLAG_POINTTOPOINT 0x04U
|
|
||||||
/** if set, the interface is configured using DHCP */
|
|
||||||
#define NETIF_FLAG_DHCP 0x08U
|
|
||||||
/** if set, the interface has an active link
|
|
||||||
* (set by the network interface driver) */
|
|
||||||
#define NETIF_FLAG_LINK_UP 0x10U
|
|
||||||
/** if set, the netif is an device using ARP */
|
|
||||||
#define NETIF_FLAG_ETHARP 0x20U
|
|
||||||
/** if set, the netif has IGMP capability */
|
|
||||||
#define NETIF_FLAG_IGMP 0x40U
|
|
||||||
/** if set, the netif has IP layer switch capability */
|
|
||||||
/* Realtek Modified Start */
|
|
||||||
#ifdef CONFIG_DONT_CARE_TP
|
|
||||||
#define NETIF_FLAG_IPSWITCH 0x80U
|
|
||||||
#endif
|
|
||||||
/* Realtek Modified End */
|
|
||||||
|
|
||||||
/** Generic data structure used for all lwIP network interfaces.
|
|
||||||
* The following fields should be filled in by the initialization
|
|
||||||
* function for the device driver: hwaddr_len, hwaddr[], mtu, flags */
|
|
||||||
|
|
||||||
struct netif {
|
|
||||||
/** pointer to next in linked list */
|
|
||||||
struct netif *next;
|
|
||||||
|
|
||||||
/** IP address configuration in network byte order */
|
|
||||||
struct ip_addr ip_addr;
|
|
||||||
struct ip_addr netmask;
|
|
||||||
struct ip_addr gw;
|
|
||||||
|
|
||||||
/** This function is called by the network device driver
|
|
||||||
* to pass a packet up the TCP/IP stack. */
|
|
||||||
err_t (* input)(struct pbuf *p, struct netif *inp);
|
|
||||||
/** This function is called by the IP module when it wants
|
|
||||||
* to send a packet on the interface. This function typically
|
|
||||||
* first resolves the hardware address, then sends the packet. */
|
|
||||||
err_t (* output)(struct netif *netif, struct pbuf *p,
|
|
||||||
struct ip_addr *ipaddr);
|
|
||||||
/** This function is called by the ARP module when it wants
|
|
||||||
* to send a packet on the interface. This function outputs
|
|
||||||
* the pbuf as-is on the link medium. */
|
|
||||||
err_t (* linkoutput)(struct netif *netif, struct pbuf *p);
|
|
||||||
#if LWIP_NETIF_STATUS_CALLBACK
|
|
||||||
/** This function is called when the netif state is set to up or down
|
|
||||||
*/
|
|
||||||
void (* status_callback)(struct netif *netif);
|
|
||||||
#endif /* LWIP_NETIF_STATUS_CALLBACK */
|
|
||||||
#if LWIP_NETIF_LINK_CALLBACK
|
|
||||||
/** This function is called when the netif link is set to up or down
|
|
||||||
*/
|
|
||||||
void (* link_callback)(struct netif *netif);
|
|
||||||
#endif /* LWIP_NETIF_LINK_CALLBACK */
|
|
||||||
/** This field can be set by the device driver and could point
|
|
||||||
* to state information for the device. */
|
|
||||||
void *state;
|
|
||||||
#if LWIP_DHCP
|
|
||||||
/** the DHCP client state information for this netif */
|
|
||||||
struct dhcp *dhcp;
|
|
||||||
#endif /* LWIP_DHCP */
|
|
||||||
#if LWIP_AUTOIP
|
|
||||||
/** the AutoIP client state information for this netif */
|
|
||||||
struct autoip *autoip;
|
|
||||||
#endif
|
|
||||||
#if LWIP_NETIF_HOSTNAME
|
|
||||||
/* the hostname for this netif, NULL is a valid value */
|
|
||||||
char* hostname;
|
|
||||||
#endif /* LWIP_NETIF_HOSTNAME */
|
|
||||||
/** maximum transfer unit (in bytes) */
|
|
||||||
u16_t mtu;
|
|
||||||
/** number of bytes used in hwaddr */
|
|
||||||
u8_t hwaddr_len;
|
|
||||||
/** link level hardware address of this interface */
|
|
||||||
u8_t hwaddr[NETIF_MAX_HWADDR_LEN];
|
|
||||||
/** flags (see NETIF_FLAG_ above) */
|
|
||||||
u8_t flags;
|
|
||||||
/** descriptive abbreviation */
|
|
||||||
char name[2];
|
|
||||||
/** number of this interface */
|
|
||||||
u8_t num;
|
|
||||||
#if LWIP_SNMP
|
|
||||||
/** link type (from "snmp_ifType" enum from snmp.h) */
|
|
||||||
u8_t link_type;
|
|
||||||
/** (estimate) link speed */
|
|
||||||
u32_t link_speed;
|
|
||||||
/** timestamp at last change made (up/down) */
|
|
||||||
u32_t ts;
|
|
||||||
/** counters */
|
|
||||||
u32_t ifinoctets;
|
|
||||||
u32_t ifinucastpkts;
|
|
||||||
u32_t ifinnucastpkts;
|
|
||||||
u32_t ifindiscards;
|
|
||||||
u32_t ifoutoctets;
|
|
||||||
u32_t ifoutucastpkts;
|
|
||||||
u32_t ifoutnucastpkts;
|
|
||||||
u32_t ifoutdiscards;
|
|
||||||
#endif /* LWIP_SNMP */
|
|
||||||
#if LWIP_IGMP
|
|
||||||
/* This function could be called to add or delete a entry in the multicast filter table of the ethernet MAC.*/
|
|
||||||
err_t (*igmp_mac_filter)( struct netif *netif, struct ip_addr *group, u8_t action);
|
|
||||||
#endif /* LWIP_IGMP */
|
|
||||||
#if LWIP_NETIF_HWADDRHINT
|
|
||||||
u8_t *addr_hint;
|
|
||||||
#endif /* LWIP_NETIF_HWADDRHINT */
|
|
||||||
#if ENABLE_LOOPBACK
|
|
||||||
/* List of packets to be queued for ourselves. */
|
|
||||||
struct pbuf *loop_first;
|
|
||||||
struct pbuf *loop_last;
|
|
||||||
#if LWIP_LOOPBACK_MAX_PBUFS
|
|
||||||
u16_t loop_cnt_current;
|
|
||||||
#endif /* LWIP_LOOPBACK_MAX_PBUFS */
|
|
||||||
#endif /* ENABLE_LOOPBACK */
|
|
||||||
};
|
|
||||||
|
|
||||||
#if LWIP_SNMP
|
|
||||||
#define NETIF_INIT_SNMP(netif, type, speed) \
|
|
||||||
/* use "snmp_ifType" enum from snmp.h for "type", snmp_ifType_ethernet_csmacd by example */ \
|
|
||||||
netif->link_type = type; \
|
|
||||||
/* your link speed here (units: bits per second) */ \
|
|
||||||
netif->link_speed = speed; \
|
|
||||||
netif->ts = 0; \
|
|
||||||
netif->ifinoctets = 0; \
|
|
||||||
netif->ifinucastpkts = 0; \
|
|
||||||
netif->ifinnucastpkts = 0; \
|
|
||||||
netif->ifindiscards = 0; \
|
|
||||||
netif->ifoutoctets = 0; \
|
|
||||||
netif->ifoutucastpkts = 0; \
|
|
||||||
netif->ifoutnucastpkts = 0; \
|
|
||||||
netif->ifoutdiscards = 0
|
|
||||||
#else /* LWIP_SNMP */
|
|
||||||
#define NETIF_INIT_SNMP(netif, type, speed)
|
|
||||||
#endif /* LWIP_SNMP */
|
|
||||||
|
|
||||||
|
|
||||||
/** The list of network interfaces. */
|
|
||||||
extern struct netif *netif_list;
|
|
||||||
/** The default network interface. */
|
|
||||||
extern struct netif *netif_default;
|
|
||||||
|
|
||||||
#define netif_init() /* Compatibility define, not init needed. */
|
|
||||||
|
|
||||||
struct netif *netif_add(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask,
|
|
||||||
struct ip_addr *gw,
|
|
||||||
void *state,
|
|
||||||
err_t (* init)(struct netif *netif),
|
|
||||||
err_t (* input)(struct pbuf *p, struct netif *netif));
|
|
||||||
|
|
||||||
void
|
|
||||||
netif_set_addr(struct netif *netif,struct ip_addr *ipaddr, struct ip_addr *netmask,
|
|
||||||
struct ip_addr *gw);
|
|
||||||
void netif_remove(struct netif * netif);
|
|
||||||
|
|
||||||
/* Returns a network interface given its name. The name is of the form
|
|
||||||
"et0", where the first two letters are the "name" field in the
|
|
||||||
netif structure, and the digit is in the num field in the same
|
|
||||||
structure. */
|
|
||||||
struct netif *netif_find(char *name);
|
|
||||||
|
|
||||||
void netif_set_default(struct netif *netif);
|
|
||||||
|
|
||||||
void netif_set_ipaddr(struct netif *netif, struct ip_addr *ipaddr);
|
|
||||||
void netif_set_netmask(struct netif *netif, struct ip_addr *netmask);
|
|
||||||
void netif_set_gw(struct netif *netif, struct ip_addr *gw);
|
|
||||||
|
|
||||||
void netif_set_up(struct netif *netif);
|
|
||||||
void netif_set_down(struct netif *netif);
|
|
||||||
u8_t netif_is_up(struct netif *netif);
|
|
||||||
|
|
||||||
#if LWIP_NETIF_STATUS_CALLBACK
|
|
||||||
/*
|
|
||||||
* Set callback to be called when interface is brought up/down
|
|
||||||
*/
|
|
||||||
void netif_set_status_callback(struct netif *netif, void (* status_callback)(struct netif *netif));
|
|
||||||
#endif /* LWIP_NETIF_STATUS_CALLBACK */
|
|
||||||
|
|
||||||
#if LWIP_NETIF_LINK_CALLBACK
|
|
||||||
void netif_set_link_up(struct netif *netif);
|
|
||||||
void netif_set_link_down(struct netif *netif);
|
|
||||||
u8_t netif_is_link_up(struct netif *netif);
|
|
||||||
/*
|
|
||||||
* Set callback to be called when link is brought up/down
|
|
||||||
*/
|
|
||||||
void netif_set_link_callback(struct netif *netif, void (* link_callback)(struct netif *netif));
|
|
||||||
#endif /* LWIP_NETIF_LINK_CALLBACK */
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if ENABLE_LOOPBACK
|
|
||||||
err_t netif_loop_output(struct netif *netif, struct pbuf *p, struct ip_addr *dest_ip);
|
|
||||||
void netif_poll(struct netif *netif);
|
|
||||||
#if !LWIP_NETIF_LOOPBACK_MULTITHREADING
|
|
||||||
void netif_poll_all(void);
|
|
||||||
#endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */
|
|
||||||
#endif /* ENABLE_LOOPBACK */
|
|
||||||
|
|
||||||
#endif /* __LWIP_NETIF_H__ */
|
|
|
@ -1,105 +0,0 @@
|
||||||
/*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __LWIP_NETIFAPI_H__
|
|
||||||
#define __LWIP_NETIFAPI_H__
|
|
||||||
|
|
||||||
#include "lwip/opt.h"
|
|
||||||
|
|
||||||
#if LWIP_NETIF_API /* don't build if not configured for use in lwipopts.h */
|
|
||||||
|
|
||||||
#include "lwip/sys.h"
|
|
||||||
#include "lwip/netif.h"
|
|
||||||
#include "lwip/dhcp.h"
|
|
||||||
#include "lwip/autoip.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct netifapi_msg_msg {
|
|
||||||
#if !LWIP_TCPIP_CORE_LOCKING
|
|
||||||
sys_sem_t sem;
|
|
||||||
#endif /* !LWIP_TCPIP_CORE_LOCKING */
|
|
||||||
err_t err;
|
|
||||||
struct netif *netif;
|
|
||||||
union {
|
|
||||||
struct {
|
|
||||||
struct ip_addr *ipaddr;
|
|
||||||
struct ip_addr *netmask;
|
|
||||||
struct ip_addr *gw;
|
|
||||||
void *state;
|
|
||||||
err_t (* init) (struct netif *netif);
|
|
||||||
err_t (* input)(struct pbuf *p, struct netif *netif);
|
|
||||||
} add;
|
|
||||||
struct {
|
|
||||||
void (* voidfunc)(struct netif *netif);
|
|
||||||
err_t (* errtfunc)(struct netif *netif);
|
|
||||||
} common;
|
|
||||||
} msg;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct netifapi_msg {
|
|
||||||
void (* function)(struct netifapi_msg_msg *msg);
|
|
||||||
struct netifapi_msg_msg msg;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/* API for application */
|
|
||||||
err_t netifapi_netif_add ( struct netif *netif,
|
|
||||||
struct ip_addr *ipaddr,
|
|
||||||
struct ip_addr *netmask,
|
|
||||||
struct ip_addr *gw,
|
|
||||||
void *state,
|
|
||||||
err_t (* init)(struct netif *netif),
|
|
||||||
err_t (* input)(struct pbuf *p, struct netif *netif) );
|
|
||||||
|
|
||||||
err_t netifapi_netif_set_addr ( struct netif *netif,
|
|
||||||
struct ip_addr *ipaddr,
|
|
||||||
struct ip_addr *netmask,
|
|
||||||
struct ip_addr *gw );
|
|
||||||
|
|
||||||
err_t netifapi_netif_common ( struct netif *netif,
|
|
||||||
void (* voidfunc)(struct netif *netif),
|
|
||||||
err_t (* errtfunc)(struct netif *netif) );
|
|
||||||
|
|
||||||
#define netifapi_netif_remove(n) netifapi_netif_common(n, netif_remove, NULL)
|
|
||||||
#define netifapi_netif_set_up(n) netifapi_netif_common(n, netif_set_up, NULL)
|
|
||||||
#define netifapi_netif_set_down(n) netifapi_netif_common(n, netif_set_down, NULL)
|
|
||||||
#define netifapi_netif_set_default(n) netifapi_netif_common(n, netif_set_default, NULL)
|
|
||||||
#define netifapi_dhcp_start(n) netifapi_netif_common(n, NULL, dhcp_start)
|
|
||||||
#define netifapi_dhcp_stop(n) netifapi_netif_common(n, dhcp_stop, NULL)
|
|
||||||
#define netifapi_autoip_start(n) netifapi_netif_common(n, NULL, autoip_start)
|
|
||||||
#define netifapi_autoip_stop(n) netifapi_netif_common(n, NULL, autoip_stop)
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* LWIP_NETIF_API */
|
|
||||||
|
|
||||||
#endif /* __LWIP_NETIFAPI_H__ */
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,120 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __LWIP_PBUF_H__
|
|
||||||
#define __LWIP_PBUF_H__
|
|
||||||
|
|
||||||
#include "lwip/opt.h"
|
|
||||||
#include "lwip/err.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define PBUF_TRANSPORT_HLEN 20
|
|
||||||
#define PBUF_IP_HLEN 20
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
PBUF_TRANSPORT,
|
|
||||||
PBUF_IP,
|
|
||||||
PBUF_LINK,
|
|
||||||
PBUF_RAW
|
|
||||||
} pbuf_layer;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
PBUF_RAM, /* pbuf data is stored in RAM */
|
|
||||||
PBUF_ROM, /* pbuf data is stored in ROM */
|
|
||||||
PBUF_REF, /* pbuf comes from the pbuf pool */
|
|
||||||
PBUF_POOL /* pbuf payload refers to RAM */
|
|
||||||
} pbuf_type;
|
|
||||||
|
|
||||||
|
|
||||||
/** indicates this packet's data should be immediately passed to the application */
|
|
||||||
#define PBUF_FLAG_PUSH 0x01U
|
|
||||||
|
|
||||||
struct pbuf {
|
|
||||||
/** next pbuf in singly linked pbuf chain */
|
|
||||||
struct pbuf *next;
|
|
||||||
|
|
||||||
/** pointer to the actual data in the buffer */
|
|
||||||
void *payload;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* total length of this buffer and all next buffers in chain
|
|
||||||
* belonging to the same packet.
|
|
||||||
*
|
|
||||||
* For non-queue packet chains this is the invariant:
|
|
||||||
* p->tot_len == p->len + (p->next? p->next->tot_len: 0)
|
|
||||||
*/
|
|
||||||
u16_t tot_len;
|
|
||||||
|
|
||||||
/** length of this buffer */
|
|
||||||
u16_t len;
|
|
||||||
|
|
||||||
/** pbuf_type as u8_t instead of enum to save space */
|
|
||||||
u8_t /*pbuf_type*/ type;
|
|
||||||
|
|
||||||
/** misc flags */
|
|
||||||
u8_t flags;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* the reference count always equals the number of pointers
|
|
||||||
* that refer to this pbuf. This can be pointers from an application,
|
|
||||||
* the stack itself, or pbuf->next pointers from a chain.
|
|
||||||
*/
|
|
||||||
u16_t ref;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Initializes the pbuf module. This call is empty for now, but may not be in future. */
|
|
||||||
#define pbuf_init()
|
|
||||||
|
|
||||||
struct pbuf *pbuf_alloc(pbuf_layer l, u16_t size, pbuf_type type);
|
|
||||||
void pbuf_realloc(struct pbuf *p, u16_t size);
|
|
||||||
u8_t pbuf_header(struct pbuf *p, s16_t header_size);
|
|
||||||
void pbuf_ref(struct pbuf *p);
|
|
||||||
void pbuf_ref_chain(struct pbuf *p);
|
|
||||||
u8_t pbuf_free(struct pbuf *p);
|
|
||||||
u8_t pbuf_clen(struct pbuf *p);
|
|
||||||
void pbuf_cat(struct pbuf *head, struct pbuf *tail);
|
|
||||||
void pbuf_chain(struct pbuf *head, struct pbuf *tail);
|
|
||||||
struct pbuf *pbuf_dechain(struct pbuf *p);
|
|
||||||
err_t pbuf_copy(struct pbuf *p_to, struct pbuf *p_from);
|
|
||||||
u16_t pbuf_copy_partial(struct pbuf *p, void *dataptr, u16_t len, u16_t offset);
|
|
||||||
err_t pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len);
|
|
||||||
struct pbuf *pbuf_coalesce(struct pbuf *p, pbuf_layer layer);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* __LWIP_PBUF_H__ */
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue