--- zzzz-none-000/linux-3.10.107/net/l2tp/l2tp_ppp.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/net/l2tp/l2tp_ppp.c 2021-02-04 17:41:59.000000000 +0000 @@ -98,6 +98,7 @@ #include #include #include +#include #include #include @@ -131,9 +132,16 @@ }; static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb); - -static const struct ppp_channel_ops pppol2tp_chan_ops = { - .start_xmit = pppol2tp_xmit, +static int pppol2tp_get_channel_protocol(struct ppp_channel *); +static int pppol2tp_get_channel_protocol_ver(struct ppp_channel *); +static void pppol2tp_hold_chan(struct ppp_channel *); +static void pppol2tp_release_chan(struct ppp_channel *); +static const struct pppol2tp_channel_ops pppol2tp_chan_ops = { + .ops.start_xmit = pppol2tp_xmit, + .ops.get_channel_protocol = pppol2tp_get_channel_protocol, + .ops.get_channel_protocol_ver = pppol2tp_get_channel_protocol_ver, + .ops.hold = pppol2tp_hold_chan, + .ops.release = pppol2tp_release_chan, }; static const struct proto_ops pppol2tp_ops; @@ -177,7 +185,7 @@ if (!pskb_may_pull(skb, 2)) return 1; - if ((skb->data[0] == 0xff) && (skb->data[1] == 0x03)) + if ((skb->data[0] == PPP_ALLSTATIONS) && (skb->data[1] == PPP_UI)) skb_pull(skb, 2); return 0; @@ -185,9 +193,8 @@ /* Receive message. This is the recvmsg for the PPPoL2TP socket. */ -static int pppol2tp_recvmsg(struct kiocb *iocb, struct socket *sock, - struct msghdr *msg, size_t len, - int flags) +static int pppol2tp_recvmsg(struct socket *sock, struct msghdr *msg, + size_t len, int flags) { int err; struct sk_buff *skb; @@ -208,7 +215,7 @@ else if (len < skb->len) msg->msg_flags |= MSG_TRUNC; - err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, len); + err = skb_copy_datagram_msg(skb, 0, msg, len); if (likely(err == 0)) err = len; @@ -252,14 +259,17 @@ nf_reset(skb); po = pppox_sk(sk); + skb->skb_iif = ppp_dev_index(&po->chan); ppp_input(&po->chan, skb); } else { - l2tp_info(session, PPPOL2TP_MSG_DATA, "%s: socket not bound\n", - session->name); + l2tp_dbg(session, PPPOL2TP_MSG_DATA, + "%s: recv %d byte data frame, passing to L2TP socket\n", + session->name, data_len); - /* Not bound. Nothing we can do, so discard. */ - atomic_long_inc(&session->stats.rx_errors); - kfree_skb(skb); + if (sock_queue_rcv_skb(sk, skb) < 0) { + atomic_long_inc(&session->stats.rx_errors); + kfree_skb(skb); + } } return; @@ -293,10 +303,9 @@ * when a user application does a sendmsg() on the session socket. L2TP and * PPP headers must be inserted into the user's data. */ -static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, +static int pppol2tp_sendmsg(struct socket *sock, struct msghdr *m, size_t total_len) { - static const unsigned char ppph[2] = { 0xff, 0x03 }; struct sock *sk = sock->sk; struct sk_buff *skb; int error; @@ -326,7 +335,7 @@ error = -ENOMEM; skb = sock_wmalloc(sk, NET_SKB_PAD + sizeof(struct iphdr) + uhlen + session->hdr_len + - sizeof(ppph) + total_len, + 2 + total_len, /* 2 bytes for PPP_ALLSTATIONS & PPP_UI */ 0, GFP_KERNEL); if (!skb) goto error_put_sess_tun; @@ -339,13 +348,12 @@ skb_reserve(skb, uhlen); /* Add PPP header */ - skb->data[0] = ppph[0]; - skb->data[1] = ppph[1]; + skb->data[0] = PPP_ALLSTATIONS; + skb->data[1] = PPP_UI; skb_put(skb, 2); /* Copy user data into skb */ - error = memcpy_fromiovec(skb_put(skb, total_len), m->msg_iov, - total_len); + error = memcpy_from_msg(skb_put(skb, total_len), m, total_len); if (error < 0) { kfree_skb(skb); goto error_put_sess_tun; @@ -368,6 +376,126 @@ return error; } +/* pppol2tp_hold_chan() */ +static void pppol2tp_hold_chan(struct ppp_channel *chan) +{ + struct sock *sk = (struct sock *)chan->private; + + sock_hold(sk); +} + +/* pppol2tp_release_chan() */ +static void pppol2tp_release_chan(struct ppp_channel *chan) +{ + struct sock *sk = (struct sock *)chan->private; + + sock_put(sk); +} + +/* pppol2tp_get_channel_protocol() + * Return the protocol type of the L2TP over PPP protocol + */ +static int pppol2tp_get_channel_protocol(struct ppp_channel *chan) +{ + return PX_PROTO_OL2TP; +} + +/* pppol2tp_get_channel_protocol_ver() + * Return the protocol version of the L2TP over PPP protocol + */ +static int pppol2tp_get_channel_protocol_ver(struct ppp_channel *chan) +{ + struct sock *sk; + struct l2tp_session *session; + struct l2tp_tunnel *tunnel; + struct pppol2tp_session *ps; + int version = 0; + + if (chan && chan->private) + sk = (struct sock *)chan->private; + else + return -1; + + /* Get session and tunnel contexts from the socket */ + session = pppol2tp_sock_to_session(sk); + if (!session) + return -1; + + ps = l2tp_session_priv(session); + if (!ps->tunnel_sock) { + sock_put(sk); + return -1; + } + + tunnel = l2tp_sock_to_tunnel(ps->tunnel_sock); + if (!tunnel) { + sock_put(sk); + return -1; + } + + version = tunnel->version; + + sock_put(ps->tunnel_sock); + sock_put(sk); + + return version; +} + +/* pppol2tp_get_addressing() */ +static int pppol2tp_get_addressing(struct ppp_channel *chan, + struct pppol2tp_common_addr *addr) +{ + struct sock *sk = (struct sock *)chan->private; + struct sock *sk_tun; + struct l2tp_session *session; + struct l2tp_tunnel *tunnel; + struct pppol2tp_session *ps; + struct inet_sock *isk = NULL; + int err = -ENXIO; + + /* Get session and tunnel contexts from the socket */ + session = pppol2tp_sock_to_session(sk); + if (!session) + return err; + + ps = l2tp_session_priv(session); + sk_tun = ps->tunnel_sock; + if (!sk_tun) { + sock_put(sk); + return err; + } + + tunnel = l2tp_sock_to_tunnel(sk_tun); + if (!tunnel) { + sock_put(sk_tun); + sock_put(sk); + return err; + } + isk = inet_sk(ps->tunnel_sock); + + addr->local_tunnel_id = tunnel->tunnel_id; + addr->remote_tunnel_id = tunnel->peer_tunnel_id; + addr->local_session_id = session->session_id; + addr->remote_session_id = session->peer_session_id; + + addr->local_addr.sin_port = isk->inet_sport; + addr->remote_addr.sin_port = isk->inet_dport; + addr->local_addr.sin_addr.s_addr = isk->inet_saddr; + addr->remote_addr.sin_addr.s_addr = isk->inet_daddr; + + sock_put(sk_tun); + sock_put(sk); + return 0; +} + +/* pppol2tp_channel_addressing_get() */ +int pppol2tp_channel_addressing_get(struct ppp_channel *chan, + struct pppol2tp_common_addr *addr) +{ + return pppol2tp_get_addressing(chan, addr); +} +EXPORT_SYMBOL(pppol2tp_channel_addressing_get); + /* Transmit function called by generic PPP driver. Sends PPP frame * over PPPoL2TP socket. * @@ -384,7 +512,6 @@ */ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) { - static const u8 ppph[2] = { 0xff, 0x03 }; struct sock *sk = (struct sock *) chan->private; struct sock *sk_tun; struct l2tp_session *session; @@ -413,14 +540,19 @@ sizeof(struct iphdr) + /* IP header */ uhlen + /* UDP header (if L2TP_ENCAPTYPE_UDP) */ session->hdr_len + /* L2TP header */ - sizeof(ppph); /* PPP header */ + 2; /* 2 bytes for PPP_ALLSTATIONS & PPP_UI */ if (skb_cow_head(skb, headroom)) goto abort_put_sess_tun; /* Setup PPP header */ - __skb_push(skb, sizeof(ppph)); - skb->data[0] = ppph[0]; - skb->data[1] = ppph[1]; + __skb_push(skb, 2); + skb->data[0] = PPP_ALLSTATIONS; + skb->data[1] = PPP_UI; + + /* set incoming interface as the ppp interface */ + if ((skb->protocol == htons(ETH_P_IP)) || + (skb->protocol == htons(ETH_P_IPV6))) + skb->skb_iif = ppp_dev_index(chan); local_bh_disable(); l2tp_xmit_skb(session, skb, session->hdr_len); @@ -454,13 +586,11 @@ BUG_ON(session->magic != L2TP_SESSION_MAGIC); + if (sock) + inet_shutdown(sock, SEND_SHUTDOWN); - if (sock) { - inet_shutdown(sock, 2); - /* Don't let the session go away before our socket does */ - l2tp_session_inc_refcount(session); - } - return; + /* Don't let the session go away before our socket does */ + l2tp_session_inc_refcount(session); } /* Really kill the session socket. (Called from sock_put() if @@ -474,7 +604,6 @@ BUG_ON(session->magic != L2TP_SESSION_MAGIC); l2tp_session_dec_refcount(session); } - return; } /* Called when the PPPoX socket (session) is closed. @@ -545,12 +674,12 @@ /* socket() handler. Initialize a new struct sock. */ -static int pppol2tp_create(struct net *net, struct socket *sock) +static int pppol2tp_create(struct net *net, struct socket *sock, int kern) { int error = -ENOMEM; struct sock *sk; - sk = sk_alloc(net, PF_PPPOX, GFP_KERNEL, &pppol2tp_sk_proto); + sk = sk_alloc(net, PF_PPPOX, GFP_KERNEL, &pppol2tp_sk_proto, kern); if (!sk) goto out; @@ -602,6 +731,7 @@ int error = 0; u32 tunnel_id, peer_tunnel_id; u32 session_id, peer_session_id; + bool drop_refcnt = false; int ver = 2; int fd; @@ -703,36 +833,36 @@ if (tunnel->peer_tunnel_id == 0) tunnel->peer_tunnel_id = peer_tunnel_id; - /* Create session if it doesn't already exist. We handle the - * case where a session was previously created by the netlink - * interface by checking that the session doesn't already have - * a socket and its tunnel socket are what we expect. If any - * of those checks fail, return EEXIST to the caller. - */ - session = l2tp_session_find(sock_net(sk), tunnel, session_id); - if (session == NULL) { - /* Default MTU must allow space for UDP/L2TP/PPP - * headers. + session = l2tp_session_get(sock_net(sk), tunnel, session_id, false); + if (session) { + drop_refcnt = true; + ps = l2tp_session_priv(session); + + /* Using a pre-existing session is fine as long as it hasn't + * been connected yet. */ - cfg.mtu = cfg.mru = 1500 - PPPOL2TP_HEADER_OVERHEAD; + if (ps->sock) { + error = -EEXIST; + goto end; + } - /* Allocate and initialize a new session context. */ - session = l2tp_session_create(sizeof(struct pppol2tp_session), - tunnel, session_id, - peer_session_id, &cfg); - if (session == NULL) { - error = -ENOMEM; + /* consistency checks */ + if (ps->tunnel_sock != tunnel->sock) { + error = -EEXIST; goto end; } } else { - ps = l2tp_session_priv(session); - error = -EEXIST; - if (ps->sock != NULL) - goto end; + /* Default MTU must allow space for UDP/L2TP/PPP headers */ + cfg.mtu = 1500 - PPPOL2TP_HEADER_OVERHEAD; + cfg.mru = cfg.mtu; - /* consistency checks */ - if (ps->tunnel_sock != tunnel->sock) + session = l2tp_session_create(sizeof(struct pppol2tp_session), + tunnel, session_id, + peer_session_id, &cfg); + if (IS_ERR(session)) { + error = PTR_ERR(session); goto end; + } } /* Associate session with its PPPoL2TP socket */ @@ -782,7 +912,7 @@ po->chan.hdrlen = PPPOL2TP_L2TP_HDR_SIZE_NOSEQ; po->chan.private = sk; - po->chan.ops = &pppol2tp_chan_ops; + po->chan.ops = &pppol2tp_chan_ops.ops; po->chan.mtu = session->mtu; error = ppp_register_net_channel(sock_net(sk), &po->chan); @@ -797,6 +927,8 @@ session->name); end: + if (drop_refcnt) + l2tp_session_dec_refcount(session); release_sock(sk); return error; @@ -824,12 +956,6 @@ if (tunnel->sock == NULL) goto out; - /* Check that this session doesn't already exist */ - error = -EEXIST; - session = l2tp_session_find(net, tunnel, session_id); - if (session != NULL) - goto out; - /* Default MTU values. */ if (cfg->mtu == 0) cfg->mtu = 1500 - PPPOL2TP_HEADER_OVERHEAD; @@ -837,12 +963,13 @@ cfg->mru = cfg->mtu; /* Allocate and initialize a new session context. */ - error = -ENOMEM; session = l2tp_session_create(sizeof(struct pppol2tp_session), tunnel, session_id, peer_session_id, cfg); - if (session == NULL) + if (IS_ERR(session)) { + error = PTR_ERR(session); goto out; + } ps = l2tp_session_priv(session); ps->tunnel_sock = tunnel->sock; @@ -909,8 +1036,8 @@ #if IS_ENABLED(CONFIG_IPV6) } else if ((tunnel->version == 2) && (tunnel->sock->sk_family == AF_INET6)) { - struct ipv6_pinfo *np = inet6_sk(tunnel->sock); struct sockaddr_pppol2tpin6 sp; + len = sizeof(sp); memset(&sp, 0, len); sp.sa_family = AF_PPPOX; @@ -923,13 +1050,13 @@ sp.pppol2tp.d_session = session->peer_session_id; sp.pppol2tp.addr.sin6_family = AF_INET6; sp.pppol2tp.addr.sin6_port = inet->inet_dport; - memcpy(&sp.pppol2tp.addr.sin6_addr, &np->daddr, - sizeof(np->daddr)); + memcpy(&sp.pppol2tp.addr.sin6_addr, &tunnel->sock->sk_v6_daddr, + sizeof(tunnel->sock->sk_v6_daddr)); memcpy(uaddr, &sp, len); } else if ((tunnel->version == 3) && (tunnel->sock->sk_family == AF_INET6)) { - struct ipv6_pinfo *np = inet6_sk(tunnel->sock); struct sockaddr_pppol2tpv3in6 sp; + len = sizeof(sp); memset(&sp, 0, len); sp.sa_family = AF_PPPOX; @@ -942,8 +1069,8 @@ sp.pppol2tp.d_session = session->peer_session_id; sp.pppol2tp.addr.sin6_family = AF_INET6; sp.pppol2tp.addr.sin6_port = inet->inet_dport; - memcpy(&sp.pppol2tp.addr.sin6_addr, &np->daddr, - sizeof(np->daddr)); + memcpy(&sp.pppol2tp.addr.sin6_addr, &tunnel->sock->sk_v6_daddr, + sizeof(tunnel->sock->sk_v6_daddr)); memcpy(uaddr, &sp, len); #endif } else if (tunnel->version == 3) { @@ -1163,11 +1290,18 @@ if (stats.session_id != 0) { /* resend to session ioctl handler */ struct l2tp_session *session = - l2tp_session_find(sock_net(sk), tunnel, stats.session_id); - if (session != NULL) - err = pppol2tp_session_ioctl(session, cmd, arg); - else + l2tp_session_get(sock_net(sk), tunnel, + stats.session_id, true); + + if (session) { + err = pppol2tp_session_ioctl(session, cmd, + arg); + if (session->deref) + session->deref(session); + l2tp_session_dec_refcount(session); + } else { err = -EBADR; + } break; } #ifdef CONFIG_XFRM @@ -1313,6 +1447,7 @@ po->chan.hdrlen = val ? PPPOL2TP_L2TP_HDR_SIZE_SEQ : PPPOL2TP_L2TP_HDR_SIZE_NOSEQ; } + l2tp_session_set_header_len(session, session->tunnel->version); l2tp_info(session, PPPOL2TP_MSG_CONTROL, "%s: set send_seq=%d\n", session->name, session->send_seq); @@ -1576,7 +1711,7 @@ static void pppol2tp_next_session(struct net *net, struct pppol2tp_seq_data *pd) { - pd->session = l2tp_session_get_nth(pd->tunnel, pd->session_idx, true); + pd->session = l2tp_session_find_nth(pd->tunnel, pd->session_idx); pd->session_idx++; if (pd->session == NULL) { @@ -1703,14 +1838,10 @@ /* Show the tunnel or session context. */ - if (!pd->session) { + if (pd->session == NULL) pppol2tp_seq_tunnel_show(m, pd->tunnel); - } else { + else pppol2tp_seq_session_show(m, pd->session); - if (pd->session->deref) - pd->session->deref(pd->session); - l2tp_session_dec_refcount(pd->session); - } out: return 0; @@ -1869,3 +2000,4 @@ MODULE_LICENSE("GPL"); MODULE_VERSION(PPPOL2TP_DRV_VERSION); MODULE_ALIAS("pppox-proto-" __stringify(PX_PROTO_OL2TP)); +MODULE_ALIAS_L2TP_PWTYPE(11);