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

📄 hdlc.c

📁 上传linux-jx2410的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	reptype = skb->data[i++];	if (skb->data[i]!=	    (mode_is(hdlc, MODE_FR_CCITT) ? LMI_CCITT_ALIVE : LMI_ALIVE)) {		printk(KERN_INFO "%s: Unsupported status element=%x\n",		       hdlc_to_name(hdlc), skb->data[i]);		return 1;	}	i++;	i++;			/* Skip length field */	hdlc->lmi.rxseq = skb->data[i++]; /* TX sequence from peer */	rxseq = skb->data[i++];	/* Should confirm our sequence */	txseq = hdlc->lmi.txseq;	if (mode_is(hdlc, MODE_DCE)) {		if (reptype != LMI_FULLREP && reptype != LMI_INTEGRITY) {			printk(KERN_INFO "%s: Unsupported report type=%x\n",			       hdlc_to_name(hdlc), reptype);			return 1;		}	}	error = 0;	if (!(hdlc->lmi.state & LINK_STATE_RELIABLE))		error = 1;	if (rxseq == 0 || rxseq != txseq) {		hdlc->lmi.N391cnt = 0; /* Ask for full report next time */		error = 1;	}	if (mode_is(hdlc, MODE_DCE)) {		if ((hdlc->lmi.state & LINK_STATE_FULLREP_SENT) && !error) {/* Stop sending full report - the last one has been confirmed by DTE */			hdlc->lmi.state &= ~LINK_STATE_FULLREP_SENT;			pvc = hdlc->first_pvc;			while (pvc) {				if (pvc->state & PVC_STATE_NEW) {					pvc->state &= ~PVC_STATE_NEW;					pvc->state |= PVC_STATE_ACTIVE;					fr_log_dlci_active(pvc);/* Tell DTE that new PVC is now active */					hdlc->lmi.state |= LINK_STATE_CHANGED;				}				pvc = pvc->next;			}		}		if (hdlc->lmi.state & LINK_STATE_CHANGED) {			reptype = LMI_FULLREP;			hdlc->lmi.state |= LINK_STATE_FULLREP_SENT;			hdlc->lmi.state &= ~LINK_STATE_CHANGED;		}		fr_lmi_send(hdlc, reptype == LMI_FULLREP ? 1 : 0);		return 0;	}	/* DTE */	if (reptype != LMI_FULLREP || error)		return 0;	stat_len = 3;	pvc = hdlc->first_pvc;	while (pvc) {		pvc->newstate = 0;		pvc = pvc->next;	}	while (skb->len >= i + 2 + stat_len) {		u16 dlci;		u8 state = 0;		if (skb->data[i] != (mode_is(hdlc, MODE_FR_CCITT) ?				     LMI_CCITT_PVCSTAT : LMI_PVCSTAT)) {			printk(KERN_WARNING "%s: Invalid PVCSTAT ID: %x\n",			       hdlc_to_name(hdlc), skb->data[i]);			return 1;		}		i++;		if (skb->data[i] != stat_len) {			printk(KERN_WARNING "%s: Invalid PVCSTAT length: %x\n",			       hdlc_to_name(hdlc), skb->data[i]);			return 1;		}		i++;		dlci = status_to_dlci(hdlc, skb->data+i, &state);		pvc = find_pvc(hdlc, dlci);		if (pvc)			pvc->newstate = state;		else if (state == PVC_STATE_NEW)			printk(KERN_INFO "%s: new PVC available, DLCI=%u\n",			       hdlc_to_name(hdlc), dlci);		i += stat_len;	}	pvc = hdlc->first_pvc;	while (pvc) {		if (pvc->newstate == PVC_STATE_NEW)			pvc->newstate = PVC_STATE_ACTIVE;		pvc->newstate |= (pvc->state &				  ~(PVC_STATE_NEW|PVC_STATE_ACTIVE));		if (pvc->state != pvc->newstate) {			pvc->state = pvc->newstate;			fr_log_dlci_active(pvc);		}		pvc = pvc->next;	}	/* Next full report after N391 polls */	hdlc->lmi.N391cnt = hdlc->lmi.N391;	return 0;}static void fr_netif(hdlc_device *hdlc, struct sk_buff *skb){	fr_hdr *fh = (fr_hdr*)skb->data;	u8 *data = skb->data;	u16 dlci;	pvc_device *pvc;	if (skb->len<4 || fh->ea1 || data[2] != FR_UI)		goto rx_error;	dlci = q922_to_dlci(skb->data);	if (dlci == LMI_DLCI) {		if (data[3] == LMI_PROTO) {			if (fr_lmi_recv(hdlc, skb))				goto rx_error;			else {				/* No request pending */				hdlc->lmi.state &= ~LINK_STATE_REQUEST;				hdlc->lmi.last_poll = jiffies;				dev_kfree_skb_any(skb);				return;			}		}		printk(KERN_INFO "%s: Received non-LMI frame with LMI DLCI\n",		       hdlc_to_name(hdlc));		goto rx_error;	}	pvc = find_pvc(hdlc, dlci);	if (!pvc) {#ifdef DEBUG_PKT		printk(KERN_INFO "%s: No PVC for received frame's DLCI %d\n",		       hdlc_to_name(hdlc), dlci);#endif		goto rx_error;	}	if ((pvc->netdev.flags & IFF_UP) == 0) {#ifdef DEBUG_PKT		printk(KERN_INFO "%s: PVC for received frame's DLCI %d is down\n",		       hdlc_to_name(hdlc), dlci);#endif		goto rx_error;	}	pvc->stats.rx_packets++; /* PVC traffic */	pvc->stats.rx_bytes += skb->len;	if ((pvc->state & PVC_STATE_FECN) != (fh->fecn ? PVC_STATE_FECN : 0)) {#ifdef DEBUG_FECN		printk(KERN_DEBUG "%s: FECN O%s\n", pvc_to_name(pvc),		       fh->fecn ? "N" : "FF");#endif		pvc->state ^= PVC_STATE_FECN;	}	if ((pvc->state & PVC_STATE_BECN) != (fh->becn ? PVC_STATE_BECN : 0)) {#ifdef DEBUG_FECN		printk(KERN_DEBUG "%s: BECN O%s\n", pvc_to_name(pvc),		       fh->becn ? "N" : "FF");#endif		pvc->state ^= PVC_STATE_BECN;	}	if (pvc->state & PVC_STATE_BECN)		pvc->stats.rx_compressed++;	if (data[3] == NLPID_IP) {		skb_pull(skb, 4); /* Remove 4-byte header (hdr, UI, NLPID) */		skb->protocol = htons(ETH_P_IP);		skb->dev = &pvc->netdev;		netif_rx(skb);		return;	}	if (data[3] == NLPID_IPV6) {		skb_pull(skb, 4); /* Remove 4-byte header (hdr, UI, NLPID) */		skb->protocol = htons(ETH_P_IPV6);		skb->dev = &pvc->netdev;		netif_rx(skb);		return;	}	if (data[3] == FR_PAD && data[4] == NLPID_SNAP && data[5] == FR_PAD &&	    data[6] == FR_PAD && data[7] == FR_PAD &&	    ((data[8]<<8) | data[9]) == ETH_P_ARP) {		skb_pull(skb, 10);		skb->protocol = htons(ETH_P_ARP);		skb->dev = &pvc->netdev;		netif_rx(skb);		return;	}	printk(KERN_INFO "%s: Unusupported protocol %x\n",	       hdlc_to_name(hdlc), data[3]);	dev_kfree_skb_any(skb);	return; rx_error:	hdlc->stats.rx_errors++; /* Mark error */	dev_kfree_skb_any(skb);}static void fr_cisco_open(hdlc_device *hdlc){	hdlc->lmi.state = LINK_STATE_CHANGED;	hdlc->lmi.txseq = hdlc->lmi.rxseq = 0;	hdlc->lmi.last_errors = 0xFFFFFFFF;	hdlc->lmi.N391cnt = 0;	init_timer(&hdlc->timer);	hdlc->timer.expires = jiffies + HZ; /* First poll after 1 second */	hdlc->timer.function = mode_is(hdlc, MODE_FR) ? fr_timer : cisco_timer;	hdlc->timer.data = (unsigned long)hdlc;	add_timer(&hdlc->timer);}static void fr_cisco_close(hdlc_device *hdlc){	pvc_device *pvc = hdlc->first_pvc;	del_timer_sync(&hdlc->timer);	while(pvc) {		/* NULL in Cisco mode */		dev_close(&pvc->netdev); /* Shutdown all PVCs for this FRAD */		pvc = pvc->next;	}}/****************************************************************** * *     generic HDLC routines * *****************************************************************/static int hdlc_change_mtu(struct net_device *dev, int new_mtu){	if ((new_mtu < 68) || (new_mtu > HDLC_MAX_MTU))		return -EINVAL;	dev->mtu = new_mtu;	return 0;}/******************************************************** * * PVC device routines * *******************************************************/static int pvc_open(struct net_device *dev){	pvc_device *pvc = dev_to_pvc(dev);	int result = 0;	if ((hdlc_to_dev(pvc->master)->flags & IFF_UP) == 0)		return -EIO;  /* Master must be UP in order to activate PVC */	memset(&(pvc->stats), 0, sizeof(struct net_device_stats));	pvc->state = 0;	if (!mode_is(pvc->master, MODE_SOFT) && pvc->master->open_pvc)		result = pvc->master->open_pvc(pvc);	if (result)		return result;	pvc->master->lmi.state |= LINK_STATE_CHANGED;	return 0;}static int pvc_close(struct net_device *dev){	pvc_device *pvc = dev_to_pvc(dev);	pvc->state = 0;	if (!mode_is(pvc->master, MODE_SOFT) && pvc->master->close_pvc)		pvc->master->close_pvc(pvc);	pvc->master->lmi.state |= LINK_STATE_CHANGED;	return 0;}static int pvc_xmit(struct sk_buff *skb, struct net_device *dev){	pvc_device *pvc = dev_to_pvc(dev);	if (pvc->state & PVC_STATE_ACTIVE) {		skb->dev = hdlc_to_dev(pvc->master);		pvc->stats.tx_bytes += skb->len;		pvc->stats.tx_packets++;		if (pvc->state & PVC_STATE_FECN)			pvc->stats.tx_compressed++; /* TX Congestion counter */		dev_queue_xmit(skb);	} else {		pvc->stats.tx_dropped++;		dev_kfree_skb(skb);	}	return 0;}static struct net_device_stats *pvc_get_stats(struct net_device *dev){	pvc_device *pvc = dev_to_pvc(dev);	return &pvc->stats;}static int pvc_change_mtu(struct net_device *dev, int new_mtu){	if ((new_mtu < 68) || (new_mtu > HDLC_MAX_MTU))		return -EINVAL;	dev->mtu = new_mtu;	return 0;}static void destroy_pvc_list(hdlc_device *hdlc){	pvc_device *pvc = hdlc->first_pvc;	while(pvc) {		pvc_device *next = pvc->next;		unregister_netdevice(&pvc->netdev);		kfree(pvc);		pvc = next;	}	hdlc->first_pvc = NULL;	/* All PVCs destroyed */	hdlc->pvc_count = 0;	hdlc->lmi.state |= LINK_STATE_CHANGED;}/******************************************************** * * X.25 protocol support routines * *******************************************************/#ifdef CONFIG_HDLC_X25/* These functions are callbacks called by LAPB layer */void x25_connect_disconnect(void *token, int reason, int code){	hdlc_device *hdlc = token;	struct sk_buff *skb;	unsigned char *ptr;	if ((skb = dev_alloc_skb(1)) == NULL) {		printk(KERN_ERR "%s: out of memory\n", hdlc_to_name(hdlc));		return;	}	ptr = skb_put(skb, 1);	*ptr = code;	skb->dev = hdlc_to_dev(hdlc);	skb->protocol = htons(ETH_P_X25);	skb->mac.raw = skb->data;	skb->pkt_type = PACKET_HOST;	netif_rx(skb);}void x25_connected(void *token, int reason){	x25_connect_disconnect(token, reason, 1);}void x25_disconnected(void *token, int reason){	x25_connect_disconnect(token, reason, 2);}int x25_data_indication(void *token, struct sk_buff *skb){	hdlc_device *hdlc = token;	unsigned char *ptr;	ptr = skb_push(skb, 1);	*ptr = 0;	skb->dev = hdlc_to_dev(hdlc);	skb->protocol = htons(ETH_P_X25);	skb->mac.raw = skb->data;	skb->pkt_type = PACKET_HOST;	return netif_rx(skb);}void x25_data_transmit(void *token, struct sk_buff *skb){	hdlc_device *hdlc = token;	hdlc->xmit(hdlc, skb);	/* Ignore return value :-( */}#endif /* CONFIG_HDLC_X25 *//******************************************************** * * HDLC device routines * *******************************************************/static int hdlc_open(struct net_device *dev){	hdlc_device *hdlc = dev_to_hdlc(dev);	int result;	if (hdlc->mode == MODE_NONE)		return -ENOSYS;	memset(&(hdlc->stats), 0, sizeof(struct net_device_stats));	if (mode_is(hdlc, MODE_FR | MODE_SOFT) ||	    mode_is(hdlc, MODE_CISCO | MODE_SOFT))		fr_cisco_open(hdlc);#ifdef CONFIG_HDLC_PPP	else if (mode_is(hdlc, MODE_PPP | MODE_SOFT)) {		sppp_attach(&hdlc->pppdev);		/* sppp_attach nukes them. We don't need syncppp's ioctl */		dev->do_ioctl = hdlc_ioctl;		hdlc->pppdev.sppp.pp_flags &= ~PP_CISCO;		dev->type = ARPHRD_PPP;		result = sppp_open(dev);		if (result) {			sppp_detach(dev);			return result;		}	}#endif#ifdef CONFIG_HDLC_X25

⌨️ 快捷键说明

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