/*
* Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/etherdevice.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/udp.h>
#include <linux/in.h>
#include <linux/if_arp.h>
#include <linux/if_ether.h>
#include <linux/if_vlan.h>
#include <linux/in6.h>
#include <linux/tcp.h>
#include <linux/icmp.h>
#include <linux/icmpv6.h>
#include <linux/uaccess.h>
#include <net/ndisc.h>
#include "gdm_lte.h"
#include "netlink_k.h"
#include "hci.h"
#include "hci_packet.h"
#include "gdm_endian.h"
/*
* Netlink protocol number
*/
#define NETLINK_LTE 30
/*
* Default MTU Size
*/
#define DEFAULT_MTU_SIZE 1500
#define IP_VERSION_4 4
#define IP_VERSION_6 6
static struct {
int ref_cnt;
struct sock *sock;
} lte_event;
static struct device_type wwan_type = {
.name = "wwan",
};
static int gdm_lte_open(struct net_device *dev)
{
netif_start_queue(dev);
return 0;
}
static int gdm_lte_close(struct net_device *dev)
{
netif_stop_queue(dev);
return 0;
}
static int gdm_lte_set_config(struct net_device *dev, struct ifmap *map)
{
if (dev->flags & IFF_UP)
return -EBUSY;
return 0;
}
static void tx_complete(void *arg)
{
struct nic *nic = arg;
if (netif_queue_stopped(nic->netdev))
netif_wake_queue(nic->netdev);
}
static int gdm_lte_rx(struct sk_buff *skb, struct nic *nic, int nic_type)
{
int ret;
ret = netif_rx_ni(skb);
if (ret == NET_RX_DROP) {
nic->stats.rx_dropped++;
} else {
nic->stats.rx_packets++;
nic->stats.rx_bytes += skb->len + ETH_HLEN;
}
return 0;
}
static int gdm_lte_emulate_arp(struct sk_buff *skb_in, u32 nic_type)
{
struct nic *nic = netdev_priv(skb_in->dev);
struct sk_buff *skb_out;
struct ethhdr eth;
struct vlan_ethhdr vlan_eth;
struct arphdr *arp_in;
struct arphdr *arp_out;
struct arpdata {
u8 ar_sha[ETH_ALEN];
u8 ar_sip[4];
u8 ar_tha[ETH_ALEN];
u8 ar_tip[4];
};
struct arpdata *arp_data_in;
struct arpdata *arp_data_out;
u8 arp_temp[60];
void *mac_header_data;
u32 mac_header_len;
/* Format the mac header so that it can be put to skb */
if (ntohs(((struct ethhdr *)skb_in->data)->h_proto) == ETH_P_8021Q) {
memcpy(&vlan_eth, skb_in->data, sizeof(struct vlan_ethhdr));
mac_header_data = &vlan_eth;
mac_header_len = VLAN_ETH_HLEN;
} else {
memcpy(ð, skb_in->data, sizeof(struct ethhdr));
mac_header_data = ð
mac_header_len = ETH_HLEN;
}
/* Get the pointer of the original request */
arp_in = (struct arphdr *)(skb_in->data + mac_header_len);
arp_data_in = (struct arpdata *)(skb_in->data + mac_header_len +
sizeof(struct arphdr));
/* Get the pointer of the outgoing response */
arp_out = (struct arphdr *)arp_temp;
arp_data_out = (struct arpdata *)(arp_temp + sizeof(struct arphdr));
/* Copy the arp header */
memcpy(arp_out, arp_in, sizeof(struct arphdr));
arp_out->ar_op = htons(ARPOP_REPLY);
/* Copy the arp payload: based on 2 bytes of mac and fill the IP */
arp_data_out->ar_sha[0] = arp_data_in->ar_sha[0];
arp_data_out->ar_sha[1] = arp_data_in->ar_sha[1];
memcpy(&arp_data_out->ar_sha[2], &arp_data_in->ar_tip[0], 4);
memcpy(&arp_data_out->ar_sip[0], &arp_data_in->ar_tip[0], 4);
memcpy(&arp_data_out->ar_tha[0], &arp_data_in->ar_sha[0], 6);
memcpy(&arp_data_out->ar_tip[0], &arp_data_in->ar_sip[0], 4);
/* Fill the destination mac with source mac of the received packet */
memcpy(mac_header_data, mac_header_data + ETH_ALEN, ETH_ALEN);
/* Fill the source mac with nic's source mac */
memcpy(mac_header_data + ETH_ALEN, nic->src_mac_addr, ETH_ALEN);
/* Alloc skb and reserve align */
skb_out = dev_alloc_skb(skb_in->len);