Commit message: ppp, slip: Validate VJ compression slot parameters completely

Currently slhc_init() treats out-of-range values of rslots and tslots
as equivalent to 0, except that if tslots is too large it will
dereference a null pointer (CVE-2015-7799).

Add a range-check at the top of the function and make it return an
ERR_PTR() on error instead of NULL.  Change the callers accordingly.

Compile-tested only.

Reported-by: 郭永刚 <guoyonggang@360.cn>
References: http://article.gmane.org/gmane.comp.security.oss.general/17908
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
Signed-off-by: David S. Miller <davem@davemloft.net>
CVE: CVE-2015-7799
CWE: NVD-CWE-Other
Vulnerability description: The slhc_init function in drivers/net/slip/slhc.c in the Linux kernel through 4.2.3 does not ensure that certain slot numbers are valid, which allows local users to cause a denial of service (NULL pointer dereference and system crash) via a crafted PPPIOCSMAXCID ioctl call.

Project: linux
File: isdn_ppp.c

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;
}

Project: linux
File: slhc.c

slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize)
{
	register int changes;
	long x;
	register struct tcphdr *thp;
	register struct iphdr *ip;
	register struct cstate *cs;
	int len, hdrlen;
	unsigned char *cp = icp;

	/* We've got a compressed packet; read the change byte */
	comp->sls_i_compressed++;
	if(isize < 3){
		comp->sls_i_error++;
		return 0;
	}
	changes = *cp++;
	if(changes & NEW_C){
		/* Make sure the state index is in range, then grab the state.
		 * If we have a good state index, clear the 'discard' flag.
		 */
		x = *cp++;	/* Read conn index */
		if(x < 0 || x > comp->rslot_limit)
			goto bad;

		comp->flags &=~ SLF_TOSS;
		comp->recv_current = x;
	} else {
		/* this packet has an implicit state index.  If we've
		 * had a line error since the last time we got an
		 * explicit state index, we have to toss the packet. */
		if(comp->flags & SLF_TOSS){
			comp->sls_i_tossed++;
			return 0;
		}
	}
	cs = &comp->rstate[comp->recv_current];
	thp = &cs->cs_tcp;
	ip = &cs->cs_ip;

	thp->check = *(__sum16 *)cp;
	cp += 2;

	thp->psh = (changes & TCP_PUSH_BIT) ? 1 : 0;
/*
 * we can use the same number for the length of the saved header and
 * the current one, because the packet wouldn't have been sent
 * as compressed unless the options were the same as the previous one
 */

	hdrlen = ip->ihl * 4 + thp->doff * 4;

	switch(changes & SPECIALS_MASK){
	case SPECIAL_I:		/* Echoed terminal traffic */
		{
		register short i;
		i = ntohs(ip->tot_len) - hdrlen;
		thp->ack_seq = htonl( ntohl(thp->ack_seq) + i);
		thp->seq = htonl( ntohl(thp->seq) + i);
		}
		break;

	case SPECIAL_D:			/* Unidirectional data */
		thp->seq = htonl( ntohl(thp->seq) +
				  ntohs(ip->tot_len) - hdrlen);
		break;

	default:
		if(changes & NEW_U){
			thp->urg = 1;
			if((x = decode(&cp)) == -1) {
				goto bad;
			}
			thp->urg_ptr = htons(x);
		} else
			thp->urg = 0;
		if(changes & NEW_W){
			if((x = decode(&cp)) == -1) {
				goto bad;
			}
			thp->window = htons( ntohs(thp->window) + x);
		}
		if(changes & NEW_A){
			if((x = decode(&cp)) == -1) {
				goto bad;
			}
			thp->ack_seq = htonl( ntohl(thp->ack_seq) + x);
		}
		if(changes & NEW_S){
			if((x = decode(&cp)) == -1) {
				goto bad;
			}
			thp->seq = htonl( ntohl(thp->seq) + x);
		}
		break;
	}
	if(changes & NEW_I){
		if((x = decode(&cp)) == -1) {
			goto bad;
		}
		ip->id = htons (ntohs (ip->id) + x);
	} else
		ip->id = htons (ntohs (ip->id) + 1);

	/*
	 * At this point, cp points to the first byte of data in the
	 * packet.  Put the reconstructed TCP and IP headers back on the
	 * packet.  Recalculate IP checksum (but not TCP checksum).
	 */

	len = isize - (cp - icp);
	if (len < 0)
		goto bad;
	len += hdrlen;
	ip->tot_len = htons(len);
	ip->check = 0;

	memmove(icp + hdrlen, cp, len - hdrlen);

	cp = icp;
	memcpy(cp, ip, 20);
	cp += 20;

	if (ip->ihl > 5) {
	  memcpy(cp, cs->cs_ipopt, (ip->ihl - 5) * 4);
	  cp += (ip->ihl - 5) * 4;
	}

	put_unaligned(ip_fast_csum(icp, ip->ihl),
		      &((struct iphdr *)icp)->check);

	memcpy(cp, thp, 20);
	cp += 20;

	if (thp->doff > 5) {
	  memcpy(cp, cs->cs_tcpopt, ((thp->doff) - 5) * 4);
	  cp += ((thp->doff) - 5) * 4;
	}

	return len;
bad:
	comp->sls_i_error++;
	return slhc_toss( comp );
}

Project: linux
File: isdn_ppp.c

isdn_ppp_open(int min, struct file *file)
{
	int slot;
	struct ippp_struct *is;

	if (min < 0 || min >= ISDN_MAX_CHANNELS)
		return -ENODEV;

	slot = isdn_ppp_get_slot();
	if (slot < 0) {
		return -EBUSY;
	}
	is = file->private_data = ippp_table[slot];

	printk(KERN_DEBUG "ippp, open, slot: %d, minor: %d, state: %04x\n",
	       slot, min, is->state);

	/* compression stuff */
	is->link_compressor   = is->compressor = NULL;
	is->link_decompressor = is->decompressor = NULL;
	is->link_comp_stat    = is->comp_stat = NULL;
	is->link_decomp_stat  = is->decomp_stat = NULL;
	is->compflags = 0;

	is->reset = isdn_ppp_ccp_reset_alloc(is);
	if (!is->reset)
		return -ENOMEM;

	is->lp = NULL;
	is->mp_seqno = 0;       /* MP sequence number */
	is->pppcfg = 0;         /* ppp configuration */
	is->mpppcfg = 0;        /* mppp configuration */
	is->last_link_seqno = -1;	/* MP: maybe set to Bundle-MIN, when joining a bundle ?? */
	is->unit = -1;          /* set, when we have our interface */
	is->mru = 1524;         /* MRU, default 1524 */
	is->maxcid = 16;        /* VJ: maxcid */
	is->tk = current;
	init_waitqueue_head(&is->wq);
	is->first = is->rq + NUM_RCV_BUFFS - 1;	/* receive queue */
	is->last = is->rq;
	is->minor = min;
#ifdef CONFIG_ISDN_PPP_VJ
	/*
	 * VJ header compression init
	 */
	is->slcomp = slhc_init(16, 16);	/* not necessary for 2. link in bundle */
	if (IS_ERR(is->slcomp)) {
		isdn_ppp_ccp_reset_free(is);
		return PTR_ERR(is->slcomp);
	}
#endif
#ifdef CONFIG_IPPP_FILTER
	is->pass_filter = NULL;
	is->active_filter = NULL;
#endif
	is->state = IPPP_OPEN;

	return 0;
}

Project: linux
File: isdn_ppp.c

isdn_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 */

}

Project: linux
File: isdn_ppp.c

isdn_ppp_if_get_unit(char *name)
{
	int len,
		i,
		unit = 0,
		deci;

	len = strlen(name);

	if (strncmp("ippp", name, 4) || len > 8)
		return -1;

	for (i = 0, deci = 1; i < len; i++, deci *= 10) {
		char a = name[len - i - 1];
		if (a >= '0' && a <= '9')
			unit += (a - '0') * deci;
		else
			break;
	}
	if (!i || len - i != 4)
		unit = -1;

	return unit;
}

Project: linux
File: isdn_ppp.c

static void isdn_ppp_ccp_xmit_reset(struct ippp_struct *is, int proto,
				    unsigned char code, unsigned char id,
				    unsigned char *data, int len)
{
	struct sk_buff *skb;
	unsigned char *p;
	int hl;
	int cnt = 0;
	isdn_net_local *lp = is->lp;

	/* Alloc large enough skb */
	hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen;
	skb = alloc_skb(len + hl + 16, GFP_ATOMIC);
	if (!skb) {
		printk(KERN_WARNING
		       "ippp: CCP cannot send reset - out of memory\n");
		return;
	}
	skb_reserve(skb, hl);

	/* We may need to stuff an address and control field first */
	if (!(is->pppcfg & SC_COMP_AC)) {
		p = skb_put(skb, 2);
		*p++ = 0xff;
		*p++ = 0x03;
	}

	/* Stuff proto, code, id and length */
	p = skb_put(skb, 6);
	*p++ = (proto >> 8);
	*p++ = (proto & 0xff);
	*p++ = code;
	*p++ = id;
	cnt = 4 + len;
	*p++ = (cnt >> 8);
	*p++ = (cnt & 0xff);

	/* Now stuff remaining bytes */
	if (len) {
		p = skb_put(skb, len);
		memcpy(p, data, len);
	}

	/* skb is now ready for xmit */
	printk(KERN_DEBUG "Sending CCP Frame:\n");
	isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit, lp->ppp_slot);

	isdn_net_write_super(lp, skb);
}

Project: linux
File: isdn_ppp.c

isdn_ppp_closewait(int slot)
{
	struct ippp_struct *is;

	if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
		printk(KERN_ERR "%s: slot(%d) out of range\n",
		       __func__, slot);
		return 0;
	}
	is = ippp_table[slot];
	if (is->state)
		wake_up_interruptible(&is->wq);
	is->state = IPPP_CLOSEWAIT;
	return 1;
}

Project: linux
File: isdn_ppp.c

isdn_ppp_bundle(struct ippp_struct *is, int unit)
{
	char ifn[IFNAMSIZ + 1];
	isdn_net_dev *p;
	isdn_net_local *lp, *nlp;
	int rc;
	unsigned long flags;

	sprintf(ifn, "ippp%d", unit);
	p = isdn_net_findif(ifn);
	if (!p) {
		printk(KERN_ERR "ippp_bundle: cannot find %s\n", ifn);
		return -EINVAL;
	}

	spin_lock_irqsave(&p->pb->lock, flags);

	nlp = is->lp;
	lp = p->queue;
	if (nlp->ppp_slot < 0 || nlp->ppp_slot >= ISDN_MAX_CHANNELS ||
	    lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
		printk(KERN_ERR "ippp_bundle: binding to invalid slot %d\n",
		       nlp->ppp_slot < 0 || nlp->ppp_slot >= ISDN_MAX_CHANNELS ?
		       nlp->ppp_slot : lp->ppp_slot);
		rc = -EINVAL;
		goto out;
	}

	isdn_net_add_to_bundle(p, nlp);

	ippp_table[nlp->ppp_slot]->unit = ippp_table[lp->ppp_slot]->unit;

	/* maybe also SC_CCP stuff */
	ippp_table[nlp->ppp_slot]->pppcfg |= ippp_table[lp->ppp_slot]->pppcfg &
		(SC_ENABLE_IP | SC_NO_TCP_CCID | SC_REJ_COMP_TCP);
	ippp_table[nlp->ppp_slot]->mpppcfg |= ippp_table[lp->ppp_slot]->mpppcfg &
		(SC_MP_PROT | SC_REJ_MP_PROT | SC_OUT_SHORT_SEQ | SC_IN_SHORT_SEQ);
	rc = isdn_ppp_mp_init(nlp, p->pb);
out:
	spin_unlock_irqrestore(&p->pb->lock, flags);
	return rc;
}

Project: linux
File: isdn_ppp.c

static void isdn_ppp_ccp_reset_free_state(struct ippp_struct *is,
					  unsigned char id)
{
	struct ippp_ccp_reset_state *rs;

	if (is->reset->rs[id]) {
		printk(KERN_DEBUG "ippp_ccp: freeing state for id %d\n", id);
		rs = is->reset->rs[id];
		/* Make sure the kernel will not call back later */
		if (rs->ta)
			del_timer(&rs->timer);
		is->reset->rs[id] = NULL;
		kfree(rs);
	} else {
		printk(KERN_WARNING "ippp_ccp: id %d is not allocated\n", id);
	}
}

Project: linux
File: isdn_ppp.c

struct sk_buff *isdn_ppp_mp_discard(ippp_bundle *mp,
				    struct sk_buff *from, struct sk_buff *to)
{
	if (from)
		while (from != to) {
			struct sk_buff *next = from->next;
			isdn_ppp_mp_free_skb(mp, from);
			from = next;
		}
	return from;
}

Project: linux
File: slhc.c

slhc_toss(struct slcompress *comp)
{
  printk(KERN_DEBUG "Called IP function on non IP-system: slhc_toss");
  return -EINVAL;
}

Project: linux
File: isdn_ppp.c

static void isdn_ppp_mp_cleanup(isdn_net_local *lp)
{
	struct sk_buff *frag = lp->netdev->pb->frags;
	struct sk_buff *nextfrag;
	while (frag) {
		nextfrag = frag->next;
		isdn_ppp_mp_free_skb(lp->netdev->pb, frag);
		frag = nextfrag;
	}
	lp->netdev->pb->frags = NULL;
}

Project: linux
File: ppp_generic.c

static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf,
			struct file *file, unsigned int cmd, unsigned long arg)
{
	int unit, err = -EFAULT;
	struct ppp *ppp;
	struct channel *chan;
	struct ppp_net *pn;
	int __user *p = (int __user *)arg;

	mutex_lock(&ppp_mutex);
	switch (cmd) {
	case PPPIOCNEWUNIT:
		/* Create a new ppp unit */
		if (get_user(unit, p))
			break;
		ppp = ppp_create_interface(net, unit, file, &err);
		if (!ppp)
			break;
		file->private_data = &ppp->file;
		err = -EFAULT;
		if (put_user(ppp->file.index, p))
			break;
		err = 0;
		break;

	case PPPIOCATTACH:
		/* Attach to an existing ppp unit */
		if (get_user(unit, p))
			break;
		err = -ENXIO;
		pn = ppp_pernet(net);
		mutex_lock(&pn->all_ppp_mutex);
		ppp = ppp_find_unit(pn, unit);
		if (ppp) {
			atomic_inc(&ppp->file.refcnt);
			file->private_data = &ppp->file;
			err = 0;
		}
		mutex_unlock(&pn->all_ppp_mutex);
		break;

	case PPPIOCATTCHAN:
		if (get_user(unit, p))
			break;
		err = -ENXIO;
		pn = ppp_pernet(net);
		spin_lock_bh(&pn->all_channels_lock);
		chan = ppp_find_channel(pn, unit);
		if (chan) {
			atomic_inc(&chan->file.refcnt);
			file->private_data = &chan->file;
			err = 0;
		}
		spin_unlock_bh(&pn->all_channels_lock);
		break;

	default:
		err = -ENOTTY;
	}
	mutex_unlock(&ppp_mutex);
	return err;
}

