예제 #1
0
static int hdlc_close(struct net_device *dev)
{
	hdlc_device *hdlc = dev_to_hdlc(dev);

	hdlc->close(hdlc);

	if (mode_is(hdlc, MODE_FR | MODE_SOFT) ||
	    mode_is(hdlc, MODE_CISCO | MODE_SOFT))
		fr_cisco_close(hdlc);
#ifdef CONFIG_HDLC_PPP
	else if (mode_is(hdlc, MODE_PPP | MODE_SOFT)) {
		sppp_close(dev);
		sppp_detach(dev);
		dev->rebuild_header = NULL;
		dev->change_mtu = hdlc_change_mtu;
		dev->mtu = HDLC_MAX_MTU;
		dev->hard_header_len = 16;
	}
#endif
#ifdef CONFIG_HDLC_X25
	else if (mode_is(hdlc, MODE_X25))
		lapb_unregister(hdlc);
#endif
	return 0;
}
예제 #2
0
static void fr_timer(unsigned long arg)
{
	hdlc_device *hdlc=(hdlc_device*)arg;
	int i, cnt=0, reliable;
	u32 list;

	if (mode_is(hdlc, MODE_DCE))
		reliable = (jiffies - hdlc->lmi.last_poll < hdlc->lmi.T392*HZ);
	else {
		hdlc->lmi.last_errors <<= 1; /* Shift the list */
		if (hdlc->lmi.state & LINK_STATE_REQUEST) {
			printk(KERN_INFO "%s: No LMI status reply received\n",
			       hdlc->name);
			hdlc->lmi.last_errors |= 1;
		}

		for (i=0, list=hdlc->lmi.last_errors; i<hdlc->lmi.N393;
		     i++, list>>=1)
			cnt += (list & 1);	/* errors count */

		reliable = (cnt < hdlc->lmi.N392);
	}

	if ((hdlc->lmi.state & LINK_STATE_RELIABLE) !=
	    (reliable ? LINK_STATE_RELIABLE : 0)) {
		pvc_device *pvc=hdlc->first_pvc;

		while (pvc) {/* Deactivate all PVCs */
			pvc->state &= ~(PVC_STATE_NEW | PVC_STATE_ACTIVE);
			pvc=pvc->next;
		}

		hdlc->lmi.state ^= LINK_STATE_RELIABLE;
		printk(KERN_INFO "%s: Link %sreliable\n", hdlc->name,
		       reliable ? "" : "un");
    
		if (reliable) {
			hdlc->lmi.N391cnt=0;	/* Request full status */
			hdlc->lmi.state |= LINK_STATE_CHANGED;
		}
	}

	if (mode_is(hdlc, MODE_DCE))
		hdlc->timer.expires = jiffies + hdlc->lmi.T392*HZ;
	else {
		if (hdlc->lmi.N391cnt)
			hdlc->lmi.N391cnt--;
		
		fr_lmi_send(hdlc, hdlc->lmi.N391cnt == 0);
		
		hdlc->lmi.state |= LINK_STATE_REQUEST;
		hdlc->timer.expires = jiffies + hdlc->lmi.T391*HZ;
	}

	hdlc->timer.function = fr_timer;
	hdlc->timer.data = arg;
	add_timer(&hdlc->timer);
}
예제 #3
0
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;

	if (mode_is(hdlc, MODE_CISCO))
		hdlc_to_dev(hdlc)->hard_header=cisco_hard_header;
	else
		hdlc_to_dev(hdlc)->hard_header=fr_hard_header;

	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);
}
예제 #4
0
static int hdlc_xmit(struct sk_buff *skb, struct net_device *dev)
{
	hdlc_device *hdlc = dev_to_hdlc(dev);

#ifdef CONFIG_HDLC_X25
	if (mode_is(hdlc, MODE_X25 | MODE_SOFT)) {
		int result;


		/* X.25 to LAPB */
		switch (skb->data[0]) {
		case 0:		/* Data to be transmitted */
			skb_pull(skb, 1);
			if ((result = lapb_data_request(hdlc, skb)) != LAPB_OK)
				dev_kfree_skb(skb);
			return 0;

		case 1:
			if ((result = lapb_connect_request(hdlc))!= LAPB_OK) {
				if (result == LAPB_CONNECTED) {
				/* Send connect confirm. msg to level 3 */
					x25_connected(hdlc, 0);
				} else {
					printk(KERN_ERR "%s: LAPB connect "
					       "request failed, error code = "
					       "%i\n", hdlc_to_name(hdlc),
					       result);
				}
			}
			break;

		case 2:
			if ((result=lapb_disconnect_request(hdlc))!=LAPB_OK) {
				if (result == LAPB_NOTCONNECTED) {
				/* Send disconnect confirm. msg to level 3 */
					x25_disconnected(hdlc, 0);
				} else {
					printk(KERN_ERR "%s: LAPB disconnect "
					       "request failed, error code = "
					       "%i\n", hdlc_to_name(hdlc),
					       result);
				}
			}
			break;

		default:
			/* to be defined */
			break;
		}

		dev_kfree_skb(skb);
		return 0;
	} /* MODE_X25 */
#endif /* CONFIG_HDLC_X25 */

	return hdlc->xmit(hdlc, skb);
}
예제 #5
0
static int pvc_close(struct 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;
}
예제 #6
0
static int hdlc_close(struct device *dev)
{
	hdlc_device *hdlc=dev_to_hdlc(dev);

	hdlc->close(hdlc);

	if (mode_is(hdlc, MODE_FR | MODE_SOFT) ||
	    mode_is(hdlc, MODE_CISCO | MODE_SOFT))
		fr_cisco_close(hdlc);

	else if (mode_is(hdlc, MODE_PPP | MODE_SOFT)) {
		sppp_close(dev);
		sppp_detach(dev);
		dev->rebuild_header=NULL;
		dev->change_mtu=hdlc_change_mtu;
		dev->mtu=HDLC_MAX_MTU;
		dev->hard_header_len=16;
	}

	return 0;
}
예제 #7
0
static int pvc_open(struct 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;
}
예제 #8
0
void hdlc_netif_rx(hdlc_device *hdlc, struct sk_buff *skb, int dlci)
{
	skb->mac.raw=skb->data;
  
	if (mode_is(hdlc, MODE_SOFT)) {
		if (mode_is(hdlc, MODE_FR)) {
			fr_netif(hdlc, skb);
			return;
		} else if (mode_is(hdlc, MODE_CISCO)) {
			cisco_netif(hdlc, skb);
			return;
		} else if (mode_is(hdlc, MODE_PPP)) {
			hdlc->stats.rx_bytes+=skb->len;
			hdlc->stats.rx_packets++;
			skb->protocol=htons(ETH_P_WAN_PPP);
			skb->dev=hdlc_to_dev(hdlc);
			netif_rx(skb);
			return;
		}
	} else {		/* protocol support in hardware/firmware */
		hdlc->stats.rx_bytes+=skb->len;
		hdlc->stats.rx_packets++;

		if (mode_is(hdlc, MODE_HDLC))
			skb->protocol=htons(ETH_P_IP);
		/* otherwise protocol set by hw driver */
		
		if (mode_is(hdlc, MODE_FR)) {
			pvc_device *pvc=find_pvc(hdlc, dlci);
			if (!pvc) { /* packet from nonexistent PVC */
				hdlc->stats.rx_errors++;
				dev_kfree_skb(skb);
			}
      
			pvc->stats.rx_bytes+=skb->len;
			pvc->stats.rx_packets++;
			skb->dev=&pvc->netdev;
		} else
			skb->dev=hdlc_to_dev(hdlc);

		netif_rx(skb);
		return;
	}
    
	hdlc->stats.rx_errors++; /* unsupported mode */
	dev_kfree_skb(skb);
}
예제 #9
0
static int hdlc_open(struct 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);

	else if (mode_is(hdlc, MODE_PPP | MODE_SOFT)) {
		sppp_attach(&hdlc->pppdev);
		/* sppp_attach nukes them. We don't need syncppp's ioctl */
		/* Anyway, I'm going to replace it with ppp_synctty.c */
		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;
		}
	}

	result=hdlc->open(hdlc);
	if (result) {
		if (mode_is(hdlc, MODE_FR | MODE_SOFT) ||
		    mode_is(hdlc, MODE_CISCO | MODE_SOFT))
			fr_cisco_close(hdlc);

		else if (mode_is(hdlc, MODE_PPP | MODE_SOFT)) {
			sppp_close(dev);
			sppp_detach(dev);
			dev->rebuild_header=NULL;
			dev->change_mtu=hdlc_change_mtu;
			dev->mtu=HDLC_MAX_MTU;
			dev->hard_header_len=16;
		}

	}

	return result;
}
예제 #10
0
static int fr_lmi_recv(hdlc_device *hdlc, struct sk_buff *skb)
{
	int stat_len;
	pvc_device *pvc;
	int reptype=-1, error;
	u8 rxseq, txseq;
	int i;

	if (skb->len < (mode_is(hdlc, MODE_FR_ANSI) ?
			LMI_ANSI_LENGTH : LMI_LENGTH)) {
		printk(KERN_INFO "%s: Short LMI frame\n", hdlc->name);
		return 1;
	}

	if (skb->data[5] != (!mode_is(hdlc, MODE_DCE) ?
			     LMI_STATUS : LMI_STATUS_ENQUIRY)) {
		printk(KERN_INFO "%s: LMI msgtype=%x, Not LMI status %s\n",
		       hdlc->name, skb->data[2],
		       mode_is(hdlc, MODE_DCE) ? "enquiry" : "reply");
		return 1;
	}
  
	i = mode_is(hdlc, MODE_FR_ANSI) ? 7 : 6;
  
	if (skb->data[i] !=
	    (mode_is(hdlc, MODE_FR_CCITT) ? LMI_CCITT_REPTYPE : LMI_REPTYPE)) {
		printk(KERN_INFO "%s: Not a report type=%x\n", hdlc->name,
		       skb->data[i]);
		return 1;
	}
	i++;

	i++;				/* Skip length field */

	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->name, 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->name, 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->name, skb->data[i]);
			return 1;
		}
		i++;
      
		if (skb->data[i] != stat_len) {
			printk(KERN_WARNING "%s: Invalid PVCSTAT length: %x\n",
			       hdlc->name, 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->name, 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;
}
예제 #11
0
static void fr_lmi_send(hdlc_device *hdlc, int fullrep)
{
	struct sk_buff *skb;
	pvc_device *pvc=hdlc->first_pvc;
	int len = mode_is(hdlc, MODE_FR_ANSI) ? LMI_ANSI_LENGTH : LMI_LENGTH;
	int stat_len = 3;
	u8 *data;
	int i=0;
  
	if (mode_is(hdlc, MODE_DCE) && fullrep) {
		len += hdlc->pvc_count * (2 + stat_len);
		if (len>HDLC_MAX_MTU) {
			printk(KERN_WARNING "%s: Too many PVCs while sending "
			       "LMI full report\n", hdlc->name);
			return;
		}
	}

	skb=dev_alloc_skb(len);
	memset(skb->data, 0, len);
	skb_reserve(skb, 4);
	fr_hard_header(skb, hdlc_to_dev(hdlc), LMI_PROTO, NULL, NULL, 0);
	data=skb->tail;
	data[i++] = LMI_CALLREF;
	data[i++] = mode_is(hdlc, MODE_DCE) ? LMI_STATUS : LMI_STATUS_ENQUIRY;
	if (mode_is(hdlc, MODE_FR_ANSI))
		data[i++] = LMI_ANSI_LOCKSHIFT;
	data[i++] = mode_is(hdlc, MODE_FR_CCITT) ? LMI_CCITT_REPTYPE :
		LMI_REPTYPE;
	data[i++] = LMI_REPT_LEN;
	data[i++] = fullrep ? LMI_FULLREP : LMI_INTEGRITY;

	data[i++] = mode_is(hdlc, MODE_FR_CCITT) ? LMI_CCITT_ALIVE : LMI_ALIVE;
	data[i++] = LMI_INTEG_LEN;
	data[i++] = hdlc->lmi.txseq = fr_lmi_nextseq(hdlc->lmi.txseq);
	data[i++] = hdlc->lmi.rxseq;

	if (mode_is(hdlc, MODE_DCE) && fullrep) {
		while (pvc) {
			data[i++] = mode_is(hdlc, MODE_FR_CCITT) ?
				LMI_CCITT_PVCSTAT:LMI_PVCSTAT;
			data[i++] = stat_len;
      
			if ((hdlc->lmi.state & LINK_STATE_RELIABLE) &&
			    (pvc->netdev.flags & IFF_UP) &&
			    !(pvc->state & (PVC_STATE_ACTIVE|PVC_STATE_NEW))) {
				pvc->state |= PVC_STATE_NEW;
				fr_log_dlci_active(pvc);
			}

			dlci_to_status(hdlc, netdev_dlci(&pvc->netdev),
				       data+i, pvc->state);
			i+=stat_len;
			pvc=pvc->next;
		}
	}

	skb_put(skb, i);
	skb->priority=TC_PRIO_CONTROL;
	skb->dev = hdlc_to_dev(hdlc);

	dev_queue_xmit(skb);
}
예제 #12
0
static int hdlc_fr_pvc(hdlc_device *hdlc, int dlci)
{
	pvc_device **pvc_p=&hdlc->first_pvc;
	pvc_device *pvc;
	int result, create=1;	/* Create or delete PVC */

	if(!capable(CAP_NET_ADMIN))
		return -EPERM;

	if(dlci<0) {
		dlci=-dlci;
		create=0;
	}

	if(dlci<=0 || dlci>=1024)
		return -EINVAL;	/* Only 10 bits for DLCI, DLCI=0 is reserved */

	if(!mode_is(hdlc, MODE_FR))
		return -EINVAL;	/* Only meaningfull on FR */
    
	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_p=kmalloc(sizeof(pvc_device), GFP_KERNEL);
		pvc=*pvc_p;
		memset(pvc, 0, sizeof(pvc_device));
    
		pvc->netdev.name=pvc->name;
		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=PVC_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;
  
		dev_init_buffers(&pvc->netdev);

		pvc->master=hdlc;
		*(u16*)pvc->netdev.dev_addr=htons(dlci);
		dlci_to_q922(pvc->netdev.broadcast, dlci);
		pvc->netdev.addr_len=2;	/* 16 bits is enough */
		pvc->netdev.irq=hdlc_to_dev(hdlc)->irq;

		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;
		}

		if (!mode_is(hdlc, MODE_SOFT) && hdlc->create_pvc) {
			result=hdlc->create_pvc(pvc);
			if (result) {
				unregister_netdevice(&pvc->netdev);
				kfree(pvc);
				*pvc_p=NULL;
				return result;
			}
		}

		hdlc->lmi.state |= LINK_STATE_CHANGED;
		hdlc->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 */
  
	if (!mode_is(hdlc, MODE_SOFT) && hdlc->destroy_pvc)
		hdlc->destroy_pvc(pvc);

	hdlc->lmi.state |= LINK_STATE_CHANGED;
	hdlc->pvc_count--;
	*pvc_p=pvc->next;
	unregister_netdevice(&pvc->netdev);
	kfree(pvc);
	return 0;
}
예제 #13
0
static int hdlc_set_mode(hdlc_device *hdlc, int mode)
{
	int result=-1;		/* Default to soft modes */

	if(!capable(CAP_NET_ADMIN))
		return -EPERM;

	if(hdlc_to_dev(hdlc)->flags & IFF_UP)
		return -EBUSY;

	hdlc_to_dev(hdlc)->addr_len=0;
	hdlc->mode=MODE_NONE;
  
	if (!(mode & MODE_SOFT))
		switch(mode) {
		case MODE_HDLC:
			result = hdlc->set_mode ?
				hdlc->set_mode(hdlc, MODE_HDLC) : 0;
			break;

		case MODE_X25:	/* By card */
		case MODE_CISCO:
		case MODE_PPP:
		case MODE_FR_ANSI:
		case MODE_FR_CCITT:
		case MODE_FR_ANSI  | MODE_DCE:
		case MODE_FR_CCITT | MODE_DCE:
			result = hdlc->set_mode ?
				hdlc->set_mode(hdlc, mode) : -ENOSYS;
			break;
	
		default:
			return -EINVAL;
		}

	if (result) {
		mode |= MODE_SOFT; /* Try "host software" protocol */

		switch(mode & ~MODE_SOFT) {
		case MODE_CISCO:
		case MODE_PPP:
			break;

		case MODE_FR_ANSI:
		case MODE_FR_CCITT:
		case MODE_FR_ANSI  | MODE_DCE:
		case MODE_FR_CCITT | MODE_DCE:
			hdlc_to_dev(hdlc)->addr_len=2;
			*(u16*)hdlc_to_dev(hdlc)->dev_addr=htons(LMI_DLCI);
			dlci_to_q922(hdlc_to_dev(hdlc)->broadcast, LMI_DLCI);
			break;

		default:
			return -EINVAL;
		}

		result = hdlc->set_mode ?
			hdlc->set_mode(hdlc, MODE_HDLC) : 0;
	}

	if (result)
		return result;

	hdlc->mode=mode;
	if (mode_is(hdlc, MODE_PPP))
		hdlc_to_dev(hdlc)->type=ARPHRD_PPP;
	if (mode_is(hdlc, MODE_X25))
		hdlc_to_dev(hdlc)->type=ARPHRD_X25;
	else if (mode_is(hdlc, MODE_FR))
		hdlc_to_dev(hdlc)->type=ARPHRD_FRAD;
	else			/* Conflict - raw HDLC and Cisco */
		hdlc_to_dev(hdlc)->type=ARPHRD_HDLC;
  
	memset(&(hdlc->stats), 0, sizeof(struct net_device_stats));
	destroy_pvc_list(hdlc);
	return 0;
}
예제 #14
0
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
	else if (mode_is(hdlc, MODE_X25)) {
		struct lapb_register_struct cb;

		cb.connect_confirmation = x25_connected;
		cb.connect_indication = x25_connected;
		cb.disconnect_confirmation = x25_disconnected;
		cb.disconnect_indication = x25_disconnected;
		cb.data_indication = x25_data_indication;
		cb.data_transmit = x25_data_transmit;

		result = lapb_register(hdlc, &cb);
		if (result != LAPB_OK)
			return result;
	}
#endif
	result = hdlc->open(hdlc);
	if (result) {
		if (mode_is(hdlc, MODE_FR | MODE_SOFT) ||
		    mode_is(hdlc, MODE_CISCO | MODE_SOFT))
			fr_cisco_close(hdlc);
#ifdef CONFIG_HDLC_PPP
		else if (mode_is(hdlc, MODE_PPP | MODE_SOFT)) {
			sppp_close(dev);
			sppp_detach(dev);
			dev->rebuild_header = NULL;
			dev->change_mtu = hdlc_change_mtu;
			dev->mtu = HDLC_MAX_MTU;
			dev->hard_header_len = 16;
		}
#endif
#ifdef CONFIG_HDLC_X25
		else if (mode_is(hdlc, MODE_X25))
			lapb_unregister(hdlc);
#endif
	}

	return result;
}