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

📄 hdlc_fr.c

📁 一个2.4.21版本的嵌入式linux内核
💻 C
📖 第 1 页 / 共 2 页
字号:
		if (hdlc->state.fr.changed) {			reptype = LMI_FULLREP;			hdlc->state.fr.fullrep_sent = 1;			hdlc->state.fr.changed = 0;		}		fr_lmi_send(hdlc, reptype == LMI_FULLREP ? 1 : 0);		return 0;	}	/* DTE */	if (reptype != LMI_FULLREP || error)		return 0;	stat_len = 3;	pvc = hdlc->state.fr.first_pvc;	while (pvc) {		pvc->state.deleted = pvc->state.active; /* mark active PVCs */		pvc = pvc->next;	}	while (skb->len >= i + 2 + stat_len) {		u16 dlci;		int active, new;		if (skb->data[i] != ((hdlc->state.fr.settings.lmi == LMI_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, &active, &new);		pvc = find_pvc(hdlc, dlci);		active |= new;		if (pvc) {			if (active && !pvc->state.active &&			    (pvc->netdev.flags & IFF_UP)) {				pvc->state.active = active;				fr_log_dlci_active(pvc);			}			pvc->state.deleted = 0;		}		else if (new)			printk(KERN_INFO "%s: new PVC available, DLCI=%u\n",			       hdlc_to_name(hdlc), dlci);		i += stat_len;	}	pvc = hdlc->state.fr.first_pvc;	while (pvc) {		if (pvc->state.deleted) {			pvc->state.active = pvc->state.new = 0;			fr_log_dlci_active(pvc);			pvc->state.deleted = 0;		}		pvc = pvc->next;	}	/* Next full report after N391 polls */	hdlc->state.fr.n391cnt = hdlc->state.fr.settings.n391;	return 0;}static void fr_rx(struct sk_buff *skb){	hdlc_device *hdlc = dev_to_hdlc(skb->dev);	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 (hdlc->state.fr.settings.lmi == LMI_NONE)			goto rx_error; /* LMI packet with no LMI? */		if (data[3] == LMI_PROTO) {			if (fr_lmi_recv(hdlc, skb))				goto rx_error;			else {				/* No request pending */				hdlc->state.fr.request = 0;				hdlc->state.fr.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 CONFIG_HDLC_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 CONFIG_HDLC_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.fecn != (fh->fecn ? PVC_STATE_FECN : 0)) {#ifdef CONFIG_HDLC_DEBUG_ECN		printk(KERN_DEBUG "%s: FECN O%s\n", pvc_to_name(pvc),		       fh->fecn ? "N" : "FF");#endif		pvc->state.fecn ^= 1;	}	if (pvc->state.becn != (fh->becn ? PVC_STATE_BECN : 0)) {#ifdef CONFIG_HDLC_DEBUG_ECN		printk(KERN_DEBUG "%s: BECN O%s\n", pvc_to_name(pvc),		       fh->becn ? "N" : "FF");#endif		pvc->state.becn ^= 1;	}	if (pvc->state.becn)		pvc->stats.rx_compressed++;	skb->dev = &pvc->netdev;	if (data[3] == NLPID_IP) {		skb_pull(skb, 4); /* Remove 4-byte header (hdr, UI, NLPID) */		skb->protocol = htons(ETH_P_IP);		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);		netif_rx(skb);		return;	}	if (data[3] == FR_PAD && data[4] == NLPID_SNAP && data[5] == FR_PAD) {		u16 oui = ntohs(*(u16*)(data + 6));		u16 pid = ntohs(*(u16*)(data + 8));		skb_pull(skb, 10);		switch ((((u32)oui) << 16) | pid) {		case ETH_P_ARP: /* routed frame with SNAP */		case ETH_P_IPX:		case ETH_P_IP:	/* a long variant */		case ETH_P_IPV6:			skb->protocol = htons(pid);			break;		default:			printk(KERN_INFO "%s: Unsupported protocol, OUI=%x "			       "PID=%x\n", hdlc_to_name(hdlc), oui, pid);			dev_kfree_skb_any(skb);			return;		}		netif_rx(skb);		return;	}	printk(KERN_INFO "%s: Unsupported protocol, NLPID=%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 int fr_open(hdlc_device *hdlc){	if (hdlc->state.fr.settings.lmi != LMI_NONE) {		hdlc->state.fr.last_poll = 0;		hdlc->state.fr.reliable = 0;		hdlc->state.fr.changed = 1;		hdlc->state.fr.request = 0;		hdlc->state.fr.fullrep_sent = 0;		hdlc->state.fr.last_errors = 0xFFFFFFFF;		hdlc->state.fr.n391cnt = 0;		hdlc->state.fr.txseq = hdlc->state.fr.rxseq = 0;		init_timer(&hdlc->state.fr.timer);		/* First poll after 1 s */		hdlc->state.fr.timer.expires = jiffies + HZ;		hdlc->state.fr.timer.function = fr_timer;		hdlc->state.fr.timer.data = (unsigned long)hdlc;		add_timer(&hdlc->state.fr.timer);	} else		hdlc->state.fr.reliable = 1;	return 0;}static void fr_close(hdlc_device *hdlc){	pvc_device *pvc = hdlc->state.fr.first_pvc;	if (hdlc->state.fr.settings.lmi != LMI_NONE)		del_timer_sync(&hdlc->state.fr.timer);	while(pvc) {		dev_close(&pvc->netdev); /* Shutdown all PVCs for this FRAD */		pvc = pvc->next;	}}static int fr_pvc(hdlc_device *hdlc, unsigned int dlci, int create){	pvc_device **pvc_p = &hdlc->state.fr.first_pvc;	pvc_device *pvc;	int result;	if(dlci <= 0 || dlci >= 1024)		return -EINVAL;	/* Only 10 bits for DLCI, DLCI 0 reserved */	while(*pvc_p) {		if (netdev_dlci(&(*pvc_p)->netdev) == dlci)			break;		pvc_p = &(*pvc_p)->next;	}	if (create) {		/* Create PVC */		if (*pvc_p != NULL)			return -EEXIST;		pvc = *pvc_p = kmalloc(sizeof(pvc_device), GFP_KERNEL);		if (!pvc) {			printk(KERN_WARNING "%s: Memory squeeze on fr_pvc()\n",			       hdlc_to_name(hdlc));			return -ENOBUFS;		}		memset(pvc, 0, sizeof(pvc_device));		pvc->netdev.hard_start_xmit = pvc_xmit;		pvc->netdev.get_stats = pvc_get_stats;		pvc->netdev.open = pvc_open;		pvc->netdev.stop = pvc_close;		pvc->netdev.change_mtu = pvc_change_mtu;		pvc->netdev.mtu = HDLC_MAX_MTU;		pvc->netdev.type = ARPHRD_DLCI;		pvc->netdev.hard_header_len = 16;		pvc->netdev.hard_header = fr_hard_header;		pvc->netdev.tx_queue_len = 0;		pvc->netdev.flags = IFF_POINTOPOINT;		pvc->master = hdlc;		*(u16*)pvc->netdev.dev_addr = htons(dlci);		dlci_to_q922(pvc->netdev.broadcast, dlci);		pvc->netdev.addr_len = 2;		result = dev_alloc_name(&pvc->netdev, "pvc%d");		if (result < 0) {			kfree(pvc);			*pvc_p = NULL;			return result;		}		if (register_netdevice(&pvc->netdev) != 0) {			kfree(pvc);			*pvc_p = NULL;			return -EIO;		}		hdlc->state.fr.changed = 1;		hdlc->state.fr.pvc_count++;		return 0;	}	if (*pvc_p == NULL)		/* Delete PVC */		return -ENOENT;	pvc = *pvc_p;	if (pvc->netdev.flags & IFF_UP)		return -EBUSY;		/* PVC in use */	hdlc->state.fr.changed = 1;	hdlc->state.fr.pvc_count--;	*pvc_p = pvc->next;	unregister_netdevice(&pvc->netdev);	kfree(pvc);	return 0;}static void fr_destroy(hdlc_device *hdlc){	pvc_device *pvc = hdlc->state.fr.first_pvc;	while(pvc) {		pvc_device *next = pvc->next;		unregister_netdev(&pvc->netdev);		kfree(pvc);		pvc = next;	}	hdlc->state.fr.first_pvc = NULL; /* All PVCs destroyed */	hdlc->state.fr.pvc_count = 0;	hdlc->state.fr.changed = 1;}int hdlc_fr_ioctl(hdlc_device *hdlc, struct ifreq *ifr){	fr_proto *fr_s = ifr->ifr_settings.ifs_ifsu.fr;	const size_t size = sizeof(fr_proto);	fr_proto new_settings;	struct net_device *dev = hdlc_to_dev(hdlc);	fr_proto_pvc pvc;	int result;	switch (ifr->ifr_settings.type) {	case IF_GET_PROTO:		ifr->ifr_settings.type = IF_PROTO_FR;		if (ifr->ifr_settings.size < size) {			ifr->ifr_settings.size = size; /* data size wanted */			return -ENOBUFS;		}		if (copy_to_user(fr_s, &hdlc->state.fr.settings, size))			return -EFAULT;		return 0;	case IF_PROTO_FR:		if(!capable(CAP_NET_ADMIN))			return -EPERM;		if(dev->flags & IFF_UP)			return -EBUSY;		if (copy_from_user(&new_settings, fr_s, size))			return -EFAULT;		if (new_settings.lmi == LMI_DEFAULT)			new_settings.lmi = LMI_ANSI;		if ((new_settings.lmi != LMI_NONE &&		     new_settings.lmi != LMI_ANSI &&		     new_settings.lmi != LMI_CCITT) ||		    new_settings.t391 < 1 ||		    new_settings.t392 < 2 ||		    new_settings.n391 < 1 ||		    new_settings.n392 < 1 ||		    new_settings.n393 < new_settings.n392 ||		    new_settings.n393 > 32 ||		    (new_settings.dce != 0 &&		     new_settings.dce != 1))			return -EINVAL;		result=hdlc->attach(hdlc, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT);		if (result)			return result;		if (hdlc->proto != IF_PROTO_FR) {			hdlc_proto_detach(hdlc);			hdlc->state.fr.first_pvc = NULL;			hdlc->state.fr.pvc_count = 0;		}		memcpy(&hdlc->state.fr.settings, &new_settings, size);		hdlc->open = fr_open;		hdlc->stop = fr_close;		hdlc->netif_rx = fr_rx;		hdlc->proto_detach = fr_destroy;		hdlc->proto = IF_PROTO_FR;		dev->hard_start_xmit = hdlc->xmit;		dev->hard_header = fr_hard_header;		dev->type = ARPHRD_FRAD;		dev->addr_len = 2;		*(u16*)dev->dev_addr = htons(LMI_DLCI);		dlci_to_q922(dev->broadcast, LMI_DLCI);		return 0;	case IF_PROTO_FR_ADD_PVC:	case IF_PROTO_FR_DEL_PVC:		if(!capable(CAP_NET_ADMIN))			return -EPERM;		if (copy_from_user(&pvc, ifr->ifr_settings.ifs_ifsu.fr_pvc,				   sizeof(fr_proto_pvc)))			return -EFAULT;		return fr_pvc(hdlc, pvc.dlci,			      ifr->ifr_settings.type == IF_PROTO_FR_ADD_PVC);	}	return -EINVAL;}

⌨️ 快捷键说明

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