Project: linux
File: isdn_ppp.c

int isdn_ppp_autodial_filter(struct sk_buff *skb, isdn_net_local *lp)
{
	struct ippp_struct *is = ippp_table[lp->ppp_slot];
	u_int16_t proto;
	int drop = 0;

	switch (ntohs(skb->protocol)) {
	case ETH_P_IP:
		proto = PPP_IP;
		break;
	case ETH_P_IPX:
		proto = PPP_IPX;
		break;
	default:
		printk(KERN_ERR "isdn_ppp_autodial_filter: unsupported protocol 0x%x.\n",
		       skb->protocol);
		return 1;
	}

	/* the filter instructions are constructed assuming
	 * a four-byte PPP header on each packet. we have to
	 * temporarily remove part of the fake header stuck on
	 * earlier.
	 */
	*skb_pull(skb, IPPP_MAX_HEADER - 4) = 1; /* indicate outbound */

	{
		__be16 *p = (__be16 *)skb->data;

		p++;
		*p = htons(proto);
	}

	drop |= is->pass_filter
		&& BPF_PROG_RUN(is->pass_filter, skb) == 0;
	drop |= is->active_filter
		&& BPF_PROG_RUN(is->active_filter, skb) == 0;

	skb_push(skb, IPPP_MAX_HEADER - 4);
	return drop;
}

Project: linux
File: isdn_ppp.c

int isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *ipc)
{
	if (ipc->prev)
		ipc->prev->next = ipc->next;
	else
		ipc_head = ipc->next;
	if (ipc->next)
		ipc->next->prev = ipc->prev;
	ipc->prev = ipc->next = NULL;
	return 0;
}

Project: linux
File: slip.c

static void sl_free_bufs(struct slip *sl)
{
	/* Free all SLIP frame buffers. */
	kfree(xchg(&sl->rbuff, NULL));
	kfree(xchg(&sl->xbuff, NULL));
#ifdef SL_INCLUDE_CSLIP
	kfree(xchg(&sl->cbuff, NULL));
	slhc_free(xchg(&sl->slcomp, NULL));
#endif
}

Project: linux
File: isdn_ppp.c

isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
{
	unsigned long val;
	int r, i, j;
	struct ippp_struct *is;
	isdn_net_local *lp;
	struct isdn_ppp_comp_data data;
	void __user *argp = (void __user *)arg;

	is = file->private_data;
	lp = is->lp;

	if (is->debug & 0x1)
		printk(KERN_DEBUG "isdn_ppp_ioctl: minor: %d cmd: %x state: %x\n", min, cmd, is->state);

	if (!(is->state & IPPP_OPEN))
		return -EINVAL;

	switch (cmd) {
	case PPPIOCBUNDLE:
#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->netdev->dev->name,
				 strlen(lp->netdev->dev->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 (IS_ERR(sltmp))
				return PTR_ERR(sltmp);
			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] |= (1UL << 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_fprog_kern fprog;
		struct sock_filter *code;
		int err, len = get_filter(argp, &code);

		if (len < 0)
			return len;

		fprog.len = len;
		fprog.filter = code;

		if (is->pass_filter) {
			bpf_prog_destroy(is->pass_filter);
			is->pass_filter = NULL;
		}
		if (fprog.filter != NULL)
			err = bpf_prog_create(&is->pass_filter, &fprog);
		else
			err = 0;
		kfree(code);

		return err;
	}
	case PPPIOCSACTIVE:
	{
		struct sock_fprog_kern fprog;
		struct sock_filter *code;
		int err, len = get_filter(argp, &code);

		if (len < 0)
			return len;

		fprog.len = len;
		fprog.filter = code;

		if (is->active_filter) {
			bpf_prog_destroy(is->active_filter);
			is->active_filter = NULL;
		}
		if (fprog.filter != NULL)
			err = bpf_prog_create(&is->active_filter, &fprog);
		else
			err = 0;
		kfree(code);

		return err;
	}
#endif /* CONFIG_IPPP_FILTER */
	default:
		break;
	}
	return 0;
}

Project: linux
File: slhc.c

pull16(unsigned char **cpp)
{
	short rval;

	rval = *(*cpp)++;
	rval <<= 8;
	rval |= *(*cpp)++;
	return rval;
}

Project: linux
File: ppp_generic.c

static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
	struct ppp_file *pf = file->private_data;
	struct ppp *ppp;
	int err = -EFAULT, val, val2, i;
	struct ppp_idle idle;
	struct npioctl npi;
	int unit, cflags;
	struct slcompress *vj;
	void __user *argp = (void __user *)arg;
	int __user *p = argp;

	if (!pf)
		return ppp_unattached_ioctl(current->nsproxy->net_ns,
					pf, file, cmd, arg);

	if (cmd == PPPIOCDETACH) {
		/*
		 * We have to be careful here... if the file descriptor
		 * has been dup'd, we could have another process in the
		 * middle of a poll using the same file *, so we had
		 * better not free the interface data structures -
		 * instead we fail the ioctl.  Even in this case, we
		 * shut down the interface if we are the owner of it.
		 * Actually, we should get rid of PPPIOCDETACH, userland
		 * (i.e. pppd) could achieve the same effect by closing
		 * this fd and reopening /dev/ppp.
		 */
		err = -EINVAL;
		mutex_lock(&ppp_mutex);
		if (pf->kind == INTERFACE) {
			ppp = PF_TO_PPP(pf);
			rtnl_lock();
			if (file == ppp->owner)
				unregister_netdevice(ppp->dev);
			rtnl_unlock();
		}
		if (atomic_long_read(&file->f_count) < 2) {
			ppp_release(NULL, file);
			err = 0;
		} else
			pr_warn("PPPIOCDETACH file->f_count=%ld\n",
				atomic_long_read(&file->f_count));
		mutex_unlock(&ppp_mutex);
		return err;
	}

	if (pf->kind == CHANNEL) {
		struct channel *pch;
		struct ppp_channel *chan;

		mutex_lock(&ppp_mutex);
		pch = PF_TO_CHANNEL(pf);

		switch (cmd) {
		case PPPIOCCONNECT:
			if (get_user(unit, p))
				break;
			err = ppp_connect_channel(pch, unit);
			break;

		case PPPIOCDISCONN:
			err = ppp_disconnect_channel(pch);
			break;

		default:
			down_read(&pch->chan_sem);
			chan = pch->chan;
			err = -ENOTTY;
			if (chan && chan->ops->ioctl)
				err = chan->ops->ioctl(chan, cmd, arg);
			up_read(&pch->chan_sem);
		}
		mutex_unlock(&ppp_mutex);
		return err;
	}

	if (pf->kind != INTERFACE) {
		/* can't happen */
		pr_err("PPP: not interface or channel??\n");
		return -EINVAL;
	}

	mutex_lock(&ppp_mutex);
	ppp = PF_TO_PPP(pf);
	switch (cmd) {
	case PPPIOCSMRU:
		if (get_user(val, p))
			break;
		ppp->mru = val;
		err = 0;
		break;

	case PPPIOCSFLAGS:
		if (get_user(val, p))
			break;
		ppp_lock(ppp);
		cflags = ppp->flags & ~val;
#ifdef CONFIG_PPP_MULTILINK
		if (!(ppp->flags & SC_MULTILINK) && (val & SC_MULTILINK))
			ppp->nextseq = 0;
#endif
		ppp->flags = val & SC_FLAG_BITS;
		ppp_unlock(ppp);
		if (cflags & SC_CCP_OPEN)
			ppp_ccp_closed(ppp);
		err = 0;
		break;

	case PPPIOCGFLAGS:
		val = ppp->flags | ppp->xstate | ppp->rstate;
		if (put_user(val, p))
			break;
		err = 0;
		break;

	case PPPIOCSCOMPRESS:
		err = ppp_set_compress(ppp, arg);
		break;

	case PPPIOCGUNIT:
		if (put_user(ppp->file.index, p))
			break;
		err = 0;
		break;

	case PPPIOCSDEBUG:
		if (get_user(val, p))
			break;
		ppp->debug = val;
		err = 0;
		break;

	case PPPIOCGDEBUG:
		if (put_user(ppp->debug, p))
			break;
		err = 0;
		break;

	case PPPIOCGIDLE:
		idle.xmit_idle = (jiffies - ppp->last_xmit) / HZ;
		idle.recv_idle = (jiffies - ppp->last_recv) / HZ;
		if (copy_to_user(argp, &idle, sizeof(idle)))
			break;
		err = 0;
		break;

	case PPPIOCSMAXCID:
		if (get_user(val, p))
			break;
		val2 = 15;
		if ((val >> 16) != 0) {
			val2 = val >> 16;
			val &= 0xffff;
		}
		vj = slhc_init(val2+1, val+1);
		if (IS_ERR(vj)) {
			err = PTR_ERR(vj);
			break;
		}
		ppp_lock(ppp);
		if (ppp->vj)
			slhc_free(ppp->vj);
		ppp->vj = vj;
		ppp_unlock(ppp);
		err = 0;
		break;

	case PPPIOCGNPMODE:
	case PPPIOCSNPMODE:
		if (copy_from_user(&npi, argp, sizeof(npi)))
			break;
		err = proto_to_npindex(npi.protocol);
		if (err < 0)
			break;
		i = err;
		if (cmd == PPPIOCGNPMODE) {
			err = -EFAULT;
			npi.mode = ppp->npmode[i];
			if (copy_to_user(argp, &npi, sizeof(npi)))
				break;
		} else {
			ppp->npmode[i] = npi.mode;
			/* we may be able to transmit more packets now (??) */
			netif_wake_queue(ppp->dev);
		}
		err = 0;
		break;

#ifdef CONFIG_PPP_FILTER
	case PPPIOCSPASS:
	{
		struct sock_filter *code;

		err = get_filter(argp, &code);
		if (err >= 0) {
			struct bpf_prog *pass_filter = NULL;
			struct sock_fprog_kern fprog = {
				.len = err,
				.filter = code,
			};

			err = 0;
			if (fprog.filter)
				err = bpf_prog_create(&pass_filter, &fprog);
			if (!err) {
				ppp_lock(ppp);
				if (ppp->pass_filter)
					bpf_prog_destroy(ppp->pass_filter);
				ppp->pass_filter = pass_filter;
				ppp_unlock(ppp);
			}
			kfree(code);
		}
		break;
	}
	case PPPIOCSACTIVE:
	{
		struct sock_filter *code;

		err = get_filter(argp, &code);
		if (err >= 0) {
			struct bpf_prog *active_filter = NULL;
			struct sock_fprog_kern fprog = {
				.len = err,
				.filter = code,
			};

			err = 0;
			if (fprog.filter)
				err = bpf_prog_create(&active_filter, &fprog);
			if (!err) {
				ppp_lock(ppp);
				if (ppp->active_filter)
					bpf_prog_destroy(ppp->active_filter);
				ppp->active_filter = active_filter;
				ppp_unlock(ppp);
			}
			kfree(code);
		}
		break;
	}
#endif /* CONFIG_PPP_FILTER */

#ifdef CONFIG_PPP_MULTILINK
	case PPPIOCSMRRU:
		if (get_user(val, p))
			break;
		ppp_recv_lock(ppp);
		ppp->mrru = val;
		ppp_recv_unlock(ppp);
		err = 0;
		break;
#endif /* CONFIG_PPP_MULTILINK */

	default:
		err = -ENOTTY;
	}
	mutex_unlock(&ppp_mutex);
	return err;
}

Project: linux
File: slhc.c

encode(unsigned char *cp, unsigned short n)
{
	if(n >= 256 || n == 0){
		*cp++ = 0;
		cp = put16(cp,n);
	} else {
		*cp++ = n;
	}
	return cp;
}

Project: linux
File: isdn_ppp.c

isdn_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",
		       iminor(file_inode(file)));

	/* 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;
}

Project: linux
File: isdn_ppp.c

isdn_ppp_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
	int error = 0;
	int len;
	isdn_net_local *lp = netdev_priv(dev);


	if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP)
		return -EINVAL;

	switch (cmd) {
#define PPP_VERSION "2.3.7"
	case SIOCGPPPVER:
		len = strlen(PPP_VERSION) + 1;
		if (copy_to_user(ifr->ifr_data, PPP_VERSION, len))
			error = -EFAULT;
		break;

	case SIOCGPPPSTATS:
		error = isdn_ppp_dev_ioctl_stats(lp->ppp_slot, ifr, dev);
		break;
	default:
		error = -EINVAL;
		break;
	}
	return error;
}

Project: linux
File: isdn_ppp.c

static int isdn_ppp_mp_bundle_array_init(void)
{
	int i;
	int sz = ISDN_MAX_CHANNELS * sizeof(ippp_bundle);
	if ((isdn_ppp_bundle_arr = kzalloc(sz, GFP_KERNEL)) == NULL)
		return -ENOMEM;
	for (i = 0; i < ISDN_MAX_CHANNELS; i++)
		spin_lock_init(&isdn_ppp_bundle_arr[i].lock);
	return 0;
}

Project: linux
File: isdn_ppp.c

isdn_ppp_push_higher(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *skb, int proto)
{
	struct net_device *dev = net_dev->dev;
	struct ippp_struct *is, *mis;
	isdn_net_local *mlp = NULL;
	int slot;

	slot = lp->ppp_slot;
	if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
		printk(KERN_ERR "isdn_ppp_push_higher: lp->ppp_slot(%d)\n",
		       lp->ppp_slot);
		goto drop_packet;
	}
	is = ippp_table[slot];

	if (lp->master) { // FIXME?
		mlp = ISDN_MASTER_PRIV(lp);
		slot = mlp->ppp_slot;
		if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
			printk(KERN_ERR "isdn_ppp_push_higher: master->ppp_slot(%d)\n",
			       lp->ppp_slot);
			goto drop_packet;
		}
	}
	mis = ippp_table[slot];

	if (is->debug & 0x10) {
		printk(KERN_DEBUG "push, skb %d %04x\n", (int) skb->len, proto);
		isdn_ppp_frame_log("rpush", skb->data, skb->len, 32, is->unit, lp->ppp_slot);
	}
	if (mis->compflags & SC_DECOMP_ON) {
		skb = isdn_ppp_decompress(skb, is, mis, &proto);
		if (!skb) // decompression error
			return;
	}
	switch (proto) {
	case PPP_IPX:  /* untested */
		if (is->debug & 0x20)
			printk(KERN_DEBUG "isdn_ppp: IPX\n");
		skb->protocol = htons(ETH_P_IPX);
		break;
	case PPP_IP:
		if (is->debug & 0x20)
			printk(KERN_DEBUG "isdn_ppp: IP\n");
		skb->protocol = htons(ETH_P_IP);
		break;
	case PPP_COMP:
	case PPP_COMPFRAG:
		printk(KERN_INFO "isdn_ppp: unexpected compressed frame dropped\n");
		goto drop_packet;
#ifdef CONFIG_ISDN_PPP_VJ
	case PPP_VJC_UNCOMP:
		if (is->debug & 0x20)
			printk(KERN_DEBUG "isdn_ppp: VJC_UNCOMP\n");
		if (net_dev->local->ppp_slot < 0) {
			printk(KERN_ERR "%s: net_dev->local->ppp_slot(%d) out of range\n",
			       __func__, net_dev->local->ppp_slot);
			goto drop_packet;
		}
		if (slhc_remember(ippp_table[net_dev->local->ppp_slot]->slcomp, skb->data, skb->len) <= 0) {
			printk(KERN_WARNING "isdn_ppp: received illegal VJC_UNCOMP frame!\n");
			goto drop_packet;
		}
		skb->protocol = htons(ETH_P_IP);
		break;
	case PPP_VJC_COMP:
		if (is->debug & 0x20)
			printk(KERN_DEBUG "isdn_ppp: VJC_COMP\n");
		{
			struct sk_buff *skb_old = skb;
			int pkt_len;
			skb = dev_alloc_skb(skb_old->len + 128);

			if (!skb) {
				printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
				skb = skb_old;
				goto drop_packet;
			}
			skb_put(skb, skb_old->len + 128);
			skb_copy_from_linear_data(skb_old, skb->data,
						  skb_old->len);
			if (net_dev->local->ppp_slot < 0) {
				printk(KERN_ERR "%s: net_dev->local->ppp_slot(%d) out of range\n",
				       __func__, net_dev->local->ppp_slot);
				goto drop_packet;
			}
			pkt_len = slhc_uncompress(ippp_table[net_dev->local->ppp_slot]->slcomp,
						  skb->data, skb_old->len);
			kfree_skb(skb_old);
			if (pkt_len < 0)
				goto drop_packet;

			skb_trim(skb, pkt_len);
			skb->protocol = htons(ETH_P_IP);
		}
		break;
#endif
	case PPP_CCP:
	case PPP_CCPFRAG:
		isdn_ppp_receive_ccp(net_dev, lp, skb, proto);
		/* Dont pop up ResetReq/Ack stuff to the daemon any
		   longer - the job is done already */
		if (skb->data[0] == CCP_RESETREQ ||
		    skb->data[0] == CCP_RESETACK)
			break;
		/* fall through */
	default:
		isdn_ppp_fill_rq(skb->data, skb->len, proto, lp->ppp_slot);	/* push data to pppd device */
		kfree_skb(skb);
		return;
	}

#ifdef CONFIG_IPPP_FILTER
	/* check if the packet passes the pass and active filters
	 * the filter instructions are constructed assuming
	 * a four-byte PPP header on each packet (which is still present) */
	skb_push(skb, 4);

	{
		u_int16_t *p = (u_int16_t *) skb->data;

		*p = 0;	/* indicate inbound */
	}

	if (is->pass_filter
	    && BPF_PROG_RUN(is->pass_filter, skb) == 0) {
		if (is->debug & 0x2)
			printk(KERN_DEBUG "IPPP: inbound frame filtered.\n");
		kfree_skb(skb);
		return;
	}
	if (!(is->active_filter
	      && BPF_PROG_RUN(is->active_filter, skb) == 0)) {
		if (is->debug & 0x2)
			printk(KERN_DEBUG "IPPP: link-active filter: resetting huptimer.\n");
		lp->huptimer = 0;
		if (mlp)
			mlp->huptimer = 0;
	}
	skb_pull(skb, 4);
#else /* CONFIG_IPPP_FILTER */
	lp->huptimer = 0;
	if (mlp)
		mlp->huptimer = 0;
#endif /* CONFIG_IPPP_FILTER */
	skb->dev = dev;
	skb_reset_mac_header(skb);
	netif_rx(skb);
	/* net_dev->local->stats.rx_packets++; done in isdn_net.c */
	return;

drop_packet:
	net_dev->local->stats.rx_dropped++;
	kfree_skb(skb);
}

Project: linux
File: isdn_ppp.c

isdn_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] = kzalloc(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;
		}
		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;
}

Project: linux
File: isdn_ppp.c

isdn_ppp_bind(isdn_net_local *lp)
{
	int i;
	int unit = 0;
	struct ippp_struct *is;
	int retval;

	if (lp->pppbind < 0) {  /* device bounded to ippp device ? */
		isdn_net_dev *net_dev = dev->netdev;
		char exclusive[ISDN_MAX_CHANNELS];	/* exclusive flags */
		memset(exclusive, 0, ISDN_MAX_CHANNELS);
		while (net_dev) {	/* step through net devices to find exclusive minors */
			isdn_net_local *lp = net_dev->local;
			if (lp->pppbind >= 0)
				exclusive[lp->pppbind] = 1;
			net_dev = net_dev->next;
		}
		/*
		 * search a free device / slot
		 */
		for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
			if (ippp_table[i]->state == IPPP_OPEN && !exclusive[ippp_table[i]->minor]) {	/* OPEN, but not connected! */
				break;
			}
		}
	} else {
		for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
			if (ippp_table[i]->minor == lp->pppbind &&
			    (ippp_table[i]->state & IPPP_OPEN) == IPPP_OPEN)
				break;
		}
	}

	if (i >= ISDN_MAX_CHANNELS) {
		printk(KERN_WARNING "isdn_ppp_bind: Can't find a (free) connection to the ipppd daemon.\n");
		retval = -1;
		goto out;
	}
	/* get unit number from interface name .. ugly! */
	unit = isdn_ppp_if_get_unit(lp->netdev->dev->name);
	if (unit < 0) {
		printk(KERN_ERR "isdn_ppp_bind: illegal interface name %s.\n",
		       lp->netdev->dev->name);
		retval = -1;
		goto out;
	}

	lp->ppp_slot = i;
	is = ippp_table[i];
	is->lp = lp;
	is->unit = unit;
	is->state = IPPP_OPEN | IPPP_ASSIGNED;	/* assigned to a netdevice but not connected */
#ifdef CONFIG_ISDN_MPP
	retval = isdn_ppp_mp_init(lp, NULL);
	if (retval < 0)
		goto out;
#endif /* CONFIG_ISDN_MPP */

	retval = lp->ppp_slot;

out:
	return retval;
}

Project: linux
File: isdn_ppp.c

isdn_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);
	if (copy_to_user(buf, save_buf, count))
		count = -EFAULT;
	kfree(save_buf);

	return count;
}

Project: linux
File: isdn_ppp.c

static int isdn_ppp_set_compressor(struct ippp_struct *is, struct isdn_ppp_comp_data *data)
{
	struct isdn_ppp_compressor *ipc = ipc_head;
	int ret;
	void *stat;
	int num = data->num;

	if (is->debug & 0x10)
		printk(KERN_DEBUG "[%d] Set %s type %d\n", is->unit,
		       (data->flags & IPPP_COMP_FLAG_XMIT) ? "compressor" : "decompressor", num);

	/* If is has no valid reset state vector, we cannot allocate a
	   decompressor. The decompressor would cause reset transactions
	   sooner or later, and they need that vector. */

	if (!(data->flags & IPPP_COMP_FLAG_XMIT) && !is->reset) {
		printk(KERN_ERR "ippp_ccp: no reset data structure - can't"
		       " allow decompression.\n");
		return -ENOMEM;
	}

	while (ipc) {
		if (ipc->num == num) {
			stat = ipc->alloc(data);
			if (stat) {
				ret = ipc->init(stat, data, is->unit, 0);
				if (!ret) {
					printk(KERN_ERR "Can't init (de)compression!\n");
					ipc->free(stat);
					stat = NULL;
					break;
				}
			}
			else {
				printk(KERN_ERR "Can't alloc (de)compression!\n");
				break;
			}

			if (data->flags & IPPP_COMP_FLAG_XMIT) {
				if (data->flags & IPPP_COMP_FLAG_LINK) {
					if (is->link_comp_stat)
						is->link_compressor->free(is->link_comp_stat);
					is->link_comp_stat = stat;
					is->link_compressor = ipc;
				}
				else {
					if (is->comp_stat)
						is->compressor->free(is->comp_stat);
					is->comp_stat = stat;
					is->compressor = ipc;
				}
			}
			else {
				if (data->flags & IPPP_COMP_FLAG_LINK) {
					if (is->link_decomp_stat)
						is->link_decompressor->free(is->link_decomp_stat);
					is->link_decomp_stat = stat;
					is->link_decompressor = ipc;
				}
				else {
					if (is->decomp_stat)
						is->decompressor->free(is->decomp_stat);
					is->decomp_stat = stat;
					is->decompressor = ipc;
				}
			}
			return 0;
		}
		ipc = ipc->next;
	}
	return -EINVAL;
}

Project: linux
File: slhc.c

slhc_free(struct slcompress *comp)
{
  printk(KERN_DEBUG "Called IP function on non IP-system: slhc_free");
}

Project: linux
File: isdn_ppp.c

isdn_ppp_get_slot(void)
{
	int i;
	for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
		if (!ippp_table[i]->state)
			return i;
	}
	return -1;
}

Project: linux
File: isdn_ppp.c

static void isdn_ppp_mp_receive(isdn_net_dev *net_dev, isdn_net_local *lp,
				struct sk_buff *skb)
{
	struct ippp_struct *is;
	isdn_net_local *lpq;
	ippp_bundle *mp;
	isdn_mppp_stats *stats;
	struct sk_buff *newfrag, *frag, *start, *nextf;
	u32 newseq, minseq, thisseq;
	unsigned long flags;
	int slot;

	spin_lock_irqsave(&net_dev->pb->lock, flags);
	mp = net_dev->pb;
	stats = &mp->stats;
	slot = lp->ppp_slot;
	if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
		printk(KERN_ERR "%s: lp->ppp_slot(%d)\n",
		       __func__, lp->ppp_slot);
		stats->frame_drops++;
		dev_kfree_skb(skb);
		spin_unlock_irqrestore(&mp->lock, flags);
		return;
	}
	is = ippp_table[slot];
	if (++mp->frames > stats->max_queue_len)
		stats->max_queue_len = mp->frames;

	if (is->debug & 0x8)
		isdn_ppp_mp_print_recv_pkt(lp->ppp_slot, skb);

	newseq = isdn_ppp_mp_get_seq(is->mpppcfg & SC_IN_SHORT_SEQ,
				     skb, is->last_link_seqno);


	/* if this packet seq # is less than last already processed one,
	 * toss it right away, but check for sequence start case first
	 */
	if (mp->seq > MP_LONGSEQ_MAX && (newseq & MP_LONGSEQ_MAXBIT)) {
		mp->seq = newseq;	/* the first packet: required for
					 * rfc1990 non-compliant clients --
					 * prevents constant packet toss */
	} else if (MP_LT(newseq, mp->seq)) {
		stats->frame_drops++;
		isdn_ppp_mp_free_skb(mp, skb);
		spin_unlock_irqrestore(&mp->lock, flags);
		return;
	}

	/* find the minimum received sequence number over all links */
	is->last_link_seqno = minseq = newseq;
	for (lpq = net_dev->queue;;) {
		slot = lpq->ppp_slot;
		if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
			printk(KERN_ERR "%s: lpq->ppp_slot(%d)\n",
			       __func__, lpq->ppp_slot);
		} else {
			u32 lls = ippp_table[slot]->last_link_seqno;
			if (MP_LT(lls, minseq))
				minseq = lls;
		}
		if ((lpq = lpq->next) == net_dev->queue)
			break;
	}
	if (MP_LT(minseq, mp->seq))
		minseq = mp->seq;	/* can't go beyond already processed
					 * packets */
	newfrag = skb;

	/* if this new fragment is before the first one, then enqueue it now. */
	if ((frag = mp->frags) == NULL || MP_LT(newseq, MP_SEQ(frag))) {
		newfrag->next = frag;
		mp->frags = frag = newfrag;
		newfrag = NULL;
	}

	start = MP_FLAGS(frag) & MP_BEGIN_FRAG &&
		MP_SEQ(frag) == mp->seq ? frag : NULL;

	/*
	 * main fragment traversing loop
	 *
	 * try to accomplish several tasks:
	 * - insert new fragment into the proper sequence slot (once that's done
	 *   newfrag will be set to NULL)
	 * - reassemble any complete fragment sequence (non-null 'start'
	 *   indicates there is a contiguous sequence present)
	 * - discard any incomplete sequences that are below minseq -- due
	 *   to the fact that sender always increment sequence number, if there
	 *   is an incomplete sequence below minseq, no new fragments would
	 *   come to complete such sequence and it should be discarded
	 *
	 * loop completes when we accomplished the following tasks:
	 * - new fragment is inserted in the proper sequence ('newfrag' is
	 *   set to NULL)
	 * - we hit a gap in the sequence, so no reassembly/processing is
	 *   possible ('start' would be set to NULL)
	 *
	 * algorithm for this code is derived from code in the book
	 * 'PPP Design And Debugging' by James Carlson (Addison-Wesley)
	 */
	while (start != NULL || newfrag != NULL) {

		thisseq = MP_SEQ(frag);
		nextf = frag->next;

		/* drop any duplicate fragments */
		if (newfrag != NULL && thisseq == newseq) {
			isdn_ppp_mp_free_skb(mp, newfrag);
			newfrag = NULL;
		}

		/* insert new fragment before next element if possible. */
		if (newfrag != NULL && (nextf == NULL ||
					MP_LT(newseq, MP_SEQ(nextf)))) {
			newfrag->next = nextf;
			frag->next = nextf = newfrag;
			newfrag = NULL;
		}

		if (start != NULL) {
			/* check for misplaced start */
			if (start != frag && (MP_FLAGS(frag) & MP_BEGIN_FRAG)) {
				printk(KERN_WARNING"isdn_mppp(seq %d): new "
				       "BEGIN flag with no prior END", thisseq);
				stats->seqerrs++;
				stats->frame_drops++;
				start = isdn_ppp_mp_discard(mp, start, frag);
				nextf = frag->next;
			}
		} else if (MP_LE(thisseq, minseq)) {
			if (MP_FLAGS(frag) & MP_BEGIN_FRAG)
				start = frag;
			else {
				if (MP_FLAGS(frag) & MP_END_FRAG)
					stats->frame_drops++;
				if (mp->frags == frag)
					mp->frags = nextf;
				isdn_ppp_mp_free_skb(mp, frag);
				frag = nextf;
				continue;
			}
		}

		/* if start is non-null and we have end fragment, then
		 * we have full reassembly sequence -- reassemble
		 * and process packet now
		 */
		if (start != NULL && (MP_FLAGS(frag) & MP_END_FRAG)) {
			minseq = mp->seq = (thisseq + 1) & MP_LONGSEQ_MASK;
			/* Reassemble the packet then dispatch it */
			isdn_ppp_mp_reassembly(net_dev, lp, start, nextf);

			start = NULL;
			frag = NULL;

			mp->frags = nextf;
		}

		/* check if need to update start pointer: if we just
		 * reassembled the packet and sequence is contiguous
		 * then next fragment should be the start of new reassembly
		 * if sequence is contiguous, but we haven't reassembled yet,
		 * keep going.
		 * if sequence is not contiguous, either clear everything
		 * below low watermark and set start to the next frag or
		 * clear start ptr.
		 */
		if (nextf != NULL &&
		    ((thisseq + 1) & MP_LONGSEQ_MASK) == MP_SEQ(nextf)) {
			/* if we just reassembled and the next one is here,
			 * then start another reassembly. */

			if (frag == NULL) {
				if (MP_FLAGS(nextf) & MP_BEGIN_FRAG)
					start = nextf;
				else
				{
					printk(KERN_WARNING"isdn_mppp(seq %d):"
					       " END flag with no following "
					       "BEGIN", thisseq);
					stats->seqerrs++;
				}
			}

		} else {
			if (nextf != NULL && frag != NULL &&
			    MP_LT(thisseq, minseq)) {
				/* we've got a break in the sequence
				 * and we not at the end yet
				 * and we did not just reassembled
				 *(if we did, there wouldn't be anything before)
				 * and we below the low watermark
				 * discard all the frames below low watermark
				 * and start over */
				stats->frame_drops++;
				mp->frags = isdn_ppp_mp_discard(mp, start, nextf);
			}
			/* break in the sequence, no reassembly */
			start = NULL;
		}

		frag = nextf;
	}	/* while -- main loop */

	if (mp->frags == NULL)
		mp->frags = frag;

	/* rather straighforward way to deal with (not very) possible
	 * queue overflow */
	if (mp->frames > MP_MAX_QUEUE_LEN) {
		stats->overflows++;
		while (mp->frames > MP_MAX_QUEUE_LEN) {
			frag = mp->frags->next;
			isdn_ppp_mp_free_skb(mp, mp->frags);
			mp->frags = frag;
		}
	}
	spin_unlock_irqrestore(&mp->lock, flags);
}

Project: linux
File: isdn_ppp.c

isdn_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 = 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;
}

Project: linux
File: isdn_ppp.c

isdn_ppp_release(int min, struct file *file)
{
	int i;
	struct ippp_struct *is;

	if (min < 0 || min >= ISDN_MAX_CHANNELS)
		return;
	is = file->private_data;

	if (!is) {
		printk(KERN_ERR "%s: no file->private_data\n", __func__);
		return;
	}
	if (is->debug & 0x1)
		printk(KERN_DEBUG "ippp: release, minor: %d %lx\n", min, (long) is->lp);

	if (is->lp) {           /* a lp address says: this link is still up */
		isdn_net_dev *p = is->lp->netdev;

		if (!p) {
			printk(KERN_ERR "%s: no lp->netdev\n", __func__);
			return;
		}
		is->state &= ~IPPP_CONNECT;	/* -> effect: no call of wakeup */
		/*
		 * isdn_net_hangup() calls isdn_ppp_free()
		 * isdn_ppp_free() sets is->lp to NULL and lp->ppp_slot to -1
		 * removing the IPPP_CONNECT flag omits calling of isdn_ppp_wakeup_daemon()
		 */
		isdn_net_hangup(p->dev);
	}
	for (i = 0; i < NUM_RCV_BUFFS; i++) {
		kfree(is->rq[i].buf);
		is->rq[i].buf = NULL;
	}
	is->first = is->rq + NUM_RCV_BUFFS - 1;	/* receive queue */
	is->last = is->rq;

#ifdef CONFIG_ISDN_PPP_VJ
/* TODO: if this was the previous master: link the slcomp to the new master */
	slhc_free(is->slcomp);
	is->slcomp = NULL;
#endif
#ifdef CONFIG_IPPP_FILTER
	if (is->pass_filter) {
		bpf_prog_destroy(is->pass_filter);
		is->pass_filter = NULL;
	}

	if (is->active_filter) {
		bpf_prog_destroy(is->active_filter);
		is->active_filter = NULL;
	}
#endif

/* TODO: if this was the previous master: link the stuff to the new master */
	if (is->comp_stat)
		is->compressor->free(is->comp_stat);
	if (is->link_comp_stat)
		is->link_compressor->free(is->link_comp_stat);
	if (is->link_decomp_stat)
		is->link_decompressor->free(is->link_decomp_stat);
	if (is->decomp_stat)
		is->decompressor->free(is->decomp_stat);
	is->compressor   = is->link_compressor   = NULL;
	is->decompressor = is->link_decompressor = NULL;
	is->comp_stat    = is->link_comp_stat    = NULL;
	is->decomp_stat  = is->link_decomp_stat  = NULL;

	/* Clean up if necessary */
	if (is->reset)
		isdn_ppp_ccp_reset_free(is);

	/* this slot is ready for new connections */
	is->state = 0;
}

Project: linux
File: isdn_ppp.c

isdn_ppp_frame_log(char *info, char *data, int len, int maxlen, int unit, int slot)
{
	int cnt,
		j,
		i;
	char buf[80];

	if (len < maxlen)
		maxlen = len;

	for (i = 0, cnt = 0; cnt < maxlen; i++) {
		for (j = 0; j < 16 && cnt < maxlen; j++, cnt++)
			sprintf(buf + j * 3, "%02x ", (unsigned char)data[cnt]);
		printk(KERN_DEBUG "[%d/%d].%s[%d]: %s\n", unit, slot, info, i, buf);
	}
}

Project: linux
File: isdn_ppp.c

static int get_filter(void __user *arg, struct sock_filter **p)
{
	struct sock_fprog uprog;
	struct sock_filter *code = NULL;
	int len;

	if (copy_from_user(&uprog, arg, sizeof(uprog)))
		return -EFAULT;

	if (!uprog.len) {
		*p = NULL;
		return 0;
	}

	/* uprog.len is unsigned short, so no overflow here */
	len = uprog.len * sizeof(struct sock_filter);
	code = memdup_user(uprog.filter, len);
	if (IS_ERR(code))
		return PTR_ERR(code);

	*p = code;
	return uprog.len;
}

Project: linux
File: ppp_generic.c

ppp_set_compress(struct ppp *ppp, unsigned long arg)
{
	int err;
	struct compressor *cp, *ocomp;
	struct ppp_option_data data;
	void *state, *ostate;
	unsigned char ccp_option[CCP_MAX_OPTION_LENGTH];

	err = -EFAULT;
	if (copy_from_user(&data, (void __user *) arg, sizeof(data)) ||
	    (data.length <= CCP_MAX_OPTION_LENGTH &&
	     copy_from_user(ccp_option, (void __user *) data.ptr, data.length)))
		goto out;
	err = -EINVAL;
	if (data.length > CCP_MAX_OPTION_LENGTH ||
	    ccp_option[1] < 2 || ccp_option[1] > data.length)
		goto out;

	cp = try_then_request_module(
		find_compressor(ccp_option[0]),
		"ppp-compress-%d", ccp_option[0]);
	if (!cp)
		goto out;

	err = -ENOBUFS;
	if (data.transmit) {
		state = cp->comp_alloc(ccp_option, data.length);
		if (state) {
			ppp_xmit_lock(ppp);
			ppp->xstate &= ~SC_COMP_RUN;
			ocomp = ppp->xcomp;
			ostate = ppp->xc_state;
			ppp->xcomp = cp;
			ppp->xc_state = state;
			ppp_xmit_unlock(ppp);
			if (ostate) {
				ocomp->comp_free(ostate);
				module_put(ocomp->owner);
			}
			err = 0;
		} else
			module_put(cp->owner);

	} else {
		state = cp->decomp_alloc(ccp_option, data.length);
		if (state) {
			ppp_recv_lock(ppp);
			ppp->rstate &= ~SC_DECOMP_RUN;
			ocomp = ppp->rcomp;
			ostate = ppp->rc_state;
			ppp->rcomp = cp;
			ppp->rc_state = state;
			ppp_recv_unlock(ppp);
			if (ostate) {
				ocomp->decomp_free(ostate);
				module_put(ocomp->owner);
			}
			err = 0;
		} else
			module_put(cp->owner);
	}

 out:
	return err;
}

Project: linux
File: slhc.c

slhc_free(struct slcompress *comp)
{
	if ( comp == NULLSLCOMPR )
		return;

	if ( comp->tstate != NULLSLSTATE )
		kfree( comp->tstate );

	if ( comp->rstate != NULLSLSTATE )
		kfree( comp->rstate );

	kfree( comp );
}

Project: linux
File: isdn_ppp.c

isdn_ppp_free(isdn_net_local *lp)
{
	struct ippp_struct *is;

	if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
		printk(KERN_ERR "%s: ppp_slot(%d) out of range\n",
		       __func__, lp->ppp_slot);
		return 0;
	}

#ifdef CONFIG_ISDN_MPP
	spin_lock(&lp->netdev->pb->lock);
#endif
	isdn_net_rm_from_bundle(lp);
#ifdef CONFIG_ISDN_MPP
	if (lp->netdev->pb->ref_ct == 1)	/* last link in queue? */
		isdn_ppp_mp_cleanup(lp);

	lp->netdev->pb->ref_ct--;
	spin_unlock(&lp->netdev->pb->lock);
#endif /* CONFIG_ISDN_MPP */
	if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
		printk(KERN_ERR "%s: ppp_slot(%d) now invalid\n",
		       __func__, lp->ppp_slot);
		return 0;
	}
	is = ippp_table[lp->ppp_slot];
	if ((is->state & IPPP_CONNECT))
		isdn_ppp_closewait(lp->ppp_slot);	/* force wakeup on ippp device */
	else if (is->state & IPPP_ASSIGNED)
		is->state = IPPP_OPEN;	/* fallback to 'OPEN but not ASSIGNED' state */

	if (is->debug & 0x1)
		printk(KERN_DEBUG "isdn_ppp_free %d %lx %lx\n", lp->ppp_slot, (long) lp, (long) is->lp);

	is->lp = NULL;          /* link is down .. set lp to NULL */
	lp->ppp_slot = -1;      /* is this OK ?? */

	return 0;
}

Project: linux
File: slhc.c

slhc_compress(struct slcompress *comp, unsigned char *icp, int isize,
	unsigned char *ocp, unsigned char **cpp, int compress_cid)
{
	register struct cstate *ocs = &(comp->tstate[comp->xmit_oldest]);
	register struct cstate *lcs = ocs;
	register struct cstate *cs = lcs->next;
	register unsigned long deltaS, deltaA;
	register short changes = 0;
	int hlen;
	unsigned char new_seq[16];
	register unsigned char *cp = new_seq;
	struct iphdr *ip;
	struct tcphdr *th, *oth;
	__sum16 csum;


	/*
	 *	Don't play with runt packets.
	 */

	if(isize<sizeof(struct iphdr))
		return isize;

	ip = (struct iphdr *) icp;

	/* Bail if this packet isn't TCP, or is an IP fragment */
	if (ip->protocol != IPPROTO_TCP || (ntohs(ip->frag_off) & 0x3fff)) {
		/* Send as regular IP */
		if(ip->protocol != IPPROTO_TCP)
			comp->sls_o_nontcp++;
		else
			comp->sls_o_tcp++;
		return isize;
	}
	/* Extract TCP header */

	th = (struct tcphdr *)(((unsigned char *)ip) + ip->ihl*4);
	hlen = ip->ihl*4 + th->doff*4;

	/*  Bail if the TCP packet isn't `compressible' (i.e., ACK isn't set or
	 *  some other control bit is set). Also uncompressible if
	 *  it's a runt.
	 */
	if(hlen > isize || th->syn || th->fin || th->rst ||
	    ! (th->ack)){
		/* TCP connection stuff; send as regular IP */
		comp->sls_o_tcp++;
		return isize;
	}
	/*
	 * Packet is compressible -- we're going to send either a
	 * COMPRESSED_TCP or UNCOMPRESSED_TCP packet.  Either way,
	 * we need to locate (or create) the connection state.
	 *
	 * States are kept in a circularly linked list with
	 * xmit_oldest pointing to the end of the list.  The
	 * list is kept in lru order by moving a state to the
	 * head of the list whenever it is referenced.  Since
	 * the list is short and, empirically, the connection
	 * we want is almost always near the front, we locate
	 * states via linear search.  If we don't find a state
	 * for the datagram, the oldest state is (re-)used.
	 */
	for ( ; ; ) {
		if( ip->saddr == cs->cs_ip.saddr
		 && ip->daddr == cs->cs_ip.daddr
		 && th->source == cs->cs_tcp.source
		 && th->dest == cs->cs_tcp.dest)
			goto found;

		/* if current equal oldest, at end of list */
		if ( cs == ocs )
			break;
		lcs = cs;
		cs = cs->next;
		comp->sls_o_searches++;
	}
	/*
	 * Didn't find it -- re-use oldest cstate.  Send an
	 * uncompressed packet that tells the other side what
	 * connection number we're using for this conversation.
	 *
	 * Note that since the state list is circular, the oldest
	 * state points to the newest and we only need to set
	 * xmit_oldest to update the lru linkage.
	 */
	comp->sls_o_misses++;
	comp->xmit_oldest = lcs->cs_this;
	goto uncompressed;

found:
	/*
	 * Found it -- move to the front on the connection list.
	 */
	if(lcs == ocs) {
 		/* found at most recently used */
	} else if (cs == ocs) {
		/* found at least recently used */
		comp->xmit_oldest = lcs->cs_this;
	} else {
		/* more than 2 elements */
		lcs->next = cs->next;
		cs->next = ocs->next;
		ocs->next = cs;
	}

	/*
	 * Make sure that only what we expect to change changed.
	 * Check the following:
	 * IP protocol version, header length & type of service.
	 * The "Don't fragment" bit.
	 * The time-to-live field.
	 * The TCP header length.
	 * IP options, if any.
	 * TCP options, if any.
	 * If any of these things are different between the previous &
	 * current datagram, we send the current datagram `uncompressed'.
	 */
	oth = &cs->cs_tcp;

	if(ip->version != cs->cs_ip.version || ip->ihl != cs->cs_ip.ihl
	 || ip->tos != cs->cs_ip.tos
	 || (ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000))
	 || ip->ttl != cs->cs_ip.ttl
	 || th->doff != cs->cs_tcp.doff
	 || (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0)
	 || (th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4) != 0)){
		goto uncompressed;
	}

	/*
	 * Figure out which of the changing fields changed.  The
	 * receiver expects changes in the order: urgent, window,
	 * ack, seq (the order minimizes the number of temporaries
	 * needed in this section of code).
	 */
	if(th->urg){
		deltaS = ntohs(th->urg_ptr);
		cp = encode(cp,deltaS);
		changes |= NEW_U;
	} else if(th->urg_ptr != oth->urg_ptr){
		/* argh! URG not set but urp changed -- a sensible
		 * implementation should never do this but RFC793
		 * doesn't prohibit the change so we have to deal
		 * with it. */
		goto uncompressed;
	}
	if((deltaS = ntohs(th->window) - ntohs(oth->window)) != 0){
		cp = encode(cp,deltaS);
		changes |= NEW_W;
	}
	if((deltaA = ntohl(th->ack_seq) - ntohl(oth->ack_seq)) != 0L){
		if(deltaA > 0x0000ffff)
			goto uncompressed;
		cp = encode(cp,deltaA);
		changes |= NEW_A;
	}
	if((deltaS = ntohl(th->seq) - ntohl(oth->seq)) != 0L){
		if(deltaS > 0x0000ffff)
			goto uncompressed;
		cp = encode(cp,deltaS);
		changes |= NEW_S;
	}

	switch(changes){
	case 0:	/* Nothing changed. If this packet contains data and the
		 * last one didn't, this is probably a data packet following
		 * an ack (normal on an interactive connection) and we send
		 * it compressed.  Otherwise it's probably a retransmit,
		 * retransmitted ack or window probe.  Send it uncompressed
		 * in case the other side missed the compressed version.
		 */
		if(ip->tot_len != cs->cs_ip.tot_len &&
		   ntohs(cs->cs_ip.tot_len) == hlen)
			break;
		goto uncompressed;
	case SPECIAL_I:
	case SPECIAL_D:
		/* actual changes match one of our special case encodings --
		 * send packet uncompressed.
		 */
		goto uncompressed;
	case NEW_S|NEW_A:
		if(deltaS == deltaA &&
		    deltaS == ntohs(cs->cs_ip.tot_len) - hlen){
			/* special case for echoed terminal traffic */
			changes = SPECIAL_I;
			cp = new_seq;
		}
		break;
	case NEW_S:
		if(deltaS == ntohs(cs->cs_ip.tot_len) - hlen){
			/* special case for data xfer */
			changes = SPECIAL_D;
			cp = new_seq;
		}
		break;
	}
	deltaS = ntohs(ip->id) - ntohs(cs->cs_ip.id);
	if(deltaS != 1){
		cp = encode(cp,deltaS);
		changes |= NEW_I;
	}
	if(th->psh)
		changes |= TCP_PUSH_BIT;
	/* Grab the cksum before we overwrite it below.  Then update our
	 * state with this packet's header.
	 */
	csum = th->check;
	memcpy(&cs->cs_ip,ip,20);
	memcpy(&cs->cs_tcp,th,20);
	/* We want to use the original packet as our compressed packet.
	 * (cp - new_seq) is the number of bytes we need for compressed
	 * sequence numbers.  In addition we need one byte for the change
	 * mask, one for the connection id and two for the tcp checksum.
	 * So, (cp - new_seq) + 4 bytes of header are needed.
	 */
	deltaS = cp - new_seq;
	if(compress_cid == 0 || comp->xmit_current != cs->cs_this){
		cp = ocp;
		*cpp = ocp;
		*cp++ = changes | NEW_C;
		*cp++ = cs->cs_this;
		comp->xmit_current = cs->cs_this;
	} else {
		cp = ocp;
		*cpp = ocp;
		*cp++ = changes;
	}
	*(__sum16 *)cp = csum;
	cp += 2;
/* deltaS is now the size of the change section of the compressed header */
	memcpy(cp,new_seq,deltaS);	/* Write list of deltas */
	memcpy(cp+deltaS,icp+hlen,isize-hlen);
	comp->sls_o_compressed++;
	ocp[0] |= SL_TYPE_COMPRESSED_TCP;
	return isize - hlen + deltaS + (cp - ocp);

	/* Update connection state cs & send uncompressed packet (i.e.,
	 * a regular ip/tcp packet but with the 'conversation id' we hope
	 * to use on future compressed packets in the protocol field).
	 */
uncompressed:
	memcpy(&cs->cs_ip,ip,20);
	memcpy(&cs->cs_tcp,th,20);
	if (ip->ihl > 5)
	  memcpy(cs->cs_ipopt, ip+1, ((ip->ihl) - 5) * 4);
	if (th->doff > 5)
	  memcpy(cs->cs_tcpopt, th+1, ((th->doff) - 5) * 4);
	comp->xmit_current = cs->cs_this;
	comp->sls_o_uncompressed++;
	memcpy(ocp, icp, isize);
	*cpp = ocp;
	ocp[9] = cs->cs_this;
	ocp[0] |= SL_TYPE_UNCOMPRESSED_TCP;
	return isize;
}

Project: linux
File: slhc.c

put16(unsigned char *cp, unsigned short x)
{
	*cp++ = x >> 8;
	*cp++ = x;

	return cp;
}

Project: linux
File: isdn_ppp.c

void isdn_ppp_mp_reassembly(isdn_net_dev *net_dev, isdn_net_local *lp,
			    struct sk_buff *from, struct sk_buff *to)
{
	ippp_bundle *mp = net_dev->pb;
	int proto;
	struct sk_buff *skb;
	unsigned int tot_len;

	if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
		printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
		       __func__, lp->ppp_slot);
		return;
	}
	if (MP_FLAGS(from) == (MP_BEGIN_FRAG | MP_END_FRAG)) {
		if (ippp_table[lp->ppp_slot]->debug & 0x40)
			printk(KERN_DEBUG "isdn_mppp: reassembly: frame %d, "
			       "len %d\n", MP_SEQ(from), from->len);
		skb = from;
		skb_pull(skb, MP_HEADER_LEN);
		mp->frames--;
	} else {
		struct sk_buff *frag;
		int n;

		for (tot_len = n = 0, frag = from; frag != to; frag = frag->next, n++)
			tot_len += frag->len - MP_HEADER_LEN;

		if (ippp_table[lp->ppp_slot]->debug & 0x40)
			printk(KERN_DEBUG"isdn_mppp: reassembling frames %d "
			       "to %d, len %d\n", MP_SEQ(from),
			       (MP_SEQ(from) + n - 1) & MP_LONGSEQ_MASK, tot_len);
		if ((skb = dev_alloc_skb(tot_len)) == NULL) {
			printk(KERN_ERR "isdn_mppp: cannot allocate sk buff "
			       "of size %d\n", tot_len);
			isdn_ppp_mp_discard(mp, from, to);
			return;
		}

		while (from != to) {
			unsigned int len = from->len - MP_HEADER_LEN;

			skb_copy_from_linear_data_offset(from, MP_HEADER_LEN,
							 skb_put(skb, len),
							 len);
			frag = from->next;
			isdn_ppp_mp_free_skb(mp, from);
			from = frag;
		}
	}
	proto = isdn_ppp_strip_proto(skb);
	isdn_ppp_push_higher(net_dev, lp, skb, proto);
}

Project: linux
File: isdn_ppp.c

static ippp_bundle *isdn_ppp_mp_bundle_alloc(void)
{
	int i;
	for (i = 0; i < ISDN_MAX_CHANNELS; i++)
		if (isdn_ppp_bundle_arr[i].ref_ct <= 0)
			return (isdn_ppp_bundle_arr + i);
	return NULL;
}

Project: linux
File: isdn_ppp.c

static int isdn_ppp_mp_init(isdn_net_local *lp, ippp_bundle *add_to)
{
	struct ippp_struct *is;

	if (lp->ppp_slot < 0) {
		printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
		       __func__, lp->ppp_slot);
		return (-EINVAL);
	}

	is = ippp_table[lp->ppp_slot];
	if (add_to) {
		if (lp->netdev->pb)
			lp->netdev->pb->ref_ct--;
		lp->netdev->pb = add_to;
	} else {		/* first link in a bundle */
		is->mp_seqno = 0;
		if ((lp->netdev->pb = isdn_ppp_mp_bundle_alloc()) == NULL)
			return -ENOMEM;
		lp->next = lp->last = lp;	/* nobody else in a queue */
		lp->netdev->pb->frags = NULL;
		lp->netdev->pb->frames = 0;
		lp->netdev->pb->seq = UINT_MAX;
	}
	lp->netdev->pb->ref_ct++;

	is->last_link_seqno = 0;
	return 0;
}

Project: linux
File: isdn_ppp.c

isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev)
{
	isdn_net_local *lp, *mlp;
	isdn_net_dev *nd;
	unsigned int proto = PPP_IP;     /* 0x21 */
	struct ippp_struct *ipt, *ipts;
	int slot, retval = NETDEV_TX_OK;

	mlp = netdev_priv(netdev);
	nd = mlp->netdev;       /* get master lp */

	slot = mlp->ppp_slot;
	if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
		printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot(%d)\n",
		       mlp->ppp_slot);
		kfree_skb(skb);
		goto out;
	}
	ipts = ippp_table[slot];

	if (!(ipts->pppcfg & SC_ENABLE_IP)) {	/* PPP connected ? */
		if (ipts->debug & 0x1)
			printk(KERN_INFO "%s: IP frame delayed.\n", netdev->name);
		retval = NETDEV_TX_BUSY;
		goto out;
	}

	switch (ntohs(skb->protocol)) {
	case ETH_P_IP:
		proto = PPP_IP;
		break;
	case ETH_P_IPX:
		proto = PPP_IPX;	/* untested */
		break;
	default:
		printk(KERN_ERR "isdn_ppp: skipped unsupported protocol: %#x.\n",
		       skb->protocol);
		dev_kfree_skb(skb);
		goto out;
	}

	lp = isdn_net_get_locked_lp(nd);
	if (!lp) {
		printk(KERN_WARNING "%s: all channels busy - requeuing!\n", netdev->name);
		retval = NETDEV_TX_BUSY;
		goto out;
	}
	/* we have our lp locked from now on */

	slot = lp->ppp_slot;
	if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
		printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot(%d)\n",
		       lp->ppp_slot);
		kfree_skb(skb);
		goto unlock;
	}
	ipt = ippp_table[slot];

	/*
	 * after this line .. requeueing in the device queue is no longer allowed!!!
	 */

	/* Pull off the fake header we stuck on earlier to keep
	 * the fragmentation code happy.
	 */
	skb_pull(skb, IPPP_MAX_HEADER);

#ifdef CONFIG_IPPP_FILTER
	/* check if we should pass this packet
	 * the filter instructions are constructed assuming
	 * a four-byte PPP header on each packet */
	*skb_push(skb, 4) = 1; /* indicate outbound */

	{
		__be16 *p = (__be16 *)skb->data;

		p++;
		*p = htons(proto);
	}

	if (ipt->pass_filter
	    && BPF_PROG_RUN(ipt->pass_filter, skb) == 0) {
		if (ipt->debug & 0x4)
			printk(KERN_DEBUG "IPPP: outbound frame filtered.\n");
		kfree_skb(skb);
		goto unlock;
	}
	if (!(ipt->active_filter
	      && BPF_PROG_RUN(ipt->active_filter, skb) == 0)) {
		if (ipt->debug & 0x4)
			printk(KERN_DEBUG "IPPP: link-active filter: resetting huptimer.\n");
		lp->huptimer = 0;
	}
	skb_pull(skb, 4);
#else /* CONFIG_IPPP_FILTER */
	lp->huptimer = 0;
#endif /* CONFIG_IPPP_FILTER */

	if (ipt->debug & 0x4)
		printk(KERN_DEBUG "xmit skb, len %d\n", (int) skb->len);
	if (ipts->debug & 0x40)
		isdn_ppp_frame_log("xmit0", skb->data, skb->len, 32, ipts->unit, lp->ppp_slot);

#ifdef CONFIG_ISDN_PPP_VJ
	if (proto == PPP_IP && ipts->pppcfg & SC_COMP_TCP) {	/* ipts here? probably yes, but check this again */
		struct sk_buff *new_skb;
		unsigned short hl;
		/*
		 * we need to reserve enough 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 + IPPP_MAX_HEADER;
		/*
		 * Note: hl might still be insufficient because the method
		 * above does not account for a possibible MPPP slave channel
		 * which had larger HL header space requirements than the
		 * master.
		 */
		new_skb = alloc_skb(hl + skb->len, GFP_ATOMIC);
		if (new_skb) {
			u_char *buf;
			int pktlen;

			skb_reserve(new_skb, hl);
			new_skb->dev = skb->dev;
			skb_put(new_skb, skb->len);
			buf = skb->data;

			pktlen = slhc_compress(ipts->slcomp, skb->data, skb->len, new_skb->data,
					       &buf, !(ipts->pppcfg & SC_NO_TCP_CCID));

			if (buf != skb->data) {
				if (new_skb->data != buf)
					printk(KERN_ERR "isdn_ppp: FATAL error after slhc_compress!!\n");
				dev_kfree_skb(skb);
				skb = new_skb;
			} else {
				dev_kfree_skb(new_skb);
			}

			skb_trim(skb, pktlen);
			if (skb->data[0] & SL_TYPE_COMPRESSED_TCP) {	/* cslip? style -> PPP */
				proto = PPP_VJC_COMP;
				skb->data[0] ^= SL_TYPE_COMPRESSED_TCP;
			} else {
				if (skb->data[0] >= SL_TYPE_UNCOMPRESSED_TCP)
					proto = PPP_VJC_UNCOMP;
				skb->data[0] = (skb->data[0] & 0x0f) | 0x40;
			}
		}
	}
#endif

	/*
	 * normal (single link) or bundle compression
	 */
	if (ipts->compflags & SC_COMP_ON) {
		/* We send compressed only if both down- und upstream
		   compression is negotiated, that means, CCP is up */
		if (ipts->compflags & SC_DECOMP_ON) {
			skb = isdn_ppp_compress(skb, &proto, ipt, ipts, 0);
		} else {
			printk(KERN_DEBUG "isdn_ppp: CCP not yet up - sending as-is\n");
		}
	}

	if (ipt->debug & 0x24)
		printk(KERN_DEBUG "xmit2 skb, len %d, proto %04x\n", (int) skb->len, proto);

#ifdef CONFIG_ISDN_MPP
	if (ipt->mpppcfg & SC_MP_PROT) {
		/* we get mp_seqno from static isdn_net_local */
		long mp_seqno = ipts->mp_seqno;
		ipts->mp_seqno++;
		if (ipt->mpppcfg & SC_OUT_SHORT_SEQ) {
			unsigned char *data = isdn_ppp_skb_push(&skb, 3);
			if (!data)
				goto unlock;
			mp_seqno &= 0xfff;
			data[0] = MP_BEGIN_FRAG | MP_END_FRAG | ((mp_seqno >> 8) & 0xf);	/* (B)egin & (E)ndbit .. */
			data[1] = mp_seqno & 0xff;
			data[2] = proto;	/* PID compression */
		} else {
			unsigned char *data = isdn_ppp_skb_push(&skb, 5);
			if (!data)
				goto unlock;
			data[0] = MP_BEGIN_FRAG | MP_END_FRAG;	/* (B)egin & (E)ndbit .. */
			data[1] = (mp_seqno >> 16) & 0xff;	/* sequence number: 24bit */
			data[2] = (mp_seqno >> 8) & 0xff;
			data[3] = (mp_seqno >> 0) & 0xff;
			data[4] = proto;	/* PID compression */
		}
		proto = PPP_MP; /* MP Protocol, 0x003d */
	}
