#include #include #include #include #include #include #include #include #include #include #if defined(__MBED__) || defined(__CSKY__) #include "lib/umac2/umac.h" #else #include "../hgic_def.h" #endif #define NOTIFY_BLOCK_CNT 4 struct netdev_mgr { u8 if_index; //only support two interface. struct mutex netdev_mutex; struct list_head netdev_list; struct notifier_block *net_notifier[NOTIFY_BLOCK_CNT]; } _netdev_mgr; extern void sys_memcpy(void *dest, void *src, int len); extern void sys_netif_recv(void *priv, char *data, int len,void *buff_priv); extern void *sys_netif_register(void *dev, char *name); extern int sys_netif_unregister(void *priv); static void call_netdevice_notifiers(unsigned long action, void *data) { int i = 0; for (i = 0; i < NOTIFY_BLOCK_CNT; i++) { if (_netdev_mgr.net_notifier[i]) { _netdev_mgr.net_notifier[i]->notifier_call(0, action, data); } } } int register_netdevice_notifier(const struct notifier_block *nb) { int i = 0; int f = -1; for (i = 0; i < NOTIFY_BLOCK_CNT; i++) { if (_netdev_mgr.net_notifier[i] == NULL && f == -1) { f = i; } else if (_netdev_mgr.net_notifier[i] == (struct notifier_block *)nb) { return 0; } } if (f != -1) { _netdev_mgr.net_notifier[f] = (struct notifier_block *)nb; } return (f == -1 ? -EOVERFLOW : 0); } int unregister_netdevice_notifier(const struct notifier_block *nb) { int i = 0; for (i = 0; i < NOTIFY_BLOCK_CNT; i++) { if (_netdev_mgr.net_notifier[i] == nb) { _netdev_mgr.net_notifier[i] = NULL; break; } } return 0; } int net_device_xmit(struct net_device *dev, char *data, int len) { struct net_device *ndev = dev; struct sk_buff *skb = alloc_skb(len + ndev->needed_headroom + 64 + ndev->needed_tailroom); if (skb) { skb_reserve(skb, ndev->needed_headroom); memcpy(skb->data, data, len); skb_put(skb, len); skb->dev = ndev; //PRINTF("xmit %p\n",skb); dev_queue_xmit(skb); //PRINTF("xmit %p done\n",skb); return len; } else { PRINTF("%s:Error!No memory!\n",__FUNCTION__); return -ENOMEM; } } int net_device_xmit_scatter(void *dev, void *scat_info,int count, int total_len) { struct net_device *ndev = dev; struct netdev_scatter_data *scat_data = NULL; struct sk_buff *skb = NULL; unsigned char *pdata = NULL; int len = 0; int i = 0; if(!scat_info) { PRINTF("%s,%d:Input param error!\n",__FUNCTION__,__LINE__); return -EINVAL; } scat_data = (struct netdev_scatter_data *)scat_info; skb = alloc_skb(total_len + ndev->needed_headroom + 64 + ndev->needed_tailroom); if (skb) { skb_reserve(skb, ndev->needed_headroom); pdata = skb->data; for (i = 0; i < count; i++) { memcpy(pdata,(unsigned char*)scat_data[i].addr,scat_data[i].size); pdata += scat_data[i].size; len += scat_data[i].size; } ASSERT(len == total_len); skb_put(skb, len); skb->dev = ndev; dev_queue_xmit(skb); return len; } else { PRINTF("%s:Error!No memory!\n",__FUNCTION__); return -ENOMEM; } } int net_device_get_addr(struct net_device *dev, char *addr) { if(dev == NULL || addr == NULL) { PRINTF("%s,%d:Input param error!\n",__FUNCTION__,__LINE__); return -1; } memcpy(addr, dev->dev_addr, 6); return 0; } int net_device_set_addr(struct net_device *dev, char *addr) { dev->netdev_ops->ndo_set_mac_address(dev, addr); return 0; } char **net_device_buff_alloc(struct net_device *dev, int len) { struct sk_buff *skb = alloc_skb(len + dev->needed_headroom + dev->needed_tailroom); if (skb) { skb_reserve(skb, dev->needed_headroom); return (char **)&skb->data; } return 0; } int net_device_buff_free(void *dev, char **buff) { struct sk_buff *skb = container_of(buff, struct sk_buff, data); kfree_skb(skb); return 0; } int net_device_buff_send(struct net_device *dev, char **buff, int len) { struct sk_buff *skb = container_of(buff, struct sk_buff, data); if (skb) { skb_put(skb, len); skb->dev = dev; dev_queue_xmit(skb); return 0; } return -ENOMEM; } static void netdev_recv_def(struct sk_buff *skb) { if (skb->dev && skb->dev->priv) { if (skb->dev->magic_num != NET_DEVICE_MAGIC_NUM) { while (1) { hgic_err("Invaild dev magic_num:%x\n", skb->dev->magic_num); } } sys_netif_recv(skb->dev->priv, skb->data, skb->len,skb->free_priv); } //skb->head = NULL; kfree_skb(skb); } int register_netdev(struct net_device *dev) { call_netdevice_notifiers(NETDEV_POST_INIT, dev); mutex_lock(&_netdev_mgr.netdev_mutex); list_add(&dev->list, &_netdev_mgr.netdev_list); mutex_unlock(&_netdev_mgr.netdev_mutex); call_netdevice_notifiers(NETDEV_REGISTER, dev); //dev->recv = netdev_recv_def; dev->magic_num = NET_DEVICE_MAGIC_NUM; dev->priv = sys_netif_register(dev, dev->name); return (dev->priv ? 0 : -EPERM); } void unregister_netdev(struct net_device *dev) { if (dev) { net_device_close(dev); call_netdevice_notifiers(NETDEV_UNREGISTER, dev); mutex_lock(&_netdev_mgr.netdev_mutex); list_del(&dev->list); mutex_unlock(&_netdev_mgr.netdev_mutex); sys_netif_unregister(dev->priv); kfree(dev); } } int dev_alloc_name(struct net_device *dev, char *name) { mutex_lock(&_netdev_mgr.netdev_mutex); dev->ifindex = (_netdev_mgr.if_index & 0x1) ? 1 : 0; _netdev_mgr.if_index |= (1 << _netdev_mgr.if_index); sprintf(dev->name, name, dev->ifindex); hgic_param_ifname(dev->name); mutex_unlock(&_netdev_mgr.netdev_mutex); return 0; } struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name, void (*setup)(struct net_device *dev), int txqs, int rxqs) { size_t alloc_size = 0; struct net_device *dev = NULL; struct net_device *p = NULL; alloc_size = sizeof(struct net_device); if (sizeof_priv) { /* ensure 32-byte alignment of private area */ alloc_size = ALIGN(alloc_size, NETDEV_ALIGN); alloc_size += sizeof_priv; } /* ensure 32-byte alignment of whole construct */ alloc_size += NETDEV_ALIGN - 1; dev = kzalloc(alloc_size, GFP_KERNEL); if (dev) { memset(dev, 0, sizeof_priv + sizeof(struct net_device)); setup(dev); dev_alloc_name(dev, (char *)name); } return dev; } int netif_ether_send(struct net_device *ndev, const u8 *dest, int proto, const u8 *data, int len) { struct ethhdr *ehdr = NULL; struct sk_buff *skb = NULL; skb = dev_alloc_skb(ndev->needed_headroom + ndev->needed_tailroom + sizeof(struct hgic_hdr) + sizeof(struct ethhdr) + len); if (skb) { skb_reserve(skb, ndev->needed_headroom + sizeof(struct hgic_hdr)); ehdr = (struct ethhdr *)skb->data; ehdr->h_proto = htons(proto); memcpy(ehdr->h_dest, dest, ETH_ALEN); memcpy(ehdr->h_source, ndev->dev_addr, ETH_ALEN); memcpy(ehdr + 1, data, len); skb->protocol = htons(proto); skb->dev = ndev; skb_put(skb, sizeof(struct ethhdr) + len); dev_queue_xmit(skb); } return 0; } int netif_receive_skb(struct sk_buff *skb) { //PRINTF("%s,%d:recv data packet,len:%d\n,", __FUNCTION__,__LINE__, skb->len); if (skb->dev && skb->dev->priv) { if (skb->dev->magic_num != NET_DEVICE_MAGIC_NUM) { while (1) { hgic_err("Invaild dev magic_num:%x\n", skb->dev->magic_num); } } sys_netif_recv(skb->dev->priv, skb->data, skb->len,skb->free_priv); } //skb->head = NULL; kfree_skb(skb); } void netif_receive_skb_list(struct list_head *head) { struct sk_buff *skb, *next; if (list_empty(head)){ return; } list_for_each_entry_safe(skb, next, head, list) { list_del(&skb->list); netif_receive_skb(skb); } } int eth_mac_addr(struct net_device *dev, char *addr) { if(!dev || !addr) { hgic_err("Input param error,dev:%p,addr:%p\n",dev,addr); return -EINVAL; } if (!is_valid_ether_addr((const u8 *)addr)) { return -EADDRNOTAVAIL; } //PRINTF("set addr:"MACSTR"\r\n", MAC2STR(addr)); memcpy(dev->dev_addr, addr, ETH_ALEN); return 0; } int if_nametoindex(const char *ifname) { struct net_device *dev = net_device_get_by_name(ifname); return (dev) ? (dev->ifindex) : 0; } int linux_get_ifhwaddr(int sock, const char *ifname, u8 *addr) { struct net_device *dev = net_device_get_by_name(ifname); if (dev) { memcpy(addr, dev->dev_addr, ETH_ALEN); //PRINTF("get addr:"MACSTR"\r\n", MAC2STR(addr)); return 0; } return -1; } int linux_set_ifhwaddr(int sock, const char *ifname, const u8 *addr) { return net_device_set_mac(ifname, (char *)addr); } struct net_device *net_device_get_by_index(int id) { struct net_device *pos, *dev = NULL; //mutex_lock(&netdev_mutex); list_for_each_entry(pos, &_netdev_mgr.netdev_list, list) { if (pos->ifindex == id) { dev = pos; break; } } //mutex_unlock(&netdev_mutex); return dev; } struct net_device *net_device_get_by_addr(char *addr) { struct net_device *pos, *dev = NULL; if (addr == NULL) { return dev; } //mutex_lock(&netdev_mutex); list_for_each_entry(pos, &_netdev_mgr.netdev_list, list) { if (memcmp(pos->dev_addr, addr, ETH_ALEN) == 0) { dev = pos; break; } } //mutex_unlock(&netdev_mutex); return dev; } struct net_device *net_device_get_by_name(const char *name) { struct net_device *pos, *dev = NULL; if (name == NULL) { return dev; } //mutex_lock(&netdev_mutex); list_for_each_entry(pos, &_netdev_mgr.netdev_list, list) { //PRINTF("%s:netdev %s in nedev_list, input name:%s\n",__FUNCTION__,pos->name, name); if (strcmp(pos->name, name) == 0) { dev = pos; break; } } //mutex_unlock(&netdev_mutex); if (!dev) { //PRINTF("%s:dev %s not find!\n", __FUNCTION__, name); } return dev; } int net_device_set_mac(const char *ifname, char *addr) { struct net_device *dev = net_device_get_by_name(ifname); if (dev) { return dev->netdev_ops->ndo_set_mac_address(dev, (void *)addr); } return -1; } int net_device_open(struct net_device *dev) { int err = -1; if (dev) { if (netif_running(dev)) { return 0; } call_netdevice_notifiers(NETDEV_PRE_UP, dev); err = dev->netdev_ops->ndo_open(dev); if (!err) { dev->flags |= IFF_RUNNING; call_netdevice_notifiers(NETDEV_UP, dev); } PRINTF("open net device:%s (err:%d)\r\n", dev->name, err); } else { PRINTF("Error,dev is NULL!\n"); } return err; } int net_device_close(struct net_device *dev) { int err = -1; if (dev) { if (!netif_running(dev)) { return 0; } call_netdevice_notifiers(NETDEV_GOING_DOWN, dev); err = dev->netdev_ops->ndo_stop(dev); dev->flags &= ~IFF_RUNNING; call_netdevice_notifiers(NETDEV_DOWN, dev); PRINTF("close net device:%s (err:%d)\r\n", dev->name, err); } return err; } void net_device_init(void) { INIT_LIST_HEAD(&_netdev_mgr.netdev_list); mutex_init(&_netdev_mgr.netdev_mutex); } void net_device_exit(void) { mutex_destroy(&_netdev_mgr.netdev_mutex); } static void net_device_state_change(struct net_device *dev, int evt_id, char *args, int len) { unsigned char *pstate = (unsigned char *)args; int event_id = 0; if(pstate == NULL || dev == NULL) { hgic_err("Input param error!\n"); return; } if(evt_id != HGIC_EVENT_STATE_CHG) { dev->event(dev->name, evt_id, args, len); return; } switch(*pstate) { case 9: //WPA_COMPLETED event_id = HGIC_EVENT_CONECTED; hgic_dbg("Connected,MAC:"MACSTR"\n",MAC2STR(pstate+1)); //memcpy(evt->mac_addr,(char *)(pstate + 1),6); dev->event(dev->name, event_id, args + 1, len - 1); break; case 0: //WPA_DISCONNECTED event_id = HGIC_EVENT_DISCONECTED; hgic_dbg("Disonnected,MAC:"MACSTR"\n",MAC2STR(pstate+1)); dev->event(dev->name, event_id, args + 1, len - 1); break; case 5: //WPA_ASSOCIATING event_id = HGIC_EVENT_CONECT_START; dev->event(dev->name, event_id, NULL, 0); break; default: event_id = *pstate; dev->event(dev->name, event_id, NULL, 0); break; } } void net_device_event(struct net_device *dev, int evt_id, char *args, int len) { int event = 0; if (dev && dev->event) { if(evt_id == HGIC_EVENT_STATE_CHG) { net_device_state_change(dev,evt_id,args,len); } else { dev->event(dev->name, evt_id, args, len); } } } int linux_set_iface_flags(int sock, const char *ifname, int up) { return up ? net_device_up(ifname) : net_device_down(ifname); } int linux_iface_up(int sock, char *ifname) { struct net_device *ndev = net_device_get_by_name(ifname); return ndev && netif_running(ndev); } int net_device_up(const char *ifname) { return net_device_open(net_device_get_by_name(ifname)); } int net_device_down(const char *ifname) { return net_device_close(net_device_get_by_name(ifname)); }