📄 capi.c
字号:
capifs_free_ncci(0, mp->minor);#endif if (mp->tty) { mp->nccip = 0;#ifdef _DEBUG_REFCOUNT printk(KERN_DEBUG "reset mp->nccip\n");#endif tty_hangup(mp->tty); } else if (mp->file) { mp->nccip = 0;#ifdef _DEBUG_REFCOUNT printk(KERN_DEBUG "reset mp->nccip\n");#endif wake_up_interruptible(&mp->recvwait); wake_up_interruptible(&mp->sendwait); } else { capiminor_free(mp); } }#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ kmem_cache_free(capincci_cachep, np); if (*pp == 0) return; } else { pp = &(*pp)->next; } }}struct capincci *capincci_find(struct capidev *cdev, __u32 ncci){ struct capincci *p; for (p=cdev->nccis; p ; p = p->next) { if (p->ncci == ncci) break; } return p;}/* -------- struct capidev ------------------------------------------ */static struct capidev *capidev_alloc(struct file *file){ struct capidev *cdev; struct capidev **pp; cdev = (struct capidev *)kmem_cache_alloc(capidev_cachep, GFP_KERNEL); if (!cdev) return 0; memset(cdev, 0, sizeof(struct capidev)); cdev->file = file; cdev->minor = MINOR(file->f_dentry->d_inode->i_rdev); skb_queue_head_init(&cdev->recvqueue); init_waitqueue_head(&cdev->recvwait); pp=&capidev_openlist; while (*pp) pp = &(*pp)->next; *pp = cdev; return cdev;}static void capidev_free(struct capidev *cdev){ struct capidev **pp; struct sk_buff *skb; if (cdev->applid) (*capifuncs->capi_release) (cdev->applid); cdev->applid = 0; while ((skb = skb_dequeue(&cdev->recvqueue)) != 0) { kfree_skb(skb); } pp=&capidev_openlist; while (*pp && *pp != cdev) pp = &(*pp)->next; if (*pp) *pp = cdev->next; kmem_cache_free(capidev_cachep, cdev);}static struct capidev *capidev_find(__u16 applid){ struct capidev *p; for (p=capidev_openlist; p; p = p->next) { if (p->applid == applid) break; } return p;}#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE/* -------- handle data queue --------------------------------------- */struct sk_buff *gen_data_b3_resp_for(struct capiminor *mp, struct sk_buff *skb){ struct sk_buff *nskb; nskb = alloc_skb(CAPI_DATA_B3_RESP_LEN, GFP_ATOMIC); if (nskb) { __u16 datahandle = CAPIMSG_U16(skb->data,CAPIMSG_BASELEN+4+4+2); unsigned char *s = skb_put(nskb, CAPI_DATA_B3_RESP_LEN); capimsg_setu16(s, 0, CAPI_DATA_B3_RESP_LEN); capimsg_setu16(s, 2, mp->applid); capimsg_setu8 (s, 4, CAPI_DATA_B3); capimsg_setu8 (s, 5, CAPI_RESP); capimsg_setu16(s, 6, mp->msgid++); capimsg_setu32(s, 8, mp->ncci); capimsg_setu16(s, 12, datahandle); } return nskb;}int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb){ struct sk_buff *nskb; unsigned int datalen; __u16 errcode, datahandle; datalen = skb->len - CAPIMSG_LEN(skb->data); if (mp->tty) { if (mp->tty->ldisc.receive_buf == 0) { printk(KERN_ERR "capi: ldisc has no receive_buf function\n"); return -1; } if (mp->ttyinstop) {#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS) printk(KERN_DEBUG "capi: recv tty throttled\n");#endif return -1; } if (mp->tty->ldisc.receive_room && mp->tty->ldisc.receive_room(mp->tty) < datalen) {#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS) printk(KERN_DEBUG "capi: no room in tty\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 => ldisc\n", datahandle, skb->len);#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;}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; } }}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 loff_tcapi_llseek(struct file *file, loff_t offset, int origin){ return -ESPIPE;}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 ((retval = copy_from_user(skb_put(skb, count), buf, count))) { kfree_skb(skb); return retval; } 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -