📄 isdn_ppp.c
字号:
#ifdef CONFIG_ISDN_MPP if (!(is->state & IPPP_CONNECT)) return -EINVAL; if ((r = get_arg(argp, &val, sizeof(val) ))) return r; printk(KERN_DEBUG "iPPP-bundle: minor: %d, slave unit: %d, master unit: %d\n", (int) min, (int) is->unit, (int) val); return isdn_ppp_bundle(is, val);#else return -1;#endif break; case PPPIOCGUNIT: /* get ppp/isdn unit number */ if ((r = set_arg(argp, &is->unit, sizeof(is->unit) ))) return r; break; case PPPIOCGIFNAME: if(!lp) return -EINVAL; if ((r = set_arg(argp, lp->name, strlen(lp->name)))) return r; break; case PPPIOCGMPFLAGS: /* get configuration flags */ if ((r = set_arg(argp, &is->mpppcfg, sizeof(is->mpppcfg) ))) return r; break; case PPPIOCSMPFLAGS: /* set configuration flags */ if ((r = get_arg(argp, &val, sizeof(val) ))) return r; is->mpppcfg = val; break; case PPPIOCGFLAGS: /* get configuration flags */ if ((r = set_arg(argp, &is->pppcfg,sizeof(is->pppcfg) ))) return r; break; case PPPIOCSFLAGS: /* set configuration flags */ if ((r = get_arg(argp, &val, sizeof(val) ))) { return r; } if (val & SC_ENABLE_IP && !(is->pppcfg & SC_ENABLE_IP) && (is->state & IPPP_CONNECT)) { if (lp) { /* OK .. we are ready to send buffers */ is->pppcfg = val; /* isdn_ppp_xmit test for SC_ENABLE_IP !!! */ netif_wake_queue(&lp->netdev->dev); break; } } is->pppcfg = val; break; case PPPIOCGIDLE: /* get idle time information */ if (lp) { struct ppp_idle pidle; pidle.xmit_idle = pidle.recv_idle = lp->huptimer; if ((r = set_arg(argp, &pidle,sizeof(struct ppp_idle)))) return r; } break; case PPPIOCSMRU: /* set receive unit size for PPP */ if ((r = get_arg(argp, &val, sizeof(val) ))) return r; is->mru = val; break; case PPPIOCSMPMRU: break; case PPPIOCSMPMTU: break; case PPPIOCSMAXCID: /* set the maximum compression slot id */ if ((r = get_arg(argp, &val, sizeof(val) ))) return r; val++; if (is->maxcid != val) {#ifdef CONFIG_ISDN_PPP_VJ struct slcompress *sltmp;#endif if (is->debug & 0x1) printk(KERN_DEBUG "ippp, ioctl: changed MAXCID to %ld\n", val); is->maxcid = val;#ifdef CONFIG_ISDN_PPP_VJ sltmp = slhc_init(16, val); if (!sltmp) { printk(KERN_ERR "ippp, can't realloc slhc struct\n"); return -ENOMEM; } if (is->slcomp) slhc_free(is->slcomp); is->slcomp = sltmp;#endif } break; case PPPIOCGDEBUG: if ((r = set_arg(argp, &is->debug, sizeof(is->debug) ))) return r; break; case PPPIOCSDEBUG: if ((r = get_arg(argp, &val, sizeof(val) ))) return r; is->debug = val; break; case PPPIOCGCOMPRESSORS: { unsigned long protos[8] = {0,}; struct isdn_ppp_compressor *ipc = ipc_head; while(ipc) { j = ipc->num / (sizeof(long)*8); i = ipc->num % (sizeof(long)*8); if(j < 8) protos[j] |= (0x1<<i); ipc = ipc->next; } if ((r = set_arg(argp,protos,8*sizeof(long) ))) return r; } break; case PPPIOCSCOMPRESSOR: if ((r = get_arg(argp, &data, sizeof(struct isdn_ppp_comp_data)))) return r; return isdn_ppp_set_compressor(is, &data); case PPPIOCGCALLINFO: { struct pppcallinfo pci; memset((char *) &pci,0,sizeof(struct pppcallinfo)); if(lp) { strncpy(pci.local_num,lp->msn,63); if(lp->dial) { strncpy(pci.remote_num,lp->dial->num,63); } pci.charge_units = lp->charge; if(lp->outgoing) pci.calltype = CALLTYPE_OUTGOING; else pci.calltype = CALLTYPE_INCOMING; if(lp->flags & ISDN_NET_CALLBACK) pci.calltype |= CALLTYPE_CALLBACK; } return set_arg(argp,&pci,sizeof(struct pppcallinfo)); }#ifdef CONFIG_IPPP_FILTER case PPPIOCSPASS: { struct sock_filter *code; int len = get_filter(argp, &code); if (len < 0) return len; kfree(is->pass_filter); is->pass_filter = code; is->pass_len = len; break; } case PPPIOCSACTIVE: { struct sock_filter *code; int len = get_filter(argp, &code); if (len < 0) return len; kfree(is->active_filter); is->active_filter = code; is->active_len = len; break; }#endif /* CONFIG_IPPP_FILTER */ default: break; } return 0;}unsigned intisdn_ppp_poll(struct file *file, poll_table * wait){ u_int mask; struct ippp_buf_queue *bf, *bl; u_long flags; struct ippp_struct *is; is = file->private_data; if (is->debug & 0x2) printk(KERN_DEBUG "isdn_ppp_poll: minor: %d\n", MINOR(file->f_dentry->d_inode->i_rdev)); /* just registers wait_queue hook. This doesn't really wait. */ poll_wait(file, &is->wq, wait); if (!(is->state & IPPP_OPEN)) { if(is->state == IPPP_CLOSEWAIT) return POLLHUP; printk(KERN_DEBUG "isdn_ppp: device not open\n"); return POLLERR; } /* we're always ready to send .. */ mask = POLLOUT | POLLWRNORM; spin_lock_irqsave(&is->buflock, flags); bl = is->last; bf = is->first; /* * if IPPP_NOBLOCK is set we return even if we have nothing to read */ if (bf->next != bl || (is->state & IPPP_NOBLOCK)) { is->state &= ~IPPP_NOBLOCK; mask |= POLLIN | POLLRDNORM; } spin_unlock_irqrestore(&is->buflock, flags); return mask;}/* * fill up isdn_ppp_read() queue .. */static intisdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot){ struct ippp_buf_queue *bf, *bl; u_long flags; u_char *nbuf; struct ippp_struct *is; if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { printk(KERN_WARNING "ippp: illegal slot(%d).\n", slot); return 0; } is = ippp_table[slot]; if (!(is->state & IPPP_CONNECT)) { printk(KERN_DEBUG "ippp: device not activated.\n"); return 0; } nbuf = (unsigned char *) kmalloc(len + 4, GFP_ATOMIC); if (!nbuf) { printk(KERN_WARNING "ippp: Can't alloc buf\n"); return 0; } nbuf[0] = PPP_ALLSTATIONS; nbuf[1] = PPP_UI; nbuf[2] = proto >> 8; nbuf[3] = proto & 0xff; memcpy(nbuf + 4, buf, len); spin_lock_irqsave(&is->buflock, flags); bf = is->first; bl = is->last; if (bf == bl) { printk(KERN_WARNING "ippp: Queue is full; discarding first buffer\n"); bf = bf->next; kfree(bf->buf); is->first = bf; } bl->buf = (char *) nbuf; bl->len = len + 4; is->last = bl->next; spin_unlock_irqrestore(&is->buflock, flags); wake_up_interruptible(&is->wq); return len;}/* * read() .. non-blocking: ipppd calls it only after select() * reports, that there is data */intisdn_ppp_read(int min, struct file *file, char __user *buf, int count){ struct ippp_struct *is; struct ippp_buf_queue *b; u_long flags; u_char *save_buf; is = file->private_data; if (!(is->state & IPPP_OPEN)) return 0; if (!access_ok(VERIFY_WRITE, buf, count)) return -EFAULT; spin_lock_irqsave(&is->buflock, flags); b = is->first->next; save_buf = b->buf; if (!save_buf) { spin_unlock_irqrestore(&is->buflock, flags); return -EAGAIN; } if (b->len < count) count = b->len; b->buf = NULL; is->first = b; spin_unlock_irqrestore(&is->buflock, flags); copy_to_user(buf, save_buf, count); kfree(save_buf); return count;}/* * ipppd wanna write a packet to the card .. non-blocking */intisdn_ppp_write(int min, struct file *file, const char __user *buf, int count){ isdn_net_local *lp; struct ippp_struct *is; int proto; unsigned char protobuf[4]; is = file->private_data; if (!(is->state & IPPP_CONNECT)) return 0; lp = is->lp; /* -> push it directly to the lowlevel interface */ if (!lp) printk(KERN_DEBUG "isdn_ppp_write: lp == NULL\n"); else { /* * Don't reset huptimer for * LCP packets. (Echo requests). */ if (copy_from_user(protobuf, buf, 4)) return -EFAULT; proto = PPP_PROTOCOL(protobuf); if (proto != PPP_LCP) lp->huptimer = 0; if (lp->isdn_device < 0 || lp->isdn_channel < 0) return 0; if ((dev->drv[lp->isdn_device]->flags & DRV_FLAG_RUNNING) && lp->dialstate == 0 && (lp->flags & ISDN_NET_CONNECTED)) { unsigned short hl; struct sk_buff *skb; /* * we need to reserve enought space in front of * sk_buff. old call to dev_alloc_skb only reserved * 16 bytes, now we are looking what the driver want */ hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen; skb = alloc_skb(hl+count, GFP_ATOMIC); if (!skb) { printk(KERN_WARNING "isdn_ppp_write: out of memory!\n"); return count; } skb_reserve(skb, hl); if (copy_from_user(skb_put(skb, count), buf, count)) { kfree_skb(skb); return -EFAULT; } if (is->debug & 0x40) { printk(KERN_DEBUG "ppp xmit: len %d\n", (int) skb->len); isdn_ppp_frame_log("xmit", skb->data, skb->len, 32,is->unit,lp->ppp_slot); } isdn_ppp_send_ccp(lp->netdev,lp,skb); /* keeps CCP/compression states in sync */ isdn_net_write_super(lp, skb); } } return count;}/* * init memory, structures etc. */intisdn_ppp_init(void){ int i, j; #ifdef CONFIG_ISDN_MPP if( isdn_ppp_mp_bundle_array_init() < 0 ) return -ENOMEM;#endif /* CONFIG_ISDN_MPP */ for (i = 0; i < ISDN_MAX_CHANNELS; i++) { if (!(ippp_table[i] = (struct ippp_struct *) kmalloc(sizeof(struct ippp_struct), GFP_KERNEL))) { printk(KERN_WARNING "isdn_ppp_init: Could not alloc ippp_table\n"); for (j = 0; j < i; j++) kfree(ippp_table[j]); return -1; } memset((char *) ippp_table[i], 0, sizeof(struct ippp_struct)); spin_lock_init(&ippp_table[i]->buflock); ippp_table[i]->state = 0; ippp_table[i]->first = ippp_table[i]->rq + NUM_RCV_BUFFS - 1; ippp_table[i]->last = ippp_table[i]->rq; for (j = 0; j < NUM_RCV_BUFFS; j++) { ippp_table[i]->rq[j].buf = NULL; ippp_table[i]->rq[j].last = ippp_table[i]->rq + (NUM_RCV_BUFFS + j - 1) % NUM_RCV_BUFFS; ippp_table[i]->rq[j].next = ippp_table[i]->rq + (j + 1) % NUM_RCV_BUFFS; } } return 0;}voidisdn_ppp_cleanup(void){ int i; for (i = 0; i < ISDN_MAX_CHANNELS; i++) kfree(ippp_table[i]);#ifdef CONFIG_ISDN_MPP kfree(isdn_ppp_bundle_arr);#endif /* CONFIG_ISDN_MPP */}/* * check for address/control field and skip if allowed * retval != 0 -> discard packet silently */static int isdn_ppp_skip_ac(struct ippp_struct *is, struct sk_buff *skb) { if (skb->len < 1) return -1; if (skb->data[0] == 0xff) { if (skb->len < 2) return -1; if (skb->data[1] != 0x03) return -1; // skip address/control (AC) field skb_pull(skb, 2); } else { if (is->pppcfg & SC_REJ_COMP_AC) // if AC compression was not negotiated, but used, discard packet return -1; } return 0;}/* * get the PPP protocol header and pull skb * retval < 0 -> discard packet silently */static int isdn_ppp_strip_proto(struct sk_buff *skb) { int proto; if (skb->len < 1) return -1; if (skb->data[0] & 0x1) { // protocol field is compressed proto = skb->data[0]; skb_pull(skb, 1); } else { if (skb->len < 2) return -1; proto = ((int) skb->data[0] << 8) + skb->data[1]; skb_pull(skb, 2); } return proto;}/* * handler for incoming packets on a syncPPP interface */void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb){ struct ippp_struct *is; int slot; int proto; if (net_dev->local->master) BUG(); // we're called with the master device always slot = lp->ppp_slot; if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { printk(KERN_ERR "isdn_ppp_receive: lp->ppp_slot(%d)\n", lp->ppp_slot);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -