blob: 62f0688d45a500530fd65014432be9fbfd5a7d69 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/* $Id: isdn_ppp.c,v 1.1.2.3 2004/02/10 01:07:13 keil Exp $
2 *
3 * Linux ISDN subsystem, functions for synchronous PPP (linklevel).
4 *
5 * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
6 *
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
9 *
10 */
11
Linus Torvalds1da177e2005-04-16 15:20:36 -070012#include <linux/isdn.h>
13#include <linux/poll.h>
14#include <linux/ppp-comp.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090015#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070016#ifdef CONFIG_IPPP_FILTER
17#include <linux/filter.h>
18#endif
19
20#include "isdn_common.h"
21#include "isdn_ppp.h"
22#include "isdn_net.h"
23
24#ifndef PPP_IPX
25#define PPP_IPX 0x002b
26#endif
27
28/* Prototypes */
29static int isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot);
30static int isdn_ppp_closewait(int slot);
Joe Perches475be4d2012-02-19 19:52:38 -080031static void isdn_ppp_push_higher(isdn_net_dev *net_dev, isdn_net_local *lp,
Linus Torvalds1da177e2005-04-16 15:20:36 -070032 struct sk_buff *skb, int proto);
33static int isdn_ppp_if_get_unit(char *namebuf);
Joe Perches475be4d2012-02-19 19:52:38 -080034static int isdn_ppp_set_compressor(struct ippp_struct *is, struct isdn_ppp_comp_data *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070035static struct sk_buff *isdn_ppp_decompress(struct sk_buff *,
Joe Perches475be4d2012-02-19 19:52:38 -080036 struct ippp_struct *, struct ippp_struct *, int *proto);
37static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp,
38 struct sk_buff *skb, int proto);
39static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in, int *proto,
40 struct ippp_struct *is, struct ippp_struct *master, int type);
Linus Torvalds1da177e2005-04-16 15:20:36 -070041static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp,
Joe Perches475be4d2012-02-19 19:52:38 -080042 struct sk_buff *skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -070043
44/* New CCP stuff */
45static void isdn_ppp_ccp_kickup(struct ippp_struct *is);
46static void isdn_ppp_ccp_xmit_reset(struct ippp_struct *is, int proto,
47 unsigned char code, unsigned char id,
48 unsigned char *data, int len);
49static struct ippp_ccp_reset *isdn_ppp_ccp_reset_alloc(struct ippp_struct *is);
50static void isdn_ppp_ccp_reset_free(struct ippp_struct *is);
51static void isdn_ppp_ccp_reset_free_state(struct ippp_struct *is,
52 unsigned char id);
53static void isdn_ppp_ccp_timer_callback(unsigned long closure);
54static struct ippp_ccp_reset_state *isdn_ppp_ccp_reset_alloc_state(struct ippp_struct *is,
Joe Perches475be4d2012-02-19 19:52:38 -080055 unsigned char id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070056static void isdn_ppp_ccp_reset_trans(struct ippp_struct *is,
57 struct isdn_ppp_resetparams *rp);
58static void isdn_ppp_ccp_reset_ack_rcvd(struct ippp_struct *is,
59 unsigned char id);
60
61
62
63#ifdef CONFIG_ISDN_MPP
Joe Perches475be4d2012-02-19 19:52:38 -080064static ippp_bundle *isdn_ppp_bundle_arr = NULL;
65
Linus Torvalds1da177e2005-04-16 15:20:36 -070066static int isdn_ppp_mp_bundle_array_init(void);
Joe Perches475be4d2012-02-19 19:52:38 -080067static int isdn_ppp_mp_init(isdn_net_local *lp, ippp_bundle *add_to);
68static void isdn_ppp_mp_receive(isdn_net_dev *net_dev, isdn_net_local *lp,
69 struct sk_buff *skb);
70static void isdn_ppp_mp_cleanup(isdn_net_local *lp);
Linus Torvalds1da177e2005-04-16 15:20:36 -070071
72static int isdn_ppp_bundle(struct ippp_struct *, int unit);
73#endif /* CONFIG_ISDN_MPP */
Joe Perches475be4d2012-02-19 19:52:38 -080074
Linus Torvalds1da177e2005-04-16 15:20:36 -070075char *isdn_ppp_revision = "$Revision: 1.1.2.3 $";
76
77static struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS];
78
79static struct isdn_ppp_compressor *ipc_head = NULL;
80
81/*
82 * frame log (debug)
83 */
84static void
Joe Perches475be4d2012-02-19 19:52:38 -080085isdn_ppp_frame_log(char *info, char *data, int len, int maxlen, int unit, int slot)
Linus Torvalds1da177e2005-04-16 15:20:36 -070086{
87 int cnt,
Joe Perches475be4d2012-02-19 19:52:38 -080088 j,
89 i;
Linus Torvalds1da177e2005-04-16 15:20:36 -070090 char buf[80];
91
92 if (len < maxlen)
93 maxlen = len;
94
95 for (i = 0, cnt = 0; cnt < maxlen; i++) {
96 for (j = 0; j < 16 && cnt < maxlen; j++, cnt++)
Joe Perches475be4d2012-02-19 19:52:38 -080097 sprintf(buf + j * 3, "%02x ", (unsigned char)data[cnt]);
98 printk(KERN_DEBUG "[%d/%d].%s[%d]: %s\n", unit, slot, info, i, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -070099 }
100}
101
102/*
103 * unbind isdn_net_local <=> ippp-device
104 * note: it can happen, that we hangup/free the master before the slaves
105 * in this case we bind another lp to the master device
106 */
107int
Joe Perches475be4d2012-02-19 19:52:38 -0800108isdn_ppp_free(isdn_net_local *lp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109{
110 struct ippp_struct *is;
111
Eric Sesterhenn052bb882006-04-11 17:29:17 -0700112 if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113 printk(KERN_ERR "%s: ppp_slot(%d) out of range\n",
Joe Perches475be4d2012-02-19 19:52:38 -0800114 __func__, lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115 return 0;
116 }
117
118#ifdef CONFIG_ISDN_MPP
119 spin_lock(&lp->netdev->pb->lock);
120#endif
121 isdn_net_rm_from_bundle(lp);
122#ifdef CONFIG_ISDN_MPP
123 if (lp->netdev->pb->ref_ct == 1) /* last link in queue? */
124 isdn_ppp_mp_cleanup(lp);
125
126 lp->netdev->pb->ref_ct--;
127 spin_unlock(&lp->netdev->pb->lock);
128#endif /* CONFIG_ISDN_MPP */
Eric Sesterhenn052bb882006-04-11 17:29:17 -0700129 if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130 printk(KERN_ERR "%s: ppp_slot(%d) now invalid\n",
Joe Perches475be4d2012-02-19 19:52:38 -0800131 __func__, lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132 return 0;
133 }
134 is = ippp_table[lp->ppp_slot];
135 if ((is->state & IPPP_CONNECT))
136 isdn_ppp_closewait(lp->ppp_slot); /* force wakeup on ippp device */
137 else if (is->state & IPPP_ASSIGNED)
138 is->state = IPPP_OPEN; /* fallback to 'OPEN but not ASSIGNED' state */
139
140 if (is->debug & 0x1)
141 printk(KERN_DEBUG "isdn_ppp_free %d %lx %lx\n", lp->ppp_slot, (long) lp, (long) is->lp);
142
143 is->lp = NULL; /* link is down .. set lp to NULL */
144 lp->ppp_slot = -1; /* is this OK ?? */
145
146 return 0;
147}
148
149/*
150 * bind isdn_net_local <=> ippp-device
151 *
152 * This function is allways called with holding dev->lock so
153 * no additional lock is needed
154 */
155int
Joe Perches475be4d2012-02-19 19:52:38 -0800156isdn_ppp_bind(isdn_net_local *lp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157{
158 int i;
159 int unit = 0;
160 struct ippp_struct *is;
161 int retval;
162
163 if (lp->pppbind < 0) { /* device bounded to ippp device ? */
164 isdn_net_dev *net_dev = dev->netdev;
165 char exclusive[ISDN_MAX_CHANNELS]; /* exclusive flags */
166 memset(exclusive, 0, ISDN_MAX_CHANNELS);
167 while (net_dev) { /* step through net devices to find exclusive minors */
168 isdn_net_local *lp = net_dev->local;
169 if (lp->pppbind >= 0)
170 exclusive[lp->pppbind] = 1;
171 net_dev = net_dev->next;
172 }
173 /*
174 * search a free device / slot
175 */
176 for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
177 if (ippp_table[i]->state == IPPP_OPEN && !exclusive[ippp_table[i]->minor]) { /* OPEN, but not connected! */
178 break;
179 }
180 }
181 } else {
182 for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
183 if (ippp_table[i]->minor == lp->pppbind &&
184 (ippp_table[i]->state & IPPP_OPEN) == IPPP_OPEN)
185 break;
186 }
187 }
188
189 if (i >= ISDN_MAX_CHANNELS) {
190 printk(KERN_WARNING "isdn_ppp_bind: Can't find a (free) connection to the ipppd daemon.\n");
191 retval = -1;
192 goto out;
193 }
Karsten Keilfaca94f2007-10-15 02:11:44 -0700194 /* get unit number from interface name .. ugly! */
195 unit = isdn_ppp_if_get_unit(lp->netdev->dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196 if (unit < 0) {
Karsten Keilfaca94f2007-10-15 02:11:44 -0700197 printk(KERN_ERR "isdn_ppp_bind: illegal interface name %s.\n",
Joe Perches475be4d2012-02-19 19:52:38 -0800198 lp->netdev->dev->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199 retval = -1;
200 goto out;
201 }
Joe Perches475be4d2012-02-19 19:52:38 -0800202
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 lp->ppp_slot = i;
204 is = ippp_table[i];
205 is->lp = lp;
206 is->unit = unit;
207 is->state = IPPP_OPEN | IPPP_ASSIGNED; /* assigned to a netdevice but not connected */
208#ifdef CONFIG_ISDN_MPP
209 retval = isdn_ppp_mp_init(lp, NULL);
210 if (retval < 0)
211 goto out;
212#endif /* CONFIG_ISDN_MPP */
213
214 retval = lp->ppp_slot;
215
Joe Perches475be4d2012-02-19 19:52:38 -0800216out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 return retval;
218}
219
220/*
221 * kick the ipppd on the device
222 * (wakes up daemon after B-channel connect)
223 */
224
225void
Joe Perches475be4d2012-02-19 19:52:38 -0800226isdn_ppp_wakeup_daemon(isdn_net_local *lp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227{
228 if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
229 printk(KERN_ERR "%s: ppp_slot(%d) out of range\n",
Joe Perches475be4d2012-02-19 19:52:38 -0800230 __func__, lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 return;
232 }
233 ippp_table[lp->ppp_slot]->state = IPPP_OPEN | IPPP_CONNECT | IPPP_NOBLOCK;
234 wake_up_interruptible(&ippp_table[lp->ppp_slot]->wq);
235}
236
237/*
238 * there was a hangup on the netdevice
239 * force wakeup of the ippp device
240 * go into 'device waits for release' state
241 */
242static int
243isdn_ppp_closewait(int slot)
244{
245 struct ippp_struct *is;
246
247 if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
248 printk(KERN_ERR "%s: slot(%d) out of range\n",
Joe Perches475be4d2012-02-19 19:52:38 -0800249 __func__, slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 return 0;
251 }
252 is = ippp_table[slot];
253 if (is->state)
254 wake_up_interruptible(&is->wq);
255 is->state = IPPP_CLOSEWAIT;
256 return 1;
257}
258
259/*
260 * isdn_ppp_find_slot / isdn_ppp_free_slot
261 */
262
263static int
264isdn_ppp_get_slot(void)
265{
266 int i;
267 for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
268 if (!ippp_table[i]->state)
269 return i;
270 }
271 return -1;
272}
273
274/*
275 * isdn_ppp_open
276 */
277
278int
279isdn_ppp_open(int min, struct file *file)
280{
281 int slot;
282 struct ippp_struct *is;
283
Eric Sesterhenn052bb882006-04-11 17:29:17 -0700284 if (min < 0 || min >= ISDN_MAX_CHANNELS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 return -ENODEV;
286
287 slot = isdn_ppp_get_slot();
288 if (slot < 0) {
289 return -EBUSY;
290 }
291 is = file->private_data = ippp_table[slot];
Joe Perches475be4d2012-02-19 19:52:38 -0800292
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 printk(KERN_DEBUG "ippp, open, slot: %d, minor: %d, state: %04x\n",
294 slot, min, is->state);
295
296 /* compression stuff */
297 is->link_compressor = is->compressor = NULL;
298 is->link_decompressor = is->decompressor = NULL;
299 is->link_comp_stat = is->comp_stat = NULL;
300 is->link_decomp_stat = is->decomp_stat = NULL;
301 is->compflags = 0;
302
303 is->reset = isdn_ppp_ccp_reset_alloc(is);
304
305 is->lp = NULL;
306 is->mp_seqno = 0; /* MP sequence number */
307 is->pppcfg = 0; /* ppp configuration */
308 is->mpppcfg = 0; /* mppp configuration */
309 is->last_link_seqno = -1; /* MP: maybe set to Bundle-MIN, when joining a bundle ?? */
310 is->unit = -1; /* set, when we have our interface */
311 is->mru = 1524; /* MRU, default 1524 */
312 is->maxcid = 16; /* VJ: maxcid */
313 is->tk = current;
314 init_waitqueue_head(&is->wq);
315 is->first = is->rq + NUM_RCV_BUFFS - 1; /* receive queue */
316 is->last = is->rq;
317 is->minor = min;
318#ifdef CONFIG_ISDN_PPP_VJ
319 /*
320 * VJ header compression init
321 */
322 is->slcomp = slhc_init(16, 16); /* not necessary for 2. link in bundle */
323#endif
324#ifdef CONFIG_IPPP_FILTER
325 is->pass_filter = NULL;
326 is->active_filter = NULL;
327#endif
328 is->state = IPPP_OPEN;
329
330 return 0;
331}
332
333/*
334 * release ippp device
335 */
336void
337isdn_ppp_release(int min, struct file *file)
338{
339 int i;
340 struct ippp_struct *is;
341
342 if (min < 0 || min >= ISDN_MAX_CHANNELS)
343 return;
344 is = file->private_data;
345
346 if (!is) {
Harvey Harrison156f1ed2008-04-28 02:14:40 -0700347 printk(KERN_ERR "%s: no file->private_data\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 return;
349 }
350 if (is->debug & 0x1)
351 printk(KERN_DEBUG "ippp: release, minor: %d %lx\n", min, (long) is->lp);
352
353 if (is->lp) { /* a lp address says: this link is still up */
354 isdn_net_dev *p = is->lp->netdev;
355
356 if (!p) {
Harvey Harrison156f1ed2008-04-28 02:14:40 -0700357 printk(KERN_ERR "%s: no lp->netdev\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 return;
359 }
360 is->state &= ~IPPP_CONNECT; /* -> effect: no call of wakeup */
361 /*
362 * isdn_net_hangup() calls isdn_ppp_free()
363 * isdn_ppp_free() sets is->lp to NULL and lp->ppp_slot to -1
364 * removing the IPPP_CONNECT flag omits calling of isdn_ppp_wakeup_daemon()
365 */
Karsten Keild62a38d2007-10-08 20:37:11 -0700366 isdn_net_hangup(p->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 }
368 for (i = 0; i < NUM_RCV_BUFFS; i++) {
Jesper Juhl3c7208f2005-11-07 01:01:29 -0800369 kfree(is->rq[i].buf);
370 is->rq[i].buf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 }
372 is->first = is->rq + NUM_RCV_BUFFS - 1; /* receive queue */
373 is->last = is->rq;
374
375#ifdef CONFIG_ISDN_PPP_VJ
376/* TODO: if this was the previous master: link the slcomp to the new master */
377 slhc_free(is->slcomp);
378 is->slcomp = NULL;
379#endif
380#ifdef CONFIG_IPPP_FILTER
Daniel Borkmann77e01142014-03-28 18:58:24 +0100381 if (is->pass_filter) {
382 sk_unattached_filter_destroy(is->pass_filter);
383 is->pass_filter = NULL;
384 }
385
386 if (is->active_filter) {
387 sk_unattached_filter_destroy(is->active_filter);
388 is->active_filter = NULL;
389 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390#endif
391
392/* TODO: if this was the previous master: link the stuff to the new master */
Joe Perches475be4d2012-02-19 19:52:38 -0800393 if (is->comp_stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 is->compressor->free(is->comp_stat);
Joe Perches475be4d2012-02-19 19:52:38 -0800395 if (is->link_comp_stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 is->link_compressor->free(is->link_comp_stat);
Joe Perches475be4d2012-02-19 19:52:38 -0800397 if (is->link_decomp_stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 is->link_decompressor->free(is->link_decomp_stat);
Joe Perches475be4d2012-02-19 19:52:38 -0800399 if (is->decomp_stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 is->decompressor->free(is->decomp_stat);
Joe Perches475be4d2012-02-19 19:52:38 -0800401 is->compressor = is->link_compressor = NULL;
402 is->decompressor = is->link_decompressor = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 is->comp_stat = is->link_comp_stat = NULL;
Joe Perches475be4d2012-02-19 19:52:38 -0800404 is->decomp_stat = is->link_decomp_stat = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405
406 /* Clean up if necessary */
Joe Perches475be4d2012-02-19 19:52:38 -0800407 if (is->reset)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 isdn_ppp_ccp_reset_free(is);
409
410 /* this slot is ready for new connections */
411 is->state = 0;
412}
413
414/*
415 * get_arg .. ioctl helper
416 */
417static int
418get_arg(void __user *b, void *val, int len)
419{
420 if (len <= 0)
421 len = sizeof(void *);
422 if (copy_from_user(val, b, len))
423 return -EFAULT;
424 return 0;
425}
426
427/*
428 * set arg .. ioctl helper
429 */
430static int
Joe Perches475be4d2012-02-19 19:52:38 -0800431set_arg(void __user *b, void *val, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432{
Joe Perches475be4d2012-02-19 19:52:38 -0800433 if (len <= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 len = sizeof(void *);
435 if (copy_to_user(b, val, len))
436 return -EFAULT;
437 return 0;
438}
439
Daniele Venzano26285ba2009-01-26 12:24:38 -0800440#ifdef CONFIG_IPPP_FILTER
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441static int get_filter(void __user *arg, struct sock_filter **p)
442{
443 struct sock_fprog uprog;
444 struct sock_filter *code = NULL;
Christoph Schulz3916a312014-07-14 08:01:10 +0200445 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446
447 if (copy_from_user(&uprog, arg, sizeof(uprog)))
448 return -EFAULT;
449
450 if (!uprog.len) {
451 *p = NULL;
452 return 0;
453 }
454
455 /* uprog.len is unsigned short, so no overflow here */
456 len = uprog.len * sizeof(struct sock_filter);
Julia Lawall024cb8a2010-05-21 22:26:42 +0000457 code = memdup_user(uprog.filter, len);
458 if (IS_ERR(code))
459 return PTR_ERR(code);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 *p = code;
462 return uprog.len;
463}
Daniele Venzano26285ba2009-01-26 12:24:38 -0800464#endif /* CONFIG_IPPP_FILTER */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465
466/*
467 * ippp device ioctl
468 */
469int
470isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
471{
472 unsigned long val;
Joe Perches475be4d2012-02-19 19:52:38 -0800473 int r, i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 struct ippp_struct *is;
475 isdn_net_local *lp;
476 struct isdn_ppp_comp_data data;
477 void __user *argp = (void __user *)arg;
478
Joe Perches54cbb1c2010-07-12 10:50:02 +0000479 is = file->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 lp = is->lp;
481
482 if (is->debug & 0x1)
483 printk(KERN_DEBUG "isdn_ppp_ioctl: minor: %d cmd: %x state: %x\n", min, cmd, is->state);
484
485 if (!(is->state & IPPP_OPEN))
486 return -EINVAL;
487
488 switch (cmd) {
Joe Perches475be4d2012-02-19 19:52:38 -0800489 case PPPIOCBUNDLE:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490#ifdef CONFIG_ISDN_MPP
Joe Perches475be4d2012-02-19 19:52:38 -0800491 if (!(is->state & IPPP_CONNECT))
492 return -EINVAL;
493 if ((r = get_arg(argp, &val, sizeof(val))))
494 return r;
495 printk(KERN_DEBUG "iPPP-bundle: minor: %d, slave unit: %d, master unit: %d\n",
496 (int) min, (int) is->unit, (int) val);
497 return isdn_ppp_bundle(is, val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498#else
Joe Perches475be4d2012-02-19 19:52:38 -0800499 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500#endif
Joe Perches475be4d2012-02-19 19:52:38 -0800501 break;
502 case PPPIOCGUNIT: /* get ppp/isdn unit number */
503 if ((r = set_arg(argp, &is->unit, sizeof(is->unit))))
504 return r;
505 break;
506 case PPPIOCGIFNAME:
507 if (!lp)
508 return -EINVAL;
509 if ((r = set_arg(argp, lp->netdev->dev->name,
510 strlen(lp->netdev->dev->name))))
511 return r;
512 break;
513 case PPPIOCGMPFLAGS: /* get configuration flags */
514 if ((r = set_arg(argp, &is->mpppcfg, sizeof(is->mpppcfg))))
515 return r;
516 break;
517 case PPPIOCSMPFLAGS: /* set configuration flags */
518 if ((r = get_arg(argp, &val, sizeof(val))))
519 return r;
520 is->mpppcfg = val;
521 break;
522 case PPPIOCGFLAGS: /* get configuration flags */
523 if ((r = set_arg(argp, &is->pppcfg, sizeof(is->pppcfg))))
524 return r;
525 break;
526 case PPPIOCSFLAGS: /* set configuration flags */
527 if ((r = get_arg(argp, &val, sizeof(val)))) {
528 return r;
529 }
530 if (val & SC_ENABLE_IP && !(is->pppcfg & SC_ENABLE_IP) && (is->state & IPPP_CONNECT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 if (lp) {
Joe Perches475be4d2012-02-19 19:52:38 -0800532 /* OK .. we are ready to send buffers */
533 is->pppcfg = val; /* isdn_ppp_xmit test for SC_ENABLE_IP !!! */
534 netif_wake_queue(lp->netdev->dev);
535 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 }
Joe Perches475be4d2012-02-19 19:52:38 -0800537 }
538 is->pppcfg = val;
539 break;
540 case PPPIOCGIDLE: /* get idle time information */
541 if (lp) {
542 struct ppp_idle pidle;
543 pidle.xmit_idle = pidle.recv_idle = lp->huptimer;
544 if ((r = set_arg(argp, &pidle, sizeof(struct ppp_idle))))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 return r;
Joe Perches475be4d2012-02-19 19:52:38 -0800546 }
547 break;
548 case PPPIOCSMRU: /* set receive unit size for PPP */
549 if ((r = get_arg(argp, &val, sizeof(val))))
550 return r;
551 is->mru = val;
552 break;
553 case PPPIOCSMPMRU:
554 break;
555 case PPPIOCSMPMTU:
556 break;
557 case PPPIOCSMAXCID: /* set the maximum compression slot id */
558 if ((r = get_arg(argp, &val, sizeof(val))))
559 return r;
560 val++;
561 if (is->maxcid != val) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562#ifdef CONFIG_ISDN_PPP_VJ
Joe Perches475be4d2012-02-19 19:52:38 -0800563 struct slcompress *sltmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564#endif
Joe Perches475be4d2012-02-19 19:52:38 -0800565 if (is->debug & 0x1)
566 printk(KERN_DEBUG "ippp, ioctl: changed MAXCID to %ld\n", val);
567 is->maxcid = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568#ifdef CONFIG_ISDN_PPP_VJ
Joe Perches475be4d2012-02-19 19:52:38 -0800569 sltmp = slhc_init(16, val);
570 if (!sltmp) {
571 printk(KERN_ERR "ippp, can't realloc slhc struct\n");
572 return -ENOMEM;
573 }
574 if (is->slcomp)
575 slhc_free(is->slcomp);
576 is->slcomp = sltmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577#endif
Joe Perches475be4d2012-02-19 19:52:38 -0800578 }
579 break;
580 case PPPIOCGDEBUG:
581 if ((r = set_arg(argp, &is->debug, sizeof(is->debug))))
582 return r;
583 break;
584 case PPPIOCSDEBUG:
585 if ((r = get_arg(argp, &val, sizeof(val))))
586 return r;
587 is->debug = val;
588 break;
589 case PPPIOCGCOMPRESSORS:
590 {
591 unsigned long protos[8] = {0,};
592 struct isdn_ppp_compressor *ipc = ipc_head;
593 while (ipc) {
594 j = ipc->num / (sizeof(long) * 8);
595 i = ipc->num % (sizeof(long) * 8);
596 if (j < 8)
Dan Carpenter435f08a2012-10-09 23:42:18 +0000597 protos[j] |= (1UL << i);
Joe Perches475be4d2012-02-19 19:52:38 -0800598 ipc = ipc->next;
599 }
600 if ((r = set_arg(argp, protos, 8 * sizeof(long))))
601 return r;
602 }
603 break;
604 case PPPIOCSCOMPRESSOR:
605 if ((r = get_arg(argp, &data, sizeof(struct isdn_ppp_comp_data))))
606 return r;
607 return isdn_ppp_set_compressor(is, &data);
608 case PPPIOCGCALLINFO:
609 {
610 struct pppcallinfo pci;
611 memset((char *)&pci, 0, sizeof(struct pppcallinfo));
612 if (lp)
613 {
614 strncpy(pci.local_num, lp->msn, 63);
615 if (lp->dial) {
616 strncpy(pci.remote_num, lp->dial->num, 63);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 }
Joe Perches475be4d2012-02-19 19:52:38 -0800618 pci.charge_units = lp->charge;
619 if (lp->outgoing)
620 pci.calltype = CALLTYPE_OUTGOING;
621 else
622 pci.calltype = CALLTYPE_INCOMING;
623 if (lp->flags & ISDN_NET_CALLBACK)
624 pci.calltype |= CALLTYPE_CALLBACK;
625 }
626 return set_arg(argp, &pci, sizeof(struct pppcallinfo));
627 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628#ifdef CONFIG_IPPP_FILTER
Joe Perches475be4d2012-02-19 19:52:38 -0800629 case PPPIOCSPASS:
630 {
Daniel Borkmannb1fcd352014-05-23 18:43:58 +0200631 struct sock_fprog_kern fprog;
Joe Perches475be4d2012-02-19 19:52:38 -0800632 struct sock_filter *code;
Daniel Borkmann77e01142014-03-28 18:58:24 +0100633 int err, len = get_filter(argp, &code);
634
Joe Perches475be4d2012-02-19 19:52:38 -0800635 if (len < 0)
636 return len;
Daniel Borkmann77e01142014-03-28 18:58:24 +0100637
638 fprog.len = len;
639 fprog.filter = code;
640
Christoph Schulzcc25eaa2014-07-16 22:10:29 +0200641 if (is->pass_filter) {
Daniel Borkmann77e01142014-03-28 18:58:24 +0100642 sk_unattached_filter_destroy(is->pass_filter);
Christoph Schulzcc25eaa2014-07-16 22:10:29 +0200643 is->pass_filter = NULL;
644 }
645 if (fprog.filter != NULL)
646 err = sk_unattached_filter_create(&is->pass_filter,
647 &fprog);
648 else
649 err = 0;
Daniel Borkmann77e01142014-03-28 18:58:24 +0100650 kfree(code);
651
652 return err;
Joe Perches475be4d2012-02-19 19:52:38 -0800653 }
654 case PPPIOCSACTIVE:
655 {
Daniel Borkmannb1fcd352014-05-23 18:43:58 +0200656 struct sock_fprog_kern fprog;
Joe Perches475be4d2012-02-19 19:52:38 -0800657 struct sock_filter *code;
Daniel Borkmann77e01142014-03-28 18:58:24 +0100658 int err, len = get_filter(argp, &code);
659
Joe Perches475be4d2012-02-19 19:52:38 -0800660 if (len < 0)
661 return len;
Daniel Borkmann77e01142014-03-28 18:58:24 +0100662
663 fprog.len = len;
664 fprog.filter = code;
665
Christoph Schulzcc25eaa2014-07-16 22:10:29 +0200666 if (is->active_filter) {
Daniel Borkmann77e01142014-03-28 18:58:24 +0100667 sk_unattached_filter_destroy(is->active_filter);
Christoph Schulzcc25eaa2014-07-16 22:10:29 +0200668 is->active_filter = NULL;
669 }
670 if (fprog.filter != NULL)
671 err = sk_unattached_filter_create(&is->active_filter,
672 &fprog);
673 else
674 err = 0;
Daniel Borkmann77e01142014-03-28 18:58:24 +0100675 kfree(code);
676
677 return err;
Joe Perches475be4d2012-02-19 19:52:38 -0800678 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679#endif /* CONFIG_IPPP_FILTER */
Joe Perches475be4d2012-02-19 19:52:38 -0800680 default:
681 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 }
683 return 0;
684}
685
686unsigned int
Joe Perches475be4d2012-02-19 19:52:38 -0800687isdn_ppp_poll(struct file *file, poll_table *wait)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688{
689 u_int mask;
690 struct ippp_buf_queue *bf, *bl;
691 u_long flags;
692 struct ippp_struct *is;
693
694 is = file->private_data;
695
696 if (is->debug & 0x2)
697 printk(KERN_DEBUG "isdn_ppp_poll: minor: %d\n",
Al Viro496ad9a2013-01-23 17:07:38 -0500698 iminor(file_inode(file)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699
700 /* just registers wait_queue hook. This doesn't really wait. */
701 poll_wait(file, &is->wq, wait);
702
703 if (!(is->state & IPPP_OPEN)) {
Joe Perches475be4d2012-02-19 19:52:38 -0800704 if (is->state == IPPP_CLOSEWAIT)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 return POLLHUP;
706 printk(KERN_DEBUG "isdn_ppp: device not open\n");
707 return POLLERR;
708 }
709 /* we're always ready to send .. */
710 mask = POLLOUT | POLLWRNORM;
711
712 spin_lock_irqsave(&is->buflock, flags);
713 bl = is->last;
714 bf = is->first;
715 /*
716 * if IPPP_NOBLOCK is set we return even if we have nothing to read
717 */
718 if (bf->next != bl || (is->state & IPPP_NOBLOCK)) {
719 is->state &= ~IPPP_NOBLOCK;
720 mask |= POLLIN | POLLRDNORM;
721 }
722 spin_unlock_irqrestore(&is->buflock, flags);
723 return mask;
724}
725
726/*
727 * fill up isdn_ppp_read() queue ..
728 */
729
730static int
731isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot)
732{
733 struct ippp_buf_queue *bf, *bl;
734 u_long flags;
735 u_char *nbuf;
736 struct ippp_struct *is;
737
738 if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
739 printk(KERN_WARNING "ippp: illegal slot(%d).\n", slot);
740 return 0;
741 }
742 is = ippp_table[slot];
743
744 if (!(is->state & IPPP_CONNECT)) {
745 printk(KERN_DEBUG "ippp: device not activated.\n");
746 return 0;
747 }
Robert P. J. Day5cbded52006-12-13 00:35:56 -0800748 nbuf = kmalloc(len + 4, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 if (!nbuf) {
750 printk(KERN_WARNING "ippp: Can't alloc buf\n");
751 return 0;
752 }
753 nbuf[0] = PPP_ALLSTATIONS;
754 nbuf[1] = PPP_UI;
755 nbuf[2] = proto >> 8;
756 nbuf[3] = proto & 0xff;
757 memcpy(nbuf + 4, buf, len);
758
759 spin_lock_irqsave(&is->buflock, flags);
760 bf = is->first;
761 bl = is->last;
762
763 if (bf == bl) {
764 printk(KERN_WARNING "ippp: Queue is full; discarding first buffer\n");
765 bf = bf->next;
766 kfree(bf->buf);
767 is->first = bf;
768 }
769 bl->buf = (char *) nbuf;
770 bl->len = len + 4;
771
772 is->last = bl->next;
773 spin_unlock_irqrestore(&is->buflock, flags);
774 wake_up_interruptible(&is->wq);
775 return len;
776}
777
778/*
779 * read() .. non-blocking: ipppd calls it only after select()
780 * reports, that there is data
781 */
782
783int
784isdn_ppp_read(int min, struct file *file, char __user *buf, int count)
785{
786 struct ippp_struct *is;
787 struct ippp_buf_queue *b;
788 u_long flags;
789 u_char *save_buf;
790
791 is = file->private_data;
792
793 if (!(is->state & IPPP_OPEN))
794 return 0;
795
796 if (!access_ok(VERIFY_WRITE, buf, count))
797 return -EFAULT;
798
799 spin_lock_irqsave(&is->buflock, flags);
800 b = is->first->next;
801 save_buf = b->buf;
802 if (!save_buf) {
803 spin_unlock_irqrestore(&is->buflock, flags);
804 return -EAGAIN;
805 }
806 if (b->len < count)
807 count = b->len;
808 b->buf = NULL;
809 is->first = b;
810
811 spin_unlock_irqrestore(&is->buflock, flags);
Jesper Juhlc41a24c2006-03-25 03:07:02 -0800812 if (copy_to_user(buf, save_buf, count))
813 count = -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 kfree(save_buf);
815
816 return count;
817}
818
819/*
820 * ipppd wanna write a packet to the card .. non-blocking
821 */
822
823int
824isdn_ppp_write(int min, struct file *file, const char __user *buf, int count)
825{
826 isdn_net_local *lp;
827 struct ippp_struct *is;
828 int proto;
829 unsigned char protobuf[4];
830
831 is = file->private_data;
832
833 if (!(is->state & IPPP_CONNECT))
834 return 0;
835
836 lp = is->lp;
837
838 /* -> push it directly to the lowlevel interface */
839
840 if (!lp)
841 printk(KERN_DEBUG "isdn_ppp_write: lp == NULL\n");
842 else {
843 /*
844 * Don't reset huptimer for
845 * LCP packets. (Echo requests).
846 */
847 if (copy_from_user(protobuf, buf, 4))
848 return -EFAULT;
849 proto = PPP_PROTOCOL(protobuf);
850 if (proto != PPP_LCP)
851 lp->huptimer = 0;
852
853 if (lp->isdn_device < 0 || lp->isdn_channel < 0)
854 return 0;
855
856 if ((dev->drv[lp->isdn_device]->flags & DRV_FLAG_RUNNING) &&
Joe Perches475be4d2012-02-19 19:52:38 -0800857 lp->dialstate == 0 &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 (lp->flags & ISDN_NET_CONNECTED)) {
859 unsigned short hl;
860 struct sk_buff *skb;
861 /*
André Goddard Rosaaf901ca2009-11-14 13:09:05 -0200862 * we need to reserve enough space in front of
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 * sk_buff. old call to dev_alloc_skb only reserved
864 * 16 bytes, now we are looking what the driver want
865 */
866 hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen;
Joe Perches475be4d2012-02-19 19:52:38 -0800867 skb = alloc_skb(hl + count, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 if (!skb) {
869 printk(KERN_WARNING "isdn_ppp_write: out of memory!\n");
870 return count;
871 }
872 skb_reserve(skb, hl);
873 if (copy_from_user(skb_put(skb, count), buf, count))
874 {
875 kfree_skb(skb);
876 return -EFAULT;
877 }
878 if (is->debug & 0x40) {
879 printk(KERN_DEBUG "ppp xmit: len %d\n", (int) skb->len);
Joe Perches475be4d2012-02-19 19:52:38 -0800880 isdn_ppp_frame_log("xmit", skb->data, skb->len, 32, is->unit, lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 }
882
Joe Perches475be4d2012-02-19 19:52:38 -0800883 isdn_ppp_send_ccp(lp->netdev, lp, skb); /* keeps CCP/compression states in sync */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884
885 isdn_net_write_super(lp, skb);
886 }
887 }
888 return count;
889}
890
891/*
892 * init memory, structures etc.
893 */
894
895int
896isdn_ppp_init(void)
897{
898 int i,
Joe Perches475be4d2012-02-19 19:52:38 -0800899 j;
900
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901#ifdef CONFIG_ISDN_MPP
Joe Perches475be4d2012-02-19 19:52:38 -0800902 if (isdn_ppp_mp_bundle_array_init() < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 return -ENOMEM;
904#endif /* CONFIG_ISDN_MPP */
905
906 for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
Burman Yan41f96932006-12-08 02:39:35 -0800907 if (!(ippp_table[i] = kzalloc(sizeof(struct ippp_struct), GFP_KERNEL))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 printk(KERN_WARNING "isdn_ppp_init: Could not alloc ippp_table\n");
909 for (j = 0; j < i; j++)
910 kfree(ippp_table[j]);
911 return -1;
912 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 spin_lock_init(&ippp_table[i]->buflock);
914 ippp_table[i]->state = 0;
915 ippp_table[i]->first = ippp_table[i]->rq + NUM_RCV_BUFFS - 1;
916 ippp_table[i]->last = ippp_table[i]->rq;
917
918 for (j = 0; j < NUM_RCV_BUFFS; j++) {
919 ippp_table[i]->rq[j].buf = NULL;
920 ippp_table[i]->rq[j].last = ippp_table[i]->rq +
Joe Perches475be4d2012-02-19 19:52:38 -0800921 (NUM_RCV_BUFFS + j - 1) % NUM_RCV_BUFFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 ippp_table[i]->rq[j].next = ippp_table[i]->rq + (j + 1) % NUM_RCV_BUFFS;
923 }
924 }
925 return 0;
926}
927
928void
929isdn_ppp_cleanup(void)
930{
931 int i;
932
933 for (i = 0; i < ISDN_MAX_CHANNELS; i++)
934 kfree(ippp_table[i]);
935
936#ifdef CONFIG_ISDN_MPP
Jesper Juhl3c7208f2005-11-07 01:01:29 -0800937 kfree(isdn_ppp_bundle_arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938#endif /* CONFIG_ISDN_MPP */
939
940}
941
942/*
943 * check for address/control field and skip if allowed
944 * retval != 0 -> discard packet silently
945 */
Joe Perches475be4d2012-02-19 19:52:38 -0800946static int isdn_ppp_skip_ac(struct ippp_struct *is, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947{
948 if (skb->len < 1)
949 return -1;
950
951 if (skb->data[0] == 0xff) {
952 if (skb->len < 2)
953 return -1;
954
955 if (skb->data[1] != 0x03)
956 return -1;
957
958 // skip address/control (AC) field
959 skb_pull(skb, 2);
Joe Perches475be4d2012-02-19 19:52:38 -0800960 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 if (is->pppcfg & SC_REJ_COMP_AC)
962 // if AC compression was not negotiated, but used, discard packet
963 return -1;
964 }
965 return 0;
966}
967
968/*
969 * get the PPP protocol header and pull skb
970 * retval < 0 -> discard packet silently
971 */
Joe Perches475be4d2012-02-19 19:52:38 -0800972static int isdn_ppp_strip_proto(struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973{
974 int proto;
Joe Perches475be4d2012-02-19 19:52:38 -0800975
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 if (skb->len < 1)
977 return -1;
978
979 if (skb->data[0] & 0x1) {
980 // protocol field is compressed
981 proto = skb->data[0];
982 skb_pull(skb, 1);
983 } else {
984 if (skb->len < 2)
985 return -1;
986 proto = ((int) skb->data[0] << 8) + skb->data[1];
987 skb_pull(skb, 2);
988 }
989 return proto;
990}
991
992
993/*
994 * handler for incoming packets on a syncPPP interface
995 */
Joe Perches475be4d2012-02-19 19:52:38 -0800996void isdn_ppp_receive(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997{
998 struct ippp_struct *is;
999 int slot;
1000 int proto;
1001
Eric Sesterhenn6dd44a7442006-03-26 18:19:26 +02001002 BUG_ON(net_dev->local->master); // we're called with the master device always
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003
1004 slot = lp->ppp_slot;
1005 if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
1006 printk(KERN_ERR "isdn_ppp_receive: lp->ppp_slot(%d)\n",
Joe Perches475be4d2012-02-19 19:52:38 -08001007 lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 kfree_skb(skb);
1009 return;
1010 }
1011 is = ippp_table[slot];
1012
1013 if (is->debug & 0x4) {
1014 printk(KERN_DEBUG "ippp_receive: is:%08lx lp:%08lx slot:%d unit:%d len:%d\n",
Joe Perches475be4d2012-02-19 19:52:38 -08001015 (long)is, (long)lp, lp->ppp_slot, is->unit, (int)skb->len);
1016 isdn_ppp_frame_log("receive", skb->data, skb->len, 32, is->unit, lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 }
1018
Joe Perches475be4d2012-02-19 19:52:38 -08001019 if (isdn_ppp_skip_ac(is, skb) < 0) {
1020 kfree_skb(skb);
1021 return;
1022 }
1023 proto = isdn_ppp_strip_proto(skb);
1024 if (proto < 0) {
1025 kfree_skb(skb);
1026 return;
1027 }
1028
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029#ifdef CONFIG_ISDN_MPP
Joe Perches475be4d2012-02-19 19:52:38 -08001030 if (is->compflags & SC_LINK_DECOMP_ON) {
1031 skb = isdn_ppp_decompress(skb, is, NULL, &proto);
1032 if (!skb) // decompression error
1033 return;
1034 }
1035
1036 if (!(is->mpppcfg & SC_REJ_MP_PROT)) { // we agreed to receive MPPP
1037 if (proto == PPP_MP) {
1038 isdn_ppp_mp_receive(net_dev, lp, skb);
1039 return;
1040 }
1041 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042#endif
Joe Perches475be4d2012-02-19 19:52:38 -08001043 isdn_ppp_push_higher(net_dev, lp, skb, proto);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044}
1045
1046/*
1047 * we receive a reassembled frame, MPPP has been taken care of before.
1048 * address/control and protocol have been stripped from the skb
1049 * note: net_dev has to be master net_dev
1050 */
1051static void
Joe Perches475be4d2012-02-19 19:52:38 -08001052isdn_ppp_push_higher(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *skb, int proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053{
Karsten Keild62a38d2007-10-08 20:37:11 -07001054 struct net_device *dev = net_dev->dev;
Joe Perches475be4d2012-02-19 19:52:38 -08001055 struct ippp_struct *is, *mis;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 isdn_net_local *mlp = NULL;
1057 int slot;
1058
1059 slot = lp->ppp_slot;
1060 if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
1061 printk(KERN_ERR "isdn_ppp_push_higher: lp->ppp_slot(%d)\n",
Joe Perches475be4d2012-02-19 19:52:38 -08001062 lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 goto drop_packet;
1064 }
1065 is = ippp_table[slot];
Joe Perches475be4d2012-02-19 19:52:38 -08001066
1067 if (lp->master) { // FIXME?
Wang Chen838361f2008-12-03 15:49:46 -08001068 mlp = ISDN_MASTER_PRIV(lp);
Joe Perches475be4d2012-02-19 19:52:38 -08001069 slot = mlp->ppp_slot;
1070 if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
1071 printk(KERN_ERR "isdn_ppp_push_higher: master->ppp_slot(%d)\n",
1072 lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 goto drop_packet;
Joe Perches475be4d2012-02-19 19:52:38 -08001074 }
1075 }
1076 mis = ippp_table[slot];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077
1078 if (is->debug & 0x10) {
1079 printk(KERN_DEBUG "push, skb %d %04x\n", (int) skb->len, proto);
Joe Perches475be4d2012-02-19 19:52:38 -08001080 isdn_ppp_frame_log("rpush", skb->data, skb->len, 32, is->unit, lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081 }
1082 if (mis->compflags & SC_DECOMP_ON) {
1083 skb = isdn_ppp_decompress(skb, is, mis, &proto);
1084 if (!skb) // decompression error
Joe Perches475be4d2012-02-19 19:52:38 -08001085 return;
1086 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 switch (proto) {
Joe Perches475be4d2012-02-19 19:52:38 -08001088 case PPP_IPX: /* untested */
1089 if (is->debug & 0x20)
1090 printk(KERN_DEBUG "isdn_ppp: IPX\n");
1091 skb->protocol = htons(ETH_P_IPX);
1092 break;
1093 case PPP_IP:
1094 if (is->debug & 0x20)
1095 printk(KERN_DEBUG "isdn_ppp: IP\n");
1096 skb->protocol = htons(ETH_P_IP);
1097 break;
1098 case PPP_COMP:
1099 case PPP_COMPFRAG:
1100 printk(KERN_INFO "isdn_ppp: unexpected compressed frame dropped\n");
1101 goto drop_packet;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102#ifdef CONFIG_ISDN_PPP_VJ
Joe Perches475be4d2012-02-19 19:52:38 -08001103 case PPP_VJC_UNCOMP:
1104 if (is->debug & 0x20)
1105 printk(KERN_DEBUG "isdn_ppp: VJC_UNCOMP\n");
1106 if (net_dev->local->ppp_slot < 0) {
1107 printk(KERN_ERR "%s: net_dev->local->ppp_slot(%d) out of range\n",
1108 __func__, net_dev->local->ppp_slot);
1109 goto drop_packet;
1110 }
1111 if (slhc_remember(ippp_table[net_dev->local->ppp_slot]->slcomp, skb->data, skb->len) <= 0) {
1112 printk(KERN_WARNING "isdn_ppp: received illegal VJC_UNCOMP frame!\n");
1113 goto drop_packet;
1114 }
1115 skb->protocol = htons(ETH_P_IP);
1116 break;
1117 case PPP_VJC_COMP:
1118 if (is->debug & 0x20)
1119 printk(KERN_DEBUG "isdn_ppp: VJC_COMP\n");
1120 {
1121 struct sk_buff *skb_old = skb;
1122 int pkt_len;
1123 skb = dev_alloc_skb(skb_old->len + 128);
1124
1125 if (!skb) {
1126 printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
1127 skb = skb_old;
1128 goto drop_packet;
1129 }
1130 skb_put(skb, skb_old->len + 128);
1131 skb_copy_from_linear_data(skb_old, skb->data,
1132 skb_old->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 if (net_dev->local->ppp_slot < 0) {
1134 printk(KERN_ERR "%s: net_dev->local->ppp_slot(%d) out of range\n",
Joe Perches475be4d2012-02-19 19:52:38 -08001135 __func__, net_dev->local->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136 goto drop_packet;
1137 }
Joe Perches475be4d2012-02-19 19:52:38 -08001138 pkt_len = slhc_uncompress(ippp_table[net_dev->local->ppp_slot]->slcomp,
1139 skb->data, skb_old->len);
1140 kfree_skb(skb_old);
1141 if (pkt_len < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142 goto drop_packet;
Joe Perches475be4d2012-02-19 19:52:38 -08001143
1144 skb_trim(skb, pkt_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145 skb->protocol = htons(ETH_P_IP);
Joe Perches475be4d2012-02-19 19:52:38 -08001146 }
1147 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148#endif
Joe Perches475be4d2012-02-19 19:52:38 -08001149 case PPP_CCP:
1150 case PPP_CCPFRAG:
1151 isdn_ppp_receive_ccp(net_dev, lp, skb, proto);
1152 /* Dont pop up ResetReq/Ack stuff to the daemon any
1153 longer - the job is done already */
1154 if (skb->data[0] == CCP_RESETREQ ||
1155 skb->data[0] == CCP_RESETACK)
1156 break;
1157 /* fall through */
1158 default:
1159 isdn_ppp_fill_rq(skb->data, skb->len, proto, lp->ppp_slot); /* push data to pppd device */
1160 kfree_skb(skb);
1161 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 }
1163
1164#ifdef CONFIG_IPPP_FILTER
1165 /* check if the packet passes the pass and active filters
1166 * the filter instructions are constructed assuming
1167 * a four-byte PPP header on each packet (which is still present) */
1168 skb_push(skb, 4);
1169
1170 {
1171 u_int16_t *p = (u_int16_t *) skb->data;
1172
Karsten Keild8470b72005-04-21 08:30:30 -07001173 *p = 0; /* indicate inbound */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174 }
1175
1176 if (is->pass_filter
Daniel Borkmann77e01142014-03-28 18:58:24 +01001177 && SK_RUN_FILTER(is->pass_filter, skb) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 if (is->debug & 0x2)
1179 printk(KERN_DEBUG "IPPP: inbound frame filtered.\n");
1180 kfree_skb(skb);
1181 return;
1182 }
1183 if (!(is->active_filter
Daniel Borkmann77e01142014-03-28 18:58:24 +01001184 && SK_RUN_FILTER(is->active_filter, skb) == 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 if (is->debug & 0x2)
Masanari Iidaee556fe2012-02-11 01:49:28 +00001186 printk(KERN_DEBUG "IPPP: link-active filter: resetting huptimer.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187 lp->huptimer = 0;
1188 if (mlp)
1189 mlp->huptimer = 0;
1190 }
1191 skb_pull(skb, 4);
1192#else /* CONFIG_IPPP_FILTER */
1193 lp->huptimer = 0;
1194 if (mlp)
1195 mlp->huptimer = 0;
1196#endif /* CONFIG_IPPP_FILTER */
1197 skb->dev = dev;
Arnaldo Carvalho de Melo459a98e2007-03-19 15:30:44 -07001198 skb_reset_mac_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199 netif_rx(skb);
1200 /* net_dev->local->stats.rx_packets++; done in isdn_net.c */
1201 return;
1202
Joe Perches475be4d2012-02-19 19:52:38 -08001203drop_packet:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204 net_dev->local->stats.rx_dropped++;
1205 kfree_skb(skb);
1206}
1207
1208/*
1209 * isdn_ppp_skb_push ..
1210 * checks whether we have enough space at the beginning of the skb
1211 * and allocs a new SKB if necessary
1212 */
Joe Perches475be4d2012-02-19 19:52:38 -08001213static unsigned char *isdn_ppp_skb_push(struct sk_buff **skb_p, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214{
1215 struct sk_buff *skb = *skb_p;
1216
Joe Perches475be4d2012-02-19 19:52:38 -08001217 if (skb_headroom(skb) < len) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218 struct sk_buff *nskb = skb_realloc_headroom(skb, len);
1219
1220 if (!nskb) {
1221 printk(KERN_ERR "isdn_ppp_skb_push: can't realloc headroom!\n");
1222 dev_kfree_skb(skb);
1223 return NULL;
1224 }
Joe Perches475be4d2012-02-19 19:52:38 -08001225 printk(KERN_DEBUG "isdn_ppp_skb_push:under %d %d\n", skb_headroom(skb), len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226 dev_kfree_skb(skb);
1227 *skb_p = nskb;
1228 return skb_push(nskb, len);
1229 }
Joe Perches475be4d2012-02-19 19:52:38 -08001230 return skb_push(skb, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231}
1232
1233/*
1234 * send ppp frame .. we expect a PIDCOMPressable proto --
1235 * (here: currently always PPP_IP,PPP_VJC_COMP,PPP_VJC_UNCOMP)
1236 *
1237 * VJ compression may change skb pointer!!! .. requeue with old
1238 * skb isn't allowed!!
1239 */
1240
1241int
1242isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev)
1243{
Joe Perches475be4d2012-02-19 19:52:38 -08001244 isdn_net_local *lp, *mlp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245 isdn_net_dev *nd;
1246 unsigned int proto = PPP_IP; /* 0x21 */
Joe Perches475be4d2012-02-19 19:52:38 -08001247 struct ippp_struct *ipt, *ipts;
Patrick McHardyec634fe2009-07-05 19:23:38 -07001248 int slot, retval = NETDEV_TX_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249
Joe Perchesa17531f2010-11-15 11:12:24 +00001250 mlp = netdev_priv(netdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251 nd = mlp->netdev; /* get master lp */
1252
1253 slot = mlp->ppp_slot;
1254 if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
1255 printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot(%d)\n",
Joe Perches475be4d2012-02-19 19:52:38 -08001256 mlp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257 kfree_skb(skb);
1258 goto out;
1259 }
1260 ipts = ippp_table[slot];
1261
1262 if (!(ipts->pppcfg & SC_ENABLE_IP)) { /* PPP connected ? */
1263 if (ipts->debug & 0x1)
1264 printk(KERN_INFO "%s: IP frame delayed.\n", netdev->name);
Patrick McHardyec634fe2009-07-05 19:23:38 -07001265 retval = NETDEV_TX_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266 goto out;
1267 }
1268
1269 switch (ntohs(skb->protocol)) {
Joe Perches475be4d2012-02-19 19:52:38 -08001270 case ETH_P_IP:
1271 proto = PPP_IP;
1272 break;
1273 case ETH_P_IPX:
1274 proto = PPP_IPX; /* untested */
1275 break;
1276 default:
1277 printk(KERN_ERR "isdn_ppp: skipped unsupported protocol: %#x.\n",
1278 skb->protocol);
1279 dev_kfree_skb(skb);
1280 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281 }
1282
1283 lp = isdn_net_get_locked_lp(nd);
1284 if (!lp) {
1285 printk(KERN_WARNING "%s: all channels busy - requeuing!\n", netdev->name);
Patrick McHardyec634fe2009-07-05 19:23:38 -07001286 retval = NETDEV_TX_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287 goto out;
1288 }
1289 /* we have our lp locked from now on */
1290
1291 slot = lp->ppp_slot;
Eric Sesterhenn052bb882006-04-11 17:29:17 -07001292 if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293 printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot(%d)\n",
Joe Perches475be4d2012-02-19 19:52:38 -08001294 lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 kfree_skb(skb);
1296 goto unlock;
1297 }
1298 ipt = ippp_table[slot];
1299
1300 /*
1301 * after this line .. requeueing in the device queue is no longer allowed!!!
1302 */
1303
1304 /* Pull off the fake header we stuck on earlier to keep
1305 * the fragmentation code happy.
1306 */
Joe Perches475be4d2012-02-19 19:52:38 -08001307 skb_pull(skb, IPPP_MAX_HEADER);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308
1309#ifdef CONFIG_IPPP_FILTER
1310 /* check if we should pass this packet
1311 * the filter instructions are constructed assuming
1312 * a four-byte PPP header on each packet */
Karsten Keild8470b72005-04-21 08:30:30 -07001313 *skb_push(skb, 4) = 1; /* indicate outbound */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314
1315 {
Harvey Harrisonc19d0362008-11-20 04:10:51 -08001316 __be16 *p = (__be16 *)skb->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317
Karsten Keild8470b72005-04-21 08:30:30 -07001318 p++;
Harvey Harrisonc19d0362008-11-20 04:10:51 -08001319 *p = htons(proto);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 }
1321
1322 if (ipt->pass_filter
Daniel Borkmann77e01142014-03-28 18:58:24 +01001323 && SK_RUN_FILTER(ipt->pass_filter, skb) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324 if (ipt->debug & 0x4)
1325 printk(KERN_DEBUG "IPPP: outbound frame filtered.\n");
1326 kfree_skb(skb);
1327 goto unlock;
1328 }
1329 if (!(ipt->active_filter
Daniel Borkmann77e01142014-03-28 18:58:24 +01001330 && SK_RUN_FILTER(ipt->active_filter, skb) == 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331 if (ipt->debug & 0x4)
Masanari Iidaee556fe2012-02-11 01:49:28 +00001332 printk(KERN_DEBUG "IPPP: link-active filter: resetting huptimer.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333 lp->huptimer = 0;
1334 }
1335 skb_pull(skb, 4);
1336#else /* CONFIG_IPPP_FILTER */
1337 lp->huptimer = 0;
1338#endif /* CONFIG_IPPP_FILTER */
1339
1340 if (ipt->debug & 0x4)
1341 printk(KERN_DEBUG "xmit skb, len %d\n", (int) skb->len);
Joe Perches475be4d2012-02-19 19:52:38 -08001342 if (ipts->debug & 0x40)
1343 isdn_ppp_frame_log("xmit0", skb->data, skb->len, 32, ipts->unit, lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344
1345#ifdef CONFIG_ISDN_PPP_VJ
1346 if (proto == PPP_IP && ipts->pppcfg & SC_COMP_TCP) { /* ipts here? probably yes, but check this again */
1347 struct sk_buff *new_skb;
Joe Perches475be4d2012-02-19 19:52:38 -08001348 unsigned short hl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 /*
André Goddard Rosaaf901ca2009-11-14 13:09:05 -02001350 * we need to reserve enough space in front of
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 * sk_buff. old call to dev_alloc_skb only reserved
1352 * 16 bytes, now we are looking what the driver want.
1353 */
1354 hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen + IPPP_MAX_HEADER;
Joe Perches475be4d2012-02-19 19:52:38 -08001355 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356 * Note: hl might still be insufficient because the method
1357 * above does not account for a possibible MPPP slave channel
1358 * which had larger HL header space requirements than the
1359 * master.
1360 */
Joe Perches475be4d2012-02-19 19:52:38 -08001361 new_skb = alloc_skb(hl + skb->len, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362 if (new_skb) {
1363 u_char *buf;
1364 int pktlen;
1365
1366 skb_reserve(new_skb, hl);
1367 new_skb->dev = skb->dev;
1368 skb_put(new_skb, skb->len);
1369 buf = skb->data;
1370
1371 pktlen = slhc_compress(ipts->slcomp, skb->data, skb->len, new_skb->data,
Joe Perches475be4d2012-02-19 19:52:38 -08001372 &buf, !(ipts->pppcfg & SC_NO_TCP_CCID));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373
Joe Perches475be4d2012-02-19 19:52:38 -08001374 if (buf != skb->data) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375 if (new_skb->data != buf)
1376 printk(KERN_ERR "isdn_ppp: FATAL error after slhc_compress!!\n");
1377 dev_kfree_skb(skb);
1378 skb = new_skb;
1379 } else {
1380 dev_kfree_skb(new_skb);
1381 }
1382
1383 skb_trim(skb, pktlen);
1384 if (skb->data[0] & SL_TYPE_COMPRESSED_TCP) { /* cslip? style -> PPP */
1385 proto = PPP_VJC_COMP;
1386 skb->data[0] ^= SL_TYPE_COMPRESSED_TCP;
1387 } else {
1388 if (skb->data[0] >= SL_TYPE_UNCOMPRESSED_TCP)
1389 proto = PPP_VJC_UNCOMP;
1390 skb->data[0] = (skb->data[0] & 0x0f) | 0x40;
1391 }
1392 }
1393 }
1394#endif
1395
1396 /*
1397 * normal (single link) or bundle compression
1398 */
Joe Perches475be4d2012-02-19 19:52:38 -08001399 if (ipts->compflags & SC_COMP_ON) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400 /* We send compressed only if both down- und upstream
1401 compression is negotiated, that means, CCP is up */
Joe Perches475be4d2012-02-19 19:52:38 -08001402 if (ipts->compflags & SC_DECOMP_ON) {
1403 skb = isdn_ppp_compress(skb, &proto, ipt, ipts, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404 } else {
1405 printk(KERN_DEBUG "isdn_ppp: CCP not yet up - sending as-is\n");
1406 }
1407 }
1408
1409 if (ipt->debug & 0x24)
1410 printk(KERN_DEBUG "xmit2 skb, len %d, proto %04x\n", (int) skb->len, proto);
1411
1412#ifdef CONFIG_ISDN_MPP
1413 if (ipt->mpppcfg & SC_MP_PROT) {
1414 /* we get mp_seqno from static isdn_net_local */
1415 long mp_seqno = ipts->mp_seqno;
1416 ipts->mp_seqno++;
1417 if (ipt->mpppcfg & SC_OUT_SHORT_SEQ) {
1418 unsigned char *data = isdn_ppp_skb_push(&skb, 3);
Joe Perches475be4d2012-02-19 19:52:38 -08001419 if (!data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420 goto unlock;
1421 mp_seqno &= 0xfff;
1422 data[0] = MP_BEGIN_FRAG | MP_END_FRAG | ((mp_seqno >> 8) & 0xf); /* (B)egin & (E)ndbit .. */
1423 data[1] = mp_seqno & 0xff;
1424 data[2] = proto; /* PID compression */
1425 } else {
1426 unsigned char *data = isdn_ppp_skb_push(&skb, 5);
Joe Perches475be4d2012-02-19 19:52:38 -08001427 if (!data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428 goto unlock;
1429 data[0] = MP_BEGIN_FRAG | MP_END_FRAG; /* (B)egin & (E)ndbit .. */
1430 data[1] = (mp_seqno >> 16) & 0xff; /* sequence number: 24bit */
1431 data[2] = (mp_seqno >> 8) & 0xff;
1432 data[3] = (mp_seqno >> 0) & 0xff;
1433 data[4] = proto; /* PID compression */
1434 }
1435 proto = PPP_MP; /* MP Protocol, 0x003d */
1436 }
1437#endif
1438
1439 /*
1440 * 'link in bundle' compression ...
1441 */
Joe Perches475be4d2012-02-19 19:52:38 -08001442 if (ipt->compflags & SC_LINK_COMP_ON)
1443 skb = isdn_ppp_compress(skb, &proto, ipt, ipts, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444
Joe Perches475be4d2012-02-19 19:52:38 -08001445 if ((ipt->pppcfg & SC_COMP_PROT) && (proto <= 0xff)) {
1446 unsigned char *data = isdn_ppp_skb_push(&skb, 1);
1447 if (!data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448 goto unlock;
1449 data[0] = proto & 0xff;
1450 }
1451 else {
Joe Perches475be4d2012-02-19 19:52:38 -08001452 unsigned char *data = isdn_ppp_skb_push(&skb, 2);
1453 if (!data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454 goto unlock;
1455 data[0] = (proto >> 8) & 0xff;
1456 data[1] = proto & 0xff;
1457 }
Joe Perches475be4d2012-02-19 19:52:38 -08001458 if (!(ipt->pppcfg & SC_COMP_AC)) {
1459 unsigned char *data = isdn_ppp_skb_push(&skb, 2);
1460 if (!data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461 goto unlock;
1462 data[0] = 0xff; /* All Stations */
1463 data[1] = 0x03; /* Unnumbered information */
1464 }
1465
1466 /* tx-stats are now updated via BSENT-callback */
1467
1468 if (ipts->debug & 0x40) {
1469 printk(KERN_DEBUG "skb xmit: len: %d\n", (int) skb->len);
Joe Perches475be4d2012-02-19 19:52:38 -08001470 isdn_ppp_frame_log("xmit", skb->data, skb->len, 32, ipt->unit, lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471 }
Joe Perches475be4d2012-02-19 19:52:38 -08001472
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473 isdn_net_writebuf_skb(lp, skb);
1474
Joe Perches475be4d2012-02-19 19:52:38 -08001475unlock:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 spin_unlock_bh(&lp->xmit_lock);
Joe Perches475be4d2012-02-19 19:52:38 -08001477out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 return retval;
1479}
1480
1481#ifdef CONFIG_IPPP_FILTER
1482/*
1483 * check if this packet may trigger auto-dial.
1484 */
1485
1486int isdn_ppp_autodial_filter(struct sk_buff *skb, isdn_net_local *lp)
1487{
1488 struct ippp_struct *is = ippp_table[lp->ppp_slot];
1489 u_int16_t proto;
1490 int drop = 0;
1491
1492 switch (ntohs(skb->protocol)) {
1493 case ETH_P_IP:
1494 proto = PPP_IP;
1495 break;
1496 case ETH_P_IPX:
1497 proto = PPP_IPX;
1498 break;
1499 default:
1500 printk(KERN_ERR "isdn_ppp_autodial_filter: unsupported protocol 0x%x.\n",
1501 skb->protocol);
1502 return 1;
1503 }
1504
1505 /* the filter instructions are constructed assuming
1506 * a four-byte PPP header on each packet. we have to
1507 * temporarily remove part of the fake header stuck on
1508 * earlier.
1509 */
Karsten Keild8470b72005-04-21 08:30:30 -07001510 *skb_pull(skb, IPPP_MAX_HEADER - 4) = 1; /* indicate outbound */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511
1512 {
Harvey Harrisonc19d0362008-11-20 04:10:51 -08001513 __be16 *p = (__be16 *)skb->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514
Karsten Keild8470b72005-04-21 08:30:30 -07001515 p++;
Harvey Harrisonc19d0362008-11-20 04:10:51 -08001516 *p = htons(proto);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517 }
Joe Perches475be4d2012-02-19 19:52:38 -08001518
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519 drop |= is->pass_filter
Daniel Borkmann77e01142014-03-28 18:58:24 +01001520 && SK_RUN_FILTER(is->pass_filter, skb) == 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 drop |= is->active_filter
Daniel Borkmann77e01142014-03-28 18:58:24 +01001522 && SK_RUN_FILTER(is->active_filter, skb) == 0;
Joe Perches475be4d2012-02-19 19:52:38 -08001523
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524 skb_push(skb, IPPP_MAX_HEADER - 4);
1525 return drop;
1526}
1527#endif
1528#ifdef CONFIG_ISDN_MPP
1529
1530/* this is _not_ rfc1990 header, but something we convert both short and long
1531 * headers to for convinience's sake:
Joe Perches475be4d2012-02-19 19:52:38 -08001532 * byte 0 is flags as in rfc1990
1533 * bytes 1...4 is 24-bit seqence number converted to host byte order
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534 */
1535#define MP_HEADER_LEN 5
1536
1537#define MP_LONGSEQ_MASK 0x00ffffff
1538#define MP_SHORTSEQ_MASK 0x00000fff
1539#define MP_LONGSEQ_MAX MP_LONGSEQ_MASK
1540#define MP_SHORTSEQ_MAX MP_SHORTSEQ_MASK
Joe Perches475be4d2012-02-19 19:52:38 -08001541#define MP_LONGSEQ_MAXBIT ((MP_LONGSEQ_MASK + 1) >> 1)
1542#define MP_SHORTSEQ_MAXBIT ((MP_SHORTSEQ_MASK + 1) >> 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543
Lucas De Marchi25985ed2011-03-30 22:57:33 -03001544/* sequence-wrap safe comparisons (for long sequence)*/
Joe Perches475be4d2012-02-19 19:52:38 -08001545#define MP_LT(a, b) ((a - b) & MP_LONGSEQ_MAXBIT)
1546#define MP_LE(a, b) !((b - a) & MP_LONGSEQ_MAXBIT)
1547#define MP_GT(a, b) ((b - a) & MP_LONGSEQ_MAXBIT)
1548#define MP_GE(a, b) !((a - b) & MP_LONGSEQ_MAXBIT)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549
Joe Perches475be4d2012-02-19 19:52:38 -08001550#define MP_SEQ(f) ((*(u32 *)(f->data + 1)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551#define MP_FLAGS(f) (f->data[0])
1552
1553static int isdn_ppp_mp_bundle_array_init(void)
1554{
1555 int i;
Joe Perches475be4d2012-02-19 19:52:38 -08001556 int sz = ISDN_MAX_CHANNELS * sizeof(ippp_bundle);
1557 if ((isdn_ppp_bundle_arr = kzalloc(sz, GFP_KERNEL)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558 return -ENOMEM;
Joe Perches475be4d2012-02-19 19:52:38 -08001559 for (i = 0; i < ISDN_MAX_CHANNELS; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560 spin_lock_init(&isdn_ppp_bundle_arr[i].lock);
1561 return 0;
1562}
1563
Joe Perches475be4d2012-02-19 19:52:38 -08001564static ippp_bundle *isdn_ppp_mp_bundle_alloc(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565{
1566 int i;
Joe Perches475be4d2012-02-19 19:52:38 -08001567 for (i = 0; i < ISDN_MAX_CHANNELS; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568 if (isdn_ppp_bundle_arr[i].ref_ct <= 0)
1569 return (isdn_ppp_bundle_arr + i);
1570 return NULL;
1571}
1572
Joe Perches475be4d2012-02-19 19:52:38 -08001573static int isdn_ppp_mp_init(isdn_net_local *lp, ippp_bundle *add_to)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574{
Joe Perches475be4d2012-02-19 19:52:38 -08001575 struct ippp_struct *is;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576
1577 if (lp->ppp_slot < 0) {
1578 printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
Joe Perches475be4d2012-02-19 19:52:38 -08001579 __func__, lp->ppp_slot);
1580 return (-EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581 }
1582
1583 is = ippp_table[lp->ppp_slot];
1584 if (add_to) {
Joe Perches475be4d2012-02-19 19:52:38 -08001585 if (lp->netdev->pb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586 lp->netdev->pb->ref_ct--;
1587 lp->netdev->pb = add_to;
1588 } else { /* first link in a bundle */
1589 is->mp_seqno = 0;
1590 if ((lp->netdev->pb = isdn_ppp_mp_bundle_alloc()) == NULL)
1591 return -ENOMEM;
1592 lp->next = lp->last = lp; /* nobody else in a queue */
David S. Millere29d4362009-11-15 22:23:47 -08001593 lp->netdev->pb->frags = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594 lp->netdev->pb->frames = 0;
1595 lp->netdev->pb->seq = UINT_MAX;
1596 }
1597 lp->netdev->pb->ref_ct++;
Joe Perches475be4d2012-02-19 19:52:38 -08001598
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599 is->last_link_seqno = 0;
1600 return 0;
1601}
1602
Joe Perches475be4d2012-02-19 19:52:38 -08001603static u32 isdn_ppp_mp_get_seq(int short_seq,
1604 struct sk_buff *skb, u32 last_seq);
1605static struct sk_buff *isdn_ppp_mp_discard(ippp_bundle *mp,
1606 struct sk_buff *from, struct sk_buff *to);
1607static void isdn_ppp_mp_reassembly(isdn_net_dev *net_dev, isdn_net_local *lp,
1608 struct sk_buff *from, struct sk_buff *to);
1609static void isdn_ppp_mp_free_skb(ippp_bundle *mp, struct sk_buff *skb);
1610static void isdn_ppp_mp_print_recv_pkt(int slot, struct sk_buff *skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611
Joe Perches475be4d2012-02-19 19:52:38 -08001612static void isdn_ppp_mp_receive(isdn_net_dev *net_dev, isdn_net_local *lp,
1613 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614{
David S. Miller38783e62008-09-22 01:15:02 -07001615 struct ippp_struct *is;
Joe Perches475be4d2012-02-19 19:52:38 -08001616 isdn_net_local *lpq;
1617 ippp_bundle *mp;
1618 isdn_mppp_stats *stats;
1619 struct sk_buff *newfrag, *frag, *start, *nextf;
David S. Millere29d4362009-11-15 22:23:47 -08001620 u32 newseq, minseq, thisseq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621 unsigned long flags;
1622 int slot;
1623
1624 spin_lock_irqsave(&net_dev->pb->lock, flags);
Joe Perches475be4d2012-02-19 19:52:38 -08001625 mp = net_dev->pb;
1626 stats = &mp->stats;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627 slot = lp->ppp_slot;
Eric Sesterhenn052bb882006-04-11 17:29:17 -07001628 if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629 printk(KERN_ERR "%s: lp->ppp_slot(%d)\n",
Joe Perches475be4d2012-02-19 19:52:38 -08001630 __func__, lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 stats->frame_drops++;
1632 dev_kfree_skb(skb);
1633 spin_unlock_irqrestore(&mp->lock, flags);
1634 return;
1635 }
1636 is = ippp_table[slot];
Joe Perches475be4d2012-02-19 19:52:38 -08001637 if (++mp->frames > stats->max_queue_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638 stats->max_queue_len = mp->frames;
Joe Perches475be4d2012-02-19 19:52:38 -08001639
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640 if (is->debug & 0x8)
1641 isdn_ppp_mp_print_recv_pkt(lp->ppp_slot, skb);
1642
Joe Perches475be4d2012-02-19 19:52:38 -08001643 newseq = isdn_ppp_mp_get_seq(is->mpppcfg & SC_IN_SHORT_SEQ,
1644 skb, is->last_link_seqno);
David S. Millere29d4362009-11-15 22:23:47 -08001645
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646
1647 /* if this packet seq # is less than last already processed one,
Joe Perches475be4d2012-02-19 19:52:38 -08001648 * toss it right away, but check for sequence start case first
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649 */
Joe Perches475be4d2012-02-19 19:52:38 -08001650 if (mp->seq > MP_LONGSEQ_MAX && (newseq & MP_LONGSEQ_MAXBIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651 mp->seq = newseq; /* the first packet: required for
1652 * rfc1990 non-compliant clients --
1653 * prevents constant packet toss */
Joe Perches475be4d2012-02-19 19:52:38 -08001654 } else if (MP_LT(newseq, mp->seq)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655 stats->frame_drops++;
1656 isdn_ppp_mp_free_skb(mp, skb);
1657 spin_unlock_irqrestore(&mp->lock, flags);
1658 return;
1659 }
Joe Perches475be4d2012-02-19 19:52:38 -08001660
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661 /* find the minimum received sequence number over all links */
1662 is->last_link_seqno = minseq = newseq;
1663 for (lpq = net_dev->queue;;) {
1664 slot = lpq->ppp_slot;
Eric Sesterhenn052bb882006-04-11 17:29:17 -07001665 if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666 printk(KERN_ERR "%s: lpq->ppp_slot(%d)\n",
Joe Perches475be4d2012-02-19 19:52:38 -08001667 __func__, lpq->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668 } else {
1669 u32 lls = ippp_table[slot]->last_link_seqno;
1670 if (MP_LT(lls, minseq))
1671 minseq = lls;
1672 }
1673 if ((lpq = lpq->next) == net_dev->queue)
1674 break;
1675 }
1676 if (MP_LT(minseq, mp->seq))
1677 minseq = mp->seq; /* can't go beyond already processed
1678 * packets */
1679 newfrag = skb;
1680
Joe Perches475be4d2012-02-19 19:52:38 -08001681 /* if this new fragment is before the first one, then enqueue it now. */
1682 if ((frag = mp->frags) == NULL || MP_LT(newseq, MP_SEQ(frag))) {
David S. Millere29d4362009-11-15 22:23:47 -08001683 newfrag->next = frag;
Joe Perches475be4d2012-02-19 19:52:38 -08001684 mp->frags = frag = newfrag;
1685 newfrag = NULL;
1686 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687
Joe Perches475be4d2012-02-19 19:52:38 -08001688 start = MP_FLAGS(frag) & MP_BEGIN_FRAG &&
1689 MP_SEQ(frag) == mp->seq ? frag : NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690
Joe Perches475be4d2012-02-19 19:52:38 -08001691 /*
David S. Millere29d4362009-11-15 22:23:47 -08001692 * main fragment traversing loop
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693 *
1694 * try to accomplish several tasks:
David S. Millere29d4362009-11-15 22:23:47 -08001695 * - insert new fragment into the proper sequence slot (once that's done
1696 * newfrag will be set to NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697 * - reassemble any complete fragment sequence (non-null 'start'
André Goddard Rosaaf901ca2009-11-14 13:09:05 -02001698 * indicates there is a contiguous sequence present)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699 * - discard any incomplete sequences that are below minseq -- due
1700 * to the fact that sender always increment sequence number, if there
1701 * is an incomplete sequence below minseq, no new fragments would
1702 * come to complete such sequence and it should be discarded
1703 *
1704 * loop completes when we accomplished the following tasks:
Joe Perches475be4d2012-02-19 19:52:38 -08001705 * - new fragment is inserted in the proper sequence ('newfrag' is
David S. Millere29d4362009-11-15 22:23:47 -08001706 * set to NULL)
Joe Perches475be4d2012-02-19 19:52:38 -08001707 * - we hit a gap in the sequence, so no reassembly/processing is
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708 * possible ('start' would be set to NULL)
1709 *
Robert P. J. Dayd08df602007-02-17 19:07:33 +01001710 * algorithm for this code is derived from code in the book
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711 * 'PPP Design And Debugging' by James Carlson (Addison-Wesley)
1712 */
Joe Perches475be4d2012-02-19 19:52:38 -08001713 while (start != NULL || newfrag != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714
Joe Perches475be4d2012-02-19 19:52:38 -08001715 thisseq = MP_SEQ(frag);
1716 nextf = frag->next;
David S. Millere29d4362009-11-15 22:23:47 -08001717
Joe Perches475be4d2012-02-19 19:52:38 -08001718 /* drop any duplicate fragments */
1719 if (newfrag != NULL && thisseq == newseq) {
1720 isdn_ppp_mp_free_skb(mp, newfrag);
1721 newfrag = NULL;
1722 }
David S. Millere29d4362009-11-15 22:23:47 -08001723
Joe Perches475be4d2012-02-19 19:52:38 -08001724 /* insert new fragment before next element if possible. */
1725 if (newfrag != NULL && (nextf == NULL ||
1726 MP_LT(newseq, MP_SEQ(nextf)))) {
1727 newfrag->next = nextf;
1728 frag->next = nextf = newfrag;
1729 newfrag = NULL;
1730 }
David S. Millere29d4362009-11-15 22:23:47 -08001731
Joe Perches475be4d2012-02-19 19:52:38 -08001732 if (start != NULL) {
1733 /* check for misplaced start */
1734 if (start != frag && (MP_FLAGS(frag) & MP_BEGIN_FRAG)) {
David S. Millere29d4362009-11-15 22:23:47 -08001735 printk(KERN_WARNING"isdn_mppp(seq %d): new "
Joe Perches475be4d2012-02-19 19:52:38 -08001736 "BEGIN flag with no prior END", thisseq);
David S. Millere29d4362009-11-15 22:23:47 -08001737 stats->seqerrs++;
1738 stats->frame_drops++;
Joe Perches475be4d2012-02-19 19:52:38 -08001739 start = isdn_ppp_mp_discard(mp, start, frag);
David S. Millere29d4362009-11-15 22:23:47 -08001740 nextf = frag->next;
Joe Perches475be4d2012-02-19 19:52:38 -08001741 }
1742 } else if (MP_LE(thisseq, minseq)) {
1743 if (MP_FLAGS(frag) & MP_BEGIN_FRAG)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744 start = frag;
Joe Perches475be4d2012-02-19 19:52:38 -08001745 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746 if (MP_FLAGS(frag) & MP_END_FRAG)
Joe Perches475be4d2012-02-19 19:52:38 -08001747 stats->frame_drops++;
1748 if (mp->frags == frag)
1749 mp->frags = nextf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750 isdn_ppp_mp_free_skb(mp, frag);
David S. Millere29d4362009-11-15 22:23:47 -08001751 frag = nextf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752 continue;
Joe Perches475be4d2012-02-19 19:52:38 -08001753 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754 }
Joe Perches475be4d2012-02-19 19:52:38 -08001755
David S. Millere29d4362009-11-15 22:23:47 -08001756 /* if start is non-null and we have end fragment, then
Joe Perches475be4d2012-02-19 19:52:38 -08001757 * we have full reassembly sequence -- reassemble
David S. Millere29d4362009-11-15 22:23:47 -08001758 * and process packet now
David S. Miller38783e62008-09-22 01:15:02 -07001759 */
Joe Perches475be4d2012-02-19 19:52:38 -08001760 if (start != NULL && (MP_FLAGS(frag) & MP_END_FRAG)) {
1761 minseq = mp->seq = (thisseq + 1) & MP_LONGSEQ_MASK;
1762 /* Reassemble the packet then dispatch it */
David S. Millere29d4362009-11-15 22:23:47 -08001763 isdn_ppp_mp_reassembly(net_dev, lp, start, nextf);
David S. Miller38783e62008-09-22 01:15:02 -07001764
Joe Perches475be4d2012-02-19 19:52:38 -08001765 start = NULL;
1766 frag = NULL;
1767
1768 mp->frags = nextf;
1769 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770
1771 /* check if need to update start pointer: if we just
1772 * reassembled the packet and sequence is contiguous
1773 * then next fragment should be the start of new reassembly
1774 * if sequence is contiguous, but we haven't reassembled yet,
1775 * keep going.
Lucas De Marchi25985ed2011-03-30 22:57:33 -03001776 * if sequence is not contiguous, either clear everything
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777 * below low watermark and set start to the next frag or
1778 * clear start ptr.
Joe Perches475be4d2012-02-19 19:52:38 -08001779 */
1780 if (nextf != NULL &&
1781 ((thisseq + 1) & MP_LONGSEQ_MASK) == MP_SEQ(nextf)) {
1782 /* if we just reassembled and the next one is here,
David S. Millere29d4362009-11-15 22:23:47 -08001783 * then start another reassembly. */
1784
Joe Perches475be4d2012-02-19 19:52:38 -08001785 if (frag == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001786 if (MP_FLAGS(nextf) & MP_BEGIN_FRAG)
Joe Perches475be4d2012-02-19 19:52:38 -08001787 start = nextf;
David S. Millere29d4362009-11-15 22:23:47 -08001788 else
1789 {
Joe Perches475be4d2012-02-19 19:52:38 -08001790 printk(KERN_WARNING"isdn_mppp(seq %d):"
1791 " END flag with no following "
1792 "BEGIN", thisseq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793 stats->seqerrs++;
1794 }
1795 }
David S. Millere29d4362009-11-15 22:23:47 -08001796
Joe Perches475be4d2012-02-19 19:52:38 -08001797 } else {
1798 if (nextf != NULL && frag != NULL &&
1799 MP_LT(thisseq, minseq)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800 /* we've got a break in the sequence
1801 * and we not at the end yet
1802 * and we did not just reassembled
1803 *(if we did, there wouldn't be anything before)
Joe Perches475be4d2012-02-19 19:52:38 -08001804 * and we below the low watermark
1805 * discard all the frames below low watermark
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806 * and start over */
1807 stats->frame_drops++;
Joe Perches475be4d2012-02-19 19:52:38 -08001808 mp->frags = isdn_ppp_mp_discard(mp, start, nextf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809 }
1810 /* break in the sequence, no reassembly */
Joe Perches475be4d2012-02-19 19:52:38 -08001811 start = NULL;
1812 }
1813
1814 frag = nextf;
1815 } /* while -- main loop */
1816
1817 if (mp->frags == NULL)
1818 mp->frags = frag;
1819
1820 /* rather straighforward way to deal with (not very) possible
David S. Millere29d4362009-11-15 22:23:47 -08001821 * queue overflow */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822 if (mp->frames > MP_MAX_QUEUE_LEN) {
1823 stats->overflows++;
David S. Millere29d4362009-11-15 22:23:47 -08001824 while (mp->frames > MP_MAX_QUEUE_LEN) {
1825 frag = mp->frags->next;
1826 isdn_ppp_mp_free_skb(mp, mp->frags);
1827 mp->frags = frag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828 }
1829 }
1830 spin_unlock_irqrestore(&mp->lock, flags);
1831}
1832
Joe Perches475be4d2012-02-19 19:52:38 -08001833static void isdn_ppp_mp_cleanup(isdn_net_local *lp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834{
Joe Perches475be4d2012-02-19 19:52:38 -08001835 struct sk_buff *frag = lp->netdev->pb->frags;
1836 struct sk_buff *nextfrag;
1837 while (frag) {
David S. Millere29d4362009-11-15 22:23:47 -08001838 nextfrag = frag->next;
1839 isdn_ppp_mp_free_skb(lp->netdev->pb, frag);
1840 frag = nextfrag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841 }
David S. Millere29d4362009-11-15 22:23:47 -08001842 lp->netdev->pb->frags = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843}
1844
Joe Perches475be4d2012-02-19 19:52:38 -08001845static u32 isdn_ppp_mp_get_seq(int short_seq,
1846 struct sk_buff *skb, u32 last_seq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847{
1848 u32 seq;
1849 int flags = skb->data[0] & (MP_BEGIN_FRAG | MP_END_FRAG);
Joe Perches475be4d2012-02-19 19:52:38 -08001850
1851 if (!short_seq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852 {
Harvey Harrisonc19d0362008-11-20 04:10:51 -08001853 seq = ntohl(*(__be32 *)skb->data) & MP_LONGSEQ_MASK;
Joe Perches475be4d2012-02-19 19:52:38 -08001854 skb_push(skb, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 }
1856 else
1857 {
Joe Perches475be4d2012-02-19 19:52:38 -08001858 /* convert 12-bit short seq number to 24-bit long one
1859 */
Harvey Harrisonc19d0362008-11-20 04:10:51 -08001860 seq = ntohs(*(__be16 *)skb->data) & MP_SHORTSEQ_MASK;
Joe Perches475be4d2012-02-19 19:52:38 -08001861
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 /* check for seqence wrap */
Joe Perches475be4d2012-02-19 19:52:38 -08001863 if (!(seq & MP_SHORTSEQ_MAXBIT) &&
1864 (last_seq & MP_SHORTSEQ_MAXBIT) &&
1865 (unsigned long)last_seq <= MP_LONGSEQ_MAX)
1866 seq |= (last_seq + MP_SHORTSEQ_MAX + 1) &
1867 (~MP_SHORTSEQ_MASK & MP_LONGSEQ_MASK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 else
1869 seq |= last_seq & (~MP_SHORTSEQ_MASK & MP_LONGSEQ_MASK);
Joe Perches475be4d2012-02-19 19:52:38 -08001870
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871 skb_push(skb, 3); /* put converted seqence back in skb */
1872 }
Joe Perches475be4d2012-02-19 19:52:38 -08001873 *(u32 *)(skb->data + 1) = seq; /* put seqence back in _host_ byte
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874 * order */
1875 skb->data[0] = flags; /* restore flags */
1876 return seq;
1877}
1878
Joe Perches475be4d2012-02-19 19:52:38 -08001879struct sk_buff *isdn_ppp_mp_discard(ippp_bundle *mp,
1880 struct sk_buff *from, struct sk_buff *to)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881{
Joe Perches475be4d2012-02-19 19:52:38 -08001882 if (from)
David S. Millere29d4362009-11-15 22:23:47 -08001883 while (from != to) {
Joe Perches475be4d2012-02-19 19:52:38 -08001884 struct sk_buff *next = from->next;
David S. Millere29d4362009-11-15 22:23:47 -08001885 isdn_ppp_mp_free_skb(mp, from);
Joe Perches475be4d2012-02-19 19:52:38 -08001886 from = next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887 }
David S. Millere29d4362009-11-15 22:23:47 -08001888 return from;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889}
1890
Joe Perches475be4d2012-02-19 19:52:38 -08001891void isdn_ppp_mp_reassembly(isdn_net_dev *net_dev, isdn_net_local *lp,
1892 struct sk_buff *from, struct sk_buff *to)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893{
Joe Perches475be4d2012-02-19 19:52:38 -08001894 ippp_bundle *mp = net_dev->pb;
David S. Miller38783e62008-09-22 01:15:02 -07001895 int proto;
Joe Perches475be4d2012-02-19 19:52:38 -08001896 struct sk_buff *skb;
David S. Millere29d4362009-11-15 22:23:47 -08001897 unsigned int tot_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898
1899 if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
1900 printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
Joe Perches475be4d2012-02-19 19:52:38 -08001901 __func__, lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902 return;
1903 }
Joe Perches475be4d2012-02-19 19:52:38 -08001904 if (MP_FLAGS(from) == (MP_BEGIN_FRAG | MP_END_FRAG)) {
1905 if (ippp_table[lp->ppp_slot]->debug & 0x40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906 printk(KERN_DEBUG "isdn_mppp: reassembly: frame %d, "
Joe Perches475be4d2012-02-19 19:52:38 -08001907 "len %d\n", MP_SEQ(from), from->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908 skb = from;
1909 skb_pull(skb, MP_HEADER_LEN);
Joe Perches475be4d2012-02-19 19:52:38 -08001910 mp->frames--;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911 } else {
Joe Perches475be4d2012-02-19 19:52:38 -08001912 struct sk_buff *frag;
David S. Millere29d4362009-11-15 22:23:47 -08001913 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914
Joe Perches475be4d2012-02-19 19:52:38 -08001915 for (tot_len = n = 0, frag = from; frag != to; frag = frag->next, n++)
David S. Millere29d4362009-11-15 22:23:47 -08001916 tot_len += frag->len - MP_HEADER_LEN;
1917
Joe Perches475be4d2012-02-19 19:52:38 -08001918 if (ippp_table[lp->ppp_slot]->debug & 0x40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919 printk(KERN_DEBUG"isdn_mppp: reassembling frames %d "
Joe Perches475be4d2012-02-19 19:52:38 -08001920 "to %d, len %d\n", MP_SEQ(from),
1921 (MP_SEQ(from) + n - 1) & MP_LONGSEQ_MASK, tot_len);
1922 if ((skb = dev_alloc_skb(tot_len)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923 printk(KERN_ERR "isdn_mppp: cannot allocate sk buff "
Joe Perches475be4d2012-02-19 19:52:38 -08001924 "of size %d\n", tot_len);
David S. Millere29d4362009-11-15 22:23:47 -08001925 isdn_ppp_mp_discard(mp, from, to);
1926 return;
1927 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928
Joe Perches475be4d2012-02-19 19:52:38 -08001929 while (from != to) {
David S. Millere29d4362009-11-15 22:23:47 -08001930 unsigned int len = from->len - MP_HEADER_LEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931
David S. Millere29d4362009-11-15 22:23:47 -08001932 skb_copy_from_linear_data_offset(from, MP_HEADER_LEN,
Joe Perches475be4d2012-02-19 19:52:38 -08001933 skb_put(skb, len),
David S. Millere29d4362009-11-15 22:23:47 -08001934 len);
1935 frag = from->next;
1936 isdn_ppp_mp_free_skb(mp, from);
Joe Perches475be4d2012-02-19 19:52:38 -08001937 from = frag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938 }
1939 }
Joe Perches475be4d2012-02-19 19:52:38 -08001940 proto = isdn_ppp_strip_proto(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001941 isdn_ppp_push_higher(net_dev, lp, skb, proto);
1942}
1943
Joe Perches475be4d2012-02-19 19:52:38 -08001944static void isdn_ppp_mp_free_skb(ippp_bundle *mp, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945{
1946 dev_kfree_skb(skb);
1947 mp->frames--;
1948}
1949
Joe Perches475be4d2012-02-19 19:52:38 -08001950static void isdn_ppp_mp_print_recv_pkt(int slot, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001951{
Joe Perches475be4d2012-02-19 19:52:38 -08001952 printk(KERN_DEBUG "mp_recv: %d/%d -> %02x %02x %02x %02x %02x %02x\n",
1953 slot, (int) skb->len,
1954 (int) skb->data[0], (int) skb->data[1], (int) skb->data[2],
1955 (int) skb->data[3], (int) skb->data[4], (int) skb->data[5]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956}
1957
1958static int
1959isdn_ppp_bundle(struct ippp_struct *is, int unit)
1960{
1961 char ifn[IFNAMSIZ + 1];
1962 isdn_net_dev *p;
1963 isdn_net_local *lp, *nlp;
1964 int rc;
1965 unsigned long flags;
1966
1967 sprintf(ifn, "ippp%d", unit);
1968 p = isdn_net_findif(ifn);
1969 if (!p) {
1970 printk(KERN_ERR "ippp_bundle: cannot find %s\n", ifn);
1971 return -EINVAL;
1972 }
1973
Joe Perches475be4d2012-02-19 19:52:38 -08001974 spin_lock_irqsave(&p->pb->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001975
1976 nlp = is->lp;
1977 lp = p->queue;
Joe Perches475be4d2012-02-19 19:52:38 -08001978 if (nlp->ppp_slot < 0 || nlp->ppp_slot >= ISDN_MAX_CHANNELS ||
1979 lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980 printk(KERN_ERR "ippp_bundle: binding to invalid slot %d\n",
Joe Perches475be4d2012-02-19 19:52:38 -08001981 nlp->ppp_slot < 0 || nlp->ppp_slot >= ISDN_MAX_CHANNELS ?
1982 nlp->ppp_slot : lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983 rc = -EINVAL;
1984 goto out;
Joe Perches475be4d2012-02-19 19:52:38 -08001985 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001986
1987 isdn_net_add_to_bundle(p, nlp);
1988
1989 ippp_table[nlp->ppp_slot]->unit = ippp_table[lp->ppp_slot]->unit;
1990
1991 /* maybe also SC_CCP stuff */
1992 ippp_table[nlp->ppp_slot]->pppcfg |= ippp_table[lp->ppp_slot]->pppcfg &
1993 (SC_ENABLE_IP | SC_NO_TCP_CCID | SC_REJ_COMP_TCP);
1994 ippp_table[nlp->ppp_slot]->mpppcfg |= ippp_table[lp->ppp_slot]->mpppcfg &
1995 (SC_MP_PROT | SC_REJ_MP_PROT | SC_OUT_SHORT_SEQ | SC_IN_SHORT_SEQ);
1996 rc = isdn_ppp_mp_init(nlp, p->pb);
1997out:
1998 spin_unlock_irqrestore(&p->pb->lock, flags);
1999 return rc;
2000}
Joe Perches475be4d2012-02-19 19:52:38 -08002001
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002#endif /* CONFIG_ISDN_MPP */
Joe Perches475be4d2012-02-19 19:52:38 -08002003
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004/*
2005 * network device ioctl handlers
2006 */
2007
2008static int
2009isdn_ppp_dev_ioctl_stats(int slot, struct ifreq *ifr, struct net_device *dev)
2010{
2011 struct ppp_stats __user *res = ifr->ifr_data;
2012 struct ppp_stats t;
Joe Perchesa17531f2010-11-15 11:12:24 +00002013 isdn_net_local *lp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014
2015 if (!access_ok(VERIFY_WRITE, res, sizeof(struct ppp_stats)))
2016 return -EFAULT;
2017
2018 /* build a temporary stat struct and copy it to user space */
2019
2020 memset(&t, 0, sizeof(struct ppp_stats));
2021 if (dev->flags & IFF_UP) {
2022 t.p.ppp_ipackets = lp->stats.rx_packets;
2023 t.p.ppp_ibytes = lp->stats.rx_bytes;
2024 t.p.ppp_ierrors = lp->stats.rx_errors;
2025 t.p.ppp_opackets = lp->stats.tx_packets;
2026 t.p.ppp_obytes = lp->stats.tx_bytes;
2027 t.p.ppp_oerrors = lp->stats.tx_errors;
2028#ifdef CONFIG_ISDN_PPP_VJ
2029 if (slot >= 0 && ippp_table[slot]->slcomp) {
2030 struct slcompress *slcomp = ippp_table[slot]->slcomp;
2031 t.vj.vjs_packets = slcomp->sls_o_compressed + slcomp->sls_o_uncompressed;
2032 t.vj.vjs_compressed = slcomp->sls_o_compressed;
2033 t.vj.vjs_searches = slcomp->sls_o_searches;
2034 t.vj.vjs_misses = slcomp->sls_o_misses;
2035 t.vj.vjs_errorin = slcomp->sls_i_error;
2036 t.vj.vjs_tossed = slcomp->sls_i_tossed;
2037 t.vj.vjs_uncompressedin = slcomp->sls_i_uncompressed;
2038 t.vj.vjs_compressedin = slcomp->sls_i_compressed;
2039 }
2040#endif
2041 }
2042 if (copy_to_user(res, &t, sizeof(struct ppp_stats)))
2043 return -EFAULT;
2044 return 0;
2045}
2046
2047int
2048isdn_ppp_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
2049{
Joe Perches475be4d2012-02-19 19:52:38 -08002050 int error = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002051 int len;
Joe Perchesa17531f2010-11-15 11:12:24 +00002052 isdn_net_local *lp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053
2054
2055 if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP)
2056 return -EINVAL;
2057
2058 switch (cmd) {
2059#define PPP_VERSION "2.3.7"
Joe Perches475be4d2012-02-19 19:52:38 -08002060 case SIOCGPPPVER:
2061 len = strlen(PPP_VERSION) + 1;
2062 if (copy_to_user(ifr->ifr_data, PPP_VERSION, len))
2063 error = -EFAULT;
2064 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002065
Joe Perches475be4d2012-02-19 19:52:38 -08002066 case SIOCGPPPSTATS:
2067 error = isdn_ppp_dev_ioctl_stats(lp->ppp_slot, ifr, dev);
2068 break;
2069 default:
2070 error = -EINVAL;
2071 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002072 }
2073 return error;
2074}
2075
2076static int
2077isdn_ppp_if_get_unit(char *name)
2078{
2079 int len,
Joe Perches475be4d2012-02-19 19:52:38 -08002080 i,
2081 unit = 0,
2082 deci;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002083
2084 len = strlen(name);
2085
2086 if (strncmp("ippp", name, 4) || len > 8)
2087 return -1;
2088
2089 for (i = 0, deci = 1; i < len; i++, deci *= 10) {
2090 char a = name[len - i - 1];
2091 if (a >= '0' && a <= '9')
2092 unit += (a - '0') * deci;
2093 else
2094 break;
2095 }
2096 if (!i || len - i != 4)
2097 unit = -1;
2098
2099 return unit;
2100}
2101
2102
2103int
2104isdn_ppp_dial_slave(char *name)
2105{
2106#ifdef CONFIG_ISDN_MPP
2107 isdn_net_dev *ndev;
2108 isdn_net_local *lp;
2109 struct net_device *sdev;
2110
2111 if (!(ndev = isdn_net_findif(name)))
2112 return 1;
2113 lp = ndev->local;
2114 if (!(lp->flags & ISDN_NET_CONNECTED))
2115 return 5;
2116
2117 sdev = lp->slave;
2118 while (sdev) {
Joe Perchesa17531f2010-11-15 11:12:24 +00002119 isdn_net_local *mlp = netdev_priv(sdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120 if (!(mlp->flags & ISDN_NET_CONNECTED))
2121 break;
2122 sdev = mlp->slave;
2123 }
2124 if (!sdev)
2125 return 2;
2126
Joe Perchesa17531f2010-11-15 11:12:24 +00002127 isdn_net_dial_req(netdev_priv(sdev));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128 return 0;
2129#else
2130 return -1;
2131#endif
2132}
2133
2134int
2135isdn_ppp_hangup_slave(char *name)
2136{
2137#ifdef CONFIG_ISDN_MPP
2138 isdn_net_dev *ndev;
2139 isdn_net_local *lp;
2140 struct net_device *sdev;
2141
2142 if (!(ndev = isdn_net_findif(name)))
2143 return 1;
2144 lp = ndev->local;
2145 if (!(lp->flags & ISDN_NET_CONNECTED))
2146 return 5;
2147
2148 sdev = lp->slave;
2149 while (sdev) {
Joe Perchesa17531f2010-11-15 11:12:24 +00002150 isdn_net_local *mlp = netdev_priv(sdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002151
2152 if (mlp->slave) { /* find last connected link in chain */
Wang Chen838361f2008-12-03 15:49:46 -08002153 isdn_net_local *nlp = ISDN_SLAVE_PRIV(mlp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154
2155 if (!(nlp->flags & ISDN_NET_CONNECTED))
2156 break;
2157 } else if (mlp->flags & ISDN_NET_CONNECTED)
2158 break;
Joe Perches475be4d2012-02-19 19:52:38 -08002159
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160 sdev = mlp->slave;
2161 }
2162 if (!sdev)
2163 return 2;
2164
2165 isdn_net_hangup(sdev);
2166 return 0;
2167#else
2168 return -1;
2169#endif
2170}
2171
2172/*
2173 * PPP compression stuff
2174 */
2175
2176
2177/* Push an empty CCP Data Frame up to the daemon to wake it up and let it
2178 generate a CCP Reset-Request or tear down CCP altogether */
2179
2180static void isdn_ppp_ccp_kickup(struct ippp_struct *is)
2181{
2182 isdn_ppp_fill_rq(NULL, 0, PPP_COMP, is->lp->ppp_slot);
2183}
2184
2185/* In-kernel handling of CCP Reset-Request and Reset-Ack is necessary,
2186 but absolutely nontrivial. The most abstruse problem we are facing is
2187 that the generation, reception and all the handling of timeouts and
2188 resends including proper request id management should be entirely left
2189 to the (de)compressor, but indeed is not covered by the current API to
2190 the (de)compressor. The API is a prototype version from PPP where only
2191 some (de)compressors have yet been implemented and all of them are
2192 rather simple in their reset handling. Especially, their is only one
2193 outstanding ResetAck at a time with all of them and ResetReq/-Acks do
2194 not have parameters. For this very special case it was sufficient to
2195 just return an error code from the decompressor and have a single
2196 reset() entry to communicate all the necessary information between
2197 the framework and the (de)compressor. Bad enough, LZS is different
2198 (and any other compressor may be different, too). It has multiple
2199 histories (eventually) and needs to Reset each of them independently
2200 and thus uses multiple outstanding Acks and history numbers as an
2201 additional parameter to Reqs/Acks.
2202 All that makes it harder to port the reset state engine into the
2203 kernel because it is not just the same simple one as in (i)pppd but
2204 it must be able to pass additional parameters and have multiple out-
2205 standing Acks. We are trying to achieve the impossible by handling
2206 reset transactions independent by their id. The id MUST change when
2207 the data portion changes, thus any (de)compressor who uses more than
2208 one resettable state must provide and recognize individual ids for
2209 each individual reset transaction. The framework itself does _only_
2210 differentiate them by id, because it has no other semantics like the
2211 (de)compressor might.
2212 This looks like a major redesign of the interface would be nice,
2213 but I don't have an idea how to do it better. */
2214
2215/* Send a CCP Reset-Request or Reset-Ack directly from the kernel. This is
2216 getting that lengthy because there is no simple "send-this-frame-out"
2217 function above but every wrapper does a bit different. Hope I guess
2218 correct in this hack... */
2219
2220static void isdn_ppp_ccp_xmit_reset(struct ippp_struct *is, int proto,
2221 unsigned char code, unsigned char id,
2222 unsigned char *data, int len)
2223{
2224 struct sk_buff *skb;
2225 unsigned char *p;
2226 int hl;
2227 int cnt = 0;
2228 isdn_net_local *lp = is->lp;
2229
2230 /* Alloc large enough skb */
2231 hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen;
Joe Perches475be4d2012-02-19 19:52:38 -08002232 skb = alloc_skb(len + hl + 16, GFP_ATOMIC);
2233 if (!skb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234 printk(KERN_WARNING
2235 "ippp: CCP cannot send reset - out of memory\n");
2236 return;
2237 }
2238 skb_reserve(skb, hl);
2239
2240 /* We may need to stuff an address and control field first */
Joe Perches475be4d2012-02-19 19:52:38 -08002241 if (!(is->pppcfg & SC_COMP_AC)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242 p = skb_put(skb, 2);
2243 *p++ = 0xff;
2244 *p++ = 0x03;
2245 }
2246
2247 /* Stuff proto, code, id and length */
2248 p = skb_put(skb, 6);
2249 *p++ = (proto >> 8);
2250 *p++ = (proto & 0xff);
2251 *p++ = code;
2252 *p++ = id;
2253 cnt = 4 + len;
2254 *p++ = (cnt >> 8);
2255 *p++ = (cnt & 0xff);
2256
2257 /* Now stuff remaining bytes */
Joe Perches475be4d2012-02-19 19:52:38 -08002258 if (len) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259 p = skb_put(skb, len);
2260 memcpy(p, data, len);
2261 }
2262
2263 /* skb is now ready for xmit */
2264 printk(KERN_DEBUG "Sending CCP Frame:\n");
Joe Perches475be4d2012-02-19 19:52:38 -08002265 isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit, lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266
2267 isdn_net_write_super(lp, skb);
2268}
2269
2270/* Allocate the reset state vector */
2271static struct ippp_ccp_reset *isdn_ppp_ccp_reset_alloc(struct ippp_struct *is)
2272{
2273 struct ippp_ccp_reset *r;
Burman Yan41f96932006-12-08 02:39:35 -08002274 r = kzalloc(sizeof(struct ippp_ccp_reset), GFP_KERNEL);
Joe Perches475be4d2012-02-19 19:52:38 -08002275 if (!r) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002276 printk(KERN_ERR "ippp_ccp: failed to allocate reset data"
2277 " structure - no mem\n");
2278 return NULL;
2279 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002280 printk(KERN_DEBUG "ippp_ccp: allocated reset data structure %p\n", r);
2281 is->reset = r;
2282 return r;
2283}
2284
2285/* Destroy the reset state vector. Kill all pending timers first. */
2286static void isdn_ppp_ccp_reset_free(struct ippp_struct *is)
2287{
2288 unsigned int id;
2289
2290 printk(KERN_DEBUG "ippp_ccp: freeing reset data structure %p\n",
2291 is->reset);
Joe Perches475be4d2012-02-19 19:52:38 -08002292 for (id = 0; id < 256; id++) {
2293 if (is->reset->rs[id]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002294 isdn_ppp_ccp_reset_free_state(is, (unsigned char)id);
2295 }
2296 }
2297 kfree(is->reset);
2298 is->reset = NULL;
2299}
2300
2301/* Free a given state and clear everything up for later reallocation */
2302static void isdn_ppp_ccp_reset_free_state(struct ippp_struct *is,
2303 unsigned char id)
2304{
2305 struct ippp_ccp_reset_state *rs;
2306
Joe Perches475be4d2012-02-19 19:52:38 -08002307 if (is->reset->rs[id]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308 printk(KERN_DEBUG "ippp_ccp: freeing state for id %d\n", id);
2309 rs = is->reset->rs[id];
2310 /* Make sure the kernel will not call back later */
Joe Perches475be4d2012-02-19 19:52:38 -08002311 if (rs->ta)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312 del_timer(&rs->timer);
2313 is->reset->rs[id] = NULL;
2314 kfree(rs);
2315 } else {
2316 printk(KERN_WARNING "ippp_ccp: id %d is not allocated\n", id);
2317 }
2318}
2319
2320/* The timer callback function which is called when a ResetReq has timed out,
2321 aka has never been answered by a ResetAck */
2322static void isdn_ppp_ccp_timer_callback(unsigned long closure)
2323{
2324 struct ippp_ccp_reset_state *rs =
2325 (struct ippp_ccp_reset_state *)closure;
2326
Joe Perches475be4d2012-02-19 19:52:38 -08002327 if (!rs) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002328 printk(KERN_ERR "ippp_ccp: timer cb with zero closure.\n");
2329 return;
2330 }
Joe Perches475be4d2012-02-19 19:52:38 -08002331 if (rs->ta && rs->state == CCPResetSentReq) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002332 /* We are correct here */
Joe Perches475be4d2012-02-19 19:52:38 -08002333 if (!rs->expra) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002334 /* Hmm, there is no Ack really expected. We can clean
2335 up the state now, it will be reallocated if the
2336 decompressor insists on another reset */
2337 rs->ta = 0;
2338 isdn_ppp_ccp_reset_free_state(rs->is, rs->id);
2339 return;
2340 }
2341 printk(KERN_DEBUG "ippp_ccp: CCP Reset timed out for id %d\n",
2342 rs->id);
2343 /* Push it again */
2344 isdn_ppp_ccp_xmit_reset(rs->is, PPP_CCP, CCP_RESETREQ, rs->id,
2345 rs->data, rs->dlen);
2346 /* Restart timer */
Joe Perches475be4d2012-02-19 19:52:38 -08002347 rs->timer.expires = jiffies + HZ * 5;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002348 add_timer(&rs->timer);
2349 } else {
2350 printk(KERN_WARNING "ippp_ccp: timer cb in wrong state %d\n",
2351 rs->state);
2352 }
2353}
2354
2355/* Allocate a new reset transaction state */
2356static struct ippp_ccp_reset_state *isdn_ppp_ccp_reset_alloc_state(struct ippp_struct *is,
Joe Perches475be4d2012-02-19 19:52:38 -08002357 unsigned char id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002358{
2359 struct ippp_ccp_reset_state *rs;
Joe Perches475be4d2012-02-19 19:52:38 -08002360 if (is->reset->rs[id]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002361 printk(KERN_WARNING "ippp_ccp: old state exists for id %d\n",
2362 id);
2363 return NULL;
2364 } else {
Burman Yan41f96932006-12-08 02:39:35 -08002365 rs = kzalloc(sizeof(struct ippp_ccp_reset_state), GFP_KERNEL);
Joe Perches475be4d2012-02-19 19:52:38 -08002366 if (!rs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002367 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002368 rs->state = CCPResetIdle;
2369 rs->is = is;
2370 rs->id = id;
Marcel Holtmanndab6df62006-12-21 23:06:24 +01002371 init_timer(&rs->timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002372 rs->timer.data = (unsigned long)rs;
2373 rs->timer.function = isdn_ppp_ccp_timer_callback;
2374 is->reset->rs[id] = rs;
2375 }
2376 return rs;
2377}
2378
2379
2380/* A decompressor wants a reset with a set of parameters - do what is
2381 necessary to fulfill it */
2382static void isdn_ppp_ccp_reset_trans(struct ippp_struct *is,
2383 struct isdn_ppp_resetparams *rp)
2384{
2385 struct ippp_ccp_reset_state *rs;
2386
Joe Perches475be4d2012-02-19 19:52:38 -08002387 if (rp->valid) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002388 /* The decompressor defines parameters by itself */
Joe Perches475be4d2012-02-19 19:52:38 -08002389 if (rp->rsend) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002390 /* And he wants us to send a request */
Joe Perches475be4d2012-02-19 19:52:38 -08002391 if (!(rp->idval)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002392 printk(KERN_ERR "ippp_ccp: decompressor must"
2393 " specify reset id\n");
2394 return;
2395 }
Joe Perches475be4d2012-02-19 19:52:38 -08002396 if (is->reset->rs[rp->id]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397 /* There is already a transaction in existence
2398 for this id. May be still waiting for a
2399 Ack or may be wrong. */
2400 rs = is->reset->rs[rp->id];
Joe Perches475be4d2012-02-19 19:52:38 -08002401 if (rs->state == CCPResetSentReq && rs->ta) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002402 printk(KERN_DEBUG "ippp_ccp: reset"
2403 " trans still in progress"
2404 " for id %d\n", rp->id);
2405 } else {
2406 printk(KERN_WARNING "ippp_ccp: reset"
2407 " trans in wrong state %d for"
2408 " id %d\n", rs->state, rp->id);
2409 }
2410 } else {
2411 /* Ok, this is a new transaction */
2412 printk(KERN_DEBUG "ippp_ccp: new trans for id"
2413 " %d to be started\n", rp->id);
2414 rs = isdn_ppp_ccp_reset_alloc_state(is, rp->id);
Joe Perches475be4d2012-02-19 19:52:38 -08002415 if (!rs) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002416 printk(KERN_ERR "ippp_ccp: out of mem"
2417 " allocing ccp trans\n");
2418 return;
2419 }
2420 rs->state = CCPResetSentReq;
2421 rs->expra = rp->expra;
Joe Perches475be4d2012-02-19 19:52:38 -08002422 if (rp->dtval) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002423 rs->dlen = rp->dlen;
2424 memcpy(rs->data, rp->data, rp->dlen);
2425 }
2426 /* HACK TODO - add link comp here */
2427 isdn_ppp_ccp_xmit_reset(is, PPP_CCP,
2428 CCP_RESETREQ, rs->id,
2429 rs->data, rs->dlen);
2430 /* Start the timer */
Joe Perches475be4d2012-02-19 19:52:38 -08002431 rs->timer.expires = jiffies + 5 * HZ;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002432 add_timer(&rs->timer);
2433 rs->ta = 1;
2434 }
2435 } else {
2436 printk(KERN_DEBUG "ippp_ccp: no reset sent\n");
2437 }
2438 } else {
2439 /* The reset params are invalid. The decompressor does not
2440 care about them, so we just send the minimal requests
2441 and increase ids only when an Ack is received for a
2442 given id */
Joe Perches475be4d2012-02-19 19:52:38 -08002443 if (is->reset->rs[is->reset->lastid]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002444 /* There is already a transaction in existence
2445 for this id. May be still waiting for a
2446 Ack or may be wrong. */
2447 rs = is->reset->rs[is->reset->lastid];
Joe Perches475be4d2012-02-19 19:52:38 -08002448 if (rs->state == CCPResetSentReq && rs->ta) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002449 printk(KERN_DEBUG "ippp_ccp: reset"
2450 " trans still in progress"
2451 " for id %d\n", rp->id);
2452 } else {
2453 printk(KERN_WARNING "ippp_ccp: reset"
2454 " trans in wrong state %d for"
2455 " id %d\n", rs->state, rp->id);
2456 }
2457 } else {
2458 printk(KERN_DEBUG "ippp_ccp: new trans for id"
2459 " %d to be started\n", is->reset->lastid);
2460 rs = isdn_ppp_ccp_reset_alloc_state(is,
2461 is->reset->lastid);
Joe Perches475be4d2012-02-19 19:52:38 -08002462 if (!rs) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002463 printk(KERN_ERR "ippp_ccp: out of mem"
2464 " allocing ccp trans\n");
2465 return;
2466 }
2467 rs->state = CCPResetSentReq;
2468 /* We always expect an Ack if the decompressor doesn't
2469 know better */
2470 rs->expra = 1;
2471 rs->dlen = 0;
2472 /* HACK TODO - add link comp here */
2473 isdn_ppp_ccp_xmit_reset(is, PPP_CCP, CCP_RESETREQ,
2474 rs->id, NULL, 0);
2475 /* Start the timer */
Joe Perches475be4d2012-02-19 19:52:38 -08002476 rs->timer.expires = jiffies + 5 * HZ;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002477 add_timer(&rs->timer);
2478 rs->ta = 1;
2479 }
2480 }
2481}
2482
2483/* An Ack was received for this id. This means we stop the timer and clean
2484 up the state prior to calling the decompressors reset routine. */
2485static void isdn_ppp_ccp_reset_ack_rcvd(struct ippp_struct *is,
2486 unsigned char id)
2487{
2488 struct ippp_ccp_reset_state *rs = is->reset->rs[id];
2489
Joe Perches475be4d2012-02-19 19:52:38 -08002490 if (rs) {
2491 if (rs->ta && rs->state == CCPResetSentReq) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492 /* Great, we are correct */
Joe Perches475be4d2012-02-19 19:52:38 -08002493 if (!rs->expra)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002494 printk(KERN_DEBUG "ippp_ccp: ResetAck received"
2495 " for id %d but not expected\n", id);
2496 } else {
2497 printk(KERN_INFO "ippp_ccp: ResetAck received out of"
2498 "sync for id %d\n", id);
2499 }
Joe Perches475be4d2012-02-19 19:52:38 -08002500 if (rs->ta) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002501 rs->ta = 0;
2502 del_timer(&rs->timer);
2503 }
2504 isdn_ppp_ccp_reset_free_state(is, id);
2505 } else {
2506 printk(KERN_INFO "ippp_ccp: ResetAck received for unknown id"
2507 " %d\n", id);
2508 }
2509 /* Make sure the simple reset stuff uses a new id next time */
2510 is->reset->lastid++;
2511}
2512
Joe Perches475be4d2012-02-19 19:52:38 -08002513/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514 * decompress packet
2515 *
2516 * if master = 0, we're trying to uncompress an per-link compressed packet,
2517 * as opposed to an compressed reconstructed-from-MPPP packet.
2518 * proto is updated to protocol field of uncompressed packet.
2519 *
2520 * retval: decompressed packet,
2521 * same packet if uncompressed,
2522 * NULL if decompression error
2523 */
2524
Joe Perches475be4d2012-02-19 19:52:38 -08002525static struct sk_buff *isdn_ppp_decompress(struct sk_buff *skb, struct ippp_struct *is, struct ippp_struct *master,
2526 int *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002527{
2528 void *stat = NULL;
2529 struct isdn_ppp_compressor *ipc = NULL;
2530 struct sk_buff *skb_out;
2531 int len;
2532 struct ippp_struct *ri;
2533 struct isdn_ppp_resetparams rsparm;
2534 unsigned char rsdata[IPPP_RESET_MAXDATABYTES];
2535
Joe Perches475be4d2012-02-19 19:52:38 -08002536 if (!master) {
2537 // per-link decompression
Linus Torvalds1da177e2005-04-16 15:20:36 -07002538 stat = is->link_decomp_stat;
2539 ipc = is->link_decompressor;
2540 ri = is;
2541 } else {
2542 stat = master->decomp_stat;
2543 ipc = master->decompressor;
2544 ri = master;
2545 }
2546
2547 if (!ipc) {
2548 // no decompressor -> we can't decompress.
2549 printk(KERN_DEBUG "ippp: no decompressor defined!\n");
2550 return skb;
2551 }
Eric Sesterhenn6dd44a7442006-03-26 18:19:26 +02002552 BUG_ON(!stat); // if we have a compressor, stat has been set as well
Linus Torvalds1da177e2005-04-16 15:20:36 -07002553
Joe Perches475be4d2012-02-19 19:52:38 -08002554 if ((master && *proto == PPP_COMP) || (!master && *proto == PPP_COMPFRAG)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002555 // compressed packets are compressed by their protocol type
2556
2557 // Set up reset params for the decompressor
Joe Perches475be4d2012-02-19 19:52:38 -08002558 memset(&rsparm, 0, sizeof(rsparm));
2559 rsparm.data = rsdata;
2560 rsparm.maxdlen = IPPP_RESET_MAXDATABYTES;
2561
2562 skb_out = dev_alloc_skb(is->mru + PPP_HDRLEN);
2563 if (!skb_out) {
2564 kfree_skb(skb);
2565 printk(KERN_ERR "ippp: decomp memory allocation failure\n");
Jesper Juhlf6e2cdc2006-12-08 02:39:34 -08002566 return NULL;
Joe Perches475be4d2012-02-19 19:52:38 -08002567 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002568 len = ipc->decompress(stat, skb, skb_out, &rsparm);
2569 kfree_skb(skb);
2570 if (len <= 0) {
Joe Perches475be4d2012-02-19 19:52:38 -08002571 switch (len) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572 case DECOMP_ERROR:
2573 printk(KERN_INFO "ippp: decomp wants reset %s params\n",
2574 rsparm.valid ? "with" : "without");
Joe Perches475be4d2012-02-19 19:52:38 -08002575
Linus Torvalds1da177e2005-04-16 15:20:36 -07002576 isdn_ppp_ccp_reset_trans(ri, &rsparm);
2577 break;
2578 case DECOMP_FATALERROR:
2579 ri->pppcfg |= SC_DC_FERROR;
2580 /* Kick ipppd to recognize the error */
2581 isdn_ppp_ccp_kickup(ri);
2582 break;
2583 }
2584 kfree_skb(skb_out);
2585 return NULL;
2586 }
2587 *proto = isdn_ppp_strip_proto(skb_out);
2588 if (*proto < 0) {
2589 kfree_skb(skb_out);
2590 return NULL;
2591 }
2592 return skb_out;
Joe Perches475be4d2012-02-19 19:52:38 -08002593 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002594 // uncompressed packets are fed through the decompressor to
2595 // update the decompressor state
2596 ipc->incomp(stat, skb, *proto);
2597 return skb;
2598 }
2599}
2600
2601/*
Joe Perches475be4d2012-02-19 19:52:38 -08002602 * compress a frame
Linus Torvalds1da177e2005-04-16 15:20:36 -07002603 * type=0: normal/bundle compression
2604 * =1: link compression
2605 * returns original skb if we haven't compressed the frame
2606 * and a new skb pointer if we've done it
2607 */
Joe Perches475be4d2012-02-19 19:52:38 -08002608static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in, int *proto,
2609 struct ippp_struct *is, struct ippp_struct *master, int type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610{
Joe Perches475be4d2012-02-19 19:52:38 -08002611 int ret;
2612 int new_proto;
2613 struct isdn_ppp_compressor *compressor;
2614 void *stat;
2615 struct sk_buff *skb_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002616
2617 /* we do not compress control protocols */
Joe Perches475be4d2012-02-19 19:52:38 -08002618 if (*proto < 0 || *proto > 0x3fff) {
2619 return skb_in;
2620 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621
Joe Perches475be4d2012-02-19 19:52:38 -08002622 if (type) { /* type=1 => Link compression */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002623 return skb_in;
2624 }
2625 else {
Joe Perches475be4d2012-02-19 19:52:38 -08002626 if (!master) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002627 compressor = is->compressor;
2628 stat = is->comp_stat;
2629 }
2630 else {
2631 compressor = master->compressor;
2632 stat = master->comp_stat;
2633 }
2634 new_proto = PPP_COMP;
2635 }
2636
Joe Perches475be4d2012-02-19 19:52:38 -08002637 if (!compressor) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002638 printk(KERN_ERR "isdn_ppp: No compressor set!\n");
2639 return skb_in;
2640 }
Joe Perches475be4d2012-02-19 19:52:38 -08002641 if (!stat) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642 printk(KERN_ERR "isdn_ppp: Compressor not initialized?\n");
2643 return skb_in;
2644 }
2645
2646 /* Allow for at least 150 % expansion (for now) */
Joe Perches475be4d2012-02-19 19:52:38 -08002647 skb_out = alloc_skb(skb_in->len + skb_in->len / 2 + 32 +
2648 skb_headroom(skb_in), GFP_ATOMIC);
2649 if (!skb_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650 return skb_in;
2651 skb_reserve(skb_out, skb_headroom(skb_in));
2652
Joe Perches475be4d2012-02-19 19:52:38 -08002653 ret = (compressor->compress)(stat, skb_in, skb_out, *proto);
2654 if (!ret) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655 dev_kfree_skb(skb_out);
2656 return skb_in;
2657 }
Joe Perches475be4d2012-02-19 19:52:38 -08002658
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659 dev_kfree_skb(skb_in);
2660 *proto = new_proto;
2661 return skb_out;
2662}
2663
2664/*
Joe Perches475be4d2012-02-19 19:52:38 -08002665 * we received a CCP frame ..
Linus Torvalds1da177e2005-04-16 15:20:36 -07002666 * not a clean solution, but we MUST handle a few cases in the kernel
2667 */
2668static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp,
Joe Perches475be4d2012-02-19 19:52:38 -08002669 struct sk_buff *skb, int proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670{
2671 struct ippp_struct *is;
2672 struct ippp_struct *mis;
2673 int len;
2674 struct isdn_ppp_resetparams rsparm;
Joe Perches475be4d2012-02-19 19:52:38 -08002675 unsigned char rsdata[IPPP_RESET_MAXDATABYTES];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002676
2677 printk(KERN_DEBUG "Received CCP frame from peer slot(%d)\n",
Joe Perches475be4d2012-02-19 19:52:38 -08002678 lp->ppp_slot);
Eric Sesterhenn052bb882006-04-11 17:29:17 -07002679 if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680 printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
Joe Perches475be4d2012-02-19 19:52:38 -08002681 __func__, lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002682 return;
2683 }
2684 is = ippp_table[lp->ppp_slot];
Joe Perches475be4d2012-02-19 19:52:38 -08002685 isdn_ppp_frame_log("ccp-rcv", skb->data, skb->len, 32, is->unit, lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002686
Joe Perches475be4d2012-02-19 19:52:38 -08002687 if (lp->master) {
Wang Chen838361f2008-12-03 15:49:46 -08002688 int slot = ISDN_MASTER_PRIV(lp)->ppp_slot;
Eric Sesterhenn052bb882006-04-11 17:29:17 -07002689 if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690 printk(KERN_ERR "%s: slot(%d) out of range\n",
Joe Perches475be4d2012-02-19 19:52:38 -08002691 __func__, slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692 return;
Joe Perches475be4d2012-02-19 19:52:38 -08002693 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694 mis = ippp_table[slot];
2695 } else
2696 mis = is;
2697
Joe Perches475be4d2012-02-19 19:52:38 -08002698 switch (skb->data[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699 case CCP_CONFREQ:
Joe Perches475be4d2012-02-19 19:52:38 -08002700 if (is->debug & 0x10)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701 printk(KERN_DEBUG "Disable compression here!\n");
Joe Perches475be4d2012-02-19 19:52:38 -08002702 if (proto == PPP_CCP)
2703 mis->compflags &= ~SC_COMP_ON;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704 else
Joe Perches475be4d2012-02-19 19:52:38 -08002705 is->compflags &= ~SC_LINK_COMP_ON;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706 break;
2707 case CCP_TERMREQ:
2708 case CCP_TERMACK:
Joe Perches475be4d2012-02-19 19:52:38 -08002709 if (is->debug & 0x10)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002710 printk(KERN_DEBUG "Disable (de)compression here!\n");
Joe Perches475be4d2012-02-19 19:52:38 -08002711 if (proto == PPP_CCP)
2712 mis->compflags &= ~(SC_DECOMP_ON | SC_COMP_ON);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002713 else
Joe Perches475be4d2012-02-19 19:52:38 -08002714 is->compflags &= ~(SC_LINK_DECOMP_ON | SC_LINK_COMP_ON);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715 break;
2716 case CCP_CONFACK:
2717 /* if we RECEIVE an ackowledge we enable the decompressor */
Joe Perches475be4d2012-02-19 19:52:38 -08002718 if (is->debug & 0x10)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719 printk(KERN_DEBUG "Enable decompression here!\n");
Joe Perches475be4d2012-02-19 19:52:38 -08002720 if (proto == PPP_CCP) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002721 if (!mis->decompressor)
2722 break;
2723 mis->compflags |= SC_DECOMP_ON;
2724 } else {
2725 if (!is->decompressor)
2726 break;
2727 is->compflags |= SC_LINK_DECOMP_ON;
2728 }
2729 break;
2730
2731 case CCP_RESETACK:
2732 printk(KERN_DEBUG "Received ResetAck from peer\n");
2733 len = (skb->data[2] << 8) | skb->data[3];
2734 len -= 4;
2735
Joe Perches475be4d2012-02-19 19:52:38 -08002736 if (proto == PPP_CCP) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737 /* If a reset Ack was outstanding for this id, then
2738 clean up the state engine */
2739 isdn_ppp_ccp_reset_ack_rcvd(mis, skb->data[1]);
Joe Perches475be4d2012-02-19 19:52:38 -08002740 if (mis->decompressor && mis->decomp_stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002741 mis->decompressor->
2742 reset(mis->decomp_stat,
2743 skb->data[0],
2744 skb->data[1],
2745 len ? &skb->data[4] : NULL,
2746 len, NULL);
2747 /* TODO: This is not easy to decide here */
2748 mis->compflags &= ~SC_DECOMP_DISCARD;
2749 }
2750 else {
2751 isdn_ppp_ccp_reset_ack_rcvd(is, skb->data[1]);
Joe Perches475be4d2012-02-19 19:52:38 -08002752 if (is->link_decompressor && is->link_decomp_stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753 is->link_decompressor->
2754 reset(is->link_decomp_stat,
2755 skb->data[0],
2756 skb->data[1],
2757 len ? &skb->data[4] : NULL,
2758 len, NULL);
2759 /* TODO: neither here */
2760 is->compflags &= ~SC_LINK_DECOMP_DISCARD;
2761 }
2762 break;
2763
2764 case CCP_RESETREQ:
2765 printk(KERN_DEBUG "Received ResetReq from peer\n");
2766 /* Receiving a ResetReq means we must reset our compressor */
2767 /* Set up reset params for the reset entry */
2768 memset(&rsparm, 0, sizeof(rsparm));
2769 rsparm.data = rsdata;
Joe Perches475be4d2012-02-19 19:52:38 -08002770 rsparm.maxdlen = IPPP_RESET_MAXDATABYTES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771 /* Isolate data length */
2772 len = (skb->data[2] << 8) | skb->data[3];
2773 len -= 4;
Joe Perches475be4d2012-02-19 19:52:38 -08002774 if (proto == PPP_CCP) {
2775 if (mis->compressor && mis->comp_stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776 mis->compressor->
2777 reset(mis->comp_stat,
2778 skb->data[0],
2779 skb->data[1],
2780 len ? &skb->data[4] : NULL,
2781 len, &rsparm);
2782 }
2783 else {
Joe Perches475be4d2012-02-19 19:52:38 -08002784 if (is->link_compressor && is->link_comp_stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785 is->link_compressor->
2786 reset(is->link_comp_stat,
2787 skb->data[0],
2788 skb->data[1],
2789 len ? &skb->data[4] : NULL,
2790 len, &rsparm);
2791 }
2792 /* Ack the Req as specified by rsparm */
Joe Perches475be4d2012-02-19 19:52:38 -08002793 if (rsparm.valid) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794 /* Compressor reset handler decided how to answer */
Joe Perches475be4d2012-02-19 19:52:38 -08002795 if (rsparm.rsend) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796 /* We should send a Frame */
2797 isdn_ppp_ccp_xmit_reset(is, proto, CCP_RESETACK,
2798 rsparm.idval ? rsparm.id
2799 : skb->data[1],
2800 rsparm.dtval ?
2801 rsparm.data : NULL,
2802 rsparm.dtval ?
2803 rsparm.dlen : 0);
2804 } else {
2805 printk(KERN_DEBUG "ResetAck suppressed\n");
2806 }
2807 } else {
2808 /* We answer with a straight reflected Ack */
2809 isdn_ppp_ccp_xmit_reset(is, proto, CCP_RESETACK,
2810 skb->data[1],
2811 len ? &skb->data[4] : NULL,
2812 len);
2813 }
2814 break;
2815 }
2816}
2817
2818
2819/*
2820 * Daemon sends a CCP frame ...
2821 */
2822
2823/* TODO: Clean this up with new Reset semantics */
2824
2825/* I believe the CCP handling as-is is done wrong. Compressed frames
2826 * should only be sent/received after CCP reaches UP state, which means
2827 * both sides have sent CONF_ACK. Currently, we handle both directions
2828 * independently, which means we may accept compressed frames too early
2829 * (supposedly not a problem), but may also mean we send compressed frames
2830 * too early, which may turn out to be a problem.
2831 * This part of state machine should actually be handled by (i)pppd, but
2832 * that's too big of a change now. --kai
2833 */
2834
2835/* Actually, we might turn this into an advantage: deal with the RFC in
2836 * the old tradition of beeing generous on what we accept, but beeing
2837 * strict on what we send. Thus we should just
2838 * - accept compressed frames as soon as decompression is negotiated
2839 * - send compressed frames only when decomp *and* comp are negotiated
2840 * - drop rx compressed frames if we cannot decomp (instead of pushing them
2841 * up to ipppd)
2842 * and I tried to modify this file according to that. --abp
2843 */
2844
2845static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *skb)
2846{
Joe Perches475be4d2012-02-19 19:52:38 -08002847 struct ippp_struct *mis, *is;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002848 int proto, slot = lp->ppp_slot;
2849 unsigned char *data;
2850
Joe Perches475be4d2012-02-19 19:52:38 -08002851 if (!skb || skb->len < 3)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002852 return;
2853 if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
2854 printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
Joe Perches475be4d2012-02-19 19:52:38 -08002855 __func__, slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002856 return;
Joe Perches475be4d2012-02-19 19:52:38 -08002857 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858 is = ippp_table[slot];
2859 /* Daemon may send with or without address and control field comp */
2860 data = skb->data;
Joe Perches475be4d2012-02-19 19:52:38 -08002861 if (!(is->pppcfg & SC_COMP_AC) && data[0] == 0xff && data[1] == 0x03) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002862 data += 2;
Joe Perches475be4d2012-02-19 19:52:38 -08002863 if (skb->len < 5)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002864 return;
2865 }
2866
Joe Perches475be4d2012-02-19 19:52:38 -08002867 proto = ((int)data[0]<<8) + data[1];
2868 if (proto != PPP_CCP && proto != PPP_CCPFRAG)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002869 return;
2870
2871 printk(KERN_DEBUG "Received CCP frame from daemon:\n");
Joe Perches475be4d2012-02-19 19:52:38 -08002872 isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit, lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002873
2874 if (lp->master) {
Wang Chen838361f2008-12-03 15:49:46 -08002875 slot = ISDN_MASTER_PRIV(lp)->ppp_slot;
Eric Sesterhenn052bb882006-04-11 17:29:17 -07002876 if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877 printk(KERN_ERR "%s: slot(%d) out of range\n",
Joe Perches475be4d2012-02-19 19:52:38 -08002878 __func__, slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002879 return;
Joe Perches475be4d2012-02-19 19:52:38 -08002880 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002881 mis = ippp_table[slot];
2882 } else
2883 mis = is;
2884 if (mis != is)
2885 printk(KERN_DEBUG "isdn_ppp: Ouch! Master CCP sends on slave slot!\n");
Joe Perches475be4d2012-02-19 19:52:38 -08002886
2887 switch (data[2]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002888 case CCP_CONFREQ:
Joe Perches475be4d2012-02-19 19:52:38 -08002889 if (is->debug & 0x10)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002890 printk(KERN_DEBUG "Disable decompression here!\n");
Joe Perches475be4d2012-02-19 19:52:38 -08002891 if (proto == PPP_CCP)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002892 is->compflags &= ~SC_DECOMP_ON;
2893 else
2894 is->compflags &= ~SC_LINK_DECOMP_ON;
2895 break;
2896 case CCP_TERMREQ:
2897 case CCP_TERMACK:
Joe Perches475be4d2012-02-19 19:52:38 -08002898 if (is->debug & 0x10)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002899 printk(KERN_DEBUG "Disable (de)compression here!\n");
Joe Perches475be4d2012-02-19 19:52:38 -08002900 if (proto == PPP_CCP)
2901 is->compflags &= ~(SC_DECOMP_ON | SC_COMP_ON);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002902 else
Joe Perches475be4d2012-02-19 19:52:38 -08002903 is->compflags &= ~(SC_LINK_DECOMP_ON | SC_LINK_COMP_ON);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002904 break;
2905 case CCP_CONFACK:
2906 /* if we SEND an ackowledge we can/must enable the compressor */
Joe Perches475be4d2012-02-19 19:52:38 -08002907 if (is->debug & 0x10)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002908 printk(KERN_DEBUG "Enable compression here!\n");
Joe Perches475be4d2012-02-19 19:52:38 -08002909 if (proto == PPP_CCP) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002910 if (!is->compressor)
2911 break;
2912 is->compflags |= SC_COMP_ON;
2913 } else {
2914 if (!is->compressor)
2915 break;
2916 is->compflags |= SC_LINK_COMP_ON;
2917 }
2918 break;
2919 case CCP_RESETACK:
2920 /* If we send a ACK we should reset our compressor */
Joe Perches475be4d2012-02-19 19:52:38 -08002921 if (is->debug & 0x10)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002922 printk(KERN_DEBUG "Reset decompression state here!\n");
2923 printk(KERN_DEBUG "ResetAck from daemon passed by\n");
Joe Perches475be4d2012-02-19 19:52:38 -08002924 if (proto == PPP_CCP) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002925 /* link to master? */
Joe Perches475be4d2012-02-19 19:52:38 -08002926 if (is->compressor && is->comp_stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927 is->compressor->reset(is->comp_stat, 0, 0,
2928 NULL, 0, NULL);
Joe Perches475be4d2012-02-19 19:52:38 -08002929 is->compflags &= ~SC_COMP_DISCARD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002930 }
2931 else {
Joe Perches475be4d2012-02-19 19:52:38 -08002932 if (is->link_compressor && is->link_comp_stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002933 is->link_compressor->reset(is->link_comp_stat,
2934 0, 0, NULL, 0, NULL);
Joe Perches475be4d2012-02-19 19:52:38 -08002935 is->compflags &= ~SC_LINK_COMP_DISCARD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002936 }
2937 break;
2938 case CCP_RESETREQ:
2939 /* Just let it pass by */
2940 printk(KERN_DEBUG "ResetReq from daemon passed by\n");
2941 break;
2942 }
2943}
2944
2945int isdn_ppp_register_compressor(struct isdn_ppp_compressor *ipc)
2946{
2947 ipc->next = ipc_head;
2948 ipc->prev = NULL;
Joe Perches475be4d2012-02-19 19:52:38 -08002949 if (ipc_head) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950 ipc_head->prev = ipc;
2951 }
2952 ipc_head = ipc;
2953 return 0;
2954}
2955
2956int isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *ipc)
2957{
Joe Perches475be4d2012-02-19 19:52:38 -08002958 if (ipc->prev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002959 ipc->prev->next = ipc->next;
2960 else
2961 ipc_head = ipc->next;
Joe Perches475be4d2012-02-19 19:52:38 -08002962 if (ipc->next)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002963 ipc->next->prev = ipc->prev;
2964 ipc->prev = ipc->next = NULL;
2965 return 0;
2966}
2967
2968static int isdn_ppp_set_compressor(struct ippp_struct *is, struct isdn_ppp_comp_data *data)
2969{
2970 struct isdn_ppp_compressor *ipc = ipc_head;
2971 int ret;
2972 void *stat;
2973 int num = data->num;
2974
Joe Perches475be4d2012-02-19 19:52:38 -08002975 if (is->debug & 0x10)
2976 printk(KERN_DEBUG "[%d] Set %s type %d\n", is->unit,
2977 (data->flags & IPPP_COMP_FLAG_XMIT) ? "compressor" : "decompressor", num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002978
2979 /* If is has no valid reset state vector, we cannot allocate a
2980 decompressor. The decompressor would cause reset transactions
2981 sooner or later, and they need that vector. */
2982
Joe Perches475be4d2012-02-19 19:52:38 -08002983 if (!(data->flags & IPPP_COMP_FLAG_XMIT) && !is->reset) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002984 printk(KERN_ERR "ippp_ccp: no reset data structure - can't"
2985 " allow decompression.\n");
2986 return -ENOMEM;
2987 }
2988
Joe Perches475be4d2012-02-19 19:52:38 -08002989 while (ipc) {
2990 if (ipc->num == num) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002991 stat = ipc->alloc(data);
Joe Perches475be4d2012-02-19 19:52:38 -08002992 if (stat) {
2993 ret = ipc->init(stat, data, is->unit, 0);
2994 if (!ret) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002995 printk(KERN_ERR "Can't init (de)compression!\n");
2996 ipc->free(stat);
2997 stat = NULL;
2998 break;
2999 }
3000 }
3001 else {
3002 printk(KERN_ERR "Can't alloc (de)compression!\n");
3003 break;
3004 }
3005
Joe Perches475be4d2012-02-19 19:52:38 -08003006 if (data->flags & IPPP_COMP_FLAG_XMIT) {
3007 if (data->flags & IPPP_COMP_FLAG_LINK) {
3008 if (is->link_comp_stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003009 is->link_compressor->free(is->link_comp_stat);
3010 is->link_comp_stat = stat;
Joe Perches475be4d2012-02-19 19:52:38 -08003011 is->link_compressor = ipc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003012 }
3013 else {
Joe Perches475be4d2012-02-19 19:52:38 -08003014 if (is->comp_stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003015 is->compressor->free(is->comp_stat);
3016 is->comp_stat = stat;
Joe Perches475be4d2012-02-19 19:52:38 -08003017 is->compressor = ipc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003018 }
3019 }
Joe Perches475be4d2012-02-19 19:52:38 -08003020 else {
3021 if (data->flags & IPPP_COMP_FLAG_LINK) {
3022 if (is->link_decomp_stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003023 is->link_decompressor->free(is->link_decomp_stat);
3024 is->link_decomp_stat = stat;
Joe Perches475be4d2012-02-19 19:52:38 -08003025 is->link_decompressor = ipc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003026 }
3027 else {
Joe Perches475be4d2012-02-19 19:52:38 -08003028 if (is->decomp_stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003029 is->decompressor->free(is->decomp_stat);
3030 is->decomp_stat = stat;
Joe Perches475be4d2012-02-19 19:52:38 -08003031 is->decompressor = ipc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003032 }
3033 }
3034 return 0;
3035 }
3036 ipc = ipc->next;
3037 }
3038 return -EINVAL;
3039}