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

📄 cycx_x25.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
/* Configure adapter. */static int cycx_x25_configure(struct cycx_device *card,			      struct cycx_x25_config *conf){	struct {		u16 nlinks;		struct cycx_x25_config conf[2];	} x25_cmd_conf;	memset(&x25_cmd_conf, 0, sizeof(x25_cmd_conf));	x25_cmd_conf.nlinks = 2;	x25_cmd_conf.conf[0] = *conf;	/* FIXME: we need to find a way in the wanrouter framework		  to configure the second link, for now lets use it		  with the same config from the first link, fixing		  the interface type to RS232, the speed in 38400 and		  the clock to external */	x25_cmd_conf.conf[1] = *conf;	x25_cmd_conf.conf[1].link = 1;	x25_cmd_conf.conf[1].speed = 5; /* 38400 */	x25_cmd_conf.conf[1].clock = 8;	x25_cmd_conf.conf[1].flags = 0; /* default = RS232 */	cycx_x25_dump_config(&x25_cmd_conf.conf[0]);	cycx_x25_dump_config(&x25_cmd_conf.conf[1]);	return x25_exec(card, X25_CONFIG, 0,			&x25_cmd_conf, sizeof(x25_cmd_conf), NULL, 0);}/* Get protocol statistics. */static int cycx_x25_get_stats(struct cycx_device *card){	/* the firmware expects 20 in the size field!!!	   thanks to Daniela */	int err = x25_exec(card, X25_STATISTIC, 0, NULL, 20, NULL, 0);	if (err)		return err;	interruptible_sleep_on(&card->wait_stats);	if (signal_pending(current))		return -EINTR;	card->wandev.stats.rx_packets = card->u.x.stats.n2_rx_frames;	card->wandev.stats.rx_over_errors = card->u.x.stats.rx_over_errors;	card->wandev.stats.rx_crc_errors = card->u.x.stats.rx_crc_errors;	card->wandev.stats.rx_length_errors = 0; /* not available from fw */	card->wandev.stats.rx_frame_errors = 0; /* not available from fw */	card->wandev.stats.rx_missed_errors = card->u.x.stats.rx_aborts;	card->wandev.stats.rx_dropped = 0; /* not available from fw */	card->wandev.stats.rx_errors = 0; /* not available from fw */	card->wandev.stats.tx_packets = card->u.x.stats.n2_tx_frames;	card->wandev.stats.tx_aborted_errors = card->u.x.stats.tx_aborts;	card->wandev.stats.tx_dropped = 0; /* not available from fw */	card->wandev.stats.collisions = 0; /* not available from fw */	card->wandev.stats.tx_errors = 0; /* not available from fw */	cycx_x25_dump_devs(&card->wandev);	return 0;}/* return the number of nibbles */static int byte_to_nibble(u8 *s, u8 *d, char *nibble){	int i = 0;	if (*nibble && *s) {		d[i] |= *s++ - '0';		*nibble = 0;		++i;	}	while (*s) {		d[i] = (*s - '0') << 4;		if (*(s + 1))			d[i] |= *(s + 1) - '0';		else {			*nibble = 1;			break;		}		++i;		s += 2;	}	return i;}static void nibble_to_byte(u8 *s, u8 *d, u8 len, u8 nibble){	if (nibble) {		*d++ = '0' + (*s++ & 0x0F);		--len;	}	while (len) {		*d++ = '0' + (*s >> 4);		if (--len) {			*d++ = '0' + (*s & 0x0F);			--len;		} else break;		++s;	}	*d = '\0';}/* Place X.25 call. */static int x25_place_call(struct cycx_device *card,			  struct cycx_x25_channel *chan){	int err = 0,	    len;	char d[64],	     nibble = 0,	     mylen = chan->local_addr ? strlen(chan->local_addr) : 0,	     remotelen = strlen(chan->addr);	u8 key;	if (card->u.x.connection_keys == ~0U) {		printk(KERN_INFO "%s: too many simultaneous connection "				 "requests!\n", card->devname);		return -EAGAIN;	}	key = ffz(card->u.x.connection_keys);	set_bit(key, (void*)&card->u.x.connection_keys);	++key;	dprintk(1, KERN_INFO "%s:x25_place_call:key=%d\n", card->devname, key);	memset(d, 0, sizeof(d));	d[1] = key; /* user key */	d[2] = 0x10;	d[4] = 0x0B;	len = byte_to_nibble(chan->addr, d + 6, &nibble);	if (chan->local_addr)		len += byte_to_nibble(chan->local_addr, d + 6 + len, &nibble);	if (nibble)		++len;	d[5] = mylen << 4 | remotelen;	d[6 + len + 1] = 0xCC; /* TCP/IP over X.25, thanks to Daniela :) */	if ((err = x25_exec(card, X25_CONNECT_REQUEST, chan->link,			    &d, 7 + len + 1, NULL, 0)) != 0)		clear_bit(--key, (void*)&card->u.x.connection_keys);	else		chan->lcn = -key;	return err;}/* Place X.25 CONNECT RESPONSE. */static int cycx_x25_connect_response(struct cycx_device *card,				     struct cycx_x25_channel *chan){	u8 d[8];	memset(d, 0, sizeof(d));	d[0] = d[3] = chan->lcn;	d[2] = 0x10;	d[4] = 0x0F;	d[7] = 0xCC; /* TCP/IP over X.25, thanks Daniela */	return x25_exec(card, X25_CONNECT_RESPONSE, chan->link, &d, 8, NULL, 0);}/* Place X.25 DISCONNECT RESPONSE.  */static int cycx_x25_disconnect_response(struct cycx_device *card, u8 link,					u8 lcn){	char d[5];	memset(d, 0, sizeof(d));	d[0] = d[3] = lcn;	d[2] = 0x10;	d[4] = 0x17;	return x25_exec(card, X25_DISCONNECT_RESPONSE, link, &d, 5, NULL, 0);}/* Clear X.25 call.  */static int x25_clear_call(struct cycx_device *card, u8 link, u8 lcn, u8 cause,			  u8 diagn){	u8 d[7];	memset(d, 0, sizeof(d));	d[0] = d[3] = lcn;	d[2] = 0x10;	d[4] = 0x13;	d[5] = cause;	d[6] = diagn;	return x25_exec(card, X25_DISCONNECT_REQUEST, link, d, 7, NULL, 0);}/* Send X.25 data packet. */static int cycx_x25_send(struct cycx_device *card, u8 link, u8 lcn, u8 bitm,			 int len, void *buf){	u8 d[] = "?\xFF\x10??";	d[0] = d[3] = lcn;	d[4] = bitm;	return x25_exec(card, X25_DATA_REQUEST, link, &d, 5, buf, len);}/* Miscellaneous *//* Find network device by its channel number.  */static struct net_device *cycx_x25_get_dev_by_lcn(struct wan_device *wandev,						  s16 lcn){	struct net_device *dev = wandev->dev;	struct cycx_x25_channel *chan;	while (dev) {		chan = (struct cycx_x25_channel*)dev->priv;		if (chan->lcn == lcn)			break;		dev = chan->slave;	}	return dev;}/* Find network device by its remote dte address. */static struct net_device *	cycx_x25_get_dev_by_dte_addr(struct wan_device *wandev, char *dte){	struct net_device *dev = wandev->dev;	struct cycx_x25_channel *chan;	while (dev) {		chan = (struct cycx_x25_channel*)dev->priv;		if (!strcmp(chan->addr, dte))			break;		dev = chan->slave;	}	return dev;}/* Initiate connection on the logical channel. * o for PVC we just get channel configuration * o for SVCs place an X.25 call * * Return:	0	connected *		>0	connection in progress *		<0	failure */static int cycx_x25_chan_connect(struct net_device *dev){	struct cycx_x25_channel *chan = dev->priv;	struct cycx_device *card = chan->card;	if (chan->svc) {		if (!chan->addr[0])			return -EINVAL; /* no destination address */		dprintk(1, KERN_INFO "%s: placing X.25 call to %s...\n",				  card->devname, chan->addr);		if (x25_place_call(card, chan))			return -EIO;		cycx_x25_set_chan_state(dev, WAN_CONNECTING);		return 1;	} else		cycx_x25_set_chan_state(dev, WAN_CONNECTED);	return 0;}/* Disconnect logical channel. * o if SVC then clear X.25 call */static void cycx_x25_chan_disconnect(struct net_device *dev){	struct cycx_x25_channel *chan = dev->priv;	if (chan->svc) {		x25_clear_call(chan->card, chan->link, chan->lcn, 0, 0);		cycx_x25_set_chan_state(dev, WAN_DISCONNECTING);	} else		cycx_x25_set_chan_state(dev, WAN_DISCONNECTED);}/* Called by kernel timer */static void cycx_x25_chan_timer(unsigned long d){	struct net_device *dev = (struct net_device *)d;	struct cycx_x25_channel *chan = dev->priv;	if (chan->state == WAN_CONNECTED)		cycx_x25_chan_disconnect(dev);	else		printk(KERN_ERR "%s: %s for svc (%s) not connected!\n",				chan->card->devname, __FUNCTION__, dev->name);}/* Set logical channel state. */static void cycx_x25_set_chan_state(struct net_device *dev, u8 state){	struct cycx_x25_channel *chan = dev->priv;	struct cycx_device *card = chan->card;	unsigned long flags;	char *string_state = NULL;	spin_lock_irqsave(&card->lock, flags);	if (chan->state != state) {		if (chan->svc && chan->state == WAN_CONNECTED)			del_timer(&chan->timer);		switch (state) {		case WAN_CONNECTED:			string_state = "connected!";			*(u16*)dev->dev_addr = htons(chan->lcn);			netif_wake_queue(dev);			reset_timer(dev);			if (chan->protocol == ETH_P_X25)				cycx_x25_chan_send_event(dev, 1);			break;		case WAN_CONNECTING:			string_state = "connecting...";			break;		case WAN_DISCONNECTING:			string_state = "disconnecting...";			break;		case WAN_DISCONNECTED:			string_state = "disconnected!";			if (chan->svc) {				*(unsigned short*)dev->dev_addr = 0;				chan->lcn = 0;			}			if (chan->protocol == ETH_P_X25)				cycx_x25_chan_send_event(dev, 2);			netif_wake_queue(dev);			break;		}		printk(KERN_INFO "%s: interface %s %s\n", card->devname,				  dev->name, string_state);		chan->state = state;	}	spin_unlock_irqrestore(&card->lock, flags);}/* Send packet on a logical channel. *	When this function is called, tx_skb field of the channel data space *	points to the transmit socket buffer.  When transmission is complete, *	release socket buffer and reset 'tbusy' flag. * * Return:	0	- transmission complete *		1	- busy * * Notes: * 1. If packet length is greater than MTU for this channel, we'll fragment *    the packet into 'complete sequence' using M-bit. * 2. When transmission is complete, an event notification should be issued *    to the router.  */static int cycx_x25_chan_send(struct net_device *dev, struct sk_buff *skb){	struct cycx_x25_channel *chan = dev->priv;	struct cycx_device *card = chan->card;	int bitm = 0;		/* final packet */	unsigned len = skb->len;	if (skb->len > card->wandev.mtu) {		len = card->wandev.mtu;		bitm = 0x10;		/* set M-bit (more data) */	}	if (cycx_x25_send(card, chan->link, chan->lcn, bitm, len, skb->data))		return 1;	if (bitm) {		skb_pull(skb, len);		return 1;	}	++chan->ifstats.tx_packets;	chan->ifstats.tx_bytes += len;	return 0;}/* Send event (connection, disconnection, etc) to X.25 socket layer */static void cycx_x25_chan_send_event(struct net_device *dev, u8 event){	struct sk_buff *skb;	unsigned char *ptr;	if ((skb = dev_alloc_skb(1)) == NULL) {		printk(KERN_ERR "%s: out of memory\n", __FUNCTION__);		return;	}	ptr  = skb_put(skb, 1);	*ptr = event;	skb->protocol = x25_type_trans(skb, dev);	netif_rx(skb);	dev->last_rx = jiffies;		/* timestamp */}/* Convert line speed in bps to a number used by cyclom 2x code. */static u8 bps_to_speed_code(u32 bps){	u8 number = 0; /* defaults to the lowest (1200) speed ;> */	     if (bps >= 512000) number = 8;	else if (bps >= 256000) number = 7;	else if (bps >= 64000)  number = 6;	else if (bps >= 38400)  number = 5;	else if (bps >= 19200)  number = 4;	else if (bps >= 9600)   number = 3;	else if (bps >= 4800)   number = 2;	else if (bps >= 2400)   number = 1;	return number;}/* log base 2 */static u8 cycx_log2(u32 n){	u8 log = 0;	if (!n)		return 0;	while (n > 1) {		n >>= 1;		++log;	}	return log;}/* Convert decimal string to unsigned integer. * If len != 0 then only 'len' characters of the string are converted. */static unsigned dec_to_uint(u8 *str, int len){	unsigned val = 0;	if (!len)		len = strlen(str);	for (; len && isdigit(*str); ++str, --len)		val = (val * 10) + (*str - (unsigned) '0');	return val;}static void reset_timer(struct net_device *dev){	struct cycx_x25_channel *chan = dev->priv;	if (chan->svc)		mod_timer(&chan->timer, jiffies+chan->idle_tmout*HZ);}#ifdef CYCLOMX_X25_DEBUGstatic void cycx_x25_dump_config(struct cycx_x25_config *conf){	printk(KERN_INFO "X.25 configuration\n");	printk(KERN_INFO "-----------------\n");	printk(KERN_INFO "link number=%d\n", conf->link);	printk(KERN_INFO "line speed=%d\n", conf->speed);	printk(KERN_INFO "clock=%sternal\n", conf->clock == 8 ? "Ex" : "In");	printk(KERN_INFO "# level 2 retransm.=%d\n", conf->n2);	printk(KERN_INFO "level 2 window=%d\n", conf->n2win);	printk(KERN_INFO "level 3 window=%d\n", conf->n3win);	printk(KERN_INFO "# logical channels=%d\n", conf->nvc);	printk(KERN_INFO "level 3 pkt len=%d\n", conf->pktlen);	printk(KERN_INFO "my address=%d\n", conf->locaddr);	printk(KERN_INFO "remote address=%d\n", conf->remaddr);	printk(KERN_INFO "t1=%d seconds\n", conf->t1);	printk(KERN_INFO "t2=%d seconds\n", conf->t2);	printk(KERN_INFO "t21=%d seconds\n", conf->t21);	printk(KERN_INFO "# PVCs=%d\n", conf->npvc);	printk(KERN_INFO "t23=%d seconds\n", conf->t23);	printk(KERN_INFO "flags=0x%x\n", conf->flags);}static void cycx_x25_dump_stats(struct cycx_x25_stats *stats){	printk(KERN_INFO "X.25 statistics\n");	printk(KERN_INFO "--------------\n");	printk(KERN_INFO "rx_crc_errors=%d\n", stats->rx_crc_errors);	printk(KERN_INFO "rx_over_errors=%d\n", stats->rx_over_errors);	printk(KERN_INFO "n2_tx_frames=%d\n", stats->n2_tx_frames);	printk(KERN_INFO "n2_rx_frames=%d\n", stats->n2_rx_frames);	printk(KERN_INFO "tx_timeouts=%d\n", stats->tx_timeouts);	printk(KERN_INFO "rx_timeouts=%d\n", stats->rx_timeouts);	printk(KERN_INFO "n3_tx_packets=%d\n", stats->n3_tx_packets);	printk(KERN_INFO "n3_rx_packets=%d\n", stats->n3_rx_packets);	printk(KERN_INFO "tx_aborts=%d\n", stats->tx_aborts);	printk(KERN_INFO "rx_aborts=%d\n", stats->rx_aborts);}static void cycx_x25_dump_devs(struct wan_device *wandev){	struct net_device *dev = wandev->dev;	printk(KERN_INFO "X.25 dev states\n");	printk(KERN_INFO "name: addr:           txoff:  protocol:\n");	printk(KERN_INFO "---------------------------------------\n");	while(dev) {		struct cycx_x25_channel *chan = dev->priv;		printk(KERN_INFO "%-5.5s %-15.15s   %d     ETH_P_%s\n",				 chan->name, chan->addr, netif_queue_stopped(dev),				 chan->protocol == ETH_P_IP ? "IP" : "X25");		dev = chan->slave;	}}#endif /* CYCLOMX_X25_DEBUG *//* End */

⌨️ 快捷键说明

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