diff options
Diffstat (limited to 'linux/net/ipsec/ipsec_xmit.c')
-rw-r--r-- | linux/net/ipsec/ipsec_xmit.c | 1782 |
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; -} |