📄 network.c
字号:
/* * * arch/xtensa/platform-iss/network.c * * Platform specific initialization. * * Authors: Chris Zankel <chris@zankel.net> * Based on work form the UML team. * * Copyright 2005 Tensilica Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * */#include <linux/config.h>#include <linux/list.h>#include <linux/irq.h>#include <linux/spinlock.h>#include <linux/slab.h>#include <linux/timer.h>#include <linux/if_ether.h>#include <linux/inetdevice.h>#include <linux/init.h>#include <linux/if_tun.h>#include <linux/etherdevice.h>#include <linux/interrupt.h>#include <linux/ioctl.h>#include <linux/bootmem.h>#include <linux/ethtool.h>#include <linux/rtnetlink.h>#include <linux/timer.h>#include <linux/platform_device.h>#include <xtensa/simcall.h>#define DRIVER_NAME "iss-netdev"#define ETH_MAX_PACKET 1500#define ETH_HEADER_OTHER 14#define ISS_NET_TIMER_VALUE (2 * HZ)static DEFINE_SPINLOCK(opened_lock);static LIST_HEAD(opened);static DEFINE_SPINLOCK(devices_lock);static LIST_HEAD(devices);/* ------------------------------------------------------------------------- *//* We currently only support the TUNTAP transport protocol. */#define TRANSPORT_TUNTAP_NAME "tuntap"#define TRANSPORT_TUNTAP_MTU ETH_MAX_PACKETstruct tuntap_info { char dev_name[IFNAMSIZ]; int fixed_config; unsigned char gw[ETH_ALEN]; int fd;};/* ------------------------------------------------------------------------- *//* This structure contains out private information for the driver. */struct iss_net_private { struct list_head device_list; struct list_head opened_list; spinlock_t lock; struct net_device *dev; struct platform_device pdev; struct timer_list tl; struct net_device_stats stats; struct timer_list timer; unsigned int timer_val; int index; int mtu; unsigned char mac[ETH_ALEN]; int have_mac; struct { union { struct tuntap_info tuntap; } info; int (*open)(struct iss_net_private *lp); void (*close)(struct iss_net_private *lp); int (*read)(struct iss_net_private *lp, struct sk_buff **skb); int (*write)(struct iss_net_private *lp, struct sk_buff **skb); unsigned short (*protocol)(struct sk_buff *skb); int (*poll)(struct iss_net_private *lp); } tp;};/* ======================= ISS SIMCALL INTERFACE =========================== *//* Note: __simc must _not_ be declared inline! */static int errno;static int __simc (int a, int b, int c, int d, int e, int f){ int ret; __asm__ __volatile__ ("simcall\n" "mov %0, a2\n" "mov %1, a3\n" : "=a" (ret), "=a" (errno) : : "a2", "a3"); return ret;}static int inline simc_open(char *file, int flags, int mode){ return __simc(SYS_open, (int) file, flags, mode, 0, 0);}static int inline simc_close(int fd){ return __simc(SYS_close, fd, 0, 0, 0, 0);}static int inline simc_ioctl(int fd, int request, void *arg){ return __simc(SYS_ioctl, fd, request, (int) arg, 0, 0);}static int inline simc_read(int fd, void *buf, size_t count){ return __simc(SYS_read, fd, (int) buf, count, 0, 0);}static int inline simc_write(int fd, void *buf, size_t count){ return __simc(SYS_write, fd, (int) buf, count, 0, 0);}static int inline simc_poll(int fd){ struct timeval tv = { .tv_sec = 0, .tv_usec = 0 }; return __simc(SYS_select_one, fd, XTISS_SELECT_ONE_READ, (int)&tv,0,0);}/* ================================ HELPERS ================================ */static char *split_if_spec(char *str, ...){ char **arg, *end; va_list ap; va_start(ap, str); while ((arg = va_arg(ap, char**)) != NULL) { if (*str == '\0') return NULL; end = strchr(str, ','); if (end != str) *arg = str; if (end == NULL) return NULL; *end ++ = '\0'; str = end; } va_end(ap); return str;}#if 0/* Adjust SKB. */struct sk_buff *ether_adjust_skb(struct sk_buff *skb, int extra){ if ((skb != NULL) && (skb_tailroom(skb) < extra)) { struct sk_buff *skb2; skb2 = skb_copy_expand(skb, 0, extra, GFP_ATOMIC); dev_kfree_skb(skb); skb = skb2; } if (skb != NULL) skb_put(skb, extra); return skb;}#endif/* Return the IP address as a string for a given device. */static void dev_ip_addr(void *d, char *buf, char *bin_buf){ struct net_device *dev = d; struct in_device *ip = dev->ip_ptr; struct in_ifaddr *in; u32 addr; if ((ip == NULL) || ((in = ip->ifa_list) == NULL)) { printk(KERN_WARNING "Device not assigned an IP address!\n"); return; } addr = in->ifa_address; sprintf(buf, "%d.%d.%d.%d", addr & 0xff, (addr >> 8) & 0xff, (addr >> 16) & 0xff, addr >> 24); if (bin_buf) { bin_buf[0] = addr & 0xff; bin_buf[1] = (addr >> 8) & 0xff; bin_buf[2] = (addr >> 16) & 0xff; bin_buf[3] = addr >> 24; }}/* Set Ethernet address of the specified device. */static void inline set_ether_mac(void *d, unsigned char *addr){ struct net_device *dev = d; memcpy(dev->dev_addr, addr, ETH_ALEN);}/* ======================= TUNTAP TRANSPORT INTERFACE ====================== */static int tuntap_open(struct iss_net_private *lp){ struct ifreq ifr; char *dev_name = lp->tp.info.tuntap.dev_name; int err = -EINVAL; int fd; /* We currently only support a fixed configuration. */ if (!lp->tp.info.tuntap.fixed_config) return -EINVAL; if ((fd = simc_open("/dev/net/tun", 02, 0)) < 0) { /* O_RDWR */ printk("Failed to open /dev/net/tun, returned %d " "(errno = %d)\n", fd, errno); return fd; } memset(&ifr, 0, sizeof ifr); ifr.ifr_flags = IFF_TAP | IFF_NO_PI; strlcpy(ifr.ifr_name, dev_name, sizeof ifr.ifr_name - 1); if ((err = simc_ioctl(fd, TUNSETIFF, (void*) &ifr)) < 0) { printk("Failed to set interface, returned %d " "(errno = %d)\n", err, errno); simc_close(fd); return err; } lp->tp.info.tuntap.fd = fd; return err;}static void tuntap_close(struct iss_net_private *lp){#if 0 if (lp->tp.info.tuntap.fixed_config) iter_addresses(lp->tp.info.tuntap.dev, close_addr, lp->host.dev_name);#endif simc_close(lp->tp.info.tuntap.fd); lp->tp.info.tuntap.fd = -1;}static int tuntap_read (struct iss_net_private *lp, struct sk_buff **skb){#if 0 *skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER); if (*skb == NULL) return -ENOMEM;#endif return simc_read(lp->tp.info.tuntap.fd, (*skb)->data, (*skb)->dev->mtu + ETH_HEADER_OTHER);}static int tuntap_write (struct iss_net_private *lp, struct sk_buff **skb){ return simc_write(lp->tp.info.tuntap.fd, (*skb)->data, (*skb)->len);}unsigned short tuntap_protocol(struct sk_buff *skb){ return eth_type_trans(skb, skb->dev);}static int tuntap_poll(struct iss_net_private *lp){ return simc_poll(lp->tp.info.tuntap.fd);}/* * Currently only a device name is supported. * ethX=tuntap[,[mac address][,[device name]]] */static int tuntap_probe(struct iss_net_private *lp, int index, char *init){ const int len = strlen(TRANSPORT_TUNTAP_NAME); char *dev_name = NULL, *mac_str = NULL, *rem = NULL; /* Transport should be 'tuntap': ethX=tuntap,mac,dev_name */ if (strncmp(init, TRANSPORT_TUNTAP_NAME, len)) return 0; if (*(init += strlen(TRANSPORT_TUNTAP_NAME)) == ',') { if ((rem=split_if_spec(init+1, &mac_str, &dev_name)) != NULL) { printk("Extra garbage on specification : '%s'\n", rem); return 0; } } else if (*init != '\0') { printk("Invalid argument: %s. Skipping device!\n", init); return 0; } if (dev_name) { strncpy(lp->tp.info.tuntap.dev_name, dev_name, sizeof lp->tp.info.tuntap.dev_name); lp->tp.info.tuntap.fixed_config = 1; } else strcpy(lp->tp.info.tuntap.dev_name, TRANSPORT_TUNTAP_NAME);#if 0 if (setup_etheraddr(mac_str, lp->mac)) lp->have_mac = 1;#endif lp->mtu = TRANSPORT_TUNTAP_MTU; //lp->info.tuntap.gate_addr = gate_addr; lp->tp.info.tuntap.fd = -1; lp->tp.open = tuntap_open; lp->tp.close = tuntap_close; lp->tp.read = tuntap_read; lp->tp.write = tuntap_write; lp->tp.protocol = tuntap_protocol; lp->tp.poll = tuntap_poll; printk("TUN/TAP backend - ");#if 0 if (lp->host.gate_addr != NULL) printk("IP = %s", lp->host.gate_addr);#endif printk("\n"); return 1;}/* ================================ ISS NET ================================ */static int iss_net_rx(struct net_device *dev){ struct iss_net_private *lp = dev->priv; int pkt_len; struct sk_buff *skb; /* Check if there is any new data. */ if (lp->tp.poll(lp) == 0) return 0; /* Try to allocate memory, if it fails, try again next round. */ if ((skb = dev_alloc_skb(dev->mtu + 2 + ETH_HEADER_OTHER)) == NULL) { lp->stats.rx_dropped++; return 0; } skb_reserve(skb, 2); /* Setup skb */ skb->dev = dev; skb->mac.raw = skb->data; pkt_len = lp->tp.read(lp, &skb); skb_put(skb, pkt_len); if (pkt_len > 0) { skb_trim(skb, pkt_len); skb->protocol = lp->tp.protocol(skb); // netif_rx(skb); netif_rx_ni(skb); lp->stats.rx_bytes += skb->len; lp->stats.rx_packets++; return pkt_len; } kfree_skb(skb); return pkt_len;}static int iss_net_poll(void){ struct list_head *ele; int err, ret = 0; spin_lock(&opened_lock);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -