[UDP]: Introduce UDP encapsulation type for L2TP
authorJames Chapman <jchapman@katalix.com>
Wed, 27 Jun 2007 22:37:46 +0000 (15:37 -0700)
committerDavid S. Miller <davem@sunset.davemloft.net>
Wed, 11 Jul 2007 05:15:57 +0000 (22:15 -0700)
This patch adds a new UDP_ENCAP_L2TPINUDP encapsulation type for UDP
sockets. When a UDP socket's encap_type is UDP_ENCAP_L2TPINUDP, the
skb is delivered to a function pointed to by the udp_sock's
encap_rcv funcptr. If the skb isn't wanted by L2TP, it returns >0, which
causes it to be passed through to UDP.

Include padding to put the new encap_rcv field on a 4-byte boundary.

Previously, the only user of UDP encap sockets was ESP, so when
CONFIG_XFRM was not defined, some of the encap code was compiled
out. This patch changes that. As a result, udp_encap_rcv() will
now do a little more work when CONFIG_XFRM is not defined.

Signed-off-by: James Chapman <jchapman@katalix.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/linux/udp.h
net/ipv4/udp.c

index 6de445c..8ec703f 100644 (file)
@@ -42,6 +42,7 @@ static inline struct udphdr *udp_hdr(const struct sk_buff *skb)
 /* UDP encapsulation types */
 #define UDP_ENCAP_ESPINUDP_NON_IKE     1 /* draft-ietf-ipsec-nat-t-ike-00/01 */
 #define UDP_ENCAP_ESPINUDP     2 /* draft-ietf-ipsec-udp-encaps-06 */
+#define UDP_ENCAP_L2TPINUDP    3 /* rfc2661 */
 
 #ifdef __KERNEL__
 #include <linux/types.h>
@@ -70,6 +71,11 @@ struct udp_sock {
 #define UDPLITE_SEND_CC  0x2           /* set via udplite setsockopt         */
 #define UDPLITE_RECV_CC  0x4           /* set via udplite setsocktopt        */
        __u8             pcflag;        /* marks socket as UDP-Lite if > 0    */
+       __u8             unused[3];
+       /*
+        * For encapsulation sockets.
+        */
+       int (*encap_rcv)(struct sock *sk, struct sk_buff *skb);
 };
 
 static inline struct udp_sock *udp_sk(const struct sock *sk)
index facb7e2..b9276f8 100644 (file)
@@ -70,6 +70,7 @@
  *     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
+ *     James Chapman           :       Add L2TP encapsulation type.
  *
  *
  *             This program is free software; you can redistribute it and/or
@@ -923,12 +924,10 @@ int udp_disconnect(struct sock *sk, int flags)
  *     1  if the UDP system should process it
  *     0  if we should drop this packet
  *     -1 if it should get processed by xfrm4_rcv_encap
+ *     -2 if it should get processed by l2tp
  */
 static int udp_encap_rcv(struct sock * sk, struct sk_buff *skb)
 {
-#ifndef CONFIG_XFRM
-       return 1;
-#else
        struct udp_sock *up = udp_sk(sk);
        struct udphdr *uh;
        struct iphdr *iph;
@@ -983,8 +982,14 @@ static int udp_encap_rcv(struct sock * sk, struct sk_buff *skb)
                        /* Must be an IKE packet.. pass it through */
                        return 1;
                break;
+       case UDP_ENCAP_L2TPINUDP:
+               /* Let caller know to send this to l2tp */
+               return -2;
        }
 
+#ifndef CONFIG_XFRM
+       return 1;
+#else
        /* 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
@@ -1055,12 +1060,25 @@ int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
                        kfree_skb(skb);
                        return 0;
                }
-               if (ret < 0) {
+               if (ret == -1) {
                        /* process the ESP packet */
                        ret = xfrm4_rcv_encap(skb, up->encap_type);
                        UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS, up->pcflag);
                        return -ret;
                }
+               if (ret == -2) {
+                       /* process the L2TP packet */
+                       if (up->encap_rcv != NULL) {
+                               ret = (*up->encap_rcv)(sk, skb);
+                               if (ret <= 0) {
+                                       UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS, up->pcflag);
+                                       return ret;
+                               }
+
+                               /* FALLTHROUGH -- pass up as UDP packet */
+                       }
+               }
+
                /* FALLTHROUGH -- it's a UDP Packet */
        }
 
@@ -1349,6 +1367,7 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname,
                case 0:
                case UDP_ENCAP_ESPINUDP:
                case UDP_ENCAP_ESPINUDP_NON_IKE:
+               case UDP_ENCAP_L2TPINUDP:
                        up->encap_type = val;
                        break;
                default: