]> git.hungrycats.org Git - linux/commitdiff
[IPSEC]: Implement UDP Encapsulation framework.
authorDerek Atkins <derek@ihtfp.com>
Wed, 2 Apr 2003 21:21:02 +0000 (13:21 -0800)
committerDavid S. Miller <davem@nuts.ninka.net>
Wed, 2 Apr 2003 21:21:02 +0000 (13:21 -0800)
In particular, implement ESPinUDP encapsulation for IPsec
Nat Traversal.

16 files changed:
include/linux/pfkeyv2.h
include/linux/udp.h
include/linux/xfrm.h
include/net/xfrm.h
net/ipv4/ah.c
net/ipv4/esp.c
net/ipv4/udp.c
net/ipv4/xfrm4_input.c
net/ipv6/ah6.c
net/ipv6/esp6.c
net/ipv6/xfrm6_input.c
net/key/af_key.c
net/netsyms.c
net/xfrm/xfrm_input.c
net/xfrm/xfrm_policy.c
net/xfrm/xfrm_state.c

index efb41c857ea33c1d2c45f9e99a47eb825e5cbbd7..b5efb37a1c2f2b9db751a48c3b43225360631102 100644 (file)
@@ -194,6 +194,26 @@ struct sadb_x_ipsecrequest {
 } __attribute__((packed));
 /* sizeof(struct sadb_x_ipsecrequest) == 16 */
 
+/* This defines the TYPE of Nat Traversal in use.  Currently only one
+ * type of NAT-T is supported, draft-ietf-ipsec-udp-encaps-06
+ */
+struct sadb_x_nat_t_type {
+       uint16_t        sadb_x_nat_t_type_len;
+       uint16_t        sadb_x_nat_t_type_exttype;
+       uint8_t         sadb_x_nat_t_type_type;
+       uint8_t         sadb_x_nat_t_type_reserved[3];
+} __attribute__((packed));
+/* sizeof(struct sadb_x_nat_t_type) == 8 */
+
+/* Pass a NAT Traversal port (Source or Dest port) */
+struct sadb_x_nat_t_port {
+       uint16_t        sadb_x_nat_t_port_len;
+       uint16_t        sadb_x_nat_t_port_exttype;
+       uint16_t        sadb_x_nat_t_port_port;
+       uint16_t        sadb_x_nat_t_port_reserved;
+} __attribute__((packed));
+/* sizeof(struct sadb_x_nat_t_port) == 8 */
+
 /* Message types */
 #define SADB_RESERVED          0
 #define SADB_GETSPI            1
@@ -218,7 +238,8 @@ struct sadb_x_ipsecrequest {
 #define SADB_X_SPDSETIDX       20
 #define SADB_X_SPDEXPIRE       21
 #define SADB_X_SPDDELETE2      22
-#define SADB_MAX               22
+#define SADB_X_NAT_T_NEW_MAPPING       23
+#define SADB_MAX               23
 
 /* Security Association flags */
 #define SADB_SAFLAGS_PFS       1
@@ -291,7 +312,12 @@ struct sadb_x_ipsecrequest {
 #define SADB_X_EXT_KMPRIVATE           17
 #define SADB_X_EXT_POLICY              18
 #define SADB_X_EXT_SA2                 19
-#define SADB_EXT_MAX                   19
+/* The next four entries are for setting up NAT Traversal */
+#define SADB_X_EXT_NAT_T_TYPE          20
+#define SADB_X_EXT_NAT_T_SPORT         21
+#define SADB_X_EXT_NAT_T_DPORT         22
+#define SADB_X_EXT_NAT_T_OA            23
+#define SADB_EXT_MAX                   23
 
 /* Identity Extension values */
 #define SADB_IDENTTYPE_RESERVED        0
index 5bdb970a1b693a563aaf0933cd90f43d8d2d5854..2cd62b5b79f31a45545be28a14af68299b1bbb0a 100644 (file)
@@ -30,10 +30,15 @@ struct udphdr {
 
 /* UDP socket options */
 #define UDP_CORK       1       /* Never send partially complete segments */
+#define UDP_ENCAP      100     /* Set the socket to accept encapsulated packets */
+
+/* UDP encapsulation types */
+#define UDP_ENCAP_ESPINUDP     2 /* draft-ietf-ipsec-udp-encaps-06 */
 
 struct udp_opt {
        int             pending;        /* Any pending frames ? */
        unsigned int    corkflag;       /* Cork is required */
+       __u16           encap_type;     /* Is this an Encapsulation socket? */
        /*
         * Following members retains the infomation to create a UDP header
         * when the socket is uncorked.
index 8b1ae0cc3ebeb5684dccc5d6a90276b57983c1de..46144681c5a783ff45c7ba689d6ec38e0173215a 100644 (file)
@@ -130,12 +130,19 @@ struct xfrm_user_tmpl {
        __u32                   calgos;
 };
 
+struct xfrm_encap_tmpl {
+       __u16           encap_type;
+       __u16           encap_sport;
+       __u16           encap_dport;
+};
+
 /* Netlink message attributes.  */
 enum xfrm_attr_type_t {
        XFRMA_UNSPEC,
        XFRMA_ALG_AUTH,         /* struct xfrm_algo */
        XFRMA_ALG_CRYPT,        /* struct xfrm_algo */
        XFRMA_ALG_COMP,         /* struct xfrm_algo */
+       XFRMA_ENCAP,            /* struct xfrm_algo + struct xfrm_encap_tmpl */
        XFRMA_TMPL,             /* 1 or more struct xfrm_user_tmpl */
 
 #define XFRMA_MAX XFRMA_TMPL
index 85ff3a302e78177106a551e39dbd0936917ee71a..f8706d30b1a6e919d7541bccdfa12058462b0e22 100644 (file)
@@ -118,6 +118,7 @@ struct xfrm_state
        struct xfrm_algo        *aalg;
        struct xfrm_algo        *ealg;
        struct xfrm_algo        *calg;
+       struct xfrm_algo        *encap_alg;
 
        /* State for replay detection */
        struct xfrm_replay_state replay;
@@ -192,6 +193,7 @@ extern int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo);
 extern struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family);
 extern void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo);
 
+struct xfrm_decap_state;
 struct xfrm_type
 {
        char                    *description;
@@ -200,7 +202,8 @@ struct xfrm_type
 
        int                     (*init_state)(struct xfrm_state *x, void *args);
        void                    (*destructor)(struct xfrm_state *);
-       int                     (*input)(struct xfrm_state *, struct sk_buff *skb);
+       int                     (*input)(struct xfrm_state *, struct xfrm_decap_state *, struct sk_buff *skb);
+       int                     (*post_input)(struct xfrm_state *, struct xfrm_decap_state *, struct sk_buff *skb);
        int                     (*output)(struct sk_buff *skb);
        /* Estimate maximal size of result of transformation of a dgram */
        u32                     (*get_max_size)(struct xfrm_state *, int size);
@@ -246,7 +249,7 @@ struct xfrm_tmpl
        __u32                   calgos;
 };
 
-#define XFRM_MAX_DEPTH         3
+#define XFRM_MAX_DEPTH         4
 
 struct xfrm_policy
 {
@@ -278,6 +281,7 @@ struct xfrm_mgr
        int                     (*notify)(struct xfrm_state *x, int event);
        int                     (*acquire)(struct xfrm_state *x, struct xfrm_tmpl *, struct xfrm_policy *xp, int dir);
        struct xfrm_policy      *(*compile_policy)(u16 family, int opt, u8 *data, int len, int *dir);
+       int                     (*new_mapping)(struct xfrm_state *x, xfrm_address_t *ipaddr, u16 sport);
 };
 
 extern int xfrm_register_km(struct xfrm_mgr *km);
@@ -498,12 +502,26 @@ struct xfrm_dst
        } u;
 };
 
+/* Decapsulation state, used by the input to store data during
+ * decapsulation procedure, to be used later (during the policy
+ * check
+ */
+struct xfrm_decap_state {
+       __u16   decap_type;
+       char    decap_data[30];
+};   
+
+struct sec_decap_state {
+       struct xfrm_state       *xvec;
+       struct xfrm_decap_state decap;
+};
+
 struct sec_path
 {
        kmem_cache_t            *pool;
        atomic_t                refcnt;
        int                     len;
-       struct xfrm_state       *xvec[XFRM_MAX_DEPTH];
+       struct sec_decap_state  x[XFRM_MAX_DEPTH];
 };
 
 static inline struct sec_path *
@@ -730,6 +748,7 @@ extern int xfrm_replay_check(struct xfrm_state *x, u32 seq);
 extern void xfrm_replay_advance(struct xfrm_state *x, u32 seq);
 extern int xfrm_check_selectors(struct xfrm_state **x, int n, struct flowi *fl);
 extern int xfrm4_rcv(struct sk_buff *skb);
+extern int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type);
 extern int xfrm6_rcv(struct sk_buff **pskb);
 extern int xfrm6_clear_mutable_options(struct sk_buff *skb, u16 *nh_offset, int dir);
 extern int xfrm_user_policy(struct sock *sk, int optname, u8 *optval, int optlen);
@@ -760,6 +779,7 @@ extern wait_queue_head_t km_waitq;
 extern void km_warn_expired(struct xfrm_state *x);
 extern void km_expired(struct xfrm_state *x);
 extern int km_query(struct xfrm_state *x, struct xfrm_tmpl *, struct xfrm_policy *pol);
+extern int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, u16 sport);
 
 extern void xfrm4_input_init(void);
 extern void xfrm6_input_init(void);
index ca11e8cb8425bff0b5332c3ce14e41a53ab24646..1f4830a9431900b1ef623d902e936e6051a53f1f 100644 (file)
@@ -152,7 +152,7 @@ error_nolock:
        return err;
 }
 
