📄 ppp.c
字号:
return 0; } if (current->signal & ~current->blocked) { kfree (new_data); return -EINTR; } }/* * Ensure that the caller's buffer is valid. */ status = verify_area (VERIFY_READ, data, count); if (status != 0) { kfree (new_data); ppp->tbuf->locked = 0; return status; } memcpy_fromfs (new_data, data, count);/* * Change the LQR frame */ count = send_revise_frame (ppp, new_data, count);/* * Send the data */ ppp_dev_xmit_frame (ppp, ppp->tbuf, new_data, count); kfree (new_data); return (int) count;}/* * Process the BSD compression IOCTL event for the tty device. */static intppp_set_compression (struct ppp *ppp, struct ppp_option_data *odp){ struct compressor *cp; struct ppp_option_data data; int error; int nb; __u8 *ptr; __u8 ccp_option[CCP_MAX_OPTION_LENGTH];/* * Fetch the compression parameters */ error = verify_area (VERIFY_READ, odp, sizeof (data)); if (error == 0) { memcpy_fromfs (&data, odp, sizeof (data)); nb = data.length; ptr = data.ptr; if ((__u32) nb >= (__u32)CCP_MAX_OPTION_LENGTH) nb = CCP_MAX_OPTION_LENGTH; error = verify_area (VERIFY_READ, ptr, nb); } if (error != 0) return error; memcpy_fromfs (ccp_option, ptr, nb); if (ccp_option[1] < 2) /* preliminary check on the length byte */ return (-EINVAL); cp = find_compressor ((int) (unsigned int) (__u8) ccp_option[0]); if (cp != (struct compressor *) 0) { /* * Found a handler for the protocol - try to allocate * a compressor or decompressor. */ error = 0; if (data.transmit) { if (ppp->sc_xc_state != NULL) (*ppp->sc_xcomp->comp_free)(ppp->sc_xc_state); ppp->sc_xcomp = cp; ppp->sc_xc_state = cp->comp_alloc(ccp_option, nb); if (ppp->sc_xc_state == NULL) { if (ppp->flags & SC_DEBUG) printk("ppp%ld: comp_alloc failed\n", ppp2dev (ppp)->base_addr); error = -ENOBUFS; } ppp->flags &= ~SC_COMP_RUN; } else { if (ppp->sc_rc_state != NULL) (*ppp->sc_rcomp->decomp_free)(ppp->sc_rc_state); ppp->sc_rcomp = cp; ppp->sc_rc_state = cp->decomp_alloc(ccp_option, nb); if (ppp->sc_rc_state == NULL) { if (ppp->flags & SC_DEBUG) printk("ppp%ld: decomp_alloc failed\n", ppp2dev (ppp)->base_addr); error = ENOBUFS; } ppp->flags &= ~SC_DECOMP_RUN; } return (error); } if (ppp->flags & SC_DEBUG) printk(KERN_DEBUG "ppp%ld: no compressor for [%x %x %x], %x\n", ppp2dev (ppp)->base_addr, ccp_option[0], ccp_option[1], ccp_option[2], nb); return (-EINVAL); /* no handler found */}/* * Process the IOCTL event for the tty device. */static intppp_tty_ioctl (struct tty_struct *tty, struct file * file, unsigned int param2, unsigned long param3){ struct ppp *ppp = tty2ppp (tty); register int temp_i = 0; int error = 0;/* * Verify the status of the PPP device. */ if (!ppp) return -EBADF; if (ppp->magic != PPP_MAGIC) return -EBADF; CHECK_PPP (-ENXIO);/* * The user must have an euid of root to do these requests. */ if (!suser ()) return -EPERM;/* * Set the MRU value */ switch (param2) { case PPPIOCSMRU: error = verify_area (VERIFY_READ, (void *) param3, sizeof (temp_i)); if (error == 0) { temp_i = get_user ((int *) param3); if (ppp->flags & SC_DEBUG) printk (KERN_INFO "ppp_tty_ioctl: set mru to %x\n", temp_i); if (ppp->mru != temp_i) ppp_changedmtu (ppp, ppp2dev (ppp)->mtu, temp_i); } break;/* * Fetch the flags */ case PPPIOCGFLAGS: error = verify_area (VERIFY_WRITE, (void *) param3, sizeof (temp_i)); if (error == 0) { temp_i = (ppp->flags & SC_MASK);#ifndef CHECK_CHARACTERS /* Don't generate errors if we don't check chars. */ temp_i |= SC_RCV_B7_1 | SC_RCV_B7_0 | SC_RCV_ODDP | SC_RCV_EVNP;#endif put_user (temp_i, (int *) param3); if (ppp->flags & SC_DEBUG) printk (KERN_DEBUG "ppp_tty_ioctl: get flags: addr %lx flags " "%x\n", param3, temp_i); } break;/* * Set the flags for the various options */ case PPPIOCSFLAGS: error = verify_area (VERIFY_READ, (void *) param3, sizeof (temp_i)); if (error == 0) { temp_i = get_user ((int *) param3) & SC_MASK; temp_i |= (ppp->flags & ~SC_MASK); if ((ppp->flags & SC_CCP_OPEN) && (temp_i & SC_CCP_OPEN) == 0) ppp_ccp_closed (ppp); if ((ppp->flags | temp_i) & SC_DEBUG) printk (KERN_INFO "ppp_tty_ioctl: set flags to %x\n", temp_i); ppp->flags = temp_i; } break;/* * Set the compression mode */ case PPPIOCSCOMPRESS: error = ppp_set_compression (ppp, (struct ppp_option_data *) param3); break;/* * Retrieve the transmit async map */ case PPPIOCGASYNCMAP: error = verify_area (VERIFY_WRITE, (void *) param3, sizeof (temp_i)); if (error == 0) { put_user (ppp->xmit_async_map[0], (int *) param3); if (ppp->flags & SC_DEBUG) printk (KERN_INFO "ppp_tty_ioctl: get asyncmap: addr " "%lx asyncmap %x\n", param3, ppp->xmit_async_map[0]); } break;/* * Set the transmit async map */ case PPPIOCSASYNCMAP: error = verify_area (VERIFY_READ, (void *) param3, sizeof (temp_i)); if (error == 0) { ppp->xmit_async_map[0] = get_user ((int *) param3); if (ppp->flags & SC_DEBUG) printk (KERN_INFO "ppp_tty_ioctl: set xmit asyncmap %x\n", ppp->xmit_async_map[0]); } break;/* * Set the receive async map */ case PPPIOCSRASYNCMAP: error = verify_area (VERIFY_READ, (void *) param3, sizeof (temp_i)); if (error == 0) { ppp->recv_async_map = get_user ((int *) param3); if (ppp->flags & SC_DEBUG) printk (KERN_INFO "ppp_tty_ioctl: set rcv asyncmap %x\n", ppp->recv_async_map); } break;/* * Obtain the unit number for this device. */ case PPPIOCGUNIT: error = verify_area (VERIFY_WRITE, (void *) param3, sizeof (temp_i)); if (error == 0) { put_user (ppp2dev (ppp)->base_addr, (int *) param3); if (ppp->flags & SC_DEBUG) printk (KERN_INFO "ppp_tty_ioctl: get unit: %ld", ppp2dev (ppp)->base_addr); } break;/* * Set the debug level */ case PPPIOCSDEBUG: error = verify_area (VERIFY_READ, (void *) param3, sizeof (temp_i)); if (error == 0) { temp_i = (get_user ((int *) param3) & 0x1F) << 16; temp_i |= (ppp->flags & ~0x1F0000); if ((ppp->flags | temp_i) & SC_DEBUG) printk (KERN_INFO "ppp_tty_ioctl: set flags to %x\n", temp_i); ppp->flags = temp_i; } break;/* * Get the debug level */ case PPPIOCGDEBUG: error = verify_area (VERIFY_WRITE, (void *) param3, sizeof (temp_i)); if (error == 0) { temp_i = (ppp->flags >> 16) & 0x1F; put_user (temp_i, (int *) param3); if (ppp->flags & SC_DEBUG) printk (KERN_INFO "ppp_tty_ioctl: get debug level %d\n", temp_i); } break;/* * Get the times since the last send/receive frame operation */ case PPPIOCGIDLE: error = verify_area (VERIFY_WRITE, (void *) param3, sizeof (struct ppp_idle)); if (error == 0) { struct ppp_idle cur_ddinfo; __u32 cur_jiffies = jiffies; /* change absolute times to relative times. */ cur_ddinfo.xmit_idle = (cur_jiffies - ppp->ddinfo.xmit_idle) / HZ; cur_ddinfo.recv_idle = (cur_jiffies - ppp->ddinfo.recv_idle) / HZ; memcpy_tofs ((void *) param3, &cur_ddinfo, sizeof (cur_ddinfo)); if (ppp->flags & SC_DEBUG) printk (KERN_INFO "ppp_tty_ioctl: read demand dial info\n"); } break;/* * Retrieve the extended async map */ case PPPIOCGXASYNCMAP: error = verify_area (VERIFY_WRITE, (void *) param3, sizeof (ppp->xmit_async_map)); if (error == 0) { memcpy_tofs ((void *) param3, ppp->xmit_async_map, sizeof (ppp->xmit_async_map)); if (ppp->flags & SC_DEBUG) printk (KERN_INFO "ppp_tty_ioctl: get xasyncmap: addr %lx\n", param3); } break;/* * Set the async extended map */ case PPPIOCSXASYNCMAP: error = verify_area (VERIFY_READ, (void *) param3, sizeof (ppp->xmit_async_map)); if (error == 0) { __u32 temp_tbl[8]; memcpy_fromfs (temp_tbl, (void *) param3, sizeof (ppp->xmit_async_map)); temp_tbl[1] = 0x00000000; temp_tbl[2] &= ~0x40000000; temp_tbl[3] |= 0x60000000; if ((temp_tbl[2] & temp_tbl[3]) != 0 || (temp_tbl[4] & temp_tbl[5]) != 0 || (temp_tbl[6] & temp_tbl[7]) != 0) error = -EINVAL; else { memcpy (ppp->xmit_async_map, temp_tbl, sizeof (ppp->xmit_async_map)); if (ppp->flags & SC_DEBUG) printk (KERN_INFO "ppp_tty_ioctl: set xasyncmap\n"); } } break;/* * Set the maximum VJ header compression slot number. */ case PPPIOCSMAXCID: error = verify_area (VERIFY_READ, (void *) param3, sizeof (temp_i)); if (error == 0) { temp_i = get_user ((int *) param3) + 1; if (ppp->flags & SC_DEBUG) printk (KERN_INFO "ppp_tty_ioctl: set maxcid to %d\n", temp_i); if (ppp->slcomp != NULL) slhc_free (ppp->slcomp); ppp->slcomp = slhc_init (16, temp_i); if (ppp->slcomp == NULL) { if (ppp->flags & SC_DEBUG) printk (KERN_ERR "ppp: no space for compression buffers!\n"); ppp_release (ppp); error = -ENOMEM; } } break; case PPPIOCXFERUNIT: ppp_tty_close_local (tty, current->pid); break; case PPPIOCGNPMODE: case PPPIOCSNPMODE: error = verify_area (VERIFY_READ, (void *) param3, sizeof (struct npioctl)); if (error == 0) { struct npioctl npi; memcpy_fromfs (&npi, (void *) param3, sizeof (npi)); switch (npi.protocol) { case PPP_IP: npi.protocol = NP_IP; break; default: error = -EINVAL; } if (error != 0) break; if (param2 == PPPIOCGNPMODE) { npi.mode = ppp->sc_npmode[npi.protocol]; error = verify_area (VERIFY_WRITE, (void *) param3, sizeof (npi)); if (error != 0) break; memcpy_tofs ((void *) param3, &npi, sizeof (npi)); break; } if (npi.mode != ppp->sc_npmode[npi.protocol]) { ppp->sc_npmode[npi.protocol] = npi.mode; if (npi.mode != NPMODE_QUEUE) { /* ppp_requeue(ppp); maybe needed */ ppp_tty_wakeup (ppp2tty(ppp)); } } } break;/* * Allow users to read, but not set, the serial port parameters */ case TCGETS: case TCGETA: error = n_tty_ioctl (tty, file, param2, param3); break; case FIONREAD: error = verify_area (VERIFY_WRITE, (void *) param3, sizeof (int)); if (error == 0) { int count = ppp->ubuf->tail - ppp->ubuf->head; if (count < 0) count += (ppp->ubuf->size + 1); put_user (count, (int *) param3); } break;/* * All other ioctl() events will come here. */ default: if (ppp->flags & SC_DEBUG) printk (KERN_ERR "ppp_tty_ioctl: invalid ioctl: %x, addr %lx\n", param2, param3); error = -ENOIOCTLCMD; break; } return error;}/* * TTY callback. * * Process the select() statement for the PPP device. */static intppp_tty_select (struct tty_struct *tty, struct inode *inode, struct file *filp, int sel_type, select_table * wait){ struct ppp *ppp = tty2ppp (tty); int result = 1;/* * Verify the status of the PPP device. */ if (!ppp) return -EBADF; if (ppp->magic != PPP_MAGIC) return -EBADF; CHECK_PPP (0);/* * Branch on the type of select mode. A read request must lock the user * buffer area. */ switch (sel_type) { case SEL_IN: if (set_bit (0, &ppp->ubuf->locked) == 0) { /* Test for the presence of data in the queue */ if (ppp->ubuf->head != ppp->ubuf->tail) { clear_bit (0, &ppp->ubuf->locked); break; } clear_bit (0, &ppp->ubuf->locked); } /* fall through */ /* * Exceptions or read errors. */ case SEL_EX: /* Is this a pty link and the remote disconnected? */ if (tty->flags & (1 << TTY_OTHER_CLOSED)) break; /* Is this a local link and the modem disconnected? */ if (tty_hung_up_p (filp)) break; select_wait (&ppp->read_wait, wait); result = 0; break;/* * Write mode. A write is allowed if there is no current transmission. */ case SEL_OUT: if (ppp->tbuf->locked != 0) { select_wait (&ppp->write_wait, wait); result = 0; } break; } return result;}/************************************************************* * NETWORK OUTPUT * This routine accepts requests from the network layer * and attempts to deliver the packets. * It also includes various routine
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -