📄 capi.c
字号:
#endif mp->tty->ldisc.receive_buf(mp->tty, skb->data, 0, skb->len); kfree_skb(skb); return 0; } else if (mp->file) { if (skb_queue_len(&mp->recvqueue) > CAPINC_MAX_RECVQUEUE) {#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS) printk(KERN_DEBUG "capi: no room in raw queue\n");#endif return -1; } if ((nskb = gen_data_b3_resp_for(mp, skb)) == 0) { printk(KERN_ERR "capi: gen_data_b3_resp failed\n"); return -1; } datahandle = CAPIMSG_U16(skb->data,CAPIMSG_BASELEN+4); errcode = (*capifuncs->capi_put_message)(mp->applid, nskb); if (errcode != CAPI_NOERROR) { printk(KERN_ERR "capi: send DATA_B3_RESP failed=%x\n", errcode); kfree_skb(nskb); return -1; } (void)skb_pull(skb, CAPIMSG_LEN(skb->data));#ifdef _DEBUG_DATAFLOW printk(KERN_DEBUG "capi: DATA_B3_RESP %u len=%d => raw\n", datahandle, skb->len);#endif skb_queue_tail(&mp->recvqueue, skb); wake_up_interruptible(&mp->recvwait); return 0; }#ifdef _DEBUG_DATAFLOW printk(KERN_DEBUG "capi: currently no receiver\n");#endif return -1;}static void handle_minor_recv(struct capiminor *mp){ struct sk_buff *skb; while ((skb = skb_dequeue(&mp->inqueue)) != 0) { unsigned int len = skb->len; mp->inbytes -= len; if (handle_recv_skb(mp, skb) < 0) { skb_queue_head(&mp->inqueue, skb); mp->inbytes += len; return; } }}static int handle_minor_send(struct capiminor *mp){ struct sk_buff *skb; u16 len; int count = 0; u16 errcode; u16 datahandle; if (mp->tty && mp->ttyoutstop) {#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS) printk(KERN_DEBUG "capi: send: tty stopped\n");#endif return 0; } while ((skb = skb_dequeue(&mp->outqueue)) != 0) { datahandle = mp->datahandle; len = (u16)skb->len; skb_push(skb, CAPI_DATA_B3_REQ_LEN); memset(skb->data, 0, CAPI_DATA_B3_REQ_LEN); capimsg_setu16(skb->data, 0, CAPI_DATA_B3_REQ_LEN); capimsg_setu16(skb->data, 2, mp->applid); capimsg_setu8 (skb->data, 4, CAPI_DATA_B3); capimsg_setu8 (skb->data, 5, CAPI_REQ); capimsg_setu16(skb->data, 6, mp->msgid++); capimsg_setu32(skb->data, 8, mp->ncci); /* NCCI */ capimsg_setu32(skb->data, 12, (u32) skb->data); /* Data32 */ capimsg_setu16(skb->data, 16, len); /* Data length */ capimsg_setu16(skb->data, 18, datahandle); capimsg_setu16(skb->data, 20, 0); /* Flags */ if (capincci_add_ack(mp, datahandle) < 0) { skb_pull(skb, CAPI_DATA_B3_REQ_LEN); skb_queue_head(&mp->outqueue, skb); return count; } errcode = (*capifuncs->capi_put_message) (mp->applid, skb); if (errcode == CAPI_NOERROR) { mp->datahandle++; count++; mp->outbytes -= len;#ifdef _DEBUG_DATAFLOW printk(KERN_DEBUG "capi: DATA_B3_REQ %u len=%u\n", datahandle, len);#endif continue; } capiminor_del_ack(mp, datahandle); if (errcode == CAPI_SENDQUEUEFULL) { skb_pull(skb, CAPI_DATA_B3_REQ_LEN); skb_queue_head(&mp->outqueue, skb); break; } /* ups, drop packet */ printk(KERN_ERR "capi: put_message = %x\n", errcode); mp->outbytes -= len; kfree_skb(skb); } if (count) wake_up_interruptible(&mp->sendwait); return count;}#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE *//* -------- function called by lower level -------------------------- */static void capi_signal(u16 applid, void *param){ struct capidev *cdev = (struct capidev *)param;#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE struct capiminor *mp; u16 datahandle;#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ struct capincci *np; struct sk_buff *skb = 0; u32 ncci; (void) (*capifuncs->capi_get_message) (applid, &skb); if (!skb) { printk(KERN_ERR "BUG: capi_signal: no skb\n"); return; } if (CAPIMSG_COMMAND(skb->data) != CAPI_DATA_B3) { skb_queue_tail(&cdev->recvqueue, skb); wake_up_interruptible(&cdev->recvwait); return; } ncci = CAPIMSG_CONTROL(skb->data); for (np = cdev->nccis; np && np->ncci != ncci; np = np->next) ; if (!np) { printk(KERN_ERR "BUG: capi_signal: ncci not found\n"); skb_queue_tail(&cdev->recvqueue, skb); wake_up_interruptible(&cdev->recvwait); return; }#ifndef CONFIG_ISDN_CAPI_MIDDLEWARE skb_queue_tail(&cdev->recvqueue, skb); wake_up_interruptible(&cdev->recvwait);#else /* CONFIG_ISDN_CAPI_MIDDLEWARE */ mp = np->minorp; if (!mp) { skb_queue_tail(&cdev->recvqueue, skb); wake_up_interruptible(&cdev->recvwait); return; } if (CAPIMSG_SUBCOMMAND(skb->data) == CAPI_IND) { datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN+4+4+2);#ifdef _DEBUG_DATAFLOW printk(KERN_DEBUG "capi_signal: DATA_B3_IND %u len=%d\n", datahandle, skb->len-CAPIMSG_LEN(skb->data));#endif skb_queue_tail(&mp->inqueue, skb); mp->inbytes += skb->len; handle_minor_recv(mp); } else if (CAPIMSG_SUBCOMMAND(skb->data) == CAPI_CONF) { datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN+4);#ifdef _DEBUG_DATAFLOW printk(KERN_DEBUG "capi_signal: DATA_B3_CONF %u 0x%x\n", datahandle, CAPIMSG_U16(skb->data, CAPIMSG_BASELEN+4+2));#endif kfree_skb(skb); (void)capiminor_del_ack(mp, datahandle); if (mp->tty) { if (mp->tty->ldisc.write_wakeup) mp->tty->ldisc.write_wakeup(mp->tty); } else { wake_up_interruptible(&mp->sendwait); } (void)handle_minor_send(mp); } else { /* ups, let capi application handle it :-) */ skb_queue_tail(&cdev->recvqueue, skb); wake_up_interruptible(&cdev->recvwait); }#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */}/* -------- file_operations for capidev ----------------------------- */static ssize_tcapi_read(struct file *file, char *buf, size_t count, loff_t *ppos){ struct capidev *cdev = (struct capidev *)file->private_data; struct sk_buff *skb; int retval; size_t copied; if (ppos != &file->f_pos) return -ESPIPE; if (!cdev->applid) return -ENODEV; if ((skb = skb_dequeue(&cdev->recvqueue)) == 0) { if (file->f_flags & O_NONBLOCK) return -EAGAIN; for (;;) { interruptible_sleep_on(&cdev->recvwait); if ((skb = skb_dequeue(&cdev->recvqueue)) != 0) break; if (signal_pending(current)) break; } if (skb == 0) return -ERESTARTNOHAND; } if (skb->len > count) { skb_queue_head(&cdev->recvqueue, skb); return -EMSGSIZE; } retval = copy_to_user(buf, skb->data, skb->len); if (retval) { skb_queue_head(&cdev->recvqueue, skb); return retval; } copied = skb->len; if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_IND) { cdev->nrecvdatapkt++; } else { cdev->nrecvctlpkt++; } kfree_skb(skb); return copied;}static ssize_tcapi_write(struct file *file, const char *buf, size_t count, loff_t *ppos){ struct capidev *cdev = (struct capidev *)file->private_data; struct sk_buff *skb; int retval; u16 mlen; if (ppos != &file->f_pos) return -ESPIPE; if (!cdev->applid) return -ENODEV; skb = alloc_skb(count, GFP_USER); if (!skb) return -ENOMEM; if ((retval = copy_from_user(skb_put(skb, count), buf, count))) { kfree_skb(skb); return -EFAULT; } mlen = CAPIMSG_LEN(skb->data); if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_REQ) { if (mlen + CAPIMSG_DATALEN(skb->data) != count) { kfree_skb(skb); return -EINVAL; } } else { if (mlen != count) { kfree_skb(skb); return -EINVAL; } } CAPIMSG_SETAPPID(skb->data, cdev->applid); cdev->errcode = (*capifuncs->capi_put_message) (cdev->applid, skb); if (cdev->errcode) { kfree_skb(skb); return -EIO; } if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_REQ) { cdev->nsentdatapkt++; } else { cdev->nsentctlpkt++; } return count;}static unsigned intcapi_poll(struct file *file, poll_table * wait){ struct capidev *cdev = (struct capidev *)file->private_data; unsigned int mask = 0; if (!cdev->applid) return POLLERR; poll_wait(file, &(cdev->recvwait), wait); mask = POLLOUT | POLLWRNORM; if (!skb_queue_empty(&cdev->recvqueue)) mask |= POLLIN | POLLRDNORM; return mask;}static intcapi_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ struct capidev *cdev = (struct capidev *)file->private_data; capi_ioctl_struct data; int retval = -EINVAL; switch (cmd) { case CAPI_REGISTER: { retval = copy_from_user((void *) &data.rparams, (void *) arg, sizeof(struct capi_register_params)); if (retval) return -EFAULT; if (cdev->applid) return -EEXIST; cdev->errcode = (*capifuncs->capi_register) (&data.rparams, &cdev->applid); if (cdev->errcode) { cdev->applid = 0; return -EIO; } (void) (*capifuncs->capi_set_signal) (cdev->applid, capi_signal, cdev); } return (int)cdev->applid; case CAPI_GET_VERSION: { retval = copy_from_user((void *) &data.contr, (void *) arg, sizeof(data.contr)); if (retval) return -EFAULT; cdev->errcode = (*capifuncs->capi_get_version) (data.contr, &data.version); if (cdev->errcode) return -EIO; retval = copy_to_user((void *) arg, (void *) &data.version, sizeof(data.version)); if (retval) return -EFAULT; } return 0; case CAPI_GET_SERIAL: { retval = copy_from_user((void *) &data.contr, (void *) arg, sizeof(data.contr)); if (retval) return -EFAULT; cdev->errcode = (*capifuncs->capi_get_serial) (data.contr, data.serial); if (cdev->errcode) return -EIO; retval = copy_to_user((void *) arg, (void *) data.serial, sizeof(data.serial)); if (retval) return -EFAULT; } return 0; case CAPI_GET_PROFILE: { retval = copy_from_user((void *) &data.contr, (void *) arg, sizeof(data.contr)); if (retval) return -EFAULT; if (data.contr == 0) { cdev->errcode = (*capifuncs->capi_get_profile) (data.contr, &data.profile); if (cdev->errcode) return -EIO; retval = copy_to_user((void *) arg, (void *) &data.profile.ncontroller, sizeof(data.profile.ncontroller)); } else { cdev->errcode = (*capifuncs->capi_get_profile) (data.contr, &data.profile); if (cdev->errcode) return -EIO; retval = copy_to_user((void *) arg, (void *) &data.profile, sizeof(data.profile)); } if (retval) return -EFAULT; } return 0; case CAPI_GET_MANUFACTURER: { retval = copy_from_user((void *) &data.contr, (void *) arg, sizeof(data.contr)); if (retval) return -EFAULT; cdev->errcode = (*capifuncs->capi_get_manufacturer) (data.contr, data.manufacturer); if (cdev->errcode) return -EIO; retval = copy_to_user((void *) arg, (void *) data.manufacturer, sizeof(data.manufacturer)); if (retval) return -EFAULT; } return 0; case CAPI_GET_ERRCODE: data.errcode = cdev->errcode; cdev->errcode = CAPI_NOERROR; if (arg) { retval = copy_to_user((void *) arg, (void *) &data.errcode, sizeof(data.errcode)); if (retval) return -EFAULT; } return data.errcode; case CAPI_INSTALLED: if ((*capifuncs->capi_isinstalled)() == CAPI_NOERROR) return 0; return -ENXIO; case CAPI_MANUFACTURER_CMD: { struct capi_manufacturer_cmd mcmd; if (!capable(CAP_SYS_ADMIN)) return -EPERM; retval = copy_from_user((void *) &mcmd, (void *) arg, sizeof(mcmd)); if (retval) return -EFAULT; return (*capifuncs->capi_manufacturer) (mcmd.cmd, mcmd.data); } return 0; case CAPI_SET_FLAGS: case CAPI_CLR_FLAGS: { unsigned userflags; retval = copy_from_user((void *) &userflags, (void *) arg, sizeof(userflags)); if (retval) return -EFAULT; if (cmd == CAPI_SET_FLAGS) cdev->userflags |= userflags; else cdev->userflags &= ~userflags; } return 0; case CAPI_GET_FLAGS: { retval = copy_to_user((void *) arg, (void *) &cdev->userflags, sizeof(cdev->userflags)); if (retval) return -EFAULT; } return 0; case CAPI_NCCI_OPENCOUNT: { struct capincci *nccip;#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE struct capiminor *mp;#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ unsigned ncci; int count = 0; retval = copy_from_user((void *) &ncci, (void *) arg, sizeof(ncci)); if (retval) return -EFAULT; nccip = capincci_find(cdev, (u32) ncci); if (!nccip)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -