sdla_ppp.c

来自「powerpc内核mpc8241linux系统下net驱动程序」· C语言 代码 · 共 2,069 行 · 第 1/5 页

C
2,069
字号
	dev->mem_start = (unsigned long)wandev->maddr;	dev->mem_end = dev->mem_start + wandev->msize - 1;	/* Set transmit buffer queue length */	dev->tx_queue_len = 100;	/* Initialize socket buffers */	dev_init_buffers(dev);	return 0;}/*============================================================================ * Open network interface. * o enable communications and interrupts. * o prevent module from unloading by incrementing use count * * Return 0 if O.k. or errno. */static int if_open(struct device *dev){	ppp_private_area_t *ppp_priv_area = dev->priv;	sdla_t *card = ppp_priv_area->card;	ppp_flags_t *flags = card->flags;	struct timeval tv;	int err = 0;	if (dev->start)		return -EBUSY;	/* only one open is allowed */	if (test_and_set_bit(0, (void *) &card->wandev.critical))		return -EAGAIN;	if ((card->hw.fwid == SFID_PPP502) ? config502(card) : config508(card)) {		err = -EIO;		card->wandev.critical = 0;		return err;	}	Intr_test_counter = 0;	err = intr_test(card);	if ((err) || (Intr_test_counter != (MAX_INTR_TEST_COUNTER + 1))) {		printk(KERN_INFO "%s: Interrupt Test Failed, Counter: %i\n",		       card->devname, Intr_test_counter);		err = -EIO;		card->wandev.critical = 0;		return err;	}	printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n",	       card->devname, Intr_test_counter);	/* Initialize Rx/Tx buffer control fields */	init_ppp_tx_rx_buff(card);	if (ppp_set_intr_mode(card, 0x03)) {		err = -EIO;		card->wandev.critical = 0;		return err;	}	flags->imask &= ~0x02;	if (ppp_comm_enable(card)) {		err = -EIO;		card->wandev.critical = 0;		return err;	}	wanpipe_set_state(card, WAN_CONNECTING);	wanpipe_open(card);	dev->mtu = min(dev->mtu, card->wandev.mtu);	dev->interrupt = 0;	dev->tbusy = 0;	dev->start = 1;	do_gettimeofday(&tv);	ppp_priv_area->router_start_time = tv.tv_sec;	card->wandev.critical = 0;	return err;}/*============================================================================ * Close network interface. * o if this is the last open, then disable communications and interrupts. * o reset flags. */static int if_close(struct device *dev){	ppp_private_area_t *ppp_priv_area = dev->priv;	sdla_t *card = ppp_priv_area->card;	if (test_and_set_bit(0, (void *) &card->wandev.critical))		return -EAGAIN;	dev->start = 0;	wanpipe_close(card);	wanpipe_set_state(card, WAN_DISCONNECTED);	ppp_set_intr_mode(card, 0);	ppp_comm_disable(card);	card->wandev.critical = 0;	return 0;}/*============================================================================ * Build media header. * * The trick here is to put packet type (Ethertype) into 'protocol' field of * the socket buffer, so that we don't forget it.  If packet type is not * supported, set skb->protocol to 0 and discard packet later. * * Return:	media header length. */static int if_header(struct sk_buff *skb, struct device *dev,	     unsigned short type, void *daddr, void *saddr, unsigned len){	switch (type) 	{		case ETH_P_IP:		case ETH_P_IPX:			skb->protocol = type;			break;		default:			skb->protocol = 0;	}	return PPP_HDR_LEN;}/*============================================================================ * Re-build media header. * * Return:	1	physical address resolved. *		0	physical address not resolved */static int if_rebuild_hdr(struct sk_buff *skb){	struct device *dev=skb->dev;	ppp_private_area_t *ppp_priv_area = dev->priv;	sdla_t *card = ppp_priv_area->card;	printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n",	       card->devname, dev->name);	return 1;}/*============================================================================ * Send a packet on a network interface. * o set tbusy flag (marks start of the transmission) to block a timer-based *   transmit from overlapping. * o check link state. If link is not up, then drop the packet. * o execute adapter send command. * 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 device *dev){	ppp_private_area_t *ppp_priv_area = dev->priv;	sdla_t *card = ppp_priv_area->card;	unsigned char *sendpacket;	unsigned long check_braddr, check_mcaddr;	unsigned long host_cpu_flags;	ppp_flags_t *flags = card->flags;	int retry = 0;	int err, udp_type;	++ppp_priv_area->if_send_entry;	if (skb == NULL) {		/* If we get here, some higher layer thinks we've missed an		 * tx-done interrupt.		 */		printk(KERN_INFO "%s: interface %s got kicked!\n",		       card->devname, dev->name);		++ppp_priv_area->if_send_skb_null;		mark_bh(NET_BH);		return 0;	}	if (dev->tbusy) {		/* If our device stays busy for at least 5 seconds then we will		 * kick start the device by making dev->tbusy = 0.  We expect 		 * that our device never stays busy more than 5 seconds. So this		 * is only used as a last resort. 		 */		++ppp_priv_area->if_send_busy;		++card->wandev.stats.collisions;		if ((jiffies - ppp_priv_area->tick_counter) < (5 * HZ)) {			return 1;		}		printk(KERN_INFO "%s: Transmit times out\n", card->devname);		++ppp_priv_area->if_send_busy_timeout;		/* unbusy the card (because only one interface per card) */		dev->tbusy = 0;	}	sendpacket = skb->data;	udp_type = udp_pkt_type(skb, card);	if (udp_type == UDP_DRVSTATS_TYPE) {		++ppp_priv_area->if_send_DRVSTATS_request;		process_udp_driver_call(UDP_PKT_FRM_STACK, card, skb, dev,					ppp_priv_area);		dev_kfree_skb(skb);		return 0;	} else if (udp_type == UDP_PTPIPE_TYPE)		++ppp_priv_area->if_send_PTPIPE_request;	/* retreive source address in two forms: broadcast & multicast */	check_braddr = sendpacket[15];	check_mcaddr = sendpacket[12];	check_braddr = check_braddr << 8;	check_mcaddr = check_mcaddr << 8;	check_braddr |= sendpacket[14];	check_mcaddr |= sendpacket[13];	check_braddr = check_braddr << 8;	check_mcaddr = check_mcaddr << 8;	check_braddr |= sendpacket[13];	check_mcaddr |= sendpacket[14];	check_braddr = check_braddr << 8;	check_mcaddr = check_mcaddr << 8;	check_braddr |= sendpacket[12];	check_mcaddr |= sendpacket[15];	/* if the Source Address is a Multicast address */	if ((ppp_priv_area->mc == WANOPT_NO) && (check_mcaddr >= 0xE0000001)	    && (check_mcaddr <= 0xFFFFFFFE)) {		printk(KERN_INFO "%s: Mutlicast Src. Addr. silently discarded\n"		       ,card->devname);		dev_kfree_skb(skb);		++ppp_priv_area->if_send_multicast;		++card->wandev.stats.tx_dropped;		return 0;	}	disable_irq(card->hw.irq);	++card->irq_dis_if_send_count;	if (test_and_set_bit(0, (void *) &card->wandev.critical)) {		if (card->wandev.critical == CRITICAL_IN_ISR) {			/* If the critical flag is set due to an Interrupt			 * then set enable transmit interrupt flag to enable			 * transmit interrupt. (delay interrupt)			 */			card->wandev.enable_tx_int = 1;			dev->tbusy = 1;			/* set the counter to see if we get the interrupt in			 * 5 seconds. 			 */			ppp_priv_area->tick_counter = jiffies;			++ppp_priv_area->if_send_critical_ISR;			save_flags(host_cpu_flags);			cli();			if ((!(--card->irq_dis_if_send_count)) &&			    (!card->irq_dis_poll_count))				enable_irq(card->hw.irq);			restore_flags(host_cpu_flags);			return 1;		}		dev_kfree_skb(skb);		++ppp_priv_area->if_send_critical_non_ISR;		save_flags(host_cpu_flags);		cli();		if ((!(--card->irq_dis_if_send_count)) &&		    (!card->irq_dis_poll_count))			enable_irq(card->hw.irq);		restore_flags(host_cpu_flags);		return 0;	}	if (udp_type == UDP_PTPIPE_TYPE) {		err = process_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb,					   dev, ppp_priv_area);	} else if (card->wandev.state != WAN_CONNECTED) {		++ppp_priv_area->if_send_wan_disconnected;		++card->wandev.stats.tx_dropped;	} else if (!skb->protocol) {		++ppp_priv_area->if_send_protocol_error;		++card->wandev.stats.tx_errors;	} else {		/*If it's IPX change the network numbers to 0 if they're ours. */		if (skb->protocol == ETH_P_IPX) {			if (card->wandev.enable_IPX) {				switch_net_numbers(skb->data,					 card->wandev.network_number, 0);			} else {				++card->wandev.stats.tx_dropped;				goto tx_done;			}		}		if (ppp_send(card, skb->data, skb->len, skb->protocol)) {			retry = 1;			dev->tbusy = 1;			++ppp_priv_area->if_send_adptr_bfrs_full;			++ppp_priv_area->if_send_tx_int_enabled;			ppp_priv_area->tick_counter = jiffies;			++card->wandev.stats.tx_errors;			flags->imask |= 0x02;	/* unmask Tx interrupts */		} else {			++ppp_priv_area->if_send_bfr_passed_to_adptr;			++card->wandev.stats.tx_packets;			card->wandev.stats.tx_bytes += skb->len;		}	}tx_done:	if (!retry) {		dev_kfree_skb(skb);	}	card->wandev.critical = 0;	save_flags(host_cpu_flags);	cli();	if ((!(--card->irq_dis_if_send_count)) && (!card->irq_dis_poll_count))		enable_irq(card->hw.irq);	restore_flags(host_cpu_flags);	return retry;}/*============================================================================ * Reply to UDP Management system. * Return length of reply. */static int reply_udp(unsigned char *data, unsigned int mbox_len){	unsigned short len, udp_length, temp, i, ip_length;	unsigned long sum;	/* Set length of packet */	len = mbox_len + 60;	/* fill in UDP reply */	data[36] = 0x02;	/* fill in UDP length */	udp_length = mbox_len + 40;	/* put it on an even boundary */	if (udp_length & 0x0001) {		udp_length += 1;		len += 1;	}	temp = (udp_length << 8) | (udp_length >> 8);	memcpy(&data[24], &temp, 2);	/* swap UDP ports */	memcpy(&temp, &data[20], 2);	memcpy(&data[20], &data[22], 2);	memcpy(&data[22], &temp, 2);	/* add UDP pseudo header */	temp = 0x1100;	memcpy(&data[udp_length + 20], &temp, 2);	temp = (udp_length << 8) | (udp_length >> 8);	memcpy(&data[udp_length + 22], &temp, 2);	/* calculate UDP checksum */	data[26] = data[27] = 0;	sum = 0;	for (i = 0; i < udp_length + 12; i += 2) {		memcpy(&temp, &data[12 + i], 2);		sum += (unsigned long) temp;	}	while (sum >> 16) {		sum = (sum & 0xffffUL) + (sum >> 16);	}	temp = (unsigned short) sum;	temp = ~temp;	if (temp == 0)		temp = 0xffff;	memcpy(&data[26], &temp, 2);	/* fill in IP length */	ip_length = udp_length + 20;	temp = (ip_length << 8) | (ip_length >> 8);	memcpy(&data[2], &temp, 2);	/* swap IP addresses */	memcpy(&temp, &data[12], 2);	memcpy(&data[12], &data[16], 2);	memcpy(&data[16], &temp, 2);	memcpy(&temp, &data[14], 2);	memcpy(&data[14], &data[18], 2);	memcpy(&data[18], &temp, 2);	/* fill in IP checksum */	data[10] = data[11] = 0;	sum = 0;	for (i = 0; i < 20; i += 2) {		memcpy(&temp, &data[i], 2);		sum += (unsigned long) temp;	}	while (sum >> 16) {		sum = (sum & 0xffffUL) + (sum >> 16);	}	temp = (unsigned short) sum;	temp = ~temp;	if (temp == 0)		temp = 0xffff;	memcpy(&data[10], &temp, 2);	return len;}				/* reply_udp *//*   If incoming is 0 (outgoing)- if the net numbers is ours make it 0   if incoming is 1 - if the net number is 0 make it ours  */static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming){	unsigned long pnetwork_number;	pnetwork_number = (unsigned long) ((sendpacket[6] << 24) +			   (sendpacket[7] << 16) + (sendpacket[8] << 8) +					   sendpacket[9]);	if (!incoming) {		/* If the destination network number is ours, make it 0 */		if (pnetwork_number == network_number) {			sendpacket[6] = sendpacket[7] = sendpacket[8] =			    sendpacket[9] = 0x00;		}	} else {		/* If the incoming network is 0, make it ours */		if (pnetwork_number == 0) {			sendpacket[6] = (unsigned char) (network_number >> 24);			sendpacket[7] = (unsigned char) ((network_number &						      0x00FF0000) >> 16);			sendpacket[8] = (unsigned char) ((network_number &						       0x0000FF00) >> 8);			sendpacket[9] = (unsigned char) (network_number &							 0x000000FF);		}	}	pnetwork_number = (unsigned long) ((sendpacket[18] << 24) +			 (sendpacket[19] << 16) + (sendpacket[20] << 8) +					   sendpacket[21]);	if (!incoming) {		/* If the source network is ours, make it 0 */		if (pnetwork_number == network_number) {			sendpacket[18] = sendpacket[19] = sendpacket[20] =			    sendpacket[21] = 0x00;

⌨️ 快捷键说明

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