summaryrefslogtreecommitdiff
path: root/linux/net/ipsec/ipsec_xmit.c
diff options
context:
space:
mode:
Diffstat (limited to 'linux/net/ipsec/ipsec_xmit.c')
-rw-r--r--linux/net/ipsec/ipsec_xmit.c1782
1 files changed, 0 insertions, 1782 deletions
diff --git a/linux/net/ipsec/ipsec_xmit.c b/linux/net/ipsec/ipsec_xmit.c
deleted file mode 100644
index bb390bcf9..000000000
--- a/linux/net/ipsec/ipsec_xmit.c
+++ /dev/null
@@ -1,1782 +0,0 @@
-/*
- * IPSEC Transmit code.
- * Copyright (C) 1996, 1997 John Ioannidis.
- * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Richard Guy Briggs.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-char ipsec_xmit_c_version[] = "RCSID $Id: ipsec_xmit.c,v 1.3 2004/06/13 19:37:23 as Exp $";
-
-#define __NO_VERSION__
-#include <linux/module.h>
-#include <linux/config.h> /* for CONFIG_IP_FORWARD */
-#include <linux/version.h>
-#include <linux/kernel.h> /* printk() */
-
-#include "freeswan/ipsec_param.h"
-
-#ifdef MALLOC_SLAB
-# include <linux/slab.h> /* kmalloc() */
-#else /* MALLOC_SLAB */
-# include <linux/malloc.h> /* kmalloc() */
-#endif /* MALLOC_SLAB */
-#include <linux/errno.h> /* error codes */
-#include <linux/types.h> /* size_t */
-#include <linux/interrupt.h> /* mark_bh */
-
-#include <linux/netdevice.h> /* struct device, struct net_device_stats, dev_queue_xmit() and other headers */
-#include <linux/etherdevice.h> /* eth_type_trans */
-#include <linux/ip.h> /* struct iphdr */
-#include <linux/tcp.h> /* struct tcphdr */
-#include <linux/udp.h> /* struct udphdr */
-#include <linux/skbuff.h>
-#include <freeswan.h>
-#ifdef NET_21
-# define MSS_HACK_ /* experimental */
-# include <asm/uaccess.h>
-# include <linux/in6.h>
-# include <net/dst.h>
-# define proto_priv cb
-#endif /* NET_21 */
-#include <asm/checksum.h>
-#include <net/icmp.h> /* icmp_send() */
-#include <net/ip.h>
-#ifdef NETDEV_23
-# include <linux/netfilter_ipv4.h>
-#endif /* NETDEV_23 */
-
-#include <linux/if_arp.h>
-#ifdef MSS_HACK
-# include <net/tcp.h> /* TCP options */
-#endif /* MSS_HACK */
-
-#include "freeswan/radij.h"
-#include "freeswan/ipsec_life.h"
-#include "freeswan/ipsec_xform.h"
-#include "freeswan/ipsec_eroute.h"
-#include "freeswan/ipsec_encap.h"
-#include "freeswan/ipsec_radij.h"
-#include "freeswan/ipsec_xmit.h"
-#include "freeswan/ipsec_sa.h"
-#include "freeswan/ipsec_tunnel.h"
-#include "freeswan/ipsec_ipe4.h"
-#include "freeswan/ipsec_ah.h"
-#include "freeswan/ipsec_esp.h"
-
-#ifdef CONFIG_IPSEC_IPCOMP
-#include "freeswan/ipcomp.h"
-#endif /* CONFIG_IPSEC_IPCOMP */
-
-#include <pfkeyv2.h>
-#include <pfkey.h>
-
-#include "freeswan/ipsec_proto.h"
-#include "freeswan/ipsec_alg.h"
-
-
-/*
- * Stupid kernel API differences in APIs. Not only do some
- * kernels not have ip_select_ident, but some have differing APIs,
- * and SuSE has one with one parameter, but no way of checking to
- * see what is really what.
- */
-
-#ifdef SUSE_LINUX_2_4_19_IS_STUPID
-#define KLIPS_IP_SELECT_IDENT(iph, skb) ip_select_ident(iph)
-#else
-
-/* simplest case, nothing */
-#if !defined(IP_SELECT_IDENT)
-#define KLIPS_IP_SELECT_IDENT(iph, skb) do { iph->id = htons(ip_id_count++); } while(0)
-#endif
-
-/* kernels > 2.3.37-ish */
-#if defined(IP_SELECT_IDENT) && !defined(IP_SELECT_IDENT_NEW)
-#define KLIPS_IP_SELECT_IDENT(iph, skb) ip_select_ident(iph, skb->dst)
-#endif
-
-/* kernels > 2.4.2 */
-#if defined(IP_SELECT_IDENT) && defined(IP_SELECT_IDENT_NEW)
-#define KLIPS_IP_SELECT_IDENT(iph, skb) ip_select_ident(iph, skb->dst, NULL)
-#endif
-
-#endif /* SUSE_LINUX_2_4_19_IS_STUPID */
-
-
-static __u32 zeroes[64];
-
-#ifdef CONFIG_IPSEC_DEBUG
-int sysctl_ipsec_debug_verbose = 0;
-#endif /* CONFIG_IPSEC_DEBUG */
-
-int ipsec_xmit_trap_count = 0;
-int ipsec_xmit_trap_sendcount = 0;
-
-int sysctl_ipsec_icmp = 0;
-int sysctl_ipsec_tos = 0;
-
-/*
- * If the IP packet (iph) is a carrying TCP/UDP, then set the encaps
- * source and destination ports to those from the TCP/UDP header.
- */
-void ipsec_extract_ports(struct iphdr * iph, struct sockaddr_encap * er)
-{
- struct udphdr *udp;
-
- switch (iph->protocol) {
- case IPPROTO_UDP:
- case IPPROTO_TCP:
- /*
- * The ports are at the same offsets in a TCP and UDP
- * header so hack it ...
- */
- udp = (struct udphdr*)(((char*)iph)+(iph->ihl<<2));
- er->sen_sport = udp->source;
- er->sen_dport = udp->dest;
- break;
- default:
- er->sen_sport = 0;
- er->sen_dport = 0;
- break;
- }
-}
-
-/*
- * A TRAP eroute is installed and we want to replace it with a HOLD
- * eroute.
- */
-static int create_hold_eroute(struct sk_buff * skb, struct iphdr * iph,
- uint32_t eroute_pid)
-{
- struct eroute hold_eroute;
- struct sa_id hold_said;
- struct sk_buff *first, *last;
- int error;
-
- first = last = NULL;
- memset((caddr_t)&hold_eroute, 0, sizeof(hold_eroute));
- memset((caddr_t)&hold_said, 0, sizeof(hold_said));
-
- hold_said.proto = IPPROTO_INT;
- hold_said.spi = htonl(SPI_HOLD);
- hold_said.dst.s_addr = INADDR_ANY;
-
- hold_eroute.er_eaddr.sen_len = sizeof(struct sockaddr_encap);
- hold_eroute.er_emask.sen_len = sizeof(struct sockaddr_encap);
- hold_eroute.er_eaddr.sen_family = AF_ENCAP;
- hold_eroute.er_emask.sen_family = AF_ENCAP;
- hold_eroute.er_eaddr.sen_type = SENT_IP4;
- hold_eroute.er_emask.sen_type = 255;
-
- hold_eroute.er_eaddr.sen_ip_src.s_addr = iph->saddr;
- hold_eroute.er_eaddr.sen_ip_dst.s_addr = iph->daddr;
- hold_eroute.er_emask.sen_ip_src.s_addr = INADDR_BROADCAST;
- hold_eroute.er_emask.sen_ip_dst.s_addr = INADDR_BROADCAST;
- hold_eroute.er_emask.sen_sport = ~0;
- hold_eroute.er_emask.sen_dport = ~0;
- hold_eroute.er_pid = eroute_pid;
- hold_eroute.er_count = 0;
- hold_eroute.er_lasttime = jiffies/HZ;
-
- hold_eroute.er_eaddr.sen_proto = iph->protocol;
- ipsec_extract_ports(iph, &hold_eroute.er_eaddr);
-
-#ifdef CONFIG_IPSEC_DEBUG
- if (debug_pfkey) {
- char buf1[64], buf2[64];
- subnettoa(hold_eroute.er_eaddr.sen_ip_src,
- hold_eroute.er_emask.sen_ip_src, 0, buf1, sizeof(buf1));
- subnettoa(hold_eroute.er_eaddr.sen_ip_dst,
- hold_eroute.er_emask.sen_ip_dst, 0, buf2, sizeof(buf2));
- KLIPS_PRINT(debug_pfkey,
- "klips_debug:ipsec_tunnel_start_xmit: "
- "calling breakeroute and makeroute for %s:%d->%s:%d %d HOLD eroute.\n",
- buf1, ntohs(hold_eroute.er_eaddr.sen_sport),
- buf2, ntohs(hold_eroute.er_eaddr.sen_dport),
- hold_eroute.er_eaddr.sen_proto);
- }
-#endif /* CONFIG_IPSEC_DEBUG */
-
- if (ipsec_breakroute(&(hold_eroute.er_eaddr), &(hold_eroute.er_emask),
- &first, &last)) {
- KLIPS_PRINT(debug_pfkey,
- "klips_debug:ipsec_tunnel_start_xmit: "
- "HOLD breakeroute found nothing.\n");
- } else {
- KLIPS_PRINT(debug_pfkey,
- "klips_debug:ipsec_tunnel_start_xmit: "
- "HOLD breakroute deleted %u.%u.%u.%u:%u -> %u.%u.%u.%u:%u %u\n",
- NIPQUAD(hold_eroute.er_eaddr.sen_ip_src),
- ntohs(hold_eroute.er_eaddr.sen_sport),
- NIPQUAD(hold_eroute.er_eaddr.sen_ip_dst),
- ntohs(hold_eroute.er_eaddr.sen_dport),
- hold_eroute.er_eaddr.sen_proto);
- }
- if (first != NULL)
- kfree_skb(first);
- if (last != NULL)
- kfree_skb(last);
-
- error = ipsec_makeroute(&(hold_eroute.er_eaddr),
- &(hold_eroute.er_emask),
- hold_said, eroute_pid, skb, NULL, NULL);
- if (error) {
- KLIPS_PRINT(debug_pfkey,
- "klips_debug:ipsec_tunnel_start_xmit: "
- "HOLD makeroute returned %d, failed.\n", error);
- } else {
- KLIPS_PRINT(debug_pfkey,
- "klips_debug:ipsec_tunnel_start_xmit: "
- "HOLD makeroute call successful.\n");
- }
- return (error == 0);
-}
-
-#ifdef CONFIG_IPSEC_DEBUG_
-DEBUG_NO_STATIC void
-dmp(char *s, caddr_t bb, int len)
-{
- int i;
- unsigned char *b = bb;
-
- if (debug_tunnel) {
- printk(KERN_INFO "klips_debug:ipsec_tunnel_:dmp: "
- "at %s, len=%d:",
- s,
- len);
- for (i=0; i < len; i++) {
- if(!(i%16)){
- printk("\nklips_debug: ");
- }
- printk(" %02x", *b++);
- }
- printk("\n");
- }
-}
-#else /* CONFIG_IPSEC_DEBUG */
-#define dmp(_x, _y, _z)
-#endif /* CONFIG_IPSEC_DEBUG */
-
-#ifndef SKB_COPY_EXPAND
-/*
- * This is mostly skbuff.c:skb_copy().
- */
-struct sk_buff *
-skb_copy_expand(struct sk_buff *skb, int headroom, int tailroom, int priority)
-{
- struct sk_buff *n;
- unsigned long offset;
-
- /*
- * Do sanity checking
- */
- if((headroom < 0) || (tailroom < 0) || ((headroom+tailroom) < 0)) {
- printk(KERN_WARNING
- "klips_error:skb_copy_expand: "
- "Illegal negative head,tailroom %d,%d\n",
- headroom,
- tailroom);
- return NULL;
- }
- /*
- * Allocate the copy buffer
- */
-
-#ifndef NET_21
- IS_SKB(skb);
-#endif /* !NET_21 */
-
-
- n=alloc_skb(skb->end - skb->head + headroom + tailroom, priority);
-
- KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
- "klips_debug:skb_copy_expand: "
- "allocating %d bytes, head=0p%p data=0p%p tail=0p%p end=0p%p end-head=%d tail-data=%d\n",
- skb->end - skb->head + headroom + tailroom,
- skb->head,
- skb->data,
- skb->tail,
- skb->end,
- skb->end - skb->head,
- skb->tail - skb->data);
-
- if(n==NULL)
- return NULL;
-
- /*
- * Shift between the two data areas in bytes
- */
-
- /* Set the data pointer */
- skb_reserve(n,skb->data-skb->head+headroom);
- /* Set the tail pointer and length */
- if(skb_tailroom(n) < skb->len) {
- printk(KERN_WARNING "klips_error:skb_copy_expand: "
- "tried to skb_put %ld, %d available. This should never happen, please report.\n",
- (unsigned long int)skb->len,
- skb_tailroom(n));
- ipsec_kfree_skb(n);
- return NULL;
- }
- skb_put(n,skb->len);
-
- offset=n->head + headroom - skb->head;
-
- /* Copy the bytes */
- memcpy(n->head + headroom, skb->head,skb->end-skb->head);
-#ifdef NET_21
- n->csum=skb->csum;
- n->priority=skb->priority;
- n->dst=dst_clone(skb->dst);
- if(skb->nh.raw)
- n->nh.raw=skb->nh.raw+offset;
-#ifndef NETDEV_23
- n->is_clone=0;
-#endif /* NETDEV_23 */
- atomic_set(&n->users, 1);
- n->destructor = NULL;
- n->security=skb->security;
-#else /* NET_21 */
- n->link3=NULL;
- n->when=skb->when;
- if(skb->ip_hdr)
- n->ip_hdr=(struct iphdr *)(((char *)skb->ip_hdr)+offset);
- n->saddr=skb->saddr;
- n->daddr=skb->daddr;
- n->raddr=skb->raddr;
- n->seq=skb->seq;
- n->end_seq=skb->end_seq;
- n->ack_seq=skb->ack_seq;
- n->acked=skb->acked;
- n->free=1;
- n->arp=skb->arp;
- n->tries=0;
- n->lock=0;
- n->users=0;
-#endif /* NET_21 */
- n->protocol=skb->protocol;
- n->list=NULL;
- n->sk=NULL;
- n->dev=skb->dev;
- if(skb->h.raw)
- n->h.raw=skb->h.raw+offset;
- if(skb->mac.raw)
- n->mac.raw=skb->mac.raw+offset;
- memcpy(n->proto_priv, skb->proto_priv, sizeof(skb->proto_priv));
-#ifndef NETDEV_23
- n->used=skb->used;
-#endif /* !NETDEV_23 */
- n->pkt_type=skb->pkt_type;
- n->stamp=skb->stamp;
-
-#ifndef NET_21
- IS_SKB(n);
-#endif /* !NET_21 */
- return n;
-}
-#endif /* !SKB_COPY_EXPAND */
-
-#ifdef CONFIG_IPSEC_DEBUG
-void
-ipsec_print_ip(struct iphdr *ip)
-{
- char buf[ADDRTOA_BUF];
-
- printk(KERN_INFO "klips_debug: IP:");
- printk(" ihl:%d", ip->ihl << 2);
- printk(" ver:%d", ip->version);
- printk(" tos:%d", ip->tos);
- printk(" tlen:%d", ntohs(ip->tot_len));
- printk(" id:%d", ntohs(ip->id));
- printk(" %s%s%sfrag_off:%d",
- ip->frag_off & __constant_htons(IP_CE) ? "CE " : "",
- ip->frag_off & __constant_htons(IP_DF) ? "DF " : "",
- ip->frag_off & __constant_htons(IP_MF) ? "MF " : "",
- (ntohs(ip->frag_off) & IP_OFFSET) << 3);
- printk(" ttl:%d", ip->ttl);
- printk(" proto:%d", ip->protocol);
- if(ip->protocol == IPPROTO_UDP)
- printk(" (UDP)");
- if(ip->protocol == IPPROTO_TCP)
- printk(" (TCP)");
- if(ip->protocol == IPPROTO_ICMP)
- printk(" (ICMP)");
- printk(" chk:%d", ntohs(ip->check));
- addrtoa(*((struct in_addr*)(&ip->saddr)), 0, buf, sizeof(buf));
- printk(" saddr:%s", buf);
- if(ip->protocol == IPPROTO_UDP)
- printk(":%d",
- ntohs(((struct udphdr*)((caddr_t)ip + (ip->ihl << 2)))->source));
- if(ip->protocol == IPPROTO_TCP)
- printk(":%d",
- ntohs(((struct tcphdr*)((caddr_t)ip + (ip->ihl << 2)))->source));
- addrtoa(*((struct in_addr*)(&ip->daddr)), 0, buf, sizeof(buf));
- printk(" daddr:%s", buf);
- if(ip->protocol == IPPROTO_UDP)
- printk(":%d",
- ntohs(((struct udphdr*)((caddr_t)ip + (ip->ihl << 2)))->dest));
- if(ip->protocol == IPPROTO_TCP)
- printk(":%d",
- ntohs(((struct tcphdr*)((caddr_t)ip + (ip->ihl << 2)))->dest));
- if(ip->protocol == IPPROTO_ICMP)
- printk(" type:code=%d:%d",
- ((struct icmphdr*)((caddr_t)ip + (ip->ihl << 2)))->type,
- ((struct icmphdr*)((caddr_t)ip + (ip->ihl << 2)))->code);
- printk("\n");
-
- if(sysctl_ipsec_debug_verbose) {
- __u8 *c;
- int i;
-
- c = ((__u8*)ip) + ip->ihl*4;
- for(i = 0; i < ntohs(ip->tot_len) - ip->ihl*4; i++ /*, c++*/) {
- if(!(i % 16)) {
- printk(KERN_INFO
- "klips_debug: @%03x:",
- i);
- }
- printk(" %02x", /***/c[i]);
- if(!((i + 1) % 16)) {
- printk("\n");
- }
- }
- if(i % 16) {
- printk("\n");
- }
- }
-}
-#endif /* CONFIG_IPSEC_DEBUG */
-
-#ifdef MSS_HACK
-/*
- * Issues:
- * 1) Fragments arriving in the tunnel should probably be rejected.
- * 2) How does this affect syncookies, mss_cache, dst cache ?
- * 3) Path MTU discovery handling needs to be reviewed. For example,
- * if we receive an ICMP 'packet too big' message from an intermediate
- * router specifying it's next hop MTU, our stack may process this and
- * adjust the MSS without taking our AH/ESP overheads into account.
- */
-
-
-/*
- * Recaclulate checksum using differences between changed datum,
- * borrowed from netfilter.
- */
-DEBUG_NO_STATIC u_int16_t
-ipsec_fast_csum(u_int32_t oldvalinv, u_int32_t newval, u_int16_t oldcheck)
-{
- u_int32_t diffs[] = { oldvalinv, newval };
- return csum_fold(csum_partial((char *)diffs, sizeof(diffs),
- oldcheck^0xFFFF));
-}
-
-/*
- * Determine effective MSS.
- *
- * Note that we assume that there is always an MSS option for our own
- * SYN segments, which is mentioned in tcp_syn_build_options(), kernel 2.2.x.
- * This could change, and we should probably parse TCP options instead.
- *
- */
-DEBUG_NO_STATIC u_int8_t
-ipsec_adjust_mss(struct sk_buff *skb, struct tcphdr *tcph, u_int16_t mtu)
-{
- u_int16_t oldmss, newmss;
- u_int32_t *mssp;
- struct sock *sk = skb->sk;
-
- newmss = tcp_sync_mss(sk, mtu);
- printk(KERN_INFO "klips: setting mss to %u\n", newmss);
- mssp = (u_int32_t *)tcph + sizeof(struct tcphdr) / sizeof(u_int32_t);
- oldmss = ntohl(*mssp) & 0x0000FFFF;
- *mssp = htonl((TCPOPT_MSS << 24) | (TCPOLEN_MSS << 16) | newmss);
- tcph->check = ipsec_fast_csum(htons(~oldmss),
- htons(newmss), tcph->check);
- return 1;
-}
-#endif /* MSS_HACK */
-
-/*
- * Sanity checks
- */
-enum ipsec_xmit_value
-ipsec_xmit_sanity_check_dev(struct ipsec_xmit_state *ixs)
-{
-
- if (ixs->dev == NULL) {
- KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
- "klips_error:ipsec_xmit_sanity_check_dev: "
- "No device associated with skb!\n" );
- return IPSEC_XMIT_NODEV;
- }
-
- ixs->prv = ixs->dev->priv;
- if (ixs->prv == NULL) {
- KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
- "klips_error:ipsec_xmit_sanity_check_dev: "
- "Device has no private structure!\n" );
- return IPSEC_XMIT_NOPRIVDEV;
- }
-
- ixs->physdev = ixs->prv->dev;
- if (ixs->physdev == NULL) {
- KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
- "klips_error:ipsec_xmit_sanity_check_dev: "
- "Device is not attached to physical device!\n" );
- return IPSEC_XMIT_NOPHYSDEV;
- }
-
- ixs->physmtu = ixs->physdev->mtu;
-
- ixs->stats = (struct net_device_stats *) &(ixs->prv->mystats);
-
- return IPSEC_XMIT_OK;
-}
-
-enum ipsec_xmit_value
-ipsec_xmit_sanity_check_skb(struct ipsec_xmit_state *ixs)
-{
- /*
- * Return if there is nothing to do. (Does this ever happen?) XXX
- */
- if (ixs->skb == NULL) {
- KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
- "klips_error:ipsec_xmit_sanity_check_skb: "
- "Nothing to do!\n" );
- return IPSEC_XMIT_NOSKB;
- }
-#ifdef NET_21
- /* if skb was cloned (most likely due to a packet sniffer such as
- tcpdump being momentarily attached to the interface), make
- a copy of our own to modify */
- if(skb_cloned(ixs->skb)) {
- if
-#ifdef SKB_COW_NEW
- (skb_cow(ixs->skb, skb_headroom(ixs->skb)) != 0)
-#else /* SKB_COW_NEW */
- ((ixs->skb = skb_cow(ixs->skb, skb_headroom(ixs->skb))) == NULL)
-#endif /* SKB_COW_NEW */
- {
- KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
- "klips_error:ipsec_xmit_sanity_check_skb: "
- "skb_cow failed to allocate buffer, dropping.\n" );
- ixs->stats->tx_dropped++;
- return IPSEC_XMIT_ERRSKBALLOC;
- }
- }
-#endif /* NET_21 */
-
-#ifdef NET_21
- ixs->iph = ixs->skb->nh.iph;
-#else /* NET_21 */
- ixs->iph = ixs->skb->ip_hdr;
-#endif /* NET_21 */
-
- /* sanity check for IP version as we can't handle IPv6 right now */
- if (ixs->iph->version != 4) {
- KLIPS_PRINT(debug_tunnel,
- "klips_debug:ipsec_xmit_sanity_check_skb: "
- "found IP Version %d but cannot process other IP versions than v4.\n",
- ixs->iph->version); /* XXX */
- ixs->stats->tx_dropped++;
- return IPSEC_XMIT_NOIPV6;
- }
-
-#if IPSEC_DISALLOW_IPOPTIONS
- if ((ixs->iph->ihl << 2) != sizeof (struct iphdr)) {
- KLIPS_PRINT(debug_tunnel,
- "klips_debug:ipsec_xmit_sanity_check_skb: "
- "cannot process IP header options yet. May be mal-formed packet.\n"); /* XXX */
- ixs->stats->tx_dropped++;
- return IPSEC_XMIT_NOIPOPTIONS;
- }
-#endif /* IPSEC_DISALLOW_IPOPTIONS */
-
-#ifndef NET_21
- if (ixs->iph->ttl <= 0) {
- /* Tell the sender its packet died... */
- ICMP_SEND(ixs->skb, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL, 0, ixs->physdev);
-
- KLIPS_PRINT(debug_tunnel, "klips_debug:ipsec_xmit_sanity_check_skb: "
- "TTL=0, too many hops!\n");
- ixs->stats->tx_dropped++;
- return IPSEC_XMIT_TTLEXPIRED;
- }
-#endif /* !NET_21 */
-
- return IPSEC_XMIT_OK;
-}
-
-enum ipsec_xmit_value
-ipsec_xmit_encap_once(struct ipsec_xmit_state *ixs)
-{
-#ifdef CONFIG_IPSEC_ESP
- struct esphdr *espp;
-#ifdef CONFIG_IPSEC_ENC_3DES
- __u32 iv[ESP_IV_MAXSZ_INT];
-#endif /* !CONFIG_IPSEC_ENC_3DES */
- unsigned char *idat, *pad;
- int authlen = 0, padlen = 0, i;
-#endif /* !CONFIG_IPSEC_ESP */
-#ifdef CONFIG_IPSEC_AH
- struct iphdr ipo;
- struct ahhdr *ahp;
-#endif /* CONFIG_IPSEC_AH */
-#if defined(CONFIG_IPSEC_AUTH_HMAC_MD5) || defined(CONFIG_IPSEC_AUTH_HMAC_SHA1)
- union {
-#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
- MD5_CTX md5;
-#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
-#ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
- SHA1_CTX sha1;
-#endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */
- } tctx;
- __u8 hash[AH_AMAX];
-#endif /* defined(CONFIG_IPSEC_AUTH_HMAC_MD5) || defined(CONFIG_IPSEC_AUTH_HMAC_SHA1) */
- int headroom = 0, tailroom = 0, ilen = 0, len = 0;
- unsigned char *dat;
- int blocksize = 8; /* XXX: should be inside ixs --jjo */
-#ifdef CONFIG_IPSEC_ALG
- struct ipsec_alg_enc *ixt_e = NULL;
- struct ipsec_alg_auth *ixt_a = NULL;
-#endif /* CONFIG_IPSEC_ALG */
-
- ixs->iphlen = ixs->iph->ihl << 2;
- ixs->pyldsz = ntohs(ixs->iph->tot_len) - ixs->iphlen;
- ixs->sa_len = satoa(ixs->ipsp->ips_said, 0, ixs->sa_txt, SATOA_BUF);
- KLIPS_PRINT(debug_tunnel & DB_TN_OXFS,
- "klips_debug:ipsec_xmit_encap_once: "
- "calling output for <%s%s%s>, SA:%s\n",
- IPS_XFORM_NAME(ixs->ipsp),
- ixs->sa_len ? ixs->sa_txt : " (error)");
-
- switch(ixs->ipsp->ips_said.proto) {
-#ifdef CONFIG_IPSEC_AH
- case IPPROTO_AH:
- headroom += sizeof(struct ahhdr);
- break;
-#endif /* CONFIG_IPSEC_AH */
-#ifdef CONFIG_IPSEC_ESP
- case IPPROTO_ESP:
-#ifdef CONFIG_IPSEC_ALG
- if ((ixt_e=ixs->ipsp->ips_alg_enc)) {
- blocksize = ixt_e->ixt_blocksize;
- headroom += ESP_HEADER_LEN + ixt_e->ixt_ivlen/8;
- } else
-#endif /* CONFIG_IPSEC_ALG */
- switch(ixs->ipsp->ips_encalg) {
-#ifdef CONFIG_IPSEC_ENC_3DES
- case ESP_3DES:
- headroom += sizeof(struct esphdr);
- break;
-#endif /* CONFIG_IPSEC_ENC_3DES */
- default:
- ixs->stats->tx_errors++;
- return IPSEC_XMIT_ESP_BADALG;
- }
-#ifdef CONFIG_IPSEC_ALG
- if ((ixt_a=ixs->ipsp->ips_alg_auth)) {
- tailroom += AHHMAC_HASHLEN;
- } else
-#endif /* CONFIG_IPSEC_ALG */
- switch(ixs->ipsp->ips_authalg) {
-#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
- case AH_MD5:
- authlen = AHHMAC_HASHLEN;
- break;
-#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
-#ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
- case AH_SHA:
- authlen = AHHMAC_HASHLEN;
- break;
-#endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */
- case AH_NONE:
- break;
- default:
- ixs->stats->tx_errors++;
- return IPSEC_XMIT_ESP_BADALG;
- }
-#ifdef CONFIG_IPSEC_ALG
- tailroom += blocksize != 1 ?
- ((blocksize - ((ixs->pyldsz + 2) % blocksize)) % blocksize) + 2 :
- ((4 - ((ixs->pyldsz + 2) % 4)) % 4) + 2;
-#else
- tailroom += ((8 - ((ixs->pyldsz + 2 * sizeof(unsigned char)) % 8)) % 8) + 2;
-#endif /* CONFIG_IPSEC_ALG */
- tailroom += authlen;
- break;
-#endif /* !CONFIG_IPSEC_ESP */
-#ifdef CONFIG_IPSEC_IPIP
- case IPPROTO_IPIP:
- headroom += sizeof(struct iphdr);
- ixs->iphlen = sizeof(struct iphdr);
- break;
-#endif /* !CONFIG_IPSEC_IPIP */
-#ifdef CONFIG_IPSEC_IPCOMP
- case IPPROTO_COMP:
- break;
-#endif /* CONFIG_IPSEC_IPCOMP */
- default:
- ixs->stats->tx_errors++;
- return IPSEC_XMIT_BADPROTO;
- }
-
- KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
- "klips_debug:ipsec_xmit_encap_once: "
- "pushing %d bytes, putting %d, proto %d.\n",
- headroom, tailroom, ixs->ipsp->ips_said.proto);
- if(skb_headroom(ixs->skb) < headroom) {
- printk(KERN_WARNING
- "klips_error:ipsec_xmit_encap_once: "
- "tried to skb_push headroom=%d, %d available. This should never happen, please report.\n",
- headroom, skb_headroom(ixs->skb));
- ixs->stats->tx_errors++;
- return IPSEC_XMIT_ESP_PUSHPULLERR;
- }
- dat = skb_push(ixs->skb, headroom);
- ilen = ixs->skb->len - tailroom;
- if(skb_tailroom(ixs->skb) < tailroom) {
- printk(KERN_WARNING
- "klips_error:ipsec_xmit_encap_once: "
- "tried to skb_put %d, %d available. This should never happen, please report.\n",
- tailroom, skb_tailroom(ixs->skb));
- ixs->stats->tx_errors++;
- return IPSEC_XMIT_ESP_PUSHPULLERR;
- }
- skb_put(ixs->skb, tailroom);
- KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
- "klips_debug:ipsec_xmit_encap_once: "
- "head,tailroom: %d,%d before xform.\n",
- skb_headroom(ixs->skb), skb_tailroom(ixs->skb));
- len = ixs->skb->len;
- if(len > 0xfff0) {
- printk(KERN_WARNING "klips_error:ipsec_xmit_encap_once: "
- "tot_len (%d) > 65520. This should never happen, please report.\n",
- len);
- ixs->stats->tx_errors++;
- return IPSEC_XMIT_BADLEN;
- }
- memmove((void *)dat, (void *)(dat + headroom), ixs->iphlen);
- ixs->iph = (struct iphdr *)dat;
- ixs->iph->tot_len = htons(ixs->skb->len);
-
- switch(ixs->ipsp->ips_said.proto) {
-#ifdef CONFIG_IPSEC_ESP
- case IPPROTO_ESP:
- espp = (struct esphdr *)(dat + ixs->iphlen);
- espp->esp_spi = ixs->ipsp->ips_said.spi;
- espp->esp_rpl = htonl(++(ixs->ipsp->ips_replaywin_lastseq));
-
-#ifdef CONFIG_IPSEC_ALG
- if (!ixt_e)
-#endif /* CONFIG_IPSEC_ALG */
- switch(ixs->ipsp->ips_encalg) {
-#if defined(CONFIG_IPSEC_ENC_3DES)
-#ifdef CONFIG_IPSEC_ENC_3DES
- case ESP_3DES:
-#endif /* CONFIG_IPSEC_ENC_3DES */
- iv[0] = *((__u32*)&(espp->esp_iv) ) =
- ((__u32*)(ixs->ipsp->ips_iv))[0];
- iv[1] = *((__u32*)&(espp->esp_iv) + 1) =
- ((__u32*)(ixs->ipsp->ips_iv))[1];
- break;
-#endif /* defined(CONFIG_IPSEC_ENC_3DES) */
- default:
- ixs->stats->tx_errors++;
- return IPSEC_XMIT_ESP_BADALG;
- }
-
- idat = dat + ixs->iphlen + headroom;
- ilen = len - (ixs->iphlen + headroom + authlen);
-
- /* Self-describing padding */
- pad = &dat[len - tailroom];
- padlen = tailroom - 2 - authlen;
- for (i = 0; i < padlen; i++) {
- pad[i] = i + 1;
- }
- dat[len - authlen - 2] = padlen;
-
- dat[len - authlen - 1] = ixs->iph->protocol;
- ixs->iph->protocol = IPPROTO_ESP;
-
-#ifdef CONFIG_IPSEC_ALG
- /* Do all operations here:
- * copy IV->ESP, encrypt, update ips IV
- */
- if (ixt_e) {
- int ret;
- memcpy(espp->esp_iv,
- ixs->ipsp->ips_iv,
- ixt_e->ixt_ivlen/8);
- ret=ipsec_alg_esp_encrypt(ixs->ipsp,
- idat, ilen, espp->esp_iv,
- IPSEC_ALG_ENCRYPT);
- memcpy(ixs->ipsp->ips_iv,
- idat + ilen - ixt_e->ixt_ivlen/8,
- ixt_e->ixt_ivlen/8);
- } else
-#endif /* CONFIG_IPSEC_ALG */
- switch(ixs->ipsp->ips_encalg) {
-#ifdef CONFIG_IPSEC_ENC_3DES
- case ESP_3DES:
- des_ede3_cbc_encrypt((des_cblock *)idat,
- (des_cblock *)idat,
- ilen,
- ((struct des_eks *)(ixs->ipsp->ips_key_e))[0].ks,
- ((struct des_eks *)(ixs->ipsp->ips_key_e))[1].ks,
- ((struct des_eks *)(ixs->ipsp->ips_key_e))[2].ks,
- (des_cblock *)iv, 1);
- break;
-#endif /* CONFIG_IPSEC_ENC_3DES */
- default:
- ixs->stats->tx_errors++;
- return IPSEC_XMIT_ESP_BADALG;
- }
-
-#ifdef CONFIG_IPSEC_ALG
- if (!ixt_e)
-#endif /* CONFIG_IPSEC_ALG */
- switch(ixs->ipsp->ips_encalg) {
-#if defined(CONFIG_IPSEC_ENC_3DES)
-#ifdef CONFIG_IPSEC_ENC_3DES
- case ESP_3DES:
-#endif /* CONFIG_IPSEC_ENC_3DES */
- /* XXX update IV with the last 8 octets of the encryption */
-#if KLIPS_IMPAIRMENT_ESPIV_CBC_ATTACK
- ((__u32*)(ixs->ipsp->ips_iv))[0] =
- ((__u32 *)(idat))[(ilen >> 2) - 2];
- ((__u32*)(ixs->ipsp->ips_iv))[1] =
- ((__u32 *)(idat))[(ilen >> 2) - 1];
-#else /* KLIPS_IMPAIRMENT_ESPIV_CBC_ATTACK */
- prng_bytes(&ipsec_prng, (char *)ixs->ipsp->ips_iv, EMT_ESPDES_IV_SZ);
-#endif /* KLIPS_IMPAIRMENT_ESPIV_CBC_ATTACK */
- break;
-#endif /* defined(CONFIG_IPSEC_ENC_3DES) */
- default:
- ixs->stats->tx_errors++;
- return IPSEC_XMIT_ESP_BADALG;
- }
-
-#ifdef CONFIG_IPSEC_ALG
- if (ixt_a) {
- ipsec_alg_sa_esp_hash(ixs->ipsp,
- (caddr_t)espp, len - ixs->iphlen - authlen,
- &(dat[len - authlen]), authlen);
-
- } else
-#endif /* CONFIG_IPSEC_ALG */
- switch(ixs->ipsp->ips_authalg) {
-#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
- case AH_MD5:
- dmp("espp", (char*)espp, len - ixs->iphlen - authlen);
- tctx.md5 = ((struct md5_ctx*)(ixs->ipsp->ips_key_a))->ictx;
- dmp("ictx", (char*)&tctx.md5, sizeof(tctx.md5));
- MD5Update(&tctx.md5, (caddr_t)espp, len - ixs->iphlen - authlen);
- dmp("ictx+dat", (char*)&tctx.md5, sizeof(tctx.md5));
- MD5Final(hash, &tctx.md5);
- dmp("ictx hash", (char*)&hash, sizeof(hash));
- tctx.md5 = ((struct md5_ctx*)(ixs->ipsp->ips_key_a))->octx;
- dmp("octx", (char*)&tctx.md5, sizeof(tctx.md5));
- MD5Update(&tctx.md5, hash, AHMD596_ALEN);
- dmp("octx+hash", (char*)&tctx.md5, sizeof(tctx.md5));
- MD5Final(hash, &tctx.md5);
- dmp("octx hash", (char*)&hash, sizeof(hash));
- memcpy(&(dat[len - authlen]), hash, authlen);
-
- /* paranoid */
- memset((caddr_t)&tctx.md5, 0, sizeof(tctx.md5));
- memset((caddr_t)hash, 0, sizeof(*hash));
- break;
-#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
-#ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
- case AH_SHA:
- tctx.sha1 = ((struct sha1_ctx*)(ixs->ipsp->ips_key_a))->ictx;
- SHA1Update(&tctx.sha1, (caddr_t)espp, len - ixs->iphlen - authlen);
- SHA1Final(hash, &tctx.sha1);
- tctx.sha1 = ((struct sha1_ctx*)(ixs->ipsp->ips_key_a))->octx;
- SHA1Update(&tctx.sha1, hash, AHSHA196_ALEN);
- SHA1Final(hash, &tctx.sha1);
- memcpy(&(dat[len - authlen]), hash, authlen);
-
- /* paranoid */
- memset((caddr_t)&tctx.sha1, 0, sizeof(tctx.sha1));
- memset((caddr_t)hash, 0, sizeof(*hash));
- break;
-#endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */
- case AH_NONE:
- break;
- default:
- ixs->stats->tx_errors++;
- return IPSEC_XMIT_AH_BADALG;
- }
-#ifdef NET_21
- ixs->skb->h.raw = (unsigned char*)espp;
-#endif /* NET_21 */
- break;
-#endif /* !CONFIG_IPSEC_ESP */
-#ifdef CONFIG_IPSEC_AH
- case IPPROTO_AH:
- ahp = (struct ahhdr *)(dat + ixs->iphlen);
- ahp->ah_spi = ixs->ipsp->ips_said.spi;
- ahp->ah_rpl = htonl(++(ixs->ipsp->ips_replaywin_lastseq));
- ahp->ah_rv = 0;
- ahp->ah_nh = ixs->iph->protocol;
- ahp->ah_hl = (headroom >> 2) - sizeof(__u64)/sizeof(__u32);
- ixs->iph->protocol = IPPROTO_AH;
- dmp("ahp", (char*)ahp, sizeof(*ahp));
-
- ipo = *ixs->iph;
- ipo.tos = 0;
- ipo.frag_off = 0;
- ipo.ttl = 0;
- ipo.check = 0;
- dmp("ipo", (char*)&ipo, sizeof(ipo));
-
- switch(ixs->ipsp->ips_authalg) {
-#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
- case AH_MD5:
- tctx.md5 = ((struct md5_ctx*)(ixs->ipsp->ips_key_a))->ictx;
- dmp("ictx", (char*)&tctx.md5, sizeof(tctx.md5));
- MD5Update(&tctx.md5, (unsigned char *)&ipo, sizeof (struct iphdr));
- dmp("ictx+ipo", (char*)&tctx.md5, sizeof(tctx.md5));
- MD5Update(&tctx.md5, (unsigned char *)ahp, headroom - sizeof(ahp->ah_data));
- dmp("ictx+ahp", (char*)&tctx.md5, sizeof(tctx.md5));
- MD5Update(&tctx.md5, (unsigned char *)zeroes, AHHMAC_HASHLEN);
- dmp("ictx+zeroes", (char*)&tctx.md5, sizeof(tctx.md5));
- MD5Update(&tctx.md5, dat + ixs->iphlen + headroom, len - ixs->iphlen - headroom);
- dmp("ictx+dat", (char*)&tctx.md5, sizeof(tctx.md5));
- MD5Final(hash, &tctx.md5);
- dmp("ictx hash", (char*)&hash, sizeof(hash));
- tctx.md5 = ((struct md5_ctx*)(ixs->ipsp->ips_key_a))->octx;
- dmp("octx", (char*)&tctx.md5, sizeof(tctx.md5));
- MD5Update(&tctx.md5, hash, AHMD596_ALEN);
- dmp("octx+hash", (char*)&tctx.md5, sizeof(tctx.md5));
- MD5Final(hash, &tctx.md5);
- dmp("octx hash", (char*)&hash, sizeof(hash));
-
- memcpy(ahp->ah_data, hash, AHHMAC_HASHLEN);
-
- /* paranoid */
- memset((caddr_t)&tctx.md5, 0, sizeof(tctx.md5));
- memset((caddr_t)hash, 0, sizeof(*hash));
- break;
-#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
-#ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
- case AH_SHA:
- tctx.sha1 = ((struct sha1_ctx*)(ixs->ipsp->ips_key_a))->ictx;
- SHA1Update(&tctx.sha1, (unsigned char *)&ipo, sizeof (struct iphdr));
- SHA1Update(&tctx.sha1, (unsigned char *)ahp, headroom - sizeof(ahp->ah_data));
- SHA1Update(&tctx.sha1, (unsigned char *)zeroes, AHHMAC_HASHLEN);
- SHA1Update(&tctx.sha1, dat + ixs->iphlen + headroom, len - ixs->iphlen - headroom);
- SHA1Final(hash, &tctx.sha1);
- tctx.sha1 = ((struct sha1_ctx*)(ixs->ipsp->ips_key_a))->octx;
- SHA1Update(&tctx.sha1, hash, AHSHA196_ALEN);
- SHA1Final(hash, &tctx.sha1);
-
- memcpy(ahp->ah_data, hash, AHHMAC_HASHLEN);
-
- /* paranoid */
- memset((caddr_t)&tctx.sha1, 0, sizeof(tctx.sha1));
- memset((caddr_t)hash, 0, sizeof(*hash));
- break;
-#endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */
- default:
- ixs->stats->tx_errors++;
- return IPSEC_XMIT_AH_BADALG;
- }
-#ifdef NET_21
- ixs->skb->h.raw = (unsigned char*)ahp;
-#endif /* NET_21 */
- break;
-#endif /* CONFIG_IPSEC_AH */
-#ifdef CONFIG_IPSEC_IPIP
- case IPPROTO_IPIP:
- ixs->iph->version = 4;
- switch(sysctl_ipsec_tos) {
- case 0:
-#ifdef NET_21
- ixs->iph->tos = ixs->skb->nh.iph->tos;
-#else /* NET_21 */
- ixs->iph->tos = ixs->skb->ip_hdr->tos;
-#endif /* NET_21 */
- break;
- case 1:
- ixs->iph->tos = 0;
- break;
- default:
- break;
- }
-#ifdef NET_21
-#ifdef NETDEV_23
- ixs->iph->ttl = sysctl_ip_default_ttl;
-#else /* NETDEV_23 */
- ixs->iph->ttl = ip_statistics.IpDefaultTTL;
-#endif /* NETDEV_23 */
-#else /* NET_21 */
- ixs->iph->ttl = 64; /* ip_statistics.IpDefaultTTL; */
-#endif /* NET_21 */
- ixs->iph->frag_off = 0;
- ixs->iph->saddr = ((struct sockaddr_in*)(ixs->ipsp->ips_addr_s))->sin_addr.s_addr;
- ixs->iph->daddr = ((struct sockaddr_in*)(ixs->ipsp->ips_addr_d))->sin_addr.s_addr;
- ixs->iph->protocol = IPPROTO_IPIP;
- ixs->iph->ihl = sizeof(struct iphdr) >> 2;
-
- KLIPS_IP_SELECT_IDENT(ixs->iph, ixs->skb);
-
- ixs->newdst = (__u32)ixs->iph->daddr;
- ixs->newsrc = (__u32)ixs->iph->saddr;
-
-#ifdef NET_21
- ixs->skb->h.ipiph = ixs->skb->nh.iph;
-#endif /* NET_21 */
- break;
-#endif /* !CONFIG_IPSEC_IPIP */
-#ifdef CONFIG_IPSEC_IPCOMP
- case IPPROTO_COMP:
- {
- unsigned int flags = 0;
-#ifdef CONFIG_IPSEC_DEBUG
- unsigned int old_tot_len = ntohs(ixs->iph->tot_len);
-#endif /* CONFIG_IPSEC_DEBUG */
- ixs->ipsp->ips_comp_ratio_dbytes += ntohs(ixs->iph->tot_len);
-
- ixs->skb = skb_compress(ixs->skb, ixs->ipsp, &flags);
-
-#ifdef NET_21
- ixs->iph = ixs->skb->nh.iph;
-#else /* NET_21 */
- ixs->iph = ixs->skb->ip_hdr;
-#endif /* NET_21 */
-
- ixs->ipsp->ips_comp_ratio_cbytes += ntohs(ixs->iph->tot_len);
-
-#ifdef CONFIG_IPSEC_DEBUG
- if (debug_tunnel & DB_TN_CROUT)
- {
- if (old_tot_len > ntohs(ixs->iph->tot_len))
- KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
- "klips_debug:ipsec_xmit_encap_once: "
- "packet shrunk from %d to %d bytes after compression, cpi=%04x (should be from spi=%08x, spi&0xffff=%04x.\n",
- old_tot_len, ntohs(ixs->iph->tot_len),
- ntohs(((struct ipcomphdr*)(((char*)ixs->iph) + ((ixs->iph->ihl) << 2)))->ipcomp_cpi),
- ntohl(ixs->ipsp->ips_said.spi),
- (__u16)(ntohl(ixs->ipsp->ips_said.spi) & 0x0000ffff));
- else
- KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
- "klips_debug:ipsec_xmit_encap_once: "
- "packet did not compress (flags = %d).\n",
- flags);
- }
-#endif /* CONFIG_IPSEC_DEBUG */
- }
- break;
-#endif /* CONFIG_IPSEC_IPCOMP */
- default:
- ixs->stats->tx_errors++;
- return IPSEC_XMIT_BADPROTO;
- }
-
-#ifdef NET_21
- ixs->skb->nh.raw = ixs->skb->data;
-#else /* NET_21 */
- ixs->skb->ip_hdr = ixs->skb->h.iph = (struct iphdr *) ixs->skb->data;
-#endif /* NET_21 */
- ixs->iph->check = 0;
- ixs->iph->check = ip_fast_csum((unsigned char *)ixs->iph, ixs->iph->ihl);
-
- KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
- "klips_debug:ipsec_xmit_encap_once: "
- "after <%s%s%s>, SA:%s:\n",
- IPS_XFORM_NAME(ixs->ipsp),
- ixs->sa_len ? ixs->sa_txt : " (error)");
- KLIPS_IP_PRINT(debug_tunnel & DB_TN_XMIT, ixs->iph);
-
- ixs->ipsp->ips_life.ipl_bytes.ipl_count += len;
- ixs->ipsp->ips_life.ipl_bytes.ipl_last = len;
-
- if(!ixs->ipsp->ips_life.ipl_usetime.ipl_count) {
- ixs->ipsp->ips_life.ipl_usetime.ipl_count = jiffies / HZ;
- }
- ixs->ipsp->ips_life.ipl_usetime.ipl_last = jiffies / HZ;
- ixs->ipsp->ips_life.ipl_packets.ipl_count++;
-
- ixs->ipsp = ixs->ipsp->ips_onext;
-
- return IPSEC_XMIT_OK;
-}
-
-enum ipsec_xmit_value
-ipsec_xmit_encap_bundle(struct ipsec_xmit_state *ixs)
-{
-#ifdef CONFIG_IPSEC_ALG
- struct ipsec_alg_enc *ixt_e = NULL;
- struct ipsec_alg_auth *ixt_a = NULL;
- int blocksize = 8;
-#endif /* CONFIG_IPSEC_ALG */
- enum ipsec_xmit_value bundle_stat = IPSEC_XMIT_OK;
-
- ixs->newdst = ixs->orgdst = ixs->iph->daddr;
- ixs->newsrc = ixs->orgsrc = ixs->iph->saddr;
- ixs->orgedst = ixs->outgoing_said.dst.s_addr;
- ixs->iphlen = ixs->iph->ihl << 2;
- ixs->pyldsz = ntohs(ixs->iph->tot_len) - ixs->iphlen;
- ixs->max_headroom = ixs->max_tailroom = 0;
-
- if (ixs->outgoing_said.proto == IPPROTO_INT) {
- switch (ntohl(ixs->outgoing_said.spi)) {
- case SPI_DROP:
- KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
- "klips_debug:ipsec_xmit_encap_bundle: "
- "shunt SA of DROP or no eroute: dropping.\n");
- ixs->stats->tx_dropped++;
- break;
-
- case SPI_REJECT:
- KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
- "klips_debug:ipsec_xmit_encap_bundle: "
- "shunt SA of REJECT: notifying and dropping.\n");
- ICMP_SEND(ixs->skb,
- ICMP_DEST_UNREACH,
- ICMP_PKT_FILTERED,
- 0,
- ixs->physdev);
- ixs->stats->tx_dropped++;
- break;
-
- case SPI_PASS:
-#ifdef NET_21
- ixs->pass = 1;
-#endif /* NET_21 */
- KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
- "klips_debug:ipsec_xmit_encap_bundle: "
- "PASS: calling dev_queue_xmit\n");
- return IPSEC_XMIT_PASS;
- goto cleanup;
-
-#if 1 /* now moved up to finderoute so we don't need to lock it longer */
- case SPI_HOLD:
- KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
- "klips_debug:ipsec_xmit_encap_bundle: "
- "shunt SA of HOLD: this does not make sense here, dropping.\n");
- ixs->stats->tx_dropped++;
- break;
-#endif
- case SPI_TRAP:
- case SPI_TRAPSUBNET:
- {
- struct sockaddr_in src, dst;
-#ifdef CONFIG_IPSEC_DEBUG
- char bufsrc[ADDRTOA_BUF], bufdst[ADDRTOA_BUF];
-#endif /* CONFIG_IPSEC_DEBUG */
-
- /* Signal all listening KMds with a PF_KEY ACQUIRE */
- ixs->ips.ips_said.proto = ixs->iph->protocol;
- src.sin_family = AF_INET;
- dst.sin_family = AF_INET;
- src.sin_addr.s_addr = ixs->iph->saddr;
- dst.sin_addr.s_addr = ixs->iph->daddr;
- src.sin_port =
- (ixs->iph->protocol == IPPROTO_UDP
- ? ((struct udphdr*) (((caddr_t)ixs->iph) + (ixs->iph->ihl << 2)))->source
- : (ixs->iph->protocol == IPPROTO_TCP
- ? ((struct tcphdr*)((caddr_t)ixs->iph + (ixs->iph->ihl << 2)))->source
- : 0));
- dst.sin_port =
- (ixs->iph->protocol == IPPROTO_UDP
- ? ((struct udphdr*) (((caddr_t)ixs->iph) + (ixs->iph->ihl << 2)))->dest
- : (ixs->iph->protocol == IPPROTO_TCP
- ? ((struct tcphdr*)((caddr_t)ixs->iph + (ixs->iph->ihl << 2)))->dest
- : 0));
- {
- int i;
- for(i = 0;
- i < sizeof(struct sockaddr_in)
- - offsetof(struct sockaddr_in, sin_zero);
- i++) {
- src.sin_zero[i] = 0;
- dst.sin_zero[i] = 0;
- }
- }
-
- ixs->ips.ips_addr_s = (struct sockaddr*)(&src);
- ixs->ips.ips_addr_d = (struct sockaddr*)(&dst);
- KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
- "klips_debug:ipsec_xmit_encap_bundle: "
- "SADB_ACQUIRE sent with src=%s:%d, dst=%s:%d, proto=%d.\n",
- addrtoa(((struct sockaddr_in*)(ixs->ips.ips_addr_s))->sin_addr, 0, bufsrc, sizeof(bufsrc)) <= ADDRTOA_BUF ? bufsrc : "BAD_ADDR",
- ntohs(((struct sockaddr_in*)(ixs->ips.ips_addr_s))->sin_port),
- addrtoa(((struct sockaddr_in*)(ixs->ips.ips_addr_d))->sin_addr, 0, bufdst, sizeof(bufdst)) <= ADDRTOA_BUF ? bufdst : "BAD_ADDR",
- ntohs(((struct sockaddr_in*)(ixs->ips.ips_addr_d))->sin_port),
- ixs->ips.ips_said.proto);
-
- /* increment count of total traps needed */
- ipsec_xmit_trap_count++;
-
- if (pfkey_acquire(&ixs->ips) == 0) {
-
- /* note that we succeeded */
- ipsec_xmit_trap_sendcount++;
-
- if (ixs->outgoing_said.spi==htonl(SPI_TRAPSUBNET)) {
- /*
- * The spinlock is to prevent any other
- * process from accessing or deleting
- * the eroute while we are using and
- * updating it.
- */
- spin_lock(&eroute_lock);
- ixs->eroute = ipsec_findroute(&ixs->matcher);
- if(ixs->eroute) {
- ixs->eroute->er_said.spi = htonl(SPI_HOLD);
- ixs->eroute->er_first = ixs->skb;
- ixs->skb = NULL;
- }
- spin_unlock(&eroute_lock);
- } else if (create_hold_eroute(ixs->skb, ixs->iph, ixs->eroute_pid)) {
- ixs->skb = NULL;
- }
- }
- ixs->stats->tx_dropped++;
- }
- default:
- /* XXX what do we do with an unknown shunt spi? */
- break;
- } /* switch (ntohl(ixs->outgoing_said.spi)) */
- return IPSEC_XMIT_STOLEN;
- } /* if (ixs->outgoing_said.proto == IPPROTO_INT) */
-
- /*
- The spinlock is to prevent any other process from
- accessing or deleting the ipsec_sa hash table or any of the
- ipsec_sa s while we are using and updating them.
-
- This is not optimal, but was relatively straightforward
- at the time. A better way to do it has been planned for
- more than a year, to lock the hash table and put reference
- counts on each ipsec_sa instead. This is not likely to happen
- in KLIPS1 unless a volunteer contributes it, but will be
- designed into KLIPS2.
- */
- spin_lock(&tdb_lock);
-
- ixs->ipsp = ipsec_sa_getbyid(&ixs->outgoing_said);
- ixs->sa_len = satoa(ixs->outgoing_said, 0, ixs->sa_txt, SATOA_BUF);
-
- if (ixs->ipsp == NULL) {
- KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
- "klips_debug:ipsec_xmit_encap_bundle: "
- "no ipsec_sa for SA%s: outgoing packet with no SA, dropped.\n",
- ixs->sa_len ? ixs->sa_txt : " (error)");
- ixs->stats->tx_dropped++;
- bundle_stat = IPSEC_XMIT_SAIDNOTFOUND;
- goto cleanup;
- }
-
- ipsec_sa_put(ixs->ipsp); /* incomplete */
-
- KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
- "klips_debug:ipsec_xmit_encap_bundle: "
- "found ipsec_sa -- SA:<%s%s%s> %s\n",
- IPS_XFORM_NAME(ixs->ipsp),
- ixs->sa_len ? ixs->sa_txt : " (error)");
-
- /*
- * How much headroom do we need to be able to apply
- * all the grouped transforms?
- */
- ixs->ipsq = ixs->ipsp; /* save the head of the ipsec_sa chain */
- while (ixs->ipsp) {
- ixs->sa_len = satoa(ixs->ipsp->ips_said, 0, ixs->sa_txt, SATOA_BUF);
- if(ixs->sa_len == 0) {
- strcpy(ixs->sa_txt, "(error)");
- }
-
- /* If it is in larval state, drop the packet, we cannot process yet. */
- if(ixs->ipsp->ips_state == SADB_SASTATE_LARVAL) {
- KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
- "klips_debug:ipsec_xmit_encap_bundle: "
- "ipsec_sa in larval state for SA:<%s%s%s> %s, cannot be used yet, dropping packet.\n",
- IPS_XFORM_NAME(ixs->ipsp),
- ixs->sa_len ? ixs->sa_txt : " (error)");
- ixs->stats->tx_errors++;
- bundle_stat = IPSEC_XMIT_SAIDNOTLIVE;
- goto cleanup;
- }
-
- if(ixs->ipsp->ips_state == SADB_SASTATE_DEAD) {
- KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
- "klips_debug:ipsec_xmit_encap_bundle: "
- "ipsec_sa in dead state for SA:<%s%s%s> %s, can no longer be used, dropping packet.\n",
- IPS_XFORM_NAME(ixs->ipsp),
- ixs->sa_len ? ixs->sa_txt : " (error)");
- ixs->stats->tx_errors++;
- bundle_stat = IPSEC_XMIT_SAIDNOTLIVE;
- goto cleanup;
- }
-
- /* If the replay window counter == -1, expire SA, it will roll */
- if(ixs->ipsp->ips_replaywin && ixs->ipsp->ips_replaywin_lastseq == -1) {
- pfkey_expire(ixs->ipsp, 1);
- KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
- "klips_debug:ipsec_xmit_encap_bundle: "
- "replay window counter rolled for SA:<%s%s%s> %s, packet dropped, expiring SA.\n",
- IPS_XFORM_NAME(ixs->ipsp),
- ixs->sa_len ? ixs->sa_txt : " (error)");
- ipsec_sa_delchain(ixs->ipsp);
- ixs->stats->tx_errors++;
- bundle_stat = IPSEC_XMIT_REPLAYROLLED;
- goto cleanup;
- }
-
- /*
- * if this is the first time we are using this SA, mark start time,
- * and offset hard/soft counters by "now" for later checking.
- */
-#if 0
- if(ixs->ipsp->ips_life.ipl_usetime.count == 0) {
- ixs->ipsp->ips_life.ipl_usetime.count = jiffies;
- ixs->ipsp->ips_life.ipl_usetime.hard += jiffies;
- ixs->ipsp->ips_life.ipl_usetime.soft += jiffies;
- }
-#endif
-
-
- if(ipsec_lifetime_check(&ixs->ipsp->ips_life.ipl_bytes, "bytes", ixs->sa_txt,
- ipsec_life_countbased, ipsec_outgoing, ixs->ipsp) == ipsec_life_harddied ||
- ipsec_lifetime_check(&ixs->ipsp->ips_life.ipl_addtime, "addtime",ixs->sa_txt,
- ipsec_life_timebased, ipsec_outgoing, ixs->ipsp) == ipsec_life_harddied ||
- ipsec_lifetime_check(&ixs->ipsp->ips_life.ipl_usetime, "usetime",ixs->sa_txt,
- ipsec_life_timebased, ipsec_outgoing, ixs->ipsp) == ipsec_life_harddied ||
- ipsec_lifetime_check(&ixs->ipsp->ips_life.ipl_packets, "packets",ixs->sa_txt,
- ipsec_life_countbased, ipsec_outgoing, ixs->ipsp) == ipsec_life_harddied) {
-
- ipsec_sa_delchain(ixs->ipsp);
- ixs->stats->tx_errors++;
- bundle_stat = IPSEC_XMIT_LIFETIMEFAILED;
- goto cleanup;
- }
-
-
- ixs->headroom = ixs->tailroom = 0;
- KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
- "klips_debug:ipsec_xmit_encap_bundle: "
- "calling room for <%s%s%s>, SA:%s\n",
- IPS_XFORM_NAME(ixs->ipsp),
- ixs->sa_len ? ixs->sa_txt : " (error)");
- switch(ixs->ipsp->ips_said.proto) {
-#ifdef CONFIG_IPSEC_AH
- case IPPROTO_AH:
- ixs->headroom += sizeof(struct ahhdr);
- break;
-#endif /* CONFIG_IPSEC_AH */
-#ifdef CONFIG_IPSEC_ESP
- case IPPROTO_ESP:
-#ifdef CONFIG_IPSEC_ALG
- if ((ixt_e=ixs->ipsp->ips_alg_enc)) {
- blocksize = ixt_e->ixt_blocksize;
- ixs->headroom += ESP_HEADER_LEN + ixt_e->ixt_ivlen/8;
- } else
-#endif /* CONFIG_IPSEC_ALG */
- switch(ixs->ipsp->ips_encalg) {
-#ifdef CONFIG_IPSEC_ENC_3DES
- case ESP_3DES:
- ixs->headroom += sizeof(struct esphdr);
- break;
-#endif /* CONFIG_IPSEC_ENC_3DES */
- default:
- ixs->stats->tx_errors++;
- bundle_stat = IPSEC_XMIT_ESP_BADALG;
- goto cleanup;
- }
-#ifdef CONFIG_IPSEC_ALG
- if ((ixt_a=ixs->ipsp->ips_alg_auth)) {
- ixs->tailroom += AHHMAC_HASHLEN;
- } else
-#endif /* CONFIG_IPSEC_ALG */
- switch(ixs->ipsp->ips_authalg) {
-#ifdef CONFIG_IPSEC_AUTH_HMAC_MD5
- case AH_MD5:
- ixs->tailroom += AHHMAC_HASHLEN;
- break;
-#endif /* CONFIG_IPSEC_AUTH_HMAC_MD5 */
-#ifdef CONFIG_IPSEC_AUTH_HMAC_SHA1
- case AH_SHA:
- ixs->tailroom += AHHMAC_HASHLEN;
- break;
-#endif /* CONFIG_IPSEC_AUTH_HMAC_SHA1 */
- case AH_NONE:
- break;
- default:
- ixs->stats->tx_errors++;
- bundle_stat = IPSEC_XMIT_AH_BADALG;
- goto cleanup;
- }
-#ifdef CONFIG_IPSEC_ALG
- ixs->tailroom += blocksize != 1 ?
- ((blocksize - ((ixs->pyldsz + 2) % blocksize)) % blocksize) + 2 :
- ((4 - ((ixs->pyldsz + 2) % 4)) % 4) + 2;
-#else
- ixs->tailroom += ((8 - ((ixs->pyldsz + 2 * sizeof(unsigned char)) % 8)) % 8) + 2;
-#endif /* CONFIG_IPSEC_ALG */
-#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
- if ((ixs->ipsp->ips_natt_type) && (!ixs->natt_type)) {
- ixs->natt_type = ixs->ipsp->ips_natt_type;
- ixs->natt_sport = ixs->ipsp->ips_natt_sport;
- ixs->natt_dport = ixs->ipsp->ips_natt_dport;
- switch (ixs->natt_type) {
- case ESPINUDP_WITH_NON_IKE:
- ixs->natt_head = sizeof(struct udphdr)+(2*sizeof(__u32));
- break;
- case ESPINUDP_WITH_NON_ESP:
- ixs->natt_head = sizeof(struct udphdr);
- break;
- default:
- ixs->natt_head = 0;
- break;
- }
- ixs->tailroom += ixs->natt_head;
- }
-#endif
- break;
-#endif /* !CONFIG_IPSEC_ESP */
-#ifdef CONFIG_IPSEC_IPIP
- case IPPROTO_IPIP:
- ixs->headroom += sizeof(struct iphdr);
- break;
-#endif /* !CONFIG_IPSEC_IPIP */
- case IPPROTO_COMP:
-#ifdef CONFIG_IPSEC_IPCOMP
- /*
- We can't predict how much the packet will
- shrink without doing the actual compression.
- We could do it here, if we were the first
- encapsulation in the chain. That might save
- us a skb_copy_expand, since we might fit
- into the existing skb then. However, this
- would be a bit unclean (and this hack has
- bit us once), so we better not do it. After
- all, the skb_copy_expand is cheap in
- comparison to the actual compression.
- At least we know the packet will not grow.
- */
- break;
-#endif /* CONFIG_IPSEC_IPCOMP */
- default:
- ixs->stats->tx_errors++;
- bundle_stat = IPSEC_XMIT_BADPROTO;
- goto cleanup;
- }
- ixs->ipsp = ixs->ipsp->ips_onext;
- KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
- "klips_debug:ipsec_xmit_encap_bundle: "
- "Required head,tailroom: %d,%d\n",
- ixs->headroom, ixs->tailroom);
- ixs->max_headroom += ixs->headroom;
- ixs->max_tailroom += ixs->tailroom;
- ixs->pyldsz += (ixs->headroom + ixs->tailroom);
- }
- ixs->ipsp = ixs->ipsq; /* restore the head of the ipsec_sa chain */
-
- KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
- "klips_debug:ipsec_xmit_encap_bundle: "
- "existing head,tailroom: %d,%d before applying xforms with head,tailroom: %d,%d .\n",
- skb_headroom(ixs->skb), skb_tailroom(ixs->skb),
- ixs->max_headroom, ixs->max_tailroom);
-
- ixs->tot_headroom += ixs->max_headroom;
- ixs->tot_tailroom += ixs->max_tailroom;
-
- ixs->mtudiff = ixs->prv->mtu + ixs->tot_headroom + ixs->tot_tailroom - ixs->physmtu;
-
- KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
- "klips_debug:ipsec_xmit_encap_bundle: "
- "mtu:%d physmtu:%d tothr:%d tottr:%d mtudiff:%d ippkttotlen:%d\n",
- ixs->prv->mtu, ixs->physmtu,
- ixs->tot_headroom, ixs->tot_tailroom, ixs->mtudiff, ntohs(ixs->iph->tot_len));
- if(ixs->mtudiff > 0) {
- int newmtu = ixs->physmtu - (ixs->tot_headroom + ((ixs->tot_tailroom + 2) & ~7) + 5);
-
- KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
- "klips_info:ipsec_xmit_encap_bundle: "
- "dev %s mtu of %d decreased by %d to %d\n",
- ixs->dev->name,
- ixs->prv->mtu,
- ixs->prv->mtu - newmtu,
- newmtu);
- ixs->prv->mtu = newmtu;
-#ifdef NET_21
-#if 0
- ixs->skb->dst->pmtu = ixs->prv->mtu; /* RGB */
-#endif /* 0 */
-#else /* NET_21 */
-#if 0
- ixs->dev->mtu = ixs->prv->mtu; /* RGB */
-#endif /* 0 */
-#endif /* NET_21 */
- }
-
- /*
- If the sender is doing PMTU discovery, and the
- packet doesn't fit within ixs->prv->mtu, notify him
- (unless it was an ICMP packet, or it was not the
- zero-offset packet) and send it anyways.
-
- Note: buggy firewall configuration may prevent the
- ICMP packet from getting back.
- */
- if(sysctl_ipsec_icmp
- && ixs->prv->mtu < ntohs(ixs->iph->tot_len)
- && (ixs->iph->frag_off & __constant_htons(IP_DF)) ) {
- int notify = ixs->iph->protocol != IPPROTO_ICMP
- && (ixs->iph->frag_off & __constant_htons(IP_OFFSET)) == 0;
-
-#ifdef IPSEC_obey_DF
- KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
- "klips_debug:ipsec_xmit_encap_bundle: "
- "fragmentation needed and DF set; %sdropping packet\n",
- notify ? "sending ICMP and " : "");
- if (notify)
- ICMP_SEND(ixs->skb,
- ICMP_DEST_UNREACH,
- ICMP_FRAG_NEEDED,
- ixs->prv->mtu,
- ixs->physdev);
- ixs->stats->tx_errors++;
- bundle_stat = IPSEC_XMIT_CANNOTFRAG;
- goto cleanup;
-#else /* IPSEC_obey_DF */
- KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
- "klips_debug:ipsec_xmit_encap_bundle: "
- "fragmentation needed and DF set; %spassing packet\n",
- notify ? "sending ICMP and " : "");
- if (notify)
- ICMP_SEND(ixs->skb,
- ICMP_DEST_UNREACH,
- ICMP_FRAG_NEEDED,
- ixs->prv->mtu,
- ixs->physdev);
-#endif /* IPSEC_obey_DF */
- }
-
-#ifdef MSS_HACK
- /*
- * If this is a transport mode TCP packet with
- * SYN set, determine an effective MSS based on
- * AH/ESP overheads determined above.
- */
- if (ixs->iph->protocol == IPPROTO_TCP
- && ixs->outgoing_said.proto != IPPROTO_IPIP) {
- struct tcphdr *tcph = ixs->skb->h.th;
- if (tcph->syn && !tcph->ack) {
- if(!ipsec_adjust_mss(ixs->skb, tcph, ixs->prv->mtu)) {
- printk(KERN_WARNING
- "klips_warning:ipsec_xmit_encap_bundle: "
- "ipsec_adjust_mss() failed\n");
- ixs->stats->tx_errors++;
- bundle_stat = IPSEC_XMIT_MSSERR;
- goto cleanup;
- }
- }
- }
-#endif /* MSS_HACK */
-
-#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
- if ((ixs->natt_type) && (ixs->outgoing_said.proto != IPPROTO_IPIP)) {
- /**
- * NAT-Traversal and Transport Mode:
- * we need to correct TCP/UDP checksum
- *
- * If we've got NAT-OA, we can fix checksum without recalculation.
- * If we don't we can zero udp checksum.
- */
- __u32 natt_oa = ixs->ipsp->ips_natt_oa ?
- ((struct sockaddr_in*)(ixs->ipsp->ips_natt_oa))->sin_addr.s_addr : 0;
- __u16 pkt_len = ixs->skb->tail - (unsigned char *)ixs->iph;
- __u16 data_len = pkt_len - (ixs->iph->ihl << 2);
- switch (ixs->iph->protocol) {
- case IPPROTO_TCP:
- if (data_len >= sizeof(struct tcphdr)) {
- struct tcphdr *tcp = (struct tcphdr *)((__u32 *)ixs->iph+ixs->iph->ihl);
- if (natt_oa) {
- __u32 buff[2] = { ~ixs->iph->daddr, natt_oa };
- KLIPS_PRINT(debug_tunnel,
- "klips_debug:ipsec_tunnel_start_xmit: "
- "NAT-T & TRANSPORT: "
- "fix TCP checksum using NAT-OA\n");
- tcp->check = csum_fold(
- csum_partial((unsigned char *)buff, sizeof(buff),
- tcp->check^0xffff));
- }
- else {
- KLIPS_PRINT(debug_tunnel,
- "klips_debug:ipsec_tunnel_start_xmit: "
- "NAT-T & TRANSPORT: do not recalc TCP checksum\n");
- }
- }
- else {
- KLIPS_PRINT(debug_tunnel,
- "klips_debug:ipsec_tunnel_start_xmit: "
- "NAT-T & TRANSPORT: can't fix TCP checksum\n");
- }
- break;
- case IPPROTO_UDP:
- if (data_len >= sizeof(struct udphdr)) {
- struct udphdr *udp = (struct udphdr *)((__u32 *)ixs->iph+ixs->iph->ihl);
- if (udp->check == 0) {
- KLIPS_PRINT(debug_tunnel,
- "klips_debug:ipsec_tunnel_start_xmit: "
- "NAT-T & TRANSPORT: UDP checksum already 0\n");
- }
- else if (natt_oa) {
- __u32 buff[2] = { ~ixs->iph->daddr, natt_oa };
- KLIPS_PRINT(debug_tunnel,
- "klips_debug:ipsec_tunnel_start_xmit: "
- "NAT-T & TRANSPORT: "
- "fix UDP checksum using NAT-OA\n");
- udp->check = csum_fold(
- csum_partial((unsigned char *)buff, sizeof(buff),
- udp->check^0xffff));
- }
- else {
- KLIPS_PRINT(debug_tunnel,
- "klips_debug:ipsec_tunnel_start_xmit: "
- "NAT-T & TRANSPORT: zero UDP checksum\n");
- udp->check = 0;
- }
- }
- else {
- KLIPS_PRINT(debug_tunnel,
- "klips_debug:ipsec_tunnel_start_xmit: "
- "NAT-T & TRANSPORT: can't fix UDP checksum\n");
- }
- break;
- default:
- KLIPS_PRINT(debug_tunnel,
- "klips_debug:ipsec_tunnel_start_xmit: "
- "NAT-T & TRANSPORT: non TCP/UDP packet -- do nothing\n");
- break;
- }
- }
-#endif /* CONFIG_IPSEC_NAT_TRAVERSAL */
-
- if(!ixs->hard_header_stripped) {
- KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
- "klips_debug:ipsec_xmit_encap_bundle: "
- "allocating %d bytes for hardheader.\n",
- ixs->hard_header_len);
- if((ixs->saved_header = kmalloc(ixs->hard_header_len, GFP_ATOMIC)) == NULL) {
- printk(KERN_WARNING "klips_debug:ipsec_xmit_encap_bundle: "
- "Failed, tried to allocate %d bytes for temp hard_header.\n",
- ixs->hard_header_len);
- ixs->stats->tx_errors++;
- bundle_stat = IPSEC_XMIT_ERRMEMALLOC;
- goto cleanup;
- }
- {
- int i;
- for (i = 0; i < ixs->hard_header_len; i++) {
- ixs->saved_header[i] = ixs->skb->data[i];
- }
- }
- if(ixs->skb->len < ixs->hard_header_len) {
- printk(KERN_WARNING "klips_error:ipsec_xmit_encap_bundle: "
- "tried to skb_pull hhlen=%d, %d available. This should never happen, please report.\n",
- ixs->hard_header_len, (int)(ixs->skb->len));
- ixs->stats->tx_errors++;
- bundle_stat = IPSEC_XMIT_ESP_PUSHPULLERR;
- goto cleanup;
- }
- skb_pull(ixs->skb, ixs->hard_header_len);
- ixs->hard_header_stripped = 1;
-
-/* ixs->iph = (struct iphdr *) (ixs->skb->data); */
- KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
- "klips_debug:ipsec_xmit_encap_bundle: "
- "head,tailroom: %d,%d after hard_header stripped.\n",
- skb_headroom(ixs->skb), skb_tailroom(ixs->skb));
- KLIPS_IP_PRINT(debug_tunnel & DB_TN_CROUT, ixs->iph);
- } else {
- KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
- "klips_debug:ipsec_xmit_encap_bundle: "
- "hard header already stripped.\n");
- }
-
- ixs->ll_headroom = (ixs->hard_header_len + 15) & ~15;
-
- if ((skb_headroom(ixs->skb) >= ixs->max_headroom + 2 * ixs->ll_headroom) &&
- (skb_tailroom(ixs->skb) >= ixs->max_tailroom)
-#ifndef NET_21
- && ixs->skb->free
-#endif /* !NET_21 */
- ) {
- KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
- "klips_debug:ipsec_xmit_encap_bundle: "
- "data fits in existing skb\n");
- } else {
- struct sk_buff* tskb;
-
- if(!ixs->oskb) {
- ixs->oskb = ixs->skb;
- }
-
- tskb = skb_copy_expand(ixs->skb,
- /* The need for 2 * link layer length here remains unexplained...RGB */
- ixs->max_headroom + 2 * ixs->ll_headroom,
- ixs->max_tailroom,
- GFP_ATOMIC);
-#ifdef NET_21
- if(tskb && ixs->skb->sk) {
- skb_set_owner_w(tskb, ixs->skb->sk);
- }
-#endif /* NET_21 */
- if(ixs->skb != ixs->oskb) {
- ipsec_kfree_skb(ixs->skb);
- }
- ixs->skb = tskb;
- if (!ixs->skb) {
- printk(KERN_WARNING
- "klips_debug:ipsec_xmit_encap_bundle: "
- "Failed, tried to allocate %d head and %d tailroom\n",
- ixs->max_headroom, ixs->max_tailroom);
- ixs->stats->tx_errors++;
- bundle_stat = IPSEC_XMIT_ERRSKBALLOC;
- goto cleanup;
- }
- KLIPS_PRINT(debug_tunnel & DB_TN_CROUT,
- "klips_debug:ipsec_xmit_encap_bundle: "
- "head,tailroom: %d,%d after allocation\n",
- skb_headroom(ixs->skb), skb_tailroom(ixs->skb));
- }
-
- /*
- * Apply grouped transforms to packet
- */
- while (ixs->ipsp) {
- enum ipsec_xmit_value encap_stat = IPSEC_XMIT_OK;
-
- encap_stat = ipsec_xmit_encap_once(ixs);
- if(encap_stat != IPSEC_XMIT_OK) {
- KLIPS_PRINT(debug_tunnel & DB_TN_XMIT,
- "klips_debug:ipsec_xmit_encap_bundle: encap_once failed: %d\n",
- encap_stat);
-
- bundle_stat = IPSEC_XMIT_ENCAPFAIL;
- goto cleanup;
- }
- }
- /* end encapsulation loop here XXX */
- cleanup:
- spin_unlock(&tdb_lock);
- return bundle_stat;
-}