⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 network.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * * 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 + -