-int ah_input(struct xfrm_state *x, struct sk_buff *skb)
+int ah_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struct sk_buff *skb)
 {
        int ah_hlen;
        struct iphdr *iph;
index cb5187f8a586fa99305d1db5d979ef5a172cf3bd..0e8a110a9254510e87d11db5f2c6e2ad351b2b74 100644 (file)
@@ -8,10 +8,17 @@
 #include <linux/pfkeyv2.h>
 #include <linux/random.h>
 #include <net/icmp.h>
-
+#include <net/udp.h>
 
 #define MAX_SG_ONSTACK 4
 
+/* encapsulation data for use when post-processing the decapsulation */
+struct esp_encap_data {
+       __u8            proto;
+       xfrm_address_t  saddr;
+       __u16           sport;
+};
+
 int esp_output(struct sk_buff *skb)
 {
        int err;
@@ -22,6 +29,8 @@ int esp_output(struct sk_buff *skb)
        struct crypto_tfm *tfm;
        struct esp_data *esp;
        struct sk_buff *trailer;
+       struct udphdr *uh = NULL;
+       struct xfrm_encap_tmpl *encap = NULL;
        int blksize;
        int clen;
        int alen;
@@ -76,10 +85,29 @@ int esp_output(struct sk_buff *skb)
        *(u8*)(trailer->tail + clen-skb->len - 2) = (clen - skb->len)-2;
        pskb_put(skb, trailer, clen - skb->len);
 
+       if (x->encap_alg)
+               encap = (struct xfrm_encap_tmpl *) (x->encap_alg->alg_key);
+
        iph = skb->nh.iph;
        if (x->props.mode) {
                top_iph = (struct iphdr*)skb_push(skb, x->props.header_len);
                esph = (struct ip_esp_hdr*)(top_iph+1);
+               if (encap && encap->encap_type) {
+                       switch (encap->encap_type) {
+                       case UDP_ENCAP_ESPINUDP:
+                               uh = (struct udphdr*) esph;
+                               esph = (struct ip_esp_hdr*)(uh+1);
+                               top_iph->protocol = IPPROTO_UDP;
+                               break;
+                       default:
+                               printk(KERN_INFO
+                                      "esp_output(): Unhandled encap: %u\n",
+                                      encap->encap_type);
+                               top_iph->protocol = IPPROTO_ESP;
+                               break;
+                       }
+               } else
+                       top_iph->protocol = IPPROTO_ESP;
                *(u8*)(trailer->tail - 1) = IPPROTO_IPIP;
                top_iph->ihl = 5;
                top_iph->version = 4;
@@ -89,7 +117,6 @@ int esp_output(struct sk_buff *skb)
                if (!(top_iph->frag_off))
                        ip_select_ident(top_iph, dst, 0);
                top_iph->ttl = iph->ttl;        /* TTL disclosed */
-               top_iph->protocol = IPPROTO_ESP;
                top_iph->check = 0;
                top_iph->saddr = x->props.saddr.a4;
                top_iph->daddr = x->id.daddr.a4;
@@ -98,14 +125,37 @@ int esp_output(struct sk_buff *skb)
                esph = (struct ip_esp_hdr*)skb_push(skb, x->props.header_len);
                top_iph = (struct iphdr*)skb_push(skb, iph->ihl*4);
                memcpy(top_iph, &tmp_iph, iph->ihl*4);
+               if (encap && encap->encap_type) {
+                       switch (encap->encap_type) {
+                       case UDP_ENCAP_ESPINUDP:
+                               uh = (struct udphdr*) esph;
+                               esph = (struct ip_esp_hdr*)(uh+1);
+                               top_iph->protocol = IPPROTO_UDP;
+                               break;
+                       default:
+                               printk(KERN_INFO
+                                      "esp_output(): Unhandled encap: %u\n",
+                                      encap->encap_type);
+                               top_iph->protocol = IPPROTO_ESP;
+                               break;
+                       }
+               } else
+                       top_iph->protocol = IPPROTO_ESP;
                iph = &tmp_iph.iph;
                top_iph->tot_len = htons(skb->len + alen);
-               top_iph->protocol = IPPROTO_ESP;
                top_iph->check = 0;
                top_iph->frag_off = iph->frag_off;
                *(u8*)(trailer->tail - 1) = iph->protocol;
        }
 
+       /* this is non-NULL only with UDP Encapsulation */
+       if (encap && uh) {
+               uh->source = encap->encap_sport;
+               uh->dest = encap->encap_dport;
+               uh->len = htons(skb->len + alen - sizeof(struct iphdr));
+               uh->check = 0;
+       }
+
        esph->spi = x->id.spi;
        esph->seq_no = htonl(++x->replay.oseq);
 
@@ -163,7 +213,7 @@ error_nolock:
  * expensive, so we only support truncated data, which is the recommended
  * and common case.
  */
-int esp_input(struct xfrm_state *x, struct sk_buff *skb)
+int esp_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struct sk_buff *skb)
 {
        struct iphdr *iph;
        struct ip_esp_hdr *esph;
@@ -173,6 +223,7 @@ int esp_input(struct xfrm_state *x, struct sk_buff *skb)
        int alen = esp->auth.icv_trunc_len;
        int elen = skb->len - sizeof(struct ip_esp_hdr) - esp->conf.ivlen - alen;
        int nfrags;
+       int encap_len = 0;
 
        if (!pskb_may_pull(skb, sizeof(struct ip_esp_hdr)))
                goto out;
@@ -234,11 +285,45 @@ int esp_input(struct xfrm_state *x, struct sk_buff *skb)
 
                /* ... check padding bits here. Silly. :-) */ 
 
+               if (x->encap_alg && decap && decap->decap_type) {
+                       struct esp_encap_data *encap_data;
+                       struct udphdr *uh = (struct udphdr *) (iph+1);
+
+                       encap_data = (struct esp_encap_data *) (decap->decap_data);
+                       encap_data->proto = 0;
+
+                       switch (decap->decap_type) {
+                       case UDP_ENCAP_ESPINUDP:
+
+                               if ((void*)uh == (void*)esph) {
+                                       printk(KERN_DEBUG
+                                              "esp_input(): Got ESP; expecting ESPinUDP\n");
+                                       break;
+                               }
+
+                               encap_data->proto = AF_INET;
+                               encap_data->saddr.a4 = iph->saddr;
+                               encap_data->sport = uh->source;
+                               encap_len = (void*)esph - (void*)uh;
+                               if (encap_len != sizeof(*uh))
+                                 printk(KERN_DEBUG
+                                        "esp_input(): UDP -> ESP: too much room: %d\n",
+                                        encap_len);
+                               break;
+
+                       default:
+                               printk(KERN_INFO
+                              "esp_input(): processing unknown encap type: %u\n",
+                                      decap->decap_type);
+                               break;
+                       }
+               }
+
                iph->protocol = nexthdr[1];
                pskb_trim(skb, skb->len - alen - padlen - 2);
                memcpy(workbuf, skb->nh.raw, iph->ihl*4);
                skb->h.raw = skb_pull(skb, sizeof(struct ip_esp_hdr) + esp->conf.ivlen);
-               skb->nh.raw += sizeof(struct ip_esp_hdr) + esp->conf.ivlen;
+               skb->nh.raw += encap_len + sizeof(struct ip_esp_hdr) + esp->conf.ivlen;
                memcpy(skb->nh.raw, workbuf, iph->ihl*4);
                skb->nh.iph->tot_len = htons(skb->len);
        }
@@ -249,6 +334,70 @@ out:
        return -EINVAL;
 }
 
+int esp_post_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struct sk_buff *skb)
+{
+  
+       if (x->encap_alg) {
+               struct xfrm_encap_tmpl *encap;
+               struct esp_encap_data *decap_data;
+
+               encap = (struct xfrm_encap_tmpl *) (x->encap_alg->alg_key);
+               decap_data = (struct esp_encap_data *)(decap->decap_data);
+
+               /* first, make sure that the decap type == the encap type */
+               if (encap->encap_type != decap->decap_type)
+                       return -EINVAL;
+
+               /* Next, if we don't have an encap type, then ignore it */
+               if (!encap->encap_type)
+                       return 0;
+
+               switch (encap->encap_type) {
+               case UDP_ENCAP_ESPINUDP:
+                       /*
+                        * 1) if the NAT-T peer's IP or port changed then
+                        *    advertize the change to the keying daemon.
+                        *    This is an inbound SA, so just compare
+                        *    SRC ports.
+                        */
+                       if (decap_data->proto == AF_INET &&
+                           (decap_data->saddr.a4 != x->props.saddr.a4 ||
+                            decap_data->sport != encap->encap_sport)) {
+                               xfrm_address_t ipaddr;
+
+                               ipaddr.a4 = decap_data->saddr.a4;
+                               km_new_mapping(x, &ipaddr, decap_data->sport);
+                                       
+                               /* XXX: perhaps add an extra
+                                * policy check here, to see
+                                * if we should allow or
+                                * reject a packet from a
+                                * different source
+                                * address/port.
+                                */
+                       }
+               
+                       /*
+                        * 2) ignore UDP/TCP checksums in case
+                        *    of NAT-T in Transport Mode, or
+                        *    perform other post-processing fixes
+                        *    as per * draft-ietf-ipsec-udp-encaps-06,
+                        *    section 3.1.2
+                        */
+                       if (!x->props.mode)
+                               skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+                       break;
+               default:
+                       printk(KERN_INFO
+                              "esp4_post_input(): Unhandled encap type: %u\n",
+                              encap->encap_type);
+                       break;
+               }
+       }
+       return 0;
+}
+
 static u32 esp4_get_max_size(struct xfrm_state *x, int mtu)
 {
        struct esp_data *esp = x->data;
@@ -368,6 +517,22 @@ int esp_init_state(struct xfrm_state *x, void *args)
        x->props.header_len = sizeof(struct ip_esp_hdr) + esp->conf.ivlen;
        if (x->props.mode)
                x->props.header_len += sizeof(struct iphdr);
+       if (x->encap_alg) {
+               struct xfrm_encap_tmpl *encap = (struct xfrm_encap_tmpl *)
+                       (x->encap_alg->alg_key);
+               if (encap->encap_type) {
+                       switch (encap->encap_type) {
+                       case UDP_ENCAP_ESPINUDP:
+                               x->props.header_len += sizeof(struct udphdr);
+                               break;
+                       default:
+                               printk (KERN_INFO
+                               "esp_init_state(): Unhandled encap type: %u\n",
+                                       encap->encap_type);
+                               break;
+                       }
+               }
+       }
        x->data = esp;
        x->props.trailer_len = esp4_get_max_size(x, 0) - x->props.header_len;
        return 0;
@@ -393,6 +558,7 @@ static struct xfrm_type esp_type =
        .destructor     = esp_destroy,
        .get_max_size   = esp4_get_max_size,
        .input          = esp_input,
+       .post_input     = esp_post_input,
        .output         = esp_output
 };
 
index 29212d8160f214507c7fad1a096962dcb1d15ee4..0d3c90f7b8fd6b91b4de8eefda4938ff639138d5 100644 (file)
@@ -69,6 +69,7 @@
  *     YOSHIFUJI Hideaki @USAGI and:   Support IPV6_V6ONLY socket option, which
  *     Alexey Kuznetsov:               allow both IPv4 and IPv6 sockets to bind
  *                                     a single port at the same time.
+ *     Derek Atkins <derek@ihtfp.com>: Add Encapulation Support
  *
  *
  *             This program is free software; you can redistribute it and/or
@@ -941,8 +942,90 @@ static void udp_close(struct sock *sk, long timeout)
        inet_sock_release(sk);
 }
 
+/* return:
+ *     1  if the the UDP system should process it
+ *     0  if we should drop this packet
+ *     -1 if it should get processed by xfrm4_rcv_encap
+ */
+static int udp_encap_rcv(struct sock * sk, struct sk_buff *skb)
+{
+       struct udp_opt *up = udp_sk(sk);
+       struct udphdr *uh = skb->h.uh;
+       struct iphdr *iph;
+       int iphlen, len;
+  
+       __u8 *udpdata = (__u8 *)uh + sizeof(struct udphdr);
+       __u32 *udpdata32 = (__u32 *)udpdata;
+       __u16 encap_type = up->encap_type;
+
+       /* if we're overly short, let UDP handle it */
+       if (udpdata > skb->tail)
+               return 1;
+
+       /* if this is not encapsulated socket, then just return now */
+       if (!encap_type)
+               return 1;
+
+       len = skb->tail - udpdata;
+
+       switch (encap_type) {
+       case UDP_ENCAP_ESPINUDP:
+               /* Check if this is a keepalive packet.  If so, eat it. */
+               if (len == 1 && udpdata[0] == 0xff) {
+                       return 0;
+               } else if (len > sizeof(struct ip_esp_hdr) && udpdata32[0] != 0 ) {
+                       /* ESP Packet without Non-ESP header */
+                       len = sizeof(struct udphdr);
+               } else
+                       /* Must be an IKE packet.. pass it through */
+                       return 1;
+
+               /* At this point we are sure that this is an ESPinUDP packet,
+                * so we need to remove 'len' bytes from the packet (the UDP
+                * header and optional ESP marker bytes) and then modify the
+                * protocol to ESP, and then call into the transform receiver.
+                */
+
+               /* Now we can update and verify the packet length... */
+               iph = skb->nh.iph;
+               iphlen = iph->ihl << 2;
+               iph->tot_len = htons(ntohs(iph->tot_len) - len);
+               if (skb->len < iphlen + len) {
+                       /* packet is too small!?! */
+                       return 0;
+               }
+
+               /* pull the data buffer up to the ESP header and set the
+                * transport header to point to ESP.  Keep UDP on the stack
+                * for later.
+                */
+               skb->h.raw = skb_pull(skb, len);
+
+               /* modify the protocol (it's ESP!) */
+               iph->protocol = IPPROTO_ESP;
+
+               /* and let the caller know to send this into the ESP processor... */
+               return -1;
+
+       default:
+               printk(KERN_INFO "udp_encap_rcv(): Unhandled UDP encap type: %u\n",
+                      encap_type);
+               return 1;
+       }
+}
+
+/* returns:
+ *  -1: error
+ *   0: success
+ *  >0: "udp encap" protocol resubmission
+ *
+ * Note that in the success and error cases, the skb is assumed to
+ * have either been requeued or freed.
+ */
 static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
 {
+       struct udp_opt *up = udp_sk(sk);
+
        /*
         *      Charge it to the socket, dropping if the queue is full.
         */
@@ -951,6 +1034,33 @@ static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
                return -1;
        }
 
+       if (up->encap_type) {
+               /*
+                * This is an encapsulation socket, so let's see if this is
+                * an encapsulated packet.
+                * If it's a keepalive packet, then just eat it.
+                * If it's an encapsulateed packet, then pass it to the
+                * IPsec xfrm input and return the response
+                * appropriately.  Otherwise, just fall through and
+                * pass this up the UDP socket.
+                */
+               int ret;
+
+               ret = udp_encap_rcv(sk, skb);
+               if (ret == 0) {
+                       /* Eat the packet .. */
+                       kfree_skb(skb);
+                       return 0;
+               }
+               if (ret < 0) {
+                       /* process the ESP packet */
+                       ret = xfrm4_rcv_encap(skb, up->encap_type);
+                       UDP_INC_STATS_BH(UdpInDatagrams);
+                       return -ret;
+               }
+               /* FALLTHROUGH -- it's a UDP Packet */
+       }
+
        if (sk->filter && skb->ip_summed != CHECKSUM_UNNECESSARY) {
                if (__udp_checksum_complete(skb)) {
                        UDP_INC_STATS_BH(UdpInErrors);
@@ -996,8 +1106,13 @@ static int udp_v4_mcast_deliver(struct sk_buff *skb, struct udphdr *uh,
                        if(sknext)
                                skb1 = skb_clone(skb, GFP_ATOMIC);
 
-                       if(skb1)
-                               udp_queue_rcv_skb(sk, skb1);
+                       if(skb1) {
+                               int ret = udp_queue_rcv_skb(sk, skb1);
+                               if (ret > 0)
+                                       /* we should probably re-process instead
+                                        * of dropping packets here. */
+                                       kfree_skb(skb1);
+                       }
                        sk = sknext;
                } while(sknext);
        } else
@@ -1070,8 +1185,14 @@ int udp_rcv(struct sk_buff *skb)
        sk = udp_v4_lookup(saddr, uh->source, daddr, uh->dest, skb->dev->ifindex);
 
        if (sk != NULL) {
-               udp_queue_rcv_skb(sk, skb);
+               int ret = udp_queue_rcv_skb(sk, skb);
                sock_put(sk);
+
+               /* a return value > 0 means to resubmit the input, but
+                * it it wants the return to be -protocol, or 0
+                */
+               if (ret > 0)
+                       return -ret;
                return 0;
        }
 
@@ -1163,6 +1284,10 @@ static int udp_setsockopt(struct sock *sk, int level, int optname,
                }
                break;
                
+       case UDP_ENCAP:
+               up->encap_type = val;
+               break;
+
        default:
                err = -ENOPROTOOPT;
                break;
@@ -1193,6 +1318,10 @@ static int udp_getsockopt(struct sock *sk, int level, int optname,
                val = up->corkflag;
                break;
 
+       case UDP_ENCAP:
+               val = up->encap_type;
+               break;
+
        default:
                return -ENOPROTOOPT;
        };
index 520243e9b903d666e5e340a80ff3a842e5b4b628..b98f9f65557f6faa0906b0a841ed02dde15fd58c 100644 (file)
@@ -4,6 +4,8 @@
  * Changes:
  *     YOSHIFUJI Hideaki @USAGI
  *             Split up af-specific portion
+ *     Derek Atkins <derek@ihtfp.com>
+ *             Add Encapsulation support
  *     
  */
 
 static kmem_cache_t *secpath_cachep;
 
 int xfrm4_rcv(struct sk_buff *skb)
+{
+       return xfrm4_rcv_encap(skb, 0);
+}
+
+int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type)
 {
        int err;
        u32 spi, seq;
-       struct xfrm_state *xfrm_vec[XFRM_MAX_DEPTH];
+       struct sec_decap_state xfrm_vec[XFRM_MAX_DEPTH];
        struct xfrm_state *x;
        int xfrm_nr = 0;
        int decaps = 0;
@@ -41,9 +48,13 @@ int xfrm4_rcv(struct sk_buff *skb)
                if (x->props.replay_window && xfrm_replay_check(x, seq))
                        goto drop_unlock;
 
-               if (x->type->input(x, skb))
+               xfrm_vec[xfrm_nr].decap.decap_type = encap_type;
+               if (x->type->input(x, &(xfrm_vec[xfrm_nr].decap), skb))
                        goto drop_unlock;
 
+               /* only the first xfrm gets the encap type */
+               encap_type = 0;
+
                if (x->props.replay_window)
                        xfrm_replay_advance(x, seq);
 
@@ -53,7 +64,7 @@ int xfrm4_rcv(struct sk_buff *skb)
 
                spin_unlock(&x->lock);
 
-               xfrm_vec[xfrm_nr++] = x;
+               xfrm_vec[xfrm_nr++].xvec = x;
 
                iph = skb->nh.iph;
 
@@ -92,7 +103,7 @@ int xfrm4_rcv(struct sk_buff *skb)
        if (xfrm_nr + skb->sp->len > XFRM_MAX_DEPTH)
                goto drop;
 
-       memcpy(skb->sp->xvec+skb->sp->len, xfrm_vec, xfrm_nr*sizeof(void*));
+       memcpy(skb->sp->x+skb->sp->len, xfrm_vec, xfrm_nr*sizeof(struct sec_decap_state));
        skb->sp->len += xfrm_nr;
 
        if (decaps) {
@@ -111,7 +122,8 @@ drop_unlock:
        xfrm_state_put(x);
 drop:
        while (--xfrm_nr >= 0)
-               xfrm_state_put(xfrm_vec[xfrm_nr]);
+               xfrm_state_put(xfrm_vec[xfrm_nr].xvec);
+
        kfree_skb(skb);
        return 0;
 }
index c3c618f317e2c4b9f4993af292c3c4b229995211..0130c3b7889b297e581da9e2facabb5ed8057c2b 100644 (file)
@@ -146,7 +146,7 @@ error_nolock:
        return err;
 }
 
-int ah6_input(struct xfrm_state *x, struct sk_buff *skb)
+int ah6_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struct sk_buff *skb)
 {
        int ah_hlen;
        struct ipv6hdr *iph;
index c0d79ba6ef39f5a8a1e2638ea171f7e76b3a95df..5f9275aabf0f57c2172b58aa0396e2c27c6cadcd 100644 (file)
@@ -254,7 +254,7 @@ error_nolock:
        return err;
 }
 
-int esp6_input(struct xfrm_state *x, struct sk_buff *skb)
+int esp6_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struct sk_buff *skb)
 {
        struct ipv6hdr *iph;
        struct ipv6_esp_hdr *esph;
index 8363a4e9d7e59ed9418d6d0ce728353733238acf..672142ab753cd9836b9a1a96a996b8fc24ce92cf 100644 (file)
@@ -128,7 +128,7 @@ int xfrm6_rcv(struct sk_buff **pskb)
        struct sk_buff *skb = *pskb;
        int err;
        u32 spi, seq;
-       struct xfrm_state *xfrm_vec[XFRM_MAX_DEPTH];
+       struct sec_decap_state xfrm_vec[XFRM_MAX_DEPTH];
        struct xfrm_state *x;
        int xfrm_nr = 0;
        int decaps = 0;
@@ -172,7 +172,7 @@ int xfrm6_rcv(struct sk_buff **pskb)
                if (x->props.replay_window && xfrm_replay_check(x, seq))
                        goto drop_unlock;
 
-               nexthdr = x->type->input(x, skb);
+               nexthdr = x->type->input(x, &(xfrm_vec[xfrm_nr].decap), skb);
                if (nexthdr <= 0)
                        goto drop_unlock;
 
@@ -185,7 +185,7 @@ int xfrm6_rcv(struct sk_buff **pskb)
 
                spin_unlock(&x->lock);
 
-               xfrm_vec[xfrm_nr++] = x;
+               xfrm_vec[xfrm_nr++].xvec = x;
 
                iph = skb->nh.ipv6h;
 
@@ -229,7 +229,7 @@ int xfrm6_rcv(struct sk_buff **pskb)
        if (xfrm_nr + skb->sp->len > XFRM_MAX_DEPTH)
                goto drop;
 
-       memcpy(skb->sp->xvec+skb->sp->len, xfrm_vec, xfrm_nr*sizeof(void*));
+       memcpy(skb->sp->x+skb->sp->len, xfrm_vec, xfrm_nr*sizeof(struct sec_decap_state));
        skb->sp->len += xfrm_nr;
 
        if (decaps) {
@@ -249,7 +249,7 @@ drop_unlock:
 drop:
        if (tmp_hdr) kfree(tmp_hdr);
        while (--xfrm_nr >= 0)
-               xfrm_state_put(xfrm_vec[xfrm_nr]);
+               xfrm_state_put(xfrm_vec[xfrm_nr].xvec);
        kfree_skb(skb);
        return 0;
 }
index 257c153b4733cdc29a4207afa3e2b2dbbd1e6e03..8c005a7f306af4d0cc169041a27ae164af2c3977 100644 (file)
@@ -11,6 +11,7 @@
  *             Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
  *             Kunihiro Ishiguro <kunihiro@ipinfusion.com>
  *             Kazunori MIYAZAWA / USAGI Project <miyazawa@linux-ipv6.org>
+ *             Derek Atkins <derek@ihtfp.com>
  */
 
 #include <linux/config.h>
@@ -345,6 +346,10 @@ static u8 sadb_ext_min_len[] = {
        [SADB_X_EXT_KMPRIVATE]          = (u8) sizeof(struct sadb_x_kmprivate),
        [SADB_X_EXT_POLICY]             = (u8) sizeof(struct sadb_x_policy),
        [SADB_X_EXT_SA2]                = (u8) sizeof(struct sadb_x_sa2),
+       [SADB_X_EXT_NAT_T_TYPE]         = (u8) sizeof(struct sadb_x_nat_t_type),
+       [SADB_X_EXT_NAT_T_SPORT]        = (u8) sizeof(struct sadb_x_nat_t_port),
+       [SADB_X_EXT_NAT_T_DPORT]        = (u8) sizeof(struct sadb_x_nat_t_port),
+       [SADB_X_EXT_NAT_T_OA]           = (u8) sizeof(struct sadb_address),
 };
 
 /* Verify sadb_address_{len,prefixlen} against sa_family.  */
@@ -442,7 +447,8 @@ static int parse_exthdrs(struct sk_buff *skb, struct sadb_msg *hdr, void **ext_h
                                return -EINVAL;
                        if (ext_type == SADB_EXT_ADDRESS_SRC ||
                            ext_type == SADB_EXT_ADDRESS_DST ||
-                           ext_type == SADB_EXT_ADDRESS_PROXY) {
+                           ext_type == SADB_EXT_ADDRESS_PROXY ||
+                           ext_type == SADB_X_EXT_NAT_T_OA) {
                                if (verify_address_len(p))
                                        return -EINVAL;
                        }                               
@@ -601,6 +607,7 @@ static struct sk_buff * pfkey_xfrm_state2msg(struct xfrm_state *x, int add_keys,
        int auth_key_size = 0;
        int encrypt_key_size = 0;
        int sockaddr_size;
+       struct xfrm_encap_tmpl *natt = NULL;
 
        /* address family check */
        sockaddr_size = pfkey_sockaddr_size(x->props.family);
@@ -639,6 +646,15 @@ static struct sk_buff * pfkey_xfrm_state2msg(struct xfrm_state *x, int add_keys,
                        size += sizeof(struct sadb_key) + encrypt_key_size;
                }
        }
+       if (x->encap_alg)
+               natt = (struct xfrm_encap_tmpl *) (x->encap_alg->alg_key);
+
+       if (natt && natt->encap_type) {
+               size += sizeof(struct sadb_x_nat_t_type);
+               size += sizeof(struct sadb_x_nat_t_port);
+               size += sizeof(struct sadb_x_nat_t_port);
+       }
+
        skb =  alloc_skb(size + 16, GFP_ATOMIC);
        if (skb == NULL)
                return ERR_PTR(-ENOBUFS);
@@ -858,6 +874,34 @@ static struct sk_buff * pfkey_xfrm_state2msg(struct xfrm_state *x, int add_keys,
        sa2->sadb_x_sa2_sequence = 0;
        sa2->sadb_x_sa2_reqid = x->props.reqid;
 
+       if (natt && natt->encap_type) {
+               struct sadb_x_nat_t_type *n_type;
+               struct sadb_x_nat_t_port *n_port;
+
+               /* type */
+               n_type = (struct sadb_x_nat_t_type*) skb_put(skb, sizeof(*n_type));
+               n_type->sadb_x_nat_t_type_len = sizeof(*n_type)/sizeof(uint64_t);
+               n_type->sadb_x_nat_t_type_exttype = SADB_X_EXT_NAT_T_TYPE;
+               n_type->sadb_x_nat_t_type_type = natt->encap_type;
+               n_type->sadb_x_nat_t_type_reserved[0] = 0;
+               n_type->sadb_x_nat_t_type_reserved[1] = 0;
+               n_type->sadb_x_nat_t_type_reserved[2] = 0;
+
+               /* source port */
+               n_port = (struct sadb_x_nat_t_port*) skb_put(skb, sizeof (*n_port));
+               n_port->sadb_x_nat_t_port_len = sizeof(*n_port)/sizeof(uint64_t);
+               n_port->sadb_x_nat_t_port_exttype = SADB_X_EXT_NAT_T_SPORT;
+               n_port->sadb_x_nat_t_port_port = natt->encap_sport;
+               n_port->sadb_x_nat_t_port_reserved = 0;
+
+               /* dest port */
+               n_port = (struct sadb_x_nat_t_port*) skb_put(skb, sizeof (*n_port));
+               n_port->sadb_x_nat_t_port_len = sizeof(*n_port)/sizeof(uint64_t);
+               n_port->sadb_x_nat_t_port_exttype = SADB_X_EXT_NAT_T_DPORT;
+               n_port->sadb_x_nat_t_port_port = natt->encap_dport;
+               n_port->sadb_x_nat_t_port_reserved = 0;
+       }
+
        return skb;
 }
 
@@ -1017,6 +1061,32 @@ static struct xfrm_state * pfkey_msg2xfrm_state(struct sadb_msg *hdr,
                x->sel.prefixlen_s = addr->sadb_address_prefixlen;
        }
 
+       if (ext_hdrs[SADB_X_EXT_NAT_T_TYPE-1]) {
+               struct sadb_x_nat_t_type* n_type;
+               struct xfrm_encap_tmpl *natt;
+               int obits = (sizeof *natt);
+
+               x->encap_alg = kmalloc(sizeof(*x->encap_alg) + obits, GFP_KERNEL);
+               if (!x->encap_alg)
+                       goto out;
+
+               strcpy(x->encap_alg->alg_name, "NAT-T");
+               natt = (struct xfrm_encap_tmpl *) (x->encap_alg->alg_key);
+               n_type = ext_hdrs[SADB_X_EXT_NAT_T_TYPE-1];
+               natt->encap_type = n_type->sadb_x_nat_t_type_type;
+
+               if (ext_hdrs[SADB_X_EXT_NAT_T_SPORT-1]) {
+                       struct sadb_x_nat_t_port* n_port =
+                               ext_hdrs[SADB_X_EXT_NAT_T_SPORT-1];
+                       natt->encap_sport = n_port->sadb_x_nat_t_port_port;
+               }
+               if (ext_hdrs[SADB_X_EXT_NAT_T_DPORT-1]) {
+                       struct sadb_x_nat_t_port* n_port =
+                               ext_hdrs[SADB_X_EXT_NAT_T_DPORT-1];
+                       natt->encap_dport = n_port->sadb_x_nat_t_port_port;
+               }
+       }
+
        x->type = xfrm_get_type(proto, x->props.family);
        if (x->type == NULL)
                goto out;
@@ -1033,6 +1103,8 @@ out:
                kfree(x->ealg);
        if (x->calg)
                kfree(x->calg);
+       if (x->encap_alg)
+               kfree(x->encap_alg);
        kfree(x);
        return ERR_PTR(-ENOBUFS);
 }
@@ -2051,7 +2123,6 @@ static int pfkey_spdflush(struct sock *sk, struct sk_buff *skb, struct sadb_msg
        return 0;
 }
 
-
 typedef int (*pfkey_handler)(struct sock *sk, struct sk_buff *skb,
                             struct sadb_msg *hdr, void **ext_hdrs);
 static pfkey_handler pfkey_funcs[SADB_MAX + 1] = {
@@ -2467,6 +2538,155 @@ out:
        return NULL;
 }
 
+static int pfkey_send_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, u16 sport)
+{
+       struct sk_buff *skb;
+       struct sadb_msg *hdr;
+       struct sadb_sa *sa;
+       struct sadb_address *addr;
+       struct sadb_x_nat_t_port *n_port;
+       struct sockaddr_in *sin;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       struct sockaddr_in6 *sin6;
+#endif
+       int sockaddr_size;
+       int size;
+       __u8 satype = (x->id.proto == IPPROTO_ESP ? SADB_SATYPE_ESP : 0);
+       struct xfrm_encap_tmpl *natt = NULL;
+
+       sockaddr_size = pfkey_sockaddr_size(x->props.family);
+       if (!sockaddr_size)
+               return -EINVAL;
+
+       if (!satype)
+               return -EINVAL;
+
+       if (!x->encap_alg)
+               return -EINVAL;
+
+       natt = (struct xfrm_encap_tmpl *) (x->encap_alg->alg_key);
+
+       /* Build an SADB_X_NAT_T_NEW_MAPPING message:
+        *
+        * HDR | SA | ADDRESS_SRC (old addr) | NAT_T_SPORT (old port) |
+        * ADDRESS_DST (new addr) | NAT_T_DPORT (new port)
+        */
+       
+       size = sizeof(struct sadb_msg) +
+               sizeof(struct sadb_sa) +
+               (sizeof(struct sadb_address) * 2) +
+               (sockaddr_size * 2) +
+               (sizeof(struct sadb_x_nat_t_port) * 2);
+       
+       skb =  alloc_skb(size + 16, GFP_ATOMIC);
+       if (skb == NULL)
+               return -ENOMEM;
+       
+       hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg));
+       hdr->sadb_msg_version = PF_KEY_V2;
+       hdr->sadb_msg_type = SADB_X_NAT_T_NEW_MAPPING;
+       hdr->sadb_msg_satype = satype;
+       hdr->sadb_msg_len = size / sizeof(uint64_t);
+       hdr->sadb_msg_errno = 0;
+       hdr->sadb_msg_reserved = 0;
+       hdr->sadb_msg_seq = x->km.seq = get_acqseq();
+       hdr->sadb_msg_pid = 0;
+
+       /* SA */
+       sa = (struct sadb_sa *) skb_put(skb, sizeof(struct sadb_sa));
+       sa->sadb_sa_len = sizeof(struct sadb_sa)/sizeof(uint64_t);
+       sa->sadb_sa_exttype = SADB_EXT_SA;
+       sa->sadb_sa_spi = x->id.spi;
+       sa->sadb_sa_replay = 0;
+       sa->sadb_sa_state = 0;
+       sa->sadb_sa_auth = 0;
+       sa->sadb_sa_encrypt = 0;
+       sa->sadb_sa_flags = 0;
+
+       /* ADDRESS_SRC (old addr) */
+       addr = (struct sadb_address*)
+               skb_put(skb, sizeof(struct sadb_address)+sockaddr_size);
+       addr->sadb_address_len = 
+               (sizeof(struct sadb_address)+sockaddr_size)/
+                       sizeof(uint64_t);
+       addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
+       addr->sadb_address_proto = 0;
+       addr->sadb_address_reserved = 0;
+       if (x->props.family == AF_INET) {
+               addr->sadb_address_prefixlen = 32;
+
+               sin = (struct sockaddr_in *) (addr + 1);
+               sin->sin_family = AF_INET;
+               sin->sin_addr.s_addr = x->props.saddr.a4;
+               sin->sin_port = 0;
+               memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
+       }
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       else if (x->props.family == AF_INET6) {
+               addr->sadb_address_prefixlen = 128;
+
+               sin6 = (struct sockaddr_in6 *) (addr + 1);
+               sin6->sin6_family = AF_INET6;
+               sin6->sin6_port = 0;
+               sin6->sin6_flowinfo = 0;
+               memcpy(&sin6->sin6_addr,
+                      x->props.saddr.a6, sizeof(struct in6_addr));
+               sin6->sin6_scope_id = 0;
+       }
+#endif
+       else
+               BUG();
+
+       /* NAT_T_SPORT (old port) */
+       n_port = (struct sadb_x_nat_t_port*) skb_put(skb, sizeof (*n_port));
+       n_port->sadb_x_nat_t_port_len = sizeof(*n_port)/sizeof(uint64_t);
+       n_port->sadb_x_nat_t_port_exttype = SADB_X_EXT_NAT_T_SPORT;
+       n_port->sadb_x_nat_t_port_port = natt->encap_sport;
+       n_port->sadb_x_nat_t_port_reserved = 0;
+
+       /* ADDRESS_DST (new addr) */
+       addr = (struct sadb_address*)
+               skb_put(skb, sizeof(struct sadb_address)+sockaddr_size);
+       addr->sadb_address_len = 
+               (sizeof(struct sadb_address)+sockaddr_size)/
+                       sizeof(uint64_t);
+       addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
+       addr->sadb_address_proto = 0;
+       addr->sadb_address_reserved = 0;
+       if (x->props.family == AF_INET) {
+               addr->sadb_address_prefixlen = 32;
+
+               sin = (struct sockaddr_in *) (addr + 1);
+               sin->sin_family = AF_INET;
+               sin->sin_addr.s_addr = ipaddr->a4;
+               sin->sin_port = 0;
+               memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
+       }
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+       else if (x->props.family == AF_INET6) {
+               addr->sadb_address_prefixlen = 128;
+
+               sin6 = (struct sockaddr_in6 *) (addr + 1);
+               sin6->sin6_family = AF_INET6;
+               sin6->sin6_port = 0;
+               sin6->sin6_flowinfo = 0;
+               memcpy(&sin6->sin6_addr, &ipaddr->a6, sizeof(struct in6_addr));
+               sin6->sin6_scope_id = 0;
+       }
+#endif
+       else
+               BUG();
+
+       /* NAT_T_DPORT (new port) */
+       n_port = (struct sadb_x_nat_t_port*) skb_put(skb, sizeof (*n_port));
+       n_port->sadb_x_nat_t_port_len = sizeof(*n_port)/sizeof(uint64_t);
+       n_port->sadb_x_nat_t_port_exttype = SADB_X_EXT_NAT_T_DPORT;
+       n_port->sadb_x_nat_t_port_port = sport;
+       n_port->sadb_x_nat_t_port_reserved = 0;
+
+       return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL);
+}
+
 static int pfkey_sendmsg(struct kiocb *kiocb,
                         struct socket *sock, struct msghdr *msg, int len)
 {
@@ -2632,6 +2852,7 @@ static struct xfrm_mgr pfkeyv2_mgr =
        .notify         = pfkey_send_notify,
        .acquire        = pfkey_send_acquire,
        .compile_policy = pfkey_compile_policy,
+       .new_mapping    = pfkey_send_new_mapping,
 };
 
 static void __exit ipsec_pfkey_exit(void)
