--- zzzz-none-000/linux-3.18.24/drivers/net/ppp/pptp.c 2015-10-31 20:39:51.000000000 +0000 +++ rtl96-5690pro-762/linux-3.18.24/drivers/net/ppp/pptp.c 2024-08-14 08:36:36.000000000 +0000 @@ -52,7 +52,7 @@ static DEFINE_SPINLOCK(chan_lock); static struct proto pptp_sk_proto __read_mostly; -static const struct ppp_channel_ops pptp_chan_ops; +/*static*/ const struct ppp_channel_ops pptp_chan_ops; static const struct proto_ops pptp_ops; #define PPP_LCP_ECHOREQ 0x09 @@ -167,6 +167,428 @@ synchronize_rcu(); } +#if 0//defined(CONFIG_RTL867X_IPTABLES_FAST_PATH) +/**************************************************************************/ +extern int vpn_ppp_down_fastpath(struct ppp_channel *chan, struct sk_buff **skb, unsigned int headroom); +extern int FastPath_Enter(struct sk_buff *skb); +static unsigned short iphdr_id=0; + +/* + * NAME: pptp_up_fastpath + * Return value: 0 fail 1 success + * Date: 20111117 + */ +/*__IRAM*/ int pptp_up_fastpath(struct ppp_channel *chan, struct sk_buff *skb) +{ + struct sock *sk = (struct sock *) chan->private; + struct pppox_sock *po = pppox_sk(sk); + struct pptp_opt *opt = &po->proto.pptp; + //struct pptp_gre_header *hdr; + unsigned char *hdr; + //struct iphdr *iph; + unsigned char *iph; + unsigned int header_len = sizeof(struct pptp_gre_header);//sizeof(*hdr); + int len; + //unsigned char *data; + __u32 seq_recv; + +#if 0//QL: move to pptp_ppp_up_fastpath() + data = skb_push(skb, 2); + data[0] = PPP_ALLSTATIONS; + data[1] = PPP_UI; +#endif + len = skb->len; + + seq_recv = opt->seq_recv; + + if (opt->ack_sent == seq_recv) + header_len -= 4;//sizeof(hdr->ack); + + /* Push down and install GRE header */ + //skb_push(skb, header_len); + //hdr = (struct pptp_gre_header *)(skb->data); + hdr = (unsigned char *)(skb->data-header_len); + +#if 0 + hdr->flags = PPTP_GRE_FLAG_K; + hdr->ver = PPTP_GRE_VER; + hdr->protocol = htons(PPTP_GRE_PROTO); + hdr->call_id = htons(opt->dst_addr.call_id); + + hdr->flags |= PPTP_GRE_FLAG_S; + hdr->seq = htonl(++opt->seq_sent); + + if (opt->ack_sent != seq_recv) { + /* send ack with this message */ + hdr->ver |= PPTP_GRE_FLAG_A; + hdr->ack = htonl(seq_recv); + opt->ack_sent = seq_recv; + } + hdr->payload_len = htons(len); +#else +#define GRE_HDR_FLAG_VER_PROTO (((PPTP_GRE_FLAG_K|PPTP_GRE_FLAG_S)<<24)|(PPTP_GRE_VER<<16)|(PPTP_GRE_PROTO)) + if (opt->ack_sent != seq_recv) { + *(unsigned int *)hdr = GRE_HDR_FLAG_VER_PROTO|(PPTP_GRE_FLAG_A<<16); + *(unsigned int *)(hdr+12) = htonl(seq_recv); + opt->ack_sent = seq_recv; + } + else + *(unsigned int *)hdr = GRE_HDR_FLAG_VER_PROTO; + *(unsigned int *)(hdr+4) = ((htons(len)<<16) | htons(opt->dst_addr.call_id)); + *(unsigned int *)(hdr+8) = htonl(++opt->seq_sent); +#endif + + //skb_push(skb, sizeof(*iph)); + iph = skb_push(skb, sizeof(struct iphdr)+header_len); + skb_reset_network_header(skb); + +#if 0 + iph->version = 4; + iph->ihl = sizeof(struct iphdr) >> 2; + iph->frag_off = 0x4000; + iph->protocol = IPPROTO_GRE; + iph->tos = 0; + iph->daddr = opt->dst_addr.sin_addr.s_addr; + iph->saddr = opt->src_addr.sin_addr.s_addr; + iph->ttl = 1; + iph->tot_len = htons(skb->len); + iph->id = ++iphdr_id; +#else + *(unsigned int *)iph = 0x45000000 | htons(skb->len); + *(unsigned int *)(iph+4) = ((++iphdr_id)<<16) | 0x4000; + *(unsigned short *)(iph+8) = 0x012F; +#ifdef CONFIG_IPV6_VPN + *(unsigned int *)(iph+12) = opt->src_addr.sin_addr.in.s_addr; + *(unsigned int *)(iph+16) = opt->dst_addr.sin_addr.in.s_addr; +#else + *(unsigned int *)(iph+12) = opt->src_addr.sin_addr.s_addr; + *(unsigned int *)(iph+16) = opt->dst_addr.sin_addr.s_addr; +#endif +#endif + + ip_send_check((struct iphdr *)iph); + + /* skb dst has been initialized to PPP device, so we must release it before redirecting to real device. */ + dst_release(skb_dst(skb)); + + if (FastPath_Enter(skb) != 1) { + struct rtable *rt; + int err = 0; + + { + struct flowi4 fl4; + + memset(&fl4, 0, sizeof(fl4)); + + fl4.flowi4_oif = 0; + #ifdef CONFIG_IPV6_VPN + fl4.daddr = opt->dst_addr.sin_addr.in.s_addr, + fl4.saddr = opt->src_addr.sin_addr.in.s_addr, + #else + fl4.daddr = opt->dst_addr.sin_addr.s_addr, + fl4.saddr = opt->src_addr.sin_addr.s_addr, + #endif + + fl4.flowi4_tos = RT_TOS(0); + fl4.flowi4_proto = IPPROTO_GRE; + + rt = ip_route_output_key(&init_net, &fl4); + + if (IS_ERR(rt)) + goto tx_error; + } + + skb_dst_set(skb, &rt->dst); + + //printk("%s %d go normal path.\n", __func__, __LINE__); + ip_local_out(skb); + } + //else + // printk("fastpath OK\n"); + + return 1; + +tx_error: + dev_kfree_skb(skb); + //printk("%s %d drop packet here(sip:%x dip:%x callid:%d).\n", __func__, __LINE__, + // iph->saddr, iph->daddr, hdr->call_id); + + return 1; +} + +/* + * NAME: pptp_down_fastpath + * Description: pptp downstream fastpath process + * Return value: 0 fail 1 success + * Date: 20111116 + */ +/*__IRAM*/ int pptp_down_fastpath(struct sk_buff **skb) +{ + struct iphdr *iph; + struct pptp_gre_header *grehdr; + struct pppox_sock *po; + struct pptp_opt *opt; + struct sock *sk; + int iphdrsize=0, grehdrsize=0, ppphdrsize=0; + int headersize=0, payload_len, seq; + __u32 orig_ack, orig_seq; + __u8 *payload; + int compressed=0; + int ret = -1; + +#if 0//pptp interface must be in route mode, don't need to do below check + if (skb->pkt_type != PACKET_HOST) + return -1; +#endif + iph = ip_hdr(*skb); + if(iph->frag_off & htons(0x3fff)) + return -1; + + iphdrsize = ip_hdrlen(*skb); + grehdr = (struct pptp_gre_header*)((__u32 *)iph + iph->ihl); + po = lookup_chan(htons(grehdr->call_id), iph->saddr); + if (NULL == po) + return -1; + + sk = sk_pppox(po); + bh_lock_sock(sk); + if (!sock_owned_by_user(sk)) { + opt = &po->proto.pptp; + + orig_ack = opt->ack_recv; + orig_seq = opt->seq_recv; + + /* test if acknowledgement present */ + if (PPTP_GRE_IS_A(grehdr->ver)) { + __u32 ack = (PPTP_GRE_IS_S(grehdr->flags)) ? + grehdr->ack : grehdr->seq; /* ack in different place if S = 0 */ + + ack = ntohl(ack); + + if (ack > opt->ack_recv) + opt->ack_recv = ack; + /* also handle sequence number wrap-around */ + if (WRAPPED(ack, opt->ack_recv)) + opt->ack_recv = ack; + } + + grehdrsize = sizeof(*grehdr); + payload_len = ntohs(grehdr->payload_len); + seq = ntohl(grehdr->seq); + + if (!PPTP_GRE_IS_A(grehdr->ver)) + grehdrsize -= sizeof(grehdr->ack); + headersize = iphdrsize + grehdrsize; + /* check for incomplete packet (length smaller than expected) */ + if ((*skb)->len - headersize < payload_len) { + ret = 1; + goto drop; + } + + payload = (*skb)->data + headersize; + if (seq < opt->seq_recv + 1 || WRAPPED(opt->seq_recv, seq)) { + opt->ack_recv = orig_ack; + goto out; + } + + opt->seq_recv = seq; + + if (payload[0] == PPP_ALLSTATIONS && payload[1] == PPP_UI) { + ppphdrsize = 2;//don't include protocol byte(2) + headersize += 2; + } + + //printk("total len %d iphdrlen %d grehdrlen %d ppphdrlen %d payloadlen %d skb->len %d\n", iph->tot_len, iphdrsize, grehdrsize, ppphdrsize, + // payload_len, skb->len); + skb_pull(*skb, headersize); + +#if 1 + if ( (!((*(*skb)->data) & 1)) && (*(__u16 *)(*skb)->data == PPP_COMP) ) + compressed = 1; + + //printk("%s proto:0x%x\n", __func__, *(__u16 *)skb->data); + if ( (!((*(*skb)->data) & 1)) && + ((*(__u16 *)(*skb)->data == PPP_IP) || (*(__u16 *)(*skb)->data == PPP_COMP)) && + ((ret = vpn_ppp_down_fastpath(&po->chan, skb, headersize)) == 1)) + goto out; + + /*if decompress done, we should modify gre hdr and ip header*/ + if (compressed) { + skb_push(*skb, ppphdrsize+grehdrsize); + grehdr = (struct pptp_gre_header*)(*skb)->data; + grehdr->payload_len = (*skb)->len-grehdrsize; + + skb_push(*skb, iphdrsize); + iph = (struct iphdr*)(*skb)->data; + iph->tot_len = (*skb)->len; + ip_send_check((struct iphdr *)iph); + } + else + skb_push(*skb, headersize); + + opt->ack_recv = orig_ack; + opt->seq_recv = orig_seq; + skb_reset_network_header(*skb); + skb_set_mac_header(*skb, -ETH_HLEN); + + //printk("%s normal path.\n", __func__); +#else + //printk("%s proto:0x%x\n", __func__, *(__u16 *)(*skb)->data); + if (((*(*skb)->data) & 1)/* protocol iscompressed*/ || + (*(__u16 *)(*skb)->data != PPP_IP) || + ((ret = vpn_ppp_down_fastpath(&po->chan, skb, headersize)) != 1)) { + opt->ack_recv = orig_ack; + opt->seq_recv = orig_seq; + skb_push(*skb, headersize); + skb_reset_network_header(*skb); + skb_set_mac_header(*skb, -ETH_HLEN); + } +#endif + + goto out; + } + +drop: + printk("%s drop packet\n", __func__); + dev_kfree_skb(*skb); +out: + bh_unlock_sock(sk); + sock_put(sk); + return ret; +} +#endif + +#ifdef CONFIG_IPV6_VPN +static int ipv6_pptp_xmit(struct ppp_channel *chan, struct sk_buff *skb) +{ + struct sock *sk = (struct sock *) chan->private; + struct pppox_sock *po = pppox_sk(sk); + struct pptp_opt *opt = &po->proto.pptp; + struct pptp_gre_header *hdr; + unsigned int header_len = sizeof(*hdr); + int err = 0; + int islcp; + int len; + unsigned char *data; + __u32 seq_recv; + + + struct flowi fl; + struct inet_sock *inet = inet_sk(sk); + struct ipv6_pinfo *np = inet6_sk(sk); + struct in6_addr *final_p = NULL, final; + struct dst_entry *dst; + struct net_device *tdev; + int max_headroom; + + + dst = __sk_dst_get(sk); + if (dst == NULL) { + memset(&fl, 0, sizeof(fl)); + fl.proto = IPPROTO_GRE; + ipv6_addr_copy(&fl.fl6_dst, &opt->dst_addr.sin_addr.in6); + ipv6_addr_copy(&fl.fl6_src, &opt->src_addr.sin_addr.in6); + fl.fl6_flowlabel = np->flow_label; + IP6_ECN_flow_xmit(sk, fl.fl6_flowlabel); + fl.oif = sk->sk_bound_dev_if; + fl.fl_ip_sport = inet->sport; + fl.fl_ip_dport = inet->dport; + security_sk_classify_flow(sk, &fl); + + if (np->opt && np->opt->srcrt) { + struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt; + ipv6_addr_copy(&final, &fl.fl6_dst); + ipv6_addr_copy(&fl.fl6_dst, rt0->addr); + final_p = &final; + } + + err = ip6_dst_lookup(sk, &dst, &fl); + + if (err) { + sk->sk_err_soft = -err; + kfree_skb(skb); + return err; + } + + if (final_p) + ipv6_addr_copy(&fl.fl6_dst, final_p); + + sk_setup_caps(sk, dst); + } + + tdev = dst->dev; + + max_headroom = LL_RESERVED_SPACE(tdev) + sizeof(struct ipv6hdr) + sizeof(*hdr) + 2; + + if (skb_headroom(skb) < max_headroom || skb_cloned(skb) || skb_shared(skb)) { + struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom); + if (!new_skb) { + goto tx_error; + } + if (skb->sk) + skb_set_owner_w(new_skb, skb->sk); + kfree_skb(skb); + skb = new_skb; + } + + data = skb->data; + islcp = ((data[0] << 8) + data[1]) == PPP_LCP && 1 <= data[2] && data[2] <= 7; + + /* compress protocol field */ + if ((opt->ppp_flags & SC_COMP_PROT) && data[0] == 0 && !islcp) + skb_pull(skb, 1); + + /* Put in the address/control bytes if necessary */ + if ((opt->ppp_flags & SC_COMP_AC) == 0 || islcp) { + data = skb_push(skb, 2); + data[0] = PPP_ALLSTATIONS; + data[1] = PPP_UI; + } + + len = skb->len; + + seq_recv = opt->seq_recv; + + if (opt->ack_sent == seq_recv) + header_len -= sizeof(hdr->ack); + + /* Push down and install GRE header */ + skb_push(skb, header_len); + hdr = (struct pptp_gre_header *)(skb->data); + + hdr->flags = PPTP_GRE_FLAG_K; + hdr->ver = PPTP_GRE_VER; + hdr->protocol = htons(PPTP_GRE_PROTO); + hdr->call_id = htons(opt->dst_addr.call_id); + + hdr->flags |= PPTP_GRE_FLAG_S; + hdr->seq = htonl(++opt->seq_sent); + if (opt->ack_sent != seq_recv) { + /* send ack with this message */ + hdr->ver |= PPTP_GRE_FLAG_A; + hdr->ack = htonl(seq_recv); + opt->ack_sent = seq_recv; + } + hdr->payload_len = htons(len); + + /* Push down and install the IP header. */ + + skb_reset_transport_header(skb); + + skb_dst_set(skb, dst_clone(dst)); + + /* Restore final destination back after routing done */ + ipv6_addr_copy(&fl.fl6_dst, &opt->dst_addr.sin_addr.in6); + + return ip6_xmit(sk, skb, &fl, np->opt, 0); + +tx_error: + kfree_skb(skb); + return 1; +} + +#endif + static int pptp_xmit(struct ppp_channel *chan, struct sk_buff *skb) { struct sock *sk = (struct sock *) chan->private; @@ -282,6 +704,9 @@ skb->ip_summed = CHECKSUM_NONE; ip_select_ident(skb, NULL); +#if 0//defined(CONFIG_RTL867X_IPTABLES_FAST_PATH) + iphdr_id = iph->id; +#endif ip_send_check(iph); ip_local_out(skb); @@ -344,6 +769,12 @@ payload = skb->data + headersize; /* check for expected sequence number */ if (seq < opt->seq_recv + 1 || WRAPPED(opt->seq_recv, seq)) { +#ifdef CONFIG_YUEME + /* We find www.openwrtdl.com PPTP server sequence number may out-of-order */ + /* Remove these code if you can find a way to re-order packets. */ + if( PPP_PROTOCOL(payload) == PPP_CHAP) + goto allow_packet; +#endif if ((payload[0] == PPP_ALLSTATIONS) && (payload[1] == PPP_UI) && (PPP_PROTOCOL(payload) == PPP_LCP) && ((payload[4] == PPP_LCP_ECHOREQ) || (payload[4] == PPP_LCP_ECHOREP))) @@ -626,7 +1057,7 @@ return err; } -static const struct ppp_channel_ops pptp_chan_ops = { +/*static*/ const struct ppp_channel_ops pptp_chan_ops = { .start_xmit = pptp_xmit, .ioctl = pptp_ppp_ioctl, };