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

📄 lcs.c

📁 LINUX 2.6.17.4的源码
💻 C
📖 第 1 页 / 共 4 页
字号:
			break;		default:			PRINT_INFO("UNRECOGNIZED LGW COMMAND\n");			break;		}	} else		lcs_notify_lancmd_waiters(card, cmd);}/** * Unpack network packet. */static voidlcs_get_skb(struct lcs_card *card, char *skb_data, unsigned int skb_len){	struct sk_buff *skb;	LCS_DBF_TEXT(5, trace, "getskb");	if (card->dev == NULL ||	    card->state != DEV_STATE_UP)		/* The card isn't up. Ignore the packet. */		return;	skb = dev_alloc_skb(skb_len);	if (skb == NULL) {		PRINT_ERR("LCS: alloc_skb failed for device=%s\n",			  card->dev->name);		card->stats.rx_dropped++;		return;	}	skb->dev = card->dev;	memcpy(skb_put(skb, skb_len), skb_data, skb_len);	skb->protocol =	card->lan_type_trans(skb, card->dev);	card->stats.rx_bytes += skb_len;	card->stats.rx_packets++;	*((__u32 *)skb->cb) = ++card->pkt_seq;	netif_rx(skb);}/** * LCS main routine to get packets and lancmd replies from the buffers */static voidlcs_get_frames_cb(struct lcs_channel *channel, struct lcs_buffer *buffer){	struct lcs_card *card;	struct lcs_header *lcs_hdr;	__u16 offset;	LCS_DBF_TEXT(5, trace, "lcsgtpkt");	lcs_hdr = (struct lcs_header *) buffer->data;	if (lcs_hdr->offset == LCS_ILLEGAL_OFFSET) {		LCS_DBF_TEXT(4, trace, "-eiogpkt");		return;	}	card = (struct lcs_card *)		((char *) channel - offsetof(struct lcs_card, read));	offset = 0;	while (lcs_hdr->offset != 0) {		if (lcs_hdr->offset <= 0 ||		    lcs_hdr->offset > LCS_IOBUFFERSIZE ||		    lcs_hdr->offset < offset) {			/* Offset invalid. */			card->stats.rx_length_errors++;			card->stats.rx_errors++;			return;		}		/* What kind of frame is it? */		if (lcs_hdr->type == LCS_FRAME_TYPE_CONTROL)			/* Control frame. */			lcs_get_control(card, (struct lcs_cmd *) lcs_hdr);		else if (lcs_hdr->type == LCS_FRAME_TYPE_ENET ||			 lcs_hdr->type == LCS_FRAME_TYPE_TR ||			 lcs_hdr->type == LCS_FRAME_TYPE_FDDI)			/* Normal network packet. */			lcs_get_skb(card, (char *)(lcs_hdr + 1),				    lcs_hdr->offset - offset -				    sizeof(struct lcs_header));		else			/* Unknown frame type. */			; // FIXME: error message ?		/* Proceed to next frame. */		offset = lcs_hdr->offset;		lcs_hdr->offset = LCS_ILLEGAL_OFFSET;		lcs_hdr = (struct lcs_header *) (buffer->data + offset);	}	/* The buffer is now empty. Make it ready again. */	lcs_ready_buffer(&card->read, buffer);}/** * get network statistics for ifconfig and other user programs */static struct net_device_stats *lcs_getstats(struct net_device *dev){	struct lcs_card *card;	LCS_DBF_TEXT(4, trace, "netstats");	card = (struct lcs_card *) dev->priv;	return &card->stats;}/** * stop lcs device * This function will be called by user doing ifconfig xxx down */static intlcs_stop_device(struct net_device *dev){	struct lcs_card *card;	int rc;	LCS_DBF_TEXT(2, trace, "stopdev");	card   = (struct lcs_card *) dev->priv;	netif_carrier_off(dev);	netif_tx_disable(dev);	dev->flags &= ~IFF_UP;	wait_event(card->write.wait_q,		(card->write.state != CH_STATE_RUNNING));	rc = lcs_stopcard(card);	if (rc)		PRINT_ERR("Try it again!\n ");	return rc;}/** * start lcs device and make it runnable * This function will be called by user doing ifconfig xxx up */static intlcs_open_device(struct net_device *dev){	struct lcs_card *card;	int rc;	LCS_DBF_TEXT(2, trace, "opendev");	card = (struct lcs_card *) dev->priv;	/* initialize statistics */	rc = lcs_detect(card);	if (rc) {		PRINT_ERR("LCS:Error in opening device!\n");	} else {		dev->flags |= IFF_UP;		netif_carrier_on(dev);		netif_wake_queue(dev);		card->state = DEV_STATE_UP;	}	return rc;}/** * show function for portno called by cat or similar things */static ssize_tlcs_portno_show (struct device *dev, struct device_attribute *attr, char *buf){        struct lcs_card *card;	card = (struct lcs_card *)dev->driver_data;        if (!card)                return 0;        return sprintf(buf, "%d\n", card->portno);}/** * store the value which is piped to file portno */static ssize_tlcs_portno_store (struct device *dev, struct device_attribute *attr, const char *buf, size_t count){        struct lcs_card *card;        int value;	card = (struct lcs_card *)dev->driver_data;        if (!card)                return 0;        sscanf(buf, "%u", &value);        /* TODO: sanity checks */        card->portno = value;        return count;}static DEVICE_ATTR(portno, 0644, lcs_portno_show, lcs_portno_store);static ssize_tlcs_type_show(struct device *dev, struct device_attribute *attr, char *buf){	struct ccwgroup_device *cgdev;	cgdev = to_ccwgroupdev(dev);	if (!cgdev)		return -ENODEV;	return sprintf(buf, "%s\n", cu3088_type[cgdev->cdev[0]->id.driver_info]);}static DEVICE_ATTR(type, 0444, lcs_type_show, NULL);static ssize_tlcs_timeout_show(struct device *dev, struct device_attribute *attr, char *buf){	struct lcs_card *card;	card = (struct lcs_card *)dev->driver_data;	return card ? sprintf(buf, "%u\n", card->lancmd_timeout) : 0;}static ssize_tlcs_timeout_store (struct device *dev, struct device_attribute *attr, const char *buf, size_t count){        struct lcs_card *card;        int value;	card = (struct lcs_card *)dev->driver_data;        if (!card)                return 0;        sscanf(buf, "%u", &value);        /* TODO: sanity checks */        card->lancmd_timeout = value;        return count;}DEVICE_ATTR(lancmd_timeout, 0644, lcs_timeout_show, lcs_timeout_store);static ssize_tlcs_dev_recover_store(struct device *dev, struct device_attribute *attr,		      const char *buf, size_t count){	struct lcs_card *card = dev->driver_data;	char *tmp;	int i;	if (!card)		return -EINVAL;	if (card->state != DEV_STATE_UP)		return -EPERM;	i = simple_strtoul(buf, &tmp, 16);	if (i == 1)		lcs_schedule_recovery(card);	return count;}static DEVICE_ATTR(recover, 0200, NULL, lcs_dev_recover_store);static struct attribute * lcs_attrs[] = {	&dev_attr_portno.attr,	&dev_attr_type.attr,	&dev_attr_lancmd_timeout.attr,	&dev_attr_recover.attr,	NULL,};static struct attribute_group lcs_attr_group = {	.attrs = lcs_attrs,};/** * lcs_probe_device is called on establishing a new ccwgroup_device. */static intlcs_probe_device(struct ccwgroup_device *ccwgdev){	struct lcs_card *card;	int ret;	if (!get_device(&ccwgdev->dev))		return -ENODEV;	LCS_DBF_TEXT(2, setup, "add_dev");        card = lcs_alloc_card();        if (!card) {                PRINT_ERR("Allocation of lcs card failed\n");		put_device(&ccwgdev->dev);                return -ENOMEM;        }	ret = sysfs_create_group(&ccwgdev->dev.kobj, &lcs_attr_group);	if (ret) {                PRINT_ERR("Creating attributes failed");		lcs_free_card(card);		put_device(&ccwgdev->dev);		return ret;        }	ccwgdev->dev.driver_data = card;	ccwgdev->cdev[0]->handler = lcs_irq;	ccwgdev->cdev[1]->handler = lcs_irq;	card->gdev = ccwgdev;	INIT_WORK(&card->kernel_thread_starter,		  (void *) lcs_start_kernel_thread, card);	card->thread_start_mask = 0;	card->thread_allowed_mask = 0;	card->thread_running_mask = 0;        return 0;}static intlcs_register_netdev(struct ccwgroup_device *ccwgdev){	struct lcs_card *card;	LCS_DBF_TEXT(2, setup, "regnetdv");	card = (struct lcs_card *)ccwgdev->dev.driver_data;	if (card->dev->reg_state != NETREG_UNINITIALIZED)		return 0;	SET_NETDEV_DEV(card->dev, &ccwgdev->dev);	return register_netdev(card->dev);}/** * lcs_new_device will be called by setting the group device online. */static intlcs_new_device(struct ccwgroup_device *ccwgdev){	struct  lcs_card *card;	struct net_device *dev=NULL;	enum lcs_dev_states recover_state;	int rc;	card = (struct lcs_card *)ccwgdev->dev.driver_data;	if (!card)		return -ENODEV;	LCS_DBF_TEXT(2, setup, "newdev");	LCS_DBF_HEX(3, setup, &card, sizeof(void*));	card->read.ccwdev  = ccwgdev->cdev[0];	card->write.ccwdev = ccwgdev->cdev[1];	recover_state = card->state;	ccw_device_set_online(card->read.ccwdev);	ccw_device_set_online(card->write.ccwdev);	LCS_DBF_TEXT(3, setup, "lcsnewdv");	lcs_setup_card(card);	rc = lcs_detect(card);	if (rc) {		LCS_DBF_TEXT(2, setup, "dtctfail");		PRINT_WARN("Detection of LCS card failed with return code "			   "%d (0x%x)\n", rc, rc);		lcs_stopcard(card);		goto out;	}	if (card->dev) {		LCS_DBF_TEXT(2, setup, "samedev");		LCS_DBF_HEX(3, setup, &card, sizeof(void*));		goto netdev_out;	}	switch (card->lan_type) {#ifdef CONFIG_NET_ETHERNET	case LCS_FRAME_TYPE_ENET:		card->lan_type_trans = eth_type_trans;		dev = alloc_etherdev(0);		break;#endif#ifdef CONFIG_TR	case LCS_FRAME_TYPE_TR:		card->lan_type_trans = tr_type_trans;		dev = alloc_trdev(0);		break;#endif#ifdef CONFIG_FDDI	case LCS_FRAME_TYPE_FDDI:		card->lan_type_trans = fddi_type_trans;		dev = alloc_fddidev(0);		break;#endif	default:		LCS_DBF_TEXT(3, setup, "errinit");		PRINT_ERR("LCS: Initialization failed\n");		PRINT_ERR("LCS: No device found!\n");		goto out;	}	if (!dev)		goto out;	card->dev = dev;	card->dev->priv = card;	card->dev->open = lcs_open_device;	card->dev->stop = lcs_stop_device;	card->dev->hard_start_xmit = lcs_start_xmit;	card->dev->get_stats = lcs_getstats;	SET_MODULE_OWNER(dev);	memcpy(card->dev->dev_addr, card->mac, LCS_MAC_LENGTH);#ifdef CONFIG_IP_MULTICAST	if (!lcs_check_multicast_support(card))		card->dev->set_multicast_list = lcs_set_multicast_list;#endifnetdev_out:	lcs_set_allowed_threads(card,0xffffffff);	if (recover_state == DEV_STATE_RECOVER) {		lcs_set_multicast_list(card->dev);		card->dev->flags |= IFF_UP;		netif_carrier_on(card->dev);		netif_wake_queue(card->dev);		card->state = DEV_STATE_UP;	} else {		lcs_stopcard(card);	}	if (lcs_register_netdev(ccwgdev) != 0)		goto out;	/* Print out supported assists: IPv6 */	PRINT_INFO("LCS device %s %s IPv6 support\n", card->dev->name,		   (card->ip_assists_supported & LCS_IPASS_IPV6_SUPPORT) ?		   "with" : "without");	/* Print out supported assist: Multicast */	PRINT_INFO("LCS device %s %s Multicast support\n", card->dev->name,		   (card->ip_assists_supported & LCS_IPASS_MULTICAST_SUPPORT) ?		   "with" : "without");	return 0;out:	ccw_device_set_offline(card->read.ccwdev);	ccw_device_set_offline(card->write.ccwdev);	return -ENODEV;}/** * lcs_shutdown_device, called when setting the group device offline. */static int__lcs_shutdown_device(struct ccwgroup_device *ccwgdev, int recovery_mode){	struct lcs_card *card;	enum lcs_dev_states recover_state;	int ret;	LCS_DBF_TEXT(3, setup, "shtdndev");	card = (struct lcs_card *)ccwgdev->dev.driver_data;	if (!card)		return -ENODEV;	if (recovery_mode == 0) {		lcs_set_allowed_threads(card, 0);		if (lcs_wait_for_threads(card, LCS_SET_MC_THREAD))			return -ERESTARTSYS;	}	LCS_DBF_HEX(3, setup, &card, sizeof(void*));	recover_state = card->state;	ret = lcs_stop_device(card->dev);	ret = ccw_device_set_offline(card->read.ccwdev);	ret = ccw_device_set_offline(card->write.ccwdev);	if (recover_state == DEV_STATE_UP) {		card->state = DEV_STATE_RECOVER;	}	if (ret)		return ret;	return 0;}static intlcs_shutdown_device(struct ccwgroup_device *ccwgdev){	return __lcs_shutdown_device(ccwgdev, 0);}/** * drive lcs recovery after startup and startlan initiated by Lan Gateway */static intlcs_recovery(void *ptr){	struct lcs_card *card;	struct ccwgroup_device *gdev;        int rc;	card = (struct lcs_card *) ptr;	daemonize("lcs_recover");	LCS_DBF_TEXT(4, trace, "recover1");	if (!lcs_do_run_thread(card, LCS_RECOVERY_THREAD))		return 0;	LCS_DBF_TEXT(4, trace, "recover2");	gdev = card->gdev;	PRINT_WARN("Recovery of device %s started...\n", gdev->dev.bus_id);	rc = __lcs_shutdown_device(gdev, 1);	rc = lcs_new_device(gdev);	if (!rc)		PRINT_INFO("Device %s successfully recovered!\n",				card->dev->name);	else		PRINT_INFO("Device %s could not be recovered!\n",				card->dev->name);	lcs_clear_thread_running_bit(card, LCS_RECOVERY_THREAD);	return 0;}/** * lcs_remove_device, free buffers and card */static voidlcs_remove_device(struct ccwgroup_device *ccwgdev){	struct lcs_card *card;	card = (struct lcs_card *)ccwgdev->dev.driver_data;	if (!card)		return;	PRINT_INFO("Removing lcs group device ....\n");	LCS_DBF_TEXT(3, setup, "remdev");	LCS_DBF_HEX(3, setup, &card, sizeof(void*));	if (ccwgdev->state == CCWGROUP_ONLINE) {		lcs_shutdown_device(ccwgdev);	}	if (card->dev)		unregister_netdev(card->dev);	sysfs_remove_group(&ccwgdev->dev.kobj, &lcs_attr_group);	lcs_cleanup_card(card);	lcs_free_card(card);	put_device(&ccwgdev->dev);}/** * LCS ccwgroup driver registration */static struct ccwgroup_driver lcs_group_driver = {	.owner       = THIS_MODULE,	.name        = "lcs",	.max_slaves  = 2,	.driver_id   = 0xD3C3E2,	.probe       = lcs_probe_device,	.remove      = lcs_remove_device,	.set_online  = lcs_new_device,	.set_offline = lcs_shutdown_device,};/** *  LCS Module/Kernel initialization function */static int__init lcs_init_module(void){	int rc;	PRINT_INFO("Loading %s\n",version);	rc = lcs_register_debug_facility();	LCS_DBF_TEXT(0, setup, "lcsinit");	if (rc) {		PRINT_ERR("Initialization failed\n");		return rc;	}	rc = register_cu3088_discipline(&lcs_group_driver);	if (rc) {		PRINT_ERR("Initialization failed\n");		return rc;	}	return 0;}/** *  LCS module cleanup function */static void__exit lcs_cleanup_module(void){	PRINT_INFO("Terminating lcs module.\n");	LCS_DBF_TEXT(0, trace, "cleanup");	unregister_cu3088_discipline(&lcs_group_driver);	lcs_unregister_debug_facility();}module_init(lcs_init_module);module_exit(lcs_cleanup_module);MODULE_AUTHOR("Frank Pavlic <fpavlic@de.ibm.com>");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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