... 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:
goldsimon
2011-05-17 19:35:14 +00:00
parent f3c1686a40
commit 4bfbe7ebeb
40 changed files with 3930 additions and 978 deletions

View File

@@ -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();

View File

@@ -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(&current_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(&current_iphdr_dest, inp)) {
if (ip_addr_isbroadcast(ip_current_dest_addr(), inp)) {
accepted = 0;
}
#endif /* LWIP_BROADCAST_PING */

View File

@@ -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 */

View File

@@ -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;

View File

@@ -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, &current_iphdr_dest);
break;
#endif /* LWIP_IGMP */

View File

@@ -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 */

View File

@@ -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 */

File diff suppressed because it is too large Load Diff

View File

@@ -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 */

View File

@@ -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>

View File

@@ -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 */

View File

@@ -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), &current_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(&current_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 */

View File

@@ -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*

View File

@@ -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(&current_iphdr_dest, inp) ||
ip_addr_ismulticast(&current_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), &current_iphdr_src) &&
ip_addr_cmp(&(pcb->local_ip), &current_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), &current_iphdr_src) &&
ip_addr_cmp(&(pcb->local_ip), &current_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), &current_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), &current_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);

View File

@@ -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);

View File

@@ -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 */

View File

@@ -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(&current_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), &current_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), &current_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(&current_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), &current_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, &current_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, &current_iphdr_src, &current_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(&current_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), &current_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(&current_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(&current_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.