index cfed5eef7c29acc0a25361ce2dcd9265ca8da28b..b678bb9df90d73d8001491664e53b822d6a75309 100644 (file)
@@ -292,6 +292,7 @@ EXPORT_SYMBOL(dlci_ioctl_hook);
 
 EXPORT_SYMBOL(xfrm_user_policy);
 EXPORT_SYMBOL(km_waitq);
+EXPORT_SYMBOL(km_new_mapping);
 EXPORT_SYMBOL(xfrm_cfg_sem);
 EXPORT_SYMBOL(xfrm_policy_alloc);
 EXPORT_SYMBOL(__xfrm_policy_destroy);
index a64b19a5c09ca0277f01d5a898af47cce460fd75..e37d0179ba80b948cbe2ccbf265f208f81feaeab 100644 (file)
@@ -14,7 +14,7 @@ void __secpath_destroy(struct sec_path *sp)
 {
        int i;
        for (i = 0; i < sp->len; i++)
-               xfrm_state_put(sp->xvec[i]);
+               xfrm_state_put(sp->x[i].xvec);
        kmem_cache_free(sp->pool, sp);
 }
 
index 055b7fffa49d3c612571ab230d4c0dd3975c0cbe..b0460abbde2d085947e5fda34196d9aed9083302 100644 (file)
@@ -9,6 +9,7 @@
  *     Kazunori MIYAZAWA @USAGI
  *     YOSHIFUJI Hideaki
  *             Split up af-specific portion
