blob: 61ac6323744602ff27a95b56042c19d5d4e527e1 [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;
445 int len, err;
446
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
461 err = sk_chk_filter(code, uprog.len);
462 if (err) {
463 kfree(code);
464 return err;
465 }
466
467 *p = code;
468 return uprog.len;
469}
Daniele Venzano26285ba2009-01-26 12:24:38 -0800470#endif /* CONFIG_IPPP_FILTER */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471
472/*
473 * ippp device ioctl
474 */
475int
476isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
477{
478 unsigned long val;
Joe Perches475be4d2012-02-19 19:52:38 -0800479 int r, i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 struct ippp_struct *is;
481 isdn_net_local *lp;
482 struct isdn_ppp_comp_data data;
483 void __user *argp = (void __user *)arg;
484
Joe Perches54cbb1c2010-07-12 10:50:02 +0000485 is = file->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 lp = is->lp;
487
488 if (is->debug & 0x1)
489 printk(KERN_DEBUG "isdn_ppp_ioctl: minor: %d cmd: %x state: %x\n", min, cmd, is->state);
490
491 if (!(is->state & IPPP_OPEN))
492 return -EINVAL;
493
494 switch (cmd) {
Joe Perches475be4d2012-02-19 19:52:38 -0800495 case PPPIOCBUNDLE:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496#ifdef CONFIG_ISDN_MPP
Joe Perches475be4d2012-02-19 19:52:38 -0800497 if (!(is->state & IPPP_CONNECT))
498 return -EINVAL;
499 if ((r = get_arg(argp, &val, sizeof(val))))
500 return r;
501 printk(KERN_DEBUG "iPPP-bundle: minor: %d, slave unit: %d, master unit: %d\n",
502 (int) min, (int) is->unit, (int) val);
503 return isdn_ppp_bundle(is, val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504#else
Joe Perches475be4d2012-02-19 19:52:38 -0800505 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506#endif
Joe Perches475be4d2012-02-19 19:52:38 -0800507 break;
508 case PPPIOCGUNIT: /* get ppp/isdn unit number */
509 if ((r = set_arg(argp, &is->unit, sizeof(is->unit))))
510 return r;
511 break;
512 case PPPIOCGIFNAME:
513 if (!lp)
514 return -EINVAL;
515 if ((r = set_arg(argp, lp->netdev->dev->name,
516 strlen(lp->netdev->dev->name))))
517 return r;
518 break;
519 case PPPIOCGMPFLAGS: /* get configuration flags */
520 if ((r = set_arg(argp, &is->mpppcfg, sizeof(is->mpppcfg))))
521 return r;
522 break;
523 case PPPIOCSMPFLAGS: /* set configuration flags */
524 if ((r = get_arg(argp, &val, sizeof(val))))
525 return r;
526 is->mpppcfg = val;
527 break;
528 case PPPIOCGFLAGS: /* get configuration flags */
529 if ((r = set_arg(argp, &is->pppcfg, sizeof(is->pppcfg))))
530 return r;
531 break;
532 case PPPIOCSFLAGS: /* set configuration flags */
533 if ((r = get_arg(argp, &val, sizeof(val)))) {
534 return r;
535 }
536 if (val & SC_ENABLE_IP && !(is->pppcfg & SC_ENABLE_IP) && (is->state & IPPP_CONNECT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 if (lp) {
Joe Perches475be4d2012-02-19 19:52:38 -0800538 /* OK .. we are ready to send buffers */
539 is->pppcfg = val; /* isdn_ppp_xmit test for SC_ENABLE_IP !!! */
540 netif_wake_queue(lp->netdev->dev);
541 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 }
Joe Perches475be4d2012-02-19 19:52:38 -0800543 }
544 is->pppcfg = val;
545 break;
546 case PPPIOCGIDLE: /* get idle time information */
547 if (lp) {
548 struct ppp_idle pidle;
549 pidle.xmit_idle = pidle.recv_idle = lp->huptimer;
550 if ((r = set_arg(argp, &pidle, sizeof(struct ppp_idle))))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 return r;
Joe Perches475be4d2012-02-19 19:52:38 -0800552 }
553 break;
554 case PPPIOCSMRU: /* set receive unit size for PPP */
555 if ((r = get_arg(argp, &val, sizeof(val))))
556 return r;
557 is->mru = val;
558 break;
559 case PPPIOCSMPMRU:
560 break;
561 case PPPIOCSMPMTU:
562 break;
563 case PPPIOCSMAXCID: /* set the maximum compression slot id */
564 if ((r = get_arg(argp, &val, sizeof(val))))
565 return r;
566 val++;
567 if (is->maxcid != val) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568#ifdef CONFIG_ISDN_PPP_VJ
Joe Perches475be4d2012-02-19 19:52:38 -0800569 struct slcompress *sltmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570#endif
Joe Perches475be4d2012-02-19 19:52:38 -0800571 if (is->debug & 0x1)
572 printk(KERN_DEBUG "ippp, ioctl: changed MAXCID to %ld\n", val);
573 is->maxcid = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574#ifdef CONFIG_ISDN_PPP_VJ
Joe Perches475be4d2012-02-19 19:52:38 -0800575 sltmp = slhc_init(16, val);
576 if (!sltmp) {
577 printk(KERN_ERR "ippp, can't realloc slhc struct\n");
578 return -ENOMEM;
579 }
580 if (is->slcomp)
581 slhc_free(is->slcomp);
582 is->slcomp = sltmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583#endif
Joe Perches475be4d2012-02-19 19:52:38 -0800584 }
585 break;
586 case PPPIOCGDEBUG:
587 if ((r = set_arg(argp, &is->debug, sizeof(is->debug))))
588 return r;
589 break;
590 case PPPIOCSDEBUG:
591 if ((r = get_arg(argp, &val, sizeof(val))))
592 return r;
593 is->debug = val;
594 break;
595 case PPPIOCGCOMPRESSORS:
596 {
597 unsigned long protos[8] = {0,};
598 struct isdn_ppp_compressor *ipc = ipc_head;
599 while (ipc) {
600 j = ipc->num / (sizeof(long) * 8);
601 i = ipc->num % (sizeof(long) * 8);
602 if (j < 8)
Dan Carpenter435f08a2012-10-09 23:42:18 +0000603 protos[j] |= (1UL << i);
Joe Perches475be4d2012-02-19 19:52:38 -0800604 ipc = ipc->next;
605 }
606 if ((r = set_arg(argp, protos, 8 * sizeof(long))))
607 return r;
608 }
609 break;
610 case PPPIOCSCOMPRESSOR:
611 if ((r = get_arg(argp, &data, sizeof(struct isdn_ppp_comp_data))))
612 return r;
613 return isdn_ppp_set_compressor(is, &data);
614 case PPPIOCGCALLINFO:
615 {
616 struct pppcallinfo pci;
617 memset((char *)&pci, 0, sizeof(struct pppcallinfo));
618 if (lp)
619 {
620 strncpy(pci.local_num, lp->msn, 63);
621 if (lp->dial) {
622 strncpy(pci.remote_num, lp->dial->num, 63);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 }
Joe Perches475be4d2012-02-19 19:52:38 -0800624 pci.charge_units = lp->charge;
625 if (lp->outgoing)
626 pci.calltype = CALLTYPE_OUTGOING;
627 else
628 pci.calltype = CALLTYPE_INCOMING;
629 if (lp->flags & ISDN_NET_CALLBACK)
630 pci.calltype |= CALLTYPE_CALLBACK;
631 }
632 return set_arg(argp, &pci, sizeof(struct pppcallinfo));
633 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634#ifdef CONFIG_IPPP_FILTER
Joe Perches475be4d2012-02-19 19:52:38 -0800635 case PPPIOCSPASS:
636 {
Daniel Borkmannb1fcd352014-05-23 18:43:58 +0200637 struct sock_fprog_kern fprog;
Joe Perches475be4d2012-02-19 19:52:38 -0800638 struct sock_filter *code;
Daniel Borkmann77e01142014-03-28 18:58:24 +0100639 int err, len = get_filter(argp, &code);
640
Joe Perches475be4d2012-02-19 19:52:38 -0800641 if (len < 0)
642 return len;
Daniel Borkmann77e01142014-03-28 18:58:24 +0100643
644 fprog.len = len;
645 fprog.filter = code;
646
647 if (is->pass_filter)
648 sk_unattached_filter_destroy(is->pass_filter);
649 err = sk_unattached_filter_create(&is->pass_filter, &fprog);
650 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
666 if (is->active_filter)
667 sk_unattached_filter_destroy(is->active_filter);
668 err = sk_unattached_filter_create(&is->active_filter, &fprog);
669 kfree(code);
670
671 return err;
Joe Perches475be4d2012-02-19 19:52:38 -0800672 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673#endif /* CONFIG_IPPP_FILTER */
Joe Perches475be4d2012-02-19 19:52:38 -0800674 default:
675 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 }
677 return 0;
678}
679
680unsigned int
Joe Perches475be4d2012-02-19 19:52:38 -0800681isdn_ppp_poll(struct file *file, poll_table *wait)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682{
683 u_int mask;
684 struct ippp_buf_queue *bf, *bl;
685 u_long flags;
686 struct ippp_struct *is;
687
688 is = file->private_data;
689
690 if (is->debug & 0x2)
691 printk(KERN_DEBUG "isdn_ppp_poll: minor: %d\n",
Al Viro496ad9a2013-01-23 17:07:38 -0500692 iminor(file_inode(file)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693
694 /* just registers wait_queue hook. This doesn't really wait. */
695 poll_wait(file, &is->wq, wait);
696
697 if (!(is->state & IPPP_OPEN)) {
Joe Perches475be4d2012-02-19 19:52:38 -0800698 if (is->state == IPPP_CLOSEWAIT)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 return POLLHUP;
700 printk(KERN_DEBUG "isdn_ppp: device not open\n");
701 return POLLERR;
702 }
703 /* we're always ready to send .. */
704 mask = POLLOUT | POLLWRNORM;
705
706 spin_lock_irqsave(&is->buflock, flags);
707 bl = is->last;
708 bf = is->first;
709 /*
710 * if IPPP_NOBLOCK is set we return even if we have nothing to read
711 */
712 if (bf->next != bl || (is->state & IPPP_NOBLOCK)) {
713 is->state &= ~IPPP_NOBLOCK;
714 mask |= POLLIN | POLLRDNORM;
715 }
716 spin_unlock_irqrestore(&is->buflock, flags);
717 return mask;
718}
719
720/*
721 * fill up isdn_ppp_read() queue ..
722 */
723
724static int
725isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot)
726{
727 struct ippp_buf_queue *bf, *bl;
728 u_long flags;
729 u_char *nbuf;
730 struct ippp_struct *is;
731
732 if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
733 printk(KERN_WARNING "ippp: illegal slot(%d).\n", slot);
734 return 0;
735 }
736 is = ippp_table[slot];
737
738 if (!(is->state & IPPP_CONNECT)) {
739 printk(KERN_DEBUG "ippp: device not activated.\n");
740 return 0;
741 }
Robert P. J. Day5cbded52006-12-13 00:35:56 -0800742 nbuf = kmalloc(len + 4, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 if (!nbuf) {
744 printk(KERN_WARNING "ippp: Can't alloc buf\n");
745 return 0;
746 }
747 nbuf[0] = PPP_ALLSTATIONS;
748 nbuf[1] = PPP_UI;
749 nbuf[2] = proto >> 8;
750 nbuf[3] = proto & 0xff;
751 memcpy(nbuf + 4, buf, len);
752
753 spin_lock_irqsave(&is->buflock, flags);
754 bf = is->first;
755 bl = is->last;
756
757 if (bf == bl) {
758 printk(KERN_WARNING "ippp: Queue is full; discarding first buffer\n");
759 bf = bf->next;
760 kfree(bf->buf);
761 is->first = bf;
762 }
763 bl->buf = (char *) nbuf;
764 bl->len = len + 4;
765
766 is->last = bl->next;
767 spin_unlock_irqrestore(&is->buflock, flags);
768 wake_up_interruptible(&is->wq);
769 return len;
770}
771
772/*
773 * read() .. non-blocking: ipppd calls it only after select()
774 * reports, that there is data
775 */
776
777int
778isdn_ppp_read(int min, struct file *file, char __user *buf, int count)
779{
780 struct ippp_struct *is;
781 struct ippp_buf_queue *b;
782 u_long flags;
783 u_char *save_buf;
784
785 is = file->private_data;
786
787 if (!(is->state & IPPP_OPEN))
788 return 0;
789
790 if (!access_ok(VERIFY_WRITE, buf, count))
791 return -EFAULT;
792
793 spin_lock_irqsave(&is->buflock, flags);
794 b = is->first->next;
795 save_buf = b->buf;
796 if (!save_buf) {
797 spin_unlock_irqrestore(&is->buflock, flags);
798 return -EAGAIN;
799 }
800 if (b->len < count)
801 count = b->len;
802 b->buf = NULL;
803 is->first = b;
804
805 spin_unlock_irqrestore(&is->buflock, flags);
Jesper Juhlc41a24c2006-03-25 03:07:02 -0800806 if (copy_to_user(buf, save_buf, count))
807 count = -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 kfree(save_buf);
809
810 return count;
811}
812
813/*
814 * ipppd wanna write a packet to the card .. non-blocking
815 */
816
817int
818isdn_ppp_write(int min, struct file *file, const char __user *buf, int count)
819{
820 isdn_net_local *lp;
821 struct ippp_struct *is;
822 int proto;
823 unsigned char protobuf[4];
824
825 is = file->private_data;
826
827 if (!(is->state & IPPP_CONNECT))
828 return 0;
829
830 lp = is->lp;
831
832 /* -> push it directly to the lowlevel interface */
833
834 if (!lp)
835 printk(KERN_DEBUG "isdn_ppp_write: lp == NULL\n");
836 else {
837 /*
838 * Don't reset huptimer for
839 * LCP packets. (Echo requests).
840 */
841 if (copy_from_user(protobuf, buf, 4))
842 return -EFAULT;
843 proto = PPP_PROTOCOL(protobuf);
844 if (proto != PPP_LCP)
845 lp->huptimer = 0;
846
847 if (lp->isdn_device < 0 || lp->isdn_channel < 0)
848 return 0;
849
850 if ((dev->drv[lp->isdn_device]->flags & DRV_FLAG_RUNNING) &&
Joe Perches475be4d2012-02-19 19:52:38 -0800851 lp->dialstate == 0 &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 (lp->flags & ISDN_NET_CONNECTED)) {
853 unsigned short hl;
854 struct sk_buff *skb;
855 /*
André Goddard Rosaaf901ca2009-11-14 13:09:05 -0200856 * we need to reserve enough space in front of
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 * sk_buff. old call to dev_alloc_skb only reserved
858 * 16 bytes, now we are looking what the driver want
859 */
860 hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen;
Joe Perches475be4d2012-02-19 19:52:38 -0800861 skb = alloc_skb(hl + count, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 if (!skb) {
863 printk(KERN_WARNING "isdn_ppp_write: out of memory!\n");
864 return count;
865 }
866 skb_reserve(skb, hl);
867 if (copy_from_user(skb_put(skb, count), buf, count))
868 {
869 kfree_skb(skb);
870 return -EFAULT;
871 }
872 if (is->debug & 0x40) {
873 printk(KERN_DEBUG "ppp xmit: len %d\n", (int) skb->len);
Joe Perches475be4d2012-02-19 19:52:38 -0800874 isdn_ppp_frame_log("xmit", skb->data, skb->len, 32, is->unit, lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 }
876
Joe Perches475be4d2012-02-19 19:52:38 -0800877 isdn_ppp_send_ccp(lp->netdev, lp, skb); /* keeps CCP/compression states in sync */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878
879 isdn_net_write_super(lp, skb);
880 }
881 }
882 return count;
883}
884
885/*
886 * init memory, structures etc.
887 */
888
889int
890isdn_ppp_init(void)
891{
892 int i,
Joe Perches475be4d2012-02-19 19:52:38 -0800893 j;
894
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895#ifdef CONFIG_ISDN_MPP
Joe Perches475be4d2012-02-19 19:52:38 -0800896 if (isdn_ppp_mp_bundle_array_init() < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 return -ENOMEM;
898#endif /* CONFIG_ISDN_MPP */
899
900 for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
Burman Yan41f96932006-12-08 02:39:35 -0800901 if (!(ippp_table[i] = kzalloc(sizeof(struct ippp_struct), GFP_KERNEL))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 printk(KERN_WARNING "isdn_ppp_init: Could not alloc ippp_table\n");
903 for (j = 0; j < i; j++)
904 kfree(ippp_table[j]);
905 return -1;
906 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 spin_lock_init(&ippp_table[i]->buflock);
908 ippp_table[i]->state = 0;
909 ippp_table[i]->first = ippp_table[i]->rq + NUM_RCV_BUFFS - 1;
910 ippp_table[i]->last = ippp_table[i]->rq;
911
912 for (j = 0; j < NUM_RCV_BUFFS; j++) {
913 ippp_table[i]->rq[j].buf = NULL;
914 ippp_table[i]->rq[j].last = ippp_table[i]->rq +
Joe Perches475be4d2012-02-19 19:52:38 -0800915 (NUM_RCV_BUFFS + j - 1) % NUM_RCV_BUFFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 ippp_table[i]->rq[j].next = ippp_table[i]->rq + (j + 1) % NUM_RCV_BUFFS;
917 }
918 }
919 return 0;
920}
921
922void
923isdn_ppp_cleanup(void)
924{
925 int i;
926
927 for (i = 0; i < ISDN_MAX_CHANNELS; i++)
928 kfree(ippp_table[i]);
929
930#ifdef CONFIG_ISDN_MPP
Jesper Juhl3c7208f2005-11-07 01:01:29 -0800931 kfree(isdn_ppp_bundle_arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932#endif /* CONFIG_ISDN_MPP */
933
934}
935
936/*
937 * check for address/control field and skip if allowed
938 * retval != 0 -> discard packet silently
939 */
Joe Perches475be4d2012-02-19 19:52:38 -0800940static int isdn_ppp_skip_ac(struct ippp_struct *is, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941{
942 if (skb->len < 1)
943 return -1;
944
945 if (skb->data[0] == 0xff) {
946 if (skb->len < 2)
947 return -1;
948
949 if (skb->data[1] != 0x03)
950 return -1;
951
952 // skip address/control (AC) field
953 skb_pull(skb, 2);
Joe Perches475be4d2012-02-19 19:52:38 -0800954 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955 if (is->pppcfg & SC_REJ_COMP_AC)
956 // if AC compression was not negotiated, but used, discard packet
957 return -1;
958 }
959 return 0;
960}
961
962/*
963 * get the PPP protocol header and pull skb
964 * retval < 0 -> discard packet silently
965 */
Joe Perches475be4d2012-02-19 19:52:38 -0800966static int isdn_ppp_strip_proto(struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967{
968 int proto;
Joe Perches475be4d2012-02-19 19:52:38 -0800969
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970 if (skb->len < 1)
971 return -1;
972
973 if (skb->data[0] & 0x1) {
974 // protocol field is compressed
975 proto = skb->data[0];
976 skb_pull(skb, 1);
977 } else {
978 if (skb->len < 2)
979 return -1;
980 proto = ((int) skb->data[0] << 8) + skb->data[1];
981 skb_pull(skb, 2);
982 }
983 return proto;
984}
985
986
987/*
988 * handler for incoming packets on a syncPPP interface
989 */
Joe Perches475be4d2012-02-19 19:52:38 -0800990void isdn_ppp_receive(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991{
992 struct ippp_struct *is;
993 int slot;
994 int proto;
995
Eric Sesterhenn6dd44a72006-03-26 18:19:26 +0200996 BUG_ON(net_dev->local->master); // we're called with the master device always
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997
998 slot = lp->ppp_slot;
999 if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
1000 printk(KERN_ERR "isdn_ppp_receive: lp->ppp_slot(%d)\n",
Joe Perches475be4d2012-02-19 19:52:38 -08001001 lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 kfree_skb(skb);
1003 return;
1004 }
1005 is = ippp_table[slot];
1006
1007 if (is->debug & 0x4) {
1008 printk(KERN_DEBUG "ippp_receive: is:%08lx lp:%08lx slot:%d unit:%d len:%d\n",
Joe Perches475be4d2012-02-19 19:52:38 -08001009 (long)is, (long)lp, lp->ppp_slot, is->unit, (int)skb->len);
1010 isdn_ppp_frame_log("receive", skb->data, skb->len, 32, is->unit, lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 }
1012
Joe Perches475be4d2012-02-19 19:52:38 -08001013 if (isdn_ppp_skip_ac(is, skb) < 0) {
1014 kfree_skb(skb);
1015 return;
1016 }
1017 proto = isdn_ppp_strip_proto(skb);
1018 if (proto < 0) {
1019 kfree_skb(skb);
1020 return;
1021 }
1022
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023#ifdef CONFIG_ISDN_MPP
Joe Perches475be4d2012-02-19 19:52:38 -08001024 if (is->compflags & SC_LINK_DECOMP_ON) {
1025 skb = isdn_ppp_decompress(skb, is, NULL, &proto);
1026 if (!skb) // decompression error
1027 return;
1028 }
1029
1030 if (!(is->mpppcfg & SC_REJ_MP_PROT)) { // we agreed to receive MPPP
1031 if (proto == PPP_MP) {
1032 isdn_ppp_mp_receive(net_dev, lp, skb);
1033 return;
1034 }
1035 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036#endif
Joe Perches475be4d2012-02-19 19:52:38 -08001037 isdn_ppp_push_higher(net_dev, lp, skb, proto);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038}
1039
1040/*
1041 * we receive a reassembled frame, MPPP has been taken care of before.
1042 * address/control and protocol have been stripped from the skb
1043 * note: net_dev has to be master net_dev
1044 */
1045static void
Joe Perches475be4d2012-02-19 19:52:38 -08001046isdn_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 -07001047{
Karsten Keild62a38d2007-10-08 20:37:11 -07001048 struct net_device *dev = net_dev->dev;
Joe Perches475be4d2012-02-19 19:52:38 -08001049 struct ippp_struct *is, *mis;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 isdn_net_local *mlp = NULL;
1051 int slot;
1052
1053 slot = lp->ppp_slot;
1054 if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
1055 printk(KERN_ERR "isdn_ppp_push_higher: lp->ppp_slot(%d)\n",
Joe Perches475be4d2012-02-19 19:52:38 -08001056 lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057 goto drop_packet;
1058 }
1059 is = ippp_table[slot];
Joe Perches475be4d2012-02-19 19:52:38 -08001060
1061 if (lp->master) { // FIXME?
Wang Chen838361f2008-12-03 15:49:46 -08001062 mlp = ISDN_MASTER_PRIV(lp);
Joe Perches475be4d2012-02-19 19:52:38 -08001063 slot = mlp->ppp_slot;
1064 if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
1065 printk(KERN_ERR "isdn_ppp_push_higher: master->ppp_slot(%d)\n",
1066 lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 goto drop_packet;
Joe Perches475be4d2012-02-19 19:52:38 -08001068 }
1069 }
1070 mis = ippp_table[slot];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071
1072 if (is->debug & 0x10) {
1073 printk(KERN_DEBUG "push, skb %d %04x\n", (int) skb->len, proto);
Joe Perches475be4d2012-02-19 19:52:38 -08001074 isdn_ppp_frame_log("rpush", skb->data, skb->len, 32, is->unit, lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 }
1076 if (mis->compflags & SC_DECOMP_ON) {
1077 skb = isdn_ppp_decompress(skb, is, mis, &proto);
1078 if (!skb) // decompression error
Joe Perches475be4d2012-02-19 19:52:38 -08001079 return;
1080 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081 switch (proto) {
Joe Perches475be4d2012-02-19 19:52:38 -08001082 case PPP_IPX: /* untested */
1083 if (is->debug & 0x20)
1084 printk(KERN_DEBUG "isdn_ppp: IPX\n");
1085 skb->protocol = htons(ETH_P_IPX);
1086 break;
1087 case PPP_IP:
1088 if (is->debug & 0x20)
1089 printk(KERN_DEBUG "isdn_ppp: IP\n");
1090 skb->protocol = htons(ETH_P_IP);
1091 break;
1092 case PPP_COMP:
1093 case PPP_COMPFRAG:
1094 printk(KERN_INFO "isdn_ppp: unexpected compressed frame dropped\n");
1095 goto drop_packet;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096#ifdef CONFIG_ISDN_PPP_VJ
Joe Perches475be4d2012-02-19 19:52:38 -08001097 case PPP_VJC_UNCOMP:
1098 if (is->debug & 0x20)
1099 printk(KERN_DEBUG "isdn_ppp: VJC_UNCOMP\n");
1100 if (net_dev->local->ppp_slot < 0) {
1101 printk(KERN_ERR "%s: net_dev->local->ppp_slot(%d) out of range\n",
1102 __func__, net_dev->local->ppp_slot);
1103 goto drop_packet;
1104 }
1105 if (slhc_remember(ippp_table[net_dev->local->ppp_slot]->slcomp, skb->data, skb->len) <= 0) {
1106 printk(KERN_WARNING "isdn_ppp: received illegal VJC_UNCOMP frame!\n");
1107 goto drop_packet;
1108 }
1109 skb->protocol = htons(ETH_P_IP);
1110 break;
1111 case PPP_VJC_COMP:
1112 if (is->debug & 0x20)
1113 printk(KERN_DEBUG "isdn_ppp: VJC_COMP\n");
1114 {
1115 struct sk_buff *skb_old = skb;
1116 int pkt_len;
1117 skb = dev_alloc_skb(skb_old->len + 128);
1118
1119 if (!skb) {
1120 printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
1121 skb = skb_old;
1122 goto drop_packet;
1123 }
1124 skb_put(skb, skb_old->len + 128);
1125 skb_copy_from_linear_data(skb_old, skb->data,
1126 skb_old->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127 if (net_dev->local->ppp_slot < 0) {
1128 printk(KERN_ERR "%s: net_dev->local->ppp_slot(%d) out of range\n",
Joe Perches475be4d2012-02-19 19:52:38 -08001129 __func__, net_dev->local->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 goto drop_packet;
1131 }
Joe Perches475be4d2012-02-19 19:52:38 -08001132 pkt_len = slhc_uncompress(ippp_table[net_dev->local->ppp_slot]->slcomp,
1133 skb->data, skb_old->len);
1134 kfree_skb(skb_old);
1135 if (pkt_len < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136 goto drop_packet;
Joe Perches475be4d2012-02-19 19:52:38 -08001137
1138 skb_trim(skb, pkt_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 skb->protocol = htons(ETH_P_IP);
Joe Perches475be4d2012-02-19 19:52:38 -08001140 }
1141 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142#endif
Joe Perches475be4d2012-02-19 19:52:38 -08001143 case PPP_CCP:
1144 case PPP_CCPFRAG:
1145 isdn_ppp_receive_ccp(net_dev, lp, skb, proto);
1146 /* Dont pop up ResetReq/Ack stuff to the daemon any
1147 longer - the job is done already */
1148 if (skb->data[0] == CCP_RESETREQ ||
1149 skb->data[0] == CCP_RESETACK)
1150 break;
1151 /* fall through */
1152 default:
1153 isdn_ppp_fill_rq(skb->data, skb->len, proto, lp->ppp_slot); /* push data to pppd device */
1154 kfree_skb(skb);
1155 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156 }
1157
1158#ifdef CONFIG_IPPP_FILTER
1159 /* check if the packet passes the pass and active filters
1160 * the filter instructions are constructed assuming
1161 * a four-byte PPP header on each packet (which is still present) */
1162 skb_push(skb, 4);
1163
1164 {
1165 u_int16_t *p = (u_int16_t *) skb->data;
1166
Karsten Keild8470b72005-04-21 08:30:30 -07001167 *p = 0; /* indicate inbound */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 }
1169
1170 if (is->pass_filter
Daniel Borkmann77e01142014-03-28 18:58:24 +01001171 && SK_RUN_FILTER(is->pass_filter, skb) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172 if (is->debug & 0x2)
1173 printk(KERN_DEBUG "IPPP: inbound frame filtered.\n");
1174 kfree_skb(skb);
1175 return;
1176 }
1177 if (!(is->active_filter
Daniel Borkmann77e01142014-03-28 18:58:24 +01001178 && SK_RUN_FILTER(is->active_filter, skb) == 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179 if (is->debug & 0x2)
Masanari Iidaee556fe2012-02-11 01:49:28 +00001180 printk(KERN_DEBUG "IPPP: link-active filter: resetting huptimer.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181 lp->huptimer = 0;
1182 if (mlp)
1183 mlp->huptimer = 0;
1184 }
1185 skb_pull(skb, 4);
1186#else /* CONFIG_IPPP_FILTER */
1187 lp->huptimer = 0;
1188 if (mlp)
1189 mlp->huptimer = 0;
1190#endif /* CONFIG_IPPP_FILTER */
1191 skb->dev = dev;
Arnaldo Carvalho de Melo459a98e2007-03-19 15:30:44 -07001192 skb_reset_mac_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193 netif_rx(skb);
1194 /* net_dev->local->stats.rx_packets++; done in isdn_net.c */
1195 return;
1196
Joe Perches475be4d2012-02-19 19:52:38 -08001197drop_packet:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198 net_dev->local->stats.rx_dropped++;
1199 kfree_skb(skb);
1200}
1201
1202/*
1203 * isdn_ppp_skb_push ..
1204 * checks whether we have enough space at the beginning of the skb
1205 * and allocs a new SKB if necessary
1206 */
Joe Perches475be4d2012-02-19 19:52:38 -08001207static unsigned char *isdn_ppp_skb_push(struct sk_buff **skb_p, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208{
1209 struct sk_buff *skb = *skb_p;
1210
Joe Perches475be4d2012-02-19 19:52:38 -08001211 if (skb_headroom(skb) < len) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212 struct sk_buff *nskb = skb_realloc_headroom(skb, len);
1213
1214 if (!nskb) {
1215 printk(KERN_ERR "isdn_ppp_skb_push: can't realloc headroom!\n");
1216 dev_kfree_skb(skb);
1217 return NULL;
1218 }
Joe Perches475be4d2012-02-19 19:52:38 -08001219 printk(KERN_DEBUG "isdn_ppp_skb_push:under %d %d\n", skb_headroom(skb), len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 dev_kfree_skb(skb);
1221 *skb_p = nskb;
1222 return skb_push(nskb, len);
1223 }
Joe Perches475be4d2012-02-19 19:52:38 -08001224 return skb_push(skb, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225}
1226
1227/*
1228 * send ppp frame .. we expect a PIDCOMPressable proto --
1229 * (here: currently always PPP_IP,PPP_VJC_COMP,PPP_VJC_UNCOMP)
1230 *
1231 * VJ compression may change skb pointer!!! .. requeue with old
1232 * skb isn't allowed!!
1233 */
1234
1235int
1236isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev)
1237{
Joe Perches475be4d2012-02-19 19:52:38 -08001238 isdn_net_local *lp, *mlp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 isdn_net_dev *nd;
1240 unsigned int proto = PPP_IP; /* 0x21 */
Joe Perches475be4d2012-02-19 19:52:38 -08001241 struct ippp_struct *ipt, *ipts;
Patrick McHardyec634fe2009-07-05 19:23:38 -07001242 int slot, retval = NETDEV_TX_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243
Joe Perchesa17531f2010-11-15 11:12:24 +00001244 mlp = netdev_priv(netdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245 nd = mlp->netdev; /* get master lp */
1246
1247 slot = mlp->ppp_slot;
1248 if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
1249 printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot(%d)\n",
Joe Perches475be4d2012-02-19 19:52:38 -08001250 mlp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251 kfree_skb(skb);
1252 goto out;
1253 }
1254 ipts = ippp_table[slot];
1255
1256 if (!(ipts->pppcfg & SC_ENABLE_IP)) { /* PPP connected ? */
1257 if (ipts->debug & 0x1)
1258 printk(KERN_INFO "%s: IP frame delayed.\n", netdev->name);
Patrick McHardyec634fe2009-07-05 19:23:38 -07001259 retval = NETDEV_TX_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260 goto out;
1261 }
1262
1263 switch (ntohs(skb->protocol)) {
Joe Perches475be4d2012-02-19 19:52:38 -08001264 case ETH_P_IP:
1265 proto = PPP_IP;
1266 break;
1267 case ETH_P_IPX:
1268 proto = PPP_IPX; /* untested */
1269 break;
1270 default:
1271 printk(KERN_ERR "isdn_ppp: skipped unsupported protocol: %#x.\n",
1272 skb->protocol);
1273 dev_kfree_skb(skb);
1274 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275 }
1276
1277 lp = isdn_net_get_locked_lp(nd);
1278 if (!lp) {
1279 printk(KERN_WARNING "%s: all channels busy - requeuing!\n", netdev->name);
Patrick McHardyec634fe2009-07-05 19:23:38 -07001280 retval = NETDEV_TX_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281 goto out;
1282 }
1283 /* we have our lp locked from now on */
1284
1285 slot = lp->ppp_slot;
Eric Sesterhenn052bb882006-04-11 17:29:17 -07001286 if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287 printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot(%d)\n",
Joe Perches475be4d2012-02-19 19:52:38 -08001288 lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289 kfree_skb(skb);
1290 goto unlock;
1291 }
1292 ipt = ippp_table[slot];
1293
1294 /*
1295 * after this line .. requeueing in the device queue is no longer allowed!!!
1296 */
1297
1298 /* Pull off the fake header we stuck on earlier to keep
1299 * the fragmentation code happy.
1300 */
Joe Perches475be4d2012-02-19 19:52:38 -08001301 skb_pull(skb, IPPP_MAX_HEADER);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302
1303#ifdef CONFIG_IPPP_FILTER
1304 /* check if we should pass this packet
1305 * the filter instructions are constructed assuming
1306 * a four-byte PPP header on each packet */
Karsten Keild8470b72005-04-21 08:30:30 -07001307 *skb_push(skb, 4) = 1; /* indicate outbound */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308
1309 {
Harvey Harrisonc19d0362008-11-20 04:10:51 -08001310 __be16 *p = (__be16 *)skb->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311
Karsten Keild8470b72005-04-21 08:30:30 -07001312 p++;
Harvey Harrisonc19d0362008-11-20 04:10:51 -08001313 *p = htons(proto);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 }
1315
1316 if (ipt->pass_filter
Daniel Borkmann77e01142014-03-28 18:58:24 +01001317 && SK_RUN_FILTER(ipt->pass_filter, skb) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318 if (ipt->debug & 0x4)
1319 printk(KERN_DEBUG "IPPP: outbound frame filtered.\n");
1320 kfree_skb(skb);
1321 goto unlock;
1322 }
1323 if (!(ipt->active_filter
Daniel Borkmann77e01142014-03-28 18:58:24 +01001324 && SK_RUN_FILTER(ipt->active_filter, skb) == 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325 if (ipt->debug & 0x4)
Masanari Iidaee556fe2012-02-11 01:49:28 +00001326 printk(KERN_DEBUG "IPPP: link-active filter: resetting huptimer.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 lp->huptimer = 0;
1328 }
1329 skb_pull(skb, 4);
1330#else /* CONFIG_IPPP_FILTER */
1331 lp->huptimer = 0;
1332#endif /* CONFIG_IPPP_FILTER */
1333
1334 if (ipt->debug & 0x4)
1335 printk(KERN_DEBUG "xmit skb, len %d\n", (int) skb->len);
Joe Perches475be4d2012-02-19 19:52:38 -08001336 if (ipts->debug & 0x40)
1337 isdn_ppp_frame_log("xmit0", skb->data, skb->len, 32, ipts->unit, lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338
1339#ifdef CONFIG_ISDN_PPP_VJ
1340 if (proto == PPP_IP && ipts->pppcfg & SC_COMP_TCP) { /* ipts here? probably yes, but check this again */
1341 struct sk_buff *new_skb;
Joe Perches475be4d2012-02-19 19:52:38 -08001342 unsigned short hl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343 /*
André Goddard Rosaaf901ca2009-11-14 13:09:05 -02001344 * we need to reserve enough space in front of
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345 * sk_buff. old call to dev_alloc_skb only reserved
1346 * 16 bytes, now we are looking what the driver want.
1347 */
1348 hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen + IPPP_MAX_HEADER;
Joe Perches475be4d2012-02-19 19:52:38 -08001349 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 * Note: hl might still be insufficient because the method
1351 * above does not account for a possibible MPPP slave channel
1352 * which had larger HL header space requirements than the
1353 * master.
1354 */
Joe Perches475be4d2012-02-19 19:52:38 -08001355 new_skb = alloc_skb(hl + skb->len, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356 if (new_skb) {
1357 u_char *buf;
1358 int pktlen;
1359
1360 skb_reserve(new_skb, hl);
1361 new_skb->dev = skb->dev;
1362 skb_put(new_skb, skb->len);
1363 buf = skb->data;
1364
1365 pktlen = slhc_compress(ipts->slcomp, skb->data, skb->len, new_skb->data,
Joe Perches475be4d2012-02-19 19:52:38 -08001366 &buf, !(ipts->pppcfg & SC_NO_TCP_CCID));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367
Joe Perches475be4d2012-02-19 19:52:38 -08001368 if (buf != skb->data) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 if (new_skb->data != buf)
1370 printk(KERN_ERR "isdn_ppp: FATAL error after slhc_compress!!\n");
1371 dev_kfree_skb(skb);
1372 skb = new_skb;
1373 } else {
1374 dev_kfree_skb(new_skb);
1375 }
1376
1377 skb_trim(skb, pktlen);
1378 if (skb->data[0] & SL_TYPE_COMPRESSED_TCP) { /* cslip? style -> PPP */
1379 proto = PPP_VJC_COMP;
1380 skb->data[0] ^= SL_TYPE_COMPRESSED_TCP;
1381 } else {
1382 if (skb->data[0] >= SL_TYPE_UNCOMPRESSED_TCP)
1383 proto = PPP_VJC_UNCOMP;
1384 skb->data[0] = (skb->data[0] & 0x0f) | 0x40;
1385 }
1386 }
1387 }
1388#endif
1389
1390 /*
1391 * normal (single link) or bundle compression
1392 */
Joe Perches475be4d2012-02-19 19:52:38 -08001393 if (ipts->compflags & SC_COMP_ON) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394 /* We send compressed only if both down- und upstream
1395 compression is negotiated, that means, CCP is up */
Joe Perches475be4d2012-02-19 19:52:38 -08001396 if (ipts->compflags & SC_DECOMP_ON) {
1397 skb = isdn_ppp_compress(skb, &proto, ipt, ipts, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398 } else {
1399 printk(KERN_DEBUG "isdn_ppp: CCP not yet up - sending as-is\n");
1400 }
1401 }
1402
1403 if (ipt->debug & 0x24)
1404 printk(KERN_DEBUG "xmit2 skb, len %d, proto %04x\n", (int) skb->len, proto);
1405
1406#ifdef CONFIG_ISDN_MPP
1407 if (ipt->mpppcfg & SC_MP_PROT) {
1408 /* we get mp_seqno from static isdn_net_local */
1409 long mp_seqno = ipts->mp_seqno;
1410 ipts->mp_seqno++;
1411 if (ipt->mpppcfg & SC_OUT_SHORT_SEQ) {
1412 unsigned char *data = isdn_ppp_skb_push(&skb, 3);
Joe Perches475be4d2012-02-19 19:52:38 -08001413 if (!data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414 goto unlock;
1415 mp_seqno &= 0xfff;
1416 data[0] = MP_BEGIN_FRAG | MP_END_FRAG | ((mp_seqno >> 8) & 0xf); /* (B)egin & (E)ndbit .. */
1417 data[1] = mp_seqno & 0xff;
1418 data[2] = proto; /* PID compression */
1419 } else {
1420 unsigned char *data = isdn_ppp_skb_push(&skb, 5);
Joe Perches475be4d2012-02-19 19:52:38 -08001421 if (!data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422 goto unlock;
1423 data[0] = MP_BEGIN_FRAG | MP_END_FRAG; /* (B)egin & (E)ndbit .. */
1424 data[1] = (mp_seqno >> 16) & 0xff; /* sequence number: 24bit */
1425 data[2] = (mp_seqno >> 8) & 0xff;
1426 data[3] = (mp_seqno >> 0) & 0xff;
1427 data[4] = proto; /* PID compression */
1428 }
1429 proto = PPP_MP; /* MP Protocol, 0x003d */
1430 }
1431#endif
1432
1433 /*
1434 * 'link in bundle' compression ...
1435 */
Joe Perches475be4d2012-02-19 19:52:38 -08001436 if (ipt->compflags & SC_LINK_COMP_ON)
1437 skb = isdn_ppp_compress(skb, &proto, ipt, ipts, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438
Joe Perches475be4d2012-02-19 19:52:38 -08001439 if ((ipt->pppcfg & SC_COMP_PROT) && (proto <= 0xff)) {
1440 unsigned char *data = isdn_ppp_skb_push(&skb, 1);
1441 if (!data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442 goto unlock;
1443 data[0] = proto & 0xff;
1444 }
1445 else {
Joe Perches475be4d2012-02-19 19:52:38 -08001446 unsigned char *data = isdn_ppp_skb_push(&skb, 2);
1447 if (!data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448 goto unlock;
1449 data[0] = (proto >> 8) & 0xff;
1450 data[1] = proto & 0xff;
1451 }
Joe Perches475be4d2012-02-19 19:52:38 -08001452 if (!(ipt->pppcfg & SC_COMP_AC)) {
1453 unsigned char *data = isdn_ppp_skb_push(&skb, 2);
1454 if (!data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455 goto unlock;
1456 data[0] = 0xff; /* All Stations */
1457 data[1] = 0x03; /* Unnumbered information */
1458 }
1459
1460 /* tx-stats are now updated via BSENT-callback */
1461
1462 if (ipts->debug & 0x40) {
1463 printk(KERN_DEBUG "skb xmit: len: %d\n", (int) skb->len);
Joe Perches475be4d2012-02-19 19:52:38 -08001464 isdn_ppp_frame_log("xmit", skb->data, skb->len, 32, ipt->unit, lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 }
Joe Perches475be4d2012-02-19 19:52:38 -08001466
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467 isdn_net_writebuf_skb(lp, skb);
1468
Joe Perches475be4d2012-02-19 19:52:38 -08001469unlock:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470 spin_unlock_bh(&lp->xmit_lock);
Joe Perches475be4d2012-02-19 19:52:38 -08001471out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 return retval;
1473}
1474
1475#ifdef CONFIG_IPPP_FILTER
1476/*
1477 * check if this packet may trigger auto-dial.
1478 */
1479
1480int isdn_ppp_autodial_filter(struct sk_buff *skb, isdn_net_local *lp)
1481{
1482 struct ippp_struct *is = ippp_table[lp->ppp_slot];
1483 u_int16_t proto;
1484 int drop = 0;
1485
1486 switch (ntohs(skb->protocol)) {
1487 case ETH_P_IP:
1488 proto = PPP_IP;
1489 break;
1490 case ETH_P_IPX:
1491 proto = PPP_IPX;
1492 break;
1493 default:
1494 printk(KERN_ERR "isdn_ppp_autodial_filter: unsupported protocol 0x%x.\n",
1495 skb->protocol);
1496 return 1;
1497 }
1498
1499 /* the filter instructions are constructed assuming
1500 * a four-byte PPP header on each packet. we have to
1501 * temporarily remove part of the fake header stuck on
1502 * earlier.
1503 */
Karsten Keild8470b72005-04-21 08:30:30 -07001504 *skb_pull(skb, IPPP_MAX_HEADER - 4) = 1; /* indicate outbound */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505
1506 {
Harvey Harrisonc19d0362008-11-20 04:10:51 -08001507 __be16 *p = (__be16 *)skb->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508
Karsten Keild8470b72005-04-21 08:30:30 -07001509 p++;
Harvey Harrisonc19d0362008-11-20 04:10:51 -08001510 *p = htons(proto);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 }
Joe Perches475be4d2012-02-19 19:52:38 -08001512
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513 drop |= is->pass_filter
Daniel Borkmann77e01142014-03-28 18:58:24 +01001514 && SK_RUN_FILTER(is->pass_filter, skb) == 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515 drop |= is->active_filter
Daniel Borkmann77e01142014-03-28 18:58:24 +01001516 && SK_RUN_FILTER(is->active_filter, skb) == 0;
Joe Perches475be4d2012-02-19 19:52:38 -08001517
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518 skb_push(skb, IPPP_MAX_HEADER - 4);
1519 return drop;
1520}
1521#endif
1522#ifdef CONFIG_ISDN_MPP
1523
1524/* this is _not_ rfc1990 header, but something we convert both short and long
1525 * headers to for convinience's sake:
Joe Perches475be4d2012-02-19 19:52:38 -08001526 * byte 0 is flags as in rfc1990
1527 * bytes 1...4 is 24-bit seqence number converted to host byte order
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528 */
1529#define MP_HEADER_LEN 5
1530
1531#define MP_LONGSEQ_MASK 0x00ffffff
1532#define MP_SHORTSEQ_MASK 0x00000fff
1533#define MP_LONGSEQ_MAX MP_LONGSEQ_MASK
1534#define MP_SHORTSEQ_MAX MP_SHORTSEQ_MASK
Joe Perches475be4d2012-02-19 19:52:38 -08001535#define MP_LONGSEQ_MAXBIT ((MP_LONGSEQ_MASK + 1) >> 1)
1536#define MP_SHORTSEQ_MAXBIT ((MP_SHORTSEQ_MASK + 1) >> 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537
Lucas De Marchi25985ed2011-03-30 22:57:33 -03001538/* sequence-wrap safe comparisons (for long sequence)*/
Joe Perches475be4d2012-02-19 19:52:38 -08001539#define MP_LT(a, b) ((a - b) & MP_LONGSEQ_MAXBIT)
1540#define MP_LE(a, b) !((b - a) & MP_LONGSEQ_MAXBIT)
1541#define MP_GT(a, b) ((b - a) & MP_LONGSEQ_MAXBIT)
1542#define MP_GE(a, b) !((a - b) & MP_LONGSEQ_MAXBIT)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543
Joe Perches475be4d2012-02-19 19:52:38 -08001544#define MP_SEQ(f) ((*(u32 *)(f->data + 1)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545#define MP_FLAGS(f) (f->data[0])
1546
1547static int isdn_ppp_mp_bundle_array_init(void)
1548{
1549 int i;
Joe Perches475be4d2012-02-19 19:52:38 -08001550 int sz = ISDN_MAX_CHANNELS * sizeof(ippp_bundle);
1551 if ((isdn_ppp_bundle_arr = kzalloc(sz, GFP_KERNEL)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552 return -ENOMEM;
Joe Perches475be4d2012-02-19 19:52:38 -08001553 for (i = 0; i < ISDN_MAX_CHANNELS; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554 spin_lock_init(&isdn_ppp_bundle_arr[i].lock);
1555 return 0;
1556}
1557
Joe Perches475be4d2012-02-19 19:52:38 -08001558static ippp_bundle *isdn_ppp_mp_bundle_alloc(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559{
1560 int i;
Joe Perches475be4d2012-02-19 19:52:38 -08001561 for (i = 0; i < ISDN_MAX_CHANNELS; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562 if (isdn_ppp_bundle_arr[i].ref_ct <= 0)
1563 return (isdn_ppp_bundle_arr + i);
1564 return NULL;
1565}
1566
Joe Perches475be4d2012-02-19 19:52:38 -08001567static int isdn_ppp_mp_init(isdn_net_local *lp, ippp_bundle *add_to)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568{
Joe Perches475be4d2012-02-19 19:52:38 -08001569 struct ippp_struct *is;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570
1571 if (lp->ppp_slot < 0) {
1572 printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
Joe Perches475be4d2012-02-19 19:52:38 -08001573 __func__, lp->ppp_slot);
1574 return (-EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575 }
1576
1577 is = ippp_table[lp->ppp_slot];
1578 if (add_to) {
Joe Perches475be4d2012-02-19 19:52:38 -08001579 if (lp->netdev->pb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580 lp->netdev->pb->ref_ct--;
1581 lp->netdev->pb = add_to;
1582 } else { /* first link in a bundle */
1583 is->mp_seqno = 0;
1584 if ((lp->netdev->pb = isdn_ppp_mp_bundle_alloc()) == NULL)
1585 return -ENOMEM;
1586 lp->next = lp->last = lp; /* nobody else in a queue */
David S. Millere29d4362009-11-15 22:23:47 -08001587 lp->netdev->pb->frags = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588 lp->netdev->pb->frames = 0;
1589 lp->netdev->pb->seq = UINT_MAX;
1590 }
1591 lp->netdev->pb->ref_ct++;
Joe Perches475be4d2012-02-19 19:52:38 -08001592
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593 is->last_link_seqno = 0;
1594 return 0;
1595}
1596
Joe Perches475be4d2012-02-19 19:52:38 -08001597static u32 isdn_ppp_mp_get_seq(int short_seq,
1598 struct sk_buff *skb, u32 last_seq);
1599static struct sk_buff *isdn_ppp_mp_discard(ippp_bundle *mp,
1600 struct sk_buff *from, struct sk_buff *to);
1601static void isdn_ppp_mp_reassembly(isdn_net_dev *net_dev, isdn_net_local *lp,
1602 struct sk_buff *from, struct sk_buff *to);
1603static void isdn_ppp_mp_free_skb(ippp_bundle *mp, struct sk_buff *skb);
1604static void isdn_ppp_mp_print_recv_pkt(int slot, struct sk_buff *skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605
Joe Perches475be4d2012-02-19 19:52:38 -08001606static void isdn_ppp_mp_receive(isdn_net_dev *net_dev, isdn_net_local *lp,
1607 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608{
David S. Miller38783e62008-09-22 01:15:02 -07001609 struct ippp_struct *is;
Joe Perches475be4d2012-02-19 19:52:38 -08001610 isdn_net_local *lpq;
1611 ippp_bundle *mp;
1612 isdn_mppp_stats *stats;
1613 struct sk_buff *newfrag, *frag, *start, *nextf;
David S. Millere29d4362009-11-15 22:23:47 -08001614 u32 newseq, minseq, thisseq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615 unsigned long flags;
1616 int slot;
1617
1618 spin_lock_irqsave(&net_dev->pb->lock, flags);
Joe Perches475be4d2012-02-19 19:52:38 -08001619 mp = net_dev->pb;
1620 stats = &mp->stats;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621 slot = lp->ppp_slot;
Eric Sesterhenn052bb882006-04-11 17:29:17 -07001622 if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 printk(KERN_ERR "%s: lp->ppp_slot(%d)\n",
Joe Perches475be4d2012-02-19 19:52:38 -08001624 __func__, lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625 stats->frame_drops++;
1626 dev_kfree_skb(skb);
1627 spin_unlock_irqrestore(&mp->lock, flags);
1628 return;
1629 }
1630 is = ippp_table[slot];
Joe Perches475be4d2012-02-19 19:52:38 -08001631 if (++mp->frames > stats->max_queue_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632 stats->max_queue_len = mp->frames;
Joe Perches475be4d2012-02-19 19:52:38 -08001633
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634 if (is->debug & 0x8)
1635 isdn_ppp_mp_print_recv_pkt(lp->ppp_slot, skb);
1636
Joe Perches475be4d2012-02-19 19:52:38 -08001637 newseq = isdn_ppp_mp_get_seq(is->mpppcfg & SC_IN_SHORT_SEQ,
1638 skb, is->last_link_seqno);
David S. Millere29d4362009-11-15 22:23:47 -08001639
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640
1641 /* if this packet seq # is less than last already processed one,
Joe Perches475be4d2012-02-19 19:52:38 -08001642 * toss it right away, but check for sequence start case first
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643 */
Joe Perches475be4d2012-02-19 19:52:38 -08001644 if (mp->seq > MP_LONGSEQ_MAX && (newseq & MP_LONGSEQ_MAXBIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645 mp->seq = newseq; /* the first packet: required for
1646 * rfc1990 non-compliant clients --
1647 * prevents constant packet toss */
Joe Perches475be4d2012-02-19 19:52:38 -08001648 } else if (MP_LT(newseq, mp->seq)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649 stats->frame_drops++;
1650 isdn_ppp_mp_free_skb(mp, skb);
1651 spin_unlock_irqrestore(&mp->lock, flags);
1652 return;
1653 }
Joe Perches475be4d2012-02-19 19:52:38 -08001654
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655 /* find the minimum received sequence number over all links */
1656 is->last_link_seqno = minseq = newseq;
1657 for (lpq = net_dev->queue;;) {
1658 slot = lpq->ppp_slot;
Eric Sesterhenn052bb882006-04-11 17:29:17 -07001659 if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660 printk(KERN_ERR "%s: lpq->ppp_slot(%d)\n",
Joe Perches475be4d2012-02-19 19:52:38 -08001661 __func__, lpq->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662 } else {
1663 u32 lls = ippp_table[slot]->last_link_seqno;
1664 if (MP_LT(lls, minseq))
1665 minseq = lls;
1666 }
1667 if ((lpq = lpq->next) == net_dev->queue)
1668 break;
1669 }
1670 if (MP_LT(minseq, mp->seq))
1671 minseq = mp->seq; /* can't go beyond already processed
1672 * packets */
1673 newfrag = skb;
1674
Joe Perches475be4d2012-02-19 19:52:38 -08001675 /* if this new fragment is before the first one, then enqueue it now. */
1676 if ((frag = mp->frags) == NULL || MP_LT(newseq, MP_SEQ(frag))) {
David S. Millere29d4362009-11-15 22:23:47 -08001677 newfrag->next = frag;
Joe Perches475be4d2012-02-19 19:52:38 -08001678 mp->frags = frag = newfrag;
1679 newfrag = NULL;
1680 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681
Joe Perches475be4d2012-02-19 19:52:38 -08001682 start = MP_FLAGS(frag) & MP_BEGIN_FRAG &&
1683 MP_SEQ(frag) == mp->seq ? frag : NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684
Joe Perches475be4d2012-02-19 19:52:38 -08001685 /*
David S. Millere29d4362009-11-15 22:23:47 -08001686 * main fragment traversing loop
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687 *
1688 * try to accomplish several tasks:
David S. Millere29d4362009-11-15 22:23:47 -08001689 * - insert new fragment into the proper sequence slot (once that's done
1690 * newfrag will be set to NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691 * - reassemble any complete fragment sequence (non-null 'start'
André Goddard Rosaaf901ca2009-11-14 13:09:05 -02001692 * indicates there is a contiguous sequence present)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693 * - discard any incomplete sequences that are below minseq -- due
1694 * to the fact that sender always increment sequence number, if there
1695 * is an incomplete sequence below minseq, no new fragments would
1696 * come to complete such sequence and it should be discarded
1697 *
1698 * loop completes when we accomplished the following tasks:
Joe Perches475be4d2012-02-19 19:52:38 -08001699 * - new fragment is inserted in the proper sequence ('newfrag' is
David S. Millere29d4362009-11-15 22:23:47 -08001700 * set to NULL)
Joe Perches475be4d2012-02-19 19:52:38 -08001701 * - we hit a gap in the sequence, so no reassembly/processing is
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702 * possible ('start' would be set to NULL)
1703 *
Robert P. J. Dayd08df602007-02-17 19:07:33 +01001704 * algorithm for this code is derived from code in the book
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 * 'PPP Design And Debugging' by James Carlson (Addison-Wesley)
1706 */
Joe Perches475be4d2012-02-19 19:52:38 -08001707 while (start != NULL || newfrag != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708
Joe Perches475be4d2012-02-19 19:52:38 -08001709 thisseq = MP_SEQ(frag);
1710 nextf = frag->next;
David S. Millere29d4362009-11-15 22:23:47 -08001711
Joe Perches475be4d2012-02-19 19:52:38 -08001712 /* drop any duplicate fragments */
1713 if (newfrag != NULL && thisseq == newseq) {
1714 isdn_ppp_mp_free_skb(mp, newfrag);
1715 newfrag = NULL;
1716 }
David S. Millere29d4362009-11-15 22:23:47 -08001717
Joe Perches475be4d2012-02-19 19:52:38 -08001718 /* insert new fragment before next element if possible. */
1719 if (newfrag != NULL && (nextf == NULL ||
1720 MP_LT(newseq, MP_SEQ(nextf)))) {
1721 newfrag->next = nextf;
1722 frag->next = nextf = newfrag;
1723 newfrag = NULL;
1724 }
David S. Millere29d4362009-11-15 22:23:47 -08001725
Joe Perches475be4d2012-02-19 19:52:38 -08001726 if (start != NULL) {
1727 /* check for misplaced start */
1728 if (start != frag && (MP_FLAGS(frag) & MP_BEGIN_FRAG)) {
David S. Millere29d4362009-11-15 22:23:47 -08001729 printk(KERN_WARNING"isdn_mppp(seq %d): new "
Joe Perches475be4d2012-02-19 19:52:38 -08001730 "BEGIN flag with no prior END", thisseq);
David S. Millere29d4362009-11-15 22:23:47 -08001731 stats->seqerrs++;
1732 stats->frame_drops++;
Joe Perches475be4d2012-02-19 19:52:38 -08001733 start = isdn_ppp_mp_discard(mp, start, frag);
David S. Millere29d4362009-11-15 22:23:47 -08001734 nextf = frag->next;
Joe Perches475be4d2012-02-19 19:52:38 -08001735 }
1736 } else if (MP_LE(thisseq, minseq)) {
1737 if (MP_FLAGS(frag) & MP_BEGIN_FRAG)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738 start = frag;
Joe Perches475be4d2012-02-19 19:52:38 -08001739 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740 if (MP_FLAGS(frag) & MP_END_FRAG)
Joe Perches475be4d2012-02-19 19:52:38 -08001741 stats->frame_drops++;
1742 if (mp->frags == frag)
1743 mp->frags = nextf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744 isdn_ppp_mp_free_skb(mp, frag);
David S. Millere29d4362009-11-15 22:23:47 -08001745 frag = nextf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746 continue;
Joe Perches475be4d2012-02-19 19:52:38 -08001747 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748 }
Joe Perches475be4d2012-02-19 19:52:38 -08001749
David S. Millere29d4362009-11-15 22:23:47 -08001750 /* if start is non-null and we have end fragment, then
Joe Perches475be4d2012-02-19 19:52:38 -08001751 * we have full reassembly sequence -- reassemble
David S. Millere29d4362009-11-15 22:23:47 -08001752 * and process packet now
David S. Miller38783e62008-09-22 01:15:02 -07001753 */
Joe Perches475be4d2012-02-19 19:52:38 -08001754 if (start != NULL && (MP_FLAGS(frag) & MP_END_FRAG)) {
1755 minseq = mp->seq = (thisseq + 1) & MP_LONGSEQ_MASK;
1756 /* Reassemble the packet then dispatch it */
David S. Millere29d4362009-11-15 22:23:47 -08001757 isdn_ppp_mp_reassembly(net_dev, lp, start, nextf);
David S. Miller38783e62008-09-22 01:15:02 -07001758
Joe Perches475be4d2012-02-19 19:52:38 -08001759 start = NULL;
1760 frag = NULL;
1761
1762 mp->frags = nextf;
1763 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764
1765 /* check if need to update start pointer: if we just
1766 * reassembled the packet and sequence is contiguous
1767 * then next fragment should be the start of new reassembly
1768 * if sequence is contiguous, but we haven't reassembled yet,
1769 * keep going.
Lucas De Marchi25985ed2011-03-30 22:57:33 -03001770 * if sequence is not contiguous, either clear everything
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771 * below low watermark and set start to the next frag or
1772 * clear start ptr.
Joe Perches475be4d2012-02-19 19:52:38 -08001773 */
1774 if (nextf != NULL &&
1775 ((thisseq + 1) & MP_LONGSEQ_MASK) == MP_SEQ(nextf)) {
1776 /* if we just reassembled and the next one is here,
David S. Millere29d4362009-11-15 22:23:47 -08001777 * then start another reassembly. */
1778
Joe Perches475be4d2012-02-19 19:52:38 -08001779 if (frag == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780 if (MP_FLAGS(nextf) & MP_BEGIN_FRAG)
Joe Perches475be4d2012-02-19 19:52:38 -08001781 start = nextf;
David S. Millere29d4362009-11-15 22:23:47 -08001782 else
1783 {
Joe Perches475be4d2012-02-19 19:52:38 -08001784 printk(KERN_WARNING"isdn_mppp(seq %d):"
1785 " END flag with no following "
1786 "BEGIN", thisseq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787 stats->seqerrs++;
1788 }
1789 }
David S. Millere29d4362009-11-15 22:23:47 -08001790
Joe Perches475be4d2012-02-19 19:52:38 -08001791 } else {
1792 if (nextf != NULL && frag != NULL &&
1793 MP_LT(thisseq, minseq)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001794 /* we've got a break in the sequence
1795 * and we not at the end yet
1796 * and we did not just reassembled
1797 *(if we did, there wouldn't be anything before)
Joe Perches475be4d2012-02-19 19:52:38 -08001798 * and we below the low watermark
1799 * discard all the frames below low watermark
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800 * and start over */
1801 stats->frame_drops++;
Joe Perches475be4d2012-02-19 19:52:38 -08001802 mp->frags = isdn_ppp_mp_discard(mp, start, nextf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803 }
1804 /* break in the sequence, no reassembly */
Joe Perches475be4d2012-02-19 19:52:38 -08001805 start = NULL;
1806 }
1807
1808 frag = nextf;
1809 } /* while -- main loop */
1810
1811 if (mp->frags == NULL)
1812 mp->frags = frag;
1813
1814 /* rather straighforward way to deal with (not very) possible
David S. Millere29d4362009-11-15 22:23:47 -08001815 * queue overflow */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001816 if (mp->frames > MP_MAX_QUEUE_LEN) {
1817 stats->overflows++;
David S. Millere29d4362009-11-15 22:23:47 -08001818 while (mp->frames > MP_MAX_QUEUE_LEN) {
1819 frag = mp->frags->next;
1820 isdn_ppp_mp_free_skb(mp, mp->frags);
1821 mp->frags = frag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822 }
1823 }
1824 spin_unlock_irqrestore(&mp->lock, flags);
1825}
1826
Joe Perches475be4d2012-02-19 19:52:38 -08001827static void isdn_ppp_mp_cleanup(isdn_net_local *lp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828{
Joe Perches475be4d2012-02-19 19:52:38 -08001829 struct sk_buff *frag = lp->netdev->pb->frags;
1830 struct sk_buff *nextfrag;
1831 while (frag) {
David S. Millere29d4362009-11-15 22:23:47 -08001832 nextfrag = frag->next;
1833 isdn_ppp_mp_free_skb(lp->netdev->pb, frag);
1834 frag = nextfrag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001835 }
David S. Millere29d4362009-11-15 22:23:47 -08001836 lp->netdev->pb->frags = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837}
1838
Joe Perches475be4d2012-02-19 19:52:38 -08001839static u32 isdn_ppp_mp_get_seq(int short_seq,
1840 struct sk_buff *skb, u32 last_seq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841{
1842 u32 seq;
1843 int flags = skb->data[0] & (MP_BEGIN_FRAG | MP_END_FRAG);
Joe Perches475be4d2012-02-19 19:52:38 -08001844
1845 if (!short_seq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846 {
Harvey Harrisonc19d0362008-11-20 04:10:51 -08001847 seq = ntohl(*(__be32 *)skb->data) & MP_LONGSEQ_MASK;
Joe Perches475be4d2012-02-19 19:52:38 -08001848 skb_push(skb, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849 }
1850 else
1851 {
Joe Perches475be4d2012-02-19 19:52:38 -08001852 /* convert 12-bit short seq number to 24-bit long one
1853 */
Harvey Harrisonc19d0362008-11-20 04:10:51 -08001854 seq = ntohs(*(__be16 *)skb->data) & MP_SHORTSEQ_MASK;
Joe Perches475be4d2012-02-19 19:52:38 -08001855
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856 /* check for seqence wrap */
Joe Perches475be4d2012-02-19 19:52:38 -08001857 if (!(seq & MP_SHORTSEQ_MAXBIT) &&
1858 (last_seq & MP_SHORTSEQ_MAXBIT) &&
1859 (unsigned long)last_seq <= MP_LONGSEQ_MAX)
1860 seq |= (last_seq + MP_SHORTSEQ_MAX + 1) &
1861 (~MP_SHORTSEQ_MASK & MP_LONGSEQ_MASK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 else
1863 seq |= last_seq & (~MP_SHORTSEQ_MASK & MP_LONGSEQ_MASK);
Joe Perches475be4d2012-02-19 19:52:38 -08001864
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 skb_push(skb, 3); /* put converted seqence back in skb */
1866 }
Joe Perches475be4d2012-02-19 19:52:38 -08001867 *(u32 *)(skb->data + 1) = seq; /* put seqence back in _host_ byte
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 * order */
1869 skb->data[0] = flags; /* restore flags */
1870 return seq;
1871}
1872
Joe Perches475be4d2012-02-19 19:52:38 -08001873struct sk_buff *isdn_ppp_mp_discard(ippp_bundle *mp,
1874 struct sk_buff *from, struct sk_buff *to)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875{
Joe Perches475be4d2012-02-19 19:52:38 -08001876 if (from)
David S. Millere29d4362009-11-15 22:23:47 -08001877 while (from != to) {
Joe Perches475be4d2012-02-19 19:52:38 -08001878 struct sk_buff *next = from->next;
David S. Millere29d4362009-11-15 22:23:47 -08001879 isdn_ppp_mp_free_skb(mp, from);
Joe Perches475be4d2012-02-19 19:52:38 -08001880 from = next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881 }
David S. Millere29d4362009-11-15 22:23:47 -08001882 return from;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883}
1884
Joe Perches475be4d2012-02-19 19:52:38 -08001885void isdn_ppp_mp_reassembly(isdn_net_dev *net_dev, isdn_net_local *lp,
1886 struct sk_buff *from, struct sk_buff *to)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887{
Joe Perches475be4d2012-02-19 19:52:38 -08001888 ippp_bundle *mp = net_dev->pb;
David S. Miller38783e62008-09-22 01:15:02 -07001889 int proto;
Joe Perches475be4d2012-02-19 19:52:38 -08001890 struct sk_buff *skb;
David S. Millere29d4362009-11-15 22:23:47 -08001891 unsigned int tot_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892
1893 if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
1894 printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
Joe Perches475be4d2012-02-19 19:52:38 -08001895 __func__, lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896 return;
1897 }
Joe Perches475be4d2012-02-19 19:52:38 -08001898 if (MP_FLAGS(from) == (MP_BEGIN_FRAG | MP_END_FRAG)) {
1899 if (ippp_table[lp->ppp_slot]->debug & 0x40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900 printk(KERN_DEBUG "isdn_mppp: reassembly: frame %d, "
Joe Perches475be4d2012-02-19 19:52:38 -08001901 "len %d\n", MP_SEQ(from), from->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902 skb = from;
1903 skb_pull(skb, MP_HEADER_LEN);
Joe Perches475be4d2012-02-19 19:52:38 -08001904 mp->frames--;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905 } else {
Joe Perches475be4d2012-02-19 19:52:38 -08001906 struct sk_buff *frag;
David S. Millere29d4362009-11-15 22:23:47 -08001907 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908
Joe Perches475be4d2012-02-19 19:52:38 -08001909 for (tot_len = n = 0, frag = from; frag != to; frag = frag->next, n++)
David S. Millere29d4362009-11-15 22:23:47 -08001910 tot_len += frag->len - MP_HEADER_LEN;
1911
Joe Perches475be4d2012-02-19 19:52:38 -08001912 if (ippp_table[lp->ppp_slot]->debug & 0x40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913 printk(KERN_DEBUG"isdn_mppp: reassembling frames %d "
Joe Perches475be4d2012-02-19 19:52:38 -08001914 "to %d, len %d\n", MP_SEQ(from),
1915 (MP_SEQ(from) + n - 1) & MP_LONGSEQ_MASK, tot_len);
1916 if ((skb = dev_alloc_skb(tot_len)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917 printk(KERN_ERR "isdn_mppp: cannot allocate sk buff "
Joe Perches475be4d2012-02-19 19:52:38 -08001918 "of size %d\n", tot_len);
David S. Millere29d4362009-11-15 22:23:47 -08001919 isdn_ppp_mp_discard(mp, from, to);
1920 return;
1921 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922
Joe Perches475be4d2012-02-19 19:52:38 -08001923 while (from != to) {
David S. Millere29d4362009-11-15 22:23:47 -08001924 unsigned int len = from->len - MP_HEADER_LEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925
David S. Millere29d4362009-11-15 22:23:47 -08001926 skb_copy_from_linear_data_offset(from, MP_HEADER_LEN,
Joe Perches475be4d2012-02-19 19:52:38 -08001927 skb_put(skb, len),
David S. Millere29d4362009-11-15 22:23:47 -08001928 len);
1929 frag = from->next;
1930 isdn_ppp_mp_free_skb(mp, from);
Joe Perches475be4d2012-02-19 19:52:38 -08001931 from = frag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932 }
1933 }
Joe Perches475be4d2012-02-19 19:52:38 -08001934 proto = isdn_ppp_strip_proto(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935 isdn_ppp_push_higher(net_dev, lp, skb, proto);
1936}
1937
Joe Perches475be4d2012-02-19 19:52:38 -08001938static void isdn_ppp_mp_free_skb(ippp_bundle *mp, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939{
1940 dev_kfree_skb(skb);
1941 mp->frames--;
1942}
1943
Joe Perches475be4d2012-02-19 19:52:38 -08001944static void isdn_ppp_mp_print_recv_pkt(int slot, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945{
Joe Perches475be4d2012-02-19 19:52:38 -08001946 printk(KERN_DEBUG "mp_recv: %d/%d -> %02x %02x %02x %02x %02x %02x\n",
1947 slot, (int) skb->len,
1948 (int) skb->data[0], (int) skb->data[1], (int) skb->data[2],
1949 (int) skb->data[3], (int) skb->data[4], (int) skb->data[5]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950}
1951
1952static int
1953isdn_ppp_bundle(struct ippp_struct *is, int unit)
1954{
1955 char ifn[IFNAMSIZ + 1];
1956 isdn_net_dev *p;
1957 isdn_net_local *lp, *nlp;
1958 int rc;
1959 unsigned long flags;
1960
1961 sprintf(ifn, "ippp%d", unit);
1962 p = isdn_net_findif(ifn);
1963 if (!p) {
1964 printk(KERN_ERR "ippp_bundle: cannot find %s\n", ifn);
1965 return -EINVAL;
1966 }
1967
Joe Perches475be4d2012-02-19 19:52:38 -08001968 spin_lock_irqsave(&p->pb->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001969
1970 nlp = is->lp;
1971 lp = p->queue;
Joe Perches475be4d2012-02-19 19:52:38 -08001972 if (nlp->ppp_slot < 0 || nlp->ppp_slot >= ISDN_MAX_CHANNELS ||
1973 lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001974 printk(KERN_ERR "ippp_bundle: binding to invalid slot %d\n",
Joe Perches475be4d2012-02-19 19:52:38 -08001975 nlp->ppp_slot < 0 || nlp->ppp_slot >= ISDN_MAX_CHANNELS ?
1976 nlp->ppp_slot : lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977 rc = -EINVAL;
1978 goto out;
Joe Perches475be4d2012-02-19 19:52:38 -08001979 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980
1981 isdn_net_add_to_bundle(p, nlp);
1982
1983 ippp_table[nlp->ppp_slot]->unit = ippp_table[lp->ppp_slot]->unit;
1984
1985 /* maybe also SC_CCP stuff */
1986 ippp_table[nlp->ppp_slot]->pppcfg |= ippp_table[lp->ppp_slot]->pppcfg &
1987 (SC_ENABLE_IP | SC_NO_TCP_CCID | SC_REJ_COMP_TCP);
1988 ippp_table[nlp->ppp_slot]->mpppcfg |= ippp_table[lp->ppp_slot]->mpppcfg &
1989 (SC_MP_PROT | SC_REJ_MP_PROT | SC_OUT_SHORT_SEQ | SC_IN_SHORT_SEQ);
1990 rc = isdn_ppp_mp_init(nlp, p->pb);
1991out:
1992 spin_unlock_irqrestore(&p->pb->lock, flags);
1993 return rc;
1994}
Joe Perches475be4d2012-02-19 19:52:38 -08001995
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996#endif /* CONFIG_ISDN_MPP */
Joe Perches475be4d2012-02-19 19:52:38 -08001997
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998/*
1999 * network device ioctl handlers
2000 */
2001
2002static int
2003isdn_ppp_dev_ioctl_stats(int slot, struct ifreq *ifr, struct net_device *dev)
2004{
2005 struct ppp_stats __user *res = ifr->ifr_data;
2006 struct ppp_stats t;
Joe Perchesa17531f2010-11-15 11:12:24 +00002007 isdn_net_local *lp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008
2009 if (!access_ok(VERIFY_WRITE, res, sizeof(struct ppp_stats)))
2010 return -EFAULT;
2011
2012 /* build a temporary stat struct and copy it to user space */
2013
2014 memset(&t, 0, sizeof(struct ppp_stats));
2015 if (dev->flags & IFF_UP) {
2016 t.p.ppp_ipackets = lp->stats.rx_packets;
2017 t.p.ppp_ibytes = lp->stats.rx_bytes;
2018 t.p.ppp_ierrors = lp->stats.rx_errors;
2019 t.p.ppp_opackets = lp->stats.tx_packets;
2020 t.p.ppp_obytes = lp->stats.tx_bytes;
2021 t.p.ppp_oerrors = lp->stats.tx_errors;
2022#ifdef CONFIG_ISDN_PPP_VJ
2023 if (slot >= 0 && ippp_table[slot]->slcomp) {
2024 struct slcompress *slcomp = ippp_table[slot]->slcomp;
2025 t.vj.vjs_packets = slcomp->sls_o_compressed + slcomp->sls_o_uncompressed;
2026 t.vj.vjs_compressed = slcomp->sls_o_compressed;
2027 t.vj.vjs_searches = slcomp->sls_o_searches;
2028 t.vj.vjs_misses = slcomp->sls_o_misses;
2029 t.vj.vjs_errorin = slcomp->sls_i_error;
2030 t.vj.vjs_tossed = slcomp->sls_i_tossed;
2031 t.vj.vjs_uncompressedin = slcomp->sls_i_uncompressed;
2032 t.vj.vjs_compressedin = slcomp->sls_i_compressed;
2033 }
2034#endif
2035 }
2036 if (copy_to_user(res, &t, sizeof(struct ppp_stats)))
2037 return -EFAULT;
2038 return 0;
2039}
2040
2041int
2042isdn_ppp_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
2043{
Joe Perches475be4d2012-02-19 19:52:38 -08002044 int error = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045 int len;
Joe Perchesa17531f2010-11-15 11:12:24 +00002046 isdn_net_local *lp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047
2048
2049 if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP)
2050 return -EINVAL;
2051
2052 switch (cmd) {
2053#define PPP_VERSION "2.3.7"
Joe Perches475be4d2012-02-19 19:52:38 -08002054 case SIOCGPPPVER:
2055 len = strlen(PPP_VERSION) + 1;
2056 if (copy_to_user(ifr->ifr_data, PPP_VERSION, len))
2057 error = -EFAULT;
2058 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002059
Joe Perches475be4d2012-02-19 19:52:38 -08002060 case SIOCGPPPSTATS:
2061 error = isdn_ppp_dev_ioctl_stats(lp->ppp_slot, ifr, dev);
2062 break;
2063 default:
2064 error = -EINVAL;
2065 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066 }
2067 return error;
2068}
2069
2070static int
2071isdn_ppp_if_get_unit(char *name)
2072{
2073 int len,
Joe Perches475be4d2012-02-19 19:52:38 -08002074 i,
2075 unit = 0,
2076 deci;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077
2078 len = strlen(name);
2079
2080 if (strncmp("ippp", name, 4) || len > 8)
2081 return -1;
2082
2083 for (i = 0, deci = 1; i < len; i++, deci *= 10) {
2084 char a = name[len - i - 1];
2085 if (a >= '0' && a <= '9')
2086 unit += (a - '0') * deci;
2087 else
2088 break;
2089 }
2090 if (!i || len - i != 4)
2091 unit = -1;
2092
2093 return unit;
2094}
2095
2096
2097int
2098isdn_ppp_dial_slave(char *name)
2099{
2100#ifdef CONFIG_ISDN_MPP
2101 isdn_net_dev *ndev;
2102 isdn_net_local *lp;
2103 struct net_device *sdev;
2104
2105 if (!(ndev = isdn_net_findif(name)))
2106 return 1;
2107 lp = ndev->local;
2108 if (!(lp->flags & ISDN_NET_CONNECTED))
2109 return 5;
2110
2111 sdev = lp->slave;
2112 while (sdev) {
Joe Perchesa17531f2010-11-15 11:12:24 +00002113 isdn_net_local *mlp = netdev_priv(sdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114 if (!(mlp->flags & ISDN_NET_CONNECTED))
2115 break;
2116 sdev = mlp->slave;
2117 }
2118 if (!sdev)
2119 return 2;
2120
Joe Perchesa17531f2010-11-15 11:12:24 +00002121 isdn_net_dial_req(netdev_priv(sdev));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122 return 0;
2123#else
2124 return -1;
2125#endif
2126}
2127
2128int
2129isdn_ppp_hangup_slave(char *name)
2130{
2131#ifdef CONFIG_ISDN_MPP
2132 isdn_net_dev *ndev;
2133 isdn_net_local *lp;
2134 struct net_device *sdev;
2135
2136 if (!(ndev = isdn_net_findif(name)))
2137 return 1;
2138 lp = ndev->local;
2139 if (!(lp->flags & ISDN_NET_CONNECTED))
2140 return 5;
2141
2142 sdev = lp->slave;
2143 while (sdev) {
Joe Perchesa17531f2010-11-15 11:12:24 +00002144 isdn_net_local *mlp = netdev_priv(sdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002145
2146 if (mlp->slave) { /* find last connected link in chain */
Wang Chen838361f2008-12-03 15:49:46 -08002147 isdn_net_local *nlp = ISDN_SLAVE_PRIV(mlp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002148
2149 if (!(nlp->flags & ISDN_NET_CONNECTED))
2150 break;
2151 } else if (mlp->flags & ISDN_NET_CONNECTED)
2152 break;
Joe Perches475be4d2012-02-19 19:52:38 -08002153
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154 sdev = mlp->slave;
2155 }
2156 if (!sdev)
2157 return 2;
2158
2159 isdn_net_hangup(sdev);
2160 return 0;
2161#else
2162 return -1;
2163#endif
2164}
2165
2166/*
2167 * PPP compression stuff
2168 */
2169
2170
2171/* Push an empty CCP Data Frame up to the daemon to wake it up and let it
2172 generate a CCP Reset-Request or tear down CCP altogether */
2173
2174static void isdn_ppp_ccp_kickup(struct ippp_struct *is)
2175{
2176 isdn_ppp_fill_rq(NULL, 0, PPP_COMP, is->lp->ppp_slot);
2177}
2178
2179/* In-kernel handling of CCP Reset-Request and Reset-Ack is necessary,
2180 but absolutely nontrivial. The most abstruse problem we are facing is
2181 that the generation, reception and all the handling of timeouts and
2182 resends including proper request id management should be entirely left
2183 to the (de)compressor, but indeed is not covered by the current API to
2184 the (de)compressor. The API is a prototype version from PPP where only
2185 some (de)compressors have yet been implemented and all of them are
2186 rather simple in their reset handling. Especially, their is only one
2187 outstanding ResetAck at a time with all of them and ResetReq/-Acks do
2188 not have parameters. For this very special case it was sufficient to
2189 just return an error code from the decompressor and have a single
2190 reset() entry to communicate all the necessary information between
2191 the framework and the (de)compressor. Bad enough, LZS is different
2192 (and any other compressor may be different, too). It has multiple
2193 histories (eventually) and needs to Reset each of them independently
2194 and thus uses multiple outstanding Acks and history numbers as an
2195 additional parameter to Reqs/Acks.
2196 All that makes it harder to port the reset state engine into the
2197 kernel because it is not just the same simple one as in (i)pppd but
2198 it must be able to pass additional parameters and have multiple out-
2199 standing Acks. We are trying to achieve the impossible by handling
2200 reset transactions independent by their id. The id MUST change when
2201 the data portion changes, thus any (de)compressor who uses more than
2202 one resettable state must provide and recognize individual ids for
2203 each individual reset transaction. The framework itself does _only_
2204 differentiate them by id, because it has no other semantics like the
2205 (de)compressor might.
2206 This looks like a major redesign of the interface would be nice,
2207 but I don't have an idea how to do it better. */
2208
2209/* Send a CCP Reset-Request or Reset-Ack directly from the kernel. This is
2210 getting that lengthy because there is no simple "send-this-frame-out"
2211 function above but every wrapper does a bit different. Hope I guess
2212 correct in this hack... */
2213
2214static void isdn_ppp_ccp_xmit_reset(struct ippp_struct *is, int proto,
2215 unsigned char code, unsigned char id,
2216 unsigned char *data, int len)
2217{
2218 struct sk_buff *skb;
2219 unsigned char *p;
2220 int hl;
2221 int cnt = 0;
2222 isdn_net_local *lp = is->lp;
2223
2224 /* Alloc large enough skb */
2225 hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen;
Joe Perches475be4d2012-02-19 19:52:38 -08002226 skb = alloc_skb(len + hl + 16, GFP_ATOMIC);
2227 if (!skb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228 printk(KERN_WARNING
2229 "ippp: CCP cannot send reset - out of memory\n");
2230 return;
2231 }
2232 skb_reserve(skb, hl);
2233
2234 /* We may need to stuff an address and control field first */
Joe Perches475be4d2012-02-19 19:52:38 -08002235 if (!(is->pppcfg & SC_COMP_AC)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236 p = skb_put(skb, 2);
2237 *p++ = 0xff;
2238 *p++ = 0x03;
2239 }
2240
2241 /* Stuff proto, code, id and length */
2242 p = skb_put(skb, 6);
2243 *p++ = (proto >> 8);
2244 *p++ = (proto & 0xff);
2245 *p++ = code;
2246 *p++ = id;
2247 cnt = 4 + len;
2248 *p++ = (cnt >> 8);
2249 *p++ = (cnt & 0xff);
2250
2251 /* Now stuff remaining bytes */
Joe Perches475be4d2012-02-19 19:52:38 -08002252 if (len) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253 p = skb_put(skb, len);
2254 memcpy(p, data, len);
2255 }
2256
2257 /* skb is now ready for xmit */
2258 printk(KERN_DEBUG "Sending CCP Frame:\n");
Joe Perches475be4d2012-02-19 19:52:38 -08002259 isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit, lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260
2261 isdn_net_write_super(lp, skb);
2262}
2263
2264/* Allocate the reset state vector */
2265static struct ippp_ccp_reset *isdn_ppp_ccp_reset_alloc(struct ippp_struct *is)
2266{
2267 struct ippp_ccp_reset *r;
Burman Yan41f96932006-12-08 02:39:35 -08002268 r = kzalloc(sizeof(struct ippp_ccp_reset), GFP_KERNEL);
Joe Perches475be4d2012-02-19 19:52:38 -08002269 if (!r) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002270 printk(KERN_ERR "ippp_ccp: failed to allocate reset data"
2271 " structure - no mem\n");
2272 return NULL;
2273 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274 printk(KERN_DEBUG "ippp_ccp: allocated reset data structure %p\n", r);
2275 is->reset = r;
2276 return r;
2277}
2278
2279/* Destroy the reset state vector. Kill all pending timers first. */
2280static void isdn_ppp_ccp_reset_free(struct ippp_struct *is)
2281{
2282 unsigned int id;
2283
2284 printk(KERN_DEBUG "ippp_ccp: freeing reset data structure %p\n",
2285 is->reset);
Joe Perches475be4d2012-02-19 19:52:38 -08002286 for (id = 0; id < 256; id++) {
2287 if (is->reset->rs[id]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288 isdn_ppp_ccp_reset_free_state(is, (unsigned char)id);
2289 }
2290 }
2291 kfree(is->reset);
2292 is->reset = NULL;
2293}
2294
2295/* Free a given state and clear everything up for later reallocation */
2296static void isdn_ppp_ccp_reset_free_state(struct ippp_struct *is,
2297 unsigned char id)
2298{
2299 struct ippp_ccp_reset_state *rs;
2300
Joe Perches475be4d2012-02-19 19:52:38 -08002301 if (is->reset->rs[id]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302 printk(KERN_DEBUG "ippp_ccp: freeing state for id %d\n", id);
2303 rs = is->reset->rs[id];
2304 /* Make sure the kernel will not call back later */
Joe Perches475be4d2012-02-19 19:52:38 -08002305 if (rs->ta)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306 del_timer(&rs->timer);
2307 is->reset->rs[id] = NULL;
2308 kfree(rs);
2309 } else {
2310 printk(KERN_WARNING "ippp_ccp: id %d is not allocated\n", id);
2311 }
2312}
2313
2314/* The timer callback function which is called when a ResetReq has timed out,
2315 aka has never been answered by a ResetAck */
2316static void isdn_ppp_ccp_timer_callback(unsigned long closure)
2317{
2318 struct ippp_ccp_reset_state *rs =
2319 (struct ippp_ccp_reset_state *)closure;
2320
Joe Perches475be4d2012-02-19 19:52:38 -08002321 if (!rs) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002322 printk(KERN_ERR "ippp_ccp: timer cb with zero closure.\n");
2323 return;
2324 }
Joe Perches475be4d2012-02-19 19:52:38 -08002325 if (rs->ta && rs->state == CCPResetSentReq) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002326 /* We are correct here */
Joe Perches475be4d2012-02-19 19:52:38 -08002327 if (!rs->expra) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002328 /* Hmm, there is no Ack really expected. We can clean
2329 up the state now, it will be reallocated if the
2330 decompressor insists on another reset */
2331 rs->ta = 0;
2332 isdn_ppp_ccp_reset_free_state(rs->is, rs->id);
2333 return;
2334 }
2335 printk(KERN_DEBUG "ippp_ccp: CCP Reset timed out for id %d\n",
2336 rs->id);
2337 /* Push it again */
2338 isdn_ppp_ccp_xmit_reset(rs->is, PPP_CCP, CCP_RESETREQ, rs->id,
2339 rs->data, rs->dlen);
2340 /* Restart timer */
Joe Perches475be4d2012-02-19 19:52:38 -08002341 rs->timer.expires = jiffies + HZ * 5;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002342 add_timer(&rs->timer);
2343 } else {
2344 printk(KERN_WARNING "ippp_ccp: timer cb in wrong state %d\n",
2345 rs->state);
2346 }
2347}
2348
2349/* Allocate a new reset transaction state */
2350static struct ippp_ccp_reset_state *isdn_ppp_ccp_reset_alloc_state(struct ippp_struct *is,
Joe Perches475be4d2012-02-19 19:52:38 -08002351 unsigned char id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002352{
2353 struct ippp_ccp_reset_state *rs;
Joe Perches475be4d2012-02-19 19:52:38 -08002354 if (is->reset->rs[id]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355 printk(KERN_WARNING "ippp_ccp: old state exists for id %d\n",
2356 id);
2357 return NULL;
2358 } else {
Burman Yan41f96932006-12-08 02:39:35 -08002359 rs = kzalloc(sizeof(struct ippp_ccp_reset_state), GFP_KERNEL);
Joe Perches475be4d2012-02-19 19:52:38 -08002360 if (!rs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002361 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002362 rs->state = CCPResetIdle;
2363 rs->is = is;
2364 rs->id = id;
Marcel Holtmanndab6df62006-12-21 23:06:24 +01002365 init_timer(&rs->timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002366 rs->timer.data = (unsigned long)rs;
2367 rs->timer.function = isdn_ppp_ccp_timer_callback;
2368 is->reset->rs[id] = rs;
2369 }
2370 return rs;
2371}
2372
2373
2374/* A decompressor wants a reset with a set of parameters - do what is
2375 necessary to fulfill it */
2376static void isdn_ppp_ccp_reset_trans(struct ippp_struct *is,
2377 struct isdn_ppp_resetparams *rp)
2378{
2379 struct ippp_ccp_reset_state *rs;
2380
Joe Perches475be4d2012-02-19 19:52:38 -08002381 if (rp->valid) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382 /* The decompressor defines parameters by itself */
Joe Perches475be4d2012-02-19 19:52:38 -08002383 if (rp->rsend) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002384 /* And he wants us to send a request */
Joe Perches475be4d2012-02-19 19:52:38 -08002385 if (!(rp->idval)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386 printk(KERN_ERR "ippp_ccp: decompressor must"
2387 " specify reset id\n");
2388 return;
2389 }
Joe Perches475be4d2012-02-19 19:52:38 -08002390 if (is->reset->rs[rp->id]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002391 /* There is already a transaction in existence
2392 for this id. May be still waiting for a
2393 Ack or may be wrong. */
2394 rs = is->reset->rs[rp->id];
Joe Perches475be4d2012-02-19 19:52:38 -08002395 if (rs->state == CCPResetSentReq && rs->ta) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002396 printk(KERN_DEBUG "ippp_ccp: reset"
2397 " trans still in progress"
2398 " for id %d\n", rp->id);
2399 } else {
2400 printk(KERN_WARNING "ippp_ccp: reset"
2401 " trans in wrong state %d for"
2402 " id %d\n", rs->state, rp->id);
2403 }
2404 } else {
2405 /* Ok, this is a new transaction */
2406 printk(KERN_DEBUG "ippp_ccp: new trans for id"
2407 " %d to be started\n", rp->id);
2408 rs = isdn_ppp_ccp_reset_alloc_state(is, rp->id);
Joe Perches475be4d2012-02-19 19:52:38 -08002409 if (!rs) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002410 printk(KERN_ERR "ippp_ccp: out of mem"
2411 " allocing ccp trans\n");
2412 return;
2413 }
2414 rs->state = CCPResetSentReq;
2415 rs->expra = rp->expra;
Joe Perches475be4d2012-02-19 19:52:38 -08002416 if (rp->dtval) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002417 rs->dlen = rp->dlen;
2418 memcpy(rs->data, rp->data, rp->dlen);
2419 }
2420 /* HACK TODO - add link comp here */
2421 isdn_ppp_ccp_xmit_reset(is, PPP_CCP,
2422 CCP_RESETREQ, rs->id,
2423 rs->data, rs->dlen);
2424 /* Start the timer */
Joe Perches475be4d2012-02-19 19:52:38 -08002425 rs->timer.expires = jiffies + 5 * HZ;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002426 add_timer(&rs->timer);
2427 rs->ta = 1;
2428 }
2429 } else {
2430 printk(KERN_DEBUG "ippp_ccp: no reset sent\n");
2431 }
2432 } else {
2433 /* The reset params are invalid. The decompressor does not
2434 care about them, so we just send the minimal requests
2435 and increase ids only when an Ack is received for a
2436 given id */
Joe Perches475be4d2012-02-19 19:52:38 -08002437 if (is->reset->rs[is->reset->lastid]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002438 /* There is already a transaction in existence
2439 for this id. May be still waiting for a
2440 Ack or may be wrong. */
2441 rs = is->reset->rs[is->reset->lastid];
Joe Perches475be4d2012-02-19 19:52:38 -08002442 if (rs->state == CCPResetSentReq && rs->ta) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443 printk(KERN_DEBUG "ippp_ccp: reset"
2444 " trans still in progress"
2445 " for id %d\n", rp->id);
2446 } else {
2447 printk(KERN_WARNING "ippp_ccp: reset"
2448 " trans in wrong state %d for"
2449 " id %d\n", rs->state, rp->id);
2450 }
2451 } else {
2452 printk(KERN_DEBUG "ippp_ccp: new trans for id"
2453 " %d to be started\n", is->reset->lastid);
2454 rs = isdn_ppp_ccp_reset_alloc_state(is,
2455 is->reset->lastid);
Joe Perches475be4d2012-02-19 19:52:38 -08002456 if (!rs) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002457 printk(KERN_ERR "ippp_ccp: out of mem"
2458 " allocing ccp trans\n");
2459 return;
2460 }
2461 rs->state = CCPResetSentReq;
2462 /* We always expect an Ack if the decompressor doesn't
2463 know better */
2464 rs->expra = 1;
2465 rs->dlen = 0;
2466 /* HACK TODO - add link comp here */
2467 isdn_ppp_ccp_xmit_reset(is, PPP_CCP, CCP_RESETREQ,
2468 rs->id, NULL, 0);
2469 /* Start the timer */
Joe Perches475be4d2012-02-19 19:52:38 -08002470 rs->timer.expires = jiffies + 5 * HZ;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002471 add_timer(&rs->timer);
2472 rs->ta = 1;
2473 }
2474 }
2475}
2476
2477/* An Ack was received for this id. This means we stop the timer and clean
2478 up the state prior to calling the decompressors reset routine. */
2479static void isdn_ppp_ccp_reset_ack_rcvd(struct ippp_struct *is,
2480 unsigned char id)
2481{
2482 struct ippp_ccp_reset_state *rs = is->reset->rs[id];
2483
Joe Perches475be4d2012-02-19 19:52:38 -08002484 if (rs) {
2485 if (rs->ta && rs->state == CCPResetSentReq) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486 /* Great, we are correct */
Joe Perches475be4d2012-02-19 19:52:38 -08002487 if (!rs->expra)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002488 printk(KERN_DEBUG "ippp_ccp: ResetAck received"
2489 " for id %d but not expected\n", id);
2490 } else {
2491 printk(KERN_INFO "ippp_ccp: ResetAck received out of"
2492 "sync for id %d\n", id);
2493 }
Joe Perches475be4d2012-02-19 19:52:38 -08002494 if (rs->ta) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002495 rs->ta = 0;
2496 del_timer(&rs->timer);
2497 }
2498 isdn_ppp_ccp_reset_free_state(is, id);
2499 } else {
2500 printk(KERN_INFO "ippp_ccp: ResetAck received for unknown id"
2501 " %d\n", id);
2502 }
2503 /* Make sure the simple reset stuff uses a new id next time */
2504 is->reset->lastid++;
2505}
2506
Joe Perches475be4d2012-02-19 19:52:38 -08002507/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002508 * decompress packet
2509 *
2510 * if master = 0, we're trying to uncompress an per-link compressed packet,
2511 * as opposed to an compressed reconstructed-from-MPPP packet.
2512 * proto is updated to protocol field of uncompressed packet.
2513 *
2514 * retval: decompressed packet,
2515 * same packet if uncompressed,
2516 * NULL if decompression error
2517 */
2518
Joe Perches475be4d2012-02-19 19:52:38 -08002519static struct sk_buff *isdn_ppp_decompress(struct sk_buff *skb, struct ippp_struct *is, struct ippp_struct *master,
2520 int *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521{
2522 void *stat = NULL;
2523 struct isdn_ppp_compressor *ipc = NULL;
2524 struct sk_buff *skb_out;
2525 int len;
2526 struct ippp_struct *ri;
2527 struct isdn_ppp_resetparams rsparm;
2528 unsigned char rsdata[IPPP_RESET_MAXDATABYTES];
2529
Joe Perches475be4d2012-02-19 19:52:38 -08002530 if (!master) {
2531 // per-link decompression
Linus Torvalds1da177e2005-04-16 15:20:36 -07002532 stat = is->link_decomp_stat;
2533 ipc = is->link_decompressor;
2534 ri = is;
2535 } else {
2536 stat = master->decomp_stat;
2537 ipc = master->decompressor;
2538 ri = master;
2539 }
2540
2541 if (!ipc) {
2542 // no decompressor -> we can't decompress.
2543 printk(KERN_DEBUG "ippp: no decompressor defined!\n");
2544 return skb;
2545 }
Eric Sesterhenn6dd44a72006-03-26 18:19:26 +02002546 BUG_ON(!stat); // if we have a compressor, stat has been set as well
Linus Torvalds1da177e2005-04-16 15:20:36 -07002547
Joe Perches475be4d2012-02-19 19:52:38 -08002548 if ((master && *proto == PPP_COMP) || (!master && *proto == PPP_COMPFRAG)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002549 // compressed packets are compressed by their protocol type
2550
2551 // Set up reset params for the decompressor
Joe Perches475be4d2012-02-19 19:52:38 -08002552 memset(&rsparm, 0, sizeof(rsparm));
2553 rsparm.data = rsdata;
2554 rsparm.maxdlen = IPPP_RESET_MAXDATABYTES;
2555
2556 skb_out = dev_alloc_skb(is->mru + PPP_HDRLEN);
2557 if (!skb_out) {
2558 kfree_skb(skb);
2559 printk(KERN_ERR "ippp: decomp memory allocation failure\n");
Jesper Juhlf6e2cdc2006-12-08 02:39:34 -08002560 return NULL;
Joe Perches475be4d2012-02-19 19:52:38 -08002561 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002562 len = ipc->decompress(stat, skb, skb_out, &rsparm);
2563 kfree_skb(skb);
2564 if (len <= 0) {
Joe Perches475be4d2012-02-19 19:52:38 -08002565 switch (len) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002566 case DECOMP_ERROR:
2567 printk(KERN_INFO "ippp: decomp wants reset %s params\n",
2568 rsparm.valid ? "with" : "without");
Joe Perches475be4d2012-02-19 19:52:38 -08002569
Linus Torvalds1da177e2005-04-16 15:20:36 -07002570 isdn_ppp_ccp_reset_trans(ri, &rsparm);
2571 break;
2572 case DECOMP_FATALERROR:
2573 ri->pppcfg |= SC_DC_FERROR;
2574 /* Kick ipppd to recognize the error */
2575 isdn_ppp_ccp_kickup(ri);
2576 break;
2577 }
2578 kfree_skb(skb_out);
2579 return NULL;
2580 }
2581 *proto = isdn_ppp_strip_proto(skb_out);
2582 if (*proto < 0) {
2583 kfree_skb(skb_out);
2584 return NULL;
2585 }
2586 return skb_out;
Joe Perches475be4d2012-02-19 19:52:38 -08002587 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588 // uncompressed packets are fed through the decompressor to
2589 // update the decompressor state
2590 ipc->incomp(stat, skb, *proto);
2591 return skb;
2592 }
2593}
2594
2595/*
Joe Perches475be4d2012-02-19 19:52:38 -08002596 * compress a frame
Linus Torvalds1da177e2005-04-16 15:20:36 -07002597 * type=0: normal/bundle compression
2598 * =1: link compression
2599 * returns original skb if we haven't compressed the frame
2600 * and a new skb pointer if we've done it
2601 */
Joe Perches475be4d2012-02-19 19:52:38 -08002602static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in, int *proto,
2603 struct ippp_struct *is, struct ippp_struct *master, int type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604{
Joe Perches475be4d2012-02-19 19:52:38 -08002605 int ret;
2606 int new_proto;
2607 struct isdn_ppp_compressor *compressor;
2608 void *stat;
2609 struct sk_buff *skb_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610
2611 /* we do not compress control protocols */
Joe Perches475be4d2012-02-19 19:52:38 -08002612 if (*proto < 0 || *proto > 0x3fff) {
2613 return skb_in;
2614 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002615
Joe Perches475be4d2012-02-19 19:52:38 -08002616 if (type) { /* type=1 => Link compression */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002617 return skb_in;
2618 }
2619 else {
Joe Perches475be4d2012-02-19 19:52:38 -08002620 if (!master) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621 compressor = is->compressor;
2622 stat = is->comp_stat;
2623 }
2624 else {
2625 compressor = master->compressor;
2626 stat = master->comp_stat;
2627 }
2628 new_proto = PPP_COMP;
2629 }
2630
Joe Perches475be4d2012-02-19 19:52:38 -08002631 if (!compressor) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002632 printk(KERN_ERR "isdn_ppp: No compressor set!\n");
2633 return skb_in;
2634 }
Joe Perches475be4d2012-02-19 19:52:38 -08002635 if (!stat) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636 printk(KERN_ERR "isdn_ppp: Compressor not initialized?\n");
2637 return skb_in;
2638 }
2639
2640 /* Allow for at least 150 % expansion (for now) */
Joe Perches475be4d2012-02-19 19:52:38 -08002641 skb_out = alloc_skb(skb_in->len + skb_in->len / 2 + 32 +
2642 skb_headroom(skb_in), GFP_ATOMIC);
2643 if (!skb_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644 return skb_in;
2645 skb_reserve(skb_out, skb_headroom(skb_in));
2646
Joe Perches475be4d2012-02-19 19:52:38 -08002647 ret = (compressor->compress)(stat, skb_in, skb_out, *proto);
2648 if (!ret) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649 dev_kfree_skb(skb_out);
2650 return skb_in;
2651 }
Joe Perches475be4d2012-02-19 19:52:38 -08002652
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653 dev_kfree_skb(skb_in);
2654 *proto = new_proto;
2655 return skb_out;
2656}
2657
2658/*
Joe Perches475be4d2012-02-19 19:52:38 -08002659 * we received a CCP frame ..
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660 * not a clean solution, but we MUST handle a few cases in the kernel
2661 */
2662static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp,
Joe Perches475be4d2012-02-19 19:52:38 -08002663 struct sk_buff *skb, int proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664{
2665 struct ippp_struct *is;
2666 struct ippp_struct *mis;
2667 int len;
2668 struct isdn_ppp_resetparams rsparm;
Joe Perches475be4d2012-02-19 19:52:38 -08002669 unsigned char rsdata[IPPP_RESET_MAXDATABYTES];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670
2671 printk(KERN_DEBUG "Received CCP frame from peer slot(%d)\n",
Joe Perches475be4d2012-02-19 19:52:38 -08002672 lp->ppp_slot);
Eric Sesterhenn052bb882006-04-11 17:29:17 -07002673 if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002674 printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
Joe Perches475be4d2012-02-19 19:52:38 -08002675 __func__, lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002676 return;
2677 }
2678 is = ippp_table[lp->ppp_slot];
Joe Perches475be4d2012-02-19 19:52:38 -08002679 isdn_ppp_frame_log("ccp-rcv", skb->data, skb->len, 32, is->unit, lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680
Joe Perches475be4d2012-02-19 19:52:38 -08002681 if (lp->master) {
Wang Chen838361f2008-12-03 15:49:46 -08002682 int slot = ISDN_MASTER_PRIV(lp)->ppp_slot;
Eric Sesterhenn052bb882006-04-11 17:29:17 -07002683 if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684 printk(KERN_ERR "%s: slot(%d) out of range\n",
Joe Perches475be4d2012-02-19 19:52:38 -08002685 __func__, slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002686 return;
Joe Perches475be4d2012-02-19 19:52:38 -08002687 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002688 mis = ippp_table[slot];
2689 } else
2690 mis = is;
2691
Joe Perches475be4d2012-02-19 19:52:38 -08002692 switch (skb->data[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693 case CCP_CONFREQ:
Joe Perches475be4d2012-02-19 19:52:38 -08002694 if (is->debug & 0x10)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695 printk(KERN_DEBUG "Disable compression here!\n");
Joe Perches475be4d2012-02-19 19:52:38 -08002696 if (proto == PPP_CCP)
2697 mis->compflags &= ~SC_COMP_ON;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002698 else
Joe Perches475be4d2012-02-19 19:52:38 -08002699 is->compflags &= ~SC_LINK_COMP_ON;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700 break;
2701 case CCP_TERMREQ:
2702 case CCP_TERMACK:
Joe Perches475be4d2012-02-19 19:52:38 -08002703 if (is->debug & 0x10)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704 printk(KERN_DEBUG "Disable (de)compression here!\n");
Joe Perches475be4d2012-02-19 19:52:38 -08002705 if (proto == PPP_CCP)
2706 mis->compflags &= ~(SC_DECOMP_ON | SC_COMP_ON);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707 else
Joe Perches475be4d2012-02-19 19:52:38 -08002708 is->compflags &= ~(SC_LINK_DECOMP_ON | SC_LINK_COMP_ON);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709 break;
2710 case CCP_CONFACK:
2711 /* if we RECEIVE an ackowledge we enable the decompressor */
Joe Perches475be4d2012-02-19 19:52:38 -08002712 if (is->debug & 0x10)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002713 printk(KERN_DEBUG "Enable decompression here!\n");
Joe Perches475be4d2012-02-19 19:52:38 -08002714 if (proto == PPP_CCP) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715 if (!mis->decompressor)
2716 break;
2717 mis->compflags |= SC_DECOMP_ON;
2718 } else {
2719 if (!is->decompressor)
2720 break;
2721 is->compflags |= SC_LINK_DECOMP_ON;
2722 }
2723 break;
2724
2725 case CCP_RESETACK:
2726 printk(KERN_DEBUG "Received ResetAck from peer\n");
2727 len = (skb->data[2] << 8) | skb->data[3];
2728 len -= 4;
2729
Joe Perches475be4d2012-02-19 19:52:38 -08002730 if (proto == PPP_CCP) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002731 /* If a reset Ack was outstanding for this id, then
2732 clean up the state engine */
2733 isdn_ppp_ccp_reset_ack_rcvd(mis, skb->data[1]);
Joe Perches475be4d2012-02-19 19:52:38 -08002734 if (mis->decompressor && mis->decomp_stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735 mis->decompressor->
2736 reset(mis->decomp_stat,
2737 skb->data[0],
2738 skb->data[1],
2739 len ? &skb->data[4] : NULL,
2740 len, NULL);
2741 /* TODO: This is not easy to decide here */
2742 mis->compflags &= ~SC_DECOMP_DISCARD;
2743 }
2744 else {
2745 isdn_ppp_ccp_reset_ack_rcvd(is, skb->data[1]);
Joe Perches475be4d2012-02-19 19:52:38 -08002746 if (is->link_decompressor && is->link_decomp_stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747 is->link_decompressor->
2748 reset(is->link_decomp_stat,
2749 skb->data[0],
2750 skb->data[1],
2751 len ? &skb->data[4] : NULL,
2752 len, NULL);
2753 /* TODO: neither here */
2754 is->compflags &= ~SC_LINK_DECOMP_DISCARD;
2755 }
2756 break;
2757
2758 case CCP_RESETREQ:
2759 printk(KERN_DEBUG "Received ResetReq from peer\n");
2760 /* Receiving a ResetReq means we must reset our compressor */
2761 /* Set up reset params for the reset entry */
2762 memset(&rsparm, 0, sizeof(rsparm));
2763 rsparm.data = rsdata;
Joe Perches475be4d2012-02-19 19:52:38 -08002764 rsparm.maxdlen = IPPP_RESET_MAXDATABYTES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765 /* Isolate data length */
2766 len = (skb->data[2] << 8) | skb->data[3];
2767 len -= 4;
Joe Perches475be4d2012-02-19 19:52:38 -08002768 if (proto == PPP_CCP) {
2769 if (mis->compressor && mis->comp_stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770 mis->compressor->
2771 reset(mis->comp_stat,
2772 skb->data[0],
2773 skb->data[1],
2774 len ? &skb->data[4] : NULL,
2775 len, &rsparm);
2776 }
2777 else {
Joe Perches475be4d2012-02-19 19:52:38 -08002778 if (is->link_compressor && is->link_comp_stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002779 is->link_compressor->
2780 reset(is->link_comp_stat,
2781 skb->data[0],
2782 skb->data[1],
2783 len ? &skb->data[4] : NULL,
2784 len, &rsparm);
2785 }
2786 /* Ack the Req as specified by rsparm */
Joe Perches475be4d2012-02-19 19:52:38 -08002787 if (rsparm.valid) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788 /* Compressor reset handler decided how to answer */
Joe Perches475be4d2012-02-19 19:52:38 -08002789 if (rsparm.rsend) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002790 /* We should send a Frame */
2791 isdn_ppp_ccp_xmit_reset(is, proto, CCP_RESETACK,
2792 rsparm.idval ? rsparm.id
2793 : skb->data[1],
2794 rsparm.dtval ?
2795 rsparm.data : NULL,
2796 rsparm.dtval ?
2797 rsparm.dlen : 0);
2798 } else {
2799 printk(KERN_DEBUG "ResetAck suppressed\n");
2800 }
2801 } else {
2802 /* We answer with a straight reflected Ack */
2803 isdn_ppp_ccp_xmit_reset(is, proto, CCP_RESETACK,
2804 skb->data[1],
2805 len ? &skb->data[4] : NULL,
2806 len);
2807 }
2808 break;
2809 }
2810}
2811
2812
2813/*
2814 * Daemon sends a CCP frame ...
2815 */
2816
2817/* TODO: Clean this up with new Reset semantics */
2818
2819/* I believe the CCP handling as-is is done wrong. Compressed frames
2820 * should only be sent/received after CCP reaches UP state, which means
2821 * both sides have sent CONF_ACK. Currently, we handle both directions
2822 * independently, which means we may accept compressed frames too early
2823 * (supposedly not a problem), but may also mean we send compressed frames
2824 * too early, which may turn out to be a problem.
2825 * This part of state machine should actually be handled by (i)pppd, but
2826 * that's too big of a change now. --kai
2827 */
2828
2829/* Actually, we might turn this into an advantage: deal with the RFC in
2830 * the old tradition of beeing generous on what we accept, but beeing
2831 * strict on what we send. Thus we should just
2832 * - accept compressed frames as soon as decompression is negotiated
2833 * - send compressed frames only when decomp *and* comp are negotiated
2834 * - drop rx compressed frames if we cannot decomp (instead of pushing them
2835 * up to ipppd)
2836 * and I tried to modify this file according to that. --abp
2837 */
2838
2839static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *skb)
2840{
Joe Perches475be4d2012-02-19 19:52:38 -08002841 struct ippp_struct *mis, *is;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002842 int proto, slot = lp->ppp_slot;
2843 unsigned char *data;
2844
Joe Perches475be4d2012-02-19 19:52:38 -08002845 if (!skb || skb->len < 3)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002846 return;
2847 if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
2848 printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
Joe Perches475be4d2012-02-19 19:52:38 -08002849 __func__, slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002850 return;
Joe Perches475be4d2012-02-19 19:52:38 -08002851 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002852 is = ippp_table[slot];
2853 /* Daemon may send with or without address and control field comp */
2854 data = skb->data;
Joe Perches475be4d2012-02-19 19:52:38 -08002855 if (!(is->pppcfg & SC_COMP_AC) && data[0] == 0xff && data[1] == 0x03) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002856 data += 2;
Joe Perches475be4d2012-02-19 19:52:38 -08002857 if (skb->len < 5)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858 return;
2859 }
2860
Joe Perches475be4d2012-02-19 19:52:38 -08002861 proto = ((int)data[0]<<8) + data[1];
2862 if (proto != PPP_CCP && proto != PPP_CCPFRAG)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002863 return;
2864
2865 printk(KERN_DEBUG "Received CCP frame from daemon:\n");
Joe Perches475be4d2012-02-19 19:52:38 -08002866 isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit, lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002867
2868 if (lp->master) {
Wang Chen838361f2008-12-03 15:49:46 -08002869 slot = ISDN_MASTER_PRIV(lp)->ppp_slot;
Eric Sesterhenn052bb882006-04-11 17:29:17 -07002870 if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002871 printk(KERN_ERR "%s: slot(%d) out of range\n",
Joe Perches475be4d2012-02-19 19:52:38 -08002872 __func__, slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002873 return;
Joe Perches475be4d2012-02-19 19:52:38 -08002874 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875 mis = ippp_table[slot];
2876 } else
2877 mis = is;
2878 if (mis != is)
2879 printk(KERN_DEBUG "isdn_ppp: Ouch! Master CCP sends on slave slot!\n");
Joe Perches475be4d2012-02-19 19:52:38 -08002880
2881 switch (data[2]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002882 case CCP_CONFREQ:
Joe Perches475be4d2012-02-19 19:52:38 -08002883 if (is->debug & 0x10)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002884 printk(KERN_DEBUG "Disable decompression here!\n");
Joe Perches475be4d2012-02-19 19:52:38 -08002885 if (proto == PPP_CCP)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002886 is->compflags &= ~SC_DECOMP_ON;
2887 else
2888 is->compflags &= ~SC_LINK_DECOMP_ON;
2889 break;
2890 case CCP_TERMREQ:
2891 case CCP_TERMACK:
Joe Perches475be4d2012-02-19 19:52:38 -08002892 if (is->debug & 0x10)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002893 printk(KERN_DEBUG "Disable (de)compression here!\n");
Joe Perches475be4d2012-02-19 19:52:38 -08002894 if (proto == PPP_CCP)
2895 is->compflags &= ~(SC_DECOMP_ON | SC_COMP_ON);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002896 else
Joe Perches475be4d2012-02-19 19:52:38 -08002897 is->compflags &= ~(SC_LINK_DECOMP_ON | SC_LINK_COMP_ON);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002898 break;
2899 case CCP_CONFACK:
2900 /* if we SEND an ackowledge we can/must enable the compressor */
Joe Perches475be4d2012-02-19 19:52:38 -08002901 if (is->debug & 0x10)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002902 printk(KERN_DEBUG "Enable compression here!\n");
Joe Perches475be4d2012-02-19 19:52:38 -08002903 if (proto == PPP_CCP) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002904 if (!is->compressor)
2905 break;
2906 is->compflags |= SC_COMP_ON;
2907 } else {
2908 if (!is->compressor)
2909 break;
2910 is->compflags |= SC_LINK_COMP_ON;
2911 }
2912 break;
2913 case CCP_RESETACK:
2914 /* If we send a ACK we should reset our compressor */
Joe Perches475be4d2012-02-19 19:52:38 -08002915 if (is->debug & 0x10)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002916 printk(KERN_DEBUG "Reset decompression state here!\n");
2917 printk(KERN_DEBUG "ResetAck from daemon passed by\n");
Joe Perches475be4d2012-02-19 19:52:38 -08002918 if (proto == PPP_CCP) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002919 /* link to master? */
Joe Perches475be4d2012-02-19 19:52:38 -08002920 if (is->compressor && is->comp_stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002921 is->compressor->reset(is->comp_stat, 0, 0,
2922 NULL, 0, NULL);
Joe Perches475be4d2012-02-19 19:52:38 -08002923 is->compflags &= ~SC_COMP_DISCARD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002924 }
2925 else {
Joe Perches475be4d2012-02-19 19:52:38 -08002926 if (is->link_compressor && is->link_comp_stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927 is->link_compressor->reset(is->link_comp_stat,
2928 0, 0, NULL, 0, NULL);
Joe Perches475be4d2012-02-19 19:52:38 -08002929 is->compflags &= ~SC_LINK_COMP_DISCARD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002930 }
2931 break;
2932 case CCP_RESETREQ:
2933 /* Just let it pass by */
2934 printk(KERN_DEBUG "ResetReq from daemon passed by\n");
2935 break;
2936 }
2937}
2938
2939int isdn_ppp_register_compressor(struct isdn_ppp_compressor *ipc)
2940{
2941 ipc->next = ipc_head;
2942 ipc->prev = NULL;
Joe Perches475be4d2012-02-19 19:52:38 -08002943 if (ipc_head) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002944 ipc_head->prev = ipc;
2945 }
2946 ipc_head = ipc;
2947 return 0;
2948}
2949
2950int isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *ipc)
2951{
Joe Perches475be4d2012-02-19 19:52:38 -08002952 if (ipc->prev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002953 ipc->prev->next = ipc->next;
2954 else
2955 ipc_head = ipc->next;
Joe Perches475be4d2012-02-19 19:52:38 -08002956 if (ipc->next)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957 ipc->next->prev = ipc->prev;
2958 ipc->prev = ipc->next = NULL;
2959 return 0;
2960}
2961
2962static int isdn_ppp_set_compressor(struct ippp_struct *is, struct isdn_ppp_comp_data *data)
2963{
2964 struct isdn_ppp_compressor *ipc = ipc_head;
2965 int ret;
2966 void *stat;
2967 int num = data->num;
2968
Joe Perches475be4d2012-02-19 19:52:38 -08002969 if (is->debug & 0x10)
2970 printk(KERN_DEBUG "[%d] Set %s type %d\n", is->unit,
2971 (data->flags & IPPP_COMP_FLAG_XMIT) ? "compressor" : "decompressor", num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002972
2973 /* If is has no valid reset state vector, we cannot allocate a
2974 decompressor. The decompressor would cause reset transactions
2975 sooner or later, and they need that vector. */
2976
Joe Perches475be4d2012-02-19 19:52:38 -08002977 if (!(data->flags & IPPP_COMP_FLAG_XMIT) && !is->reset) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002978 printk(KERN_ERR "ippp_ccp: no reset data structure - can't"
2979 " allow decompression.\n");
2980 return -ENOMEM;
2981 }
2982
Joe Perches475be4d2012-02-19 19:52:38 -08002983 while (ipc) {
2984 if (ipc->num == num) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002985 stat = ipc->alloc(data);
Joe Perches475be4d2012-02-19 19:52:38 -08002986 if (stat) {
2987 ret = ipc->init(stat, data, is->unit, 0);
2988 if (!ret) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002989 printk(KERN_ERR "Can't init (de)compression!\n");
2990 ipc->free(stat);
2991 stat = NULL;
2992 break;
2993 }
2994 }
2995 else {
2996 printk(KERN_ERR "Can't alloc (de)compression!\n");
2997 break;
2998 }
2999
Joe Perches475be4d2012-02-19 19:52:38 -08003000 if (data->flags & IPPP_COMP_FLAG_XMIT) {
3001 if (data->flags & IPPP_COMP_FLAG_LINK) {
3002 if (is->link_comp_stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003003 is->link_compressor->free(is->link_comp_stat);
3004 is->link_comp_stat = stat;
Joe Perches475be4d2012-02-19 19:52:38 -08003005 is->link_compressor = ipc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003006 }
3007 else {
Joe Perches475be4d2012-02-19 19:52:38 -08003008 if (is->comp_stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003009 is->compressor->free(is->comp_stat);
3010 is->comp_stat = stat;
Joe Perches475be4d2012-02-19 19:52:38 -08003011 is->compressor = ipc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003012 }
3013 }
Joe Perches475be4d2012-02-19 19:52:38 -08003014 else {
3015 if (data->flags & IPPP_COMP_FLAG_LINK) {
3016 if (is->link_decomp_stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003017 is->link_decompressor->free(is->link_decomp_stat);
3018 is->link_decomp_stat = stat;
Joe Perches475be4d2012-02-19 19:52:38 -08003019 is->link_decompressor = ipc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003020 }
3021 else {
Joe Perches475be4d2012-02-19 19:52:38 -08003022 if (is->decomp_stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003023 is->decompressor->free(is->decomp_stat);
3024 is->decomp_stat = stat;
Joe Perches475be4d2012-02-19 19:52:38 -08003025 is->decompressor = ipc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003026 }
3027 }
3028 return 0;
3029 }
3030 ipc = ipc->next;
3031 }
3032 return -EINVAL;
3033}