mirror of
https://git.savannah.nongnu.org/git/lwip.git
synced 2026-08-11 10:03:47 +08:00
... and finally, we got a first working version of a dual-stack lwIP runnin IPv4 and IPv6 in parallel - big thanks to Ivan Delamer! (this is work in progress, so please beware, test a lot and report problems!)
This commit is contained in:
@@ -56,6 +56,9 @@
|
||||
#include "lwip/dns.h"
|
||||
#include "lwip/timers.h"
|
||||
#include "netif/etharp.h"
|
||||
#include "lwip/ip6.h"
|
||||
#include "lwip/nd6.h"
|
||||
#include "lwip/mld6.h"
|
||||
|
||||
/* Compile-time sanity checks for configuration errors.
|
||||
* These can be done independently of LWIP_DEBUG, without penalty.
|
||||
@@ -299,6 +302,13 @@ lwip_init(void)
|
||||
#if LWIP_DNS
|
||||
dns_init();
|
||||
#endif /* LWIP_DNS */
|
||||
#if LWIP_IPV6
|
||||
ip6_init();
|
||||
nd6_init();
|
||||
#if LWIP_IPV6_MLD
|
||||
mld6_init();
|
||||
#endif /* LWIP_IPV6_MLD */
|
||||
#endif /* LWIP_IPV6 */
|
||||
|
||||
#if LWIP_TIMERS
|
||||
sys_timeouts_init();
|
||||
|
||||
@@ -70,7 +70,7 @@ static void icmp_send_response(struct pbuf *p, u8_t type, u8_t code);
|
||||
* 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 p the icmp echo request packet, p->payload pointing to the icmp header
|
||||
* @param inp the netif on which this packet was received
|
||||
*/
|
||||
void
|
||||
@@ -87,10 +87,9 @@ icmp_input(struct pbuf *p, struct netif *inp)
|
||||
ICMP_STATS_INC(icmp.recv);
|
||||
snmp_inc_icmpinmsgs();
|
||||
|
||||
|
||||
iphdr = (struct ip_hdr *)p->payload;
|
||||
iphdr = (struct ip_hdr *)ip_current_header();
|
||||
hlen = IPH_HL(iphdr) * 4;
|
||||
if (pbuf_header(p, -hlen) || (p->tot_len < sizeof(u16_t)*2)) {
|
||||
if (p->len < sizeof(u16_t)*2) {
|
||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: short ICMP (%"U16_F" bytes) received\n", p->tot_len));
|
||||
goto lenerr;
|
||||
}
|
||||
@@ -110,13 +109,13 @@ icmp_input(struct pbuf *p, struct netif *inp)
|
||||
int accepted = 1;
|
||||
#if !LWIP_MULTICAST_PING
|
||||
/* multicast destination address? */
|
||||
if (ip_addr_ismulticast(¤t_iphdr_dest)) {
|
||||
if (ip_addr_ismulticast(ip_current_dest_addr())) {
|
||||
accepted = 0;
|
||||
}
|
||||
#endif /* LWIP_MULTICAST_PING */
|
||||
#if !LWIP_BROADCAST_PING
|
||||
/* broadcast destination address? */
|
||||
if (ip_addr_isbroadcast(¤t_iphdr_dest, inp)) {
|
||||
if (ip_addr_isbroadcast(ip_current_dest_addr(), inp)) {
|
||||
accepted = 0;
|
||||
}
|
||||
#endif /* LWIP_BROADCAST_PING */
|
||||
|
||||
@@ -382,14 +382,13 @@ igmp_remove_group(struct igmp_group *group)
|
||||
/**
|
||||
* Called from ip_input() if a new IGMP packet is received.
|
||||
*
|
||||
* @param p received igmp packet, p->payload pointing to the ip header
|
||||
* @param p received igmp packet, p->payload pointing to the igmp 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, ip_addr_t *dest)
|
||||
{
|
||||
struct ip_hdr * iphdr;
|
||||
struct igmp_msg* igmp;
|
||||
struct igmp_group* group;
|
||||
struct igmp_group* groupref;
|
||||
@@ -397,8 +396,7 @@ igmp_input(struct pbuf *p, struct netif *inp, ip_addr_t *dest)
|
||||
IGMP_STATS_INC(igmp.recv);
|
||||
|
||||
/* Note that the length CAN be greater than 8 but only 8 are used - All are included in the checksum */
|
||||
iphdr = (struct ip_hdr *)p->payload;
|
||||
if (pbuf_header(p, -(s16_t)(IPH_HL(iphdr) * 4)) || (p->len < IGMP_MINLEN)) {
|
||||
if (p->len < IGMP_MINLEN) {
|
||||
pbuf_free(p);
|
||||
IGMP_STATS_INC(igmp.lenerr);
|
||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: length error\n"));
|
||||
@@ -406,9 +404,9 @@ igmp_input(struct pbuf *p, struct netif *inp, ip_addr_t *dest)
|
||||
}
|
||||
|
||||
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: message from "));
|
||||
ip_addr_debug_print(IGMP_DEBUG, &(iphdr->src));
|
||||
ip_addr_debug_print(IGMP_DEBUG, &(ip_current_header()->src));
|
||||
LWIP_DEBUGF(IGMP_DEBUG, (" to address "));
|
||||
ip_addr_debug_print(IGMP_DEBUG, &(iphdr->dest));
|
||||
ip_addr_debug_print(IGMP_DEBUG, &(ip_current_header()->dest));
|
||||
LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", inp));
|
||||
|
||||
/* Now calculate and check the checksum */
|
||||
|
||||
@@ -60,6 +60,7 @@
|
||||
# ifndef LWIP_CHKSUM_ALGORITHM
|
||||
# define LWIP_CHKSUM_ALGORITHM 2
|
||||
# endif
|
||||
u16_t lwip_standard_chksum(void *dataptr, int len);
|
||||
#endif
|
||||
/* If none set: */
|
||||
#ifndef LWIP_CHKSUM_ALGORITHM
|
||||
@@ -77,7 +78,7 @@
|
||||
* @note accumulator size limits summable length to 64k
|
||||
* @note host endianess is irrelevant (p3 RFC1071)
|
||||
*/
|
||||
static u16_t
|
||||
u16_t
|
||||
lwip_standard_chksum(void *dataptr, u16_t len)
|
||||
{
|
||||
u32_t acc;
|
||||
@@ -131,7 +132,7 @@ lwip_standard_chksum(void *dataptr, u16_t len)
|
||||
* @return host order (!) lwip checksum (non-inverted Internet sum)
|
||||
*/
|
||||
|
||||
static u16_t
|
||||
u16_t
|
||||
lwip_standard_chksum(void *dataptr, int len)
|
||||
{
|
||||
u8_t *pb = (u8_t *)dataptr;
|
||||
@@ -187,7 +188,7 @@ lwip_standard_chksum(void *dataptr, int len)
|
||||
* by Curt McDowell, Broadcom Corp. December 8th, 2005
|
||||
*/
|
||||
|
||||
static u16_t
|
||||
u16_t
|
||||
lwip_standard_chksum(void *dataptr, int len)
|
||||
{
|
||||
u8_t *pb = (u8_t *)dataptr;
|
||||
|
||||
@@ -496,23 +496,27 @@ ip_input(struct pbuf *p, struct netif *inp)
|
||||
case IP_PROTO_UDPLITE:
|
||||
#endif /* LWIP_UDPLITE */
|
||||
snmp_inc_ipindelivers();
|
||||
pbuf_header(p, -iphdr_hlen); /* Move to payload, no check necessary. */
|
||||
udp_input(p, inp);
|
||||
break;
|
||||
#endif /* LWIP_UDP */
|
||||
#if LWIP_TCP
|
||||
case IP_PROTO_TCP:
|
||||
snmp_inc_ipindelivers();
|
||||
pbuf_header(p, -iphdr_hlen); /* Move to payload, no check necessary. */
|
||||
tcp_input(p, inp);
|
||||
break;
|
||||
#endif /* LWIP_TCP */
|
||||
#if LWIP_ICMP
|
||||
case IP_PROTO_ICMP:
|
||||
snmp_inc_ipindelivers();
|
||||
pbuf_header(p, -iphdr_hlen); /* Move to payload, no check necessary. */
|
||||
icmp_input(p, inp);
|
||||
break;
|
||||
#endif /* LWIP_ICMP */
|
||||
#if LWIP_IGMP
|
||||
case IP_PROTO_IGMP:
|
||||
pbuf_header(p, -iphdr_hlen); /* Move to payload, no check necessary. */
|
||||
igmp_input(p, inp, ¤t_iphdr_dest);
|
||||
break;
|
||||
#endif /* LWIP_IGMP */
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* IPv6 version of ICMP, as per RFC 4443.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
||||
* Copyright (c) 2010 Inico Technologies Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
@@ -26,154 +32,272 @@
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
* Author: Ivan Delamer <delamer@inicotech.com>
|
||||
*
|
||||
*
|
||||
* Please coordinate changes and requests with Ivan Delamer
|
||||
* <delamer@inicotech.com>
|
||||
*/
|
||||
|
||||
/* 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 */
|
||||
#if LWIP_ICMP6 && LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "lwip/icmp.h"
|
||||
#include "lwip/inet.h"
|
||||
#include "lwip/ip.h"
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/icmp6.h"
|
||||
#include "lwip/ip6.h"
|
||||
#include "lwip/ip6_addr.h"
|
||||
#include "lwip/ip6_chksum.h"
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/netif.h"
|
||||
#include "lwip/nd6.h"
|
||||
#include "lwip/mld6.h"
|
||||
#include "lwip/stats.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#ifndef LWIP_ICMP6_DATASIZE
|
||||
#define LWIP_ICMP6_DATASIZE 8
|
||||
#endif
|
||||
#if LWIP_ICMP6_DATASIZE == 0
|
||||
#define LWIP_ICMP6_DATASIZE 8
|
||||
#endif
|
||||
|
||||
/* Forward declarations */
|
||||
static void icmp6_send_response(struct pbuf *p, u8_t type, u8_t code, u32_t data);
|
||||
|
||||
|
||||
/**
|
||||
* Process an input ICMPv6 message. Called by ip6_input.
|
||||
*
|
||||
* Will generate a reply for echo requests. Other messages are forwarded
|
||||
* to nd6_input, or mld6_input.
|
||||
*
|
||||
* @param p the mld packet, p->payload pointing to the icmpv6 header
|
||||
* @param inp the netif on which this packet was received
|
||||
*/
|
||||
void
|
||||
icmp_input(struct pbuf *p, struct netif *inp)
|
||||
icmp6_input(struct pbuf *p, struct netif *inp)
|
||||
{
|
||||
u8_t type;
|
||||
struct icmp_echo_hdr *iecho;
|
||||
struct ip_hdr *iphdr;
|
||||
struct ip_addr tmpaddr;
|
||||
struct icmp6_hdr *icmp6hdr;
|
||||
struct pbuf * r;
|
||||
ip6_addr_t * reply_src;
|
||||
|
||||
ICMP_STATS_INC(icmp.recv);
|
||||
ICMP6_STATS_INC(icmp6.recv);
|
||||
|
||||
/* TODO: check length before accessing payload! */
|
||||
/* Check that ICMPv6 header fits in payload */
|
||||
if (p->len < sizeof(struct icmp6_hdr)) {
|
||||
/* drop short packets */
|
||||
pbuf_free(p);
|
||||
ICMP6_STATS_INC(icmp6.lenerr);
|
||||
ICMP6_STATS_INC(icmp6.drop);
|
||||
return;
|
||||
}
|
||||
|
||||
type = ((u8_t *)p->payload)[0];
|
||||
icmp6hdr = (struct icmp6_hdr *)p->payload;
|
||||
|
||||
switch (type) {
|
||||
case ICMP6_ECHO:
|
||||
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"));
|
||||
#if LWIP_ICMP6_CHECKSUM_CHECK
|
||||
if (ip6_chksum_pseudo(p, ip6_current_src_addr(), ip6_current_dest_addr(),
|
||||
IP6_NEXTH_ICMP6, p->tot_len) != 0) {
|
||||
/* Checksum failed */
|
||||
pbuf_free(p);
|
||||
ICMP6_STATS_INC(icmp6.chkerr);
|
||||
ICMP6_STATS_INC(icmp6.drop);
|
||||
return;
|
||||
}
|
||||
#endif /* LWIP_ICMP6_CHECKSUM_CHECK */
|
||||
|
||||
switch (icmp6hdr->type) {
|
||||
case ICMP6_TYPE_NA: /* Neighbor advertisement */
|
||||
case ICMP6_TYPE_NS: /* Neighbor solicitation */
|
||||
case ICMP6_TYPE_RA: /* Router advertisement */
|
||||
case ICMP6_TYPE_RD: /* Redirect */
|
||||
case ICMP6_TYPE_PTB: /* Packet too big */
|
||||
nd6_input(p, inp);
|
||||
return;
|
||||
break;
|
||||
case ICMP6_TYPE_RS:
|
||||
#if LWIP_IPV6_FORWARD
|
||||
/* TODO implement router functionality */
|
||||
#endif
|
||||
break;
|
||||
#if LWIP_IPV6_MLD
|
||||
case ICMP6_TYPE_MLQ:
|
||||
case ICMP6_TYPE_MLR:
|
||||
case ICMP6_TYPE_MLD:
|
||||
mld6_input(p, inp);
|
||||
return;
|
||||
break;
|
||||
#endif
|
||||
case ICMP6_TYPE_EREQ:
|
||||
#if !LWIP_MULTICAST_PING
|
||||
/* multicast destination address? */
|
||||
if (ip6_addr_ismulticast(ip6_current_dest_addr())) {
|
||||
/* drop */
|
||||
pbuf_free(p);
|
||||
ICMP_STATS_INC(icmp.lenerr);
|
||||
ICMP6_STATS_INC(icmp6.drop);
|
||||
return;
|
||||
}
|
||||
iecho = p->payload;
|
||||
iphdr = (struct ip_hdr *)((u8_t *)p->payload - IP_HLEN);
|
||||
if (inet_chksum_pbuf(p) != 0) {
|
||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo (%"X16_F")\n", inet_chksum_pseudo(p, &(iphdr->src), &(iphdr->dest), IP_PROTO_ICMP, p->tot_len)));
|
||||
ICMP_STATS_INC(icmp.chkerr);
|
||||
/* return;*/
|
||||
}
|
||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp: p->len %"S16_F" p->tot_len %"S16_F"\n", p->len, p->tot_len));
|
||||
ip_addr_set(&tmpaddr, &(iphdr->src));
|
||||
ip_addr_set(&(iphdr->src), &(iphdr->dest));
|
||||
ip_addr_set(&(iphdr->dest), &tmpaddr);
|
||||
iecho->type = ICMP6_ER;
|
||||
/* adjust the checksum */
|
||||
if (iecho->chksum >= htons(0xffff - (ICMP6_ECHO << 8))) {
|
||||
iecho->chksum += htons(ICMP6_ECHO << 8) + 1;
|
||||
} else {
|
||||
iecho->chksum += htons(ICMP6_ECHO << 8);
|
||||
}
|
||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo (%"X16_F")\n", inet_chksum_pseudo(p, &(iphdr->src), &(iphdr->dest), IP_PROTO_ICMP, p->tot_len)));
|
||||
ICMP_STATS_INC(icmp.xmit);
|
||||
#endif /* LWIP_MULTICAST_PING */
|
||||
|
||||
/* Allocate reply. */
|
||||
r = pbuf_alloc(PBUF_IP, p->tot_len, PBUF_RAM);
|
||||
if (r == NULL) {
|
||||
/* drop */
|
||||
pbuf_free(p);
|
||||
ICMP6_STATS_INC(icmp6.memerr);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Copy echo request. */
|
||||
if (pbuf_copy(r, p) != ERR_OK) {
|
||||
/* drop */
|
||||
pbuf_free(p);
|
||||
pbuf_free(r);
|
||||
ICMP6_STATS_INC(icmp6.err);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Determine reply source IPv6 address. */
|
||||
reply_src = ip6_select_source_address(inp, ip6_current_src_addr());
|
||||
if (reply_src == NULL) {
|
||||
/* drop */
|
||||
pbuf_free(p);
|
||||
pbuf_free(r);
|
||||
ICMP6_STATS_INC(icmp6.rterr);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set fields in reply. */
|
||||
((struct icmp6_echo_hdr *)(r->payload))->type = ICMP6_TYPE_EREP;
|
||||
((struct icmp6_echo_hdr *)(r->payload))->chksum = 0;
|
||||
((struct icmp6_echo_hdr *)(r->payload))->chksum = ip6_chksum_pseudo(r,
|
||||
reply_src, ip6_current_src_addr(),
|
||||
IP6_NEXTH_ICMP6, r->tot_len);
|
||||
|
||||
/* Send reply. */
|
||||
ICMP6_STATS_INC(icmp6.xmit);
|
||||
ip6_output_if(r, reply_src, ip6_current_src_addr(),
|
||||
LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6, inp);
|
||||
pbuf_free(r);
|
||||
|
||||
/* LWIP_DEBUGF("icmp: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len);*/
|
||||
ip_output_if (p, &(iphdr->src), IP_HDRINCL,
|
||||
iphdr->hoplim, IP_PROTO_ICMP, inp);
|
||||
break;
|
||||
default:
|
||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ICMP type %"S16_F" not supported.\n", (s16_t)type));
|
||||
ICMP_STATS_INC(icmp.proterr);
|
||||
ICMP_STATS_INC(icmp.drop);
|
||||
ICMP6_STATS_INC(icmp6.proterr);
|
||||
ICMP6_STATS_INC(icmp6.drop);
|
||||
break;
|
||||
}
|
||||
|
||||
pbuf_free(p);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send an icmpv6 'destination unreachable' packet.
|
||||
*
|
||||
* @param p the input packet for which the 'unreachable' should be sent,
|
||||
* p->payload pointing to the IPv6 header
|
||||
* @param c ICMPv6 code for the unreachable type
|
||||
*/
|
||||
void
|
||||
icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t)
|
||||
icmp6_dest_unreach(struct pbuf *p, enum icmp6_dur_code c)
|
||||
{
|
||||
struct pbuf *q;
|
||||
struct ip_hdr *iphdr;
|
||||
struct icmp_dur_hdr *idur;
|
||||
|
||||
/* @todo: can this be PBUF_LINK instead of PBUF_IP? */
|
||||
q = pbuf_alloc(PBUF_IP, 8 + IP_HLEN + 8, PBUF_RAM);
|
||||
/* ICMP header + IP header + 8 bytes of data */
|
||||
if (q == NULL) {
|
||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_dest_unreach: failed to allocate pbuf for ICMP packet.\n"));
|
||||
pbuf_free(p);
|
||||
return;
|
||||
}
|
||||
LWIP_ASSERT("check that first pbuf can hold icmp message",
|
||||
(q->len >= (8 + IP_HLEN + 8)));
|
||||
|
||||
iphdr = p->payload;
|
||||
|
||||
idur = q->payload;
|
||||
idur->type = (u8_t)ICMP6_DUR;
|
||||
idur->icode = (u8_t)t;
|
||||
|
||||
SMEMCPY((u8_t *)q->payload + 8, p->payload, IP_HLEN + 8);
|
||||
|
||||
/* calculate checksum */
|
||||
idur->chksum = 0;
|
||||
idur->chksum = inet_chksum(idur, q->len);
|
||||
ICMP_STATS_INC(icmp.xmit);
|
||||
|
||||
ip_output(q, NULL,
|
||||
(struct ip_addr *)&(iphdr->src), ICMP_TTL, IP_PROTO_ICMP);
|
||||
pbuf_free(q);
|
||||
icmp6_send_response(p, ICMP6_TYPE_DUR, c, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an icmpv6 'packet too big' packet.
|
||||
*
|
||||
* @param p the input packet for which the 'packet too big' should be sent,
|
||||
* p->payload pointing to the IPv6 header
|
||||
* @param mtu the maximum mtu that we can accept
|
||||
*/
|
||||
void
|
||||
icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t)
|
||||
icmp6_packet_too_big(struct pbuf *p, u32_t mtu)
|
||||
{
|
||||
icmp6_send_response(p, ICMP6_TYPE_PTB, 0, mtu);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an icmpv6 'time exceeded' packet.
|
||||
*
|
||||
* @param p the input packet for which the 'unreachable' should be sent,
|
||||
* p->payload pointing to the IPv6 header
|
||||
* @param c ICMPv6 code for the time exceeded type
|
||||
*/
|
||||
void
|
||||
icmp6_time_exceeded(struct pbuf *p, enum icmp6_te_code c)
|
||||
{
|
||||
icmp6_send_response(p, ICMP6_TYPE_TE, c, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an icmpv6 'parameter problem' packet.
|
||||
*
|
||||
* @param p the input packet for which the 'param problem' should be sent,
|
||||
* p->payload pointing to the IP header
|
||||
* @param c ICMPv6 code for the param problem type
|
||||
* @param pointer the pointer to the byte where the parameter is found
|
||||
*/
|
||||
void
|
||||
icmp6_param_problem(struct pbuf *p, enum icmp6_pp_code c, u32_t pointer)
|
||||
{
|
||||
icmp6_send_response(p, ICMP6_TYPE_PP, c, pointer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an ICMPv6 packet in response to an incoming packet.
|
||||
*
|
||||
* @param p the input packet for which the response should be sent,
|
||||
* p->payload pointing to the IPv6 header
|
||||
* @param type Type of the ICMPv6 header
|
||||
* @param code Code of the ICMPv6 header
|
||||
* @param data Additional 32-bit parameter in the ICMPv6 header
|
||||
*/
|
||||
static void
|
||||
icmp6_send_response(struct pbuf *p, u8_t type, u8_t code, u32_t data)
|
||||
{
|
||||
struct pbuf *q;
|
||||
struct ip_hdr *iphdr;
|
||||
struct icmp_te_hdr *tehdr;
|
||||
struct icmp6_hdr *icmp6hdr;
|
||||
ip6_addr_t * reply_src;
|
||||
|
||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded\n"));
|
||||
|
||||
/* @todo: can this be PBUF_LINK instead of PBUF_IP? */
|
||||
q = pbuf_alloc(PBUF_IP, 8 + IP_HLEN + 8, PBUF_RAM);
|
||||
/* ICMP header + IP header + 8 bytes of data */
|
||||
/* ICMPv6 header + IPv6 header + data */
|
||||
q = pbuf_alloc(PBUF_IP, sizeof(struct icmp6_hdr) + IP6_HLEN + LWIP_ICMP6_DATASIZE,
|
||||
PBUF_RAM);
|
||||
if (q == NULL) {
|
||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_dest_unreach: failed to allocate pbuf for ICMP packet.\n"));
|
||||
pbuf_free(p);
|
||||
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMPv6 packet.\n"));
|
||||
ICMP6_STATS_INC(icmp6.memerr);
|
||||
return;
|
||||
}
|
||||
LWIP_ASSERT("check that first pbuf can hold icmp message",
|
||||
(q->len >= (8 + IP_HLEN + 8)));
|
||||
LWIP_ASSERT("check that first pbuf can hold icmp 6message",
|
||||
(q->len >= (sizeof(struct icmp6_hdr) + IP6_HLEN + LWIP_ICMP6_DATASIZE)));
|
||||
|
||||
iphdr = p->payload;
|
||||
|
||||
tehdr = q->payload;
|
||||
tehdr->type = (u8_t)ICMP6_TE;
|
||||
tehdr->icode = (u8_t)t;
|
||||
icmp6hdr = (struct icmp6_hdr *)q->payload;
|
||||
icmp6hdr->type = type;
|
||||
icmp6hdr->code = code;
|
||||
icmp6hdr->data = data;
|
||||
|
||||
/* copy fields from original packet */
|
||||
SMEMCPY((u8_t *)q->payload + 8, (u8_t *)p->payload, IP_HLEN + 8);
|
||||
SMEMCPY((u8_t *)q->payload + sizeof(struct icmp6_hdr), (u8_t *)p->payload,
|
||||
IP6_HLEN + LWIP_ICMP6_DATASIZE);
|
||||
|
||||
/* Select an address to use as source. */
|
||||
reply_src = ip6_select_source_address(current_netif, ip6_current_src_addr());
|
||||
if (reply_src == NULL) {
|
||||
/* drop */
|
||||
pbuf_free(q);
|
||||
ICMP6_STATS_INC(icmp6.rterr);
|
||||
return;
|
||||
}
|
||||
|
||||
/* calculate checksum */
|
||||
tehdr->chksum = 0;
|
||||
tehdr->chksum = inet_chksum(tehdr, q->len);
|
||||
ICMP_STATS_INC(icmp.xmit);
|
||||
ip_output(q, NULL,
|
||||
(struct ip_addr *)&(iphdr->src), ICMP_TTL, IP_PROTO_ICMP);
|
||||
icmp6hdr->chksum = 0;
|
||||
icmp6hdr->chksum = ip6_chksum_pseudo(q, reply_src, ip6_current_src_addr(),
|
||||
IP6_NEXTH_ICMP6, q->tot_len);
|
||||
|
||||
ICMP6_STATS_INC(icmp6.xmit);
|
||||
ip6_output(q, reply_src, ip6_current_src_addr(), LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6);
|
||||
pbuf_free(q);
|
||||
}
|
||||
|
||||
#endif /* LWIP_ICMP */
|
||||
|
||||
#endif /* LWIP_ICMP6 && LWIP_IPV6 */
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
/**
|
||||
* @file
|
||||
* Functions common to all TCP/IPv6 modules, such as the Internet checksum and the
|
||||
* byte order functions.
|
||||
*
|
||||
* INET v6 addresses.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
||||
* Copyright (c) 2010 Inico Technologies Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
@@ -33,131 +32,20 @@
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
* Author: Ivan Delamer <delamer@inicotech.com>
|
||||
*
|
||||
*
|
||||
* Please coordinate changes and requests with Ivan Delamer
|
||||
* <delamer@inicotech.com>
|
||||
*/
|
||||
|
||||
#include "lwip/opt.h"
|
||||
|
||||
#if LWIP_IPV6 && LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/inet.h"
|
||||
#include "lwip/inet6.h"
|
||||
|
||||
/* chksum:
|
||||
*
|
||||
* Sums up all 16 bit words in a memory portion. Also includes any odd byte.
|
||||
* This function is used by the other checksum functions.
|
||||
*
|
||||
* For now, this is not optimized. Must be optimized for the particular processor
|
||||
* arcitecture on which it is to run. Preferebly coded in assembler.
|
||||
*/
|
||||
/** @see ip6_addr.c for implementation of functions. */
|
||||
|
||||
static u32_t
|
||||
chksum(void *dataptr, u16_t len)
|
||||
{
|
||||
u16_t *sdataptr = dataptr;
|
||||
u32_t acc;
|
||||
|
||||
|
||||
for(acc = 0; len > 1; len -= 2) {
|
||||
acc += *sdataptr++;
|
||||
}
|
||||
|
||||
/* add up any odd byte */
|
||||
if (len == 1) {
|
||||
acc += htons((u16_t)(*(u8_t *)dataptr) << 8);
|
||||
}
|
||||
|
||||
return acc;
|
||||
|
||||
}
|
||||
|
||||
/* inet_chksum_pseudo:
|
||||
*
|
||||
* Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.
|
||||
*/
|
||||
|
||||
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 acc;
|
||||
struct pbuf *q;
|
||||
u8_t swapped, i;
|
||||
|
||||
acc = 0;
|
||||
swapped = 0;
|
||||
for(q = p; q != NULL; q = q->next) {
|
||||
acc += chksum(q->payload, q->len);
|
||||
while (acc >> 16) {
|
||||
acc = (acc & 0xffff) + (acc >> 16);
|
||||
}
|
||||
if (q->len % 2 != 0) {
|
||||
swapped = 1 - swapped;
|
||||
acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
if (swapped) {
|
||||
acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8);
|
||||
}
|
||||
|
||||
for(i = 0; i < 8; i++) {
|
||||
acc += ((u16_t *)src->addr)[i] & 0xffff;
|
||||
acc += ((u16_t *)dest->addr)[i] & 0xffff;
|
||||
while (acc >> 16) {
|
||||
acc = (acc & 0xffff) + (acc >> 16);
|
||||
}
|
||||
}
|
||||
acc += (u16_t)htons((u16_t)proto);
|
||||
acc += ((u16_t *)&proto_len)[0] & 0xffff;
|
||||
acc += ((u16_t *)&proto_len)[1] & 0xffff;
|
||||
|
||||
while (acc >> 16) {
|
||||
acc = (acc & 0xffff) + (acc >> 16);
|
||||
}
|
||||
return ~(acc & 0xffff);
|
||||
}
|
||||
|
||||
/* inet_chksum:
|
||||
*
|
||||
* Calculates the Internet checksum over a portion of memory. Used primarely for IP
|
||||
* and ICMP.
|
||||
*/
|
||||
|
||||
u16_t
|
||||
inet_chksum(void *dataptr, u16_t len)
|
||||
{
|
||||
u32_t acc, sum;
|
||||
|
||||
acc = chksum(dataptr, len);
|
||||
sum = (acc & 0xffff) + (acc >> 16);
|
||||
sum += (sum >> 16);
|
||||
return ~(sum & 0xffff);
|
||||
}
|
||||
|
||||
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 += chksum(q->payload, q->len);
|
||||
while (acc >> 16) {
|
||||
acc = (acc & 0xffff) + (acc >> 16);
|
||||
}
|
||||
if (q->len % 2 != 0) {
|
||||
swapped = 1 - swapped;
|
||||
acc = (acc & 0xff << 8) | (acc & 0xff00 >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
if (swapped) {
|
||||
acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8);
|
||||
}
|
||||
return ~(acc & 0xffff);
|
||||
}
|
||||
#endif /* LWIP_IPV6 */
|
||||
|
||||
1105
src/core/ipv6/ip6.c
1105
src/core/ipv6/ip6.c
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,11 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* IPv6 addresses.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
|
||||
* Copyright (c) 2010 Inico Technologies Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
@@ -26,47 +32,210 @@
|
||||
*
|
||||
* This file is part of the lwIP TCP/IP stack.
|
||||
*
|
||||
* Author: Adam Dunkels <adam@sics.se>
|
||||
* Author: Ivan Delamer <delamer@inicotech.com>
|
||||
*
|
||||
* Functions for handling IPv6 addresses.
|
||||
*
|
||||
* Please coordinate changes and requests with Ivan Delamer
|
||||
* <delamer@inicotech.com>
|
||||
*/
|
||||
|
||||
#include "lwip/opt.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/inet.h"
|
||||
|
||||
u8_t
|
||||
ip_addr_netcmp(struct ip_addr *addr1, struct ip_addr *addr2,
|
||||
struct ip_addr *mask)
|
||||
#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */
|
||||
|
||||
#include "lwip/ip6_addr.h"
|
||||
#include "lwip/def.h"
|
||||
|
||||
/* used by IP6_ADDR_ANY in ip6_addr.h */
|
||||
const ip6_addr_t ip6_addr_any = { { 0ul, 0ul, 0ul, 0ul } };
|
||||
|
||||
#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')
|
||||
#define xchar(i) ((i) < 10 ? '0' + (i) : 'A' + (i) - 10)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Check whether "cp" is a valid ascii representation
|
||||
* of an IPv6 address and convert to a binary address.
|
||||
* Returns 1 if the address is valid, 0 if not.
|
||||
*
|
||||
* @param cp IPv6 address in ascii represenation (e.g. "FF01::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
|
||||
ip6addr_aton(const char *cp, ip6_addr_t *addr)
|
||||
{
|
||||
return((addr1->addr[0] & mask->addr[0]) == (addr2->addr[0] & mask->addr[0]) &&
|
||||
(addr1->addr[1] & mask->addr[1]) == (addr2->addr[1] & mask->addr[1]) &&
|
||||
(addr1->addr[2] & mask->addr[2]) == (addr2->addr[2] & mask->addr[2]) &&
|
||||
(addr1->addr[3] & mask->addr[3]) == (addr2->addr[3] & mask->addr[3]));
|
||||
|
||||
u32_t addr_index, zero_blocks, current_block_index, current_block_value;
|
||||
const char * s;
|
||||
|
||||
/* Count the number of colons, to count the number of blocks in a "::" sequence
|
||||
zero_blocks may be 1 even if there are no :: sequences */
|
||||
zero_blocks = 8;
|
||||
for (s = cp; *s != 0; s++) {
|
||||
if (*s == ':')
|
||||
zero_blocks--;
|
||||
else if (!isxdigit(*s))
|
||||
break;
|
||||
}
|
||||
|
||||
/* parse each block */
|
||||
addr_index = 0;
|
||||
current_block_index = 0;
|
||||
current_block_value = 0;
|
||||
for (s = cp; *s != 0; s++) {
|
||||
if (*s == ':') {
|
||||
if (current_block_index & 0x1) {
|
||||
addr->addr[addr_index++] |= current_block_value;
|
||||
}
|
||||
else {
|
||||
addr->addr[addr_index] = current_block_value << 16;
|
||||
}
|
||||
current_block_index++;
|
||||
current_block_value = 0;
|
||||
if (current_block_index > 7) {
|
||||
/* address too long! */
|
||||
return 0;
|
||||
} if (s[1] == ':') {
|
||||
s++;
|
||||
/* "::" found, set zeros */
|
||||
while (zero_blocks-- > 0) {
|
||||
if (current_block_index & 0x1) {
|
||||
addr_index++;
|
||||
}
|
||||
else {
|
||||
addr->addr[addr_index] = 0;
|
||||
}
|
||||
current_block_index++;
|
||||
}
|
||||
}
|
||||
} else if (isxdigit(*s)) {
|
||||
/* add current digit */
|
||||
current_block_value = (current_block_value << 4) +
|
||||
(isdigit(*s) ? *s - '0' :
|
||||
10 + (islower(*s) ? *s - 'a' : *s - 'A'));
|
||||
} else {
|
||||
/* unexpected digit, space? CRLF? */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (current_block_index & 0x1) {
|
||||
addr->addr[addr_index++] |= current_block_value;
|
||||
}
|
||||
else {
|
||||
addr->addr[addr_index] = current_block_value << 16;
|
||||
}
|
||||
|
||||
/* convert to network byte order. */
|
||||
for (addr_index = 0; addr_index < 4; addr_index++) {
|
||||
addr->addr[addr_index] = htonl(addr->addr[addr_index]);
|
||||
}
|
||||
|
||||
if (current_block_index != 7) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
u8_t
|
||||
ip_addr_cmp(struct ip_addr *addr1, struct ip_addr *addr2)
|
||||
/**
|
||||
* Convert numeric IPv6 address into ASCII representation.
|
||||
* returns ptr to static buffer; not reentrant!
|
||||
*
|
||||
* @param addr ip6 address in network order to convert
|
||||
* @return pointer to a global static (!) buffer that holds the ASCII
|
||||
* represenation of addr
|
||||
*/
|
||||
char *
|
||||
ip6addr_ntoa(const ip6_addr_t *addr)
|
||||
{
|
||||
return(addr1->addr[0] == addr2->addr[0] &&
|
||||
addr1->addr[1] == addr2->addr[1] &&
|
||||
addr1->addr[2] == addr2->addr[2] &&
|
||||
addr1->addr[3] == addr2->addr[3]);
|
||||
static char str[40];
|
||||
return ip6addr_ntoa_r(addr, str, 40);
|
||||
}
|
||||
|
||||
void
|
||||
ip_addr_set(struct ip_addr *dest, struct ip_addr *src)
|
||||
/**
|
||||
* Same as ipaddr_ntoa, but reentrant since a user-supplied buffer is used.
|
||||
*
|
||||
* @param addr ip6 address in network order to convert
|
||||
* @param buf target buffer where the string is stored
|
||||
* @param buflen length of buf
|
||||
* @return either pointer to buf which now holds the ASCII
|
||||
* representation of addr or NULL if buf was too small
|
||||
*/
|
||||
char *
|
||||
ip6addr_ntoa_r(const ip6_addr_t *addr, char *buf, int buflen)
|
||||
{
|
||||
SMEMCPY(dest, src, sizeof(struct ip_addr));
|
||||
/* dest->addr[0] = src->addr[0];
|
||||
dest->addr[1] = src->addr[1];
|
||||
dest->addr[2] = src->addr[2];
|
||||
dest->addr[3] = src->addr[3];*/
|
||||
}
|
||||
u32_t current_block_index, current_block_value;
|
||||
s32_t zero_flag, i;
|
||||
|
||||
u8_t
|
||||
ip_addr_isany(struct ip_addr *addr)
|
||||
{
|
||||
if (addr == NULL) return 1;
|
||||
return((addr->addr[0] | addr->addr[1] | addr->addr[2] | addr->addr[3]) == 0);
|
||||
i = 0;
|
||||
zero_flag = 0; /* used to indicate a zero chain for "::' */
|
||||
|
||||
for (current_block_index = 0; current_block_index < 8; current_block_index++) {
|
||||
/* get the current 16-bit block */
|
||||
current_block_value = htonl(addr->addr[current_block_index >> 1]);
|
||||
if ((current_block_index & 0x1) == 0) {
|
||||
current_block_value = current_block_value >> 16;
|
||||
}
|
||||
current_block_value &= 0xffff;
|
||||
|
||||
if (current_block_value == 0) {
|
||||
/* generate empty block "::" */
|
||||
if (!zero_flag) {
|
||||
if (current_block_index > 0) {
|
||||
zero_flag = 1;
|
||||
buf[i++] = ':';
|
||||
if (i >= buflen) return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (current_block_index > 0) {
|
||||
buf[i++] = ':';
|
||||
if (i >= buflen) return NULL;
|
||||
}
|
||||
|
||||
if ((current_block_value & 0xf000) == 0) {
|
||||
zero_flag = 1;
|
||||
}
|
||||
else {
|
||||
buf[i++] = xchar(((current_block_value & 0xf000) >> 12));
|
||||
if (i >= buflen) return NULL;
|
||||
}
|
||||
|
||||
if (((current_block_value & 0xf00) == 0) && (zero_flag)) {
|
||||
/* do nothing */
|
||||
}
|
||||
else {
|
||||
buf[i++] = xchar(((current_block_value & 0xf00) >> 8));
|
||||
if (i >= buflen) return NULL;
|
||||
}
|
||||
|
||||
if (((current_block_value & 0xf0) == 0) && (zero_flag)) {
|
||||
/* do nothing */
|
||||
}
|
||||
else {
|
||||
buf[i++] = xchar(((current_block_value & 0xf0) >> 4));
|
||||
if (i >= buflen) return NULL;
|
||||
}
|
||||
|
||||
buf[i++] = xchar((current_block_value & 0xf));
|
||||
if (i >= buflen) return NULL;
|
||||
|
||||
zero_flag = 0;
|
||||
}
|
||||
}
|
||||
|
||||
buf[i] = 0;
|
||||
|
||||
return buf;
|
||||
}
|
||||
#endif /* LWIP_IPV6 */
|
||||
|
||||
@@ -58,6 +58,9 @@
|
||||
#include "lwip/snmp_msg.h"
|
||||
#include "lwip/dns.h"
|
||||
#include "netif/ppp_oe.h"
|
||||
#include "lwip/nd6.h"
|
||||
#include "lwip/ip6_frag.h"
|
||||
#include "lwip/mld6.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
117
src/core/netif.c
117
src/core/netif.c
@@ -40,6 +40,7 @@
|
||||
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/ip6_addr.h"
|
||||
#include "lwip/netif.h"
|
||||
#include "lwip/tcp_impl.h"
|
||||
#include "lwip/snmp.h"
|
||||
@@ -59,6 +60,12 @@
|
||||
#if LWIP_DHCP
|
||||
#include "lwip/dhcp.h"
|
||||
#endif /* LWIP_DHCP */
|
||||
#if LWIP_IPV6_DHCP6
|
||||
#include "lwip/dhcp6.h"
|
||||
#endif /* LWIP_IPV6_DHCP6 */
|
||||
#if LWIP_IPV6_MLD
|
||||
#include "lwip/mld6.h"
|
||||
#endif /* LWIP_IPV6_MLD */
|
||||
|
||||
#if LWIP_NETIF_STATUS_CALLBACK
|
||||
#define NETIF_STATUS_CALLBACK(n) do{ if (n->status_callback) { (n->status_callback)(n); }}while(0)
|
||||
@@ -138,6 +145,9 @@ netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask,
|
||||
ip_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input)
|
||||
{
|
||||
static u8_t netifnum = 0;
|
||||
#if LWIP_IPV6
|
||||
u32_t i;
|
||||
#endif
|
||||
|
||||
LWIP_ASSERT("No init function given", init != NULL);
|
||||
|
||||
@@ -145,6 +155,12 @@ netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask,
|
||||
ip_addr_set_zero(&netif->ip_addr);
|
||||
ip_addr_set_zero(&netif->netmask);
|
||||
ip_addr_set_zero(&netif->gw);
|
||||
#if LWIP_IPV6
|
||||
for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
|
||||
ip6_addr_set_zero(&netif->ip6_addr[i]);
|
||||
netif_ip6_addr_set_state(netif, i, IP6_ADDR_INVALID);
|
||||
}
|
||||
#endif /* LWIP_IPV6 */
|
||||
netif->flags = 0;
|
||||
#if LWIP_DHCP
|
||||
/* netif not under DHCP control by default */
|
||||
@@ -154,6 +170,17 @@ netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask,
|
||||
/* netif not under AutoIP control by default */
|
||||
netif->autoip = NULL;
|
||||
#endif /* LWIP_AUTOIP */
|
||||
#if LWIP_IPV6_AUTOCONFIG
|
||||
/* IPv6 address autoconfiguration not enabled by default */
|
||||
netif->ip6_autoconfig_enabled = 0;
|
||||
#endif /* LWIP_IPV6_AUTOCONFIG */
|
||||
#if LWIP_IPV6_SEND_ROUTER_SOLICIT
|
||||
netif->rs_count = LWIP_ND6_MAX_MULTICAST_SOLICIT;
|
||||
#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */
|
||||
#if LWIP_IPV6_DHCP6
|
||||
/* netif not under DHCPv6 control by default */
|
||||
netif->dhcp6 = NULL;
|
||||
#endif /* LWIP_IPV6_DHCP6 */
|
||||
#if LWIP_NETIF_STATUS_CALLBACK
|
||||
netif->status_callback = NULL;
|
||||
#endif /* LWIP_NETIF_STATUS_CALLBACK */
|
||||
@@ -163,6 +190,9 @@ netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask,
|
||||
#if LWIP_IGMP
|
||||
netif->igmp_mac_filter = NULL;
|
||||
#endif /* LWIP_IGMP */
|
||||
#if LWIP_IPV6 && LWIP_IPV6_MLD
|
||||
netif->mld_mac_filter = NULL;
|
||||
#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
|
||||
#if ENABLE_LOOPBACK
|
||||
netif->loop_first = NULL;
|
||||
netif->loop_last = NULL;
|
||||
@@ -245,6 +275,10 @@ netif_remove(struct netif *netif)
|
||||
igmp_stop(netif);
|
||||
}
|
||||
#endif /* LWIP_IGMP */
|
||||
#if LWIP_IPV6 && LWIP_IPV6_MLD
|
||||
/* stop MLD processing */
|
||||
mld6_stop(netif);
|
||||
#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
|
||||
if (netif_is_up(netif)) {
|
||||
/* set netif down before removing (call callback function) */
|
||||
netif_set_down(netif);
|
||||
@@ -331,10 +365,10 @@ netif_set_ipaddr(struct netif *netif, ip_addr_t *ipaddr)
|
||||
pcb = tcp_active_pcbs;
|
||||
while (pcb != NULL) {
|
||||
/* PCB bound to current local interface address? */
|
||||
if (ip_addr_cmp(&(pcb->local_ip), &(netif->ip_addr))
|
||||
if (ip_addr_cmp(&(pcb->local_ip.ip4), &(netif->ip_addr))
|
||||
#if LWIP_AUTOIP
|
||||
/* connections to link-local addresses must persist (RFC3927 ch. 1.9) */
|
||||
&& !ip_addr_islinklocal(&(pcb->local_ip))
|
||||
&& !ip_addr_islinklocal(&(pcb->local_ip.ip4))
|
||||
#endif /* LWIP_AUTOIP */
|
||||
) {
|
||||
/* this connection must be aborted */
|
||||
@@ -348,11 +382,11 @@ netif_set_ipaddr(struct netif *netif, ip_addr_t *ipaddr)
|
||||
}
|
||||
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)))) {
|
||||
if ((!(ip_addr_isany(&(lpcb->local_ip.ip4)))) &&
|
||||
(ip_addr_cmp(&(lpcb->local_ip.ip4), &(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);
|
||||
ip_addr_set(&(lpcb->local_ip.ip4), ipaddr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -471,6 +505,16 @@ void netif_set_up(struct netif *netif)
|
||||
igmp_report_groups( netif);
|
||||
}
|
||||
#endif /* LWIP_IGMP */
|
||||
#if LWIP_IPV6 && LWIP_IPV6_MLD
|
||||
/* send mld memberships */
|
||||
mld6_report_groups( netif);
|
||||
#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
|
||||
|
||||
#if LWIP_IPV6_SEND_ROUTER_SOLICIT
|
||||
/* Send Router Solicitation messages. */
|
||||
netif->rs_count = LWIP_ND6_MAX_MULTICAST_SOLICIT;
|
||||
#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -541,6 +585,10 @@ void netif_set_link_up(struct netif *netif )
|
||||
igmp_report_groups( netif);
|
||||
}
|
||||
#endif /* LWIP_IGMP */
|
||||
#if LWIP_IPV6 && LWIP_IPV6_MLD
|
||||
/* send mld memberships */
|
||||
mld6_report_groups( netif);
|
||||
#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
|
||||
}
|
||||
NETIF_LINK_CALLBACK(netif);
|
||||
}
|
||||
@@ -750,3 +798,62 @@ netif_poll_all(void)
|
||||
}
|
||||
#endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */
|
||||
#endif /* ENABLE_LOOPBACK */
|
||||
|
||||
#if LWIP_IPV6
|
||||
s8_t
|
||||
netif_matches_ip6_addr(struct netif * netif, ip6_addr_t * ip6addr)
|
||||
{
|
||||
s8_t i;
|
||||
for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
|
||||
if (ip6_addr_cmp(netif_ip6_addr(netif, i), ip6addr)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void
|
||||
netif_create_ip6_linklocal_address(struct netif * netif, u8_t from_mac_48bit)
|
||||
{
|
||||
u8_t i, addr_index;
|
||||
|
||||
/* Link-local prefix. */
|
||||
netif->ip6_addr[0].addr[0] = PP_HTONL(0xfe800000ul);
|
||||
netif->ip6_addr[0].addr[1] = 0;
|
||||
|
||||
/* Generate interface ID. */
|
||||
if (from_mac_48bit) {
|
||||
/* Assume hwaddr is a 48-bit IEEE 802 MAC. Convert to EUI-64 address. Complement Group bit. */
|
||||
netif->ip6_addr[0].addr[2] = htonl((((u32_t)(netif->hwaddr[0] ^ 0x02)) << 24) |
|
||||
((u32_t)(netif->hwaddr[1]) << 16) |
|
||||
((u32_t)(netif->hwaddr[2]) << 8) |
|
||||
(0xff));
|
||||
netif->ip6_addr[0].addr[3] = htonl((0xfeul << 24) |
|
||||
((u32_t)(netif->hwaddr[3]) << 16) |
|
||||
((u32_t)(netif->hwaddr[4]) << 8) |
|
||||
(netif->hwaddr[5]));
|
||||
}
|
||||
else {
|
||||
/* Use hwaddr directly as interface ID. */
|
||||
netif->ip6_addr[0].addr[2] = 0;
|
||||
netif->ip6_addr[0].addr[3] = 0;
|
||||
|
||||
addr_index = 3;
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (i == 4) {
|
||||
addr_index--;
|
||||
}
|
||||
netif->ip6_addr[0].addr[addr_index] |= ((u32_t)(netif->hwaddr[netif->hwaddr_len - i - 1])) << (8 * (i & 0x03));
|
||||
}
|
||||
}
|
||||
|
||||
/* Set address state. */
|
||||
#if LWIP_IPV6_DUP_DETECT_ATTEMPTS
|
||||
/* Will perform duplicate address detection (DAD). */
|
||||
netif->ip6_addr_state[0] = IP6_ADDR_TENTATIVE;
|
||||
#else
|
||||
/* Consider address valid. */
|
||||
netif->ip6_addr_state[0] = IP6_ADDR_PREFERRED;
|
||||
#endif /* LWIP_IPV6_AUTOCONFIG */
|
||||
}
|
||||
#endif /* LWIP_IPV6 */
|
||||
|
||||
195
src/core/raw.c
195
src/core/raw.c
@@ -49,6 +49,8 @@
|
||||
#include "lwip/raw.h"
|
||||
#include "lwip/stats.h"
|
||||
#include "arch/perf.h"
|
||||
#include "lwip/ip6.h"
|
||||
#include "lwip/ip6_addr.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
@@ -79,11 +81,24 @@ raw_input(struct pbuf *p, struct netif *inp)
|
||||
struct ip_hdr *iphdr;
|
||||
s16_t proto;
|
||||
u8_t eaten = 0;
|
||||
#if LWIP_IPV6
|
||||
struct ip6_hdr *ip6hdr;
|
||||
#endif /* LWIP_IPV6 */
|
||||
|
||||
|
||||
LWIP_UNUSED_ARG(inp);
|
||||
|
||||
iphdr = (struct ip_hdr *)p->payload;
|
||||
proto = IPH_PROTO(iphdr);
|
||||
#if LWIP_IPV6
|
||||
if (IPH_V(iphdr) == 6) {
|
||||
ip6hdr = (struct ip6_hdr *)p->payload;
|
||||
proto = IP6H_NEXTH(ip6hdr);
|
||||
}
|
||||
else
|
||||
#endif /* LWIP_IPV6 */
|
||||
{
|
||||
proto = IPH_PROTO(iphdr);
|
||||
}
|
||||
|
||||
prev = NULL;
|
||||
pcb = raw_pcbs;
|
||||
@@ -91,17 +106,38 @@ raw_input(struct pbuf *p, struct netif *inp)
|
||||
/* this allows multiple pcbs to match against the packet by design */
|
||||
while ((eaten == 0) && (pcb != NULL)) {
|
||||
if ((pcb->protocol == proto) &&
|
||||
(ip_addr_isany(&pcb->local_ip) ||
|
||||
ip_addr_cmp(&(pcb->local_ip), ¤t_iphdr_dest))) {
|
||||
#if LWIP_IPV6
|
||||
((pcb->isipv6 &&
|
||||
(ip6_addr_isany(&pcb->local_ip.ip6) ||
|
||||
ip6_addr_cmp(&pcb->local_ip.ip6, ip6_current_dest_addr()))) ||
|
||||
(!pcb->isipv6 &&
|
||||
#else /* LWIP_IPV6 */
|
||||
((
|
||||
#endif /* LWIP_IPV6 */
|
||||
(ip_addr_isany(&pcb->local_ip.ip4) ||
|
||||
ip_addr_cmp(&(pcb->local_ip.ip4), ip_current_dest_addr()))))) {
|
||||
#if IP_SOF_BROADCAST_RECV
|
||||
/* broadcast filter? */
|
||||
if ((pcb->so_options & SOF_BROADCAST) || !ip_addr_isbroadcast(¤t_iphdr_dest, inp))
|
||||
if (((pcb->so_options & SOF_BROADCAST) || !ip_addr_isbroadcast(ip_current_dest_addr(), inp))
|
||||
#if LWIP_IPV6
|
||||
&& !pcb->isipv6
|
||||
#endif /* LWIP_IPV6 */
|
||||
)
|
||||
#endif /* IP_SOF_BROADCAST_RECV */
|
||||
{
|
||||
/* receive callback function available? */
|
||||
if (pcb->recv != NULL) {
|
||||
if (pcb->recv.ip4 != NULL) {
|
||||
/* the receive callback function did not eat the packet? */
|
||||
if (pcb->recv(pcb->recv_arg, pcb, p, ip_current_src_addr()) != 0) {
|
||||
#if LWIP_IPV6
|
||||
if (pcb->isipv6) {
|
||||
eaten = pcb->recv.ip6(pcb->recv_arg, pcb, p, ip6_current_src_addr());
|
||||
}
|
||||
else
|
||||
#endif /* LWIP_IPV6 */
|
||||
{
|
||||
eaten = pcb->recv.ip4(pcb->recv_arg, pcb, p, ip_current_src_addr());
|
||||
}
|
||||
if (eaten != 0) {
|
||||
/* receive function ate the packet */
|
||||
p = NULL;
|
||||
eaten = 1;
|
||||
@@ -141,7 +177,15 @@ raw_input(struct pbuf *p, struct netif *inp)
|
||||
err_t
|
||||
raw_bind(struct raw_pcb *pcb, ip_addr_t *ipaddr)
|
||||
{
|
||||
ip_addr_set(&pcb->local_ip, ipaddr);
|
||||
#if LWIP_IPV6
|
||||
if (pcb->isipv6) {
|
||||
ip6_addr_set(&pcb->local_ip.ip6, (ip6_addr_t *)ipaddr);
|
||||
}
|
||||
else
|
||||
#endif /* LWIP_IPV6 */
|
||||
{
|
||||
ip_addr_set(&pcb->local_ip.ip4, ipaddr);
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
@@ -161,7 +205,15 @@ raw_bind(struct raw_pcb *pcb, ip_addr_t *ipaddr)
|
||||
err_t
|
||||
raw_connect(struct raw_pcb *pcb, ip_addr_t *ipaddr)
|
||||
{
|
||||
ip_addr_set(&pcb->remote_ip, ipaddr);
|
||||
#if LWIP_IPV6
|
||||
if (pcb->isipv6) {
|
||||
ip6_addr_set(&pcb->remote_ip.ip6, (ip6_addr_t *)ipaddr);
|
||||
}
|
||||
else
|
||||
#endif /* LWIP_IPV6 */
|
||||
{
|
||||
ip_addr_set(&pcb->remote_ip.ip4, ipaddr);
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
@@ -183,7 +235,7 @@ void
|
||||
raw_recv(struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg)
|
||||
{
|
||||
/* remember recv() callback and user data */
|
||||
pcb->recv = recv;
|
||||
pcb->recv.ip4 = recv;
|
||||
pcb->recv_arg = recv_arg;
|
||||
}
|
||||
|
||||
@@ -209,6 +261,33 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr)
|
||||
|
||||
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_sendto\n"));
|
||||
|
||||
#if LWIP_IPV6
|
||||
/* TODO lots of v4 and v6 code duplication, optimize! Or will compiler optimize? */
|
||||
if (pcb->isipv6) {
|
||||
/* not enough space to add an IPv6 header to first pbuf in given p chain? */
|
||||
if (pbuf_header(p, IP6_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, -IP6_HLEN)) {
|
||||
LWIP_ASSERT("Can't restore header we just removed!", 0);
|
||||
return ERR_MEM;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif /* LWIP_IPV6 */
|
||||
/* 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 */
|
||||
@@ -233,6 +312,19 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr)
|
||||
}
|
||||
}
|
||||
|
||||
#if LWIP_IPV6
|
||||
if (pcb->isipv6) {
|
||||
if ((netif = ip6_route(&pcb->local_ip.ip6, (ip6_addr_t *)ipaddr)) == NULL) {
|
||||
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: No route to IPv6 destionation\n"));
|
||||
/* free any temporary header pbuf allocated by pbuf_header() */
|
||||
if (q != p) {
|
||||
pbuf_free(q);
|
||||
}
|
||||
return ERR_RTE;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif /* LWIP_IPV6 */
|
||||
if ((netif = ip_route(ipaddr)) == NULL) {
|
||||
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
|
||||
ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr)));
|
||||
@@ -244,29 +336,62 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr)
|
||||
}
|
||||
|
||||
#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);
|
||||
#if LWIP_IPV6
|
||||
if (!netif->isipv6) {
|
||||
#endif /* LWIP_IPV6 */
|
||||
/* 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;
|
||||
}
|
||||
return ERR_VAL;
|
||||
#if LWIP_IPV6
|
||||
}
|
||||
#endif /* LWIP_IPV6 */
|
||||
#endif /* IP_SOF_BROADCAST */
|
||||
|
||||
if (ip_addr_isany(&pcb->local_ip)) {
|
||||
#if LWIP_IPV6
|
||||
if (pcb->isipv6) {
|
||||
if (ip6_addr_isany(&pcb->local_ip.ip6)) {
|
||||
/* select an IPv6 address from the netif as source address */
|
||||
src_ip = (ip_addr_t *)ip6_select_source_address(netif, (ip6_addr_t *)ipaddr);
|
||||
if (src_ip == NULL) {
|
||||
/* No suitable source address was found. */
|
||||
if (q != p) {
|
||||
pbuf_free(q);
|
||||
}
|
||||
return ERR_RTE;
|
||||
}
|
||||
} else {
|
||||
/* use RAW PCB local IPv6 address as source address */
|
||||
src_ip = (ip_addr_t *)&(pcb->local_ip.ip6);
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif /* LWIP_IPV6 */
|
||||
if (ip_addr_isany(&pcb->local_ip.ip4)) {
|
||||
/* 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);
|
||||
src_ip = &(pcb->local_ip.ip4);
|
||||
}
|
||||
|
||||
#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_IPV6
|
||||
if (pcb->isipv6) {
|
||||
err = ip6_output_if(q, (ip6_addr_t *)src_ip, (ip6_addr_t *)ipaddr, pcb->ttl, pcb->tos, pcb->protocol, netif);
|
||||
}
|
||||
else
|
||||
#endif /* LWIP_IPV6 */
|
||||
{
|
||||
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*/
|
||||
@@ -289,7 +414,13 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr)
|
||||
err_t
|
||||
raw_send(struct raw_pcb *pcb, struct pbuf *p)
|
||||
{
|
||||
return raw_sendto(pcb, p, &pcb->remote_ip);
|
||||
#if LWIP_IPV6
|
||||
if (pcb->isipv6) {
|
||||
/* TODO is this necessary, or ar ip4 and ip6 pointers the same (think union)? */
|
||||
return raw_sendto(pcb, p, (ip_addr_t *)&pcb->remote_ip.ip6);
|
||||
}
|
||||
#endif /* LWIP_IPV6 */
|
||||
return raw_sendto(pcb, p, &pcb->remote_ip.ip4);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -351,4 +482,28 @@ raw_new(u8_t proto)
|
||||
return pcb;
|
||||
}
|
||||
|
||||
#if LWIP_IPV6
|
||||
/**
|
||||
* Create a RAW PCB for IPv6.
|
||||
*
|
||||
* @return The RAW PCB which was created. NULL if the PCB data structure
|
||||
* could not be allocated.
|
||||
*
|
||||
* @param proto the protocol number (next header) of the IPv6 packet payload
|
||||
* (e.g. IP6_NEXTH_ICMP6)
|
||||
*
|
||||
* @see raw_remove()
|
||||
*/
|
||||
struct raw_pcb *
|
||||
raw_new_ip6(u8_t proto)
|
||||
{
|
||||
struct raw_pcb *pcb;
|
||||
pcb = raw_new(proto);
|
||||
if (pcb != NULL) {
|
||||
pcb->isipv6 = 1;
|
||||
}
|
||||
return pcb;
|
||||
}
|
||||
#endif /* LWIP_IPV6 */
|
||||
|
||||
#endif /* LWIP_RAW */
|
||||
|
||||
240
src/core/tcp.c
240
src/core/tcp.c
@@ -52,6 +52,9 @@
|
||||
#include "lwip/tcp_impl.h"
|
||||
#include "lwip/debug.h"
|
||||
#include "lwip/stats.h"
|
||||
#include "lwip/ip6.h"
|
||||
#include "lwip/ip6_addr.h"
|
||||
#include "lwip/nd6.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
@@ -147,8 +150,17 @@ tcp_close_shutdown(struct tcp_pcb *pcb, u8_t rst_on_unacked_data)
|
||||
|
||||
/* don't call tcp_abort here: we must not deallocate the pcb since
|
||||
that might not be expected when calling tcp_close */
|
||||
tcp_rst(pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip,
|
||||
pcb->local_port, pcb->remote_port);
|
||||
#if LWIP_IPV6
|
||||
if (pcb->isipv6) {
|
||||
tcp_rst_ip6(pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip.ip6, &pcb->remote_ip.ip6,
|
||||
pcb->local_port, pcb->remote_port);
|
||||
}
|
||||
else
|
||||
#endif /* LWIP_IPV6 */
|
||||
{
|
||||
tcp_rst(pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip.ip4, &pcb->remote_ip.ip4,
|
||||
pcb->local_port, pcb->remote_port);
|
||||
}
|
||||
|
||||
tcp_pcb_purge(pcb);
|
||||
|
||||
@@ -318,8 +330,8 @@ void
|
||||
tcp_abandon(struct tcp_pcb *pcb, int reset)
|
||||
{
|
||||
u32_t seqno, ackno;
|
||||
u16_t remote_port, local_port;
|
||||
ip_addr_t remote_ip, local_ip;
|
||||
/*u16_t remote_port, local_port;
|
||||
ip_addr_t remote_ip, local_ip; */
|
||||
#if LWIP_CALLBACK_API
|
||||
tcp_err_fn errf;
|
||||
#endif /* LWIP_CALLBACK_API */
|
||||
@@ -337,10 +349,10 @@ tcp_abandon(struct tcp_pcb *pcb, int reset)
|
||||
} else {
|
||||
seqno = pcb->snd_nxt;
|
||||
ackno = pcb->rcv_nxt;
|
||||
ip_addr_copy(local_ip, pcb->local_ip);
|
||||
ip_addr_copy(remote_ip, pcb->remote_ip);
|
||||
/*ip_addr_copy(local_ip, pcb->local_ip.ip4);
|
||||
ip_addr_copy(remote_ip, pcb->remote_ip.ip4);
|
||||
local_port = pcb->local_port;
|
||||
remote_port = pcb->remote_port;
|
||||
remote_port = pcb->remote_port;*/
|
||||
#if LWIP_CALLBACK_API
|
||||
errf = pcb->errf;
|
||||
#endif /* LWIP_CALLBACK_API */
|
||||
@@ -357,12 +369,20 @@ tcp_abandon(struct tcp_pcb *pcb, int reset)
|
||||
tcp_segs_free(pcb->ooseq);
|
||||
}
|
||||
#endif /* TCP_QUEUE_OOSEQ */
|
||||
memp_free(MEMP_TCP_PCB, pcb);
|
||||
TCP_EVENT_ERR(errf, errf_arg, ERR_ABRT);
|
||||
if (reset) {
|
||||
LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_abandon: sending RST\n"));
|
||||
tcp_rst(seqno, ackno, &local_ip, &remote_ip, local_port, remote_port);
|
||||
#if LWIP_IPV6
|
||||
if (pcb->isipv6) {
|
||||
tcp_rst_ip6(seqno, ackno, &pcb->local_ip.ip6, &pcb->remote_ip.ip6, pcb->local_port, pcb->remote_port);
|
||||
}
|
||||
else
|
||||
#endif /* LWIP_IPV6 */
|
||||
{
|
||||
tcp_rst(seqno, ackno, &pcb->local_ip.ip4, &pcb->remote_ip.ip4, pcb->local_port, pcb->remote_port);
|
||||
}
|
||||
}
|
||||
memp_free(MEMP_TCP_PCB, pcb);
|
||||
TCP_EVENT_ERR(errf, errf_arg, ERR_ABRT);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -432,18 +452,40 @@ tcp_bind(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
|
||||
((cpcb->so_options & SOF_REUSEADDR) == 0))
|
||||
#endif /* SO_REUSE */
|
||||
{
|
||||
if (ip_addr_isany(&(cpcb->local_ip)) ||
|
||||
if (
|
||||
#if LWIP_IPV6
|
||||
!pcb->isipv6 &&
|
||||
!cpcb->isipv6 &&
|
||||
#endif /* LWIP_IPV6 */
|
||||
(ip_addr_isany(&(cpcb->local_ip.ip4)) ||
|
||||
ip_addr_isany(ipaddr) ||
|
||||
ip_addr_cmp(&(cpcb->local_ip), ipaddr)) {
|
||||
ip_addr_cmp(&(cpcb->local_ip.ip4), ipaddr))) {
|
||||
return ERR_USE;
|
||||
}
|
||||
#if LWIP_IPV6
|
||||
if (pcb->isipv6 &&
|
||||
cpcb->isipv6 &&
|
||||
(ip6_addr_isany(&(cpcb->local_ip.ip6)) ||
|
||||
ip6_addr_isany((ip6_addr_t *)ipaddr) ||
|
||||
ip6_addr_cmp(&(cpcb->local_ip.ip6), (ip6_addr_t *)ipaddr))) {
|
||||
return ERR_USE;
|
||||
}
|
||||
#endif /* LWIP_IPV6 */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if LWIP_IPV6
|
||||
if (pcb->isipv6) {
|
||||
if (!ip6_addr_isany((ip6_addr_t *)ipaddr)) {
|
||||
ip6_addr_set(&pcb->local_ip.ip6, (ip6_addr_t *)ipaddr);
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif /* LWIP_IPV6 */
|
||||
if (!ip_addr_isany(ipaddr)) {
|
||||
pcb->local_ip = *ipaddr;
|
||||
pcb->local_ip.ip4 = *ipaddr;
|
||||
}
|
||||
pcb->local_port = port;
|
||||
TCP_REG(&tcp_bound_pcbs, pcb);
|
||||
@@ -498,7 +540,15 @@ tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog)
|
||||
this port is only used once for every local IP. */
|
||||
for(lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
|
||||
if (lpcb->local_port == pcb->local_port) {
|
||||
if (ip_addr_cmp(&lpcb->local_ip, &pcb->local_ip)) {
|
||||
if ((
|
||||
#if LWIP_IPV6
|
||||
pcb->isipv6 &&
|
||||
lpcb->isipv6 &&
|
||||
ip6_addr_cmp(&lpcb->local_ip.ip6, &pcb->local_ip.ip6)) ||
|
||||
(!pcb->isipv6 &&
|
||||
!lpcb->isipv6 &&
|
||||
#endif /* LWIP_IPV6 */
|
||||
ip_addr_cmp(&lpcb->local_ip.ip4, &pcb->local_ip.ip4))) {
|
||||
/* this address/port is already used */
|
||||
return NULL;
|
||||
}
|
||||
@@ -518,7 +568,16 @@ tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog)
|
||||
lpcb->so_options |= SOF_ACCEPTCONN;
|
||||
lpcb->ttl = pcb->ttl;
|
||||
lpcb->tos = pcb->tos;
|
||||
ip_addr_copy(lpcb->local_ip, pcb->local_ip);
|
||||
#if LWIP_IPV6
|
||||
lpcb->isipv6 = pcb->isipv6;
|
||||
if (lpcb->isipv6) {
|
||||
ip6_addr_copy(lpcb->local_ip.ip6, pcb->local_ip.ip6);
|
||||
}
|
||||
else
|
||||
#endif /* LWIP_IPV6 */
|
||||
{
|
||||
ip_addr_copy(lpcb->local_ip.ip4, pcb->local_ip.ip4);
|
||||
}
|
||||
if (pcb->local_port != 0) {
|
||||
TCP_RMV(&tcp_bound_pcbs, pcb);
|
||||
}
|
||||
@@ -657,23 +716,55 @@ tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port,
|
||||
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("tcp_connect to port %"U16_F"\n", port));
|
||||
if (ipaddr != NULL) {
|
||||
pcb->remote_ip = *ipaddr;
|
||||
#if LWIP_IPV6
|
||||
if (pcb->isipv6) {
|
||||
ip6_addr_set(&pcb->remote_ip.ip6, (ip6_addr_t *)ipaddr);
|
||||
}
|
||||
else
|
||||
#endif /* LWIP_IPV6 */
|
||||
{
|
||||
pcb->remote_ip.ip4 = *ipaddr;
|
||||
}
|
||||
} else {
|
||||
return ERR_VAL;
|
||||
}
|
||||
pcb->remote_port = port;
|
||||
|
||||
/* check if we have a route to the remote host */
|
||||
if (ip_addr_isany(&(pcb->local_ip))) {
|
||||
#if LWIP_IPV6
|
||||
if (pcb->isipv6) {
|
||||
if (ip6_addr_isany(&(pcb->local_ip.ip6))) {
|
||||
/* no local IPv6 address set, yet. */
|
||||
ip6_addr_t * local_addr6;
|
||||
struct netif *netif = ip6_route(&(pcb->remote_ip.ip6), &(pcb->remote_ip.ip6));
|
||||
if (netif == NULL) {
|
||||
/* Don't even try to send a SYN packet if we have no route
|
||||
since that will fail. */
|
||||
return ERR_RTE;
|
||||
}
|
||||
/* Select and IPv6 address from the netif. */
|
||||
local_addr6 = ip6_select_source_address(netif, &(pcb->remote_ip.ip6));
|
||||
if (local_addr6 == NULL) {
|
||||
/* Don't even try to send a SYN packet if we have no suitable
|
||||
source address. */
|
||||
return ERR_RTE;
|
||||
}
|
||||
|
||||
ip6_addr_set(&pcb->local_ip.ip6, local_addr6);
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif /* LWIP_IPV6 */
|
||||
if (ip_addr_isany(&(pcb->local_ip.ip4))) {
|
||||
/* no local IP address set, yet. */
|
||||
struct netif *netif = ip_route(&(pcb->remote_ip));
|
||||
struct netif *netif = ip_route(&(pcb->remote_ip.ip4));
|
||||
if (netif == NULL) {
|
||||
/* Don't even try to send a SYN packet if we have no route
|
||||
since that will fail. */
|
||||
return ERR_RTE;
|
||||
}
|
||||
/* Use the netif's IP address as local address. */
|
||||
ip_addr_copy(pcb->local_ip, netif->ip_addr);
|
||||
ip_addr_copy(pcb->local_ip.ip4, netif->ip_addr);
|
||||
}
|
||||
|
||||
old_local_port = pcb->local_port;
|
||||
@@ -691,8 +782,18 @@ tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port,
|
||||
for(cpcb = *tcp_pcb_lists[i]; cpcb != NULL; cpcb = cpcb->next) {
|
||||
if ((cpcb->local_port == pcb->local_port) &&
|
||||
(cpcb->remote_port == port) &&
|
||||
ip_addr_cmp(&cpcb->local_ip, &pcb->local_ip) &&
|
||||
ip_addr_cmp(&cpcb->remote_ip, ipaddr)) {
|
||||
#if LWIP_IPV6
|
||||
((cpcb->isipv6 &&
|
||||
pcb->isipv6 &&
|
||||
ip6_addr_cmp(&cpcb->local_ip.ip6, &pcb->local_ip.ip6) &&
|
||||
ip6_addr_cmp(&cpcb->remote_ip.ip6, (ip6_addr_t *)ipaddr)) ||
|
||||
(!cpcb->isipv6 &&
|
||||
!pcb->isipv6 &&
|
||||
#else /* LWIP_IPV6 */
|
||||
((
|
||||
#endif /* LWIP_IPV6 */
|
||||
ip_addr_cmp(&cpcb->local_ip.ip4, &pcb->local_ip.ip4) &&
|
||||
ip_addr_cmp(&cpcb->remote_ip.ip4, ipaddr)))) {
|
||||
/* linux returns EISCONN here, but ERR_USE should be OK for us */
|
||||
return ERR_USE;
|
||||
}
|
||||
@@ -713,7 +814,15 @@ tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port,
|
||||
The send MSS is updated when an MSS option is received. */
|
||||
pcb->mss = (TCP_MSS > 536) ? 536 : TCP_MSS;
|
||||
#if TCP_CALCULATE_EFF_SEND_MSS
|
||||
pcb->mss = tcp_eff_send_mss(pcb->mss, ipaddr);
|
||||
#if LWIP_IPV6
|
||||
if (pcb->isipv6) {
|
||||
pcb->mss = tcp_eff_send_mss_ip6(pcb->mss, &pcb->local_ip.ip6, &pcb->remote_ip.ip6);
|
||||
}
|
||||
else
|
||||
#endif /* LWIP_IPV6 */
|
||||
{
|
||||
pcb->mss = tcp_eff_send_mss(pcb->mss, &pcb->remote_ip.ip4);
|
||||
}
|
||||
#endif /* TCP_CALCULATE_EFF_SEND_MSS */
|
||||
pcb->cwnd = 1;
|
||||
pcb->ssthresh = pcb->mss * 10;
|
||||
@@ -852,9 +961,13 @@ tcp_slowtmr(void)
|
||||
(pcb->keep_idle + TCP_MAXIDLE) / TCP_SLOW_INTERVAL)
|
||||
#endif /* LWIP_TCP_KEEPALIVE */
|
||||
{
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: KEEPALIVE timeout. Aborting connection to %"U16_F".%"U16_F".%"U16_F".%"U16_F".\n",
|
||||
ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip),
|
||||
ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip)));
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: KEEPALIVE timeout. Aborting connection to "));
|
||||
if (!pcb->isipv6) {
|
||||
ip_addr_debug_print(TCP_DEBUG, &pcb->remote_ip.ip4);
|
||||
} else {
|
||||
ip6_addr_debug_print(TCP_DEBUG, &pcb->remote_ip.ip6);
|
||||
}
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("\n"));
|
||||
|
||||
++pcb_remove;
|
||||
++pcb_reset;
|
||||
@@ -919,8 +1032,17 @@ tcp_slowtmr(void)
|
||||
|
||||
TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_ABRT);
|
||||
if (pcb_reset) {
|
||||
tcp_rst(pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip,
|
||||
pcb->local_port, pcb->remote_port);
|
||||
#if LWIP_IPV6
|
||||
if (pcb->isipv6) {
|
||||
tcp_rst_ip6(pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip.ip6, &pcb->remote_ip.ip6,
|
||||
pcb->local_port, pcb->remote_port);
|
||||
}
|
||||
else
|
||||
#endif /* LWIP_IPV6 */
|
||||
{
|
||||
tcp_rst(pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip.ip4, &pcb->remote_ip.ip4,
|
||||
pcb->local_port, pcb->remote_port);
|
||||
}
|
||||
}
|
||||
|
||||
pcb2 = pcb;
|
||||
@@ -1266,6 +1388,27 @@ tcp_new(void)
|
||||
return tcp_alloc(TCP_PRIO_NORMAL);
|
||||
}
|
||||
|
||||
#if LWIP_IPV6
|
||||
/**
|
||||
* Creates a new TCP-over-IPv6 protocol control block but doesn't
|
||||
* place it on any of the TCP PCB lists.
|
||||
* The pcb is not put on any list until binding using tcp_bind().
|
||||
*
|
||||
* @return a new tcp_pcb that initially is in state CLOSED
|
||||
*/
|
||||
struct tcp_pcb *
|
||||
tcp_new_ip6(void)
|
||||
{
|
||||
struct tcp_pcb * pcb;
|
||||
pcb = tcp_alloc(TCP_PRIO_NORMAL);
|
||||
/* could allocate TCP PCB? */
|
||||
if (pcb != NULL) {
|
||||
pcb->isipv6 = 1;
|
||||
}
|
||||
return pcb;
|
||||
}
|
||||
#endif /* LWIP_IPV6 */
|
||||
|
||||
/**
|
||||
* Used to specify the argument that should be passed callback
|
||||
* functions.
|
||||
@@ -1376,8 +1519,18 @@ tcp_pcb_purge(struct tcp_pcb *pcb)
|
||||
tcp_listen_pcbs.listen_pcbs != NULL);
|
||||
for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
|
||||
if ((lpcb->local_port == pcb->local_port) &&
|
||||
(ip_addr_isany(&lpcb->local_ip) ||
|
||||
ip_addr_cmp(&pcb->local_ip, &lpcb->local_ip))) {
|
||||
#if LWIP_IPV6
|
||||
((lpcb->isipv6 &&
|
||||
pcb->isipv6 &&
|
||||
(ip6_addr_isany(&lpcb->local_ip.ip6) ||
|
||||
ip6_addr_cmp(&pcb->local_ip.ip6, &lpcb->local_ip.ip6))) ||
|
||||
(!lpcb->isipv6 &&
|
||||
!pcb->isipv6 &&
|
||||
#else /* LWIP_IPV6 */
|
||||
((
|
||||
#endif /* LWIP_IPV6 */
|
||||
(ip_addr_isany(&lpcb->local_ip.ip4) ||
|
||||
ip_addr_cmp(&pcb->local_ip.ip4, &lpcb->local_ip.ip4))))) {
|
||||
/* port and address of the listen pcb match the timed-out pcb */
|
||||
LWIP_ASSERT("tcp_pcb_purge: listen pcb does not have accepts pending",
|
||||
lpcb->accepts_pending > 0);
|
||||
@@ -1492,6 +1645,35 @@ tcp_eff_send_mss(u16_t sendmss, ip_addr_t *addr)
|
||||
}
|
||||
return sendmss;
|
||||
}
|
||||
|
||||
#if LWIP_IPV6
|
||||
/**
|
||||
* Calculates the effective send mss that can be used for a specific IPv6
|
||||
* address by using ip6_route to determine the netif used to send to the
|
||||
* address and calculating the minimum of TCP_MSS and that netif's mtu (if set).
|
||||
*/
|
||||
u16_t
|
||||
tcp_eff_send_mss_ip6(u16_t sendmss, ip6_addr_t *src, ip6_addr_t *dest)
|
||||
{
|
||||
u16_t mss_s;
|
||||
struct netif *outif;
|
||||
s16_t mtu;
|
||||
|
||||
/* First look in destination cache, to see if there is a PAth MTU. */
|
||||
outif = ip6_route(src, dest);
|
||||
mtu = nd6_get_destination_mtu(dest, outif);
|
||||
|
||||
if (mtu != 0) {
|
||||
mss_s = mtu - IP6_HLEN - TCP_HLEN;
|
||||
/* RFC 1122, chap 4.2.2.6:
|
||||
* Eff.snd.MSS = min(SendMSS+20, MMS_S) - TCPhdrsize - IPoptionsize
|
||||
* We correct for TCP options in tcp_write().
|
||||
*/
|
||||
sendmss = LWIP_MIN(sendmss, mss_s);
|
||||
}
|
||||
return sendmss;
|
||||
}
|
||||
#endif /* LWIP_IPV6 */
|
||||
#endif /* TCP_CALCULATE_EFF_SEND_MSS */
|
||||
|
||||
const char*
|
||||
|
||||
@@ -55,13 +55,18 @@
|
||||
#include "lwip/stats.h"
|
||||
#include "lwip/snmp.h"
|
||||
#include "arch/perf.h"
|
||||
#include "lwip/ip6.h"
|
||||
#include "lwip/ip6_addr.h"
|
||||
#include "lwip/ip6_chksum.h"
|
||||
#if LWIP_ND6_TCP_REACHABILITY_HINTS
|
||||
#include "lwip/nd6.h"
|
||||
#endif /* LWIP_ND6_TCP_REACHABILITY_HINTS */
|
||||
|
||||
/* These variables are global to all functions involved in the input
|
||||
processing of TCP segments. They are set by the tcp_input()
|
||||
function. */
|
||||
static struct tcp_seg inseg;
|
||||
static struct tcp_hdr *tcphdr;
|
||||
static struct ip_hdr *iphdr;
|
||||
static u32_t seqno, ackno;
|
||||
static u8_t flags;
|
||||
static u16_t tcplen;
|
||||
@@ -85,7 +90,7 @@ static err_t tcp_timewait_input(struct tcp_pcb *pcb);
|
||||
* the TCP finite state machine. This function is called by the IP layer (in
|
||||
* ip_input()).
|
||||
*
|
||||
* @param p received TCP segment to process (p->payload pointing to the IP header)
|
||||
* @param p received TCP segment to process (p->payload pointing to the TCP header)
|
||||
* @param inp network interface on which this segment was received
|
||||
*/
|
||||
void
|
||||
@@ -105,15 +110,14 @@ tcp_input(struct pbuf *p, struct netif *inp)
|
||||
TCP_STATS_INC(tcp.recv);
|
||||
snmp_inc_tcpinsegs();
|
||||
|
||||
iphdr = (struct ip_hdr *)p->payload;
|
||||
tcphdr = (struct tcp_hdr *)((u8_t *)p->payload + IPH_HL(iphdr) * 4);
|
||||
tcphdr = (struct tcp_hdr *)p->payload;
|
||||
|
||||
#if TCP_INPUT_DEBUG
|
||||
tcp_debug_print(tcphdr);
|
||||
#endif
|
||||
|
||||
/* remove header from payload */
|
||||
if (pbuf_header(p, -((s16_t)(IPH_HL(iphdr) * 4))) || (p->tot_len < sizeof(struct tcp_hdr))) {
|
||||
/* Check that TCP header fits in payload */
|
||||
if (p->len < sizeof(struct tcp_hdr)) {
|
||||
/* drop short packets */
|
||||
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet (%"U16_F" bytes) discarded\n", p->tot_len));
|
||||
TCP_STATS_INC(tcp.lenerr);
|
||||
@@ -124,8 +128,14 @@ tcp_input(struct pbuf *p, struct netif *inp)
|
||||
}
|
||||
|
||||
/* Don't even process incoming broadcasts/multicasts. */
|
||||
if (ip_addr_isbroadcast(¤t_iphdr_dest, inp) ||
|
||||
ip_addr_ismulticast(¤t_iphdr_dest)) {
|
||||
if ((
|
||||
#if LWIP_IPV6
|
||||
(ip6_current_header() != NULL) &&
|
||||
ip6_addr_ismulticast(ip6_current_dest_addr())) ||
|
||||
((ip_current_header() != NULL) &&
|
||||
#endif /* LWIP_IPV6 */
|
||||
(ip_addr_isbroadcast(ip_current_dest_addr(), inp) ||
|
||||
ip_addr_ismulticast(ip_current_dest_addr())))) {
|
||||
TCP_STATS_INC(tcp.proterr);
|
||||
TCP_STATS_INC(tcp.drop);
|
||||
snmp_inc_tcpinerrs();
|
||||
@@ -134,6 +144,25 @@ tcp_input(struct pbuf *p, struct netif *inp)
|
||||
}
|
||||
|
||||
#if CHECKSUM_CHECK_TCP
|
||||
#if LWIP_IPV6
|
||||
if (ip6_current_header() != NULL) {
|
||||
if (ip6_chksum_pseudo(p, ip6_current_src_addr(), ip6_current_dest_addr(),
|
||||
IP6_NEXTH_TCP, p->tot_len) != 0) {
|
||||
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packet discarded due to failing checksum 0x%04"X16_F"\n",
|
||||
ip6_chksum_pseudo(p, ip6_current_src_addr(), ip6_current_dest_addr(),
|
||||
IP6_NEXTH_TCP, p->tot_len)));
|
||||
#if TCP_DEBUG
|
||||
tcp_debug_print(tcphdr);
|
||||
#endif /* TCP_DEBUG */
|
||||
TCP_STATS_INC(tcp.chkerr);
|
||||
TCP_STATS_INC(tcp.drop);
|
||||
snmp_inc_tcpinerrs();
|
||||
pbuf_free(p);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif /* LWIP_IPV6 */
|
||||
/* Verify TCP checksum. */
|
||||
if (inet_chksum_pseudo(p, ip_current_src_addr(), ip_current_dest_addr(),
|
||||
IP_PROTO_TCP, p->tot_len) != 0) {
|
||||
@@ -149,7 +178,7 @@ tcp_input(struct pbuf *p, struct netif *inp)
|
||||
pbuf_free(p);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#endif /* CHECKSUM_CHECK_TCP */
|
||||
|
||||
/* Move the payload pointer in the pbuf so that it points to the
|
||||
TCP data instead of the TCP header. */
|
||||
@@ -184,9 +213,18 @@ tcp_input(struct pbuf *p, struct netif *inp)
|
||||
LWIP_ASSERT("tcp_input: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT);
|
||||
LWIP_ASSERT("tcp_input: active pcb->state != LISTEN", pcb->state != LISTEN);
|
||||
if (pcb->remote_port == tcphdr->src &&
|
||||
pcb->local_port == tcphdr->dest &&
|
||||
ip_addr_cmp(&(pcb->remote_ip), ¤t_iphdr_src) &&
|
||||
ip_addr_cmp(&(pcb->local_ip), ¤t_iphdr_dest)) {
|
||||
pcb->local_port == tcphdr->dest &&
|
||||
((
|
||||
#if LWIP_IPV6
|
||||
pcb->isipv6 &&
|
||||
(ip6_current_header() != NULL) &&
|
||||
ip6_addr_cmp(&(pcb->remote_ip.ip6), ip6_current_src_addr()) &&
|
||||
ip6_addr_cmp(&(pcb->local_ip.ip6), ip6_current_dest_addr())) ||
|
||||
(!pcb->isipv6 &&
|
||||
(ip_current_header() != NULL) &&
|
||||
#endif /* LWIP_IPV6 */
|
||||
ip_addr_cmp(&(pcb->remote_ip.ip4), ip_current_src_addr()) &&
|
||||
ip_addr_cmp(&(pcb->local_ip.ip4), ip_current_dest_addr())))) {
|
||||
|
||||
/* Move this PCB to the front of the list so that subsequent
|
||||
lookups will be faster (we exploit locality in TCP segment
|
||||
@@ -209,9 +247,18 @@ tcp_input(struct pbuf *p, struct netif *inp)
|
||||
for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {
|
||||
LWIP_ASSERT("tcp_input: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);
|
||||
if (pcb->remote_port == tcphdr->src &&
|
||||
pcb->local_port == tcphdr->dest &&
|
||||
ip_addr_cmp(&(pcb->remote_ip), ¤t_iphdr_src) &&
|
||||
ip_addr_cmp(&(pcb->local_ip), ¤t_iphdr_dest)) {
|
||||
pcb->local_port == tcphdr->dest &&
|
||||
((
|
||||
#if LWIP_IPV6
|
||||
pcb->isipv6 &&
|
||||
(ip6_current_header() != NULL) &&
|
||||
ip6_addr_cmp(&(pcb->remote_ip.ip6), ip6_current_src_addr()) &&
|
||||
ip6_addr_cmp(&(pcb->local_ip.ip6), ip6_current_dest_addr())) ||
|
||||
(!pcb->isipv6 &&
|
||||
(ip_current_header() != NULL) &&
|
||||
#endif /* LWIP_IPV6 */
|
||||
ip_addr_cmp(&(pcb->remote_ip.ip4), ip_current_src_addr()) &&
|
||||
ip_addr_cmp(&(pcb->local_ip.ip4), ip_current_dest_addr())))) {
|
||||
/* We don't really care enough to move this PCB to the front
|
||||
of the list since we are not very likely to receive that
|
||||
many segments for connections in TIME-WAIT. */
|
||||
@@ -228,19 +275,50 @@ tcp_input(struct pbuf *p, struct netif *inp)
|
||||
for(lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
|
||||
if (lpcb->local_port == tcphdr->dest) {
|
||||
#if SO_REUSE
|
||||
if (ip_addr_cmp(&(lpcb->local_ip), ¤t_iphdr_dest)) {
|
||||
/* found an exact match */
|
||||
break;
|
||||
} else if(ip_addr_isany(&(lpcb->local_ip))) {
|
||||
/* found an ANY-match */
|
||||
lpcb_any = lpcb;
|
||||
lpcb_prev = prev;
|
||||
#if LWIP_IPV6
|
||||
if (lpcb->isipv6 &&
|
||||
(ip6_current_header() != NULL)) {
|
||||
if (ip6_addr_cmp(&(lpcb->local_ip.ip6), ip6_current_dest_addr())) {
|
||||
/* found an exact match */
|
||||
break;
|
||||
} else if(ip6_addr_isany(&(lpcb->local_ip.ip6))) {
|
||||
/* found an ANY-match */
|
||||
lpcb_any = lpcb;
|
||||
lpcb_prev = prev;
|
||||
}
|
||||
}
|
||||
else if (!lpcb->isipv6 &&
|
||||
(ip_current_header() != NULL))
|
||||
#endif /* LWIP_IPV6 */
|
||||
{
|
||||
if (ip_addr_cmp(&(lpcb->local_ip.ip4), ip_current_dest_addr())) {
|
||||
/* found an exact match */
|
||||
break;
|
||||
} else if(ip_addr_isany(&(lpcb->local_ip.ip4))) {
|
||||
/* found an ANY-match */
|
||||
lpcb_any = lpcb;
|
||||
lpcb_prev = prev;
|
||||
}
|
||||
}
|
||||
#else /* SO_REUSE */
|
||||
if (ip_addr_cmp(&(lpcb->local_ip), ¤t_iphdr_dest) ||
|
||||
ip_addr_isany(&(lpcb->local_ip))) {
|
||||
/* found a match */
|
||||
break;
|
||||
#if LWIP_IPV6
|
||||
if (lpcb->isipv6 &&
|
||||
(ip6_current_header() != NULL)) {
|
||||
if (ip6_addr_cmp(&(lpcb->local_ip.ip6), ip6_current_dest_addr()) ||
|
||||
ip6_addr_isany(&(lpcb->local_ip.ip6))) {
|
||||
/* found an exact match */
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (!lpcb->isipv6 &&
|
||||
(ip_current_header() != NULL))
|
||||
#endif /* LWIP_IPV6 */
|
||||
{
|
||||
if (ip_addr_cmp(&(lpcb->local_ip.ip4), ip_current_dest_addr()) ||
|
||||
ip_addr_isany(&(lpcb->local_ip.ip4))) {
|
||||
/* found a match */
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif /* SO_REUSE */
|
||||
}
|
||||
@@ -415,9 +493,19 @@ aborted:
|
||||
if (!(TCPH_FLAGS(tcphdr) & TCP_RST)) {
|
||||
TCP_STATS_INC(tcp.proterr);
|
||||
TCP_STATS_INC(tcp.drop);
|
||||
tcp_rst(ackno, seqno + tcplen,
|
||||
ip_current_dest_addr(), ip_current_src_addr(),
|
||||
tcphdr->dest, tcphdr->src);
|
||||
#if LWIP_IPV6
|
||||
if (ip6_current_header() != NULL) {
|
||||
tcp_rst_ip6(ackno, seqno + tcplen,
|
||||
ip6_current_dest_addr(), ip6_current_src_addr(),
|
||||
tcphdr->dest, tcphdr->src);
|
||||
}
|
||||
else
|
||||
#endif /* LWIP_IPV6 */
|
||||
{
|
||||
tcp_rst(ackno, seqno + tcplen,
|
||||
ip_current_dest_addr(), ip_current_src_addr(),
|
||||
tcphdr->dest, tcphdr->src);
|
||||
}
|
||||
}
|
||||
pbuf_free(p);
|
||||
}
|
||||
@@ -450,9 +538,19 @@ tcp_listen_input(struct tcp_pcb_listen *pcb)
|
||||
/* For incoming segments with the ACK flag set, respond with a
|
||||
RST. */
|
||||
LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_listen_input: ACK in LISTEN, sending reset\n"));
|
||||
tcp_rst(ackno + 1, seqno + tcplen,
|
||||
ip_current_dest_addr(), ip_current_src_addr(),
|
||||
tcphdr->dest, tcphdr->src);
|
||||
#if LWIP_IPV6
|
||||
if (ip6_current_header() != NULL) {
|
||||
tcp_rst_ip6(ackno + 1, seqno + tcplen,
|
||||
ip6_current_dest_addr(), ip6_current_src_addr(),
|
||||
tcphdr->dest, tcphdr->src);
|
||||
}
|
||||
else
|
||||
#endif /* LWIP_IPV6 */
|
||||
{
|
||||
tcp_rst(ackno + 1, seqno + tcplen,
|
||||
ip_current_dest_addr(), ip_current_src_addr(),
|
||||
tcphdr->dest, tcphdr->src);
|
||||
}
|
||||
} else if (flags & TCP_SYN) {
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("TCP connection request %"U16_F" -> %"U16_F".\n", tcphdr->src, tcphdr->dest));
|
||||
#if TCP_LISTEN_BACKLOG
|
||||
@@ -474,9 +572,19 @@ tcp_listen_input(struct tcp_pcb_listen *pcb)
|
||||
pcb->accepts_pending++;
|
||||
#endif /* TCP_LISTEN_BACKLOG */
|
||||
/* Set up the new PCB. */
|
||||
ip_addr_copy(npcb->local_ip, current_iphdr_dest);
|
||||
#if LWIP_IPV6
|
||||
npcb->isipv6 = pcb->isipv6;
|
||||
if (npcb->isipv6) {
|
||||
ip6_addr_copy(npcb->local_ip.ip6, *ip6_current_dest_addr());
|
||||
ip6_addr_copy(npcb->remote_ip.ip6, *ip6_current_src_addr());
|
||||
}
|
||||
else
|
||||
#endif /* LWIP_IPV6 */
|
||||
{
|
||||
ip_addr_copy(npcb->local_ip.ip4, *ip_current_dest_addr());
|
||||
ip_addr_copy(npcb->remote_ip.ip4, *ip_current_src_addr());
|
||||
}
|
||||
npcb->local_port = pcb->local_port;
|
||||
ip_addr_copy(npcb->remote_ip, current_iphdr_src);
|
||||
npcb->remote_port = tcphdr->src;
|
||||
npcb->state = SYN_RCVD;
|
||||
npcb->rcv_nxt = seqno + 1;
|
||||
@@ -497,7 +605,15 @@ tcp_listen_input(struct tcp_pcb_listen *pcb)
|
||||
/* Parse any options in the SYN. */
|
||||
tcp_parseopt(npcb);
|
||||
#if TCP_CALCULATE_EFF_SEND_MSS
|
||||
npcb->mss = tcp_eff_send_mss(npcb->mss, &(npcb->remote_ip));
|
||||
#if LWIP_IPV6
|
||||
if (npcb->isipv6) {
|
||||
npcb->mss = tcp_eff_send_mss_ip6(npcb->mss, &(npcb->local_ip.ip6), &(npcb->remote_ip.ip6));
|
||||
}
|
||||
else
|
||||
#endif /* LWIP_IPV6 */
|
||||
{
|
||||
npcb->mss = tcp_eff_send_mss(npcb->mss, &(npcb->remote_ip.ip4));
|
||||
}
|
||||
#endif /* TCP_CALCULATE_EFF_SEND_MSS */
|
||||
|
||||
snmp_inc_tcppassiveopens();
|
||||
@@ -539,8 +655,17 @@ tcp_timewait_input(struct tcp_pcb *pcb)
|
||||
should be sent in reply */
|
||||
if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt+pcb->rcv_wnd)) {
|
||||
/* If the SYN is in the window it is an error, send a reset */
|
||||
tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(),
|
||||
tcphdr->dest, tcphdr->src);
|
||||
#if LWIP_IPV6
|
||||
if (ip6_current_header() != NULL) {
|
||||
tcp_rst_ip6(ackno, seqno + tcplen, ip6_current_dest_addr(), ip6_current_src_addr(),
|
||||
tcphdr->dest, tcphdr->src);
|
||||
}
|
||||
else
|
||||
#endif /* LWIP_IPV6 */
|
||||
{
|
||||
tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(),
|
||||
tcphdr->dest, tcphdr->src);
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
} else if (flags & TCP_FIN) {
|
||||
@@ -637,7 +762,15 @@ tcp_process(struct tcp_pcb *pcb)
|
||||
pcb->state = ESTABLISHED;
|
||||
|
||||
#if TCP_CALCULATE_EFF_SEND_MSS
|
||||
pcb->mss = tcp_eff_send_mss(pcb->mss, &(pcb->remote_ip));
|
||||
#if LWIP_IPV6
|
||||
if (pcb->isipv6) {
|
||||
pcb->mss = tcp_eff_send_mss_ip6(pcb->mss, &(pcb->local_ip.ip6), &(pcb->remote_ip.ip6));
|
||||
}
|
||||
else
|
||||
#endif /* LWIP_IPV6 */
|
||||
{
|
||||
pcb->mss = tcp_eff_send_mss(pcb->mss, &(pcb->remote_ip.ip4));
|
||||
}
|
||||
#endif /* TCP_CALCULATE_EFF_SEND_MSS */
|
||||
|
||||
/* Set ssthresh again after changing pcb->mss (already set in tcp_connect
|
||||
@@ -673,8 +806,17 @@ tcp_process(struct tcp_pcb *pcb)
|
||||
/* received ACK? possibly a half-open connection */
|
||||
else if (flags & TCP_ACK) {
|
||||
/* send a RST to bring the other side in a non-synchronized state. */
|
||||
tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(),
|
||||
tcphdr->dest, tcphdr->src);
|
||||
#if LWIP_IPV6
|
||||
if (ip6_current_header() != NULL) {
|
||||
tcp_rst_ip6(ackno, seqno + tcplen, ip6_current_dest_addr(), ip6_current_src_addr(),
|
||||
tcphdr->dest, tcphdr->src);
|
||||
}
|
||||
else
|
||||
#endif /* LWIP_IPV6 */
|
||||
{
|
||||
tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(),
|
||||
tcphdr->dest, tcphdr->src);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SYN_RCVD:
|
||||
@@ -716,8 +858,17 @@ tcp_process(struct tcp_pcb *pcb)
|
||||
}
|
||||
} else {
|
||||
/* incorrect ACK number, send RST */
|
||||
tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(),
|
||||
tcphdr->dest, tcphdr->src);
|
||||
#if LWIP_IPV6
|
||||
if (ip6_current_header() != NULL) {
|
||||
tcp_rst_ip6(ackno, seqno + tcplen, ip6_current_dest_addr(), ip6_current_src_addr(),
|
||||
tcphdr->dest, tcphdr->src);
|
||||
}
|
||||
else
|
||||
#endif /* LWIP_IPV6 */
|
||||
{
|
||||
tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(),
|
||||
tcphdr->dest, tcphdr->src);
|
||||
}
|
||||
}
|
||||
} else if ((flags & TCP_SYN) && (seqno == pcb->rcv_nxt - 1)) {
|
||||
/* Looks like another copy of the SYN - retransmit our SYN-ACK */
|
||||
@@ -1019,6 +1170,13 @@ tcp_receive(struct tcp_pcb *pcb)
|
||||
pcb->rtime = 0;
|
||||
|
||||
pcb->polltmr = 0;
|
||||
|
||||
#if LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS
|
||||
if (pcb->isipv6) {
|
||||
/* Inform neighbor reachability of forward progress. */
|
||||
nd6_reachability_hint(ip6_current_src_addr());
|
||||
}
|
||||
#endif /* LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS*/
|
||||
} else {
|
||||
/* Fix bug bug #21582: out of sequence ACK, didn't really ack anything */
|
||||
pcb->acked = 0;
|
||||
@@ -1336,6 +1494,13 @@ tcp_receive(struct tcp_pcb *pcb)
|
||||
/* Acknowledge the segment(s). */
|
||||
tcp_ack(pcb);
|
||||
|
||||
#if LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS
|
||||
if (pcb->isipv6) {
|
||||
/* Inform neighbor reachability of forward progress. */
|
||||
nd6_reachability_hint(ip6_current_src_addr());
|
||||
}
|
||||
#endif /* LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS*/
|
||||
|
||||
} else {
|
||||
/* We get here if the incoming segment is out-of-sequence. */
|
||||
tcp_send_empty_ack(pcb);
|
||||
|
||||
@@ -52,6 +52,9 @@
|
||||
#include "lwip/inet_chksum.h"
|
||||
#include "lwip/stats.h"
|
||||
#include "lwip/snmp.h"
|
||||
#include "lwip/ip6.h"
|
||||
#include "lwip/ip6_addr.h"
|
||||
#include "lwip/ip6_chksum.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
@@ -865,17 +868,34 @@ tcp_send_empty_ack(struct tcp_pcb *pcb)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if LWIP_IPV6
|
||||
if (pcb->isipv6) {
|
||||
/* Chksum is mandatory over IPv6 */
|
||||
tcphdr->chksum = ip6_chksum_pseudo(p, &(pcb->local_ip.ip6), &(pcb->remote_ip.ip6),
|
||||
IP6_NEXTH_TCP, p->tot_len);
|
||||
#if LWIP_NETIF_HWADDRHINT
|
||||
ip6_output_hinted(p, &(pcb->local_ip.ip6), &(pcb->remote_ip.ip6), pcb->ttl, pcb->tos,
|
||||
IP6_NEXTH_TCP, &(pcb->addr_hint));
|
||||
#else /* LWIP_NETIF_HWADDRHINT*/
|
||||
ip6_output(p, &(pcb->local_ip.ip6), &(pcb->remote_ip.ip6), pcb->ttl, pcb->tos,
|
||||
IP6_NEXTH_TCP);
|
||||
#endif /* LWIP_NETIF_HWADDRHINT*/
|
||||
}
|
||||
else
|
||||
#endif /* LWIP_IPV6 */
|
||||
{
|
||||
#if CHECKSUM_GEN_TCP
|
||||
tcphdr->chksum = inet_chksum_pseudo(p, &(pcb->local_ip), &(pcb->remote_ip),
|
||||
IP_PROTO_TCP, p->tot_len);
|
||||
tcphdr->chksum = inet_chksum_pseudo(p, &(pcb->local_ip.ip4), &(pcb->remote_ip.ip4),
|
||||
IP_PROTO_TCP, p->tot_len);
|
||||
#endif
|
||||
#if LWIP_NETIF_HWADDRHINT
|
||||
ip_output_hinted(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
|
||||
IP_PROTO_TCP, &(pcb->addr_hint));
|
||||
ip_output_hinted(p, &(pcb->local_ip.ip4), &(pcb->remote_ip.ip4), pcb->ttl, pcb->tos,
|
||||
IP_PROTO_TCP, &(pcb->addr_hint));
|
||||
#else /* LWIP_NETIF_HWADDRHINT*/
|
||||
ip_output(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
|
||||
IP_PROTO_TCP);
|
||||
ip_output(p, &(pcb->local_ip.ip4), &(pcb->remote_ip.ip4), pcb->ttl, pcb->tos,
|
||||
IP_PROTO_TCP);
|
||||
#endif /* LWIP_NETIF_HWADDRHINT*/
|
||||
}
|
||||
pbuf_free(p);
|
||||
|
||||
return ERR_OK;
|
||||
@@ -1086,12 +1106,30 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
|
||||
|
||||
/* If we don't have a local IP address, we get one by
|
||||
calling ip_route(). */
|
||||
if (ip_addr_isany(&(pcb->local_ip))) {
|
||||
netif = ip_route(&(pcb->remote_ip));
|
||||
#if LWIP_IPV6
|
||||
if (pcb->isipv6) {
|
||||
if (ip6_addr_isany(&(pcb->local_ip.ip6))) {
|
||||
ip6_addr_t * local_addr6;
|
||||
netif = ip6_route(&(pcb->local_ip.ip6), &(pcb->remote_ip.ip6));
|
||||
if (netif == NULL) {
|
||||
return;
|
||||
}
|
||||
/* Select and IPv6 address from the netif. */
|
||||
local_addr6 = ip6_select_source_address(netif, &(pcb->remote_ip.ip6));
|
||||
if (local_addr6 == NULL) {
|
||||
return;
|
||||
}
|
||||
ip6_addr_set(&pcb->local_ip.ip6, local_addr6);
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif /* LWIP_IPV6 */
|
||||
if (ip_addr_isany(&(pcb->local_ip.ip4))) {
|
||||
netif = ip_route(&(pcb->remote_ip.ip4));
|
||||
if (netif == NULL) {
|
||||
return;
|
||||
}
|
||||
ip_addr_copy(pcb->local_ip, netif->ip_addr);
|
||||
ip_addr_copy(pcb->local_ip.ip4, netif->ip_addr);
|
||||
}
|
||||
|
||||
if (pcb->rttest == 0) {
|
||||
@@ -1112,14 +1150,24 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
|
||||
seg->p->payload = seg->tcphdr;
|
||||
|
||||
seg->tcphdr->chksum = 0;
|
||||
#if CHECKSUM_GEN_TCP
|
||||
#if TCP_CHECKSUM_ON_COPY
|
||||
{
|
||||
u32_t acc;
|
||||
#if TCP_CHECKSUM_ON_COPY_SANITY_CHECK
|
||||
u16_t chksum_slow = inet_chksum_pseudo(seg->p, &(pcb->local_ip),
|
||||
&(pcb->remote_ip),
|
||||
IP_PROTO_TCP, seg->p->tot_len);
|
||||
u16_t chksum_slow;
|
||||
#if LWIP_IPV6
|
||||
if (pcb->isipv6) {
|
||||
chksum_slow = ip6_chksum_pseudo(seg->p, &(pcb->local_ip.ip6),
|
||||
&(pcb->remote_ip.ip6),
|
||||
IP6_NEXTH_TCP, seg->p->tot_len);
|
||||
}
|
||||
else
|
||||
#endif /* LWIP_IPV6 */
|
||||
{
|
||||
chksum_slow = inet_chksum_pseudo(seg->p, &(pcb->local_ip.ip4),
|
||||
&(pcb->remote_ip.ip4),
|
||||
IP_PROTO_TCP, seg->p->tot_len);
|
||||
}
|
||||
#endif /* TCP_CHECKSUM_ON_COPY_SANITY_CHECK */
|
||||
if ((seg->flags & TF_SEG_DATA_CHECKSUMMED) == 0) {
|
||||
LWIP_ASSERT("data included but not checksummed",
|
||||
@@ -1127,9 +1175,19 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
|
||||
}
|
||||
|
||||
/* rebuild TCP header checksum (TCP header changes for retransmissions!) */
|
||||
acc = inet_chksum_pseudo_partial(seg->p, &(pcb->local_ip),
|
||||
&(pcb->remote_ip),
|
||||
IP_PROTO_TCP, seg->p->tot_len, TCPH_HDRLEN(seg->tcphdr) * 4);
|
||||
#if LWIP_IPV6
|
||||
if (pcb->isipv6) {
|
||||
acc = ip6_chksum_pseudo_partial(seg->p, &(pcb->local_ip.ip6),
|
||||
&(pcb->remote_ip.ip6),
|
||||
IP6_NEXTH_TCP, seg->p->tot_len, TCPH_HDRLEN(seg->tcphdr) * 4);
|
||||
}
|
||||
else
|
||||
#endif /* LWIP_IPV6 */
|
||||
{
|
||||
acc = inet_chksum_pseudo_partial(seg->p, &(pcb->local_ip.ip4),
|
||||
&(pcb->remote_ip.ip4),
|
||||
IP_PROTO_TCP, seg->p->tot_len, TCPH_HDRLEN(seg->tcphdr) * 4);
|
||||
}
|
||||
/* add payload checksum */
|
||||
if (seg->chksum_swapped) {
|
||||
seg->chksum = SWAP_BYTES_IN_WORD(seg->chksum);
|
||||
@@ -1147,20 +1205,46 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
|
||||
#endif /* TCP_CHECKSUM_ON_COPY_SANITY_CHECK */
|
||||
}
|
||||
#else /* TCP_CHECKSUM_ON_COPY */
|
||||
seg->tcphdr->chksum = inet_chksum_pseudo(seg->p, &(pcb->local_ip),
|
||||
&(pcb->remote_ip),
|
||||
IP_PROTO_TCP, seg->p->tot_len);
|
||||
#endif /* TCP_CHECKSUM_ON_COPY */
|
||||
#if LWIP_IPV6
|
||||
if (pcb->isipv6) {
|
||||
/* Chksum is mandatory in IPv6 */
|
||||
seg->tcphdr->chksum = ip6_chksum_pseudo(seg->p, &(pcb->local_ip.ip6),
|
||||
&(pcb->remote_ip.ip6),
|
||||
IP6_NEXTH_TCP, seg->p->tot_len);
|
||||
}
|
||||
else
|
||||
#endif /* LWIP_IPV6 */
|
||||
{
|
||||
#if CHECKSUM_GEN_TCP
|
||||
seg->tcphdr->chksum = inet_chksum_pseudo(seg->p, &(pcb->local_ip.ip4),
|
||||
&(pcb->remote_ip.ip4),
|
||||
IP_PROTO_TCP, seg->p->tot_len);
|
||||
#endif /* CHECKSUM_GEN_TCP */
|
||||
}
|
||||
#endif /* TCP_CHECKSUM_ON_COPY */
|
||||
TCP_STATS_INC(tcp.xmit);
|
||||
|
||||
#if LWIP_IPV6
|
||||
if (pcb->isipv6) {
|
||||
#if LWIP_NETIF_HWADDRHINT
|
||||
ip_output_hinted(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
|
||||
IP_PROTO_TCP, &(pcb->addr_hint));
|
||||
ip6_output_hinted(seg->p, &(pcb->local_ip.ip6), &(pcb->remote_ip.ip6), pcb->ttl, pcb->tos,
|
||||
IP6_NEXTH_TCP, &(pcb->addr_hint));
|
||||
#else /* LWIP_NETIF_HWADDRHINT*/
|
||||
ip_output(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
|
||||
IP_PROTO_TCP);
|
||||
ip6_output(seg->p, &(pcb->local_ip.ip6), &(pcb->remote_ip.ip6), pcb->ttl, pcb->tos,
|
||||
IP6_NEXTH_TCP);
|
||||
#endif /* LWIP_NETIF_HWADDRHINT*/
|
||||
}
|
||||
else
|
||||
#endif /* LWIP_IPV6 */
|
||||
{
|
||||
#if LWIP_NETIF_HWADDRHINT
|
||||
ip_output_hinted(seg->p, &(pcb->local_ip.ip4), &(pcb->remote_ip.ip4), pcb->ttl, pcb->tos,
|
||||
IP_PROTO_TCP, &(pcb->addr_hint));
|
||||
#else /* LWIP_NETIF_HWADDRHINT*/
|
||||
ip_output(seg->p, &(pcb->local_ip.ip4), &(pcb->remote_ip.ip4), pcb->ttl, pcb->tos,
|
||||
IP_PROTO_TCP);
|
||||
#endif /* LWIP_NETIF_HWADDRHINT*/
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1220,6 +1304,65 @@ tcp_rst(u32_t seqno, u32_t ackno,
|
||||
LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_rst: seqno %"U32_F" ackno %"U32_F".\n", seqno, ackno));
|
||||
}
|
||||
|
||||
#if LWIP_IPV6
|
||||
/**
|
||||
* Send a TCP RESET packet (empty segment with RST flag set) over IPv6,
|
||||
* either to abort a connection or to show that there is no matching local
|
||||
* connection for a received segment.
|
||||
*
|
||||
* Called by tcp_abort() (to abort a local connection), tcp_input() (if no
|
||||
* matching local pcb was found), tcp_listen_input() (if incoming segment
|
||||
* has ACK flag set) and tcp_process() (received segment in the wrong state)
|
||||
*
|
||||
* Since a RST segment is in most cases not sent for an active connection,
|
||||
* tcp_rst() has a number of arguments that are taken from a tcp_pcb for
|
||||
* most other segment output functions.
|
||||
*
|
||||
* @param seqno the sequence number to use for the outgoing segment
|
||||
* @param ackno the acknowledge number to use for the outgoing segment
|
||||
* @param local_ip6 the local IPv6 address to send the segment from
|
||||
* @param remote_ip6 the remote IPv6 address to send the segment to
|
||||
* @param local_port the local TCP port to send the segment from
|
||||
* @param remote_port the remote TCP port to send the segment to
|
||||
*/
|
||||
void
|
||||
tcp_rst_ip6(u32_t seqno, u32_t ackno,
|
||||
ip6_addr_t *local_ip6, ip6_addr_t *remote_ip6,
|
||||
u16_t local_port, u16_t remote_port)
|
||||
{
|
||||
struct pbuf *p;
|
||||
struct tcp_hdr *tcphdr;
|
||||
p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM);
|
||||
if (p == NULL) {
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("tcp_rst: could not allocate memory for pbuf\n"));
|
||||
return;
|
||||
}
|
||||
LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr",
|
||||
(p->len >= sizeof(struct tcp_hdr)));
|
||||
|
||||
tcphdr = (struct tcp_hdr *)p->payload;
|
||||
tcphdr->src = htons(local_port);
|
||||
tcphdr->dest = htons(remote_port);
|
||||
tcphdr->seqno = htonl(seqno);
|
||||
tcphdr->ackno = htonl(ackno);
|
||||
TCPH_HDRLEN_FLAGS_SET(tcphdr, TCP_HLEN/4, TCP_RST | TCP_ACK);
|
||||
tcphdr->wnd = PP_HTONS(TCP_WND);
|
||||
tcphdr->chksum = 0;
|
||||
tcphdr->urgp = 0;
|
||||
|
||||
/* chksum us mandatory over IPv6. */
|
||||
tcphdr->chksum = ip6_chksum_pseudo(p, local_ip6, remote_ip6,
|
||||
IP6_NEXTH_TCP, p->tot_len);
|
||||
|
||||
TCP_STATS_INC(tcp.xmit);
|
||||
snmp_inc_tcpoutrsts();
|
||||
/* Send output with hardcoded HL since we have no access to the pcb */
|
||||
ip6_output(p, local_ip6, remote_ip6, TCP_TTL, 0, IP6_NEXTH_TCP);
|
||||
pbuf_free(p);
|
||||
LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_rst: seqno %"U32_F" ackno %"U32_F".\n", seqno, ackno));
|
||||
}
|
||||
#endif /* LWIP_IPV6 */
|
||||
|
||||
/**
|
||||
* Requeue all unacked segments for retransmission
|
||||
*
|
||||
@@ -1351,9 +1494,13 @@ tcp_keepalive(struct tcp_pcb *pcb)
|
||||
struct pbuf *p;
|
||||
struct tcp_hdr *tcphdr;
|
||||
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: sending KEEPALIVE probe to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
|
||||
ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip),
|
||||
ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip)));
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: sending KEEPALIVE probe to "));
|
||||
if (!pcb->isipv6) {
|
||||
ip_addr_debug_print(TCP_DEBUG, &pcb->remote_ip.ip4);
|
||||
} else {
|
||||
ip6_addr_debug_print(TCP_DEBUG, &pcb->remote_ip.ip6);
|
||||
}
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("\n"));
|
||||
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: tcp_ticks %"U32_F" pcb->tmr %"U32_F" pcb->keep_cnt_sent %"U16_F"\n",
|
||||
tcp_ticks, pcb->tmr, pcb->keep_cnt_sent));
|
||||
@@ -1366,19 +1513,41 @@ tcp_keepalive(struct tcp_pcb *pcb)
|
||||
}
|
||||
tcphdr = (struct tcp_hdr *)p->payload;
|
||||
|
||||
#if LWIP_IPV6
|
||||
if (pcb->isipv6) {
|
||||
tcphdr->chksum = ip6_chksum_pseudo(p, &pcb->local_ip.ip6, &pcb->remote_ip.ip6,
|
||||
IP6_NEXTH_TCP, p->tot_len);
|
||||
}
|
||||
else
|
||||
#endif /* LWIP_IPV6 */
|
||||
{
|
||||
#if CHECKSUM_GEN_TCP
|
||||
tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip,
|
||||
IP_PROTO_TCP, p->tot_len);
|
||||
tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip.ip4, &pcb->remote_ip.ip4,
|
||||
IP_PROTO_TCP, p->tot_len);
|
||||
#endif
|
||||
}
|
||||
TCP_STATS_INC(tcp.xmit);
|
||||
|
||||
/* Send output to IP */
|
||||
#if LWIP_IPV6
|
||||
if (pcb->isipv6) {
|
||||
#if LWIP_NETIF_HWADDRHINT
|
||||
ip_output_hinted(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP,
|
||||
&(pcb->addr_hint));
|
||||
ip6_output_hinted(p, &pcb->local_ip.ip6, &pcb->remote_ip.ip6, pcb->ttl, 0, IP6_NEXTH_TCP,
|
||||
&(pcb->addr_hint));
|
||||
#else /* LWIP_NETIF_HWADDRHINT*/
|
||||
ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP);
|
||||
ip6_output(p, &pcb->local_ip.ip6, &pcb->remote_ip.ip6, pcb->ttl, 0, IP6_NEXTH_TCP);
|
||||
#endif /* LWIP_NETIF_HWADDRHINT*/
|
||||
}
|
||||
else
|
||||
#endif /* LWIP_IPV6 */
|
||||
{
|
||||
#if LWIP_NETIF_HWADDRHINT
|
||||
ip_output_hinted(p, &pcb->local_ip.ip4, &pcb->remote_ip.ip4, pcb->ttl, 0, IP_PROTO_TCP,
|
||||
&(pcb->addr_hint));
|
||||
#else /* LWIP_NETIF_HWADDRHINT*/
|
||||
ip_output(p, &pcb->local_ip.ip4, &pcb->remote_ip.ip4, pcb->ttl, 0, IP_PROTO_TCP);
|
||||
#endif /* LWIP_NETIF_HWADDRHINT*/
|
||||
}
|
||||
|
||||
pbuf_free(p);
|
||||
|
||||
@@ -1404,11 +1573,13 @@ tcp_zero_window_probe(struct tcp_pcb *pcb)
|
||||
u16_t len;
|
||||
u8_t is_fin;
|
||||
|
||||
LWIP_DEBUGF(TCP_DEBUG,
|
||||
("tcp_zero_window_probe: sending ZERO WINDOW probe to %"
|
||||
U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
|
||||
ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip),
|
||||
ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip)));
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: sending ZERO WINDOW probe to "));
|
||||
if (!pcb->isipv6) {
|
||||
ip_addr_debug_print(TCP_DEBUG, &pcb->remote_ip.ip4);
|
||||
} else {
|
||||
ip6_addr_debug_print(TCP_DEBUG, &pcb->remote_ip.ip6);
|
||||
}
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("\n"));
|
||||
|
||||
LWIP_DEBUGF(TCP_DEBUG,
|
||||
("tcp_zero_window_probe: tcp_ticks %"U32_F
|
||||
@@ -1445,19 +1616,41 @@ tcp_zero_window_probe(struct tcp_pcb *pcb)
|
||||
pbuf_copy_partial(seg->p, d, 1, TCPH_HDRLEN(thdr) * 4);
|
||||
}
|
||||
|
||||
#if LWIP_IPV6
|
||||
if (pcb->isipv6) {
|
||||
tcphdr->chksum = ip6_chksum_pseudo(p, &pcb->local_ip.ip6, &pcb->remote_ip.ip6,
|
||||
IP6_NEXTH_TCP, p->tot_len);
|
||||
}
|
||||
else
|
||||
#endif /* LWIP_IPV6 */
|
||||
{
|
||||
#if CHECKSUM_GEN_TCP
|
||||
tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip,
|
||||
IP_PROTO_TCP, p->tot_len);
|
||||
tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip.ip4, &pcb->remote_ip.ip4,
|
||||
IP_PROTO_TCP, p->tot_len);
|
||||
#endif
|
||||
}
|
||||
TCP_STATS_INC(tcp.xmit);
|
||||
|
||||
/* Send output to IP */
|
||||
#if LWIP_IPV6
|
||||
if (pcb->isipv6) {
|
||||
#if LWIP_NETIF_HWADDRHINT
|
||||
ip_output_hinted(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP,
|
||||
&(pcb->addr_hint));
|
||||
ip6_output_hinted(p, &pcb->local_ip.ip6, &pcb->remote_ip.ip6, pcb->ttl, 0, IP6_NEXTH_TCP,
|
||||
&(pcb->addr_hint));
|
||||
#else /* LWIP_NETIF_HWADDRHINT*/
|
||||
ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP);
|
||||
ip6_output(p, &pcb->local_ip.ip6, &pcb->remote_ip.ip6, pcb->ttl, 0, IP6_NEXTH_TCP);
|
||||
#endif /* LWIP_NETIF_HWADDRHINT*/
|
||||
}
|
||||
else
|
||||
#endif /* LWIP_IPV6 */
|
||||
{
|
||||
#if LWIP_NETIF_HWADDRHINT
|
||||
ip_output_hinted(p, &pcb->local_ip.ip4, &pcb->remote_ip.ip4, pcb->ttl, 0, IP_PROTO_TCP,
|
||||
&(pcb->addr_hint));
|
||||
#else /* LWIP_NETIF_HWADDRHINT*/
|
||||
ip_output(p, &pcb->local_ip.ip4, &pcb->remote_ip.ip4, pcb->ttl, 0, IP_PROTO_TCP);
|
||||
#endif /* LWIP_NETIF_HWADDRHINT*/
|
||||
}
|
||||
|
||||
pbuf_free(p);
|
||||
|
||||
|
||||
@@ -56,7 +56,9 @@
|
||||
#include "lwip/autoip.h"
|
||||
#include "lwip/igmp.h"
|
||||
#include "lwip/dns.h"
|
||||
|
||||
#include "lwip/nd6.h"
|
||||
#include "lwip/ip6_frag.h"
|
||||
#include "lwip/mld6.h"
|
||||
|
||||
/** The one and only timeout list */
|
||||
static struct sys_timeo *next_timeout;
|
||||
@@ -217,6 +219,54 @@ dns_timer(void *arg)
|
||||
}
|
||||
#endif /* LWIP_DNS */
|
||||
|
||||
#if LWIP_IPV6
|
||||
/**
|
||||
* Timer callback function that calls nd6_tmr() and reschedules itself.
|
||||
*
|
||||
* @param arg unused argument
|
||||
*/
|
||||
static void
|
||||
nd6_timer(void *arg)
|
||||
{
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: nd6_tmr()\n"));
|
||||
nd6_tmr();
|
||||
sys_timeout(ND6_TMR_INTERVAL, nd6_timer, NULL);
|
||||
}
|
||||
|
||||
#if LWIP_IPV6_REASS
|
||||
/**
|
||||
* Timer callback function that calls ip6_reass_tmr() and reschedules itself.
|
||||
*
|
||||
* @param arg unused argument
|
||||
*/
|
||||
static void
|
||||
ip6_reass_timer(void *arg)
|
||||
{
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: ip6_reass_tmr()\n"));
|
||||
ip6_reass_tmr();
|
||||
sys_timeout(IP6_REASS_TMR_INTERVAL, ip6_reass_timer, NULL);
|
||||
}
|
||||
#endif /* LWIP_IPV6_REASS */
|
||||
|
||||
#if LWIP_IPV6_MLD
|
||||
/**
|
||||
* Timer callback function that calls mld6_tmr() and reschedules itself.
|
||||
*
|
||||
* @param arg unused argument
|
||||
*/
|
||||
static void
|
||||
mld6_timer(void *arg)
|
||||
{
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: mld6_tmr()\n"));
|
||||
mld6_tmr();
|
||||
sys_timeout(MLD6_TMR_INTERVAL, mld6_timer, NULL);
|
||||
}
|
||||
#endif /* LWIP_IPV6_MLD */
|
||||
#endif /* LWIP_IPV6 */
|
||||
|
||||
/** Initialize this module */
|
||||
void sys_timeouts_init(void)
|
||||
{
|
||||
@@ -239,6 +289,15 @@ void sys_timeouts_init(void)
|
||||
#if LWIP_DNS
|
||||
sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL);
|
||||
#endif /* LWIP_DNS */
|
||||
#if LWIP_IPV6
|
||||
sys_timeout(ND6_TMR_INTERVAL, nd6_timer, NULL);
|
||||
#if LWIP_IPV6_REASS
|
||||
sys_timeout(IP6_REASS_TMR_INTERVAL, ip6_reass_timer, NULL);
|
||||
#endif /* LWIP_IPV6_REASS */
|
||||
#if LWIP_IPV6_MLD
|
||||
sys_timeout(MLD6_TMR_INTERVAL, mld6_timer, NULL);
|
||||
#endif /* LWIP_IPV6_MLD */
|
||||
#endif /* LWIP_IPV6 */
|
||||
|
||||
#if NO_SYS
|
||||
/* Initialise timestamp for sys_check_timeouts */
|
||||
|
||||
583
src/core/udp.c
583
src/core/udp.c
@@ -55,8 +55,12 @@
|
||||
#include "lwip/memp.h"
|
||||
#include "lwip/inet_chksum.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/ip6.h"
|
||||
#include "lwip/ip6_addr.h"
|
||||
#include "lwip/ip6_chksum.h"
|
||||
#include "lwip/netif.h"
|
||||
#include "lwip/icmp.h"
|
||||
#include "lwip/icmp6.h"
|
||||
#include "lwip/stats.h"
|
||||
#include "lwip/snmp.h"
|
||||
#include "arch/perf.h"
|
||||
@@ -76,7 +80,7 @@ struct udp_pcb *udp_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 p pbuf to be demultiplexed to a UDP PCB (p->payload pointing to the UDP header)
|
||||
* @param inp network interface on which the datagram was received.
|
||||
*
|
||||
*/
|
||||
@@ -86,7 +90,6 @@ 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;
|
||||
@@ -95,11 +98,8 @@ udp_input(struct pbuf *p, struct netif *inp)
|
||||
|
||||
UDP_STATS_INC(udp.recv);
|
||||
|
||||
iphdr = (struct ip_hdr *)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))) {
|
||||
/* Check minimum length (UDP header) */
|
||||
if (p->len < UDP_HLEN) {
|
||||
/* drop short packets */
|
||||
LWIP_DEBUGF(UDP_DEBUG,
|
||||
("udp_input: short UDP datagram (%"U16_F" bytes) discarded\n", p->tot_len));
|
||||
@@ -113,7 +113,11 @@ udp_input(struct pbuf *p, struct netif *inp)
|
||||
udphdr = (struct udp_hdr *)p->payload;
|
||||
|
||||
/* is broadcast packet ? */
|
||||
broadcast = ip_addr_isbroadcast(¤t_iphdr_dest, inp);
|
||||
#if LWIP_IPV6
|
||||
broadcast = (ip_current_header() != NULL) && ip_addr_isbroadcast(ip_current_dest_addr(), inp);
|
||||
#else /* LWIP_IPV6 */
|
||||
broadcast = ip_addr_isbroadcast(ip_current_dest_addr(), inp);
|
||||
#endif /* LWIP_IPV6 */
|
||||
|
||||
LWIP_DEBUGF(UDP_DEBUG, ("udp_input: received datagram of length %"U16_F"\n", p->tot_len));
|
||||
|
||||
@@ -124,13 +128,19 @@ udp_input(struct pbuf *p, struct netif *inp)
|
||||
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_16(&iphdr->dest), ip4_addr2_16(&iphdr->dest),
|
||||
ip4_addr3_16(&iphdr->dest), ip4_addr4_16(&iphdr->dest), ntohs(udphdr->dest),
|
||||
ip4_addr1_16(&iphdr->src), ip4_addr2_16(&iphdr->src),
|
||||
ip4_addr3_16(&iphdr->src), ip4_addr4_16(&iphdr->src), ntohs(udphdr->src)));
|
||||
LWIP_DEBUGF(UDP_DEBUG, ("udp ("));
|
||||
if (ip_current_header() != NULL) {
|
||||
ip_addr_debug_print(UDP_DEBUG, ip_current_dest_addr());
|
||||
} else {
|
||||
ip6_addr_debug_print(UDP_DEBUG, ip6_current_dest_addr());
|
||||
}
|
||||
LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F") <-- (", ntohs(udphdr->dest)));
|
||||
if (ip_current_header() != NULL) {
|
||||
ip_addr_debug_print(UDP_DEBUG, ip_current_src_addr());
|
||||
} else {
|
||||
ip6_addr_debug_print(UDP_DEBUG, ip6_current_src_addr());
|
||||
}
|
||||
LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F")\n", ntohs(udphdr->src)));
|
||||
|
||||
#if LWIP_DHCP
|
||||
pcb = NULL;
|
||||
@@ -143,8 +153,12 @@ udp_input(struct pbuf *p, struct netif *inp)
|
||||
/* 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), ¤t_iphdr_src))) {
|
||||
if (
|
||||
#if LWIP_IPV6
|
||||
!pcb->isipv6 &&
|
||||
#endif /* LWIP_IPV6 */
|
||||
((ip_addr_isany(&inp->dhcp->pcb->remote_ip.ip4) ||
|
||||
ip_addr_cmp(&(inp->dhcp->pcb->remote_ip.ip4), ip_current_src_addr())))) {
|
||||
pcb = inp->dhcp->pcb;
|
||||
}
|
||||
}
|
||||
@@ -162,25 +176,44 @@ udp_input(struct pbuf *p, struct netif *inp)
|
||||
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_16(&pcb->local_ip), ip4_addr2_16(&pcb->local_ip),
|
||||
ip4_addr3_16(&pcb->local_ip), ip4_addr4_16(&pcb->local_ip), pcb->local_port,
|
||||
ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip),
|
||||
ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip), pcb->remote_port));
|
||||
LWIP_DEBUGF(UDP_DEBUG, ("pcb ("));
|
||||
if (!pcb->isipv6) {
|
||||
ip_addr_debug_print(UDP_DEBUG, &pcb->local_ip.ip4);
|
||||
} else {
|
||||
ip6_addr_debug_print(UDP_DEBUG, &pcb->local_ip.ip6);
|
||||
}
|
||||
LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F") <-- (", pcb->local_port));
|
||||
if (!pcb->isipv6) {
|
||||
ip_addr_debug_print(UDP_DEBUG, &pcb->remote_ip.ip4);
|
||||
} else {
|
||||
ip6_addr_debug_print(UDP_DEBUG, &pcb->remote_ip.ip6);
|
||||
}
|
||||
LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F")\n", 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), ¤t_iphdr_dest) ||
|
||||
#if LWIP_IPV6
|
||||
((pcb->isipv6 &&
|
||||
(ip6_current_header() != NULL) &&
|
||||
(ip6_addr_isany(&pcb->local_ip.ip6) ||
|
||||
#if LWIP_IPV6_MLD
|
||||
ip6_addr_ismulticast(ip6_current_dest_addr()) ||
|
||||
#endif /* LWIP_IPV6_MLD */
|
||||
ip6_addr_cmp(&pcb->local_ip.ip6, ip6_current_dest_addr()))) ||
|
||||
(!pcb->isipv6 &&
|
||||
(ip_current_header() != NULL) &&
|
||||
#else /* LWIP_IPV6 */
|
||||
((
|
||||
#endif /* LWIP_IPV6 */
|
||||
((!broadcast && ip_addr_isany(&pcb->local_ip.ip4)) ||
|
||||
ip_addr_cmp(&(pcb->local_ip.ip4), ip_current_dest_addr()) ||
|
||||
#if LWIP_IGMP
|
||||
ip_addr_ismulticast(¤t_iphdr_dest) ||
|
||||
ip_addr_ismulticast(ip_current_dest_addr()) ||
|
||||
#endif /* LWIP_IGMP */
|
||||
#if IP_SOF_BROADCAST_RECV
|
||||
(broadcast && (pcb->so_options & SOF_BROADCAST)))) {
|
||||
(broadcast && (pcb->so_options & SOF_BROADCAST)))))) {
|
||||
#else /* IP_SOF_BROADCAST_RECV */
|
||||
(broadcast))) {
|
||||
(broadcast))))) {
|
||||
#endif /* IP_SOF_BROADCAST_RECV */
|
||||
local_match = 1;
|
||||
if ((uncon_pcb == NULL) &&
|
||||
@@ -192,8 +225,18 @@ udp_input(struct pbuf *p, struct netif *inp)
|
||||
/* 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), ¤t_iphdr_src))) {
|
||||
#if LWIP_IPV6
|
||||
((pcb->isipv6 &&
|
||||
(ip6_current_header() != NULL) &&
|
||||
(ip6_addr_isany(&pcb->remote_ip.ip6) ||
|
||||
ip6_addr_cmp(&pcb->remote_ip.ip6, ip6_current_src_addr()))) ||
|
||||
(!pcb->isipv6 &&
|
||||
(ip_current_header() != NULL) &&
|
||||
#else /* LWIP_IPV6 */
|
||||
((
|
||||
#endif /* LWIP_IPV6 */
|
||||
((ip_addr_isany(&pcb->remote_ip.ip4) ||
|
||||
ip_addr_cmp(&(pcb->remote_ip.ip4), ip_current_src_addr())))))) {
|
||||
/* the first fully matching PCB */
|
||||
if (prev != NULL) {
|
||||
/* move the pcb to the front of udp_pcbs so that is
|
||||
@@ -215,10 +258,26 @@ udp_input(struct pbuf *p, struct netif *inp)
|
||||
}
|
||||
|
||||
/* Check checksum if this is a match or if it was directed at us. */
|
||||
if (pcb != NULL || ip_addr_cmp(&inp->ip_addr, ¤t_iphdr_dest)) {
|
||||
if ((pcb != NULL) ||
|
||||
#if LWIP_IPV6
|
||||
((ip6_current_header() != NULL) &&
|
||||
netif_matches_ip6_addr(inp, ip6_current_dest_addr())) ||
|
||||
((ip_current_header() != NULL) &&
|
||||
#else /* LWIP_IPV6 */
|
||||
(
|
||||
#endif /* LWIP_IPV6 */
|
||||
ip_addr_cmp(&inp->ip_addr, ip_current_dest_addr()))) {
|
||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: calculating checksum\n"));
|
||||
#if LWIP_UDPLITE
|
||||
if (IPH_PROTO(iphdr) == IP_PROTO_UDPLITE) {
|
||||
if (
|
||||
#if LWIP_IPV6
|
||||
((ip6_current_header() != NULL) &&
|
||||
(IP6H_NEXTH(ip6_current_header()) == IP_PROTO_UDPLITE)) ||
|
||||
((ip_current_header() != NULL) &&
|
||||
#else /* LWIP_IPV6 */
|
||||
(
|
||||
#endif /* LWIP_IPV6 */
|
||||
(IPH_PROTO(iphdr) == IP_PROTO_UDPLITE))) {
|
||||
/* Do the UDP Lite checksum */
|
||||
#if CHECKSUM_CHECK_UDP
|
||||
u16_t chklen = ntohs(udphdr->len);
|
||||
@@ -237,7 +296,22 @@ udp_input(struct pbuf *p, struct netif *inp)
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
if (inet_chksum_pseudo_partial(p, ¤t_iphdr_src, ¤t_iphdr_dest,
|
||||
#if LWIP_IPV6
|
||||
if (ip6_current_header() != NULL) {
|
||||
if (ip6_chksum_pseudo_partial(p, ip6_current_src_addr(), ip6_current_dest_addr(),
|
||||
IP6_NEXTH_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;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif /* LWIP_IPV6 */
|
||||
if (inet_chksum_pseudo_partial(p, ip_current_src_addr(), ip_current_dest_addr(),
|
||||
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"));
|
||||
@@ -253,6 +327,21 @@ udp_input(struct pbuf *p, struct netif *inp)
|
||||
{
|
||||
#if CHECKSUM_CHECK_UDP
|
||||
if (udphdr->chksum != 0) {
|
||||
#if LWIP_IPV6
|
||||
if (ip6_current_header() != NULL) {
|
||||
if (ip6_chksum_pseudo(p, ip6_current_src_addr(), ip6_current_dest_addr(),
|
||||
IP6_NEXTH_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;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif /* LWIP_IPV6 */
|
||||
if (inet_chksum_pseudo(p, ip_current_src_addr(), ip_current_dest_addr(),
|
||||
IP_PROTO_UDP, p->tot_len) != 0) {
|
||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
|
||||
@@ -277,32 +366,53 @@ udp_input(struct pbuf *p, struct netif *inp)
|
||||
if (pcb != NULL) {
|
||||
snmp_inc_udpindatagrams();
|
||||
#if SO_REUSE && SO_REUSE_RXTOALL
|
||||
if ((broadcast || ip_addr_ismulticast(¤t_iphdr_dest)) &&
|
||||
if ((broadcast ||
|
||||
#if LWIP_IPV6
|
||||
ip6_addr_ismulticast(ip6_current_dest_addr()) ||
|
||||
#endif /* LWIP_IPV6 */
|
||||
ip_addr_ismulticast(ip_current_dest_addr())) &&
|
||||
((pcb->so_options & SOF_REUSEADDR) != 0)) {
|
||||
/* pass broadcast- or multicast packets to all multicast pcbs
|
||||
if SOF_REUSEADDR is set on the first match */
|
||||
struct udp_pcb *mpcb;
|
||||
u8_t p_header_changed = 0;
|
||||
s16_t hdrs_len;
|
||||
#if LWIP_IPV6
|
||||
if (ip6_current_header() != NULL) {
|
||||
hdrs_len = (s16_t)(ip6_current_header_tot_len() + UDP_HLEN);
|
||||
} else
|
||||
#endif /* LWIP_IPV6 */
|
||||
{
|
||||
hdrs_len = (s16_t)((IPH_HL(ip_current_header()) * 4) + UDP_HLEN);
|
||||
}
|
||||
for (mpcb = udp_pcbs; mpcb != NULL; mpcb = mpcb->next) {
|
||||
if (mpcb != pcb) {
|
||||
/* compare PCB local addr+port to UDP destination addr+port */
|
||||
if ((mpcb->local_port == dest) &&
|
||||
((!broadcast && ip_addr_isany(&mpcb->local_ip)) ||
|
||||
ip_addr_cmp(&(mpcb->local_ip), ¤t_iphdr_dest) ||
|
||||
#if LWIP_IPV6
|
||||
((mpcb->isipv6 &&
|
||||
(ip6_addr_ismulticast(ip6_current_dest_addr()) ||
|
||||
ip6_addr_cmp(&mpcb->local_ip.ip6, ip6_current_dest_addr()))) ||
|
||||
(!mpcb->isipv6 &&
|
||||
#else /* LWIP_IPV6 */
|
||||
((
|
||||
#endif /* LWIP_IPV6 */
|
||||
((!broadcast && ip_addr_isany(&mpcb->local_ip.ip4)) ||
|
||||
ip_addr_cmp(&(mpcb->local_ip.ip4), ip_current_dest_addr()) ||
|
||||
#if LWIP_IGMP
|
||||
ip_addr_ismulticast(¤t_iphdr_dest) ||
|
||||
ip_addr_ismulticast(ip_current_dest_addr()) ||
|
||||
#endif /* LWIP_IGMP */
|
||||
#if IP_SOF_BROADCAST_RECV
|
||||
(broadcast && (mpcb->so_options & SOF_BROADCAST)))) {
|
||||
(broadcast && (mpcb->so_options & SOF_BROADCAST)))))) {
|
||||
#else /* IP_SOF_BROADCAST_RECV */
|
||||
(broadcast))) {
|
||||
(broadcast))))) {
|
||||
#endif /* IP_SOF_BROADCAST_RECV */
|
||||
/* pass a copy of the packet to all local matches */
|
||||
if (mpcb->recv != NULL) {
|
||||
if (mpcb->recv.ip4 != NULL) {
|
||||
struct pbuf *q;
|
||||
/* for that, move payload to IP header again */
|
||||
if (p_header_changed == 0) {
|
||||
pbuf_header(p, (s16_t)((IPH_HL(iphdr) * 4) + UDP_HLEN));
|
||||
pbuf_header(p, hdrs_len);
|
||||
p_header_changed = 1;
|
||||
}
|
||||
q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
|
||||
@@ -310,8 +420,16 @@ udp_input(struct pbuf *p, struct netif *inp)
|
||||
err_t err = pbuf_copy(q, p);
|
||||
if (err == ERR_OK) {
|
||||
/* move payload to UDP data */
|
||||
pbuf_header(q, -(s16_t)((IPH_HL(iphdr) * 4) + UDP_HLEN));
|
||||
mpcb->recv(mpcb->recv_arg, mpcb, q, ip_current_src_addr(), src);
|
||||
pbuf_header(q, -hdrs_len);
|
||||
#if LWIP_IPV6
|
||||
if (mpcb->isipv6) {
|
||||
mpcb->recv.ip6(mpcb->recv_arg, mpcb, q, ip6_current_src_addr(), src);
|
||||
}
|
||||
else
|
||||
#endif /* LWIP_IPV6 */
|
||||
{
|
||||
mpcb->recv.ip4(mpcb->recv_arg, mpcb, q, ip_current_src_addr(), src);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -320,14 +438,22 @@ udp_input(struct pbuf *p, struct netif *inp)
|
||||
}
|
||||
if (p_header_changed) {
|
||||
/* and move payload to UDP data again */
|
||||
pbuf_header(p, -(s16_t)((IPH_HL(iphdr) * 4) + UDP_HLEN));
|
||||
pbuf_header(p, -hdrs_len);
|
||||
}
|
||||
}
|
||||
#endif /* SO_REUSE && SO_REUSE_RXTOALL */
|
||||
/* callback */
|
||||
if (pcb->recv != NULL) {
|
||||
if (pcb->recv.ip4 != NULL) {
|
||||
/* now the recv function is responsible for freeing p */
|
||||
pcb->recv(pcb->recv_arg, pcb, p, ip_current_src_addr(), src);
|
||||
#if LWIP_IPV6
|
||||
if (pcb->isipv6) {
|
||||
pcb->recv.ip6(pcb->recv_arg, pcb, p, ip6_current_src_addr(), src);
|
||||
}
|
||||
else
|
||||
#endif /* LWIP_IPV6 */
|
||||
{
|
||||
pcb->recv.ip4(pcb->recv_arg, pcb, p, ip_current_src_addr(), src);
|
||||
}
|
||||
} else {
|
||||
/* no recv function registered? then we have to free the pbuf! */
|
||||
pbuf_free(p);
|
||||
@@ -336,17 +462,33 @@ udp_input(struct pbuf *p, struct netif *inp)
|
||||
} else {
|
||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: not for us.\n"));
|
||||
|
||||
#if LWIP_ICMP
|
||||
#if LWIP_ICMP || LWIP_ICMP6
|
||||
/* No match was found, send ICMP destination port unreachable unless
|
||||
destination address was broadcast/multicast. */
|
||||
if (!broadcast &&
|
||||
!ip_addr_ismulticast(¤t_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);
|
||||
}
|
||||
#if LWIP_IPV6
|
||||
!ip6_addr_ismulticast(ip6_current_dest_addr()) &&
|
||||
#endif /* LWIP_IPV6 */
|
||||
!ip_addr_ismulticast(ip_current_dest_addr())) {
|
||||
#if LWIP_IPV6 && LWIP_ICMP6
|
||||
if (ip6_current_header() != NULL) {
|
||||
/* move payload pointer back to ip header */
|
||||
pbuf_header(p, ip6_current_header_tot_len() + UDP_HLEN);
|
||||
LWIP_ASSERT("p->payload == ip6_current_header()", (p->payload == ip6_current_header()));
|
||||
icmp6_dest_unreach(p, ICMP6_DUR_PORT);
|
||||
}
|
||||
else
|
||||
#endif /* LWIP_IPV6 && LWIP_ICMP6 */
|
||||
{
|
||||
#if LWIP_ICMP
|
||||
/* move payload pointer back to ip header */
|
||||
pbuf_header(p, (IPH_HL(ip_current_header()) * 4) + UDP_HLEN);
|
||||
LWIP_ASSERT("p->payload == ip_current_header()", (p->payload == ip_current_header()));
|
||||
icmp_dest_unreach(p, ICMP_DUR_PORT);
|
||||
#endif /* LWIP_ICMP */
|
||||
}
|
||||
}
|
||||
#endif /* LWIP_ICMP || LWIP_ICMP6 */
|
||||
UDP_STATS_INC(udp.proterr);
|
||||
UDP_STATS_INC(udp.drop);
|
||||
snmp_inc_udpnoports();
|
||||
@@ -381,7 +523,7 @@ 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);
|
||||
return udp_sendto(pcb, p, &pcb->remote_ip.ip4, pcb->remote_port);
|
||||
}
|
||||
|
||||
#if LWIP_CHECKSUM_ON_COPY
|
||||
@@ -392,7 +534,7 @@ udp_send_chksum(struct udp_pcb *pcb, struct pbuf *p,
|
||||
u8_t have_chksum, u16_t chksum)
|
||||
{
|
||||
/* send to the packet using remote ip and port stored in the pcb */
|
||||
return udp_sendto_chksum(pcb, p, &pcb->remote_ip, pcb->remote_port,
|
||||
return udp_sendto_chksum(pcb, p, &pcb->remote_ip.ip4, pcb->remote_port,
|
||||
have_chksum, chksum);
|
||||
}
|
||||
#endif /* LWIP_CHECKSUM_ON_COPY */
|
||||
@@ -433,16 +575,35 @@ udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip,
|
||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send\n"));
|
||||
|
||||
/* find the outgoing network interface for this packet */
|
||||
#if LWIP_IPV6
|
||||
if (pcb->isipv6) {
|
||||
if (ip6_addr_ismulticast((ip6_addr_t *)dst_ip)) {
|
||||
/* For multicast, find a netif based on source address. */
|
||||
netif = ip6_route(&(pcb->local_ip.ip6), &(pcb->local_ip.ip6));
|
||||
}
|
||||
else {
|
||||
netif = ip6_route(&(pcb->local_ip.ip6), (ip6_addr_t *)dst_ip);
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif /* LWIP_IPV6 */
|
||||
{
|
||||
#if LWIP_IGMP
|
||||
netif = ip_route((ip_addr_ismulticast(dst_ip))?(&(pcb->multicast_ip)):(dst_ip));
|
||||
netif = ip_route((ip_addr_ismulticast(dst_ip))?(&(pcb->multicast_ip)):(dst_ip));
|
||||
#else
|
||||
netif = ip_route(dst_ip);
|
||||
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 %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
|
||||
ip4_addr1_16(dst_ip), ip4_addr2_16(dst_ip), ip4_addr3_16(dst_ip), ip4_addr4_16(dst_ip)));
|
||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: No route to "));
|
||||
if (!pcb->isipv6) {
|
||||
ip_addr_debug_print(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, dst_ip);
|
||||
} else {
|
||||
ip6_addr_debug_print(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, (ip6_addr_t *)dst_ip);
|
||||
}
|
||||
LWIP_DEBUGF(UDP_DEBUG, ("\n"));
|
||||
UDP_STATS_INC(udp.rterr);
|
||||
return ERR_RTE;
|
||||
}
|
||||
@@ -494,7 +655,11 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip,
|
||||
|
||||
#if IP_SOF_BROADCAST
|
||||
/* broadcast filter? */
|
||||
if ( ((pcb->so_options & SOF_BROADCAST) == 0) && ip_addr_isbroadcast(dst_ip, netif) ) {
|
||||
if ( ((pcb->so_options & SOF_BROADCAST) == 0) &&
|
||||
#if LWIP_IPV6
|
||||
!pcb->isipv6 &&
|
||||
#endif /* LWIP_IPV6 */
|
||||
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;
|
||||
@@ -504,7 +669,7 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip,
|
||||
/* 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);
|
||||
err = udp_bind(pcb, &pcb->local_ip.ip4, 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;
|
||||
@@ -544,20 +709,60 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip,
|
||||
|
||||
/* Multicast Loop? */
|
||||
#if LWIP_IGMP
|
||||
if (ip_addr_ismulticast(dst_ip) && ((pcb->flags & UDP_FLAGS_MULTICAST_LOOP) != 0)) {
|
||||
if (((pcb->flags & UDP_FLAGS_MULTICAST_LOOP) != 0) &&
|
||||
#if LWIP_IPV6
|
||||
(
|
||||
#if LWIP_IPV6_MLD
|
||||
(pcb->isipv6 &&
|
||||
ip6_addr_ismulticast((ip6_addr_t*)dst_ip)) ||
|
||||
#endif /* LWIP_IPV6_MLD */
|
||||
(!pcb->isipv6 &&
|
||||
#else /* LWIP_IPV6 */
|
||||
((
|
||||
#endif /* LWIP_IPV6 */
|
||||
ip_addr_ismulticast(dst_ip)))) {
|
||||
q->flags |= PBUF_FLAG_MCASTLOOP;
|
||||
}
|
||||
#endif /* LWIP_IGMP */
|
||||
|
||||
|
||||
/* PCB local address is IP_ANY_ADDR? */
|
||||
if (ip_addr_isany(&pcb->local_ip)) {
|
||||
#if LWIP_IPV6
|
||||
if (pcb->isipv6) {
|
||||
if (ip6_addr_isany(&pcb->local_ip.ip6)) {
|
||||
src_ip =(ip_addr_t *)ip6_select_source_address(netif, (ip6_addr_t *)dst_ip);
|
||||
if (src_ip == NULL) {
|
||||
/* No suitable source address was found. */
|
||||
if (q != p) {
|
||||
/* free the header pbuf */
|
||||
pbuf_free(q);
|
||||
/* p is still referenced by the caller, and will live on */
|
||||
}
|
||||
return ERR_RTE;
|
||||
}
|
||||
} else {
|
||||
/* use UDP PCB local IPv6 address as source address, if still valid. */
|
||||
if (netif_matches_ip6_addr(netif, &(pcb->local_ip.ip6)) < 0) {
|
||||
/* Address isn't valid anymore. */
|
||||
if (q != p) {
|
||||
/* free the header pbuf */
|
||||
pbuf_free(q);
|
||||
/* p is still referenced by the caller, and will live on */
|
||||
}
|
||||
return ERR_RTE;
|
||||
}
|
||||
src_ip = (ip_addr_t *)&(pcb->local_ip.ip6);
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif /* LWIP_IPV6 */
|
||||
if (ip_addr_isany(&pcb->local_ip.ip4)) {
|
||||
/* 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))) {
|
||||
if (!ip_addr_cmp(&(pcb->local_ip.ip4), &(netif->ip_addr))) {
|
||||
/* local_ip doesn't match, drop the packet */
|
||||
if (q != p) {
|
||||
/* free the header pbuf */
|
||||
@@ -568,7 +773,7 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip,
|
||||
return ERR_VAL;
|
||||
}
|
||||
/* use UDP PCB local IP address as source address */
|
||||
src_ip = &(pcb->local_ip);
|
||||
src_ip = &(pcb->local_ip.ip4);
|
||||
}
|
||||
|
||||
LWIP_DEBUGF(UDP_DEBUG, ("udp_send: sending datagram of length %"U16_F"\n", q->tot_len));
|
||||
@@ -595,31 +800,64 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip,
|
||||
}
|
||||
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,
|
||||
#if !LWIP_CHECKSUM_ON_COPY
|
||||
chklen);
|
||||
#else /* !LWIP_CHECKSUM_ON_COPY */
|
||||
(have_chksum ? UDP_HLEN : chklen));
|
||||
if (have_chksum) {
|
||||
u32_t acc;
|
||||
acc = udphdr->chksum + (u16_t)~(chksum);
|
||||
udphdr->chksum = FOLD_U32T(acc);
|
||||
}
|
||||
#endif /* !LWIP_CHECKSUM_ON_COPY */
|
||||
#if LWIP_IPV6
|
||||
/* Checksum is mandatory for IPv6. */
|
||||
if (pcb->isipv6) {
|
||||
udphdr->chksum = ip6_chksum_pseudo_partial(q, (ip6_addr_t *)src_ip, (ip6_addr_t *)dst_ip,
|
||||
IP6_NEXTH_UDPLITE, q->tot_len,
|
||||
#if !LWIP_CHECKSUM_ON_COPY
|
||||
chklen);
|
||||
#else /* !LWIP_CHECKSUM_ON_COPY */
|
||||
(have_chksum ? UDP_HLEN : chklen));
|
||||
if (have_chksum) {
|
||||
u32_t acc;
|
||||
acc = udphdr->chksum + (u16_t)~(chksum);
|
||||
udphdr->chksum = FOLD_U32T(acc);
|
||||
}
|
||||
#endif /* !LWIP_CHECKSUM_ON_COPY */
|
||||
|
||||
/* chksum zero must become 0xffff, as zero means 'no checksum' */
|
||||
if (udphdr->chksum == 0x0000) {
|
||||
udphdr->chksum = 0xffff;
|
||||
/* chksum zero must become 0xffff, as zero means 'no checksum' */
|
||||
if (udphdr->chksum == 0x0000) {
|
||||
udphdr->chksum = 0xffff;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif /* LWIP_IPV6 */
|
||||
{
|
||||
#if CHECKSUM_GEN_UDP
|
||||
udphdr->chksum = inet_chksum_pseudo_partial(q, src_ip, dst_ip,
|
||||
IP_PROTO_UDPLITE, q->tot_len,
|
||||
#if !LWIP_CHECKSUM_ON_COPY
|
||||
chklen);
|
||||
#else /* !LWIP_CHECKSUM_ON_COPY */
|
||||
(have_chksum ? UDP_HLEN : chklen));
|
||||
if (have_chksum) {
|
||||
u32_t acc;
|
||||
acc = udphdr->chksum + (u16_t)~(chksum);
|
||||
udphdr->chksum = FOLD_U32T(acc);
|
||||
}
|
||||
#endif /* !LWIP_CHECKSUM_ON_COPY */
|
||||
|
||||
/* chksum zero must become 0xffff, as zero means 'no checksum' */
|
||||
if (udphdr->chksum == 0x0000) {
|
||||
udphdr->chksum = 0xffff;
|
||||
}
|
||||
#endif /* CHECKSUM_GEN_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_IPV6
|
||||
if (pcb->isipv6) {
|
||||
err = ip6_output_if(q, (ip6_addr_t*)src_ip, (ip6_addr_t*)dst_ip, pcb->ttl, pcb->tos, IP6_NEXTH_UDPLITE, netif);
|
||||
}
|
||||
else
|
||||
#endif /* LWIP_IPV6 */
|
||||
{
|
||||
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*/
|
||||
@@ -629,20 +867,21 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip,
|
||||
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) {
|
||||
#if LWIP_IPV6
|
||||
/* Checksum is mandatory over IPv6. */
|
||||
if (pcb->isipv6) {
|
||||
u16_t udpchksum;
|
||||
#if LWIP_CHECKSUM_ON_COPY
|
||||
if (have_chksum) {
|
||||
u32_t acc;
|
||||
udpchksum = inet_chksum_pseudo_partial(q, src_ip, dst_ip, IP_PROTO_UDP,
|
||||
udpchksum = ip6_chksum_pseudo_partial(q, (ip6_addr_t*)src_ip, (ip6_addr_t*)dst_ip, IP6_NEXTH_UDP,
|
||||
q->tot_len, UDP_HLEN);
|
||||
acc = udpchksum + (u16_t)~(chksum);
|
||||
udpchksum = FOLD_U32T(acc);
|
||||
} else
|
||||
#endif /* LWIP_CHECKSUM_ON_COPY */
|
||||
{
|
||||
udpchksum = inet_chksum_pseudo(q, src_ip, dst_ip, IP_PROTO_UDP, q->tot_len);
|
||||
udpchksum = ip6_chksum_pseudo(q, (ip6_addr_t*)src_ip, (ip6_addr_t*)dst_ip, IP6_NEXTH_UDP, q->tot_len);
|
||||
}
|
||||
|
||||
/* chksum zero must become 0xffff, as zero means 'no checksum' */
|
||||
@@ -651,14 +890,48 @@ udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip,
|
||||
}
|
||||
udphdr->chksum = udpchksum;
|
||||
}
|
||||
else
|
||||
#endif /* LWIP_IPV6 */
|
||||
{
|
||||
#if CHECKSUM_GEN_UDP
|
||||
if ((pcb->flags & UDP_FLAGS_NOCHKSUM) == 0) {
|
||||
u16_t udpchksum;
|
||||
#if LWIP_CHECKSUM_ON_COPY
|
||||
if (have_chksum) {
|
||||
u32_t acc;
|
||||
udpchksum = inet_chksum_pseudo_partial(q, src_ip, dst_ip, IP_PROTO_UDP,
|
||||
q->tot_len, UDP_HLEN);
|
||||
acc = udpchksum + (u16_t)~(chksum);
|
||||
udpchksum = FOLD_U32T(acc);
|
||||
} else
|
||||
#endif /* LWIP_CHECKSUM_ON_COPY */
|
||||
{
|
||||
udpchksum = 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 (udpchksum == 0x0000) {
|
||||
udpchksum = 0xffff;
|
||||
}
|
||||
udphdr->chksum = udpchksum;
|
||||
}
|
||||
#endif /* CHECKSUM_GEN_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_IPV6
|
||||
if (pcb->isipv6) {
|
||||
err = ip6_output_if(q, (ip6_addr_t*)src_ip, (ip6_addr_t*)dst_ip, pcb->ttl, pcb->tos, IP6_NEXTH_UDP, netif);
|
||||
}
|
||||
else
|
||||
#endif /* LWIP_IPV6 */
|
||||
{
|
||||
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*/
|
||||
@@ -704,7 +977,11 @@ udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
|
||||
u8_t rebind;
|
||||
|
||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_bind(ipaddr = "));
|
||||
ip_addr_debug_print(UDP_DEBUG, ipaddr);
|
||||
if (!pcb->isipv6) {
|
||||
ip_addr_debug_print(UDP_DEBUG | LWIP_DBG_TRACE, ipaddr);
|
||||
} else {
|
||||
ip6_addr_debug_print(UDP_DEBUG | LWIP_DBG_TRACE, (ip6_addr_t *)ipaddr);
|
||||
}
|
||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, (", port = %"U16_F")\n", port));
|
||||
|
||||
rebind = 0;
|
||||
@@ -730,9 +1007,20 @@ udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
|
||||
#endif /* SO_REUSE */
|
||||
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))) {
|
||||
#if LWIP_IPV6
|
||||
((pcb->isipv6 &&
|
||||
ipcb->isipv6 &&
|
||||
(ip6_addr_isany(&(ipcb->local_ip.ip6)) ||
|
||||
ip6_addr_isany((ip6_addr_t *)ipaddr) ||
|
||||
ip6_addr_cmp(&(ipcb->local_ip.ip6), (ip6_addr_t *)ipaddr))) ||
|
||||
(!pcb->isipv6 &&
|
||||
!ipcb->isipv6 &&
|
||||
#else /* LWIP_IPV6 */
|
||||
((
|
||||
#endif /* LWIP_IPV6 */
|
||||
(ip_addr_isany(&(ipcb->local_ip.ip4)) ||
|
||||
ip_addr_isany(ipaddr) ||
|
||||
ip_addr_cmp(&(ipcb->local_ip.ip4), 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));
|
||||
@@ -741,7 +1029,15 @@ udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
|
||||
}
|
||||
}
|
||||
|
||||
ip_addr_set(&pcb->local_ip, ipaddr);
|
||||
#if LWIP_IPV6
|
||||
if (pcb->isipv6) {
|
||||
ip6_addr_set(&pcb->local_ip.ip6, (ip6_addr_t *)ipaddr);
|
||||
}
|
||||
else
|
||||
#endif /* LWIP_IPV6 */
|
||||
{
|
||||
ip_addr_set(&pcb->local_ip.ip4, ipaddr);
|
||||
}
|
||||
|
||||
/* no port specified? */
|
||||
if (port == 0) {
|
||||
@@ -778,11 +1074,13 @@ udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
|
||||
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",
|
||||
ip4_addr1_16(&pcb->local_ip), ip4_addr2_16(&pcb->local_ip),
|
||||
ip4_addr3_16(&pcb->local_ip), ip4_addr4_16(&pcb->local_ip),
|
||||
pcb->local_port));
|
||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("udp_bind: bound to "));
|
||||
if (!pcb->isipv6) {
|
||||
ip_addr_debug_print(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, &pcb->local_ip.ip4);
|
||||
} else {
|
||||
ip6_addr_debug_print(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, &pcb->local_ip.ip6);
|
||||
}
|
||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (", port %"U16_F")\n", pcb->local_port));
|
||||
return ERR_OK;
|
||||
}
|
||||
/**
|
||||
@@ -808,39 +1106,54 @@ udp_connect(struct udp_pcb *pcb, ip_addr_t *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);
|
||||
err_t err = udp_bind(pcb, &pcb->local_ip.ip4, pcb->local_port);
|
||||
if (err != ERR_OK) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
ip_addr_set(&pcb->remote_ip, ipaddr);
|
||||
#if LWIP_IPV6
|
||||
if (pcb->isipv6) {
|
||||
ip6_addr_set(&pcb->remote_ip.ip6, (ip6_addr_t *)ipaddr);
|
||||
}
|
||||
else
|
||||
#endif /* LWIP_IPV6 */
|
||||
{
|
||||
ip_addr_set(&pcb->remote_ip.ip4, 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 LWIP_IPV6
|
||||
if (!pcb->isipv6)
|
||||
#endif /* LWIP_IPV6 */
|
||||
{
|
||||
/* Nail down local IP for netconn_addr()/getsockname() */
|
||||
if (ip_addr_isany(&pcb->local_ip.ip4) && !ip_addr_isany(&pcb->remote_ip.ip4)) {
|
||||
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;
|
||||
if ((netif = ip_route(&(pcb->remote_ip.ip4))) == NULL) {
|
||||
LWIP_DEBUGF(UDP_DEBUG, ("udp_connect: No route to 0x%lx\n", pcb->remote_ip.ip4.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.ip4 = netif->ip_addr;
|
||||
} else if (ip_addr_isany(&pcb->remote_ip.ip4)) {
|
||||
pcb->local_ip.ip4.addr = 0;
|
||||
}
|
||||
/** 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",
|
||||
ip4_addr1_16(&pcb->local_ip), ip4_addr2_16(&pcb->local_ip),
|
||||
ip4_addr3_16(&pcb->local_ip), ip4_addr4_16(&pcb->local_ip),
|
||||
pcb->local_port));
|
||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("udp_connect: connected to "));
|
||||
if (!pcb->isipv6) {
|
||||
ip_addr_debug_print(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, &pcb->remote_ip.ip4);
|
||||
} else {
|
||||
ip6_addr_debug_print(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, &pcb->remote_ip.ip6);
|
||||
}
|
||||
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (", port %"U16_F")\n", pcb->remote_port));
|
||||
|
||||
/* Insert UDP PCB into the list of active UDP PCBs. */
|
||||
for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) {
|
||||
@@ -864,7 +1177,15 @@ void
|
||||
udp_disconnect(struct udp_pcb *pcb)
|
||||
{
|
||||
/* reset remote address association */
|
||||
ip_addr_set_any(&pcb->remote_ip);
|
||||
#if LWIP_IPV6
|
||||
if (pcb->isipv6) {
|
||||
ip6_addr_set_any(&pcb->remote_ip.ip6);
|
||||
}
|
||||
else
|
||||
#endif /* LWIP_IPV6 */
|
||||
{
|
||||
ip_addr_set_any(&pcb->remote_ip.ip4);
|
||||
}
|
||||
pcb->remote_port = 0;
|
||||
/* mark PCB as unconnected */
|
||||
pcb->flags &= ~UDP_FLAGS_CONNECTED;
|
||||
@@ -883,7 +1204,7 @@ void
|
||||
udp_recv(struct udp_pcb *pcb, udp_recv_fn recv, void *recv_arg)
|
||||
{
|
||||
/* remember recv() callback and user data */
|
||||
pcb->recv = recv;
|
||||
pcb->recv.ip4 = recv;
|
||||
pcb->recv_arg = recv_arg;
|
||||
}
|
||||
|
||||
@@ -943,6 +1264,28 @@ udp_new(void)
|
||||
return pcb;
|
||||
}
|
||||
|
||||
#if LWIP_IPV6
|
||||
/**
|
||||
* Create a UDP PCB for IPv6.
|
||||
*
|
||||
* @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_ip6(void)
|
||||
{
|
||||
struct udp_pcb *pcb;
|
||||
pcb = udp_new();
|
||||
/* could allocate UDP PCB? */
|
||||
if (pcb != NULL) {
|
||||
pcb->isipv6 = 1;
|
||||
}
|
||||
return pcb;
|
||||
}
|
||||
#endif /* LWIP_IPV6 */
|
||||
|
||||
#if UDP_DEBUG
|
||||
/**
|
||||
* Print UDP header information for debug purposes.
|
||||
|
||||
Reference in New Issue
Block a user