[Feature][ZXW-237]merge P54U03 version
Only Configure: No
Affected branch: master
Affected module: unknow
Is it affected on both ZXIC and MTK: only ZXIC
Self-test: Yes
Doc Update: No
Change-Id: Id39ef8b992af691eab09c01d4ea26da89e5f4049
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/psnet/psnet_dev.c b/ap/os/linux/linux-3.4.x/drivers/net/psnet/psnet_dev.c
index 5df877d..09a1b2b 100755
--- a/ap/os/linux/linux-3.4.x/drivers/net/psnet/psnet_dev.c
+++ b/ap/os/linux/linux-3.4.x/drivers/net/psnet/psnet_dev.c
@@ -6,6 +6,14 @@
#include "psnet.h"
#include "psnet_io.h"
#include <mach/iomap.h>
+
+#include <linux/if_addr.h>
+#include <linux/ip.h>
+#include <net/ip.h>
+#include <linux/ipv6.h>
+#include <net/ipv6.h>
+#include <net/protocol.h>
+
#define WATCHDOG_TIMEO (5*HZ)
/* NET NUMBER; channel id; lan/wan*/
@@ -248,6 +256,49 @@
netif_wake_queue(net);
}
+typedef int (*set_xlat_CB)(unsigned char *ip_info, unsigned char *dev_name);
+extern set_xlat_CB g_set_xlat_cb;
+extern struct in6_addr g_plat_subnet;
+extern struct in6_addr g_ipv6_local_subnet;
+extern struct in_addr g_ipv4_local_subnet;
+extern struct net_device *g_xlat_dev;
+int psnet_set_xlat(unsigned char *ip_info, unsigned char *dev_name)
+{
+ unsigned char *buff = ip_info;
+ memcpy(&g_plat_subnet, buff, sizeof(struct in6_addr));
+ buff = buff + sizeof(struct in6_addr);
+ memcpy(&g_ipv6_local_subnet, buff, sizeof(struct in6_addr));
+ buff = buff + sizeof(struct in6_addr);
+ memcpy(&g_ipv4_local_subnet, buff, sizeof(struct in_addr));
+ g_xlat_dev = dev_get_by_name(&init_net, dev_name);
+}
+
+int fill_ip_header(struct iphdr *ip, const struct ipv6hdr *old_header) {
+ if(memcmp(&old_header->saddr, &g_plat_subnet, 12)){
+ return 0;
+ }
+ if(memcmp(&old_header->daddr, &g_ipv6_local_subnet, 16)){
+ return 0;
+ }
+ ip->saddr = old_header->saddr.s6_addr32[3];
+ ip->daddr = g_ipv4_local_subnet.s_addr;
+ ip->ihl = 5;
+ ip->version = 4;
+ ip->tos = 0;
+ ip->tot_len = htons(sizeof(struct iphdr) + ntohs(old_header->payload_len));
+ ip->id = 0;
+ ip->frag_off = htons(IP_DF);
+ ip->ttl = old_header->hop_limit;
+ ip->protocol = old_header->nexthdr;
+ ip->check = 0;
+ return 1;
+}
+extern int fast_nat_check(unsigned char *data);
+extern uint32_t ipv6_pseudo_header_checksum(const struct ipv6hdr *ip6, uint16_t len, uint8_t protocol);
+extern uint32_t ipv4_pseudo_header_checksum(const struct iphdr *ip, uint16_t len);
+extern uint16_t ip_checksum(const void *data, int len);
+extern uint16_t ip_checksum_adjust(uint16_t checksum, uint32_t old_hdr_sum, uint32_t new_hdr_sum);
+
#define PSBUFF_DL_HEADER_OFFSET 64 //80
//extern void * zGetpsbufferHead(void * data);
void psnet_recv_notify(unsigned int index, const void *buffer, unsigned int length)//(T_ZDrvRpMsg_Msg rpmsg)
@@ -267,6 +318,41 @@
psData.pbuf_head = buffer - PSBUFF_DL_HEADER_OFFSET;
#endif
psData.datalen = length;
+
+ unsigned char header[40] = {0};
+ if(unlikely(g_xlat_dev) && g_xlat_dev == dev->net && ((*(uint8_t *)psData.pbuf_data)&0xf0) == 0x60 && (g_xlat_dev->flags & IFF_UP)){
+ struct iphdr *ip_h = header;
+ struct ipv6hdr *ip6_h = (struct ipv6hdr *)psData.pbuf_data;
+ memcpy(header + sizeof(struct iphdr), psData.pbuf_data + sizeof(struct ipv6hdr), 4);
+ if(fill_ip_header(ip_h, ip6_h) && fast_nat_check(ip_h)){//
+ uint32_t old_sum, new_sum;
+ uint16_t checksum, len_left;
+ uint8_t protocol = ip6_h->nexthdr;
+
+ len_left = ntohs(ip6_h->payload_len);
+ old_sum = ipv6_pseudo_header_checksum(psData.pbuf_data, len_left, protocol);
+ new_sum = ipv4_pseudo_header_checksum(ip_h, len_left);
+ ip_h->check = ip_checksum(ip_h, sizeof(struct iphdr));
+ if (protocol == IPPROTO_TCP) {
+ struct tcphdr *tcp_targ = (struct tcphdr *)(psData.pbuf_data + sizeof(struct ipv6hdr));
+ checksum = ip_checksum_adjust(tcp_targ->check, old_sum, new_sum);
+ tcp_targ->check = checksum;
+ psData.pbuf_data = psData.pbuf_data + sizeof(struct ipv6hdr) - sizeof(struct iphdr);
+ memcpy(psData.pbuf_data, ip_h, sizeof(struct iphdr));
+ psData.datalen = psData.datalen - sizeof(struct ipv6hdr) + sizeof(struct iphdr);
+ }else if (protocol == IPPROTO_UDP) {
+ struct udphdr *udp_targ = (struct udphdr *)(psData.pbuf_data + sizeof(struct ipv6hdr));
+ if(udp_targ->check){
+ checksum = ip_checksum_adjust(udp_targ->check, old_sum, new_sum);
+ udp_targ->check = checksum;
+ }
+ psData.pbuf_data = psData.pbuf_data + sizeof(struct ipv6hdr) - sizeof(struct iphdr);
+ memcpy(psData.pbuf_data, ip_h, sizeof(struct iphdr));
+ psData.datalen = psData.datalen - sizeof(struct ipv6hdr) + sizeof(struct iphdr);
+ }
+ }
+ }
+
skb = skb_build_psbuf(&psData);
if (!skb)
@@ -369,7 +455,7 @@
int err;
struct psnet *dev;
struct net_device *net;
-
+ g_set_xlat_cb = psnet_set_xlat;
dbg("ddr_ap_net_lan_init.\n");
err = -ENOMEM;
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/tun.c b/ap/os/linux/linux-3.4.x/drivers/net/tun.c
old mode 100644
new mode 100755
index 8e8b74e..3309fc9
--- a/ap/os/linux/linux-3.4.x/drivers/net/tun.c
+++ b/ap/os/linux/linux-3.4.x/drivers/net/tun.c
@@ -603,7 +603,7 @@
return skb;
}
-
+extern int (*fast_from_softirq) (struct sk_buff *skb);
/* Get packet from user space buffer */
static ssize_t tun_get_user(struct tun_struct *tun,
const struct iovec *iv, size_t count,
@@ -733,7 +733,12 @@
skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY;
skb_shinfo(skb)->gso_segs = 0;
}
-
+ if (fast_from_softirq && fast_from_softirq(skb))
+ {
+ tun->dev->stats.rx_packets++;
+ tun->dev->stats.rx_bytes += len;
+ return count;
+ }
netif_rx_ni(skb);
tun->dev->stats.rx_packets++;