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

📄 comx-proto-fr.c

📁 linux-2.4.29操作系统的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Frame-relay protocol module for the COMX driver  * for Linux 2.2.X * * Original author: Tivadar Szemethy <tiv@itc.hu> * Maintainer: Gergely Madarasz <gorgo@itc.hu> * * Copyright (C) 1998-1999 ITConsult-Pro Co. <info@itc.hu> *  * Contributors: * Arnaldo Carvalho de Melo <acme@conectiva.com.br> (0.73) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * * Version 0.70 (99/06/14): *		- cleaned up the source code a bit *		- ported back to kernel, now works as builtin code  * * Version 0.71 (99/06/25): *		- use skb priorities and queues for sending keepalive * 		- use device queues for slave->master data transmit *		- set IFF_RUNNING only line protocol up *		- fixes on slave device flags *  * Version 0.72 (99/07/09): *		- handle slave tbusy with master tbusy (should be fixed) *		- fix the keepalive timer addition/deletion * * Version 0.73 (00/08/15) * 		- resource release on failure at fr_master_init and *		  fr_slave_init 		   */#define VERSION "0.73"#include <linux/module.h>#include <linux/version.h>#include <linux/types.h>#include <linux/sched.h>#include <linux/netdevice.h>#include <linux/proc_fs.h>#include <linux/if_arp.h>#include <linux/inetdevice.h>#include <linux/pkt_sched.h>#include <linux/init.h>#include <asm/uaccess.h>#include "comx.h"#include "comxhw.h"MODULE_AUTHOR("Author: Tivadar Szemethy <tiv@itc.hu>");MODULE_DESCRIPTION("Frame Relay protocol implementation for the COMX drivers"	"for Linux kernel 2.4.X");MODULE_LICENSE("GPL");#define	FRAD_UI		0x03#define	NLPID_IP	0xcc#define	NLPID_Q933_LMI	0x08#define	NLPID_CISCO_LMI	0x09	#define Q933_ENQ	0x75#define	Q933_LINESTAT	0x51#define	Q933_COUNTERS	0x53#define	MAXALIVECNT	3		/* No. of failures */struct fr_data {	u16	dlci;	struct	net_device *master;	char	keepa_pend;	char	keepa_freq;	char	keepalivecnt, keeploopcnt;	struct	timer_list keepa_timer;	u8	local_cnt, remote_cnt;};static struct comx_protocol fr_master_protocol;static struct comx_protocol fr_slave_protocol;static struct comx_hardware fr_dlci;static void fr_keepalive_send(struct net_device *dev) {	struct comx_channel *ch = dev->priv;	struct fr_data *fr = ch->LINE_privdata;	struct sk_buff *skb;	u8 *fr_packet;		skb=alloc_skb(dev->hard_header_len + 13, GFP_ATOMIC);		if(skb==NULL)		return;                       skb_reserve(skb, dev->hard_header_len);                fr_packet=(u8*)skb_put(skb, 13);                 	fr_packet[0] = (fr->dlci & (1024 - 15)) >> 2;	fr_packet[1] = (fr->dlci & 15) << 4 | 1;	// EA bit 1	fr_packet[2] = FRAD_UI;	fr_packet[3] = NLPID_Q933_LMI;	fr_packet[4] = 0;	fr_packet[5] = Q933_ENQ;	fr_packet[6] = Q933_LINESTAT;	fr_packet[7] = 0x01;	fr_packet[8] = 0x01;	fr_packet[9] = Q933_COUNTERS;	fr_packet[10] = 0x02;	fr_packet[11] = ++fr->local_cnt;	fr_packet[12] = fr->remote_cnt;	skb->dev = dev;	skb->priority = TC_PRIO_CONTROL;	dev_queue_xmit(skb);}static void fr_keepalive_timerfun(unsigned long d) {	struct net_device *dev = (struct net_device *)d;	struct comx_channel *ch = dev->priv;	struct fr_data *fr = ch->LINE_privdata;	struct proc_dir_entry *dir = ch->procdir->parent->subdir;	struct comx_channel *sch;	struct fr_data *sfr;	struct net_device *sdev;	if (ch->init_status & LINE_OPEN) {		if (fr->keepalivecnt == MAXALIVECNT) {			comx_status(dev, ch->line_status & ~PROTO_UP);			dev->flags &= ~IFF_RUNNING;			for (; dir ; dir = dir->next) {				if(!S_ISDIR(dir->mode)) {				    continue;				}					if ((sdev = dir->data) && (sch = sdev->priv) && 				    (sdev->type == ARPHRD_DLCI) && 				    (sfr = sch->LINE_privdata) 				    && (sfr->master == dev) && 				    (sdev->flags & IFF_UP)) {					sdev->flags &= ~IFF_RUNNING;					comx_status(sdev, 						sch->line_status & ~PROTO_UP);				}			}		}		if (fr->keepalivecnt <= MAXALIVECNT) {			++fr->keepalivecnt;		}		fr_keepalive_send(dev);	}	mod_timer(&fr->keepa_timer, jiffies + HZ * fr->keepa_freq);}static void fr_rx_lmi(struct net_device *dev, struct sk_buff *skb, 	u16 dlci, u8 nlpid) {	struct comx_channel *ch = dev->priv;	struct fr_data *fr = ch->LINE_privdata;	struct proc_dir_entry *dir = ch->procdir->parent->subdir;	struct comx_channel *sch;	struct fr_data *sfr;	struct net_device *sdev;	if (dlci != fr->dlci || nlpid != NLPID_Q933_LMI || !fr->keepa_freq) {		return;	}	fr->remote_cnt = skb->data[7];	if (skb->data[8] == fr->local_cnt) { // keepalive UP!		fr->keepalivecnt = 0;		if ((ch->line_status & LINE_UP) && 		    !(ch->line_status & PROTO_UP)) {			comx_status(dev, ch->line_status |= PROTO_UP);			dev->flags |= IFF_RUNNING;			for (; dir ; dir = dir->next) {				if(!S_ISDIR(dir->mode)) {				    continue;				}					if ((sdev = dir->data) && (sch = sdev->priv) && 				    (sdev->type == ARPHRD_DLCI) && 				    (sfr = sch->LINE_privdata) 				    && (sfr->master == dev) && 				    (sdev->flags & IFF_UP)) {					sdev->flags |= IFF_RUNNING;					comx_status(sdev, 						sch->line_status | PROTO_UP);				}			}		}	}}static void fr_set_keepalive(struct net_device *dev, int keepa) {	struct comx_channel *ch = dev->priv;	struct fr_data *fr = ch->LINE_privdata;	if (!keepa && fr->keepa_freq) { // switch off		fr->keepa_freq = 0;		if (ch->line_status & LINE_UP) {			comx_status(dev, ch->line_status | PROTO_UP);			dev->flags |= IFF_RUNNING;			del_timer(&fr->keepa_timer);		}		return;	}	if (keepa) { // bekapcs		if(fr->keepa_freq && (ch->line_status & LINE_UP)) {			del_timer(&fr->keepa_timer);		}		fr->keepa_freq = keepa;		fr->local_cnt = fr->remote_cnt = 0;		fr->keepa_timer.expires = jiffies + HZ;		fr->keepa_timer.function = fr_keepalive_timerfun;		fr->keepa_timer.data = (unsigned long)dev;		ch->line_status &= ~(PROTO_UP | PROTO_LOOP);		dev->flags &= ~IFF_RUNNING;		comx_status(dev, ch->line_status);		if(ch->line_status & LINE_UP) {			add_timer(&fr->keepa_timer);		}	}}static void fr_rx(struct net_device *dev, struct sk_buff *skb) {	struct comx_channel *ch = dev->priv;	struct proc_dir_entry *dir = ch->procdir->parent->subdir;	struct net_device *sdev = dev;	struct comx_channel *sch;	struct fr_data *sfr;	u16 dlci;	u8 nlpid;	if(skb->len <= 4 || skb->data[2] != FRAD_UI) {		kfree_skb(skb);		return;	}	/* Itt majd ki kell talalni, melyik slave kapja a csomagot */	dlci = ((skb->data[0] & 0xfc) << 2) | ((skb->data[1] & 0xf0) >> 4);	if ((nlpid = skb->data[3]) == 0) { // Optional padding 		nlpid = skb->data[4];		skb_pull(skb, 1);	}	skb_pull(skb, 4);	/* DLCI and header throw away */	if (ch->debug_flags & DEBUG_COMX_DLCI) {		comx_debug(dev, "Frame received, DLCI: %d, NLPID: 0x%02x\n", 			dlci, nlpid);		comx_debug_skb(dev, skb, "Contents");	}	/* Megkeressuk, kihez tartozik */	for (; dir ; dir = dir->next) {		if(!S_ISDIR(dir->mode)) {			continue;		}		if ((sdev = dir->data) && (sch = sdev->priv) && 		    (sdev->type == ARPHRD_DLCI) && (sfr = sch->LINE_privdata) &&		    (sfr->master == dev) && (sfr->dlci == dlci)) {			skb->dev = sdev;				if (ch->debug_flags & DEBUG_COMX_DLCI) {				comx_debug(dev, "Passing it to %s\n",sdev->name);			}			if (dev != sdev) {				sch->stats.rx_packets++;				sch->stats.rx_bytes += skb->len;			}			break;		}	}	switch(nlpid) {		case NLPID_IP:			skb->protocol = htons(ETH_P_IP);			skb->mac.raw = skb->data;			comx_rx(sdev, skb);			break;		case NLPID_Q933_LMI:			fr_rx_lmi(dev, skb, dlci, nlpid);		default:			kfree_skb(skb);			break;	}}static int fr_tx(struct net_device *dev) {	struct comx_channel *ch = dev->priv;	struct proc_dir_entry *dir = ch->procdir->parent->subdir;	struct net_device *sdev;	struct comx_channel *sch;	struct fr_data *sfr;	int cnt = 1;	/* Ha minden igaz, 2 helyen fog allni a tbusy: a masternel, 	   es annal a slave-nel aki eppen kuldott.	   Egy helyen akkor all, ha a master kuldott.	   Ez megint jo lesz majd, ha utemezni akarunk */	   	/* This should be fixed, the slave tbusy should be set when 	   the masters queue is full and reset when not */	for (; dir ; dir = dir->next) {		if(!S_ISDIR(dir->mode)) {		    continue;		}		if ((sdev = dir->data) && (sch = sdev->priv) && 		    (sdev->type == ARPHRD_DLCI) && (sfr = sch->LINE_privdata) &&		    (sfr->master == dev) && (netif_queue_stopped(sdev))) {		    	netif_wake_queue(sdev);			cnt++;		}	}	netif_wake_queue(dev);	return 0;}static void fr_status(struct net_device *dev, unsigned short status){	struct comx_channel *ch = dev->priv;	struct fr_data *fr = ch->LINE_privdata;	struct proc_dir_entry *dir = ch->procdir->parent->subdir;	struct net_device *sdev;	struct comx_channel *sch;	struct fr_data *sfr;	if (status & LINE_UP) {		if (!fr->keepa_freq) {			status |= PROTO_UP;		}	} else {		status &= ~(PROTO_UP | PROTO_LOOP);	}	if (dev == fr->master && fr->keepa_freq) {		if (status & LINE_UP) {			fr->keepa_timer.expires = jiffies + HZ;			add_timer(&fr->keepa_timer);			fr->keepalivecnt = MAXALIVECNT + 1;			fr->keeploopcnt = 0;		} else {			del_timer(&fr->keepa_timer);		}	}			/* Itt a status valtozast vegig kell vinni az osszes slave-n */	for (; dir ; dir = dir->next) {		if(!S_ISDIR(dir->mode)) {		    continue;		}			if ((sdev = dir->data) && (sch = sdev->priv) && 		    (sdev->type == ARPHRD_FRAD || sdev->type == ARPHRD_DLCI) && 		    (sfr = sch->LINE_privdata) && (sfr->master == dev)) {			if(status & LINE_UP) {				netif_wake_queue(sdev);			}			comx_status(sdev, status);			if(status & (PROTO_UP | PROTO_LOOP)) {				dev->flags |= IFF_RUNNING;			} else {				dev->flags &= ~IFF_RUNNING;			}		}	}}static int fr_open(struct net_device *dev){	struct comx_channel *ch = dev->priv;	struct fr_data *fr = ch->LINE_privdata;	struct proc_dir_entry *comxdir = ch->procdir;	struct comx_channel *mch;	if (!(ch->init_status & HW_OPEN)) {		return -ENODEV;	}	if ((ch->hardware == &fr_dlci && ch->protocol != &fr_slave_protocol) ||	    (ch->protocol == &fr_slave_protocol && ch->hardware != &fr_dlci)) {		printk(KERN_ERR "Trying to open an improperly set FR interface, giving up\n");		return -EINVAL;	}	if (!fr->master) {		return -ENODEV;	}	mch = fr->master->priv;	if (fr->master != dev && (!(mch->init_status & LINE_OPEN) 	   || (mch->protocol != &fr_master_protocol))) {		printk(KERN_ERR "Master %s is inactive, or incorrectly set up, "			"unable to open %s\n", fr->master->name, dev->name);		return -ENODEV;	}	ch->init_status |= LINE_OPEN;	ch->line_status &= ~(PROTO_UP | PROTO_LOOP);	dev->flags &= ~IFF_RUNNING;	if (fr->master == dev) {		if (fr->keepa_freq) {			fr->keepa_timer.function = fr_keepalive_timerfun;			fr->keepa_timer.data = (unsigned long)dev;			add_timer(&fr->keepa_timer);		} else {			if (ch->line_status & LINE_UP) {				ch->line_status |= PROTO_UP;				dev->flags |= IFF_RUNNING;			}		}	} else {		ch->line_status = mch->line_status;		if(fr->master->flags & IFF_RUNNING) {			dev->flags |= IFF_RUNNING;		}	}	for (; comxdir ; comxdir = comxdir->next) {		if (strcmp(comxdir->name, FILENAME_DLCI) == 0 ||		   strcmp(comxdir->name, FILENAME_MASTER) == 0 ||		   strcmp(comxdir->name, FILENAME_KEEPALIVE) == 0) {			comxdir->mode = S_IFREG | 0444;		}	}//	comx_status(dev, ch->line_status);	return 0;}static int fr_close(struct net_device *dev){	struct comx_channel *ch = dev->priv;	struct fr_data *fr = ch->LINE_privdata;	struct proc_dir_entry *comxdir = ch->procdir;	if (fr->master == dev) { // Ha master 		struct proc_dir_entry *dir = ch->procdir->parent->subdir;		struct net_device *sdev = dev;		struct comx_channel *sch;		struct fr_data *sfr;		if (!(ch->init_status & HW_OPEN)) {			return -ENODEV;		}		if (fr->keepa_freq) {			del_timer(&fr->keepa_timer);		}				for (; dir ; dir = dir->next) {			if(!S_ISDIR(dir->mode)) {				continue;			}			if ((sdev = dir->data) && (sch = sdev->priv) && 			    (sdev->type == ARPHRD_DLCI) && 			    (sfr = sch->LINE_privdata) &&			    (sfr->master == dev) && 			    (sch->init_status & LINE_OPEN)) {				dev_close(sdev);			}		}	}	ch->init_status &= ~LINE_OPEN;	ch->line_status &= ~(PROTO_UP | PROTO_LOOP);	dev->flags &= ~IFF_RUNNING;	for (; comxdir ; comxdir = comxdir->next) {		if (strcmp(comxdir->name, FILENAME_DLCI) == 0 ||		    strcmp(comxdir->name, FILENAME_MASTER) == 0 ||		    strcmp(comxdir->name, FILENAME_KEEPALIVE) == 0) {			comxdir->mode = S_IFREG | 0444;		}	}	return 0;}static int fr_xmit(struct sk_buff *skb, struct net_device *dev){	struct comx_channel *ch = dev->priv;	struct comx_channel *sch, *mch;	struct fr_data *fr = ch->LINE_privdata;	struct fr_data *sfr;	struct net_device *sdev;	struct proc_dir_entry *dir = ch->procdir->parent->subdir;	if (!fr->master) {		printk(KERN_ERR "BUG: fr_xmit without a master!!! dev: %s\n", dev->name);		return 0;	}	mch = fr->master->priv;	/* Ennek majd a slave utemezeskor lesz igazan jelentosege */	if (ch->debug_flags & DEBUG_COMX_DLCI) {		comx_debug_skb(dev, skb, "Sending frame");	}	if (dev != fr->master) {		struct sk_buff *newskb=skb_clone(skb, GFP_ATOMIC);		if (!newskb)			return -ENOMEM;

⌨️ 快捷键说明

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