+ *     Derek Atkins <derek@ihtfp.com>          Add the post_input processor
  *     
  */
 
@@ -889,7 +890,7 @@ xfrm_policy_ok(struct xfrm_tmpl *tmpl, struct sec_path *sp, int idx,
               unsigned short family)
 {
        for (; idx < sp->len; idx++) {
-               if (xfrm_state_ok(tmpl, sp->xvec[idx], family))
+               if (xfrm_state_ok(tmpl, sp->x[idx].xvec, family))
                        return ++idx;
        }
        return -1;
@@ -922,7 +923,15 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
                int i;
 
                for (i=skb->sp->len-1; i>=0; i--) {
-                       if (!xfrm_selector_match(&skb->sp->xvec[i]->sel, &fl, family))
+                 struct sec_decap_state *xvec = &(skb->sp->x[i]);
+                       if (!xfrm_selector_match(&xvec->xvec->sel, &fl, family))
+                               return 0;
+
+                       /* If there is a post_input processor, try running it */
+                       if (xvec->xvec->type->post_input &&
+                           (xvec->xvec->type->post_input)(xvec->xvec,
+                                                          &(xvec->decap),
+                                                          skb) != 0)
                                return 0;
                }
        }
index 75f2a2b157a3eda464d6882d798d6d6dbfc5a1a0..d1e833b0945b0ae09dc2aa3ffe70fadc4050e502 100644 (file)
@@ -8,6 +8,8 @@
  *             IPv6 support
  *     YOSHIFUJI Hideaki @USAGI
  *             Split up af-specific functions
+ *     Derek Atkins <derek@ihtfp.com>
+ *             Add UDP Encapsulation
  *     
  */
 
@@ -155,6 +157,8 @@ void __xfrm_state_destroy(struct xfrm_state *x)
                kfree(x->ealg);
        if (x->calg)
                kfree(x->calg);
+       if (x->encap_alg)
+               kfree(x->encap_alg);
        if (x->type)
                xfrm_put_type(x->type);
        kfree(x);
@@ -632,6 +636,22 @@ int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol)
        return err;
 }
 
+int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, u16 sport)
+{
+       int err = -EINVAL;
+       struct xfrm_mgr *km;
+
+       read_lock(&xfrm_km_lock);
+       list_for_each_entry(km, &xfrm_km_list, list) {
+               if (km->new_mapping)
+                       err = km->new_mapping(x, ipaddr, sport);
+               if (!err)
+                       break;
+       }
+       read_unlock(&xfrm_km_lock);
+       return err;
+}
+
 int xfrm_user_policy(struct sock *sk, int optname, u8 *optval, int optlen)
 {
        int err;