📄 isdn_common.c
字号:
case IIOCGETCPS: if (arg) { ulong *p = (ulong *) arg; int i; if ((ret = verify_area(VERIFY_WRITE, (void *) arg, sizeof(ulong) * ISDN_MAX_CHANNELS * 2))) return ret; for (i = 0; i < ISDN_MAX_CHANNELS; i++) { put_user(dev->ibytes[i], p++); put_user(dev->obytes[i], p++); } return 0; } else return -EINVAL; break;#ifdef CONFIG_NETDEVICES case IIOCNETGPN: /* Get peer phone number of a connected * isdn network interface */ if (arg) { if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone))) return -EFAULT; return isdn_net_getpeer(&phone, (isdn_net_ioctl_phone *) arg); } else return -EINVAL;#endif default: return -EINVAL; } } if (!dev->drivers) return -ENODEV; if (minor < ISDN_MINOR_CTRL) { drvidx = isdn_minor2drv(minor); if (drvidx < 0) return -ENODEV; chidx = isdn_minor2chan(minor); if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) return -ENODEV; return 0; } if (minor <= ISDN_MINOR_CTRLMAX) {/* * isdn net devices manage lots of configuration variables as linked lists. * Those lists must only be manipulated from user space. Some of the ioctl's * service routines access user space and are not atomic. Therefor, ioctl's * manipulating the lists and ioctl's sleeping while accessing the lists * are serialized by means of a semaphore. */ switch (cmd) { case IIOCNETDWRSET: printk(KERN_INFO "INFO: ISDN_DW_ABC_EXTENSION not enabled\n"); return(-EINVAL); case IIOCNETLCR: printk(KERN_INFO "INFO: ISDN_ABC_LCR_SUPPORT not enabled\n"); return -ENODEV;#ifdef CONFIG_NETDEVICES case IIOCNETAIF: /* Add a network-interface */ if (arg) { if (copy_from_user(name, (char *) arg, sizeof(name))) return -EFAULT; s = name; } else { s = NULL; } ret = down_interruptible(&dev->sem); if( ret ) return ret; if ((s = isdn_net_new(s, NULL))) { if (copy_to_user((char *) arg, s, strlen(s) + 1)){ ret = -EFAULT; } else { ret = 0; } } else ret = -ENODEV; up(&dev->sem); return ret; case IIOCNETASL: /* Add a slave to a network-interface */ if (arg) { if (copy_from_user(bname, (char *) arg, sizeof(bname) - 1)) return -EFAULT; } else return -EINVAL; ret = down_interruptible(&dev->sem); if( ret ) return ret; if ((s = isdn_net_newslave(bname))) { if (copy_to_user((char *) arg, s, strlen(s) + 1)){ ret = -EFAULT; } else { ret = 0; } } else ret = -ENODEV; up(&dev->sem); return ret; case IIOCNETDIF: /* Delete a network-interface */ if (arg) { if (copy_from_user(name, (char *) arg, sizeof(name))) return -EFAULT; ret = down_interruptible(&dev->sem); if( ret ) return ret; ret = isdn_net_rm(name); up(&dev->sem); return ret; } else return -EINVAL; case IIOCNETSCF: /* Set configurable parameters of a network-interface */ if (arg) { if (copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg))) return -EFAULT; return isdn_net_setcfg(&cfg); } else return -EINVAL; case IIOCNETGCF: /* Get configurable parameters of a network-interface */ if (arg) { if (copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg))) return -EFAULT; if (!(ret = isdn_net_getcfg(&cfg))) { if (copy_to_user((char *) arg, (char *) &cfg, sizeof(cfg))) return -EFAULT; } return ret; } else return -EINVAL; case IIOCNETANM: /* Add a phone-number to a network-interface */ if (arg) { if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone))) return -EFAULT; ret = down_interruptible(&dev->sem); if( ret ) return ret; ret = isdn_net_addphone(&phone); up(&dev->sem); return ret; } else return -EINVAL; case IIOCNETGNM: /* Get list of phone-numbers of a network-interface */ if (arg) { if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone))) return -EFAULT; ret = down_interruptible(&dev->sem); if( ret ) return ret; ret = isdn_net_getphones(&phone, (char *) arg); up(&dev->sem); return ret; } else return -EINVAL; case IIOCNETDNM: /* Delete a phone-number of a network-interface */ if (arg) { if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone))) return -EFAULT; ret = down_interruptible(&dev->sem); if( ret ) return ret; ret = isdn_net_delphone(&phone); up(&dev->sem); return ret; } else return -EINVAL; case IIOCNETDIL: /* Force dialing of a network-interface */ if (arg) { if (copy_from_user(name, (char *) arg, sizeof(name))) return -EFAULT; return isdn_net_force_dial(name); } else return -EINVAL;#ifdef CONFIG_ISDN_PPP case IIOCNETALN: if (!arg) return -EINVAL; if (copy_from_user(name, (char *) arg, sizeof(name))) return -EFAULT; return isdn_ppp_dial_slave(name); case IIOCNETDLN: if (!arg) return -EINVAL; if (copy_from_user(name, (char *) arg, sizeof(name))) return -EFAULT; return isdn_ppp_hangup_slave(name);#endif case IIOCNETHUP: /* Force hangup of a network-interface */ if (!arg) return -EINVAL; if (copy_from_user(name, (char *) arg, sizeof(name))) return -EFAULT; return isdn_net_force_hangup(name); break;#endif /* CONFIG_NETDEVICES */ case IIOCSETVER: dev->net_verbose = arg; printk(KERN_INFO "isdn: Verbose-Level is %d\n", dev->net_verbose); return 0; case IIOCSETGST: if (arg) dev->global_flags |= ISDN_GLOBAL_STOPPED; else dev->global_flags &= ~ISDN_GLOBAL_STOPPED; printk(KERN_INFO "isdn: Global Mode %s\n", (dev->global_flags & ISDN_GLOBAL_STOPPED) ? "stopped" : "running"); return 0; case IIOCSETBRJ: drvidx = -1; if (arg) { int i; char *p; if (copy_from_user((char *) &iocts, (char *) arg, sizeof(isdn_ioctl_struct))) return -EFAULT; if (strlen(iocts.drvid)) { if ((p = strchr(iocts.drvid, ','))) *p = 0; drvidx = -1; for (i = 0; i < ISDN_MAX_DRIVERS; i++) if (!(strcmp(dev->drvid[i], iocts.drvid))) { drvidx = i; break; } } } if (drvidx == -1) return -ENODEV; if (iocts.arg) dev->drv[drvidx]->flags |= DRV_FLAG_REJBUS; else dev->drv[drvidx]->flags &= ~DRV_FLAG_REJBUS; return 0; case IIOCSIGPRF: dev->profd = current; return 0; break; case IIOCGETPRF: /* Get all Modem-Profiles */ if (arg) { char *p = (char *) arg; int i; if ((ret = verify_area(VERIFY_WRITE, (void *) arg, (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN) * ISDN_MAX_CHANNELS))) return ret; for (i = 0; i < ISDN_MAX_CHANNELS; i++) { if (copy_to_user(p, dev->mdm.info[i].emu.profile, ISDN_MODEM_NUMREG)) return -EFAULT; p += ISDN_MODEM_NUMREG; if (copy_to_user(p, dev->mdm.info[i].emu.pmsn, ISDN_MSNLEN)) return -EFAULT; p += ISDN_MSNLEN; if (copy_to_user(p, dev->mdm.info[i].emu.plmsn, ISDN_LMSNLEN)) return -EFAULT; p += ISDN_LMSNLEN; } return (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN) * ISDN_MAX_CHANNELS; } else return -EINVAL; break; case IIOCSETPRF: /* Set all Modem-Profiles */ if (arg) { char *p = (char *) arg; int i; if ((ret = verify_area(VERIFY_READ, (void *) arg, (ISDN_MODEM_NUMREG + ISDN_MSNLEN) * ISDN_MAX_CHANNELS))) return ret; for (i = 0; i < ISDN_MAX_CHANNELS; i++) { if (copy_from_user(dev->mdm.info[i].emu.profile, p, ISDN_MODEM_NUMREG)) return -EFAULT; p += ISDN_MODEM_NUMREG; if (copy_from_user(dev->mdm.info[i].emu.pmsn, p, ISDN_MSNLEN)) return -EFAULT; p += ISDN_MSNLEN; } return 0; } else return -EINVAL; break; case IIOCSETMAP: case IIOCGETMAP: /* Set/Get MSN->EAZ-Mapping for a driver */ if (arg) { if (copy_from_user((char *) &iocts, (char *) arg, sizeof(isdn_ioctl_struct))) return -EFAULT; if (strlen(iocts.drvid)) { drvidx = -1; for (i = 0; i < ISDN_MAX_DRIVERS; i++) if (!(strcmp(dev->drvid[i], iocts.drvid))) { drvidx = i; break; } } else drvidx = 0; if (drvidx == -1) return -ENODEV; if (cmd == IIOCSETMAP) { int loop = 1; p = (char *) iocts.arg; i = 0; while (loop) { int j = 0; while (1) { if ((ret = verify_area(VERIFY_READ, p, 1))) return ret; get_user(bname[j], p++); switch (bname[j]) { case '\0': loop = 0; /* Fall through */ case ',': bname[j] = '\0'; strcpy(dev->drv[drvidx]->msn2eaz[i], bname); j = ISDN_MSNLEN; break; default: j++; } if (j >= ISDN_MSNLEN) break; } if (++i > 9) break; } } else { p = (char *) iocts.arg; for (i = 0; i < 10; i++) { sprintf(bname, "%s%s", strlen(dev->drv[drvidx]->msn2eaz[i]) ? dev->drv[drvidx]->msn2eaz[i] : "_", (i < 9) ? "," : "\0"); if (copy_to_user(p, bname, strlen(bname) + 1)) return -EFAULT; p += strlen(bname); } } return 0; } else return -EINVAL; case IIOCDBGVAR: if (arg) { if (copy_to_user((char *) arg, (char *) &dev, sizeof(ulong))) return -EFAULT; return 0; } else return -EINVAL; break; default: if ((cmd & IIOCDRVCTL) == IIOCDRVCTL) cmd = ((cmd >> _IOC_NRSHIFT) & _IOC_NRMASK) & ISDN_DRVIOCTL_MASK; else return -EINVAL; if (arg) { int i; char *p; if (copy_from_user((char *) &iocts, (char *) arg, sizeof(isdn_ioctl_struct))) return -EFAULT; if (strlen(iocts.drvid)) { if ((p = strchr(iocts.drvid, ','))) *p = 0; drvidx = -1; for (i = 0; i < ISDN_MAX_DRIVERS; i++) if (!(strcmp(dev->drvid[i], iocts.drvid))) { drvidx = i; break; } } else drvidx = 0; if (drvidx == -1) return -ENODEV; if ((ret = verify_area(VERIFY_WRITE, (void *) arg, sizeof(isdn_ioctl_struct)))) return ret; c.driver = drvidx; c.command = ISDN_CMD_IOCTL; c.arg = cmd; memcpy(c.parm.num, (char *) &iocts.arg, sizeof(ulong)); ret = isdn_command(&c); memcpy((char *) &iocts.arg, c.parm.num, sizeof(ulong)); if (copy_to_user((char *) arg, &iocts, sizeof(isdn_ioctl_struct))) return -EFAULT; return ret; } else return -EINVAL; } }#ifdef CONFIG_ISDN_PPP if (minor <= ISDN_MINOR_PPPMAX) return (isdn_ppp_ioctl(minor - ISDN_MINOR_PPP, file, cmd, arg));#endif return -ENODEV;#undef name#undef bname#undef iocts#undef phone#undef cfg}/* * Open the device code. */static intisdn_open(struct inode *ino, struct file *filep){ uint minor = MINOR(ino->i_rdev); int drvidx; int chidx; int retval = -ENODEV; if (minor == ISDN_MINOR_STATUS) { infostruct *p; if ((p = (infostruct *) kmalloc(sizeof(infostruct), GFP_KERNEL))) { p->next = (char *) dev->infochain; p->private = (char *) &(filep->private_data); dev->infochain = p; /* At opening we allow a single update */ filep->private_data = (char *) 1; retval = 0; goto out; } else { retval = -ENOMEM; goto out; } } if (!dev->channels) goto out; if (minor < ISDN_MINOR_CTRL) { printk(KERN_WARNING "isdn_open minor %d obsolete!\n", minor); drvidx = isdn_minor2drv(minor); if (drvidx < 0) goto out; chidx = isdn_minor2chan(minor); if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) goto out; if (!(dev->drv[drvidx]->online & (1 << chidx))) goto out; isdn_lock_drivers(); retval = 0; goto out; } if (minor <= ISDN_MINOR_CTRLMAX) { drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL); if (drvidx < 0) goto out; isdn_lock_drivers(); retval = 0; goto out; }#ifdef CONFIG_ISDN_PPP if (minor <= ISDN_MINOR_PPPMAX) { retval = isdn_ppp_open(minor - ISDN_MINOR_PPP, filep); if (retval == 0) isdn_lock_drivers(); goto out; }#endif out: return retval;}static intisdn_close(struct inode *ino, struct file *filep){ uint minor = MINOR(ino->i_rdev); lock_kernel(); if (minor == ISDN_MINOR_STATUS) { infostruct *p = dev->infochain; infostruct *q = NULL; while (p) { if (p->private == (char *) &(filep->private_data)) { if (q) q->next = p->next; else dev->infochain = (infostruct *) (p->next); kfree(p); goto out; } q = p; p = (infostruct *) (p->next); } printk(KERN_WARNING "isdn: No private data while closing isdnctrl\n"); goto out; } isdn_unlock_drivers(); if (minor < ISDN_MINOR_CTRL) goto out; if (minor <= ISDN_MINOR_CTRLMAX) { if (dev->profd == current) dev->profd = NULL; goto out; }#ifdef CONFIG_ISDN_PPP if (minor <= ISDN_MINOR_PPPMAX) isdn_ppp_release(minor - ISDN_MINOR_PPP, filep);#endif out: unlock_kernel(); return 0;}static struct file_operations isdn_fops ={ owner: THIS_MODULE, llseek: isdn_llseek, read: isdn_read, write: isdn_write, poll: isdn_poll, ioctl: isdn_ioctl, open: isdn_open, release: isdn_close,};char *isdn_map_eaz2msn(char *msn, int di){ driver *this = dev->drv[di]; int i; if (strlen(msn) == 1) { i = msn[0] - '0'; if ((i >= 0) && (i <= 9)) if (strlen(this->msn2eaz[i])) return (this->msn2eaz[i]); } return (msn);}/* * Find an unused ISDN-channel, whose feature-flags match the * given L2- and L3-protocols. */#define L2V (~(ISDN_FEATURE_L2_V11096|ISDN_FEATURE_L2_V11019|ISDN_FEATURE_L2_V11038))intisdn_get_free_channel(int usage, int l2_proto, int l3_proto, int pre_dev ,int pre_chan, char *msn){ int i; ulong flags; ulong features; ulong vfeatures; save_flags(flags); cli(); features = ((1 << l2_proto) | (0x10000 << l3_proto)); vfeatures = (((1 << l2_proto) | (0x10000 << l3_proto)) & ~(ISDN_FEATURE_L2_V11096|ISDN_FEATURE_L2_V11019|ISDN_FEATURE_L2_V11038)); /* If Layer-2 protocol is V.110, accept drivers with * transparent feature even if these don't support V.110 * because we can emulate this in linklevel. */ for (i = 0; i < ISDN_MAX_CHANNELS; i++) if (USG_NONE(dev->usage[i]) && (dev->drvmap[i] != -1)) { int d = dev->drvmap[i]; if ((dev->usage[i] & ISDN_USAGE_EXCLUSIVE) && ((pre_dev != d) || (pre_chan != dev->chanmap[i]))) continue; if (!strcmp(isdn_map_eaz2msn(msn, d), "-")) continue; if (dev->usage[i] & ISDN_USAGE_DISABLED) continue; /* usage not allowed */ if (dev->drv[d]->flags & DRV_FLAG_RUNNING) { if (((dev->drv[d]->interface->features & features) == features) || (((dev->drv[d]->interface->features & vfeatures) == vfeatures) && (dev->drv[d]->interface->features & ISDN_FEATURE_L2_TRANS))) { if ((pre_dev < 0) || (pre_chan < 0)) { dev->usage[i] &= ISDN_USAGE_EXCLUSIVE; dev->usage[i] |= usage; isdn_info_update(); restore_flags(flags); return i; } else { if ((pre_dev == d) && (pre_chan == dev->chanmap[i])) { dev->usage[i] &= ISDN_USAGE_EXCLUSIVE; dev->usage[i] |= usage; isdn_info_update(); restore_flags(flags); return i; } } } } } restore_flags(flags); return -1;}/* * Set state of ISDN-channel to 'unused' */voidisdn_free_channel(int di, int ch, int usage){ int i; ulong flags; save_flags(flags); cli(); for (i = 0; i < ISDN_MAX_CHANNELS; i++)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -