-/*
- * Print the buffer
- */
- if (ppp->flags & SC_LOG_OUTPKT)
- ppp_print_buffer ("write frame", data, count);
-/*
- * Determine if the frame may be compressed. Attempt to compress the
- * frame if possible.
- */
- proto = PPP_PROTOCOL (data);
- address = PPP_ADDRESS (data);
- control = PPP_CONTROL (data);
-
- if (((ppp->flags & SC_COMP_RUN) != 0) &&
- (ppp->sc_xc_state != (void *) 0) &&
- (address == PPP_ALLSTATIONS) &&
- (control == PPP_UI) &&
- (proto != PPP_LCP) &&
- (proto != PPP_CCP)) {
- new_data = kmalloc (count, GFP_ATOMIC);
- if (new_data == NULL) {
- if (ppp->flags & SC_DEBUG)
- printk (KERN_ERR
- "ppp_dev_xmit_frame: no memory\n");
- return 1;
- }
-
- new_count = (*ppp->sc_xcomp->compress)
- (ppp->sc_xc_state, data, new_data, count, count);
-
- if (new_count > 0 && (ppp->flags & SC_CCP_UP)) {
- ppp_dev_xmit_lower (ppp, buf, new_data, new_count, 0);
- kfree (new_data);
- return 0;
- }
-/*
- * The frame could not be compressed, or it could not be sent in
- * compressed form because CCP is not yet up.
- */
- kfree (new_data);
- }
-/*
- * Go to the escape encoding
- */
- ppp_dev_xmit_lower (ppp, buf, data, count, !!(proto & 0xFF00));
- return 0;
-}
-
-/*
- * Revise the tty frame for specific protocols.
- */
-
-static int
-send_revise_frame (register struct ppp *ppp, __u8 *data, int len)
-{
- __u8 *p;
-
- switch (PPP_PROTOCOL (data)) {
-/*
- * Update the LQR frame with the current MIB information. This saves having
- * the daemon read old MIB data from the driver.
- */
- case PPP_LQR:
- len = 48; /* total size of this frame */
- p = (__u8 *) &data [40]; /* Point to last two items. */
- p = store_long (p, ppp->stats.ppp_opackets + 1);
- p = store_long (p, ppp->stats.ppp_ooctects + len);
- break;
-/*
- * Outbound compression frames
- */
- case PPP_CCP:
- ppp_proto_ccp (ppp,
- data + PPP_HARD_HDR_LEN,
- len - PPP_HARD_HDR_LEN,
- 0);
- break;
-
- default:
- break;
- }
-
- return len;
-}
-
-/*
- * write a frame with NR chars from BUF to TTY
- * we have to put the FCS field on ourselves
- */
-
-static int
-ppp_tty_write (struct tty_struct *tty, struct file *file, const __u8 * data,
- unsigned int count)
-{
- struct ppp *ppp = tty2ppp (tty);
- __u8 *new_data;
- int status;
-/*
- * Verify the pointers.
- */
- if (!ppp)
- return -EIO;
-
- if (ppp->magic != PPP_MAGIC)
- return -EIO;
-
- CHECK_PPP (-ENXIO);
-/*
- * Ensure that the caller does not wish to send too much.
- */
- if (count > PPP_MTU + PPP_HDRLEN) {
- if (ppp->flags & SC_DEBUG)
- printk (KERN_WARNING
- "ppp_tty_write: truncating user packet "
- "from %u to mtu %d\n", count,
- PPP_MTU + PPP_HDRLEN);
- count = PPP_MTU + PPP_HDRLEN;
- }
-/*
- * Allocate a buffer for the data and fetch it from the user space.
- */
- new_data = kmalloc (count, GFP_KERNEL);
- if (new_data == NULL) {
- if (ppp->flags & SC_DEBUG)
- printk (KERN_ERR
- "ppp_tty_write: no memory\n");
- return 0;
- }
-/*
- * lock this PPP unit so we will be the only writer;
- * sleep if necessary
- */
- while (lock_buffer (ppp->tbuf) != 0) {
- current->timeout = 0;
- if (ppp->flags & SC_DEBUG)
- printk (KERN_DEBUG "ppp_tty_write: sleeping\n");
- interruptible_sleep_on (&ppp->write_wait);
-
- ppp = tty2ppp (tty);
- if (!ppp || ppp->magic != PPP_MAGIC || !ppp->inuse
- || tty != ppp->tty) {
- kfree (new_data);
- return 0;
- }
-
- if (current->signal & ~current->blocked) {
- kfree (new_data);
- return -EINTR;
- }
- }
-/*
- * Retrieve the user's buffer
- */
- COPY_FROM_USER (status,
- new_data,
- data,
- count);
-
- if (status != 0) {
- kfree (new_data);
- ppp->tbuf->locked = 0;
- return status;
- }
-/*
- * 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 int
-ppp_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
- */
- COPY_FROM_USER (error,
- &data,
- odp,
- sizeof (data));
-
- if (error != 0)
- return error;
-
- nb = data.length;
- ptr = data.ptr;
- if ((__u32) nb >= (__u32)CCP_MAX_OPTION_LENGTH)
- nb = CCP_MAX_OPTION_LENGTH;
-
- COPY_FROM_USER (error,
- ccp_option,
- ptr,
- nb);
-
- if (error != 0)
- return error;
-
- 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 int
-ppp_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:
- GET_USER (error, temp_i, (int *) param3);
- if (error == 0) {
- 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:
- 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 (error, temp_i, (int *) param3);
- break;
-/*
- * Set the flags for the various options
- */
- case PPPIOCSFLAGS:
- GET_USER (error, temp_i, (int *) param3);
- if (error == 0) {
- temp_i &= 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:
- PUT_USER (error, ppp->xmit_async_map[0], (int *) param3);
- break;
-/*
- * Set the transmit async map
- */
- case PPPIOCSASYNCMAP:
- GET_USER (error, temp_i, (int *) param3);
- if (error == 0) {
- ppp->xmit_async_map[0] = temp_i;
- 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:
- GET_USER (error, temp_i, (int *) param3);
- if (error == 0) {
- ppp->recv_async_map = temp_i;
- 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:
- PUT_USER (error, ppp2dev (ppp)->base_addr, (int *) param3);
- if (error == 0) {
- if (ppp->flags & SC_DEBUG)
- printk (KERN_INFO
- "ppp_tty_ioctl: get unit: %ld\n",
- ppp2dev (ppp)->base_addr);
- }
- break;
-/*
- * Set the debug level
- */
- case PPPIOCSDEBUG:
- GET_USER (error, temp_i, (int *) param3);
- if (error == 0) {
- temp_i = (temp_i & 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:
- temp_i = (ppp->flags >> 16) & 0x1F;
- PUT_USER (error, temp_i, (int *) param3);
- break;
-/*
- * Get the times since the last send/receive frame operation
- */
- case PPPIOCGIDLE:
- {
- 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;
- COPY_TO_USER (error,
- (void *) param3,
- &cur_ddinfo,
- sizeof (cur_ddinfo));
- }
- break;
-/*
- * Retrieve the extended async map
- */
- case PPPIOCGXASYNCMAP:
- COPY_TO_USER (error,
- (void *) param3,
- ppp->xmit_async_map,
- sizeof (ppp->xmit_async_map));
- break;
-/*
- * Set the async extended map
- */
- case PPPIOCSXASYNCMAP:
- {
- __u32 temp_tbl[8];
-
- COPY_FROM_USER (error,
- temp_tbl,
- (void *) param3,
- sizeof (temp_tbl));
-
- if (error == 0) {
- 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:
- GET_USER (error, temp_i, (int *) param3);
- if (error == 0) {
- temp_i = (temp_i & 255) + 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->backup_tty = tty;
- ppp->sc_xfer = current->pid;
- break;