--- zzzz-none-000/linux-4.4.60/net/l2tp/l2tp_ppp.c 2017-04-08 07:53:53.000000000 +0000 +++ dragonfly-4020-701/linux-4.4.60/net/l2tp/l2tp_ppp.c 2018-11-08 13:36:17.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; @@ -251,6 +259,7 @@ nf_reset(skb); po = pppox_sk(sk); + skb->skb_iif = ppp_dev_index(&po->chan); ppp_input(&po->chan, skb); } else { l2tp_dbg(session, PPPOL2TP_MSG_DATA, @@ -368,6 +377,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. * @@ -421,6 +550,10 @@ __skb_push(skb, sizeof(ppph)); skb->data[0] = ppph[0]; skb->data[1] = ppph[1]; + /* 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); @@ -779,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);