zte's code,first commit
Change-Id: I9a04da59e459a9bc0d67f101f700d9d7dc8d681b
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/psnet/Kconfig b/ap/os/linux/linux-3.4.x/drivers/net/psnet/Kconfig
new file mode 100644
index 0000000..b058eae
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/psnet/Kconfig
@@ -0,0 +1,7 @@
+#
+# Appletalk driver configuration
+#
+config PS_NET
+ tristate "ZTE AP LAN AND WAN"
+ default y
+
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/psnet/Makefile b/ap/os/linux/linux-3.4.x/drivers/net/psnet/Makefile
new file mode 100644
index 0000000..53c6333
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/psnet/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the Linux Wireless network device drivers.
+#
+
+obj-y += psnet_dev.o psnet_io.o
+
+ccflags-y += -I$(TOPDIR)/cp/ps/modem/com/inc
\ No newline at end of file
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/psnet/psnet.h b/ap/os/linux/linux-3.4.x/drivers/net/psnet/psnet.h
new file mode 100644
index 0000000..98bcfb7
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/psnet/psnet.h
@@ -0,0 +1,97 @@
+#ifndef _PSNET_H_
+#define _PSNET_H_
+
+#include <linux/interrupt.h>
+
+#include <linux/netdevice.h>
+
+#include <linux/kthread.h>
+
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/semaphore.h>
+//#include "psnet.h"
+
+#ifdef dbg
+#undef dbg
+#endif
+#if PSNET_DEBUG
+#define dbg(format, arg...) printk(KERN_DEBUG " psnet.c<%s>: " format "\n" , \
+ __func__ , ## arg)
+#else
+#define dbg(format, arg...) do {} while (0)
+#endif
+
+#ifdef err
+#undef err
+#endif
+#define err(format, arg...) printk(KERN_ERR " psnet.c<%s>: " format "\n" , \
+ __func__ , ## arg)
+
+#ifdef warn
+#undef warn
+#endif
+#define warn(format, arg...) printk(KERN_WARNING " psnet.c<%s>: " format "\n" , \
+ __func__ , ## arg)
+
+#ifdef info
+#undef info
+#endif
+#define info(format, arg...) printk(KERN_ERR " psnet.c<%s>: " format "\n" , \
+ __func__ , ## arg)
+
+
+#define NET_LAN 0x10
+#define NET_WAN 0x11
+typedef (*functpye1)(unsigned int);
+typedef (*functpye2)(unsigned int, void*, unsigned int);
+
+struct psnet_msg
+{
+ void *buf;
+ unsigned int len;
+ u32 protocol;
+};
+
+struct psnet {
+ struct net_device *net;
+ //void* IOhandle;
+ int initflag;
+ /*lan0 or wan0*/
+ unsigned char lan;
+ unsigned int index;
+ //struct sk_buff_head txq;
+ struct sk_buff_head rxq;
+ //struct semaphore skb_que_sem;
+ //struct tasklet_struct rx_bh;
+ struct task_struct* rcv_thread;
+ //struct completion rcv_completion;
+ //wait_queue_head_t waitqueue;
+ void (*channelOpen)(unsigned int chid);
+ void (*channelClose)(unsigned int chid);
+ int (*transdataOut)(unsigned int channel, void* buff, unsigned int length);
+};
+
+enum{
+ DDR_DEV_WAN1 = 0,
+ DDR_DEV_WAN2,
+ DDR_DEV_WAN3,
+ DDR_DEV_WAN4,
+ DDR_DEV_WAN5,
+ DDR_DEV_WAN6,
+ DDR_DEV_WAN7,
+ DDR_DEV_WAN8,
+ DDR_DEV_MAX,
+
+};
+void psnet_recv_notify(unsigned int index, const void *buffer, unsigned int length);
+int psnet_registerOpsCallback(unsigned int chID, functpye1* funcOpen, functpye1* funcClose, functpye2* funcOut);
+
+#if 0
+#ifdef USE_PSNET_PACKET
+s32 psnet_skb_xmit_thread(void * __dev);
+#endif
+int psnet_rx_packet(struct net_device *net, struct psnet_msg *psMsg);
+#endif
+#endif /* _PSNET_H_ */
+
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
new file mode 100755
index 0000000..ad98163
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/psnet/psnet_dev.c
@@ -0,0 +1,487 @@
+#include <linux/module.h>
+#include <linux/etherdevice.h>
+
+#include <net/SI/ext_mem.h>
+
+#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*/
+
+static unsigned int ddr_net_collect[DDR_DEV_MAX][2]= {
+ {DDR_DEV_WAN1, NET_WAN},
+ {DDR_DEV_WAN2, NET_WAN},
+ {DDR_DEV_WAN3, NET_WAN},
+ {DDR_DEV_WAN4, NET_WAN},
+ {DDR_DEV_WAN5, NET_WAN},
+ {DDR_DEV_WAN6, NET_WAN},
+ {DDR_DEV_WAN7, NET_WAN},
+ {DDR_DEV_WAN8, NET_WAN}
+};
+
+//int *vir_addr_ddrnet = ZX_DDR_PSBUF_BASE;
+int *vir_addr_ddrnet = 0;
+EXPORT_SYMBOL(vir_addr_ddrnet);
+
+static struct net_device *psnet_dev[DDR_DEV_MAX];
+
+struct psnet *global_psnet[DDR_DEV_MAX];
+
+extern int (*fast_from_driver)(struct sk_buff *skb, struct net_device* dev);
+
+static psnet_receive_thread(unsigned long param)
+{
+ struct psnet *dev = (struct psnet *)param;
+ struct sk_buff *skb;
+ int status;
+
+ struct sched_param sch_param = { .sched_priority = 1 };
+ sch_param.sched_priority = 37;
+ sched_setscheduler(current, SCHED_FIFO, &sch_param);
+
+ while(1) {
+
+ if (dev->rxq.qlen == 0)
+ {
+ // avoid to continue calling wake_up_process() when cmd_thread is NULL
+ //set_bit(WAKE_EVENT_CMD, &pshare->wake_event);
+ //DECLARE_WAITQUEUE(wait, current);
+ //add_wait_queue(&dev->waitqueue, &wait);
+ set_current_state(TASK_KILLABLE);
+ //printk("[%s] is closed (%d)\n",dev->net->name, dev->bOpen);
+ schedule();
+ set_current_state(TASK_RUNNING);
+ //remove_wait_queue(&dev->waitqueue, &wait);
+ continue;
+ }
+ skb = skb_dequeue(&dev->rxq);
+ //TO DO read data from ps and trans to skb data
+
+ if (skb && skb->len)
+ {
+ skb->protocol = eth_type_trans (skb, dev->net);
+
+ status = netif_rx (skb);
+ if (status == NET_RX_SUCCESS) {
+ dev->net->stats.rx_packets++;
+ dev->net->stats.rx_bytes += skb->len;
+ } else {
+ dev->net->stats.rx_errors++;
+ err("netif_rx status %d.", status);
+ }
+ }
+ else {
+ dev->net->stats.rx_errors++;
+
+ dev_kfree_skb (skb);
+ err("drop!!!psnet_bh skb len == 0.");
+ }
+ }
+}
+
+static int psnet_open(struct net_device *net)
+{
+ //int retval;
+ struct psnet *dev = netdev_priv(net);
+ if(dev->initflag != 1)
+ return 0;
+ info("psnet_open %s", dev->net->name);
+
+ if(net->flags & IFF_UP) {
+ dbg("the %s has been opened!", dev->net->name);
+ return -EBUSY;
+ }
+ if(dev->rcv_thread == NULL)
+ dev->rcv_thread = kthread_run(psnet_receive_thread, dev, "psnet-thread/%s", dev->net->name);
+ else
+ wake_up_process(dev->rcv_thread);
+ netif_start_queue (net);
+ dev->channelOpen(dev->index);
+ dev->initflag = 2;
+ return 0;
+}
+
+static int psnet_close(struct net_device *net)
+{
+ struct psnet *dev = netdev_priv(net);
+ if(dev->initflag != 2)
+ return 0;
+ info("psnet_close");
+ netif_stop_queue(net);
+ dev->channelClose(dev->index);
+ //tasklet_kill (&dev->rx_bh);
+ dev->initflag = 1;
+ return 0;
+}
+extern unsigned long skb_max_panic;
+extern atomic_t skb_used;
+extern atomic_t skb_tops;
+extern atomic_t skb_fromps;
+/* Called by the kernel in order to transmit a packet. */
+static netdev_tx_t psnet_xmit(struct sk_buff *skb, struct net_device *net)
+{
+ unsigned int length;
+ unsigned char *psbuff;
+ struct psnet *dev = netdev_priv(net);
+ int retval = 0;
+
+ if (!skb) {
+ panic("skb err!!!!");
+ }
+ if(skb_max_panic && (atomic_read(&skb_tops) > skb_max_panic))
+ {
+ kfree_skb(skb);
+ //printk("skb=%d tops fail tops=%d fromps=%d\n",atomic_read(&skb_used),atomic_read(&skb_tops),atomic_read(&skb_fromps));
+ net->stats.tx_dropped++;
+ return NET_XMIT_SUCCESS;
+ }
+ //Æ«ÒÆÖÁipÍ·
+ skb_pull(skb, ETH_HLEN);
+
+ //Ë¢ÐÂcache
+ skb = flush_skbuf(skb);
+ if (!skb) {
+ panic("skb err!!!!");
+ return NET_XMIT_SUCCESS;
+ }
+ insert_toext_mem(skb);
+
+ //TODO convert data to psbuf, wirte data to ps
+ length = skb->len;
+ retval = dev->transdataOut(dev->index, skb, length);
+ if (retval == 0) {
+ net->trans_start = jiffies;
+ net->stats.tx_packets++;
+ net->stats.tx_bytes += length;
+ return NET_XMIT_SUCCESS;
+ } else {
+ printk("write err, ret : %d!!!!", retval);
+// dev_kfree_skb(skb);
+ free_toext_mem(skb);
+ net->stats.tx_errors++;
+ return NET_XMIT_SUCCESS;
+ }
+
+}
+#if 0
+static void psnet_rx_bh (unsigned long param)
+{
+ struct psnet *dev = (struct psnet *)param;
+ struct sk_buff *skb;
+ int status;
+ while(skb = skb_dequeue(&dev->rxq)) {
+ if (skb->len)
+ {
+ skb->protocol = eth_type_trans (skb, dev->net);
+
+ status = netif_rx (skb);
+ if (status == NET_RX_SUCCESS) {
+ dev->net->stats.rx_packets++;
+ dev->net->stats.rx_bytes += skb->len;
+ } else {
+ dev->net->stats.rx_errors++;
+ err("netif_rx status %d.", status);
+ }
+ }
+ else {
+ dev->net->stats.rx_errors++;
+
+ dev_kfree_skb (skb);
+ err("drop!!!psnet_bh skb len == 0.");
+ }
+ }
+}
+#endif
+
+/* Called by the kernel when transmit times out */
+static void psnet_tx_timeout(struct net_device *net)
+{
+ err("sent timeout!");
+ net->stats.tx_errors++;
+ 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)
+{
+ struct sk_buff *skb;
+ struct psnet *dev = (struct psnet *)global_psnet[index];
+ struct T_FromExt_mem psData = { 0 };
+
+ psData.pbuf_data = (void *)buffer;
+#if 0
+#ifdef USE_CPPS_KO
+ psData.pbuf_head = (void *)cpps_callbacks.zGetpsbufferHead(buffer);
+#else
+ psData.pbuf_head = (void *)zGetpsbufferHead(buffer);
+#endif
+#else
+ 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)
+ {
+ //err("psnet_recv_notify can not allocate skb. drop the package");
+ dev->net->stats.rx_dropped++;
+ }
+ else
+ {
+ skb_push(skb, ETH_HLEN);
+
+ if (set_protocol_by_version(skb) < 0)
+ return;
+
+ if (fast_from_driver && fast_from_driver(skb, dev->net))
+ {
+ return;
+ }
+
+ memcpy(skb->data, dev->net->dev_addr, ETH_ALEN);
+ memcpy(skb->data + ETH_ALEN, dev->net->dev_addr, ETH_ALEN);
+
+ skb_queue_tail(&dev->rxq, skb);
+ wake_up_process(dev->rcv_thread);
+ }
+
+}
+
+static struct net_device_stats *psnet_get_stats(struct net_device *net)
+{
+// dbg("%s: request for stats\n", net->name);
+ return &net->stats;
+}
+
+const struct net_device_ops psnet_netdev_ops = {
+ .ndo_open = psnet_open,
+ .ndo_stop = psnet_close,
+ .ndo_start_xmit = psnet_xmit,
+ .ndo_tx_timeout = psnet_tx_timeout,
+ .ndo_get_stats = psnet_get_stats,
+};
+int psnet_registerOpsCallback(unsigned int chID, functpye1* funcOpen, functpye1* funcClose, functpye2* funcOut)
+{
+ int nRet = -1;
+ struct psnet *dev = global_psnet[chID];
+ if(funcOpen && funcClose && funcOut)
+ {
+ dev->channelOpen = funcOpen;
+ dev->channelClose = funcClose;
+ //rpmsg_channel->transdatatoRpmsg = funcIn;
+ dev->transdataOut = funcOut;
+ dev->initflag = 1;
+ nRet = 0;
+ }
+ return nRet;
+}
+
+static inline void psnet_init_netdev(struct net_device *net)
+{
+ //memset(net->dev_addr, 0xfe, ETH_ALEN);
+#if 0
+ u8 mac[ETH_ALEN] = {0x0, 0xa0, 0xc6, 0x11, 0x22, 0x33};
+ memcpy(net->dev_addr, mac, ETH_ALEN);
+#else
+ // randomly generated ethernet address
+ static u8 node_id [ETH_ALEN];
+ random_ether_addr(node_id);
+ memcpy (net->dev_addr, node_id, sizeof node_id);
+#endif
+ net->netdev_ops = &psnet_netdev_ops;
+ net->watchdog_timeo = WATCHDOG_TIMEO;
+ net->flags |= IFF_NOARP;
+}
+static inline void psnet_init_lan(struct net_device *net, unsigned int index)
+{
+ struct psnet *dev;
+ dev = netdev_priv(net);
+ dev->net = net;
+ //strcpy(net->name, "lan%d");
+ sprintf(net->name, "ps%d", index+1);
+ dev->lan = 1;
+ skb_queue_head_init (&dev->rxq);
+}
+
+static inline void psnet_init_wan(struct net_device *net, unsigned int index)
+{
+ struct psnet *dev;
+ //unsigned wan_index;
+ dev = netdev_priv(net);
+ dev->net = net;
+ sprintf(net->name, "wan%d", index+1);// WAN1, WAN2,....
+ dev->lan = 0;
+ skb_queue_head_init (&dev->rxq);
+}
+
+
+static int __init psnet_init(void)
+{
+ int i;
+ 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;
+ for (i = 0; i < DDR_DEV_MAX; i++){
+ //for (i = 0; i < 1; i++) {
+ net = alloc_etherdev(sizeof(struct psnet));
+ if (!net) {
+ printk(KERN_ERR "could not allocate device.\n");
+ return err;
+ }
+
+ //È·±£ËùÓз¢Íùcp²àµÄÊý¾ÝÍ·²¿Ô¤Áô×ã¹»£¬±ÜÃâË¢cacheµÄʱºòÖØÐÂÉêÇëskb
+ net->needed_headroom += NET_SKB_PAD - ETH_HLEN;
+
+ dev = netdev_priv(net);
+ global_psnet[i] = dev;
+
+ if(ddr_net_collect[i][1] == NET_LAN)
+ {
+ printk("NET_LAN :%d\n",i);
+ psnet_init_lan(net, i);
+ }
+ else if (ddr_net_collect[i][1] == NET_WAN)
+ {
+ psnet_init_wan(net, i);
+ printk("NET_WAN :%d\n",i);
+ }
+ else
+ {
+ printk("NET_error :%d\n",i);
+ goto out_free_netdev;
+ }
+ dev->index = i;
+ dev->net = net;
+ //dev->rx_bh.func = psnet_rx_bh;
+ //dev->rx_bh.data = (unsigned long) dev;
+ //sema_init(&dev->skb_que_sem,1);
+ //init_waitqueue_head(&dev->waitqueue);
+ //init_completion(&dev->rcv_completion);
+ psnet_init_netdev(net);
+ err = register_netdev(net);
+ printk("register_netdev error:%d :%d\n",err,i);
+ if (err)
+ goto out_free_netdev;
+ psnet_dev[i] = net;
+// psnet_start(net);
+ }
+
+ return 0;
+
+out_free_netdev:
+ free_netdev(net);
+ return err;
+}
+late_initcall(psnet_init);
+
+static void __exit psnet_exit(void)
+{
+ int i;
+ struct net_device *net;
+
+ for (i = 0; i < DDR_DEV_MAX; i++) {
+ if ((net = psnet_dev[i])) {
+ unregister_netdev(net);
+ free_netdev(net);
+ psnet_dev[i] = NULL;
+ }
+ }
+}
+module_exit(psnet_exit);
+
+MODULE_AUTHOR("P96G");
+MODULE_DESCRIPTION("7510 AP Lan Net Device");
+MODULE_LICENSE("GPL");
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/psnet/psnet_io.c b/ap/os/linux/linux-3.4.x/drivers/net/psnet/psnet_io.c
new file mode 100755
index 0000000..bef6240
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/psnet/psnet_io.c
@@ -0,0 +1,400 @@
+#define NEW_PS_BUF
+#include <linux/module.h>
+#include "psnet.h"
+#include "psnet_io.h"
+#include <linux/cp_types.h>
+#include <linux/soc/zte/rpm/rpmsg_sim.h>
+#include "zpsi_api.h"
+#include <linux/if_addr.h>
+#include <linux/if_arp.h>
+#include <linux/ipv6.h>
+#include <linux/icmpv6.h>
+#include <net/ipv6.h>
+#include <net/protocol.h>
+#include <net/ndisc.h>
+
+extern struct psnet *global_psnet[DDR_DEV_MAX];
+
+#define ZATI2_DATA_CHANNEL_ID_NUM_START (CHANNEL_AP2PS_MAXID)//+1
+#define PSNET_IO_SUCCESS 0
+#define PSNET_IO_ERROR 1
+//×Ö½Ú¶ÔÆë¶ÏÑÔ
+#define MAC4BYTE_ASSERT 4
+#define MAC2BYTE_ASSERT 2
+
+#define ZATI2_SUCCESS 0
+#define ZATI2_ERROR 1
+
+typedef struct _PS_CHID_INFO{
+ unsigned int chid;
+ unsigned int stat;
+} PS_CHID_INFO;
+
+static PS_CHID_INFO s_pschid_info[DDR_DEV_MAX] = {
+ {ZATI2_DATA_CHANNEL_ID_NUM_START + 0, 0},
+ {ZATI2_DATA_CHANNEL_ID_NUM_START + 1, 0},
+ {ZATI2_DATA_CHANNEL_ID_NUM_START + 2, 0},
+ {ZATI2_DATA_CHANNEL_ID_NUM_START + 3, 0},
+ {ZATI2_DATA_CHANNEL_ID_NUM_START + 4, 0},
+ {ZATI2_DATA_CHANNEL_ID_NUM_START + 5, 0},
+ {ZATI2_DATA_CHANNEL_ID_NUM_START + 6, 0},
+ {ZATI2_DATA_CHANNEL_ID_NUM_START + 7, 0}
+};
+extern PBYTE zPutSkb2Psbuf(PBYTE pbIpData, WORD wIpDataLen, PBYTE pbPdcpPduAddr, PBYTE pbSkbAddr);
+extern WORD zGetUpLinkSduSize(VOID);
+enum ip_ver {
+ IP_V4,
+ IP_V6,
+ MAX_IP_VER
+};
+
+extern VOID zFreeDlBuf(PBYTE pBuf);
+
+struct nd_opt_prefix_info /* prefix information */
+{
+ uint8_t nd_opt_pi_type;
+ uint8_t nd_opt_pi_len;
+ uint8_t nd_opt_pi_prefix_len;
+ uint8_t nd_opt_pi_flags_reserved;
+ uint32_t nd_opt_pi_valid_time;
+ uint32_t nd_opt_pi_preferred_time;
+ uint32_t nd_opt_pi_reserved2;
+ struct in6_addr nd_opt_pi_prefix;
+};
+
+struct psnet_RA_info
+{
+ unsigned int flag;
+ struct in6_addr prefix;
+ unsigned char prefix_len;
+ unsigned char ext_cid;
+ struct semaphore sem;
+};
+typedef void (*set_pdp_state_CB)(unsigned char cid, unsigned int state);
+typedef int (*get_ipv6_prefix_CB)(unsigned char cid, int len, unsigned char *prefix, unsigned char *prefix_len);
+extern set_pdp_state_CB g_psnet_set_RA_state;
+extern get_ipv6_prefix_CB g_psnet_get_prefix;
+extern int zAti2_IsExCid(unsigned char cid, unsigned char *pcid);
+struct psnet_RA_info g_psnet_ipv6_prefix[DDR_DEV_MAX] = {0};
+
+void psnet_parse_RA_pkt(unsigned char cid, unsigned char* pkt, int len)
+{
+ //warn("cid=%d flag=%d\n", cid, g_psnet_ipv6_prefix[cid-1].flag);
+ if(likely(g_psnet_ipv6_prefix[cid-1].flag))
+ return;
+
+ if ((pkt[0] & 0xF0) == 0x60 && len >= (sizeof(struct ipv6hdr) + sizeof(struct ra_msg) + sizeof(struct nd_opt_prefix_info))){
+ struct ipv6hdr *ip6h = (struct ipv6hdr *)pkt;
+ unsigned char nexthdr = ip6h->nexthdr;
+ unsigned char *hp = pkt + sizeof(struct ipv6hdr);
+ warn("cid=%d nexthdr=%d data=%d\n", cid,nexthdr,(*hp));
+ while((nexthdr == NEXTHDR_HOP)||(nexthdr == NEXTHDR_ROUTING)|| (nexthdr == NEXTHDR_DEST)){
+ nexthdr = *hp;
+ hp = hp + ipv6_optlen((struct ipv6_opt_hdr *)hp);
+ }
+ if(nexthdr == IPPROTO_ICMPV6 && (*hp) == NDISC_ROUTER_ADVERTISEMENT){
+ struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)(hp + sizeof(struct ra_msg));
+ int opt_len = len - sizeof(struct ipv6hdr) - sizeof(struct ra_msg);
+ while (opt_len) {
+ int l;
+ if (opt_len < sizeof(struct nd_opt_hdr))
+ return;
+ l = nd_opt->nd_opt_len << 3;
+ if (opt_len < l || l == 0)
+ return;
+ if((nd_opt->nd_opt_type) == ND_OPT_PREFIX_INFO){
+ struct nd_opt_prefix_info *pinfo = (struct nd_opt_prefix_info *)nd_opt;
+ unsigned char ext_cid = 0;
+#ifdef USE_CPPS_KO
+ cpps_callbacks.zAti2_IsExCid(cid, &ext_cid);
+#else
+ zAti2_IsExCid(cid, &ext_cid);
+#endif
+ if(ext_cid){
+ g_psnet_ipv6_prefix[cid-1].flag = 2;
+ g_psnet_ipv6_prefix[cid-1].ext_cid = ext_cid;
+ g_psnet_ipv6_prefix[ext_cid-1].ext_cid = cid;
+ }else{
+ ext_cid = cid;
+ }
+ memcpy(&g_psnet_ipv6_prefix[ext_cid-1].prefix, &pinfo->nd_opt_pi_prefix, sizeof(struct in6_addr));
+ g_psnet_ipv6_prefix[ext_cid-1].prefix_len = pinfo->nd_opt_pi_prefix_len;
+ g_psnet_ipv6_prefix[ext_cid-1].flag = 1;
+ up(&g_psnet_ipv6_prefix[ext_cid-1].sem);
+ warn("cid=%d prefix_len=%d\n", ext_cid, pinfo->nd_opt_pi_prefix_len);
+ return;
+ }
+ opt_len -= l;
+ nd_opt = ((void *)nd_opt) + l;
+ }
+ }
+ }
+}
+
+void psnet_set_RA_state(unsigned char cid, unsigned int flag)
+{
+ if(cid > 0 && cid <= DDR_DEV_MAX){
+ unsigned char ext_cid = g_psnet_ipv6_prefix[cid-1].ext_cid;
+ warn("cid=%d flag=%d cur_flg=%d ext=%d\n", cid, flag, g_psnet_ipv6_prefix[cid-1].flag, ext_cid);
+ if(flag == 0 && ext_cid > 0 && ext_cid <= DDR_DEV_MAX){
+ warn("ext cid=%d cur_flg=%d ext=%d\n", ext_cid,
+ g_psnet_ipv6_prefix[ext_cid-1].flag, g_psnet_ipv6_prefix[ext_cid-1].ext_cid);
+ if(g_psnet_ipv6_prefix[cid-1].flag == 1){
+ g_psnet_ipv6_prefix[ext_cid-1].flag = 0;
+ }
+ g_psnet_ipv6_prefix[ext_cid-1].ext_cid = 0;
+ g_psnet_ipv6_prefix[cid-1].ext_cid = 0;
+ }
+ g_psnet_ipv6_prefix[cid-1].flag = flag;
+ if(flag == 0){
+ int ret = down_trylock(&g_psnet_ipv6_prefix[cid-1].sem);
+ if(ret != 0)//cov
+ warn("cid=%d down_trylock ret=%d\n", cid, ret);
+ }
+ return;
+ }
+ err("err cid=%d flag=%d \n", cid, flag);
+}
+
+int psnet_get_prefix(unsigned char cid, int len, unsigned char *prefix, unsigned char *prefix_len)
+{
+ if(cid > 0 && cid <= DDR_DEV_MAX){
+ if(g_psnet_ipv6_prefix[cid-1].flag == 0){
+ int ret = down_timeout(&g_psnet_ipv6_prefix[cid-1].sem, 3*HZ);
+ if(ret != 0)//cov
+ err("err ipv6_prefix down_timeout ret=%d\n", ret);
+ }
+ if(g_psnet_ipv6_prefix[cid-1].flag == 1
+ && len > (((g_psnet_ipv6_prefix[cid-1].prefix_len/8+1)/2) * 5)){
+ int i = 0;
+ unsigned char* prefix_str = prefix;
+ int prefix_temp = g_psnet_ipv6_prefix[cid-1].prefix_len/8;
+
+ for (i = 0; i < prefix_temp; i++) {
+ sprintf(prefix_str + strlen(prefix_str), "%02x", g_psnet_ipv6_prefix[cid-1].prefix.s6_addr[i]);
+ if (i % 2 == 1)
+ sprintf(prefix_str + strlen(prefix_str), "%s", ":");
+ }
+ warn("cid=%d len=%d plen=%d prefix=%s\n", cid, len, g_psnet_ipv6_prefix[cid-1].prefix_len, prefix);
+ *prefix_len = g_psnet_ipv6_prefix[cid-1].prefix_len;
+ return strlen(prefix)+1;
+ }
+ err("err flag=%d pflen=%d \n", g_psnet_ipv6_prefix[cid-1].flag, g_psnet_ipv6_prefix[cid-1].prefix_len);
+ }
+ err("err cid=%d len=%d \n", cid, len);
+ return 0;
+}
+
+void psnet_freepsbuf(void *head)
+{
+#ifdef USE_CPPS_KO
+ cpps_callbacks.zFreeDlBuf(head);
+#else
+ zFreeDlBuf(head);
+#endif
+}
+
+unsigned int psnet_get_pschid_stat(unsigned int chid)
+{
+ unsigned int index = chid - ZATI2_DATA_CHANNEL_ID_NUM_START;
+ return s_pschid_info[index].stat;
+}
+void psnet_set_pschid_stat(unsigned int chid, unsigned int newstat)
+{
+ unsigned int index = chid - ZATI2_DATA_CHANNEL_ID_NUM_START;
+ s_pschid_info[index].stat = newstat;
+}
+
+static int psnet_write(struct sk_buff *skb, unsigned long data_len, unsigned char ip_type, int ch_id)
+{
+ int ret = 1;
+ unsigned char * pdata = skb->data;
+ //µ¥ºËÖÐEL2Ïà¹ØDDR½øÐÐѹËõ£¬UL EPDCP NODEÓÉEL2½øÐйÜÀí£¬
+ //AP²»ÔÙ½øÐÐÉêÇ룬¸³ÖµºÍÊͷŹÜÀí
+ //unsigned char * pdcpDataAddr = skb->head;
+ unsigned char * pdcpDataAddr = NULL;
+#ifdef USE_CPPS_KO
+ PBYTE p_to_ps_packet = (PBYTE)cpps_callbacks.zPutSkb2Psbuf(pdata, data_len, pdcpDataAddr, skb);
+#else
+ PBYTE p_to_ps_packet = (PBYTE)zPutSkb2Psbuf(pdata, data_len, pdcpDataAddr, skb);
+#endif
+ if(p_to_ps_packet == NULL)
+ panic("get ulbufaddr error ");
+
+ //p_to_ps_packet->wIpPacketLen = (UINT16)(data_len);
+ //p_to_ps_packet->wIpPacketOffSet = (UINT16)(pdata - (UINT8 *)p_to_ps_packet->Data);
+
+ //printk("[ZJT] IPType =%d , skb->len = %d, ch_id = %d \r\n", ip_type, data_len, ch_id);
+#ifdef USE_CPPS_KO
+ WORD SduSize = cpps_callbacks.zGetUpLinkSduSize();
+#else
+ WORD SduSize = zGetUpLinkSduSize();
+#endif
+ if(0 == ip_type)
+#ifdef USE_CPPS_KO
+ ret = cpps_callbacks.zAti2_Send(ch_id, (UINT8*)p_to_ps_packet, SduSize, ZATI2_CHIND_PSD);
+#else
+ ret = zAti2_Send(ch_id, (UINT8*)p_to_ps_packet, SduSize, ZATI2_CHIND_PSD);
+#endif
+ else if(1 == ip_type)
+#ifdef USE_CPPS_KO
+ ret = cpps_callbacks.zAti2_Send(ch_id, (UINT8*)p_to_ps_packet, SduSize, ZATI2_CHIND_PSDV6);
+#else
+ ret = zAti2_Send(ch_id, (UINT8*)p_to_ps_packet, SduSize, ZATI2_CHIND_PSDV6);
+#endif
+ else
+ panic("send data with wrong ip_type ");
+
+ return (0-ret);
+}
+int open_flag[DDR_DEV_MAX] = {0};
+int psnet_IOOpen(unsigned int index)
+{
+ int chid;
+ int ret;
+ char pStr[20] = {0};
+
+ if(index >= DDR_DEV_MAX)
+ {
+ err("%s: chid [%d] is illegal \n", __func__, index);
+ return PSNET_IO_ERROR;
+ }
+
+ chid = s_pschid_info[index].chid;
+ if(0 == open_flag[index])
+ {
+#ifdef USE_CPPS_KO
+ ret = cpps_callbacks.zAti2_Open(chid);
+#else
+ ret = zAti2_Open(chid);
+#endif
+ if(ret != ZATI2_SUCCESS)
+ {
+ panic("open chid failed");
+ }
+ open_flag[index]=1;
+ }
+
+ //·¢ËÍZGACT£¬½«µ±Ç°Í¨µÀÇÐΪÊý¾Ý̬£¬ºóÐøÒ»Ö±¶¼ÎªÊý¾Ý̬
+ sprintf((char *)pStr, "\r\nAT+ZGACT=1,%d\r\n",index+1);
+ //printk("[zjt] chid= %d, pStr =%s \n", chid, pStr);
+#ifdef USE_CPPS_KO
+ ret = cpps_callbacks.zAti2_Send(chid, pStr, strlen(pStr), ZATI2_CHIND_AT);
+#else
+ ret = zAti2_Send(chid, pStr, strlen(pStr), ZATI2_CHIND_AT);
+#endif
+ if(ret != 0)
+ {
+ err("send %s to %d failed!!!", pStr, chid);
+ }
+ return PSNET_IO_SUCCESS;
+}
+
+int psnet_IOClose(unsigned int index)
+{
+ int chid;
+
+ if(index >= DDR_DEV_MAX)
+ {
+ err("%s: dev index [%d] is illegal \n", __func__, index);
+ return PSNET_IO_ERROR;
+ }
+
+ chid = s_pschid_info[index].chid;
+ if(s_pschid_info[index].stat != 1)
+ {
+ err("%s: chid [%d] is already deact, please check !!! \n", __func__, chid);
+ return PSNET_IO_ERROR;
+ }
+
+ //·¢ËÍZGACT£¬½«µ±Ç°Í¨µÀÇÐΪAT̬£¬
+#ifdef USE_CPPS_KO
+ cpps_callbacks.zAti2_Send(chid, NULL, 0, ZATI2_CHIND_TURN_AT);
+#else
+ zAti2_Send(chid, NULL, 0, ZATI2_CHIND_TURN_AT);
+#endif
+ s_pschid_info[index].stat = 0;
+
+ return 0;
+}
+
+int psnet_transIPdataToPS(unsigned int index, struct sk_buff * skb, unsigned int length)
+{
+
+ unsigned long flags;
+ int chid;
+ int ret = 0;
+
+ unsigned char * buffer = skb->data;
+ if(index >= DDR_DEV_MAX)
+ {
+ err("%s: chid [%d] is illegal \n", __func__, index);
+ return PSNET_IO_ERROR;
+ }
+
+ if(buffer == NULL)//cov_2 || length < 0)
+ {
+ err("%s: Input data is not valid \n", __func__);
+ return PSNET_IO_ERROR;
+ }
+
+ chid = s_pschid_info[index].chid;
+
+ //if(!((unsigned long)buffer%MAC4BYTE_ASSERT != 0) || !((unsigned long)buffer % MAC2BYTE_ASSERT == 0))
+ // panic("wrong skb data");
+
+ if ((((unsigned)buffer[0]) & 0xF0) == 0x40 && (s_pschid_info[index].stat == 1))
+ {
+ ret = psnet_write(skb, length, IP_V4, chid);
+ }
+ else if ((((unsigned)buffer[0]) & 0xF0) == 0x60 && (s_pschid_info[index].stat == 1))
+ {
+ ret = psnet_write(skb, length, IP_V6, chid);
+ }
+ else
+ {
+ //err("%s:: IP type of data is wrong!!!", __func__);
+ return PSNET_IO_ERROR;
+ }
+
+ if(ret < 0)
+ {
+ //err("%s:: direct psnet_transIPdataToPS failed!!!\n", __func__);
+ return PSNET_IO_ERROR;
+ }
+
+ return 0;
+}
+int transdataToTCPIP(unsigned int chid, void *buffer, unsigned int length)
+{
+ int index = chid - ZATI2_DATA_CHANNEL_ID_NUM_START;
+ //truct psnet *dev = global_psnet[index];
+ psnet_recv_notify(index,buffer,length);
+ return 0;
+}
+
+int psnet_IOInit(void)
+{
+ int index;
+ for (index = 0; index < DDR_DEV_MAX; index++)
+ {
+ psnet_registerOpsCallback(index, psnet_IOOpen, psnet_IOClose, psnet_transIPdataToPS);
+ sema_init(&g_psnet_ipv6_prefix[index].sem, 0);
+ }
+ g_psnet_set_RA_state = psnet_set_RA_state;
+ g_psnet_get_prefix = psnet_get_prefix;
+ return 0;
+}
+
+int psnet_IOExit(void)
+{
+ return 0;
+}
+
+late_initcall(psnet_IOInit);
+module_exit(psnet_IOExit);
+
+MODULE_AUTHOR("ZTE");
+MODULE_DESCRIPTION("ZTE Lan Net Device");
+MODULE_LICENSE("GPL");
+
diff --git a/ap/os/linux/linux-3.4.x/drivers/net/psnet/psnet_io.h b/ap/os/linux/linux-3.4.x/drivers/net/psnet/psnet_io.h
new file mode 100644
index 0000000..992c80b
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/net/psnet/psnet_io.h
@@ -0,0 +1,15 @@
+
+#ifndef PSNETIO_H
+#define PSNETIO_H
+#include <net/SI/ext_mem.h>
+//#include <linux/module.h>
+
+
+int psnet_IOOpen(unsigned int index);
+int psnet_IOClose(unsigned int index);
+int psnet_transIPdataToPS(unsigned int index, struct sk_buff *skb, unsigned int length);
+int transdataToTCPIP(unsigned int index, void *buffer, unsigned int length);
+
+
+#endif //PSNETIO_H
+