diff options
author | James Chapman <jchapman@katalix.com> | 2010-04-02 02:19:00 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-04-03 17:56:04 -0400 |
commit | 0d76751fad7739014485ba5bd388d4f1b4fd4143 (patch) | |
tree | 25a4525bf6b2ec9f052f22ba98cdfd3ff3a86aa3 /net/l2tp/l2tp_core.c | |
parent | e0d4435f93905f517003cfa7328a36ea19788147 (diff) |
l2tp: Add L2TPv3 IP encapsulation (no UDP) support
This patch adds a new L2TPIP socket family and modifies the core to
handle the case where there is no UDP header in the L2TP
packet. L2TP/IP uses IP protocol 115. Since L2TP/UDP and L2TP/IP
packets differ in layout, the datapath packet handling code needs
changes too. Userspace uses an L2TPIP socket instead of a UDP socket
when IP encapsulation is required.
We can't use raw sockets for this because the semantics of raw sockets
don't lend themselves to the socket-per-tunnel model - we need to
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/l2tp/l2tp_core.c')
-rw-r--r-- | net/l2tp/l2tp_core.c | 163 |
1 files changed, 103 insertions, 60 deletions
diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index 0eee1a65f1b1..1739d04367e4 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c | |||
@@ -36,8 +36,10 @@ | |||
36 | #include <linux/inetdevice.h> | 36 | #include <linux/inetdevice.h> |
37 | #include <linux/skbuff.h> | 37 | #include <linux/skbuff.h> |
38 | #include <linux/init.h> | 38 | #include <linux/init.h> |
39 | #include <linux/in.h> | ||
39 | #include <linux/ip.h> | 40 | #include <linux/ip.h> |
40 | #include <linux/udp.h> | 41 | #include <linux/udp.h> |
42 | #include <linux/l2tp.h> | ||
41 | #include <linux/hash.h> | 43 | #include <linux/hash.h> |
42 | #include <linux/sort.h> | 44 | #include <linux/sort.h> |
43 | #include <linux/file.h> | 45 | #include <linux/file.h> |
@@ -48,6 +50,7 @@ | |||
48 | #include <net/ip.h> | 50 | #include <net/ip.h> |
49 | #include <net/udp.h> | 51 | #include <net/udp.h> |
50 | #include <net/xfrm.h> | 52 | #include <net/xfrm.h> |
53 | #include <net/protocol.h> | ||
51 | 54 | ||
52 | #include <asm/byteorder.h> | 55 | #include <asm/byteorder.h> |
53 | #include <asm/atomic.h> | 56 | #include <asm/atomic.h> |
@@ -849,15 +852,21 @@ static int l2tp_build_l2tpv2_header(struct l2tp_session *session, void *buf) | |||
849 | 852 | ||
850 | static int l2tp_build_l2tpv3_header(struct l2tp_session *session, void *buf) | 853 | static int l2tp_build_l2tpv3_header(struct l2tp_session *session, void *buf) |
851 | { | 854 | { |
855 | struct l2tp_tunnel *tunnel = session->tunnel; | ||
852 | char *bufp = buf; | 856 | char *bufp = buf; |
853 | char *optr = bufp; | 857 | char *optr = bufp; |
854 | u16 flags = L2TP_HDR_VER_3; | ||
855 | 858 | ||
856 | /* Setup L2TP header. */ | 859 | /* Setup L2TP header. The header differs slightly for UDP and |
857 | *((__be16 *) bufp) = htons(flags); | 860 | * IP encapsulations. For UDP, there is 4 bytes of flags. |
858 | bufp += 2; | 861 | */ |
859 | *((__be16 *) bufp) = 0; | 862 | if (tunnel->encap == L2TP_ENCAPTYPE_UDP) { |
860 | bufp += 2; | 863 | u16 flags = L2TP_HDR_VER_3; |
864 | *((__be16 *) bufp) = htons(flags); | ||
865 | bufp += 2; | ||
866 | *((__be16 *) bufp) = 0; | ||
867 | bufp += 2; | ||
868 | } | ||
869 | |||
861 | *((__be32 *) bufp) = htonl(session->peer_session_id); | 870 | *((__be32 *) bufp) = htonl(session->peer_session_id); |
862 | bufp += 4; | 871 | bufp += 4; |
863 | if (session->cookie_len) { | 872 | if (session->cookie_len) { |
@@ -902,10 +911,11 @@ int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb, size_t dat | |||
902 | 911 | ||
903 | if (session->debug & L2TP_MSG_DATA) { | 912 | if (session->debug & L2TP_MSG_DATA) { |
904 | int i; | 913 | int i; |
905 | unsigned char *datap = skb->data + sizeof(struct udphdr); | 914 | int uhlen = (tunnel->encap == L2TP_ENCAPTYPE_UDP) ? sizeof(struct udphdr) : 0; |
915 | unsigned char *datap = skb->data + uhlen; | ||
906 | 916 | ||
907 | printk(KERN_DEBUG "%s: xmit:", session->name); | 917 | printk(KERN_DEBUG "%s: xmit:", session->name); |
908 | for (i = 0; i < (len - sizeof(struct udphdr)); i++) { | 918 | for (i = 0; i < (len - uhlen); i++) { |
909 | printk(" %02X", *datap++); | 919 | printk(" %02X", *datap++); |
910 | if (i == 31) { | 920 | if (i == 31) { |
911 | printk(" ..."); | 921 | printk(" ..."); |
@@ -956,21 +966,23 @@ static inline void l2tp_skb_set_owner_w(struct sk_buff *skb, struct sock *sk) | |||
956 | int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len) | 966 | int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len) |
957 | { | 967 | { |
958 | int data_len = skb->len; | 968 | int data_len = skb->len; |
959 | struct sock *sk = session->tunnel->sock; | 969 | struct l2tp_tunnel *tunnel = session->tunnel; |
970 | struct sock *sk = tunnel->sock; | ||
960 | struct udphdr *uh; | 971 | struct udphdr *uh; |
961 | unsigned int udp_len; | ||
962 | struct inet_sock *inet; | 972 | struct inet_sock *inet; |
963 | __wsum csum; | 973 | __wsum csum; |
964 | int old_headroom; | 974 | int old_headroom; |
965 | int new_headroom; | 975 | int new_headroom; |
966 | int headroom; | 976 | int headroom; |
977 | int uhlen = (tunnel->encap == L2TP_ENCAPTYPE_UDP) ? sizeof(struct udphdr) : 0; | ||
978 | int udp_len; | ||
967 | 979 | ||
968 | /* Check that there's enough headroom in the skb to insert IP, | 980 | /* Check that there's enough headroom in the skb to insert IP, |
969 | * UDP and L2TP headers. If not enough, expand it to | 981 | * UDP and L2TP headers. If not enough, expand it to |
970 | * make room. Adjust truesize. | 982 | * make room. Adjust truesize. |
971 | */ | 983 | */ |
972 | headroom = NET_SKB_PAD + sizeof(struct iphdr) + | 984 | headroom = NET_SKB_PAD + sizeof(struct iphdr) + |
973 | sizeof(struct udphdr) + hdr_len; | 985 | uhlen + hdr_len; |
974 | old_headroom = skb_headroom(skb); | 986 | old_headroom = skb_headroom(skb); |
975 | if (skb_cow_head(skb, headroom)) | 987 | if (skb_cow_head(skb, headroom)) |
976 | goto abort; | 988 | goto abort; |
@@ -981,18 +993,8 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len | |||
981 | 993 | ||
982 | /* Setup L2TP header */ | 994 | /* Setup L2TP header */ |
983 | session->build_header(session, __skb_push(skb, hdr_len)); | 995 | session->build_header(session, __skb_push(skb, hdr_len)); |
984 | udp_len = sizeof(struct udphdr) + hdr_len + data_len; | ||
985 | |||
986 | /* Setup UDP header */ | ||
987 | inet = inet_sk(sk); | ||
988 | __skb_push(skb, sizeof(*uh)); | ||
989 | skb_reset_transport_header(skb); | ||
990 | uh = udp_hdr(skb); | ||
991 | uh->source = inet->inet_sport; | ||
992 | uh->dest = inet->inet_dport; | ||
993 | uh->len = htons(udp_len); | ||
994 | uh->check = 0; | ||
995 | 996 | ||
997 | /* Reset skb netfilter state */ | ||
996 | memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); | 998 | memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); |
997 | IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED | | 999 | IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED | |
998 | IPSKB_REROUTED); | 1000 | IPSKB_REROUTED); |
@@ -1001,29 +1003,48 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len | |||
1001 | /* Get routing info from the tunnel socket */ | 1003 | /* Get routing info from the tunnel socket */ |
1002 | skb_dst_drop(skb); | 1004 | skb_dst_drop(skb); |
1003 | skb_dst_set(skb, dst_clone(__sk_dst_get(sk))); | 1005 | skb_dst_set(skb, dst_clone(__sk_dst_get(sk))); |
1004 | l2tp_skb_set_owner_w(skb, sk); | ||
1005 | 1006 | ||
1006 | /* Calculate UDP checksum if configured to do so */ | 1007 | switch (tunnel->encap) { |
1007 | if (sk->sk_no_check == UDP_CSUM_NOXMIT) | 1008 | case L2TP_ENCAPTYPE_UDP: |
1008 | skb->ip_summed = CHECKSUM_NONE; | 1009 | /* Setup UDP header */ |
1009 | else if ((skb_dst(skb) && skb_dst(skb)->dev) && | 1010 | inet = inet_sk(sk); |
1010 | (!(skb_dst(skb)->dev->features & NETIF_F_V4_CSUM))) { | 1011 | __skb_push(skb, sizeof(*uh)); |
1011 | skb->ip_summed = CHECKSUM_COMPLETE; | 1012 | skb_reset_transport_header(skb); |
1012 | csum = skb_checksum(skb, 0, udp_len, 0); | 1013 | uh = udp_hdr(skb); |
1013 | uh->check = csum_tcpudp_magic(inet->inet_saddr, | 1014 | uh->source = inet->inet_sport; |
1014 | inet->inet_daddr, | 1015 | uh->dest = inet->inet_dport; |
1015 | udp_len, IPPROTO_UDP, csum); | 1016 | udp_len = uhlen + hdr_len + data_len; |
1016 | if (uh->check == 0) | 1017 | uh->len = htons(udp_len); |
1017 | uh->check = CSUM_MANGLED_0; | 1018 | uh->check = 0; |
1018 | } else { | 1019 | |
1019 | skb->ip_summed = CHECKSUM_PARTIAL; | 1020 | /* Calculate UDP checksum if configured to do so */ |
1020 | skb->csum_start = skb_transport_header(skb) - skb->head; | 1021 | if (sk->sk_no_check == UDP_CSUM_NOXMIT) |
1021 | skb->csum_offset = offsetof(struct udphdr, check); | 1022 | skb->ip_summed = CHECKSUM_NONE; |
1022 | uh->check = ~csum_tcpudp_magic(inet->inet_saddr, | 1023 | else if ((skb_dst(skb) && skb_dst(skb)->dev) && |
1023 | inet->inet_daddr, | 1024 | (!(skb_dst(skb)->dev->features & NETIF_F_V4_CSUM))) { |
1024 | udp_len, IPPROTO_UDP, 0); | 1025 | skb->ip_summed = CHECKSUM_COMPLETE; |
1026 | csum = skb_checksum(skb, 0, udp_len, 0); | ||
1027 | uh->check = csum_tcpudp_magic(inet->inet_saddr, | ||
1028 | inet->inet_daddr, | ||
1029 | udp_len, IPPROTO_UDP, csum); | ||
1030 | if (uh->check == 0) | ||
1031 | uh->check = CSUM_MANGLED_0; | ||
1032 | } else { | ||
1033 | skb->ip_summed = CHECKSUM_PARTIAL; | ||
1034 | skb->csum_start = skb_transport_header(skb) - skb->head; | ||
1035 | skb->csum_offset = offsetof(struct udphdr, check); | ||
1036 | uh->check = ~csum_tcpudp_magic(inet->inet_saddr, | ||
1037 | inet->inet_daddr, | ||
1038 | udp_len, IPPROTO_UDP, 0); | ||
1039 | } | ||
1040 | break; | ||
1041 | |||
1042 | case L2TP_ENCAPTYPE_IP: | ||
1043 | break; | ||
1025 | } | 1044 | } |
1026 | 1045 | ||
1046 | l2tp_skb_set_owner_w(skb, sk); | ||
1047 | |||
1027 | l2tp_xmit_core(session, skb, data_len); | 1048 | l2tp_xmit_core(session, skb, data_len); |
1028 | 1049 | ||
1029 | abort: | 1050 | abort: |
@@ -1053,9 +1074,15 @@ void l2tp_tunnel_destruct(struct sock *sk) | |||
1053 | /* Close all sessions */ | 1074 | /* Close all sessions */ |
1054 | l2tp_tunnel_closeall(tunnel); | 1075 | l2tp_tunnel_closeall(tunnel); |
1055 | 1076 | ||
1056 | /* No longer an encapsulation socket. See net/ipv4/udp.c */ | 1077 | switch (tunnel->encap) { |
1057 | (udp_sk(sk))->encap_type = 0; | 1078 | case L2TP_ENCAPTYPE_UDP: |
1058 | (udp_sk(sk))->encap_rcv = NULL; | 1079 | /* No longer an encapsulation socket. See net/ipv4/udp.c */ |
1080 | (udp_sk(sk))->encap_type = 0; | ||
1081 | (udp_sk(sk))->encap_rcv = NULL; | ||
1082 | break; | ||
1083 | case L2TP_ENCAPTYPE_IP: | ||
1084 | break; | ||
1085 | } | ||
1059 | 1086 | ||
1060 | /* Remove hooks into tunnel socket */ | 1087 | /* Remove hooks into tunnel socket */ |
1061 | tunnel->sock = NULL; | 1088 | tunnel->sock = NULL; |
@@ -1168,6 +1195,7 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32 | |||
1168 | struct socket *sock = NULL; | 1195 | struct socket *sock = NULL; |
1169 | struct sock *sk = NULL; | 1196 | struct sock *sk = NULL; |
1170 | struct l2tp_net *pn; | 1197 | struct l2tp_net *pn; |
1198 | enum l2tp_encap_type encap = L2TP_ENCAPTYPE_UDP; | ||
1171 | 1199 | ||
1172 | /* Get the tunnel socket from the fd, which was opened by | 1200 | /* Get the tunnel socket from the fd, which was opened by |
1173 | * the userspace L2TP daemon. | 1201 | * the userspace L2TP daemon. |
@@ -1182,18 +1210,27 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32 | |||
1182 | 1210 | ||
1183 | sk = sock->sk; | 1211 | sk = sock->sk; |
1184 | 1212 | ||
1213 | if (cfg != NULL) | ||
1214 | encap = cfg->encap; | ||
1215 | |||
1185 | /* Quick sanity checks */ | 1216 | /* Quick sanity checks */ |
1186 | err = -EPROTONOSUPPORT; | 1217 | switch (encap) { |
1187 | if (sk->sk_protocol != IPPROTO_UDP) { | 1218 | case L2TP_ENCAPTYPE_UDP: |
1188 | printk(KERN_ERR "tunl %hu: fd %d wrong protocol, got %d, expected %d\n", | 1219 | err = -EPROTONOSUPPORT; |
1189 | tunnel_id, fd, sk->sk_protocol, IPPROTO_UDP); | 1220 | if (sk->sk_protocol != IPPROTO_UDP) { |
1190 | goto err; | 1221 | printk(KERN_ERR "tunl %hu: fd %d wrong protocol, got %d, expected %d\n", |
1191 | } | 1222 | tunnel_id, fd, sk->sk_protocol, IPPROTO_UDP); |
1192 | err = -EAFNOSUPPORT; | 1223 | goto err; |
1193 | if (sock->ops->family != AF_INET) { | 1224 | } |
1194 | printk(KERN_ERR "tunl %hu: fd %d wrong family, got %d, expected %d\n", | 1225 | break; |
1195 | tunnel_id, fd, sock->ops->family, AF_INET); | 1226 | case L2TP_ENCAPTYPE_IP: |
1196 | goto err; | 1227 | err = -EPROTONOSUPPORT; |
1228 | if (sk->sk_protocol != IPPROTO_L2TP) { | ||
1229 | printk(KERN_ERR "tunl %hu: fd %d wrong protocol, got %d, expected %d\n", | ||
1230 | tunnel_id, fd, sk->sk_protocol, IPPROTO_L2TP); | ||
1231 | goto err; | ||
1232 | } | ||
1233 | break; | ||
1197 | } | 1234 | } |
1198 | 1235 | ||
1199 | /* Check if this socket has already been prepped */ | 1236 | /* Check if this socket has already been prepped */ |
@@ -1223,12 +1260,16 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32 | |||
1223 | tunnel->l2tp_net = net; | 1260 | tunnel->l2tp_net = net; |
1224 | pn = l2tp_pernet(net); | 1261 | pn = l2tp_pernet(net); |
1225 | 1262 | ||
1226 | if (cfg) | 1263 | if (cfg != NULL) |
1227 | tunnel->debug = cfg->debug; | 1264 | tunnel->debug = cfg->debug; |
1228 | 1265 | ||
1229 | /* Mark socket as an encapsulation socket. See net/ipv4/udp.c */ | 1266 | /* Mark socket as an encapsulation socket. See net/ipv4/udp.c */ |
1230 | udp_sk(sk)->encap_type = UDP_ENCAP_L2TPINUDP; | 1267 | tunnel->encap = encap; |
1231 | udp_sk(sk)->encap_rcv = l2tp_udp_encap_recv; | 1268 | if (encap == L2TP_ENCAPTYPE_UDP) { |
1269 | /* Mark socket as an encapsulation socket. See net/ipv4/udp.c */ | ||
1270 | udp_sk(sk)->encap_type = UDP_ENCAP_L2TPINUDP; | ||
1271 | udp_sk(sk)->encap_rcv = l2tp_udp_encap_recv; | ||
1272 | } | ||
1232 | 1273 | ||
1233 | sk->sk_user_data = tunnel; | 1274 | sk->sk_user_data = tunnel; |
1234 | 1275 | ||
@@ -1318,7 +1359,9 @@ void l2tp_session_set_header_len(struct l2tp_session *session, int version) | |||
1318 | if (session->send_seq) | 1359 | if (session->send_seq) |
1319 | session->hdr_len += 4; | 1360 | session->hdr_len += 4; |
1320 | } else { | 1361 | } else { |
1321 | session->hdr_len = 8 + session->cookie_len + session->l2specific_len + session->offset; | 1362 | session->hdr_len = 4 + session->cookie_len + session->l2specific_len + session->offset; |
1363 | if (session->tunnel->encap == L2TP_ENCAPTYPE_UDP) | ||
1364 | session->hdr_len += 4; | ||
1322 | } | 1365 | } |
1323 | 1366 | ||
1324 | } | 1367 | } |