#include "lwip/netif.h"
#include "lwip/raw.h"
#include "lwip/stats.h"
-#include "arch/perf.h"
#include "lwip/ip6.h"
#include "lwip/ip6_addr.h"
+#include "lwip/inet_chksum.h"
#include <string.h>
raw_input(struct pbuf *p, struct netif *inp)
{
struct raw_pcb *pcb, *prev;
- 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;
#if LWIP_IPV6
- if (IPH_V(iphdr) == 6) {
- ip6hdr = (struct ip6_hdr *)p->payload;
+#if LWIP_IPV4
+ if (IP_HDR_GET_VERSION(p->payload) == 6)
+#endif /* LWIP_IPV4 */
+ {
+ struct ip6_hdr *ip6hdr = (struct ip6_hdr *)p->payload;
proto = IP6H_NEXTH(ip6hdr);
}
+#if LWIP_IPV4
else
+#endif /* LWIP_IPV4 */
#endif /* LWIP_IPV6 */
+#if LWIP_IPV4
{
- proto = IPH_PROTO(iphdr);
+ proto = IPH_PROTO((struct ip_hdr *)p->payload);
}
+#endif /* LWIP_IPV4 */
prev = NULL;
pcb = raw_pcbs;
/* this allows multiple pcbs to match against the packet by design */
while ((eaten == 0) && (pcb != NULL)) {
if ((pcb->protocol == proto) && IP_PCB_IPVER_INPUT_MATCH(pcb) &&
- (ipX_addr_isany(PCB_ISIPV6(pcb), &pcb->local_ip) ||
- ipX_addr_cmp(PCB_ISIPV6(pcb), &(pcb->local_ip), ipX_current_dest_addr()))) {
+ (ip_addr_isany(&pcb->local_ip) ||
+ ip_addr_cmp(&pcb->local_ip, ip_current_dest_addr()))) {
#if IP_SOF_BROADCAST_RECV
/* broadcast filter? */
- if (((pcb->so_options & SOF_BROADCAST) || !ip_addr_isbroadcast(ip_current_dest_addr(), inp))
+ if ((ip_get_option(pcb, SOF_BROADCAST) || !ip_addr_isbroadcast(ip_current_dest_addr(), ip_current_netif()))
#if LWIP_IPV6
- && !PCB_ISIPV6(pcb)
+ || PCB_ISIPV6(pcb)
#endif /* LWIP_IPV6 */
)
#endif /* IP_SOF_BROADCAST_RECV */
{
/* receive callback function available? */
- if (pcb->recv.ip4 != NULL) {
+ if (pcb->recv != NULL) {
+#ifndef LWIP_NOASSERT
+ void* old_payload = p->payload;
+#endif
/* the receive callback function did not eat the packet? */
- eaten = pcb->recv.ip4(pcb->recv_arg, pcb, p, ip_current_src_addr());
+ eaten = pcb->recv(pcb->recv_arg, pcb, p, ip_current_src_addr());
if (eaten != 0) {
/* receive function ate the packet */
p = NULL;
pcb->next = raw_pcbs;
raw_pcbs = pcb;
}
+ } else {
+ /* sanity-check that the receive callback did not alter the pbuf */
+ LWIP_ASSERT("raw pcb recv callback altered pbuf payload pointer without eating packet",
+ p->payload == old_payload);
}
}
/* no receive callback function was set for this raw PCB */
* bind to all local interfaces.
*
* @return lwIP error code.
- * - ERR_OK. Successful. No error occured.
+ * - ERR_OK. Successful. No error occurred.
* - ERR_USE. The specified IP address is already bound to by
* another RAW PCB.
*
* @see raw_disconnect()
*/
err_t
-raw_bind(struct raw_pcb *pcb, ip_addr_t *ipaddr)
+raw_bind(struct raw_pcb *pcb, const ip_addr_t *ipaddr)
{
- ipX_addr_set_ipaddr(PCB_ISIPV6(pcb), &pcb->local_ip, ipaddr);
+ if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH(pcb, ipaddr)) {
+ return ERR_VAL;
+ }
+ ip_addr_set_ipaddr(&pcb->local_ip, ipaddr);
return ERR_OK;
}
* @see raw_disconnect() and raw_sendto()
*/
err_t
-raw_connect(struct raw_pcb *pcb, ip_addr_t *ipaddr)
+raw_connect(struct raw_pcb *pcb, const ip_addr_t *ipaddr)
{
- ipX_addr_set_ipaddr(PCB_ISIPV6(pcb), &pcb->remote_ip, ipaddr);
+ if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH(pcb, ipaddr)) {
+ return ERR_VAL;
+ }
+ ip_addr_set_ipaddr(&pcb->remote_ip, ipaddr);
return ERR_OK;
}
-
/**
* Set the callback function for received packets that match the
- * raw PCB's protocol and binding.
- *
+ * raw PCB's protocol and binding.
+ *
* The callback function MUST either
* - eat the packet by calling pbuf_free() and returning non-zero. The
* packet will not be passed to other raw PCBs or other protocol layers.
* - not free the packet, and return zero. The packet will be matched
* against further PCBs and/or forwarded to another protocol layers.
- *
+ *
* @return non-zero if the packet was free()d, zero if the packet remains
* available for others.
*/
raw_recv(struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg)
{
/* remember recv() callback and user data */
- pcb->recv.ip4 = recv;
+ pcb->recv = recv;
pcb->recv_arg = recv_arg;
}
*
*/
err_t
-raw_sendto(struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr)
+raw_sendto(struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *ipaddr)
{
err_t err;
struct netif *netif;
- ipX_addr_t *src_ip;
+ const ip_addr_t *src_ip;
struct pbuf *q; /* q will be sent down the stack */
s16_t header_size;
- ipX_addr_t *dst_ip = ip_2_ipX(ipaddr);
+ const ip_addr_t *dst_ip = ipaddr;
+
+ if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH(pcb, ipaddr)) {
+ return ERR_VAL;
+ }
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_sendto\n"));
header_size = (
-#if LWIP_IPV6
- PCB_ISIPV6(pcb) ? IP6_HLEN :
-#endif /* LWIP_IPV6 */
+#if LWIP_IPV4 && LWIP_IPV6
+ PCB_ISIPV6(pcb) ? IP6_HLEN : IP_HLEN);
+#elif LWIP_IPV4
IP_HLEN);
+#else
+ IP6_HLEN);
+#endif
/* not enough space to add an IP header to first pbuf in given p chain? */
if (pbuf_header(p, header_size)) {
}
/* { 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 {
+ } else {
/* first pbuf q equals given pbuf */
q = p;
- if(pbuf_header(q, -header_size)) {
+ if (pbuf_header(q, -header_size)) {
LWIP_ASSERT("Can't restore header we just removed!", 0);
return ERR_MEM;
}
}
- netif = ipX_route(PCB_ISIPV6(pcb), &pcb->local_ip, dst_ip);
+ netif = ip_route(PCB_ISIPV6(pcb), &pcb->local_ip, dst_ip);
if (netif == NULL) {
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: No route to "));
- ipX_addr_debug_print(PCB_ISIPV6(pcb), RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, dst_ip);
+ ip_addr_debug_print(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, dst_ip);
/* free any temporary header pbuf allocated by pbuf_header() */
if (q != p) {
pbuf_free(q);
#if IP_SOF_BROADCAST
#if LWIP_IPV6
- /* @todo: why does IPv6 not filter broadcast with SOF_BROADCAST enabled? */
if (!PCB_ISIPV6(pcb))
#endif /* LWIP_IPV6 */
{
/* broadcast filter? */
- if (((pcb->so_options & SOF_BROADCAST) == 0) && ip_addr_isbroadcast(ipaddr, netif)) {
+ if (!ip_get_option(pcb, SOF_BROADCAST) && 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) {
}
#endif /* IP_SOF_BROADCAST */
- if (ipX_addr_isany(PCB_ISIPV6(pcb), &pcb->local_ip)) {
+ if (ip_addr_isany(&pcb->local_ip)) {
/* use outgoing network interface IP address as source address */
- src_ip = ipX_netif_get_local_ipX(PCB_ISIPV6(pcb), netif, dst_ip);
+ src_ip = ip_netif_get_local_ip(PCB_ISIPV6(pcb), netif, dst_ip);
#if LWIP_IPV6
if (src_ip == NULL) {
if (q != p) {
src_ip = &pcb->local_ip;
}
+#if LWIP_IPV6
+ /* If requested, based on the IPV6_CHECKSUM socket option per RFC3542,
+ compute the checksum and update the checksum in the payload. */
+ if (PCB_ISIPV6(pcb) && pcb->chksum_reqd) {
+ u16_t chksum = ip6_chksum_pseudo(p, pcb->protocol, p->tot_len, ip_2_ip6(src_ip), ip_2_ip6(dst_ip));
+ LWIP_ASSERT("Checksum must fit into first pbuf", p->len >= (pcb->chksum_offset + 2));
+ SMEMCPY(((u8_t *)p->payload) + pcb->chksum_offset, &chksum, sizeof(u16_t));
+ }
+#endif
+
NETIF_SET_HWADDRHINT(netif, &pcb->addr_hint);
- err = ipX_output_if(PCB_ISIPV6(pcb), q, ipX_2_ip(src_ip), ipX_2_ip(dst_ip), pcb->ttl, pcb->tos, pcb->protocol, netif);
+ err = ip_output_if(PCB_ISIPV6(pcb), q, src_ip, dst_ip, pcb->ttl, pcb->tos, pcb->protocol, netif);
NETIF_SET_HWADDRHINT(netif, NULL);
/* did we chain a header earlier? */
err_t
raw_send(struct raw_pcb *pcb, struct pbuf *p)
{
- return raw_sendto(pcb, p, ipX_2_ip(&pcb->remote_ip));
+ return raw_sendto(pcb, p, &pcb->remote_ip);
}
/**
raw_pcbs = raw_pcbs->next;
/* pcb not 1st in list */
} else {
- for(pcb2 = raw_pcbs; pcb2 != NULL; pcb2 = pcb2->next) {
+ for (pcb2 = raw_pcbs; pcb2 != NULL; pcb2 = pcb2->next) {
/* find pcb in raw_pcbs list */
if (pcb2->next != NULL && pcb2->next == pcb) {
/* remove pcb from list */
{
struct raw_pcb *pcb;
pcb = raw_new(proto);
+#if LWIP_IPV4
ip_set_v6(pcb, 1);
+#endif /* LWIP_IPV4 */
return pcb;
}
#endif /* LWIP_IPV6 */