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

📄 cycx_x25.c

📁 该文件是rt_linux
💻 C
📖 第 1 页 / 共 3 页
字号:
		if (chan->state == WAN_CONNECTED || chan->state == WAN_CONNECTING)		chan_disconnect(dev);			cyclomx_mod_dec_use_count(card);	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 if_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 if_rebuild_hdr (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 if_send (struct sk_buff *skb, struct net_device *dev){	x25_channel_t *chan = dev->priv;	cycx_t *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 (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 (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 */				chan_connect(dev);				goto free_packet;		        case 2: /* Disconnect request */				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 (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 *if_stats (struct net_device *dev){        x25_channel_t *chan = dev->priv;	return chan ? &chan->ifstats : NULL;}/* Interrupt Handlers *//* X.25 Interrupt Service Routine. */static void cyx_isr (cycx_t *card){	TX25Cmd 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:			rx_intr(card, &cmd);			break;		case X25_ACK_FROM_VC:			tx_intr(card, &cmd);			break;		case X25_LOG: 			log_intr(card, &cmd);			break;		case X25_STATISTIC: 			stat_intr(card, &cmd);			break;		case X25_CONNECT_CONFIRM:			connect_confirm_intr(card, &cmd);			break;		case X25_CONNECT_INDICATION:			connect_intr(card, &cmd);			break;		case X25_DISCONNECT_INDICATION:			disconnect_intr(card, &cmd);			break;		case X25_DISCONNECT_CONFIRM:			disconnect_confirm_intr(card, &cmd);			break;		case X25_LINE_ON:			cyclomx_set_state(card, WAN_CONNECTED);			break;		case X25_LINE_OFF:			cyclomx_set_state(card, WAN_DISCONNECTED);			break;		default: 			spur_intr(card, &cmd); /* unwanted interrupt */	}	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 tx_intr (cycx_t *card, TX25Cmd *cmd){	struct net_device *dev;	wan_device_t *wandev = &card->wandev;	u8 lcn;	cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn));	/* unbusy device and then dev_tint(); */	if ((dev = get_dev_by_lcn(wandev, lcn)) != NULL) {		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 rx_intr (cycx_t *card, TX25Cmd *cmd){	wan_device_t *wandev = &card->wandev;	struct net_device *dev;	x25_channel_t *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;	if ((dev = get_dev_by_lcn(wandev, lcn)) == NULL) {		/* 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 connect_intr (cycx_t *card, TX25Cmd *cmd){	wan_device_t *wandev = &card->wandev;	struct net_device *dev = NULL;	x25_channel_t *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 "connect_intr:lcn=%d, local=%s, remote=%s\n",			  lcn, loc, rem);	if ((dev = get_dev_by_dte_addr(wandev, rem)) == NULL) {		/* Invalid channel, discard packet */		printk(KERN_INFO "%s: connect not expected: remote %s!\n",				 card->devname, rem);		return;	}	chan = dev->priv;	chan->lcn = lcn;	x25_connect_response(card, chan);	set_chan_state(dev, WAN_CONNECTED);}/* Connect confirm interrupt handler. */static void connect_confirm_intr (cycx_t *card, TX25Cmd *cmd){	wan_device_t *wandev = &card->wandev;	struct net_device *dev;	x25_channel_t *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: connect_confirm_intr:lcn=%d, key=%d\n",			  card->devname, lcn, key);	if ((dev = get_dev_by_lcn(wandev, -key)) == NULL) {		/* 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;	set_chan_state(dev, WAN_CONNECTED);}/* Disconnect confirm interrupt handler. */static void disconnect_confirm_intr (cycx_t *card, TX25Cmd *cmd){	wan_device_t *wandev = &card->wandev;	struct net_device *dev;	u8 lcn;	cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn));	dprintk(1, KERN_INFO "%s: disconnect_confirm_intr:lcn=%d\n",			  card->devname, lcn);	if ((dev = get_dev_by_lcn(wandev, lcn)) == NULL) {		/* Invalid channel, discard packet */		printk(KERN_INFO "%s:disconnect confirm not expected!:lcn %d\n",				 card->devname, lcn);		return;	}	set_chan_state(dev, WAN_DISCONNECTED);}/* disconnect interrupt handler. */static void disconnect_intr (cycx_t *card, TX25Cmd *cmd){	wan_device_t *wandev = &card->wandev;	struct net_device *dev;	u8 lcn;	cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn));	dprintk(1, KERN_INFO "disconnect_intr:lcn=%d\n", lcn);	if ((dev = get_dev_by_lcn(wandev, lcn)) != NULL) {		x25_channel_t *chan = dev->priv;		x25_disconnect_response(card, chan->link, lcn);		set_chan_state(dev, WAN_DISCONNECTED);	} else		x25_disconnect_response(card, 0, lcn);}/* LOG interrupt handler. */static void log_intr (cycx_t *card, TX25Cmd *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 "cyx_isr: 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 stat_intr (cycx_t *card, TX25Cmd *cmd){	cycx_peek(&card->hw, cmd->buf, &card->u.x.stats,		  sizeof(card->u.x.stats));	hex_dump("stat_intr", (unsigned char*)&card->u.x.stats,		 sizeof(card->u.x.stats));	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 spur_intr (cycx_t *card, TX25Cmd *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 (cycx_t *card, int command, int link,		     void *d1, int len1, void *d2, int len2){	TX25Cmd c;	unsigned long flags;	u32 addr = 0x1200 + 0x2E0 * link + 0x1E2;	u8 retry = 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;}/* Configure adapter. */static int x25_configure (cycx_t *card, TX25Config *conf){	struct {		u16 nlinks;		TX25Config conf[2];	} x25_cmd_conf;

⌨️ 快捷键说明

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