if (sk_laddr && !ipv6_addr_any(sk_laddr) &&
!ipv6_addr_any(laddr) && !ipv6_addr_equal(sk_laddr, laddr)) continue;
if (!ipv6_addr_any(sk_raddr) && raddr &&
!ipv6_addr_any(raddr) && !ipv6_addr_equal(sk_raddr, raddr)) continue;
if (l2tp->conn_id != tunnel_id) continue;
goto found;
}
sk = NULL;
found: return sk;
}
/* When processing receive frames, there are two cases to * consider. Data frames consist of a non-zero session-id and an * optional cookie. Control frames consist of a regular L2TP header * preceded by 32-bits of zeros. * * L2TPv3 Session Header Over IP * * 0 1 2 3 * 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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Session ID | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Cookie (optional, maximum 64 bits)... * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * * L2TPv3 Control Message Header Over IP * * 0 1 2 3 * 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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | (32 bits of zeros) | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * |T|L|x|x|S|x|x|x|x|x|x|x| Ver | Length | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Control Connection ID | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Ns | Nr | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * * All control frames are passed to userspace.
*/ staticint l2tp_ip6_recv(struct sk_buff *skb)
{ struct net *net = dev_net(skb->dev); struct l2tp_ip6_net *pn; struct sock *sk;
u32 session_id;
u32 tunnel_id; unsignedchar *ptr, *optr; struct l2tp_session *session; struct l2tp_tunnel *tunnel = NULL; struct ipv6hdr *iph;
pn = l2tp_ip6_pernet(net);
if (!pskb_may_pull(skb, 4)) goto discard;
/* Point to L2TP header */
optr = skb->data;
ptr = skb->data;
session_id = ntohl(*((__be32 *)ptr));
ptr += 4;
/* RFC3931: L2TP/IP packets have the first 4 bytes containing * the session_id. If it is 0, the packet is a L2TP control * frame and the session_id value can be discarded.
*/ if (session_id == 0) {
__skb_pull(skb, 4); goto pass_up;
}
/* Ok, this is a data packet. Lookup the session. */
session = l2tp_v3_session_get(net, NULL, session_id); if (!session) goto discard;
tunnel = session->tunnel; if (!tunnel) goto discard_sess;
if (l2tp_v3_ensure_opt_in_linear(session, skb, &ptr, &optr)) goto discard_sess;
tunnel = l2tp_sk_to_tunnel(sk); if (tunnel) {
l2tp_tunnel_delete(tunnel);
l2tp_tunnel_put(tunnel);
}
}
staticint l2tp_ip6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
{ struct inet_sock *inet = inet_sk(sk); struct ipv6_pinfo *np = inet6_sk(sk); struct sockaddr_l2tpip6 *addr = (struct sockaddr_l2tpip6 *)uaddr; struct net *net = sock_net(sk); struct l2tp_ip6_net *pn;
__be32 v4addr = 0; int bound_dev_if; int addr_type; int err;
pn = l2tp_ip6_pernet(net);
if (addr->l2tp_family != AF_INET6) return -EINVAL; if (addr_len < sizeof(*addr)) return -EINVAL;
addr_type = ipv6_addr_type(&addr->l2tp_addr);
/* l2tp_ip6 sockets are IPv6 only */ if (addr_type == IPV6_ADDR_MAPPED) return -EADDRNOTAVAIL;
/* L2TP is point-point, not multicast */ if (addr_type & IPV6_ADDR_MULTICAST) return -EADDRNOTAVAIL;
lock_sock(sk);
err = -EINVAL; if (!sock_flag(sk, SOCK_ZAPPED)) goto out_unlock;
if (sk->sk_state != TCP_CLOSE) goto out_unlock;
bound_dev_if = sk->sk_bound_dev_if;
/* Check if the address belongs to the host. */
rcu_read_lock(); if (addr_type != IPV6_ADDR_ANY) { struct net_device *dev = NULL;
if (addr_type & IPV6_ADDR_LINKLOCAL) { if (addr->l2tp_scope_id)
bound_dev_if = addr->l2tp_scope_id;
/* Binding to link-local address requires an * interface.
*/ if (!bound_dev_if) goto out_unlock_rcu;
err = -ENODEV;
dev = dev_get_by_index_rcu(sock_net(sk), bound_dev_if); if (!dev) goto out_unlock_rcu;
}
/* ipv4 addr of the socket is invalid. Only the * unspecified and mapped address have a v4 equivalent.
*/
v4addr = LOOPBACK4_IPV6;
err = -EADDRNOTAVAIL; if (!ipv6_chk_addr(sock_net(sk), &addr->l2tp_addr, dev, 0)) goto out_unlock_rcu;
}
rcu_read_unlock();
if (lsa) { if (addr_len < SIN6_LEN_RFC2133) return -EINVAL;
if (lsa->l2tp_family && lsa->l2tp_family != AF_INET6) return -EAFNOSUPPORT;
daddr = &lsa->l2tp_addr; if (inet6_test_bit(SNDFLOW, sk)) {
fl6.flowlabel = lsa->l2tp_flowinfo & IPV6_FLOWINFO_MASK; if (fl6.flowlabel & IPV6_FLOWLABEL_MASK) {
flowlabel = fl6_sock_lookup(sk, fl6.flowlabel); if (IS_ERR(flowlabel)) return -EINVAL;
}
}
/* Otherwise it will be difficult to maintain * sk->sk_dst_cache.
*/ if (sk->sk_state == TCP_ESTABLISHED &&
ipv6_addr_equal(daddr, &sk->sk_v6_daddr))
daddr = &sk->sk_v6_daddr;
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Chris Elston ");
MODULE_DESCRIPTION("L2TP IP encapsulation for IPv6");
MODULE_VERSION("1.0");
/* Use the values of SOCK_DGRAM (2) as type and IPPROTO_L2TP (115) as protocol, * because __stringify doesn't like enums
*/
MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET6, 115, 2);
MODULE_ALIAS_NET_PF_PROTO(PF_INET6, 115);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.