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; }
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; }
static int hdlc_set_mode(hdlc_device *hdlc, int mode) { int result = -1; /* Default to soft modes */ struct net_device *dev = hdlc_to_dev(hdlc); if(!capable(CAP_NET_ADMIN)) return -EPERM; if(dev->flags & IFF_UP) return -EBUSY; dev->addr_len = 0; dev->hard_header = NULL; hdlc->mode = MODE_NONE; if (!(mode & MODE_SOFT)) switch(mode & MODE_MASK) { case MODE_HDLC: result = hdlc->set_mode ? hdlc->set_mode(hdlc, MODE_HDLC) : 0; break; case MODE_CISCO: /* By card */ #ifdef CONFIG_HDLC_PPP case MODE_PPP: #endif #ifdef CONFIG_HDLC_X25 case MODE_X25: #endif case MODE_FR: 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_MASK) { case MODE_CISCO: dev->hard_header = cisco_hard_header; break; #ifdef CONFIG_HDLC_PPP case MODE_PPP: break; #endif #ifdef CONFIG_HDLC_X25 case MODE_X25: break; #endif case MODE_FR: dev->hard_header = fr_hard_header; dev->addr_len = 2; *(u16*)dev->dev_addr = htons(LMI_DLCI); dlci_to_q922(dev->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; switch(mode & MODE_MASK) { #ifdef CONFIG_HDLC_PPP case MODE_PPP: dev->type = ARPHRD_PPP; break; #endif #ifdef CONFIG_HDLC_X25 case MODE_X25: dev->type = ARPHRD_X25; break; #endif case MODE_FR: dev->type = ARPHRD_FRAD; break; case MODE_CISCO: dev->type = ARPHRD_CISCO; break; default: dev->type = ARPHRD_RAWHDLC; } memset(&(hdlc->stats), 0, sizeof(struct net_device_stats)); destroy_pvc_list(hdlc); return 0; }