#endif

	/*
	 * 'link in bundle' compression  ...
	 */
	if (ipt->compflags & SC_LINK_COMP_ON)
		skb = isdn_ppp_compress(skb, &proto, ipt, ipts, 1);

	if ((ipt->pppcfg & SC_COMP_PROT) && (proto <= 0xff)) {
		unsigned char *data = isdn_ppp_skb_push(&skb, 1);
		if (!data)
			goto unlock;
		data[0] = proto & 0xff;
	}
	else {
		unsigned char *data = isdn_ppp_skb_push(&skb, 2);
		if (!data)
			goto unlock;
		data[0] = (proto >> 8) & 0xff;
		data[1] = proto & 0xff;
	}
	if (!(ipt->pppcfg & SC_COMP_AC)) {
		unsigned char *data = isdn_ppp_skb_push(&skb, 2);
		if (!data)
			goto unlock;
		data[0] = 0xff;    /* All Stations */
		data[1] = 0x03;    /* Unnumbered information */
	}

	/* tx-stats are now updated via BSENT-callback */

	if (ipts->debug & 0x40) {
		printk(KERN_DEBUG "skb xmit: len: %d\n", (int) skb->len);
		isdn_ppp_frame_log("xmit", skb->data, skb->len, 32, ipt->unit, lp->ppp_slot);
	}

	isdn_net_writebuf_skb(lp, skb);

unlock:
	spin_unlock_bh(&lp->xmit_lock);
out:
	return retval;
}

Project: linux
File: isdn_ppp.c

isdn_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 enough 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;
}

Project: linux
File: slhc.c

slhc_toss(struct slcompress *comp)
{
	if ( comp == NULLSLCOMPR )
		return 0;

	comp->flags |= SLF_TOSS;
	return 0;
}

Project: linux
File: isdn_ppp.c

static void isdn_ppp_mp_print_recv_pkt(int slot, struct sk_buff *skb)
{
	printk(KERN_DEBUG "mp_recv: %d/%d -> %02x %02x %02x %02x %02x %02x\n",
	       slot, (int) skb->len,
	       (int) skb->data[0], (int) skb->data[1], (int) skb->data[2],
	       (int) skb->data[3], (int) skb->data[4], (int) skb->data[5]);
}

Project: linux
File: isdn_ppp.c

static unsigned char *isdn_ppp_skb_push(struct sk_buff **skb_p, int len)
{
	struct sk_buff *skb = *skb_p;

	if (skb_headroom(skb) < len) {
		struct sk_buff *nskb = skb_realloc_headroom(skb, len);

		if (!nskb) {
			printk(KERN_ERR "isdn_ppp_skb_push: can't realloc headroom!\n");
			dev_kfree_skb(skb);
			return NULL;
		}
		printk(KERN_DEBUG "isdn_ppp_skb_push:under %d %d\n", skb_headroom(skb), len);
		dev_kfree_skb(skb);
		*skb_p = nskb;
		return skb_push(nskb, len);
	}
	return skb_push(skb, len);
}

Project: linux
File: isdn_ppp.c

set_arg(void __user *b, void *val, int len)
{
	if (len <= 0)
		len = sizeof(void *);
	if (copy_to_user(b, val, len))
		return -EFAULT;
	return 0;
}

Project: linux
File: isdn_ppp.c

isdn_ppp_wakeup_daemon(isdn_net_local *lp)
{
	if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
		printk(KERN_ERR "%s: ppp_slot(%d) out of range\n",
		       __func__, lp->ppp_slot);
		return;
	}
	ippp_table[lp->ppp_slot]->state = IPPP_OPEN | IPPP_CONNECT | IPPP_NOBLOCK;
	wake_up_interruptible(&ippp_table[lp->ppp_slot]->wq);
}

Project: linux
File: isdn_ppp.c

static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *skb)
{
	struct ippp_struct *mis, *is;
	int proto, slot = lp->ppp_slot;
	unsigned char *data;

	if (!skb || skb->len < 3)
		return;
	if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
		printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
		       __func__, slot);
		return;
	}
	is = ippp_table[slot];
	/* Daemon may send with or without address and control field comp */
	data = skb->data;
	if (!(is->pppcfg & SC_COMP_AC) && data[0] == 0xff && data[1] == 0x03) {
		data += 2;
		if (skb->len < 5)
			return;
	}

	proto = ((int)data[0]<<8) + data[1];
	if (proto != PPP_CCP && proto != PPP_CCPFRAG)
		return;

	printk(KERN_DEBUG "Received CCP frame from daemon:\n");
	isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit, lp->ppp_slot);

	if (lp->master) {
		slot = ISDN_MASTER_PRIV(lp)->ppp_slot;
		if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
			printk(KERN_ERR "%s: slot(%d) out of range\n",
			       __func__, slot);
			return;
		}
		mis = ippp_table[slot];
	} else
		mis = is;
	if (mis != is)
		printk(KERN_DEBUG "isdn_ppp: Ouch! Master CCP sends on slave slot!\n");

	switch (data[2]) {
	case CCP_CONFREQ:
		if (is->debug & 0x10)
			printk(KERN_DEBUG "Disable decompression here!\n");
		if (proto == PPP_CCP)
			is->compflags &= ~SC_DECOMP_ON;
		else
			is->compflags &= ~SC_LINK_DECOMP_ON;
		break;
	case CCP_TERMREQ:
	case CCP_TERMACK:
		if (is->debug & 0x10)
			printk(KERN_DEBUG "Disable (de)compression here!\n");
		if (proto == PPP_CCP)
			is->compflags &= ~(SC_DECOMP_ON | SC_COMP_ON);
		else
			is->compflags &= ~(SC_LINK_DECOMP_ON | SC_LINK_COMP_ON);
		break;
	case CCP_CONFACK:
		/* if we SEND an ackowledge we can/must enable the compressor */
		if (is->debug & 0x10)
			printk(KERN_DEBUG "Enable compression here!\n");
		if (proto == PPP_CCP) {
			if (!is->compressor)
				break;
			is->compflags |= SC_COMP_ON;
		} else {
			if (!is->compressor)
				break;
			is->compflags |= SC_LINK_COMP_ON;
		}
		break;
	case CCP_RESETACK:
		/* If we send a ACK we should reset our compressor */
		if (is->debug & 0x10)
			printk(KERN_DEBUG "Reset decompression state here!\n");
		printk(KERN_DEBUG "ResetAck from daemon passed by\n");
		if (proto == PPP_CCP) {
			/* link to master? */
			if (is->compressor && is->comp_stat)
				is->compressor->reset(is->comp_stat, 0, 0,
						      NULL, 0, NULL);
			is->compflags &= ~SC_COMP_DISCARD;
		}
		else {
			if (is->link_compressor && is->link_comp_stat)
				is->link_compressor->reset(is->link_comp_stat,
							   0, 0, NULL, 0, NULL);
			is->compflags &= ~SC_LINK_COMP_DISCARD;
		}
		break;
	case CCP_RESETREQ:
		/* Just let it pass by */
		printk(KERN_DEBUG "ResetReq from daemon passed by\n");
		break;
	}
}

Project: linux
File: isdn_ppp.c

static struct ippp_ccp_reset_state *isdn_ppp_ccp_reset_alloc_state(struct ippp_struct *is,
								   unsigned char id)
{
	struct ippp_ccp_reset_state *rs;
	if (is->reset->rs[id]) {
		printk(KERN_WARNING "ippp_ccp: old state exists for id %d\n",
		       id);
		return NULL;
	} else {
		rs = kzalloc(sizeof(struct ippp_ccp_reset_state), GFP_KERNEL);
		if (!rs)
			return NULL;
		rs->state = CCPResetIdle;
		rs->is = is;
		rs->id = id;
		init_timer(&rs->timer);
		rs->timer.data = (unsigned long)rs;
		rs->timer.function = isdn_ppp_ccp_timer_callback;
		is->reset->rs[id] = rs;
	}
	return rs;
}

Project: linux
File: isdn_ppp.c

static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in, int *proto,
					 struct ippp_struct *is, struct ippp_struct *master, int type)
{
	int ret;
	int new_proto;
	struct isdn_ppp_compressor *compressor;
	void *stat;
	struct sk_buff *skb_out;

	/* we do not compress control protocols */
	if (*proto < 0 || *proto > 0x3fff) {
		return skb_in;
	}

	if (type) { /* type=1 => Link compression */
		return skb_in;
	}
	else {
		if (!master) {
			compressor = is->compressor;
			stat = is->comp_stat;
		}
		else {
			compressor = master->compressor;
			stat = master->comp_stat;
		}
		new_proto = PPP_COMP;
	}

	if (!compressor) {
		printk(KERN_ERR "isdn_ppp: No compressor set!\n");
		return skb_in;
	}
	if (!stat) {
		printk(KERN_ERR "isdn_ppp: Compressor not initialized?\n");
		return skb_in;
	}

	/* Allow for at least 150 % expansion (for now) */
	skb_out = alloc_skb(skb_in->len + skb_in->len / 2 + 32 +
			    skb_headroom(skb_in), GFP_ATOMIC);
	if (!skb_out)
		return skb_in;
	skb_reserve(skb_out, skb_headroom(skb_in));

	ret = (compressor->compress)(stat, skb_in, skb_out, *proto);
	if (!ret) {
		dev_kfree_skb(skb_out);
		return skb_in;
	}

	dev_kfree_skb(skb_in);
	*proto = new_proto;
	return skb_out;
}

Project: linux
File: isdn_ppp.c

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;
}

Project: linux
File: slip.c

static int sl_alloc_bufs(struct slip *sl, int mtu)
{
	int err = -ENOBUFS;
	unsigned long len;
	char *rbuff = NULL;
	char *xbuff = NULL;
#ifdef SL_INCLUDE_CSLIP
	char *cbuff = NULL;
	struct slcompress *slcomp = NULL;
#endif

	/*
	 * Allocate the SLIP frame buffers:
	 *
	 * rbuff	Receive buffer.
	 * xbuff	Transmit buffer.
	 * cbuff        Temporary compression buffer.
	 */
	len = mtu * 2;

	/*
	 * allow for arrival of larger UDP packets, even if we say not to
	 * also fixes a bug in which SunOS sends 512-byte packets even with
	 * an MSS of 128
	 */
	if (len < 576 * 2)
		len = 576 * 2;
	rbuff = kmalloc(len + 4, GFP_KERNEL);
	if (rbuff == NULL)
		goto err_exit;
	xbuff = kmalloc(len + 4, GFP_KERNEL);
	if (xbuff == NULL)
		goto err_exit;
#ifdef SL_INCLUDE_CSLIP
	cbuff = kmalloc(len + 4, GFP_KERNEL);
	if (cbuff == NULL)
		goto err_exit;
	slcomp = slhc_init(16, 16);
	if (IS_ERR(slcomp))
		goto err_exit;
#endif
	spin_lock_bh(&sl->lock);
	if (sl->tty == NULL) {
		spin_unlock_bh(&sl->lock);
		err = -ENODEV;
		goto err_exit;
	}
	sl->mtu	     = mtu;
	sl->buffsize = len;
	sl->rcount   = 0;
	sl->xleft    = 0;
	rbuff = xchg(&sl->rbuff, rbuff);
	xbuff = xchg(&sl->xbuff, xbuff);
#ifdef SL_INCLUDE_CSLIP
	cbuff = xchg(&sl->cbuff, cbuff);
	slcomp = xchg(&sl->slcomp, slcomp);
#endif
#ifdef CONFIG_SLIP_MODE_SLIP6
	sl->xdata    = 0;
	sl->xbits    = 0;
#endif
	spin_unlock_bh(&sl->lock);
	err = 0;

	/* Cleanup */
err_exit:
#ifdef SL_INCLUDE_CSLIP
	kfree(cbuff);
	slhc_free(slcomp);
#endif
	kfree(xbuff);
	kfree(rbuff);
	return err;
}

Project: linux
File: slhc.c

slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize)
{
  printk(KERN_DEBUG "Called IP function on non IP-system: slhc_uncompress");
  return -EINVAL;
}

Project: linux
File: slhc.c

decode(unsigned char **cpp)
{
	register int x;

	x = *(*cpp)++;
	if(x == 0){
		return pull16(cpp) & 0xffff;	/* pull16 returns -1 on error */
	} else {
		return x & 0xff;		/* -1 if PULLCHAR returned error */
	}
}

Project: linux
File: isdn_ppp.c

static void isdn_ppp_ccp_kickup(struct ippp_struct *is)
{
	isdn_ppp_fill_rq(NULL, 0, PPP_COMP, is->lp->ppp_slot);
}

Project: linux
File: isdn_ppp.c

static u32 isdn_ppp_mp_get_seq(int short_seq,
			       struct sk_buff *skb, u32 last_seq)
{
	u32 seq;
	int flags = skb->data[0] & (MP_BEGIN_FRAG | MP_END_FRAG);

	if (!short_seq)
	{
		seq = ntohl(*(__be32 *)skb->data) & MP_LONGSEQ_MASK;
		skb_push(skb, 1);
	}
	else
	{
		/* convert 12-bit short seq number to 24-bit long one
		 */
		seq = ntohs(*(__be16 *)skb->data) & MP_SHORTSEQ_MASK;

		/* check for seqence wrap */
		if (!(seq &  MP_SHORTSEQ_MAXBIT) &&
		    (last_seq &  MP_SHORTSEQ_MAXBIT) &&
		    (unsigned long)last_seq <= MP_LONGSEQ_MAX)
			seq |= (last_seq + MP_SHORTSEQ_MAX + 1) &
				(~MP_SHORTSEQ_MASK & MP_LONGSEQ_MASK);
		else
			seq |= last_seq & (~MP_SHORTSEQ_MASK & MP_LONGSEQ_MASK);

		skb_push(skb, 3);	/* put converted seqence back in skb */
	}
	*(u32 *)(skb->data + 1) = seq;	/* put seqence back in _host_ byte
					 * order */
	skb->data[0] = flags;	        /* restore flags */
	return seq;
}

Project: linux
File: isdn_ppp.c

int isdn_ppp_register_compressor(struct isdn_ppp_compressor *ipc)
{
	ipc->next = ipc_head;
	ipc->prev = NULL;
	if (ipc_head) {
		ipc_head->prev = ipc;
	}
	ipc_head = ipc;
	return 0;
}

Project: linux
File: isdn_ppp.c

static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp,
				 struct sk_buff *skb, int proto)
{
	struct ippp_struct *is;
	struct ippp_struct *mis;
	int len;
	struct isdn_ppp_resetparams rsparm;
	unsigned char rsdata[IPPP_RESET_MAXDATABYTES];

	printk(KERN_DEBUG "Received CCP frame from peer slot(%d)\n",
	       lp->ppp_slot);
	if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
		printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
		       __func__, lp->ppp_slot);
		return;
	}
	is = ippp_table[lp->ppp_slot];
	isdn_ppp_frame_log("ccp-rcv", skb->data, skb->len, 32, is->unit, lp->ppp_slot);

	if (lp->master) {
		int slot = ISDN_MASTER_PRIV(lp)->ppp_slot;
		if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
			printk(KERN_ERR "%s: slot(%d) out of range\n",
			       __func__, slot);
			return;
		}
		mis = ippp_table[slot];
	} else
		mis = is;

	switch (skb->data[0]) {
	case CCP_CONFREQ:
		if (is->debug & 0x10)
			printk(KERN_DEBUG "Disable compression here!\n");
		if (proto == PPP_CCP)
			mis->compflags &= ~SC_COMP_ON;
		else
			is->compflags &= ~SC_LINK_COMP_ON;
		break;
	case CCP_TERMREQ:
	case CCP_TERMACK:
		if (is->debug & 0x10)
			printk(KERN_DEBUG "Disable (de)compression here!\n");
		if (proto == PPP_CCP)
			mis->compflags &= ~(SC_DECOMP_ON | SC_COMP_ON);
		else
			is->compflags &= ~(SC_LINK_DECOMP_ON | SC_LINK_COMP_ON);
		break;
	case CCP_CONFACK:
		/* if we RECEIVE an ackowledge we enable the decompressor */
		if (is->debug & 0x10)
			printk(KERN_DEBUG "Enable decompression here!\n");
		if (proto == PPP_CCP) {
			if (!mis->decompressor)
				break;
			mis->compflags |= SC_DECOMP_ON;
		} else {
			if (!is->decompressor)
				break;
			is->compflags |= SC_LINK_DECOMP_ON;
		}
		break;

	case CCP_RESETACK:
		printk(KERN_DEBUG "Received ResetAck from peer\n");
		len = (skb->data[2] << 8) | skb->data[3];
		len -= 4;

		if (proto == PPP_CCP) {
			/* If a reset Ack was outstanding for this id, then
			   clean up the state engine */
			isdn_ppp_ccp_reset_ack_rcvd(mis, skb->data[1]);
			if (mis->decompressor && mis->decomp_stat)
				mis->decompressor->
					reset(mis->decomp_stat,
					      skb->data[0],
					      skb->data[1],
					      len ? &skb->data[4] : NULL,
					      len, NULL);
			/* TODO: This is not easy to decide here */
			mis->compflags &= ~SC_DECOMP_DISCARD;
		}
		else {
			isdn_ppp_ccp_reset_ack_rcvd(is, skb->data[1]);
			if (is->link_decompressor && is->link_decomp_stat)
				is->link_decompressor->
					reset(is->link_decomp_stat,
					      skb->data[0],
					      skb->data[1],
					      len ? &skb->data[4] : NULL,
					      len, NULL);
			/* TODO: neither here */
			is->compflags &= ~SC_LINK_DECOMP_DISCARD;
		}
		break;

	case CCP_RESETREQ:
		printk(KERN_DEBUG "Received ResetReq from peer\n");
		/* Receiving a ResetReq means we must reset our compressor */
		/* Set up reset params for the reset entry */
		memset(&rsparm, 0, sizeof(rsparm));
		rsparm.data = rsdata;
		rsparm.maxdlen = IPPP_RESET_MAXDATABYTES;
		/* Isolate data length */
		len = (skb->data[2] << 8) | skb->data[3];
		len -= 4;
		if (proto == PPP_CCP) {
			if (mis->compressor && mis->comp_stat)
				mis->compressor->
					reset(mis->comp_stat,
					      skb->data[0],
					      skb->data[1],
					      len ? &skb->data[4] : NULL,
					      len, &rsparm);
		}
		else {
			if (is->link_compressor && is->link_comp_stat)
				is->link_compressor->
					reset(is->link_comp_stat,
					      skb->data[0],
					      skb->data[1],
					      len ? &skb->data[4] : NULL,
					      len, &rsparm);
		}
		/* Ack the Req as specified by rsparm */
		if (rsparm.valid) {
			/* Compressor reset handler decided how to answer */
			if (rsparm.rsend) {
				/* We should send a Frame */
				isdn_ppp_ccp_xmit_reset(is, proto, CCP_RESETACK,
							rsparm.idval ? rsparm.id
							: skb->data[1],
							rsparm.dtval ?
							rsparm.data : NULL,
							rsparm.dtval ?
							rsparm.dlen : 0);
			} else {
				printk(KERN_DEBUG "ResetAck suppressed\n");
			}
		} else {
			/* We answer with a straight reflected Ack */
			isdn_ppp_ccp_xmit_reset(is, proto, CCP_RESETACK,
						skb->data[1],
						len ? &skb->data[4] : NULL,
						len);
		}
		break;
	}
}

Project: linux
File: isdn_ppp.c

isdn_ppp_hangup_slave(char *name)
{
#ifdef CONFIG_ISDN_MPP
	isdn_net_dev *ndev;
	isdn_net_local *lp;
	struct net_device *sdev;

	if (!(ndev = isdn_net_findif(name)))
		return 1;
	lp = ndev->local;
	if (!(lp->flags & ISDN_NET_CONNECTED))
		return 5;

	sdev = lp->slave;
	while (sdev) {
		isdn_net_local *mlp = netdev_priv(sdev);

		if (mlp->slave) { /* find last connected link in chain */
			isdn_net_local *nlp = ISDN_SLAVE_PRIV(mlp);

			if (!(nlp->flags & ISDN_NET_CONNECTED))
				break;
		} else if (mlp->flags & ISDN_NET_CONNECTED)
			break;

		sdev = mlp->slave;
	}
	if (!sdev)
		return 2;

	isdn_net_hangup(sdev);
	return 0;
#else
	return -1;
#endif
}

Project: linux
File: isdn_ppp.c

get_arg(void __user *b, void *val, int len)
{
	if (len <= 0)
		len = sizeof(void *);
	if (copy_from_user(val, b, len))
		return -EFAULT;
	return 0;
}

Project: linux
File: slhc.c

slhc_init(int rslots, int tslots)
{
	register short i;
	register struct cstate *ts;
	struct slcompress *comp;

	if (rslots < 0 || rslots > 255 || tslots < 0 || tslots > 255)
		return ERR_PTR(-EINVAL);

	comp = kzalloc(sizeof(struct slcompress), GFP_KERNEL);
	if (! comp)
		goto out_fail;

	if (rslots > 0) {
		size_t rsize = rslots * sizeof(struct cstate);
		comp->rstate = kzalloc(rsize, GFP_KERNEL);
		if (! comp->rstate)
			goto out_free;
		comp->rslot_limit = rslots - 1;
	}

	if (tslots > 0) {
		size_t tsize = tslots * sizeof(struct cstate);
		comp->tstate = kzalloc(tsize, GFP_KERNEL);
		if (! comp->tstate)
			goto out_free2;
		comp->tslot_limit = tslots - 1;
	}

	comp->xmit_oldest = 0;
	comp->xmit_current = 255;
	comp->recv_current = 255;
	/*
	 * don't accept any packets with implicit index until we get
	 * one with an explicit index.  Otherwise the uncompress code
	 * will try to use connection 255, which is almost certainly
	 * out of range
	 */
	comp->flags |= SLF_TOSS;

	if ( tslots > 0 ) {
		ts = comp->tstate;
		for(i = comp->tslot_limit; i > 0; --i){
			ts[i].cs_this = i;
			ts[i].next = &(ts[i - 1]);
		}
		ts[0].next = &(ts[comp->tslot_limit]);
		ts[0].cs_this = 0;
	}
	return comp;

out_free2:
	kfree(comp->rstate);
out_free:
	kfree(comp);
out_fail:
	return ERR_PTR(-ENOMEM);
}

Project: linux
File: isdn_ppp.c

static void isdn_ppp_ccp_timer_callback(unsigned long closure)
{
	struct ippp_ccp_reset_state *rs =
		(struct ippp_ccp_reset_state *)closure;

	if (!rs) {
		printk(KERN_ERR "ippp_ccp: timer cb with zero closure.\n");
		return;
	}
	if (rs->ta && rs->state == CCPResetSentReq) {
		/* We are correct here */
		if (!rs->expra) {
			/* Hmm, there is no Ack really expected. We can clean
			   up the state now, it will be reallocated if the
			   decompressor insists on another reset */
			rs->ta = 0;
			isdn_ppp_ccp_reset_free_state(rs->is, rs->id);
			return;
		}
		printk(KERN_DEBUG "ippp_ccp: CCP Reset timed out for id %d\n",
		       rs->id);
		/* Push it again */
		isdn_ppp_ccp_xmit_reset(rs->is, PPP_CCP, CCP_RESETREQ, rs->id,
					rs->data, rs->dlen);
		/* Restart timer */
		rs->timer.expires = jiffies + HZ * 5;
		add_timer(&rs->timer);
	} else {
		printk(KERN_WARNING "ippp_ccp: timer cb in wrong state %d\n",
		       rs->state);
	}
}

Project: linux
File: isdn_ppp.c

static struct ippp_ccp_reset *isdn_ppp_ccp_reset_alloc(struct ippp_struct *is)
{
	struct ippp_ccp_reset *r;
	r = kzalloc(sizeof(struct ippp_ccp_reset), GFP_KERNEL);
	if (!r) {
		printk(KERN_ERR "ippp_ccp: failed to allocate reset data"
		       " structure - no mem\n");
		return NULL;
	}
	printk(KERN_DEBUG "ippp_ccp: allocated reset data structure %p\n", r);
	is->reset = r;
	return r;
}

Project: linux
File: ppp_generic.c

static ssize_t ppp_read(struct file *file, char __user *buf,
			size_t count, loff_t *ppos)
{
	struct ppp_file *pf = file->private_data;
	DECLARE_WAITQUEUE(wait, current);
	ssize_t ret;
	struct sk_buff *skb = NULL;
	struct iovec iov;
	struct iov_iter to;

	ret = count;

	if (!pf)
		return -ENXIO;
	add_wait_queue(&pf->rwait, &wait);
	for (;;) {
		set_current_state(TASK_INTERRUPTIBLE);
		skb = skb_dequeue(&pf->rq);
		if (skb)
			break;
		ret = 0;
		if (pf->dead)
			break;
		if (pf->kind == INTERFACE) {
			/*
			 * Return 0 (EOF) on an interface that has no
			 * channels connected, unless it is looping
			 * network traffic (demand mode).
			 */
			struct ppp *ppp = PF_TO_PPP(pf);
			if (ppp->n_channels == 0 &&
			    (ppp->flags & SC_LOOP_TRAFFIC) == 0)
				break;
		}
		ret = -EAGAIN;
		if (file->f_flags & O_NONBLOCK)
			break;
		ret = -ERESTARTSYS;
		if (signal_pending(current))
			break;
		schedule();
	}
	set_current_state(TASK_RUNNING);
	remove_wait_queue(&pf->rwait, &wait);

	if (!skb)
		goto out;

	ret = -EOVERFLOW;
	if (skb->len > count)
		goto outf;
	ret = -EFAULT;
	iov.iov_base = buf;
	iov.iov_len = count;
	iov_iter_init(&to, READ, &iov, 1, count);
	if (skb_copy_datagram_iter(skb, 0, &to, skb->len))
		goto outf;
	ret = skb->len;

 outf:
	kfree_skb(skb);
 out:
	return ret;
}

Project: linux
File: slhc.c

slhc_remember(struct slcompress *comp, unsigned char *icp, int isize)
{
  printk(KERN_DEBUG "Called IP function on non IP-system: slhc_remember");
  return -EINVAL;
}

Project: linux
File: isdn_ppp.c

isdn_ppp_dial_slave(char *name)
{
#ifdef CONFIG_ISDN_MPP
	isdn_net_dev *ndev;
	isdn_net_local *lp;
	struct net_device *sdev;

	if (!(ndev = isdn_net_findif(name)))
		return 1;
	lp = ndev->local;
	if (!(lp->flags & ISDN_NET_CONNECTED))
		return 5;

	sdev = lp->slave;
	while (sdev) {
		isdn_net_local *mlp = netdev_priv(sdev);
		if (!(mlp->flags & ISDN_NET_CONNECTED))
			break;
		sdev = mlp->slave;
	}
	if (!sdev)
		return 2;

	isdn_net_dial_req(netdev_priv(sdev));
	return 0;
#else
	return -1;
#endif
}

Project: linux
File: isdn_ppp.c

static void isdn_ppp_ccp_reset_ack_rcvd(struct ippp_struct *is,
					unsigned char id)
{
	struct ippp_ccp_reset_state *rs = is->reset->rs[id];

	if (rs) {
		if (rs->ta && rs->state == CCPResetSentReq) {
			/* Great, we are correct */
			if (!rs->expra)
				printk(KERN_DEBUG "ippp_ccp: ResetAck received"
				       " for id %d but not expected\n", id);
		} else {
			printk(KERN_INFO "ippp_ccp: ResetAck received out of"
			       "sync for id %d\n", id);
		}
		if (rs->ta) {
			rs->ta = 0;
			del_timer(&rs->timer);
		}
		isdn_ppp_ccp_reset_free_state(is, id);
	} else {
		printk(KERN_INFO "ippp_ccp: ResetAck received for unknown id"
		       " %d\n", id);
	}
	/* Make sure the simple reset stuff uses a new id next time */
	is->reset->lastid++;
}

Project: linux
File: ppp_generic.c

static struct ppp *ppp_create_interface(struct net *net, int unit,
					struct file *file, int *retp)
{
	struct ppp *ppp;
	struct ppp_net *pn;
	struct net_device *dev = NULL;
	int ret = -ENOMEM;
	int i;

	dev = alloc_netdev(sizeof(struct ppp), "", NET_NAME_UNKNOWN,
			   ppp_setup);
	if (!dev)
		goto out1;

	pn = ppp_pernet(net);

	ppp = netdev_priv(dev);
	ppp->dev = dev;
	ppp->mru = PPP_MRU;
	init_ppp_file(&ppp->file, INTERFACE);
	ppp->file.hdrlen = PPP_HDRLEN - 2;	/* don't count proto bytes */
	ppp->owner = file;
	for (i = 0; i < NUM_NP; ++i)
		ppp->npmode[i] = NPMODE_PASS;
	INIT_LIST_HEAD(&ppp->channels);
	spin_lock_init(&ppp->rlock);
	spin_lock_init(&ppp->wlock);
#ifdef CONFIG_PPP_MULTILINK
	ppp->minseq = -1;
	skb_queue_head_init(&ppp->mrq);
#endif /* CONFIG_PPP_MULTILINK */
#ifdef CONFIG_PPP_FILTER
	ppp->pass_filter = NULL;
	ppp->active_filter = NULL;
#endif /* CONFIG_PPP_FILTER */

	/*
	 * drum roll: don't forget to set
	 * the net device is belong to
	 */
	dev_net_set(dev, net);

	rtnl_lock();
	mutex_lock(&pn->all_ppp_mutex);

	if (unit < 0) {
		unit = unit_get(&pn->units_idr, ppp);
		if (unit < 0) {
			ret = unit;
			goto out2;
		}
	} else {
		ret = -EEXIST;
		if (unit_find(&pn->units_idr, unit))
			goto out2; /* unit already exists */
		/*
		 * if caller need a specified unit number
		 * lets try to satisfy him, otherwise --
		 * he should better ask us for new unit number
		 *
		 * NOTE: yes I know that returning EEXIST it's not
		 * fair but at least pppd will ask us to allocate
		 * new unit in this case so user is happy :)
		 */
		unit = unit_set(&pn->units_idr, ppp, unit);
		if (unit < 0)
			goto out2;
	}

	/* Initialize the new ppp unit */
	ppp->file.index = unit;
	sprintf(dev->name, "ppp%d", unit);

	ret = register_netdevice(dev);
	if (ret != 0) {
		unit_put(&pn->units_idr, unit);
		netdev_err(ppp->dev, "PPP: couldn't register device %s (%d)\n",
			   dev->name, ret);
		goto out2;
	}

	ppp->ppp_net = net;

	atomic_inc(&ppp_unit_count);
	mutex_unlock(&pn->all_ppp_mutex);
	rtnl_unlock();

	*retp = 0;
	return ppp;

out2:
	mutex_unlock(&pn->all_ppp_mutex);
	free_netdev(dev);
out1:
	*retp = ret;
	return NULL;
}

Project: linux
File: isdn_ppp.c

static void isdn_ppp_mp_free_skb(ippp_bundle *mp, struct sk_buff *skb)
{
	dev_kfree_skb(skb);
	mp->frames--;
}

Project: linux
File: isdn_ppp.c

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;

	BUG_ON(net_dev->local->master); // 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);
		kfree_skb(skb);
		return;
	}
	is = ippp_table[slot];

	if (is->debug & 0x4) {
		printk(KERN_DEBUG "ippp_receive: is:%08lx lp:%08lx slot:%d unit:%d len:%d\n",
		       (long)is, (long)lp, lp->ppp_slot, is->unit, (int)skb->len);
		isdn_ppp_frame_log("receive", skb->data, skb->len, 32, is->unit, lp->ppp_slot);
	}

	if (isdn_ppp_skip_ac(is, skb) < 0) {
		kfree_skb(skb);
		return;
	}
	proto = isdn_ppp_strip_proto(skb);
	if (proto < 0) {
		kfree_skb(skb);
		return;
	}

#ifdef CONFIG_ISDN_MPP
	if (is->compflags & SC_LINK_DECOMP_ON) {
		skb = isdn_ppp_decompress(skb, is, NULL, &proto);
		if (!skb) // decompression error
			return;
	}

	if (!(is->mpppcfg & SC_REJ_MP_PROT)) { // we agreed to receive MPPP
		if (proto == PPP_MP) {
			isdn_ppp_mp_receive(net_dev, lp, skb);
			return;
		}
	}
#endif
	isdn_ppp_push_higher(net_dev, lp, skb, proto);
}

Project: linux
File: slhc.c

slhc_compress(struct slcompress *comp, unsigned char *icp, int isize,
	unsigned char *ocp, unsigned char **cpp, int compress_cid)
{
  printk(KERN_DEBUG "Called IP function on non IP-system: slhc_compress");
  return -EINVAL;
}

Project: linux
File: isdn_ppp.c

static struct sk_buff *isdn_ppp_decompress(struct sk_buff *skb, struct ippp_struct *is, struct ippp_struct *master,
					   int *proto)
{
	void *stat = NULL;
	struct isdn_ppp_compressor *ipc = NULL;
	struct sk_buff *skb_out;
	int len;
	struct ippp_struct *ri;
	struct isdn_ppp_resetparams rsparm;
	unsigned char rsdata[IPPP_RESET_MAXDATABYTES];

	if (!master) {
		// per-link decompression
		stat = is->link_decomp_stat;
		ipc = is->link_decompressor;
		ri = is;
	} else {
		stat = master->decomp_stat;
		ipc = master->decompressor;
		ri = master;
	}

	if (!ipc) {
		// no decompressor -> we can't decompress.
		printk(KERN_DEBUG "ippp: no decompressor defined!\n");
		return skb;
	}
	BUG_ON(!stat); // if we have a compressor, stat has been set as well

	if ((master && *proto == PPP_COMP) || (!master && *proto == PPP_COMPFRAG)) {
		// compressed packets are compressed by their protocol type

		// Set up reset params for the decompressor
		memset(&rsparm, 0, sizeof(rsparm));
		rsparm.data = rsdata;
		rsparm.maxdlen = IPPP_RESET_MAXDATABYTES;

		skb_out = dev_alloc_skb(is->mru + PPP_HDRLEN);
		if (!skb_out) {
			kfree_skb(skb);
			printk(KERN_ERR "ippp: decomp memory allocation failure\n");
			return NULL;
		}
		len = ipc->decompress(stat, skb, skb_out, &rsparm);
		kfree_skb(skb);
		if (len <= 0) {
			switch (len) {
			case DECOMP_ERROR:
				printk(KERN_INFO "ippp: decomp wants reset %s params\n",
				       rsparm.valid ? "with" : "without");

				isdn_ppp_ccp_reset_trans(ri, &rsparm);
				break;
			case DECOMP_FATALERROR:
				ri->pppcfg |= SC_DC_FERROR;
				/* Kick ipppd to recognize the error */
				isdn_ppp_ccp_kickup(ri);
				break;
			}
			kfree_skb(skb_out);
			return NULL;
		}
		*proto = isdn_ppp_strip_proto(skb_out);
		if (*proto < 0) {
			kfree_skb(skb_out);
			return NULL;
		}
		return skb_out;
	} else {
		// uncompressed packets are fed through the decompressor to
		// update the decompressor state
		ipc->incomp(stat, skb, *proto);
		return skb;
	}
}

Project: linux
File: isdn_ppp.c

isdn_ppp_dev_ioctl_stats(int slot, struct ifreq *ifr, struct net_device *dev)
{
	struct ppp_stats __user *res = ifr->ifr_data;
	struct ppp_stats t;
	isdn_net_local *lp = netdev_priv(dev);

	if (!access_ok(VERIFY_WRITE, res, sizeof(struct ppp_stats)))
		return -EFAULT;

	/* build a temporary stat struct and copy it to user space */

	memset(&t, 0, sizeof(struct ppp_stats));
	if (dev->flags & IFF_UP) {
		t.p.ppp_ipackets = lp->stats.rx_packets;
		t.p.ppp_ibytes = lp->stats.rx_bytes;
		t.p.ppp_ierrors = lp->stats.rx_errors;
		t.p.ppp_opackets = lp->stats.tx_packets;
		t.p.ppp_obytes = lp->stats.tx_bytes;
		t.p.ppp_oerrors = lp->stats.tx_errors;
#ifdef CONFIG_ISDN_PPP_VJ
		if (slot >= 0 && ippp_table[slot]->slcomp) {
			struct slcompress *slcomp = ippp_table[slot]->slcomp;
			t.vj.vjs_packets = slcomp->sls_o_compressed + slcomp->sls_o_uncompressed;
			t.vj.vjs_compressed = slcomp->sls_o_compressed;
			t.vj.vjs_searches = slcomp->sls_o_searches;
			t.vj.vjs_misses = slcomp->sls_o_misses;
			t.vj.vjs_errorin = slcomp->sls_i_error;
			t.vj.vjs_tossed = slcomp->sls_i_tossed;
			t.vj.vjs_uncompressedin = slcomp->sls_i_uncompressed;
			t.vj.vjs_compressedin = slcomp->sls_i_compressed;
		}
#endif
	}
	if (copy_to_user(res, &t, sizeof(struct ppp_stats)))
		return -EFAULT;
	return 0;
}

Project: linux
File: isdn_ppp.c

static void isdn_ppp_ccp_reset_free(struct ippp_struct *is)
{
	unsigned int id;

	printk(KERN_DEBUG "ippp_ccp: freeing reset data structure %p\n",
	       is->reset);
	for (id = 0; id < 256; id++) {
		if (is->reset->rs[id]) {
			isdn_ppp_ccp_reset_free_state(is, (unsigned char)id);
		}
	}
	kfree(is->reset);
	is->reset = NULL;
}

Project: linux
File: ppp_generic.c

static void ppp_setup(struct net_device *dev)
{
	dev->netdev_ops = &ppp_netdev_ops;
	dev->hard_header_len = PPP_HDRLEN;
	dev->mtu = PPP_MRU;
	dev->addr_len = 0;
	dev->tx_queue_len = 3;
	dev->type = ARPHRD_PPP;
	dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
	netif_keep_dst(dev);
}

Project: linux
File: slhc.c

slhc_remember(struct slcompress *comp, unsigned char *icp, int isize)
{
	register struct cstate *cs;
	unsigned ihl;

	unsigned char index;

	if(isize < 20) {
		/* The packet is shorter than a legal IP header */
		comp->sls_i_runt++;
		return slhc_toss( comp );
	}
	/* Peek at the IP header's IHL field to find its length */
	ihl = icp[0] & 0xf;
	if(ihl < 20 / 4){
		/* The IP header length field is too small */
		comp->sls_i_runt++;
		return slhc_toss( comp );
	}
	index = icp[9];
	icp[9] = IPPROTO_TCP;

	if (ip_fast_csum(icp, ihl)) {
		/* Bad IP header checksum; discard */
		comp->sls_i_badcheck++;
		return slhc_toss( comp );
	}
	if(index > comp->rslot_limit) {
		comp->sls_i_error++;
		return slhc_toss(comp);
	}

	/* Update local state */
	cs = &comp->rstate[comp->recv_current = index];
	comp->flags &=~ SLF_TOSS;
	memcpy(&cs->cs_ip,icp,20);
	memcpy(&cs->cs_tcp,icp + ihl*4,20);
	if (ihl > 5)
	  memcpy(cs->cs_ipopt, icp + sizeof(struct iphdr), (ihl - 5) * 4);
	if (cs->cs_tcp.doff > 5)
	  memcpy(cs->cs_tcpopt, icp + ihl*4 + sizeof(struct tcphdr), (cs->cs_tcp.doff - 5) * 4);
	cs->cs_hsize = ihl*2 + cs->cs_tcp.doff*2;
	/* Put headers back on packet
	 * Neither header checksum is recalculated
	 */
	comp->sls_i_uncompressed++;
	return isize;
}

Project: linux
File: ppp_generic.c

static unsigned int ppp_poll(struct file *file, poll_table *wait)
{
	struct ppp_file *pf = file->private_data;
	unsigned int mask;

	if (!pf)
		return 0;
	poll_wait(file, &pf->rwait, wait);
	mask = POLLOUT | POLLWRNORM;
	if (skb_peek(&pf->rq))
		mask |= POLLIN | POLLRDNORM;
	if (pf->dead)
		mask |= POLLHUP;
	else if (pf->kind == INTERFACE) {
		/* see comment in ppp_read */
		struct ppp *ppp = PF_TO_PPP(pf);
		if (ppp->n_channels == 0 &&
		    (ppp->flags & SC_LOOP_TRAFFIC) == 0)
			mask |= POLLIN | POLLRDNORM;
	}

	return mask;
}

Project: linux
File: isdn_ppp.c

static void isdn_ppp_ccp_reset_trans(struct ippp_struct *is,
				     struct isdn_ppp_resetparams *rp)
{
	struct ippp_ccp_reset_state *rs;

	if (rp->valid) {
		/* The decompressor defines parameters by itself */
		if (rp->rsend) {
			/* And he wants us to send a request */
			if (!(rp->idval)) {
				printk(KERN_ERR "ippp_ccp: decompressor must"
				       " specify reset id\n");
				return;
			}
			if (is->reset->rs[rp->id]) {
				/* There is already a transaction in existence
				   for this id. May be still waiting for a
				   Ack or may be wrong. */
				rs = is->reset->rs[rp->id];
				if (rs->state == CCPResetSentReq && rs->ta) {
					printk(KERN_DEBUG "ippp_ccp: reset"
					       " trans still in progress"
					       " for id %d\n", rp->id);
				} else {
					printk(KERN_WARNING "ippp_ccp: reset"
					       " trans in wrong state %d for"
					       " id %d\n", rs->state, rp->id);
				}
			} else {
				/* Ok, this is a new transaction */
				printk(KERN_DEBUG "ippp_ccp: new trans for id"
				       " %d to be started\n", rp->id);
				rs = isdn_ppp_ccp_reset_alloc_state(is, rp->id);
				if (!rs) {
					printk(KERN_ERR "ippp_ccp: out of mem"
					       " allocing ccp trans\n");
					return;
				}
				rs->state = CCPResetSentReq;
				rs->expra = rp->expra;
				if (rp->dtval) {
					rs->dlen = rp->dlen;
					memcpy(rs->data, rp->data, rp->dlen);
				}
				/* HACK TODO - add link comp here */
				isdn_ppp_ccp_xmit_reset(is, PPP_CCP,
							CCP_RESETREQ, rs->id,
							rs->data, rs->dlen);
				/* Start the timer */
				rs->timer.expires = jiffies + 5 * HZ;
				add_timer(&rs->timer);
				rs->ta = 1;
			}
		} else {
			printk(KERN_DEBUG "ippp_ccp: no reset sent\n");
		}
	} else {
		/* The reset params are invalid. The decompressor does not
		   care about them, so we just send the minimal requests
		   and increase ids only when an Ack is received for a
		   given id */
		if (is->reset->rs[is->reset->lastid]) {
			/* There is already a transaction in existence
			   for this id. May be still waiting for a
			   Ack or may be wrong. */
			rs = is->reset->rs[is->reset->lastid];
			if (rs->state == CCPResetSentReq && rs->ta) {
				printk(KERN_DEBUG "ippp_ccp: reset"
				       " trans still in progress"
				       " for id %d\n", rp->id);
			} else {
				printk(KERN_WARNING "ippp_ccp: reset"
				       " trans in wrong state %d for"
				       " id %d\n", rs->state, rp->id);
			}
		} else {
			printk(KERN_DEBUG "ippp_ccp: new trans for id"
			       " %d to be started\n", is->reset->lastid);
			rs = isdn_ppp_ccp_reset_alloc_state(is,
							    is->reset->lastid);
			if (!rs) {
				printk(KERN_ERR "ippp_ccp: out of mem"
				       " allocing ccp trans\n");
				return;
			}
			rs->state = CCPResetSentReq;
			/* We always expect an Ack if the decompressor doesn't
			   know	better */
			rs->expra = 1;
			rs->dlen = 0;
			/* HACK TODO - add link comp here */
			isdn_ppp_ccp_xmit_reset(is, PPP_CCP, CCP_RESETREQ,
						rs->id, NULL, 0);
			/* Start the timer */
			rs->timer.expires = jiffies + 5 * HZ;
			add_timer(&rs->timer);
			rs->ta = 1;
		}
	}
}