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

📄 cycx_x25.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
static int cycx_netdevice_stop(struct net_device *dev){	struct cycx_x25_channel *chan = dev->priv;	netif_stop_queue(dev);	if (chan->state == WAN_CONNECTED || chan->state == WAN_CONNECTING)		cycx_x25_chan_disconnect(dev);	return 0;}/* Build media header. * o encapsulate packet according to encapsulation type. * * The trick here is to put packet type (Ethertype) into 'protocol' field of * the socket buffer, so that we don't forget it.  If encapsulation fails, * set skb->protocol to 0 and discard packet later. * * Return:	media header length. */static int cycx_netdevice_hard_header(struct sk_buff *skb,				      struct net_device *dev, u16 type,				      void *daddr, void *saddr, unsigned len){	skb->protocol = type;	return dev->hard_header_len;}/* * Re-build media header. * Return:	1	physical address resolved. *		0	physical address not resolved */static int cycx_netdevice_rebuild_header(struct sk_buff *skb){	return 1;}/* Send a packet on a network interface. * o set busy flag (marks start of the transmission). * o check link state. If link is not up, then drop the packet. * o check channel status. If it's down then initiate a call. * o pass a packet to corresponding WAN device. * o free socket buffer * * Return:	0	complete (socket buffer must be freed) *		non-0	packet may be re-transmitted (tbusy must be set) * * Notes: * 1. This routine is called either by the protocol stack or by the "net *    bottom half" (with interrupts enabled). * 2. Setting tbusy flag will inhibit further transmit requests from the *    protocol stack and can be used for flow control with protocol layer. */static int cycx_netdevice_hard_start_xmit(struct sk_buff *skb,					  struct net_device *dev){	struct cycx_x25_channel *chan = dev->priv;	struct cycx_device *card = chan->card;	if (!chan->svc)		chan->protocol = skb->protocol;	if (card->wandev.state != WAN_CONNECTED)		++chan->ifstats.tx_dropped;	else if (chan->svc && chan->protocol &&		 chan->protocol != skb->protocol) {		printk(KERN_INFO		       "%s: unsupported Ethertype 0x%04X on interface %s!\n",		       card->devname, skb->protocol, dev->name);		++chan->ifstats.tx_errors;	} else if (chan->protocol == ETH_P_IP) {		switch (chan->state) {		case WAN_DISCONNECTED:			if (cycx_x25_chan_connect(dev)) {				netif_stop_queue(dev);				return -EBUSY;			}			/* fall thru */		case WAN_CONNECTED:			reset_timer(dev);			dev->trans_start = jiffies;			netif_stop_queue(dev);			if (cycx_x25_chan_send(dev, skb))				return -EBUSY;			break;		default:			++chan->ifstats.tx_dropped;			++card->wandev.stats.tx_dropped;	}	} else { /* chan->protocol == ETH_P_X25 */		switch (skb->data[0]) {		case 0: break;		case 1: /* Connect request */			cycx_x25_chan_connect(dev);			goto free_packet;		case 2: /* Disconnect request */			cycx_x25_chan_disconnect(dev);			goto free_packet;	        default:			printk(KERN_INFO			       "%s: unknown %d x25-iface request on %s!\n",			       card->devname, skb->data[0], dev->name);			++chan->ifstats.tx_errors;			goto free_packet;		}		skb_pull(skb, 1); /* Remove control byte */		reset_timer(dev);		dev->trans_start = jiffies;		netif_stop_queue(dev);		if (cycx_x25_chan_send(dev, skb)) {			/* prepare for future retransmissions */			skb_push(skb, 1);			return -EBUSY;		}	}free_packet:	dev_kfree_skb(skb);	return 0;}/* Get Ethernet-style interface statistics. * Return a pointer to struct net_device_stats */static struct net_device_stats *cycx_netdevice_get_stats(struct net_device *dev){	struct cycx_x25_channel *chan = dev->priv;	return chan ? &chan->ifstats : NULL;}/* Interrupt Handlers *//* X.25 Interrupt Service Routine. */static void cycx_x25_irq_handler(struct cycx_device *card){	struct cycx_x25_cmd cmd;	u16 z = 0;	card->in_isr = 1;	card->buff_int_mode_unbusy = 0;	cycx_peek(&card->hw, X25_RXMBOX_OFFS, &cmd, sizeof(cmd));	switch (cmd.command) {	case X25_DATA_INDICATION:		cycx_x25_irq_rx(card, &cmd);		break;	case X25_ACK_FROM_VC:		cycx_x25_irq_tx(card, &cmd);		break;	case X25_LOG:		cycx_x25_irq_log(card, &cmd);		break;	case X25_STATISTIC:		cycx_x25_irq_stat(card, &cmd);		break;	case X25_CONNECT_CONFIRM:		cycx_x25_irq_connect_confirm(card, &cmd);		break;	case X25_CONNECT_INDICATION:		cycx_x25_irq_connect(card, &cmd);		break;	case X25_DISCONNECT_INDICATION:		cycx_x25_irq_disconnect(card, &cmd);		break;	case X25_DISCONNECT_CONFIRM:		cycx_x25_irq_disconnect_confirm(card, &cmd);		break;	case X25_LINE_ON:		cycx_set_state(card, WAN_CONNECTED);		break;	case X25_LINE_OFF:		cycx_set_state(card, WAN_DISCONNECTED);		break;	default:		cycx_x25_irq_spurious(card, &cmd);		break;	}	cycx_poke(&card->hw, 0, &z, sizeof(z));	cycx_poke(&card->hw, X25_RXMBOX_OFFS, &z, sizeof(z));	card->in_isr = 0;}/* Transmit interrupt handler. *	o Release socket buffer *	o Clear 'tbusy' flag */static void cycx_x25_irq_tx(struct cycx_device *card, struct cycx_x25_cmd *cmd){	struct net_device *dev;	struct wan_device *wandev = &card->wandev;	u8 lcn;	cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn));	/* unbusy device and then dev_tint(); */	dev = cycx_x25_get_dev_by_lcn(wandev, lcn);	if (dev) {		card->buff_int_mode_unbusy = 1;		netif_wake_queue(dev);	} else		printk(KERN_ERR "%s:ackvc for inexistent lcn %d\n",				 card->devname, lcn);}/* Receive interrupt handler. * This routine handles fragmented IP packets using M-bit according to the * RFC1356. * o map logical channel number to network interface. * o allocate socket buffer or append received packet to the existing one. * o if M-bit is reset (i.e. it's the last packet in a sequence) then *   decapsulate packet and pass socket buffer to the protocol stack. * * Notes: * 1. When allocating a socket buffer, if M-bit is set then more data is *    coming and we have to allocate buffer for the maximum IP packet size *    expected on this channel. * 2. If something goes wrong and X.25 packet has to be dropped (e.g. no *    socket buffers available) the whole packet sequence must be discarded. */static void cycx_x25_irq_rx(struct cycx_device *card, struct cycx_x25_cmd *cmd){	struct wan_device *wandev = &card->wandev;	struct net_device *dev;	struct cycx_x25_channel *chan;	struct sk_buff *skb;	u8 bitm, lcn;	int pktlen = cmd->len - 5;	cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn));	cycx_peek(&card->hw, cmd->buf + 4, &bitm, sizeof(bitm));	bitm &= 0x10;	dev = cycx_x25_get_dev_by_lcn(wandev, lcn);	if (!dev) {		/* Invalid channel, discard packet */		printk(KERN_INFO "%s: receiving on orphaned LCN %d!\n",				 card->devname, lcn);		return;	}	chan = dev->priv;	reset_timer(dev);	if (chan->drop_sequence) {		if (!bitm)			chan->drop_sequence = 0;		else			return;	}	if ((skb = chan->rx_skb) == NULL) {		/* Allocate new socket buffer */		int bufsize = bitm ? dev->mtu : pktlen;		if ((skb = dev_alloc_skb((chan->protocol == ETH_P_X25 ? 1 : 0) +					 bufsize +					 dev->hard_header_len)) == NULL) {			printk(KERN_INFO "%s: no socket buffers available!\n",					 card->devname);			chan->drop_sequence = 1;			++chan->ifstats.rx_dropped;			return;		}		if (chan->protocol == ETH_P_X25) /* X.25 socket layer control */			/* 0 = data packet (dev_alloc_skb zeroed skb->data) */			skb_put(skb, 1);		skb->dev = dev;		skb->protocol = htons(chan->protocol);		chan->rx_skb = skb;	}	if (skb_tailroom(skb) < pktlen) {		/* No room for the packet. Call off the whole thing! */		dev_kfree_skb_irq(skb);		chan->rx_skb = NULL;		if (bitm)			chan->drop_sequence = 1;		printk(KERN_INFO "%s: unexpectedly long packet sequence "			"on interface %s!\n", card->devname, dev->name);		++chan->ifstats.rx_length_errors;		return;	}	/* Append packet to the socket buffer  */	cycx_peek(&card->hw, cmd->buf + 5, skb_put(skb, pktlen), pktlen);	if (bitm)		return; /* more data is coming */	chan->rx_skb = NULL;		/* dequeue packet */	++chan->ifstats.rx_packets;	chan->ifstats.rx_bytes += pktlen;	skb->mac.raw = skb->data;	netif_rx(skb);	dev->last_rx = jiffies;		/* timestamp */}/* Connect interrupt handler. */static void cycx_x25_irq_connect(struct cycx_device *card,				 struct cycx_x25_cmd *cmd){	struct wan_device *wandev = &card->wandev;	struct net_device *dev = NULL;	struct cycx_x25_channel *chan;	u8 d[32],	   loc[24],	   rem[24];	u8 lcn, sizeloc, sizerem;	cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn));	cycx_peek(&card->hw, cmd->buf + 5, &sizeloc, sizeof(sizeloc));	cycx_peek(&card->hw, cmd->buf + 6, d, cmd->len - 6);	sizerem = sizeloc >> 4;	sizeloc &= 0x0F;	loc[0] = rem[0] = '\0';	if (sizeloc)		nibble_to_byte(d, loc, sizeloc, 0);	if (sizerem)		nibble_to_byte(d + (sizeloc >> 1), rem, sizerem, sizeloc & 1);	dprintk(1, KERN_INFO "%s:lcn=%d, local=%s, remote=%s\n",			  __FUNCTION__, lcn, loc, rem);	dev = cycx_x25_get_dev_by_dte_addr(wandev, rem);	if (!dev) {		/* Invalid channel, discard packet */		printk(KERN_INFO "%s: connect not expected: remote %s!\n",				 card->devname, rem);		return;	}	chan = dev->priv;	chan->lcn = lcn;	cycx_x25_connect_response(card, chan);	cycx_x25_set_chan_state(dev, WAN_CONNECTED);}/* Connect confirm interrupt handler. */static void cycx_x25_irq_connect_confirm(struct cycx_device *card,					 struct cycx_x25_cmd *cmd){	struct wan_device *wandev = &card->wandev;	struct net_device *dev;	struct cycx_x25_channel *chan;	u8 lcn, key;	cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn));	cycx_peek(&card->hw, cmd->buf + 1, &key, sizeof(key));	dprintk(1, KERN_INFO "%s: %s:lcn=%d, key=%d\n",			  card->devname, __FUNCTION__, lcn, key);	dev = cycx_x25_get_dev_by_lcn(wandev, -key);	if (!dev) {		/* Invalid channel, discard packet */		clear_bit(--key, (void*)&card->u.x.connection_keys);		printk(KERN_INFO "%s: connect confirm not expected: lcn %d, "				 "key=%d!\n", card->devname, lcn, key);		return;	}	clear_bit(--key, (void*)&card->u.x.connection_keys);	chan = dev->priv;	chan->lcn = lcn;	cycx_x25_set_chan_state(dev, WAN_CONNECTED);}/* Disconnect confirm interrupt handler. */static void cycx_x25_irq_disconnect_confirm(struct cycx_device *card,					    struct cycx_x25_cmd *cmd){	struct wan_device *wandev = &card->wandev;	struct net_device *dev;	u8 lcn;	cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn));	dprintk(1, KERN_INFO "%s: %s:lcn=%d\n",			  card->devname, __FUNCTION__, lcn);	dev = cycx_x25_get_dev_by_lcn(wandev, lcn);	if (!dev) {		/* Invalid channel, discard packet */		printk(KERN_INFO "%s:disconnect confirm not expected!:lcn %d\n",				 card->devname, lcn);		return;	}	cycx_x25_set_chan_state(dev, WAN_DISCONNECTED);}/* disconnect interrupt handler. */static void cycx_x25_irq_disconnect(struct cycx_device *card,				    struct cycx_x25_cmd *cmd){	struct wan_device *wandev = &card->wandev;	struct net_device *dev;	u8 lcn;	cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn));	dprintk(1, KERN_INFO "%s:lcn=%d\n", __FUNCTION__, lcn);	dev = cycx_x25_get_dev_by_lcn(wandev, lcn);	if (dev) {		struct cycx_x25_channel *chan = dev->priv;		cycx_x25_disconnect_response(card, chan->link, lcn);		cycx_x25_set_chan_state(dev, WAN_DISCONNECTED);	} else		cycx_x25_disconnect_response(card, 0, lcn);}/* LOG interrupt handler. */static void cycx_x25_irq_log(struct cycx_device *card, struct cycx_x25_cmd *cmd){#if CYCLOMX_X25_DEBUG	char bf[20];	u16 size, toread, link, msg_code;	u8 code, routine;	cycx_peek(&card->hw, cmd->buf, &msg_code, sizeof(msg_code));	cycx_peek(&card->hw, cmd->buf + 2, &link, sizeof(link));	cycx_peek(&card->hw, cmd->buf + 4, &size, sizeof(size));	/* at most 20 bytes are available... thanks to Daniela :) */	toread = size < 20 ? size : 20;	cycx_peek(&card->hw, cmd->buf + 10, &bf, toread);	cycx_peek(&card->hw, cmd->buf + 10 + toread, &code, 1);	cycx_peek(&card->hw, cmd->buf + 10 + toread + 1, &routine, 1);	printk(KERN_INFO "cycx_x25_irq_handler: X25_LOG (0x4500) indic.:\n");	printk(KERN_INFO "cmd->buf=0x%X\n", cmd->buf);	printk(KERN_INFO "Log message code=0x%X\n", msg_code);	printk(KERN_INFO "Link=%d\n", link);	printk(KERN_INFO "log code=0x%X\n", code);	printk(KERN_INFO "log routine=0x%X\n", routine);	printk(KERN_INFO "Message size=%d\n", size);	hex_dump("Message", bf, toread);#endif}/* STATISTIC interrupt handler. */static void cycx_x25_irq_stat(struct cycx_device *card,			      struct cycx_x25_cmd *cmd){	cycx_peek(&card->hw, cmd->buf, &card->u.x.stats,		  sizeof(card->u.x.stats));	hex_dump("cycx_x25_irq_stat", (unsigned char*)&card->u.x.stats,		 sizeof(card->u.x.stats));	cycx_x25_dump_stats(&card->u.x.stats);	wake_up_interruptible(&card->wait_stats);}/* Spurious interrupt handler. * o print a warning * If number of spurious interrupts exceeded some limit, then ??? */static void cycx_x25_irq_spurious(struct cycx_device *card,				  struct cycx_x25_cmd *cmd){	printk(KERN_INFO "%s: spurious interrupt (0x%X)!\n",			 card->devname, cmd->command);}#ifdef CYCLOMX_X25_DEBUGstatic void hex_dump(char *msg, unsigned char *p, int len){	unsigned char hex[1024],	    	* phex = hex;	if (len >= (sizeof(hex) / 2))		len = (sizeof(hex) / 2) - 1;	while (len--) {		sprintf(phex, "%02x", *p++);		phex += 2;	}	printk(KERN_INFO "%s: %s\n", msg, hex);}#endif/* Cyclom 2X Firmware-Specific Functions *//* Exec X.25 command. */static int x25_exec(struct cycx_device *card, int command, int link,		    void *d1, int len1, void *d2, int len2){	struct cycx_x25_cmd c;	unsigned long flags;	u32 addr = 0x1200 + 0x2E0 * link + 0x1E2;	u8 retry = CYCX_X25_MAX_CMD_RETRY;	int err = 0;	c.command = command;	c.link = link;	c.len = len1 + len2;	spin_lock_irqsave(&card->u.x.lock, flags);	/* write command */	cycx_poke(&card->hw, X25_MBOX_OFFS, &c, sizeof(c) - sizeof(c.buf));	/* write X.25 data */	if (d1) {		cycx_poke(&card->hw, addr, d1, len1);		if (d2) {			if (len2 > 254) {				u32 addr1 = 0xA00 + 0x400 * link;				cycx_poke(&card->hw, addr + len1, d2, 249);				cycx_poke(&card->hw, addr1, ((u8*)d2) + 249,					  len2 - 249);			} else				cycx_poke(&card->hw, addr + len1, d2, len2);		}	}	/* generate interruption, executing command */	cycx_intr(&card->hw);	/* wait till card->mbox == 0 */	do {		err = cycx_exec(card->mbox);	} while (retry-- && err);	spin_unlock_irqrestore(&card->u.x.lock, flags);	return err;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -