X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fisdn%2Fi4l%2Fisdn_common.c;h=6a2ef0a87ed9a5143ba61a396cd35bdfd4908f68;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=1b95f600592f39f1c4632e38038be66b607d97e2;hpb=9213980e6a70d8473e0ffd4b39ab5b6caaba9ff5;p=linux-2.6.git diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c index 1b95f6005..6a2ef0a87 100644 --- a/drivers/isdn/i4l/isdn_common.c +++ b/drivers/isdn/i4l/isdn_common.c @@ -11,10 +11,8 @@ * */ -#include #include #include -#include #include #include #include @@ -64,10 +62,10 @@ static isdn_divert_if *divert_if; /* = NULL */ #endif /* CONFIG_ISDN_DIVERSION */ -static int isdn_writebuf_stub(int, int, const u_char *, int, int); +static int isdn_writebuf_stub(int, int, const u_char __user *, int); static void set_global_features(void); static int isdn_wildmat(char *s, char *p); - +static int isdn_add_channels(isdn_driver_t *d, int drvidx, int n, int adding); static inline void isdn_lock_driver(isdn_driver_t *drv) @@ -341,6 +339,16 @@ isdn_command(isdn_ctrl *cmd) printk(KERN_WARNING "isdn_command command(%x) driver -1\n", cmd->command); return(1); } + if (!dev->drv[cmd->driver]) { + printk(KERN_WARNING "isdn_command command(%x) dev->drv[%d] NULL\n", + cmd->command, cmd->driver); + return(1); + } + if (!dev->drv[cmd->driver]->interface) { + printk(KERN_WARNING "isdn_command command(%x) dev->drv[%d]->interface NULL\n", + cmd->command, cmd->driver); + return(1); + } if (cmd->command == ISDN_CMD_SETL2) { int idx = isdn_dc2minor(cmd->driver, cmd->arg & 255); unsigned long l2prot = (cmd->arg >> 8) & 255; @@ -388,7 +396,7 @@ isdn_all_eaz(int di, int ch) */ #include -int +static int isdn_capi_rec_hl_msg(capi_msg *cm) { int di; @@ -858,6 +866,118 @@ isdn_readbchan(int di, int channel, u_char * buf, u_char * fp, int len, wait_que return count; } +/* + * isdn_readbchan_tty() tries to get data from the read-queue. + * It MUST be called with interrupts off. + * + * Be aware that this is not an atomic operation when sleep != 0, even though + * interrupts are turned off! Well, like that we are currently only called + * on behalf of a read system call on raw device files (which are documented + * to be dangerous and for for debugging purpose only). The inode semaphore + * takes care that this is not called for the same minor device number while + * we are sleeping, but access is not serialized against simultaneous read() + * from the corresponding ttyI device. Can other ugly events, like changes + * of the mapping (di,ch)<->minor, happen during the sleep? --he + */ +int +isdn_readbchan_tty(int di, int channel, struct tty_struct *tty, int cisco_hack) +{ + int count; + int count_pull; + int count_put; + int dflag; + struct sk_buff *skb; + char last = 0; + int len; + + if (!dev->drv[di]) + return 0; + if (skb_queue_empty(&dev->drv[di]->rpqueue[channel])) + return 0; + + len = tty_buffer_request_room(tty, dev->drv[di]->rcvcount[channel]); + if(len == 0) + return len; + + count = 0; + while (len) { + if (!(skb = skb_peek(&dev->drv[di]->rpqueue[channel]))) + break; +#ifdef CONFIG_ISDN_AUDIO + if (ISDN_AUDIO_SKB_LOCK(skb)) + break; + ISDN_AUDIO_SKB_LOCK(skb) = 1; + if ((ISDN_AUDIO_SKB_DLECOUNT(skb)) || (dev->drv[di]->DLEflag & (1 << channel))) { + char *p = skb->data; + unsigned long DLEmask = (1 << channel); + + dflag = 0; + count_pull = count_put = 0; + while ((count_pull < skb->len) && (len > 0)) { + len--; + if (dev->drv[di]->DLEflag & DLEmask) { + last = DLE; + dev->drv[di]->DLEflag &= ~DLEmask; + } else { + last = *p; + if (last == DLE) { + dev->drv[di]->DLEflag |= DLEmask; + (ISDN_AUDIO_SKB_DLECOUNT(skb))--; + } + p++; + count_pull++; + } + count_put++; + } + if (count_pull >= skb->len) + dflag = 1; + } else { +#endif + /* No DLE's in buff, so simply copy it */ + dflag = 1; + if ((count_pull = skb->len) > len) { + count_pull = len; + dflag = 0; + } + count_put = count_pull; + if(count_put > 1) + tty_insert_flip_string(tty, skb->data, count_put - 1); + last = skb->data[count_put - 1]; + len -= count_put; +#ifdef CONFIG_ISDN_AUDIO + } +#endif + count += count_put; + if (dflag) { + /* We got all the data in this buff. + * Now we can dequeue it. + */ + if(cisco_hack) + tty_insert_flip_char(tty, last, 0xFF); + else + tty_insert_flip_char(tty, last, TTY_NORMAL); +#ifdef CONFIG_ISDN_AUDIO + ISDN_AUDIO_SKB_LOCK(skb) = 0; +#endif + skb = skb_dequeue(&dev->drv[di]->rpqueue[channel]); + dev_kfree_skb(skb); + } else { + tty_insert_flip_char(tty, last, TTY_NORMAL); + /* Not yet emptied this buff, so it + * must stay in the queue, for further calls + * but we pull off the data we got until now. + */ + skb_pull(skb, count_pull); +#ifdef CONFIG_ISDN_AUDIO + ISDN_AUDIO_SKB_LOCK(skb) = 0; +#endif + } + dev->drv[di]->rcvcount[channel] -= count_put; + } + return count; +} + + static __inline int isdn_minor2drv(int minor) { @@ -937,18 +1057,15 @@ isdn_info_update(void) } static ssize_t -isdn_read(struct file *file, char *buf, size_t count, loff_t * off) +isdn_read(struct file *file, char __user *buf, size_t count, loff_t * off) { - uint minor = MINOR(file->f_dentry->d_inode->i_rdev); + uint minor = iminor(file->f_path.dentry->d_inode); int len = 0; int drvidx; int chidx; int retval; char *p; - if (off != &file->f_pos) - return -ESPIPE; - lock_kernel(); if (minor == ISDN_MINOR_STATUS) { if (!file->private_data) { @@ -959,7 +1076,7 @@ isdn_read(struct file *file, char *buf, size_t count, loff_t * off) interruptible_sleep_on(&(dev->info_waitq)); } p = isdn_statstr(); - file->private_data = 0; + file->private_data = NULL; if ((len = strlen(p)) <= count) { if (copy_to_user(buf, p, len)) { retval = -EFAULT; @@ -992,7 +1109,7 @@ isdn_read(struct file *file, char *buf, size_t count, loff_t * off) retval = -ENOMEM; goto out; } - len = isdn_readbchan(drvidx, chidx, p, 0, count, + len = isdn_readbchan(drvidx, chidx, p, NULL, count, &dev->drv[drvidx]->rcv_waitq[chidx]); *off += len; if (copy_to_user(buf,p,len)) @@ -1017,9 +1134,12 @@ isdn_read(struct file *file, char *buf, size_t count, loff_t * off) if (dev->drv[drvidx]->interface->readstat) { if (count > dev->drv[drvidx]->stavail) count = dev->drv[drvidx]->stavail; - len = dev->drv[drvidx]->interface-> - readstat(buf, count, 1, drvidx, - isdn_minor2chan(minor)); + len = dev->drv[drvidx]->interface->readstat(buf, count, + drvidx, isdn_minor2chan(minor)); + if (len < 0) { + retval = len; + goto out; + } } else { len = 0; } @@ -1044,16 +1164,13 @@ isdn_read(struct file *file, char *buf, size_t count, loff_t * off) } static ssize_t -isdn_write(struct file *file, const char *buf, size_t count, loff_t * off) +isdn_write(struct file *file, const char __user *buf, size_t count, loff_t * off) { - uint minor = MINOR(file->f_dentry->d_inode->i_rdev); + uint minor = iminor(file->f_path.dentry->d_inode); int drvidx; int chidx; int retval; - if (off != &file->f_pos) - return -ESPIPE; - if (minor == ISDN_MINOR_STATUS) return -EPERM; if (!dev->drivers) @@ -1072,9 +1189,8 @@ isdn_write(struct file *file, const char *buf, size_t count, loff_t * off) goto out; } chidx = isdn_minor2chan(minor); - while (isdn_writebuf_stub(drvidx, chidx, buf, count, 1) != count) + while ((retval = isdn_writebuf_stub(drvidx, chidx, buf, count)) == 0) interruptible_sleep_on(&dev->drv[drvidx]->snd_waitq[chidx]); - retval = count; goto out; } if (minor <= ISDN_MINOR_CTRLMAX) { @@ -1091,7 +1207,7 @@ isdn_write(struct file *file, const char *buf, size_t count, loff_t * off) */ if (dev->drv[drvidx]->interface->writecmd) retval = dev->drv[drvidx]->interface-> - writecmd(buf, count, 1, drvidx, isdn_minor2chan(minor)); + writecmd(buf, count, drvidx, isdn_minor2chan(minor)); else retval = count; goto out; @@ -1112,7 +1228,7 @@ static unsigned int isdn_poll(struct file *file, poll_table * wait) { unsigned int mask = 0; - unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev); + unsigned int minor = iminor(file->f_path.dentry->d_inode); int drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL); lock_kernel(); @@ -1153,13 +1269,13 @@ isdn_poll(struct file *file, poll_table * wait) static int isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) { - uint minor = MINOR(inode->i_rdev); + uint minor = iminor(inode); isdn_ctrl c; int drvidx; int chidx; int ret; int i; - char *p; + char __user *p; char *s; union iocpar { char name[10]; @@ -1168,6 +1284,7 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) isdn_net_ioctl_phone phone; isdn_net_ioctl_cfg cfg; } iocpar; + void __user *argp = (void __user *)arg; #define name iocpar.name #define bname iocpar.bname @@ -1183,11 +1300,11 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) (INF_DV << 16)); case IIOCGETCPS: if (arg) { - ulong *p = (ulong *) arg; + ulong __user *p = argp; int i; - if ((ret = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(ulong) * ISDN_MAX_CHANNELS * 2))) - return ret; + if (!access_ok(VERIFY_WRITE, p, + sizeof(ulong) * ISDN_MAX_CHANNELS * 2)) + return -EFAULT; for (i = 0; i < ISDN_MAX_CHANNELS; i++) { put_user(dev->ibytes[i], p++); put_user(dev->obytes[i], p++); @@ -1201,9 +1318,9 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) /* Get peer phone number of a connected * isdn network interface */ if (arg) { - if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone))) + if (copy_from_user(&phone, argp, sizeof(phone))) return -EFAULT; - return isdn_net_getpeer(&phone, (isdn_net_ioctl_phone *) arg); + return isdn_net_getpeer(&phone, argp); } else return -EINVAL; #endif @@ -1241,7 +1358,7 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) case IIOCNETAIF: /* Add a network-interface */ if (arg) { - if (copy_from_user(name, (char *) arg, sizeof(name))) + if (copy_from_user(name, argp, sizeof(name))) return -EFAULT; s = name; } else { @@ -1250,7 +1367,7 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) 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)){ + if (copy_to_user(argp, s, strlen(s) + 1)){ ret = -EFAULT; } else { ret = 0; @@ -1262,14 +1379,14 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) case IIOCNETASL: /* Add a slave to a network-interface */ if (arg) { - if (copy_from_user(bname, (char *) arg, sizeof(bname) - 1)) + if (copy_from_user(bname, argp, 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)){ + if (copy_to_user(argp, s, strlen(s) + 1)){ ret = -EFAULT; } else { ret = 0; @@ -1281,7 +1398,7 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) case IIOCNETDIF: /* Delete a network-interface */ if (arg) { - if (copy_from_user(name, (char *) arg, sizeof(name))) + if (copy_from_user(name, argp, sizeof(name))) return -EFAULT; ret = down_interruptible(&dev->sem); if( ret ) return ret; @@ -1293,7 +1410,7 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) case IIOCNETSCF: /* Set configurable parameters of a network-interface */ if (arg) { - if (copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg))) + if (copy_from_user(&cfg, argp, sizeof(cfg))) return -EFAULT; return isdn_net_setcfg(&cfg); } else @@ -1301,10 +1418,10 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) case IIOCNETGCF: /* Get configurable parameters of a network-interface */ if (arg) { - if (copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg))) + if (copy_from_user(&cfg, argp, sizeof(cfg))) return -EFAULT; if (!(ret = isdn_net_getcfg(&cfg))) { - if (copy_to_user((char *) arg, (char *) &cfg, sizeof(cfg))) + if (copy_to_user(argp, &cfg, sizeof(cfg))) return -EFAULT; } return ret; @@ -1313,7 +1430,7 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) case IIOCNETANM: /* Add a phone-number to a network-interface */ if (arg) { - if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone))) + if (copy_from_user(&phone, argp, sizeof(phone))) return -EFAULT; ret = down_interruptible(&dev->sem); if( ret ) return ret; @@ -1325,11 +1442,11 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) case IIOCNETGNM: /* Get list of phone-numbers of a network-interface */ if (arg) { - if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone))) + if (copy_from_user(&phone, argp, sizeof(phone))) return -EFAULT; ret = down_interruptible(&dev->sem); if( ret ) return ret; - ret = isdn_net_getphones(&phone, (char *) arg); + ret = isdn_net_getphones(&phone, argp); up(&dev->sem); return ret; } else @@ -1337,7 +1454,7 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) case IIOCNETDNM: /* Delete a phone-number of a network-interface */ if (arg) { - if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone))) + if (copy_from_user(&phone, argp, sizeof(phone))) return -EFAULT; ret = down_interruptible(&dev->sem); if( ret ) return ret; @@ -1349,7 +1466,7 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) case IIOCNETDIL: /* Force dialing of a network-interface */ if (arg) { - if (copy_from_user(name, (char *) arg, sizeof(name))) + if (copy_from_user(name, argp, sizeof(name))) return -EFAULT; return isdn_net_force_dial(name); } else @@ -1358,13 +1475,13 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) case IIOCNETALN: if (!arg) return -EINVAL; - if (copy_from_user(name, (char *) arg, sizeof(name))) + if (copy_from_user(name, argp, 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))) + if (copy_from_user(name, argp, sizeof(name))) return -EFAULT; return isdn_ppp_hangup_slave(name); #endif @@ -1372,7 +1489,7 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) /* Force hangup of a network-interface */ if (!arg) return -EINVAL; - if (copy_from_user(name, (char *) arg, sizeof(name))) + if (copy_from_user(name, argp, sizeof(name))) return -EFAULT; return isdn_net_force_hangup(name); break; @@ -1394,7 +1511,7 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) if (arg) { int i; char *p; - if (copy_from_user((char *) &iocts, (char *) arg, + if (copy_from_user(&iocts, argp, sizeof(isdn_ioctl_struct))) return -EFAULT; if (strlen(iocts.drvid)) { @@ -1422,13 +1539,13 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) case IIOCGETPRF: /* Get all Modem-Profiles */ if (arg) { - char *p = (char *) arg; + char __user *p = argp; int i; - if ((ret = verify_area(VERIFY_WRITE, (void *) arg, + if (!access_ok(VERIFY_WRITE, argp, (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN) - * ISDN_MAX_CHANNELS))) - return ret; + * ISDN_MAX_CHANNELS)) + return -EFAULT; for (i = 0; i < ISDN_MAX_CHANNELS; i++) { if (copy_to_user(p, dev->mdm.info[i].emu.profile, @@ -1449,13 +1566,13 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) case IIOCSETPRF: /* Set all Modem-Profiles */ if (arg) { - char *p = (char *) arg; + char __user *p = argp; int i; - if ((ret = verify_area(VERIFY_READ, (void *) arg, + if (!access_ok(VERIFY_READ, argp, (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN) - * ISDN_MAX_CHANNELS))) - return ret; + * ISDN_MAX_CHANNELS)) + return -EFAULT; for (i = 0; i < ISDN_MAX_CHANNELS; i++) { if (copy_from_user(dev->mdm.info[i].emu.profile, p, @@ -1478,8 +1595,7 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) /* Set/Get MSN->EAZ-Mapping for a driver */ if (arg) { - if (copy_from_user((char *) &iocts, - (char *) arg, + if (copy_from_user(&iocts, argp, sizeof(isdn_ioctl_struct))) return -EFAULT; if (strlen(iocts.drvid)) { @@ -1496,14 +1612,14 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) if (cmd == IIOCSETMAP) { int loop = 1; - p = (char *) iocts.arg; + p = (char __user *) iocts.arg; i = 0; while (loop) { int j = 0; while (1) { - if ((ret = verify_area(VERIFY_READ, p, 1))) - return ret; + if (!access_ok(VERIFY_READ, p, 1)) + return -EFAULT; get_user(bname[j], p++); switch (bname[j]) { case '\0': @@ -1524,7 +1640,7 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) break; } } else { - p = (char *) iocts.arg; + p = (char __user *) iocts.arg; for (i = 0; i < 10; i++) { sprintf(bname, "%s%s", strlen(dev->drv[drvidx]->msn2eaz[i]) ? @@ -1540,7 +1656,7 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) return -EINVAL; case IIOCDBGVAR: if (arg) { - if (copy_to_user((char *) arg, (char *) &dev, sizeof(ulong))) + if (copy_to_user(argp, &dev, sizeof(ulong))) return -EFAULT; return 0; } else @@ -1554,7 +1670,7 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) if (arg) { int i; char *p; - if (copy_from_user((char *) &iocts, (char *) arg, sizeof(isdn_ioctl_struct))) + if (copy_from_user(&iocts, argp, sizeof(isdn_ioctl_struct))) return -EFAULT; if (strlen(iocts.drvid)) { if ((p = strchr(iocts.drvid, ','))) @@ -1569,16 +1685,16 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) drvidx = 0; if (drvidx == -1) return -ENODEV; - if ((ret = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(isdn_ioctl_struct)))) - return ret; + if (!access_ok(VERIFY_WRITE, argp, + sizeof(isdn_ioctl_struct))) + return -EFAULT; c.driver = drvidx; c.command = ISDN_CMD_IOCTL; c.arg = cmd; - memcpy(c.parm.num, (char *) &iocts.arg, sizeof(ulong)); + memcpy(c.parm.num, &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))) + memcpy(&iocts.arg, c.parm.num, sizeof(ulong)); + if (copy_to_user(argp, &iocts, sizeof(isdn_ioctl_struct))) return -EFAULT; return ret; } else @@ -1604,7 +1720,7 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) static int isdn_open(struct inode *ino, struct file *filep) { - uint minor = MINOR(ino->i_rdev); + uint minor = iminor(ino); int drvidx; int chidx; int retval = -ENODEV; @@ -1659,13 +1775,14 @@ isdn_open(struct inode *ino, struct file *filep) } #endif out: + nonseekable_open(ino, filep); return retval; } static int isdn_close(struct inode *ino, struct file *filep) { - uint minor = MINOR(ino->i_rdev); + uint minor = iminor(ino); lock_kernel(); if (minor == ISDN_MINOR_STATUS) { @@ -1798,6 +1915,11 @@ isdn_free_channel(int di, int ch, int usage) { int i; + if ((di < 0) || (ch < 0)) { + printk(KERN_WARNING "%s: called with invalid drv(%d) or channel(%d)\n", + __FUNCTION__, di, ch); + return; + } for (i = 0; i < ISDN_MAX_CHANNELS; i++) if (((!usage) || ((dev->usage[i] & ISDN_USAGE_MASK) == usage)) && (dev->drvmap[i] == di) && @@ -1813,7 +1935,8 @@ isdn_free_channel(int di, int ch, int usage) dev->v110[i] = NULL; // 20.10.99 JIM, try to reinitialize v110 ! isdn_info_update(); - skb_queue_purge(&dev->drv[di]->rpqueue[ch]); + if (dev->drv[di]) + skb_queue_purge(&dev->drv[di]->rpqueue[ch]); } } @@ -1838,20 +1961,17 @@ isdn_unexclusive_channel(int di, int ch) * writebuf replacement for SKB_ABLE drivers */ static int -isdn_writebuf_stub(int drvidx, int chan, const u_char * buf, int len, - int user) +isdn_writebuf_stub(int drvidx, int chan, const u_char __user * buf, int len) { int ret; int hl = dev->drv[drvidx]->interface->hl_hdrlen; struct sk_buff *skb = alloc_skb(hl + len, GFP_ATOMIC); if (!skb) - return 0; + return -ENOMEM; skb_reserve(skb, hl); - if (user) - copy_from_user(skb_put(skb, len), buf, len); - else - memcpy(skb_put(skb, len), buf, len); + if (copy_from_user(skb_put(skb, len), buf, len)) + return -EFAULT; ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, 1, skb); if (ret <= 0) dev_kfree_skb(skb); @@ -1932,7 +2052,7 @@ isdn_writebuf_skb_stub(int drvidx, int chan, int ack, struct sk_buff *skb) return ret; } -int +static int isdn_add_channels(isdn_driver_t *d, int drvidx, int n, int adding) { int j, k, m; @@ -1952,20 +2072,19 @@ isdn_add_channels(isdn_driver_t *d, int drvidx, int n, int adding) if ((adding) && (d->rcverr)) kfree(d->rcverr); - if (!(d->rcverr = kmalloc(sizeof(int) * m, GFP_ATOMIC))) { + if (!(d->rcverr = kzalloc(sizeof(int) * m, GFP_ATOMIC))) { printk(KERN_WARNING "register_isdn: Could not alloc rcverr\n"); return -1; } - memset((char *) d->rcverr, 0, sizeof(int) * m); if ((adding) && (d->rcvcount)) kfree(d->rcvcount); - if (!(d->rcvcount = kmalloc(sizeof(int) * m, GFP_ATOMIC))) { + if (!(d->rcvcount = kzalloc(sizeof(int) * m, GFP_ATOMIC))) { printk(KERN_WARNING "register_isdn: Could not alloc rcvcount\n"); - if (!adding) kfree(d->rcverr); + if (!adding) + kfree(d->rcverr); return -1; } - memset((char *) d->rcvcount, 0, sizeof(int) * m); if ((adding) && (d->rpqueue)) { for (j = 0; j < d->channels; j++) @@ -2105,11 +2224,10 @@ register_isdn(isdn_if * i) printk(KERN_WARNING "register_isdn: No write routine given.\n"); return 0; } - if (!(d = kmalloc(sizeof(isdn_driver_t), GFP_KERNEL))) { + if (!(d = kzalloc(sizeof(isdn_driver_t), GFP_KERNEL))) { printk(KERN_WARNING "register_isdn: Could not alloc driver-struct\n"); return 0; } - memset((char *) d, 0, sizeof(isdn_driver_t)); d->maxbufsize = i->maxbufsize; d->pktcount = 0;