12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 220dcb110STom Parkin /* L2TPv3 IP encapsulation support for IPv6 3a32e0eecSChris Elston * 4a32e0eecSChris Elston * Copyright (c) 2012 Katalix Systems Ltd 5a32e0eecSChris Elston */ 6a32e0eecSChris Elston 7a4ca44faSJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 8a4ca44faSJoe Perches 9a32e0eecSChris Elston #include <linux/icmp.h> 10a32e0eecSChris Elston #include <linux/module.h> 11a32e0eecSChris Elston #include <linux/skbuff.h> 12a32e0eecSChris Elston #include <linux/random.h> 13a32e0eecSChris Elston #include <linux/socket.h> 14a32e0eecSChris Elston #include <linux/l2tp.h> 15a32e0eecSChris Elston #include <linux/in.h> 16a32e0eecSChris Elston #include <linux/in6.h> 17a32e0eecSChris Elston #include <net/sock.h> 18a32e0eecSChris Elston #include <net/ip.h> 19a32e0eecSChris Elston #include <net/icmp.h> 20a32e0eecSChris Elston #include <net/udp.h> 21a32e0eecSChris Elston #include <net/inet_common.h> 22a32e0eecSChris Elston #include <net/tcp_states.h> 23a32e0eecSChris Elston #include <net/protocol.h> 24a32e0eecSChris Elston #include <net/xfrm.h> 25a32e0eecSChris Elston 26a32e0eecSChris Elston #include <net/transp_v6.h> 27a32e0eecSChris Elston #include <net/addrconf.h> 28a32e0eecSChris Elston #include <net/ip6_route.h> 29a32e0eecSChris Elston 30a32e0eecSChris Elston #include "l2tp_core.h" 31a32e0eecSChris Elston 32a32e0eecSChris Elston struct l2tp_ip6_sock { 33a32e0eecSChris Elston /* inet_sock has to be the first member of l2tp_ip6_sock */ 34a32e0eecSChris Elston struct inet_sock inet; 35a32e0eecSChris Elston 36a32e0eecSChris Elston u32 conn_id; 37a32e0eecSChris Elston u32 peer_conn_id; 38a32e0eecSChris Elston 39a32e0eecSChris Elston /* ipv6_pinfo has to be the last member of l2tp_ip6_sock, see 4020dcb110STom Parkin * inet6_sk_generic 4120dcb110STom Parkin */ 42a32e0eecSChris Elston struct ipv6_pinfo inet6; 43a32e0eecSChris Elston }; 44a32e0eecSChris Elston 45a32e0eecSChris Elston static DEFINE_RWLOCK(l2tp_ip6_lock); 46a32e0eecSChris Elston static struct hlist_head l2tp_ip6_table; 47a32e0eecSChris Elston static struct hlist_head l2tp_ip6_bind_table; 48a32e0eecSChris Elston 49a32e0eecSChris Elston static inline struct l2tp_ip6_sock *l2tp_ip6_sk(const struct sock *sk) 50a32e0eecSChris Elston { 51a32e0eecSChris Elston return (struct l2tp_ip6_sock *)sk; 52a32e0eecSChris Elston } 53a32e0eecSChris Elston 54bb39b0bdSGuillaume Nault static struct sock *__l2tp_ip6_bind_lookup(const struct net *net, 55bb39b0bdSGuillaume Nault const struct in6_addr *laddr, 56a9b2dff8SGuillaume Nault const struct in6_addr *raddr, 57a32e0eecSChris Elston int dif, u32 tunnel_id) 58a32e0eecSChris Elston { 59a32e0eecSChris Elston struct sock *sk; 60a32e0eecSChris Elston 61b67bfe0dSSasha Levin sk_for_each_bound(sk, &l2tp_ip6_bind_table) { 6297b84fd6SGuillaume Nault const struct in6_addr *sk_laddr = inet6_rcv_saddr(sk); 63a9b2dff8SGuillaume Nault const struct in6_addr *sk_raddr = &sk->sk_v6_daddr; 64bb39b0bdSGuillaume Nault const struct l2tp_ip6_sock *l2tp = l2tp_ip6_sk(sk); 65a32e0eecSChris Elston 66c5fdae04SGuillaume Nault if (!net_eq(sock_net(sk), net)) 67c5fdae04SGuillaume Nault continue; 68c5fdae04SGuillaume Nault 69c5fdae04SGuillaume Nault if (sk->sk_bound_dev_if && dif && sk->sk_bound_dev_if != dif) 70c5fdae04SGuillaume Nault continue; 71c5fdae04SGuillaume Nault 72c5fdae04SGuillaume Nault if (sk_laddr && !ipv6_addr_any(sk_laddr) && 73c5fdae04SGuillaume Nault !ipv6_addr_any(laddr) && !ipv6_addr_equal(sk_laddr, laddr)) 74c5fdae04SGuillaume Nault continue; 75c5fdae04SGuillaume Nault 76c5fdae04SGuillaume Nault if (!ipv6_addr_any(sk_raddr) && raddr && 77c5fdae04SGuillaume Nault !ipv6_addr_any(raddr) && !ipv6_addr_equal(sk_raddr, raddr)) 78c5fdae04SGuillaume Nault continue; 79c5fdae04SGuillaume Nault 80c5fdae04SGuillaume Nault if (l2tp->conn_id != tunnel_id) 81c5fdae04SGuillaume Nault continue; 82c5fdae04SGuillaume Nault 83a32e0eecSChris Elston goto found; 84a32e0eecSChris Elston } 85a32e0eecSChris Elston 86a32e0eecSChris Elston sk = NULL; 87a32e0eecSChris Elston found: 88a32e0eecSChris Elston return sk; 89a32e0eecSChris Elston } 90a32e0eecSChris Elston 91a32e0eecSChris Elston /* When processing receive frames, there are two cases to 92a32e0eecSChris Elston * consider. Data frames consist of a non-zero session-id and an 93a32e0eecSChris Elston * optional cookie. Control frames consist of a regular L2TP header 94a32e0eecSChris Elston * preceded by 32-bits of zeros. 95a32e0eecSChris Elston * 96a32e0eecSChris Elston * L2TPv3 Session Header Over IP 97a32e0eecSChris Elston * 98a32e0eecSChris Elston * 0 1 2 3 99a32e0eecSChris Elston * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 100a32e0eecSChris Elston * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 101a32e0eecSChris Elston * | Session ID | 102a32e0eecSChris Elston * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 103a32e0eecSChris Elston * | Cookie (optional, maximum 64 bits)... 104a32e0eecSChris Elston * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 105a32e0eecSChris Elston * | 106a32e0eecSChris Elston * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 107a32e0eecSChris Elston * 108a32e0eecSChris Elston * L2TPv3 Control Message Header Over IP 109a32e0eecSChris Elston * 110a32e0eecSChris Elston * 0 1 2 3 111a32e0eecSChris Elston * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 112a32e0eecSChris Elston * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 113a32e0eecSChris Elston * | (32 bits of zeros) | 114a32e0eecSChris Elston * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 115a32e0eecSChris Elston * |T|L|x|x|S|x|x|x|x|x|x|x| Ver | Length | 116a32e0eecSChris Elston * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 117a32e0eecSChris Elston * | Control Connection ID | 118a32e0eecSChris Elston * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 119a32e0eecSChris Elston * | Ns | Nr | 120a32e0eecSChris Elston * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 121a32e0eecSChris Elston * 122a32e0eecSChris Elston * All control frames are passed to userspace. 123a32e0eecSChris Elston */ 124a32e0eecSChris Elston static int l2tp_ip6_recv(struct sk_buff *skb) 125a32e0eecSChris Elston { 1260e6b5259SShmulik Ladkani struct net *net = dev_net(skb->dev); 127a32e0eecSChris Elston struct sock *sk; 128a32e0eecSChris Elston u32 session_id; 129a32e0eecSChris Elston u32 tunnel_id; 130a32e0eecSChris Elston unsigned char *ptr, *optr; 131a32e0eecSChris Elston struct l2tp_session *session; 132a32e0eecSChris Elston struct l2tp_tunnel *tunnel = NULL; 1338f7dc9aeSGuillaume Nault struct ipv6hdr *iph; 134a32e0eecSChris Elston 135a32e0eecSChris Elston if (!pskb_may_pull(skb, 4)) 136a32e0eecSChris Elston goto discard; 137a32e0eecSChris Elston 138be447f30SHaishuang Yan /* Point to L2TP header */ 13995075150STom Parkin optr = skb->data; 14095075150STom Parkin ptr = skb->data; 141a32e0eecSChris Elston session_id = ntohl(*((__be32 *)ptr)); 142a32e0eecSChris Elston ptr += 4; 143a32e0eecSChris Elston 144a32e0eecSChris Elston /* RFC3931: L2TP/IP packets have the first 4 bytes containing 145a32e0eecSChris Elston * the session_id. If it is 0, the packet is a L2TP control 146a32e0eecSChris Elston * frame and the session_id value can be discarded. 147a32e0eecSChris Elston */ 148a32e0eecSChris Elston if (session_id == 0) { 149a32e0eecSChris Elston __skb_pull(skb, 4); 150a32e0eecSChris Elston goto pass_up; 151a32e0eecSChris Elston } 152a32e0eecSChris Elston 153a32e0eecSChris Elston /* Ok, this is a data packet. Lookup the session. */ 15401e28b92SGuillaume Nault session = l2tp_session_get(net, session_id); 15561b9a047SGuillaume Nault if (!session) 156a32e0eecSChris Elston goto discard; 157a32e0eecSChris Elston 158a32e0eecSChris Elston tunnel = session->tunnel; 15961b9a047SGuillaume Nault if (!tunnel) 16061b9a047SGuillaume Nault goto discard_sess; 161a32e0eecSChris Elston 1624522a70dSJacob Wen if (l2tp_v3_ensure_opt_in_linear(session, skb, &ptr, &optr)) 1634522a70dSJacob Wen goto discard_sess; 1644522a70dSJacob Wen 1652b139e6bSGuillaume Nault l2tp_recv_common(session, skb, ptr, optr, 0, skb->len); 16661b9a047SGuillaume Nault l2tp_session_dec_refcount(session); 16761b9a047SGuillaume Nault 168a32e0eecSChris Elston return 0; 169a32e0eecSChris Elston 170a32e0eecSChris Elston pass_up: 171a32e0eecSChris Elston /* Get the tunnel_id from the L2TP header */ 172a32e0eecSChris Elston if (!pskb_may_pull(skb, 12)) 173a32e0eecSChris Elston goto discard; 174a32e0eecSChris Elston 175a32e0eecSChris Elston if ((skb->data[0] & 0xc0) != 0xc0) 176a32e0eecSChris Elston goto discard; 177a32e0eecSChris Elston 178a32e0eecSChris Elston tunnel_id = ntohl(*(__be32 *)&skb->data[4]); 1798f7dc9aeSGuillaume Nault iph = ipv6_hdr(skb); 180a32e0eecSChris Elston 181a32e0eecSChris Elston read_lock_bh(&l2tp_ip6_lock); 182a9b2dff8SGuillaume Nault sk = __l2tp_ip6_bind_lookup(net, &iph->daddr, &iph->saddr, 183a9b2dff8SGuillaume Nault inet6_iif(skb), tunnel_id); 184a3c18422SGuillaume Nault if (!sk) { 185a32e0eecSChris Elston read_unlock_bh(&l2tp_ip6_lock); 186a3c18422SGuillaume Nault goto discard; 187a32e0eecSChris Elston } 188a32e0eecSChris Elston sock_hold(sk); 189a3c18422SGuillaume Nault read_unlock_bh(&l2tp_ip6_lock); 190a32e0eecSChris Elston 191a32e0eecSChris Elston if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) 192a32e0eecSChris Elston goto discard_put; 193a32e0eecSChris Elston 194895b5c9fSFlorian Westphal nf_reset_ct(skb); 195a32e0eecSChris Elston 196a32e0eecSChris Elston return sk_receive_skb(sk, skb, 1); 197a32e0eecSChris Elston 19861b9a047SGuillaume Nault discard_sess: 19961b9a047SGuillaume Nault l2tp_session_dec_refcount(session); 20061b9a047SGuillaume Nault goto discard; 20161b9a047SGuillaume Nault 202a32e0eecSChris Elston discard_put: 203a32e0eecSChris Elston sock_put(sk); 204a32e0eecSChris Elston 205a32e0eecSChris Elston discard: 206a32e0eecSChris Elston kfree_skb(skb); 207a32e0eecSChris Elston return 0; 208a32e0eecSChris Elston } 209a32e0eecSChris Elston 21002c71b14SEric Dumazet static int l2tp_ip6_hash(struct sock *sk) 21102c71b14SEric Dumazet { 21202c71b14SEric Dumazet if (sk_unhashed(sk)) { 21302c71b14SEric Dumazet write_lock_bh(&l2tp_ip6_lock); 21402c71b14SEric Dumazet sk_add_node(sk, &l2tp_ip6_table); 21502c71b14SEric Dumazet write_unlock_bh(&l2tp_ip6_lock); 21602c71b14SEric Dumazet } 21702c71b14SEric Dumazet return 0; 21802c71b14SEric Dumazet } 21902c71b14SEric Dumazet 22002c71b14SEric Dumazet static void l2tp_ip6_unhash(struct sock *sk) 22102c71b14SEric Dumazet { 22202c71b14SEric Dumazet if (sk_unhashed(sk)) 22302c71b14SEric Dumazet return; 22402c71b14SEric Dumazet write_lock_bh(&l2tp_ip6_lock); 22502c71b14SEric Dumazet sk_del_node_init(sk); 22602c71b14SEric Dumazet write_unlock_bh(&l2tp_ip6_lock); 22702c71b14SEric Dumazet } 22802c71b14SEric Dumazet 229a32e0eecSChris Elston static int l2tp_ip6_open(struct sock *sk) 230a32e0eecSChris Elston { 231a32e0eecSChris Elston /* Prevent autobind. We don't have ports. */ 232a32e0eecSChris Elston inet_sk(sk)->inet_num = IPPROTO_L2TP; 233a32e0eecSChris Elston 23402c71b14SEric Dumazet l2tp_ip6_hash(sk); 235a32e0eecSChris Elston return 0; 236a32e0eecSChris Elston } 237a32e0eecSChris Elston 238a32e0eecSChris Elston static void l2tp_ip6_close(struct sock *sk, long timeout) 239a32e0eecSChris Elston { 240a32e0eecSChris Elston write_lock_bh(&l2tp_ip6_lock); 241a32e0eecSChris Elston hlist_del_init(&sk->sk_bind_node); 242a32e0eecSChris Elston sk_del_node_init(sk); 243a32e0eecSChris Elston write_unlock_bh(&l2tp_ip6_lock); 244a32e0eecSChris Elston 245a32e0eecSChris Elston sk_common_release(sk); 246a32e0eecSChris Elston } 247a32e0eecSChris Elston 248a32e0eecSChris Elston static void l2tp_ip6_destroy_sock(struct sock *sk) 249a32e0eecSChris Elston { 25045faeff1STom Parkin struct l2tp_tunnel *tunnel = l2tp_sk_to_tunnel(sk); 25193606317STom Parkin 252a32e0eecSChris Elston lock_sock(sk); 253a32e0eecSChris Elston ip6_flush_pending_frames(sk); 254a32e0eecSChris Elston release_sock(sk); 255a32e0eecSChris Elston 256d00fa9adSJames Chapman if (tunnel) 257d00fa9adSJames Chapman l2tp_tunnel_delete(tunnel); 25893606317STom Parkin 259a32e0eecSChris Elston inet6_destroy_sock(sk); 260a32e0eecSChris Elston } 261a32e0eecSChris Elston 262a32e0eecSChris Elston static int l2tp_ip6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) 263a32e0eecSChris Elston { 264a32e0eecSChris Elston struct inet_sock *inet = inet_sk(sk); 265a32e0eecSChris Elston struct ipv6_pinfo *np = inet6_sk(sk); 266a32e0eecSChris Elston struct sockaddr_l2tpip6 *addr = (struct sockaddr_l2tpip6 *)uaddr; 2670e6b5259SShmulik Ladkani struct net *net = sock_net(sk); 268a32e0eecSChris Elston __be32 v4addr = 0; 269d5e3a190SGuillaume Nault int bound_dev_if; 270a32e0eecSChris Elston int addr_type; 271a32e0eecSChris Elston int err; 272a32e0eecSChris Elston 273c51ce497SJames Chapman if (addr->l2tp_family != AF_INET6) 274c51ce497SJames Chapman return -EINVAL; 275a32e0eecSChris Elston if (addr_len < sizeof(*addr)) 276a32e0eecSChris Elston return -EINVAL; 277a32e0eecSChris Elston 278a32e0eecSChris Elston addr_type = ipv6_addr_type(&addr->l2tp_addr); 279a32e0eecSChris Elston 280a32e0eecSChris Elston /* l2tp_ip6 sockets are IPv6 only */ 281a32e0eecSChris Elston if (addr_type == IPV6_ADDR_MAPPED) 282a32e0eecSChris Elston return -EADDRNOTAVAIL; 283a32e0eecSChris Elston 284a32e0eecSChris Elston /* L2TP is point-point, not multicast */ 285a32e0eecSChris Elston if (addr_type & IPV6_ADDR_MULTICAST) 286a32e0eecSChris Elston return -EADDRNOTAVAIL; 287a32e0eecSChris Elston 288a32e0eecSChris Elston lock_sock(sk); 289a32e0eecSChris Elston 290a32e0eecSChris Elston err = -EINVAL; 29132c23116SGuillaume Nault if (!sock_flag(sk, SOCK_ZAPPED)) 29232c23116SGuillaume Nault goto out_unlock; 29332c23116SGuillaume Nault 294a32e0eecSChris Elston if (sk->sk_state != TCP_CLOSE) 295a32e0eecSChris Elston goto out_unlock; 296a32e0eecSChris Elston 297d5e3a190SGuillaume Nault bound_dev_if = sk->sk_bound_dev_if; 298d5e3a190SGuillaume Nault 299a32e0eecSChris Elston /* Check if the address belongs to the host. */ 300a32e0eecSChris Elston rcu_read_lock(); 301a32e0eecSChris Elston if (addr_type != IPV6_ADDR_ANY) { 302a32e0eecSChris Elston struct net_device *dev = NULL; 303a32e0eecSChris Elston 304a32e0eecSChris Elston if (addr_type & IPV6_ADDR_LINKLOCAL) { 305d5e3a190SGuillaume Nault if (addr->l2tp_scope_id) 306d5e3a190SGuillaume Nault bound_dev_if = addr->l2tp_scope_id; 307a32e0eecSChris Elston 308a32e0eecSChris Elston /* Binding to link-local address requires an 309d5e3a190SGuillaume Nault * interface. 310d5e3a190SGuillaume Nault */ 311d5e3a190SGuillaume Nault if (!bound_dev_if) 312a32e0eecSChris Elston goto out_unlock_rcu; 313a32e0eecSChris Elston 314a32e0eecSChris Elston err = -ENODEV; 315d5e3a190SGuillaume Nault dev = dev_get_by_index_rcu(sock_net(sk), bound_dev_if); 316a32e0eecSChris Elston if (!dev) 317a32e0eecSChris Elston goto out_unlock_rcu; 318a32e0eecSChris Elston } 319a32e0eecSChris Elston 320a32e0eecSChris Elston /* ipv4 addr of the socket is invalid. Only the 321a32e0eecSChris Elston * unspecified and mapped address have a v4 equivalent. 322a32e0eecSChris Elston */ 323a32e0eecSChris Elston v4addr = LOOPBACK4_IPV6; 324a32e0eecSChris Elston err = -EADDRNOTAVAIL; 325a32e0eecSChris Elston if (!ipv6_chk_addr(sock_net(sk), &addr->l2tp_addr, dev, 0)) 326a32e0eecSChris Elston goto out_unlock_rcu; 327a32e0eecSChris Elston } 328a32e0eecSChris Elston rcu_read_unlock(); 329a32e0eecSChris Elston 330d5e3a190SGuillaume Nault write_lock_bh(&l2tp_ip6_lock); 331a9b2dff8SGuillaume Nault if (__l2tp_ip6_bind_lookup(net, &addr->l2tp_addr, NULL, bound_dev_if, 332d5e3a190SGuillaume Nault addr->l2tp_conn_id)) { 333d5e3a190SGuillaume Nault write_unlock_bh(&l2tp_ip6_lock); 334d5e3a190SGuillaume Nault err = -EADDRINUSE; 335d5e3a190SGuillaume Nault goto out_unlock; 336d5e3a190SGuillaume Nault } 337d5e3a190SGuillaume Nault 338d5e3a190SGuillaume Nault inet->inet_saddr = v4addr; 339d5e3a190SGuillaume Nault inet->inet_rcv_saddr = v4addr; 340d5e3a190SGuillaume Nault sk->sk_bound_dev_if = bound_dev_if; 341efe4208fSEric Dumazet sk->sk_v6_rcv_saddr = addr->l2tp_addr; 342a32e0eecSChris Elston np->saddr = addr->l2tp_addr; 343a32e0eecSChris Elston 344a32e0eecSChris Elston l2tp_ip6_sk(sk)->conn_id = addr->l2tp_conn_id; 345a32e0eecSChris Elston 346a32e0eecSChris Elston sk_add_bind_node(sk, &l2tp_ip6_bind_table); 347a32e0eecSChris Elston sk_del_node_init(sk); 348a32e0eecSChris Elston write_unlock_bh(&l2tp_ip6_lock); 349a32e0eecSChris Elston 350c51ce497SJames Chapman sock_reset_flag(sk, SOCK_ZAPPED); 351a32e0eecSChris Elston release_sock(sk); 352a32e0eecSChris Elston return 0; 353a32e0eecSChris Elston 354a32e0eecSChris Elston out_unlock_rcu: 355a32e0eecSChris Elston rcu_read_unlock(); 356a32e0eecSChris Elston out_unlock: 357a32e0eecSChris Elston release_sock(sk); 358a32e0eecSChris Elston 359a32e0eecSChris Elston return err; 360a32e0eecSChris Elston } 361a32e0eecSChris Elston 362a32e0eecSChris Elston static int l2tp_ip6_connect(struct sock *sk, struct sockaddr *uaddr, 363a32e0eecSChris Elston int addr_len) 364a32e0eecSChris Elston { 365a32e0eecSChris Elston struct sockaddr_l2tpip6 *lsa = (struct sockaddr_l2tpip6 *)uaddr; 366a32e0eecSChris Elston struct sockaddr_in6 *usin = (struct sockaddr_in6 *)uaddr; 367a32e0eecSChris Elston struct in6_addr *daddr; 368a32e0eecSChris Elston int addr_type; 369a32e0eecSChris Elston int rc; 370a32e0eecSChris Elston 371a32e0eecSChris Elston if (addr_len < sizeof(*lsa)) 372a32e0eecSChris Elston return -EINVAL; 373a32e0eecSChris Elston 37482b276cdSHannes Frederic Sowa if (usin->sin6_family != AF_INET6) 37582b276cdSHannes Frederic Sowa return -EINVAL; 37682b276cdSHannes Frederic Sowa 377a32e0eecSChris Elston addr_type = ipv6_addr_type(&usin->sin6_addr); 378a32e0eecSChris Elston if (addr_type & IPV6_ADDR_MULTICAST) 379a32e0eecSChris Elston return -EINVAL; 380a32e0eecSChris Elston 381a32e0eecSChris Elston if (addr_type & IPV6_ADDR_MAPPED) { 382a32e0eecSChris Elston daddr = &usin->sin6_addr; 383a32e0eecSChris Elston if (ipv4_is_multicast(daddr->s6_addr32[3])) 384a32e0eecSChris Elston return -EINVAL; 385a32e0eecSChris Elston } 386a32e0eecSChris Elston 387a32e0eecSChris Elston lock_sock(sk); 388a32e0eecSChris Elston 3890382a25aSGuillaume Nault /* Must bind first - autobinding does not work */ 3900382a25aSGuillaume Nault if (sock_flag(sk, SOCK_ZAPPED)) { 3910382a25aSGuillaume Nault rc = -EINVAL; 3920382a25aSGuillaume Nault goto out_sk; 3930382a25aSGuillaume Nault } 3940382a25aSGuillaume Nault 3950382a25aSGuillaume Nault rc = __ip6_datagram_connect(sk, uaddr, addr_len); 3960382a25aSGuillaume Nault if (rc < 0) 3970382a25aSGuillaume Nault goto out_sk; 3980382a25aSGuillaume Nault 399a32e0eecSChris Elston l2tp_ip6_sk(sk)->peer_conn_id = lsa->l2tp_conn_id; 400a32e0eecSChris Elston 401a32e0eecSChris Elston write_lock_bh(&l2tp_ip6_lock); 402a32e0eecSChris Elston hlist_del_init(&sk->sk_bind_node); 403a32e0eecSChris Elston sk_add_bind_node(sk, &l2tp_ip6_bind_table); 404a32e0eecSChris Elston write_unlock_bh(&l2tp_ip6_lock); 405a32e0eecSChris Elston 4060382a25aSGuillaume Nault out_sk: 407a32e0eecSChris Elston release_sock(sk); 408a32e0eecSChris Elston 409a32e0eecSChris Elston return rc; 410a32e0eecSChris Elston } 411a32e0eecSChris Elston 412c51ce497SJames Chapman static int l2tp_ip6_disconnect(struct sock *sk, int flags) 413c51ce497SJames Chapman { 414c51ce497SJames Chapman if (sock_flag(sk, SOCK_ZAPPED)) 415c51ce497SJames Chapman return 0; 416c51ce497SJames Chapman 417286c72deSEric Dumazet return __udp_disconnect(sk, flags); 418c51ce497SJames Chapman } 419c51ce497SJames Chapman 420a32e0eecSChris Elston static int l2tp_ip6_getname(struct socket *sock, struct sockaddr *uaddr, 4219b2c45d4SDenys Vlasenko int peer) 422a32e0eecSChris Elston { 423a32e0eecSChris Elston struct sockaddr_l2tpip6 *lsa = (struct sockaddr_l2tpip6 *)uaddr; 424a32e0eecSChris Elston struct sock *sk = sock->sk; 425a32e0eecSChris Elston struct ipv6_pinfo *np = inet6_sk(sk); 426a32e0eecSChris Elston struct l2tp_ip6_sock *lsk = l2tp_ip6_sk(sk); 427a32e0eecSChris Elston 428a32e0eecSChris Elston lsa->l2tp_family = AF_INET6; 429a32e0eecSChris Elston lsa->l2tp_flowinfo = 0; 430a32e0eecSChris Elston lsa->l2tp_scope_id = 0; 43104d4fbcaSMathias Krause lsa->l2tp_unused = 0; 432a32e0eecSChris Elston if (peer) { 433a32e0eecSChris Elston if (!lsk->peer_conn_id) 434a32e0eecSChris Elston return -ENOTCONN; 435a32e0eecSChris Elston lsa->l2tp_conn_id = lsk->peer_conn_id; 436efe4208fSEric Dumazet lsa->l2tp_addr = sk->sk_v6_daddr; 437a32e0eecSChris Elston if (np->sndflow) 438a32e0eecSChris Elston lsa->l2tp_flowinfo = np->flow_label; 439a32e0eecSChris Elston } else { 440efe4208fSEric Dumazet if (ipv6_addr_any(&sk->sk_v6_rcv_saddr)) 441a32e0eecSChris Elston lsa->l2tp_addr = np->saddr; 442a32e0eecSChris Elston else 443efe4208fSEric Dumazet lsa->l2tp_addr = sk->sk_v6_rcv_saddr; 444a32e0eecSChris Elston 445a32e0eecSChris Elston lsa->l2tp_conn_id = lsk->conn_id; 446a32e0eecSChris Elston } 447a32e0eecSChris Elston if (ipv6_addr_type(&lsa->l2tp_addr) & IPV6_ADDR_LINKLOCAL) 448a32e0eecSChris Elston lsa->l2tp_scope_id = sk->sk_bound_dev_if; 4499b2c45d4SDenys Vlasenko return sizeof(*lsa); 450a32e0eecSChris Elston } 451a32e0eecSChris Elston 452a32e0eecSChris Elston static int l2tp_ip6_backlog_recv(struct sock *sk, struct sk_buff *skb) 453a32e0eecSChris Elston { 454a32e0eecSChris Elston int rc; 455a32e0eecSChris Elston 456a32e0eecSChris Elston /* Charge it to the socket, dropping if the queue is full. */ 457a32e0eecSChris Elston rc = sock_queue_rcv_skb(sk, skb); 458a32e0eecSChris Elston if (rc < 0) 459a32e0eecSChris Elston goto drop; 460a32e0eecSChris Elston 461a32e0eecSChris Elston return 0; 462a32e0eecSChris Elston 463a32e0eecSChris Elston drop: 4640e6b5259SShmulik Ladkani IP_INC_STATS(sock_net(sk), IPSTATS_MIB_INDISCARDS); 465a32e0eecSChris Elston kfree_skb(skb); 466a32e0eecSChris Elston return -1; 467a32e0eecSChris Elston } 468a32e0eecSChris Elston 469a32e0eecSChris Elston static int l2tp_ip6_push_pending_frames(struct sock *sk) 470a32e0eecSChris Elston { 471a32e0eecSChris Elston struct sk_buff *skb; 472a32e0eecSChris Elston __be32 *transhdr = NULL; 473a32e0eecSChris Elston int err = 0; 474a32e0eecSChris Elston 475a32e0eecSChris Elston skb = skb_peek(&sk->sk_write_queue); 4760febc7b3STom Parkin if (!skb) 477a32e0eecSChris Elston goto out; 478a32e0eecSChris Elston 479a32e0eecSChris Elston transhdr = (__be32 *)skb_transport_header(skb); 480a32e0eecSChris Elston *transhdr = 0; 481a32e0eecSChris Elston 482a32e0eecSChris Elston err = ip6_push_pending_frames(sk); 483a32e0eecSChris Elston 484a32e0eecSChris Elston out: 485a32e0eecSChris Elston return err; 486a32e0eecSChris Elston } 487a32e0eecSChris Elston 488a32e0eecSChris Elston /* Userspace will call sendmsg() on the tunnel socket to send L2TP 489a32e0eecSChris Elston * control frames. 490a32e0eecSChris Elston */ 4911b784140SYing Xue static int l2tp_ip6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) 492a32e0eecSChris Elston { 493a32e0eecSChris Elston struct ipv6_txoptions opt_space; 494342dfc30SSteffen Hurrle DECLARE_SOCKADDR(struct sockaddr_l2tpip6 *, lsa, msg->msg_name); 495a32e0eecSChris Elston struct in6_addr *daddr, *final_p, final; 496a32e0eecSChris Elston struct ipv6_pinfo *np = inet6_sk(sk); 49745f6fad8SEric Dumazet struct ipv6_txoptions *opt_to_free = NULL; 498a32e0eecSChris Elston struct ipv6_txoptions *opt = NULL; 499a32e0eecSChris Elston struct ip6_flowlabel *flowlabel = NULL; 500a32e0eecSChris Elston struct dst_entry *dst = NULL; 501a32e0eecSChris Elston struct flowi6 fl6; 50226879da5SWei Wang struct ipcm6_cookie ipc6; 503a32e0eecSChris Elston int addr_len = msg->msg_namelen; 504a32e0eecSChris Elston int transhdrlen = 4; /* zero session-id */ 505a32e0eecSChris Elston int ulen = len + transhdrlen; 506a32e0eecSChris Elston int err; 507a32e0eecSChris Elston 508a32e0eecSChris Elston /* Rough check on arithmetic overflow, 50920dcb110STom Parkin * better check is made in ip6_append_data(). 510a32e0eecSChris Elston */ 511a32e0eecSChris Elston if (len > INT_MAX) 512a32e0eecSChris Elston return -EMSGSIZE; 513a32e0eecSChris Elston 514a32e0eecSChris Elston /* Mirror BSD error message compatibility */ 515a32e0eecSChris Elston if (msg->msg_flags & MSG_OOB) 516a32e0eecSChris Elston return -EOPNOTSUPP; 517a32e0eecSChris Elston 51820dcb110STom Parkin /* Get and verify the address */ 519a32e0eecSChris Elston memset(&fl6, 0, sizeof(fl6)); 520a32e0eecSChris Elston 521a32e0eecSChris Elston fl6.flowi6_mark = sk->sk_mark; 522e2d118a1SLorenzo Colitti fl6.flowi6_uid = sk->sk_uid; 523a32e0eecSChris Elston 524b515430aSWillem de Bruijn ipcm6_init(&ipc6); 52526879da5SWei Wang 526a32e0eecSChris Elston if (lsa) { 527a32e0eecSChris Elston if (addr_len < SIN6_LEN_RFC2133) 528a32e0eecSChris Elston return -EINVAL; 529a32e0eecSChris Elston 530a32e0eecSChris Elston if (lsa->l2tp_family && lsa->l2tp_family != AF_INET6) 531a32e0eecSChris Elston return -EAFNOSUPPORT; 532a32e0eecSChris Elston 533a32e0eecSChris Elston daddr = &lsa->l2tp_addr; 534a32e0eecSChris Elston if (np->sndflow) { 535a32e0eecSChris Elston fl6.flowlabel = lsa->l2tp_flowinfo & IPV6_FLOWINFO_MASK; 536a32e0eecSChris Elston if (fl6.flowlabel & IPV6_FLOWLABEL_MASK) { 537a32e0eecSChris Elston flowlabel = fl6_sock_lookup(sk, fl6.flowlabel); 53859c820b2SWillem de Bruijn if (IS_ERR(flowlabel)) 539a32e0eecSChris Elston return -EINVAL; 540a32e0eecSChris Elston } 541a32e0eecSChris Elston } 542a32e0eecSChris Elston 54320dcb110STom Parkin /* Otherwise it will be difficult to maintain 544a32e0eecSChris Elston * sk->sk_dst_cache. 545a32e0eecSChris Elston */ 546a32e0eecSChris Elston if (sk->sk_state == TCP_ESTABLISHED && 547efe4208fSEric Dumazet ipv6_addr_equal(daddr, &sk->sk_v6_daddr)) 548efe4208fSEric Dumazet daddr = &sk->sk_v6_daddr; 549a32e0eecSChris Elston 550a32e0eecSChris Elston if (addr_len >= sizeof(struct sockaddr_in6) && 551a32e0eecSChris Elston lsa->l2tp_scope_id && 552a32e0eecSChris Elston ipv6_addr_type(daddr) & IPV6_ADDR_LINKLOCAL) 553a32e0eecSChris Elston fl6.flowi6_oif = lsa->l2tp_scope_id; 554a32e0eecSChris Elston } else { 555a32e0eecSChris Elston if (sk->sk_state != TCP_ESTABLISHED) 556a32e0eecSChris Elston return -EDESTADDRREQ; 557a32e0eecSChris Elston 558efe4208fSEric Dumazet daddr = &sk->sk_v6_daddr; 559a32e0eecSChris Elston fl6.flowlabel = np->flow_label; 560a32e0eecSChris Elston } 561a32e0eecSChris Elston 562a32e0eecSChris Elston if (fl6.flowi6_oif == 0) 563a32e0eecSChris Elston fl6.flowi6_oif = sk->sk_bound_dev_if; 564a32e0eecSChris Elston 565a32e0eecSChris Elston if (msg->msg_controllen) { 566a32e0eecSChris Elston opt = &opt_space; 567a32e0eecSChris Elston memset(opt, 0, sizeof(struct ipv6_txoptions)); 568a32e0eecSChris Elston opt->tot_len = sizeof(struct ipv6_txoptions); 56926879da5SWei Wang ipc6.opt = opt; 570a32e0eecSChris Elston 5715fdaa88dSWillem de Bruijn err = ip6_datagram_send_ctl(sock_net(sk), sk, msg, &fl6, &ipc6); 572a32e0eecSChris Elston if (err < 0) { 573a32e0eecSChris Elston fl6_sock_release(flowlabel); 574a32e0eecSChris Elston return err; 575a32e0eecSChris Elston } 576a32e0eecSChris Elston if ((fl6.flowlabel & IPV6_FLOWLABEL_MASK) && !flowlabel) { 577a32e0eecSChris Elston flowlabel = fl6_sock_lookup(sk, fl6.flowlabel); 57859c820b2SWillem de Bruijn if (IS_ERR(flowlabel)) 579a32e0eecSChris Elston return -EINVAL; 580a32e0eecSChris Elston } 581a32e0eecSChris Elston if (!(opt->opt_nflen | opt->opt_flen)) 582a32e0eecSChris Elston opt = NULL; 583a32e0eecSChris Elston } 584a32e0eecSChris Elston 58545f6fad8SEric Dumazet if (!opt) { 58645f6fad8SEric Dumazet opt = txopt_get(np); 58745f6fad8SEric Dumazet opt_to_free = opt; 58845f6fad8SEric Dumazet } 589a32e0eecSChris Elston if (flowlabel) 590a32e0eecSChris Elston opt = fl6_merge_options(&opt_space, flowlabel, opt); 591a32e0eecSChris Elston opt = ipv6_fixup_options(&opt_space, opt); 59226879da5SWei Wang ipc6.opt = opt; 593a32e0eecSChris Elston 594a32e0eecSChris Elston fl6.flowi6_proto = sk->sk_protocol; 595a32e0eecSChris Elston if (!ipv6_addr_any(daddr)) 596a32e0eecSChris Elston fl6.daddr = *daddr; 597a32e0eecSChris Elston else 598a32e0eecSChris Elston fl6.daddr.s6_addr[15] = 0x1; /* :: means loopback (BSD'ism) */ 599a32e0eecSChris Elston if (ipv6_addr_any(&fl6.saddr) && !ipv6_addr_any(&np->saddr)) 600a32e0eecSChris Elston fl6.saddr = np->saddr; 601a32e0eecSChris Elston 602a32e0eecSChris Elston final_p = fl6_update_dst(&fl6, opt, &final); 603a32e0eecSChris Elston 604a32e0eecSChris Elston if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr)) 605a32e0eecSChris Elston fl6.flowi6_oif = np->mcast_oif; 606a32e0eecSChris Elston else if (!fl6.flowi6_oif) 607a32e0eecSChris Elston fl6.flowi6_oif = np->ucast_oif; 608a32e0eecSChris Elston 6093df98d79SPaul Moore security_sk_classify_flow(sk, flowi6_to_flowi_common(&fl6)); 610a32e0eecSChris Elston 61138b7097bSHannes Frederic Sowa if (ipc6.tclass < 0) 61238b7097bSHannes Frederic Sowa ipc6.tclass = np->tclass; 61338b7097bSHannes Frederic Sowa 61438b7097bSHannes Frederic Sowa fl6.flowlabel = ip6_make_flowinfo(ipc6.tclass, fl6.flowlabel); 61538b7097bSHannes Frederic Sowa 616c4e85f73SSabrina Dubroca dst = ip6_dst_lookup_flow(sock_net(sk), sk, &fl6, final_p); 617a32e0eecSChris Elston if (IS_ERR(dst)) { 618a32e0eecSChris Elston err = PTR_ERR(dst); 619a32e0eecSChris Elston goto out; 620a32e0eecSChris Elston } 621a32e0eecSChris Elston 62226879da5SWei Wang if (ipc6.hlimit < 0) 62326879da5SWei Wang ipc6.hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst); 624a32e0eecSChris Elston 62526879da5SWei Wang if (ipc6.dontfrag < 0) 62626879da5SWei Wang ipc6.dontfrag = np->dontfrag; 627a32e0eecSChris Elston 628a32e0eecSChris Elston if (msg->msg_flags & MSG_CONFIRM) 629a32e0eecSChris Elston goto do_confirm; 630a32e0eecSChris Elston 631a32e0eecSChris Elston back_from_confirm: 632a32e0eecSChris Elston lock_sock(sk); 633f69e6d13SAl Viro err = ip6_append_data(sk, ip_generic_getfrag, msg, 63426879da5SWei Wang ulen, transhdrlen, &ipc6, 635a32e0eecSChris Elston &fl6, (struct rt6_info *)dst, 6365fdaa88dSWillem de Bruijn msg->msg_flags); 637a32e0eecSChris Elston if (err) 638a32e0eecSChris Elston ip6_flush_pending_frames(sk); 639a32e0eecSChris Elston else if (!(msg->msg_flags & MSG_MORE)) 640a32e0eecSChris Elston err = l2tp_ip6_push_pending_frames(sk); 641a32e0eecSChris Elston release_sock(sk); 642a32e0eecSChris Elston done: 643a32e0eecSChris Elston dst_release(dst); 644a32e0eecSChris Elston out: 645a32e0eecSChris Elston fl6_sock_release(flowlabel); 64645f6fad8SEric Dumazet txopt_put(opt_to_free); 647a32e0eecSChris Elston 648a32e0eecSChris Elston return err < 0 ? err : len; 649a32e0eecSChris Elston 650a32e0eecSChris Elston do_confirm: 6510dec879fSJulian Anastasov if (msg->msg_flags & MSG_PROBE) 6520dec879fSJulian Anastasov dst_confirm_neigh(dst, &fl6.daddr); 653a32e0eecSChris Elston if (!(msg->msg_flags & MSG_PROBE) || len) 654a32e0eecSChris Elston goto back_from_confirm; 655a32e0eecSChris Elston err = 0; 656a32e0eecSChris Elston goto done; 657a32e0eecSChris Elston } 658a32e0eecSChris Elston 6591b784140SYing Xue static int l2tp_ip6_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, 660*ec095263SOliver Hartkopp int flags, int *addr_len) 661a32e0eecSChris Elston { 662700163dbSTom Parkin struct ipv6_pinfo *np = inet6_sk(sk); 663342dfc30SSteffen Hurrle DECLARE_SOCKADDR(struct sockaddr_l2tpip6 *, lsa, msg->msg_name); 664a32e0eecSChris Elston size_t copied = 0; 665a32e0eecSChris Elston int err = -EOPNOTSUPP; 666a32e0eecSChris Elston struct sk_buff *skb; 667a32e0eecSChris Elston 668a32e0eecSChris Elston if (flags & MSG_OOB) 669a32e0eecSChris Elston goto out; 670a32e0eecSChris Elston 671a32e0eecSChris Elston if (flags & MSG_ERRQUEUE) 67285fbaa75SHannes Frederic Sowa return ipv6_recv_error(sk, msg, len, addr_len); 673a32e0eecSChris Elston 674f4b41f06SOliver Hartkopp skb = skb_recv_datagram(sk, flags, &err); 675a32e0eecSChris Elston if (!skb) 676a32e0eecSChris Elston goto out; 677a32e0eecSChris Elston 678a32e0eecSChris Elston copied = skb->len; 679a32e0eecSChris Elston if (len < copied) { 680a32e0eecSChris Elston msg->msg_flags |= MSG_TRUNC; 681a32e0eecSChris Elston copied = len; 682a32e0eecSChris Elston } 683a32e0eecSChris Elston 68451f3d02bSDavid S. Miller err = skb_copy_datagram_msg(skb, 0, msg, copied); 685a32e0eecSChris Elston if (err) 686a32e0eecSChris Elston goto done; 687a32e0eecSChris Elston 688a32e0eecSChris Elston sock_recv_timestamp(msg, sk, skb); 689a32e0eecSChris Elston 690a32e0eecSChris Elston /* Copy the address. */ 691a32e0eecSChris Elston if (lsa) { 692a32e0eecSChris Elston lsa->l2tp_family = AF_INET6; 693a32e0eecSChris Elston lsa->l2tp_unused = 0; 694a32e0eecSChris Elston lsa->l2tp_addr = ipv6_hdr(skb)->saddr; 695a32e0eecSChris Elston lsa->l2tp_flowinfo = 0; 696a32e0eecSChris Elston lsa->l2tp_scope_id = 0; 697b860d3ccSMathias Krause lsa->l2tp_conn_id = 0; 698a32e0eecSChris Elston if (ipv6_addr_type(&lsa->l2tp_addr) & IPV6_ADDR_LINKLOCAL) 6994330487aSDuan Jiong lsa->l2tp_scope_id = inet6_iif(skb); 700163d1c3dSEric Dumazet *addr_len = sizeof(*lsa); 701a32e0eecSChris Elston } 702a32e0eecSChris Elston 703700163dbSTom Parkin if (np->rxopt.all) 704700163dbSTom Parkin ip6_datagram_recv_ctl(sk, msg, skb); 705a32e0eecSChris Elston 706a32e0eecSChris Elston if (flags & MSG_TRUNC) 707a32e0eecSChris Elston copied = skb->len; 708a32e0eecSChris Elston done: 709a32e0eecSChris Elston skb_free_datagram(sk, skb); 710a32e0eecSChris Elston out: 711a32e0eecSChris Elston return err ? err : copied; 712a32e0eecSChris Elston } 713a32e0eecSChris Elston 714a32e0eecSChris Elston static struct proto l2tp_ip6_prot = { 715a32e0eecSChris Elston .name = "L2TP/IPv6", 716a32e0eecSChris Elston .owner = THIS_MODULE, 717a32e0eecSChris Elston .init = l2tp_ip6_open, 718a32e0eecSChris Elston .close = l2tp_ip6_close, 719a32e0eecSChris Elston .bind = l2tp_ip6_bind, 720a32e0eecSChris Elston .connect = l2tp_ip6_connect, 721c51ce497SJames Chapman .disconnect = l2tp_ip6_disconnect, 72272fb96e7SEric Dumazet .ioctl = l2tp_ioctl, 723a32e0eecSChris Elston .destroy = l2tp_ip6_destroy_sock, 724a32e0eecSChris Elston .setsockopt = ipv6_setsockopt, 725a32e0eecSChris Elston .getsockopt = ipv6_getsockopt, 726a32e0eecSChris Elston .sendmsg = l2tp_ip6_sendmsg, 727a32e0eecSChris Elston .recvmsg = l2tp_ip6_recvmsg, 728a32e0eecSChris Elston .backlog_rcv = l2tp_ip6_backlog_recv, 72902c71b14SEric Dumazet .hash = l2tp_ip6_hash, 73002c71b14SEric Dumazet .unhash = l2tp_ip6_unhash, 731a32e0eecSChris Elston .obj_size = sizeof(struct l2tp_ip6_sock), 732a32e0eecSChris Elston }; 733a32e0eecSChris Elston 734a32e0eecSChris Elston static const struct proto_ops l2tp_ip6_ops = { 735a32e0eecSChris Elston .family = PF_INET6, 736a32e0eecSChris Elston .owner = THIS_MODULE, 737a32e0eecSChris Elston .release = inet6_release, 738a32e0eecSChris Elston .bind = inet6_bind, 739a32e0eecSChris Elston .connect = inet_dgram_connect, 740a32e0eecSChris Elston .socketpair = sock_no_socketpair, 741a32e0eecSChris Elston .accept = sock_no_accept, 742a32e0eecSChris Elston .getname = l2tp_ip6_getname, 743a11e1d43SLinus Torvalds .poll = datagram_poll, 744a32e0eecSChris Elston .ioctl = inet6_ioctl, 745c7cbdbf2SArnd Bergmann .gettstamp = sock_gettstamp, 746a32e0eecSChris Elston .listen = sock_no_listen, 747a32e0eecSChris Elston .shutdown = inet_shutdown, 748a32e0eecSChris Elston .setsockopt = sock_common_setsockopt, 749a32e0eecSChris Elston .getsockopt = sock_common_getsockopt, 750a32e0eecSChris Elston .sendmsg = inet_sendmsg, 751a32e0eecSChris Elston .recvmsg = sock_common_recvmsg, 752a32e0eecSChris Elston .mmap = sock_no_mmap, 753a32e0eecSChris Elston .sendpage = sock_no_sendpage, 754a32e0eecSChris Elston #ifdef CONFIG_COMPAT 7553986912fSChristoph Hellwig .compat_ioctl = inet6_compat_ioctl, 756a32e0eecSChris Elston #endif 757a32e0eecSChris Elston }; 758a32e0eecSChris Elston 759a32e0eecSChris Elston static struct inet_protosw l2tp_ip6_protosw = { 760a32e0eecSChris Elston .type = SOCK_DGRAM, 761a32e0eecSChris Elston .protocol = IPPROTO_L2TP, 762a32e0eecSChris Elston .prot = &l2tp_ip6_prot, 763a32e0eecSChris Elston .ops = &l2tp_ip6_ops, 764a32e0eecSChris Elston }; 765a32e0eecSChris Elston 766a32e0eecSChris Elston static struct inet6_protocol l2tp_ip6_protocol __read_mostly = { 767a32e0eecSChris Elston .handler = l2tp_ip6_recv, 768a32e0eecSChris Elston }; 769a32e0eecSChris Elston 770a32e0eecSChris Elston static int __init l2tp_ip6_init(void) 771a32e0eecSChris Elston { 772a32e0eecSChris Elston int err; 773a32e0eecSChris Elston 774a4ca44faSJoe Perches pr_info("L2TP IP encapsulation support for IPv6 (L2TPv3)\n"); 775a32e0eecSChris Elston 776a32e0eecSChris Elston err = proto_register(&l2tp_ip6_prot, 1); 777a32e0eecSChris Elston if (err != 0) 778a32e0eecSChris Elston goto out; 779a32e0eecSChris Elston 780a32e0eecSChris Elston err = inet6_add_protocol(&l2tp_ip6_protocol, IPPROTO_L2TP); 781a32e0eecSChris Elston if (err) 782a32e0eecSChris Elston goto out1; 783a32e0eecSChris Elston 784a32e0eecSChris Elston inet6_register_protosw(&l2tp_ip6_protosw); 785a32e0eecSChris Elston return 0; 786a32e0eecSChris Elston 787a32e0eecSChris Elston out1: 788a32e0eecSChris Elston proto_unregister(&l2tp_ip6_prot); 789a32e0eecSChris Elston out: 790a32e0eecSChris Elston return err; 791a32e0eecSChris Elston } 792a32e0eecSChris Elston 793a32e0eecSChris Elston static void __exit l2tp_ip6_exit(void) 794a32e0eecSChris Elston { 795a32e0eecSChris Elston inet6_unregister_protosw(&l2tp_ip6_protosw); 796a32e0eecSChris Elston inet6_del_protocol(&l2tp_ip6_protocol, IPPROTO_L2TP); 797a32e0eecSChris Elston proto_unregister(&l2tp_ip6_prot); 798a32e0eecSChris Elston } 799a32e0eecSChris Elston 800a32e0eecSChris Elston module_init(l2tp_ip6_init); 801a32e0eecSChris Elston module_exit(l2tp_ip6_exit); 802a32e0eecSChris Elston 803a32e0eecSChris Elston MODULE_LICENSE("GPL"); 804a32e0eecSChris Elston MODULE_AUTHOR("Chris Elston <celston@katalix.com>"); 805a32e0eecSChris Elston MODULE_DESCRIPTION("L2TP IP encapsulation for IPv6"); 806a32e0eecSChris Elston MODULE_VERSION("1.0"); 807a32e0eecSChris Elston 808a32e0eecSChris Elston /* Use the value of SOCK_DGRAM (2) directory, because __stringify doesn't like 809a32e0eecSChris Elston * enums 810a32e0eecSChris Elston */ 811a32e0eecSChris Elston MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET6, 2, IPPROTO_L2TP); 812163c2e25Sstephen hemminger MODULE_ALIAS_NET_PF_PROTO(PF_INET6, IPPROTO_L2TP); 813