blob: c4198fa490bfac50dd3c05fa324502d4e6f228c8 [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) {
Alexei Starovoitov7ae457c2014-07-30 20:34:16 -0700382 bpf_prog_destroy(is->pass_filter);
Daniel Borkmann77e01142014-03-28 18:58:24 +0100383 is->pass_filter = NULL;
384 }
385
386 if (is->active_filter) {
Alexei Starovoitov7ae457c2014-07-30 20:34:16 -0700387 bpf_prog_destroy(is->active_filter);
Daniel Borkmann77e01142014-03-28 18:58:24 +0100388 is->active_filter = NULL;
389 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390#endif
391
392/* TODO: if this was the previous master: link the stuff to the new master */
Joe Perches475be4d2012-02-19 19:52:38 -0800393 if (is->comp_stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 is->compressor->free(is->comp_stat);
Joe Perches475be4d2012-02-19 19:52:38 -0800395 if (is->link_comp_stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 is->link_compressor->free(is->link_comp_stat);
Joe Perches475be4d2012-02-19 19:52:38 -0800397 if (is->link_decomp_stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 is->link_decompressor->free(is->link_decomp_stat);
Joe Perches475be4d2012-02-19 19:52:38 -0800399 if (is->decomp_stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 is->decompressor->free(is->decomp_stat);
Joe Perches475be4d2012-02-19 19:52:38 -0800401 is->compressor = is->link_compressor = NULL;
402 is->decompressor = is->link_decompressor = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 is->comp_stat = is->link_comp_stat = NULL;
Joe Perches475be4d2012-02-19 19:52:38 -0800404 is->decomp_stat = is->link_decomp_stat = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405
406 /* Clean up if necessary */
Joe Perches475be4d2012-02-19 19:52:38 -0800407 if (is->reset)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 isdn_ppp_ccp_reset_free(is);
409
410 /* this slot is ready for new connections */
411 is->state = 0;
412}
413
414/*
415 * get_arg .. ioctl helper
416 */
417static int
418get_arg(void __user *b, void *val, int len)
419{
420 if (len <= 0)
421 len = sizeof(void *);
422 if (copy_from_user(val, b, len))
423 return -EFAULT;
424 return 0;
425}
426
427/*
428 * set arg .. ioctl helper
429 */
430static int
Joe Perches475be4d2012-02-19 19:52:38 -0800431set_arg(void __user *b, void *val, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432{
Joe Perches475be4d2012-02-19 19:52:38 -0800433 if (len <= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 len = sizeof(void *);
435 if (copy_to_user(b, val, len))
436 return -EFAULT;
437 return 0;
438}
439
Daniele Venzano26285ba2009-01-26 12:24:38 -0800440#ifdef CONFIG_IPPP_FILTER
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441static int get_filter(void __user *arg, struct sock_filter **p)
442{
443 struct sock_fprog uprog;
444 struct sock_filter *code = NULL;
Christoph Schulz3916a312014-07-14 08:01:10 +0200445 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446
447 if (copy_from_user(&uprog, arg, sizeof(uprog)))
448 return -EFAULT;
449
450 if (!uprog.len) {
451 *p = NULL;
452 return 0;
453 }
454
455 /* uprog.len is unsigned short, so no overflow here */
456 len = uprog.len * sizeof(struct sock_filter);
Julia Lawall024cb8a2010-05-21 22:26:42 +0000457 code = memdup_user(uprog.filter, len);
458 if (IS_ERR(code))
459 return PTR_ERR(code);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 *p = code;
462 return uprog.len;
463}
Daniele Venzano26285ba2009-01-26 12:24:38 -0800464#endif /* CONFIG_IPPP_FILTER */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465
466/*
467 * ippp device ioctl
468 */
469int
470isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
471{
472 unsigned long val;
Joe Perches475be4d2012-02-19 19:52:38 -0800473 int r, i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 struct ippp_struct *is;
475 isdn_net_local *lp;
476 struct isdn_ppp_comp_data data;
477 void __user *argp = (void __user *)arg;
478
Joe Perches54cbb1c2010-07-12 10:50:02 +0000479 is = file->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 lp = is->lp;
481
482 if (is->debug & 0x1)
483 printk(KERN_DEBUG "isdn_ppp_ioctl: minor: %d cmd: %x state: %x\n", min, cmd, is->state);
484
485 if (!(is->state & IPPP_OPEN))
486 return -EINVAL;
487
488 switch (cmd) {
Joe Perches475be4d2012-02-19 19:52:38 -0800489 case PPPIOCBUNDLE:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490#ifdef CONFIG_ISDN_MPP
Joe Perches475be4d2012-02-19 19:52:38 -0800491 if (!(is->state & IPPP_CONNECT))
492 return -EINVAL;
493 if ((r = get_arg(argp, &val, sizeof(val))))
494 return r;
495 printk(KERN_DEBUG "iPPP-bundle: minor: %d, slave unit: %d, master unit: %d\n",
496 (int) min, (int) is->unit, (int) val);
497 return isdn_ppp_bundle(is, val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498#else
Joe Perches475be4d2012-02-19 19:52:38 -0800499 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500#endif
Joe Perches475be4d2012-02-19 19:52:38 -0800501 break;
502 case PPPIOCGUNIT: /* get ppp/isdn unit number */
503 if ((r = set_arg(argp, &is->unit, sizeof(is->unit))))
504 return r;
505 break;
506 case PPPIOCGIFNAME:
507 if (!lp)
508 return -EINVAL;
509 if ((r = set_arg(argp, lp->netdev->dev->name,
510 strlen(lp->netdev->dev->name))))
511 return r;
512 break;
513 case PPPIOCGMPFLAGS: /* get configuration flags */
514 if ((r = set_arg(argp, &is->mpppcfg, sizeof(is->mpppcfg))))
515 return r;
516 break;
517 case PPPIOCSMPFLAGS: /* set configuration flags */
518 if ((r = get_arg(argp, &val, sizeof(val))))
519 return r;
520 is->mpppcfg = val;
521 break;
522 case PPPIOCGFLAGS: /* get configuration flags */
523 if ((r = set_arg(argp, &is->pppcfg, sizeof(is->pppcfg))))
524 return r;
525 break;
526 case PPPIOCSFLAGS: /* set configuration flags */
527 if ((r = get_arg(argp, &val, sizeof(val)))) {
528 return r;
529 }
530 if (val & SC_ENABLE_IP && !(is->pppcfg & SC_ENABLE_IP) && (is->state & IPPP_CONNECT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 if (lp) {
Joe Perches475be4d2012-02-19 19:52:38 -0800532 /* OK .. we are ready to send buffers */
533 is->pppcfg = val; /* isdn_ppp_xmit test for SC_ENABLE_IP !!! */
534 netif_wake_queue(lp->netdev->dev);
535 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 }
Joe Perches475be4d2012-02-19 19:52:38 -0800537 }
538 is->pppcfg = val;
539 break;
540 case PPPIOCGIDLE: /* get idle time information */
541 if (lp) {
542 struct ppp_idle pidle;
543 pidle.xmit_idle = pidle.recv_idle = lp->huptimer;
544 if ((r = set_arg(argp, &pidle, sizeof(struct ppp_idle))))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 return r;
Joe Perches475be4d2012-02-19 19:52:38 -0800546 }
547 break;
548 case PPPIOCSMRU: /* set receive unit size for PPP */
549 if ((r = get_arg(argp, &val, sizeof(val))))
550 return r;
551 is->mru = val;
552 break;
553 case PPPIOCSMPMRU:
554 break;
555 case PPPIOCSMPMTU:
556 break;
557 case PPPIOCSMAXCID: /* set the maximum compression slot id */
558 if ((r = get_arg(argp, &val, sizeof(val))))
559 return r;
560 val++;
561 if (is->maxcid != val) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562#ifdef CONFIG_ISDN_PPP_VJ
Joe Perches475be4d2012-02-19 19:52:38 -0800563 struct slcompress *sltmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564#endif
Joe Perches475be4d2012-02-19 19:52:38 -0800565 if (is->debug & 0x1)
566 printk(KERN_DEBUG "ippp, ioctl: changed MAXCID to %ld\n", val);
567 is->maxcid = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568#ifdef CONFIG_ISDN_PPP_VJ
Joe Perches475be4d2012-02-19 19:52:38 -0800569 sltmp = slhc_init(16, val);
570 if (!sltmp) {
571 printk(KERN_ERR "ippp, can't realloc slhc struct\n");
572 return -ENOMEM;
573 }
574 if (is->slcomp)
575 slhc_free(is->slcomp);
576 is->slcomp = sltmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577#endif
Joe Perches475be4d2012-02-19 19:52:38 -0800578 }
579 break;
580 case PPPIOCGDEBUG:
581 if ((r = set_arg(argp, &is->debug, sizeof(is->debug))))
582 return r;
583 break;
584 case PPPIOCSDEBUG:
585 if ((r = get_arg(argp, &val, sizeof(val))))
586 return r;
587 is->debug = val;
588 break;
589 case PPPIOCGCOMPRESSORS:
590 {
591 unsigned long protos[8] = {0,};
592 struct isdn_ppp_compressor *ipc = ipc_head;
593 while (ipc) {
594 j = ipc->num / (sizeof(long) * 8);
595 i = ipc->num % (sizeof(long) * 8);
596 if (j < 8)
Dan Carpenter435f08a2012-10-09 23:42:18 +0000597 protos[j] |= (1UL << i);
Joe Perches475be4d2012-02-19 19:52:38 -0800598 ipc = ipc->next;
599 }
600 if ((r = set_arg(argp, protos, 8 * sizeof(long))))
601 return r;
602 }
603 break;
604 case PPPIOCSCOMPRESSOR:
605 if ((r = get_arg(argp, &data, sizeof(struct isdn_ppp_comp_data))))
606 return r;
607 return isdn_ppp_set_compressor(is, &data);
608 case PPPIOCGCALLINFO:
609 {
610 struct pppcallinfo pci;
611 memset((char *)&pci, 0, sizeof(struct pppcallinfo));
612 if (lp)
613 {
614 strncpy(pci.local_num, lp->msn, 63);
615 if (lp->dial) {
616 strncpy(pci.remote_num, lp->dial->num, 63);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 }
Joe Perches475be4d2012-02-19 19:52:38 -0800618 pci.charge_units = lp->charge;
619 if (lp->outgoing)
620 pci.calltype = CALLTYPE_OUTGOING;
621 else
622 pci.calltype = CALLTYPE_INCOMING;
623 if (lp->flags & ISDN_NET_CALLBACK)
624 pci.calltype |= CALLTYPE_CALLBACK;
625 }
626 return set_arg(argp, &pci, sizeof(struct pppcallinfo));
627 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628#ifdef CONFIG_IPPP_FILTER
Joe Perches475be4d2012-02-19 19:52:38 -0800629 case PPPIOCSPASS:
630 {
Daniel Borkmannb1fcd352014-05-23 18:43:58 +0200631 struct sock_fprog_kern fprog;
Joe Perches475be4d2012-02-19 19:52:38 -0800632 struct sock_filter *code;
Daniel Borkmann77e01142014-03-28 18:58:24 +0100633 int err, len = get_filter(argp, &code);
634
Joe Perches475be4d2012-02-19 19:52:38 -0800635 if (len < 0)
636 return len;
Daniel Borkmann77e01142014-03-28 18:58:24 +0100637
638 fprog.len = len;
639 fprog.filter = code;
640
Christoph Schulzcc25eaa2014-07-16 22:10:29 +0200641 if (is->pass_filter) {
Alexei Starovoitov7ae457c2014-07-30 20:34:16 -0700642 bpf_prog_destroy(is->pass_filter);
Christoph Schulzcc25eaa2014-07-16 22:10:29 +0200643 is->pass_filter = NULL;
644 }
645 if (fprog.filter != NULL)
Alexei Starovoitov7ae457c2014-07-30 20:34:16 -0700646 err = bpf_prog_create(&is->pass_filter, &fprog);
Christoph Schulzcc25eaa2014-07-16 22:10:29 +0200647 else
648 err = 0;
Daniel Borkmann77e01142014-03-28 18:58:24 +0100649 kfree(code);
650
651 return err;
Joe Perches475be4d2012-02-19 19:52:38 -0800652 }
653 case PPPIOCSACTIVE:
654 {
Daniel Borkmannb1fcd352014-05-23 18:43:58 +0200655 struct sock_fprog_kern fprog;
Joe Perches475be4d2012-02-19 19:52:38 -0800656 struct sock_filter *code;
Daniel Borkmann77e01142014-03-28 18:58:24 +0100657 int err, len = get_filter(argp, &code);
658
Joe Perches475be4d2012-02-19 19:52:38 -0800659 if (len < 0)
660 return len;
Daniel Borkmann77e01142014-03-28 18:58:24 +0100661
662 fprog.len = len;
663 fprog.filter = code;
664
Christoph Schulzcc25eaa2014-07-16 22:10:29 +0200665 if (is->active_filter) {
Alexei Starovoitov7ae457c2014-07-30 20:34:16 -0700666 bpf_prog_destroy(is->active_filter);
Christoph Schulzcc25eaa2014-07-16 22:10:29 +0200667 is->active_filter = NULL;
668 }
669 if (fprog.filter != NULL)
Alexei Starovoitov7ae457c2014-07-30 20:34:16 -0700670 err = bpf_prog_create(&is->active_filter, &fprog);
Christoph Schulzcc25eaa2014-07-16 22:10:29 +0200671 else
672 err = 0;
Daniel Borkmann77e01142014-03-28 18:58:24 +0100673 kfree(code);
674
675 return err;
Joe Perches475be4d2012-02-19 19:52:38 -0800676 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677#endif /* CONFIG_IPPP_FILTER */
Joe Perches475be4d2012-02-19 19:52:38 -0800678 default:
679 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 }
681 return 0;
682}
683
684unsigned int
Joe Perches475be4d2012-02-19 19:52:38 -0800685isdn_ppp_poll(struct file *file, poll_table *wait)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686{
687 u_int mask;
688 struct ippp_buf_queue *bf, *bl;
689 u_long flags;
690 struct ippp_struct *is;
691
692 is = file->private_data;
693
694 if (is->debug & 0x2)
695 printk(KERN_DEBUG "isdn_ppp_poll: minor: %d\n",
Al Viro496ad9a2013-01-23 17:07:38 -0500696 iminor(file_inode(file)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697
698 /* just registers wait_queue hook. This doesn't really wait. */
699 poll_wait(file, &is->wq, wait);
700
701 if (!(is->state & IPPP_OPEN)) {
Joe Perches475be4d2012-02-19 19:52:38 -0800702 if (is->state == IPPP_CLOSEWAIT)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 return POLLHUP;
704 printk(KERN_DEBUG "isdn_ppp: device not open\n");
705 return POLLERR;
706 }
707 /* we're always ready to send .. */
708 mask = POLLOUT | POLLWRNORM;
709
710 spin_lock_irqsave(&is->buflock, flags);
711 bl = is->last;
712 bf = is->first;
713 /*
714 * if IPPP_NOBLOCK is set we return even if we have nothing to read
715 */
716 if (bf->next != bl || (is->state & IPPP_NOBLOCK)) {
717 is->state &= ~IPPP_NOBLOCK;
718 mask |= POLLIN | POLLRDNORM;
719 }
720 spin_unlock_irqrestore(&is->buflock, flags);
721 return mask;
722}
723
724/*
725 * fill up isdn_ppp_read() queue ..
726 */
727
728static int
729isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot)
730{
731 struct ippp_buf_queue *bf, *bl;
732 u_long flags;
733 u_char *nbuf;
734 struct ippp_struct *is;
735
736 if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
737 printk(KERN_WARNING "ippp: illegal slot(%d).\n", slot);
738 return 0;
739 }
740 is = ippp_table[slot];
741
742 if (!(is->state & IPPP_CONNECT)) {
743 printk(KERN_DEBUG "ippp: device not activated.\n");
744 return 0;
745 }
Robert P. J. Day5cbded52006-12-13 00:35:56 -0800746 nbuf = kmalloc(len + 4, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 if (!nbuf) {
748 printk(KERN_WARNING "ippp: Can't alloc buf\n");
749 return 0;
750 }
751 nbuf[0] = PPP_ALLSTATIONS;
752 nbuf[1] = PPP_UI;
753 nbuf[2] = proto >> 8;
754 nbuf[3] = proto & 0xff;
755 memcpy(nbuf + 4, buf, len);
756
757 spin_lock_irqsave(&is->buflock, flags);
758 bf = is->first;
759 bl = is->last;
760
761 if (bf == bl) {
762 printk(KERN_WARNING "ippp: Queue is full; discarding first buffer\n");
763 bf = bf->next;
764 kfree(bf->buf);
765 is->first = bf;
766 }
767 bl->buf = (char *) nbuf;
768 bl->len = len + 4;
769
770 is->last = bl->next;
771 spin_unlock_irqrestore(&is->buflock, flags);
772 wake_up_interruptible(&is->wq);
773 return len;
774}
775
776/*
777 * read() .. non-blocking: ipppd calls it only after select()
778 * reports, that there is data
779 */
780
781int
782isdn_ppp_read(int min, struct file *file, char __user *buf, int count)
783{
784 struct ippp_struct *is;
785 struct ippp_buf_queue *b;
786 u_long flags;
787 u_char *save_buf;
788
789 is = file->private_data;
790
791 if (!(is->state & IPPP_OPEN))
792 return 0;
793
794 if (!access_ok(VERIFY_WRITE, buf, count))
795 return -EFAULT;
796
797 spin_lock_irqsave(&is->buflock, flags);
798 b = is->first->next;
799 save_buf = b->buf;
800 if (!save_buf) {
801 spin_unlock_irqrestore(&is->buflock, flags);
802 return -EAGAIN;
803 }
804 if (b->len < count)
805 count = b->len;
806 b->buf = NULL;
807 is->first = b;
808
809 spin_unlock_irqrestore(&is->buflock, flags);
Jesper Juhlc41a24c2006-03-25 03:07:02 -0800810 if (copy_to_user(buf, save_buf, count))
811 count = -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 kfree(save_buf);
813
814 return count;
815}
816
817/*
818 * ipppd wanna write a packet to the card .. non-blocking
819 */
820
821int
822isdn_ppp_write(int min, struct file *file, const char __user *buf, int count)
823{
824 isdn_net_local *lp;
825 struct ippp_struct *is;
826 int proto;
827 unsigned char protobuf[4];
828
829 is = file->private_data;
830
831 if (!(is->state & IPPP_CONNECT))
832 return 0;
833
834 lp = is->lp;
835
836 /* -> push it directly to the lowlevel interface */
837
838 if (!lp)
839 printk(KERN_DEBUG "isdn_ppp_write: lp == NULL\n");
840 else {
841 /*
842 * Don't reset huptimer for
843 * LCP packets. (Echo requests).
844 */
845 if (copy_from_user(protobuf, buf, 4))
846 return -EFAULT;
847 proto = PPP_PROTOCOL(protobuf);
848 if (proto != PPP_LCP)
849 lp->huptimer = 0;
850
851 if (lp->isdn_device < 0 || lp->isdn_channel < 0)
852 return 0;
853
854 if ((dev->drv[lp->isdn_device]->flags & DRV_FLAG_RUNNING) &&
Joe Perches475be4d2012-02-19 19:52:38 -0800855 lp->dialstate == 0 &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 (lp->flags & ISDN_NET_CONNECTED)) {
857 unsigned short hl;
858 struct sk_buff *skb;
859 /*
André Goddard Rosaaf901ca2009-11-14 13:09:05 -0200860 * we need to reserve enough space in front of
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 * sk_buff. old call to dev_alloc_skb only reserved
862 * 16 bytes, now we are looking what the driver want
863 */
864 hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen;
Joe Perches475be4d2012-02-19 19:52:38 -0800865 skb = alloc_skb(hl + count, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 if (!skb) {
867 printk(KERN_WARNING "isdn_ppp_write: out of memory!\n");
868 return count;
869 }
870 skb_reserve(skb, hl);
871 if (copy_from_user(skb_put(skb, count), buf, count))
872 {
873 kfree_skb(skb);
874 return -EFAULT;
875 }
876 if (is->debug & 0x40) {
877 printk(KERN_DEBUG "ppp xmit: len %d\n", (int) skb->len);
Joe Perches475be4d2012-02-19 19:52:38 -0800878 isdn_ppp_frame_log("xmit", skb->data, skb->len, 32, is->unit, lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 }
880
Joe Perches475be4d2012-02-19 19:52:38 -0800881 isdn_ppp_send_ccp(lp->netdev, lp, skb); /* keeps CCP/compression states in sync */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882
883 isdn_net_write_super(lp, skb);
884 }
885 }
886 return count;
887}
888
889/*
890 * init memory, structures etc.
891 */
892
893int
894isdn_ppp_init(void)
895{
896 int i,
Joe Perches475be4d2012-02-19 19:52:38 -0800897 j;
898
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899#ifdef CONFIG_ISDN_MPP
Joe Perches475be4d2012-02-19 19:52:38 -0800900 if (isdn_ppp_mp_bundle_array_init() < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 return -ENOMEM;
902#endif /* CONFIG_ISDN_MPP */
903
904 for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
Burman Yan41f96932006-12-08 02:39:35 -0800905 if (!(ippp_table[i] = kzalloc(sizeof(struct ippp_struct), GFP_KERNEL))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 printk(KERN_WARNING "isdn_ppp_init: Could not alloc ippp_table\n");
907 for (j = 0; j < i; j++)
908 kfree(ippp_table[j]);
909 return -1;
910 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 spin_lock_init(&ippp_table[i]->buflock);
912 ippp_table[i]->state = 0;
913 ippp_table[i]->first = ippp_table[i]->rq + NUM_RCV_BUFFS - 1;
914 ippp_table[i]->last = ippp_table[i]->rq;
915
916 for (j = 0; j < NUM_RCV_BUFFS; j++) {
917 ippp_table[i]->rq[j].buf = NULL;
918 ippp_table[i]->rq[j].last = ippp_table[i]->rq +
Joe Perches475be4d2012-02-19 19:52:38 -0800919 (NUM_RCV_BUFFS + j - 1) % NUM_RCV_BUFFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 ippp_table[i]->rq[j].next = ippp_table[i]->rq + (j + 1) % NUM_RCV_BUFFS;
921 }
922 }
923 return 0;
924}
925
926void
927isdn_ppp_cleanup(void)
928{
929 int i;
930
931 for (i = 0; i < ISDN_MAX_CHANNELS; i++)
932 kfree(ippp_table[i]);
933
934#ifdef CONFIG_ISDN_MPP
Jesper Juhl3c7208f2005-11-07 01:01:29 -0800935 kfree(isdn_ppp_bundle_arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936#endif /* CONFIG_ISDN_MPP */
937
938}
939
940/*
941 * check for address/control field and skip if allowed
942 * retval != 0 -> discard packet silently
943 */
Joe Perches475be4d2012-02-19 19:52:38 -0800944static int isdn_ppp_skip_ac(struct ippp_struct *is, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945{
946 if (skb->len < 1)
947 return -1;
948
949 if (skb->data[0] == 0xff) {
950 if (skb->len < 2)
951 return -1;
952
953 if (skb->data[1] != 0x03)
954 return -1;
955
956 // skip address/control (AC) field
957 skb_pull(skb, 2);
Joe Perches475be4d2012-02-19 19:52:38 -0800958 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959 if (is->pppcfg & SC_REJ_COMP_AC)
960 // if AC compression was not negotiated, but used, discard packet
961 return -1;
962 }
963 return 0;
964}
965
966/*
967 * get the PPP protocol header and pull skb
968 * retval < 0 -> discard packet silently
969 */
Joe Perches475be4d2012-02-19 19:52:38 -0800970static int isdn_ppp_strip_proto(struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971{
972 int proto;
Joe Perches475be4d2012-02-19 19:52:38 -0800973
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 if (skb->len < 1)
975 return -1;
976
977 if (skb->data[0] & 0x1) {
978 // protocol field is compressed
979 proto = skb->data[0];
980 skb_pull(skb, 1);
981 } else {
982 if (skb->len < 2)
983 return -1;
984 proto = ((int) skb->data[0] << 8) + skb->data[1];
985 skb_pull(skb, 2);
986 }
987 return proto;
988}
989
990
991/*
992 * handler for incoming packets on a syncPPP interface
993 */
Joe Perches475be4d2012-02-19 19:52:38 -0800994void isdn_ppp_receive(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995{
996 struct ippp_struct *is;
997 int slot;
998 int proto;
999
Eric Sesterhenn6dd44a72006-03-26 18:19:26 +02001000 BUG_ON(net_dev->local->master); // we're called with the master device always
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001
1002 slot = lp->ppp_slot;
1003 if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
1004 printk(KERN_ERR "isdn_ppp_receive: lp->ppp_slot(%d)\n",
Joe Perches475be4d2012-02-19 19:52:38 -08001005 lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 kfree_skb(skb);
1007 return;
1008 }
1009 is = ippp_table[slot];
1010
1011 if (is->debug & 0x4) {
1012 printk(KERN_DEBUG "ippp_receive: is:%08lx lp:%08lx slot:%d unit:%d len:%d\n",
Joe Perches475be4d2012-02-19 19:52:38 -08001013 (long)is, (long)lp, lp->ppp_slot, is->unit, (int)skb->len);
1014 isdn_ppp_frame_log("receive", skb->data, skb->len, 32, is->unit, lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015 }
1016
Joe Perches475be4d2012-02-19 19:52:38 -08001017 if (isdn_ppp_skip_ac(is, skb) < 0) {
1018 kfree_skb(skb);
1019 return;
1020 }
1021 proto = isdn_ppp_strip_proto(skb);
1022 if (proto < 0) {
1023 kfree_skb(skb);
1024 return;
1025 }
1026
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027#ifdef CONFIG_ISDN_MPP
Joe Perches475be4d2012-02-19 19:52:38 -08001028 if (is->compflags & SC_LINK_DECOMP_ON) {
1029 skb = isdn_ppp_decompress(skb, is, NULL, &proto);
1030 if (!skb) // decompression error
1031 return;
1032 }
1033
1034 if (!(is->mpppcfg & SC_REJ_MP_PROT)) { // we agreed to receive MPPP
1035 if (proto == PPP_MP) {
1036 isdn_ppp_mp_receive(net_dev, lp, skb);
1037 return;
1038 }
1039 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040#endif
Joe Perches475be4d2012-02-19 19:52:38 -08001041 isdn_ppp_push_higher(net_dev, lp, skb, proto);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042}
1043
1044/*
1045 * we receive a reassembled frame, MPPP has been taken care of before.
1046 * address/control and protocol have been stripped from the skb
1047 * note: net_dev has to be master net_dev
1048 */
1049static void
Joe Perches475be4d2012-02-19 19:52:38 -08001050isdn_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 -07001051{
Karsten Keild62a38d2007-10-08 20:37:11 -07001052 struct net_device *dev = net_dev->dev;
Joe Perches475be4d2012-02-19 19:52:38 -08001053 struct ippp_struct *is, *mis;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 isdn_net_local *mlp = NULL;
1055 int slot;
1056
1057 slot = lp->ppp_slot;
1058 if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
1059 printk(KERN_ERR "isdn_ppp_push_higher: lp->ppp_slot(%d)\n",
Joe Perches475be4d2012-02-19 19:52:38 -08001060 lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 goto drop_packet;
1062 }
1063 is = ippp_table[slot];
Joe Perches475be4d2012-02-19 19:52:38 -08001064
1065 if (lp->master) { // FIXME?
Wang Chen838361f2008-12-03 15:49:46 -08001066 mlp = ISDN_MASTER_PRIV(lp);
Joe Perches475be4d2012-02-19 19:52:38 -08001067 slot = mlp->ppp_slot;
1068 if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
1069 printk(KERN_ERR "isdn_ppp_push_higher: master->ppp_slot(%d)\n",
1070 lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 goto drop_packet;
Joe Perches475be4d2012-02-19 19:52:38 -08001072 }
1073 }
1074 mis = ippp_table[slot];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075
1076 if (is->debug & 0x10) {
1077 printk(KERN_DEBUG "push, skb %d %04x\n", (int) skb->len, proto);
Joe Perches475be4d2012-02-19 19:52:38 -08001078 isdn_ppp_frame_log("rpush", skb->data, skb->len, 32, is->unit, lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 }
1080 if (mis->compflags & SC_DECOMP_ON) {
1081 skb = isdn_ppp_decompress(skb, is, mis, &proto);
1082 if (!skb) // decompression error
Joe Perches475be4d2012-02-19 19:52:38 -08001083 return;
1084 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 switch (proto) {
Joe Perches475be4d2012-02-19 19:52:38 -08001086 case PPP_IPX: /* untested */
1087 if (is->debug & 0x20)
1088 printk(KERN_DEBUG "isdn_ppp: IPX\n");
1089 skb->protocol = htons(ETH_P_IPX);
1090 break;
1091 case PPP_IP:
1092 if (is->debug & 0x20)
1093 printk(KERN_DEBUG "isdn_ppp: IP\n");
1094 skb->protocol = htons(ETH_P_IP);
1095 break;
1096 case PPP_COMP:
1097 case PPP_COMPFRAG:
1098 printk(KERN_INFO "isdn_ppp: unexpected compressed frame dropped\n");
1099 goto drop_packet;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100#ifdef CONFIG_ISDN_PPP_VJ
Joe Perches475be4d2012-02-19 19:52:38 -08001101 case PPP_VJC_UNCOMP:
1102 if (is->debug & 0x20)
1103 printk(KERN_DEBUG "isdn_ppp: VJC_UNCOMP\n");
1104 if (net_dev->local->ppp_slot < 0) {
1105 printk(KERN_ERR "%s: net_dev->local->ppp_slot(%d) out of range\n",
1106 __func__, net_dev->local->ppp_slot);
1107 goto drop_packet;
1108 }
1109 if (slhc_remember(ippp_table[net_dev->local->ppp_slot]->slcomp, skb->data, skb->len) <= 0) {
1110 printk(KERN_WARNING "isdn_ppp: received illegal VJC_UNCOMP frame!\n");
1111 goto drop_packet;
1112 }
1113 skb->protocol = htons(ETH_P_IP);
1114 break;
1115 case PPP_VJC_COMP:
1116 if (is->debug & 0x20)
1117 printk(KERN_DEBUG "isdn_ppp: VJC_COMP\n");
1118 {
1119 struct sk_buff *skb_old = skb;
1120 int pkt_len;
1121 skb = dev_alloc_skb(skb_old->len + 128);
1122
1123 if (!skb) {
1124 printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
1125 skb = skb_old;
1126 goto drop_packet;
1127 }
1128 skb_put(skb, skb_old->len + 128);
1129 skb_copy_from_linear_data(skb_old, skb->data,
1130 skb_old->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131 if (net_dev->local->ppp_slot < 0) {
1132 printk(KERN_ERR "%s: net_dev->local->ppp_slot(%d) out of range\n",
Joe Perches475be4d2012-02-19 19:52:38 -08001133 __func__, net_dev->local->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134 goto drop_packet;
1135 }
Joe Perches475be4d2012-02-19 19:52:38 -08001136 pkt_len = slhc_uncompress(ippp_table[net_dev->local->ppp_slot]->slcomp,
1137 skb->data, skb_old->len);
1138 kfree_skb(skb_old);
1139 if (pkt_len < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 goto drop_packet;
Joe Perches475be4d2012-02-19 19:52:38 -08001141
1142 skb_trim(skb, pkt_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143 skb->protocol = htons(ETH_P_IP);
Joe Perches475be4d2012-02-19 19:52:38 -08001144 }
1145 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146#endif
Joe Perches475be4d2012-02-19 19:52:38 -08001147 case PPP_CCP:
1148 case PPP_CCPFRAG:
1149 isdn_ppp_receive_ccp(net_dev, lp, skb, proto);
1150 /* Dont pop up ResetReq/Ack stuff to the daemon any
1151 longer - the job is done already */
1152 if (skb->data[0] == CCP_RESETREQ ||
1153 skb->data[0] == CCP_RESETACK)
1154 break;
1155 /* fall through */
1156 default:
1157 isdn_ppp_fill_rq(skb->data, skb->len, proto, lp->ppp_slot); /* push data to pppd device */
1158 kfree_skb(skb);
1159 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 }
1161
1162#ifdef CONFIG_IPPP_FILTER
1163 /* check if the packet passes the pass and active filters
1164 * the filter instructions are constructed assuming
1165 * a four-byte PPP header on each packet (which is still present) */
1166 skb_push(skb, 4);
1167
1168 {
1169 u_int16_t *p = (u_int16_t *) skb->data;
1170
Karsten Keild8470b72005-04-21 08:30:30 -07001171 *p = 0; /* indicate inbound */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172 }
1173
1174 if (is->pass_filter
Alexei Starovoitov7ae457c2014-07-30 20:34:16 -07001175 && BPF_PROG_RUN(is->pass_filter, skb) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176 if (is->debug & 0x2)
1177 printk(KERN_DEBUG "IPPP: inbound frame filtered.\n");
1178 kfree_skb(skb);
1179 return;
1180 }
1181 if (!(is->active_filter
Alexei Starovoitov7ae457c2014-07-30 20:34:16 -07001182 && BPF_PROG_RUN(is->active_filter, skb) == 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183 if (is->debug & 0x2)
Masanari Iidaee556fe2012-02-11 01:49:28 +00001184 printk(KERN_DEBUG "IPPP: link-active filter: resetting huptimer.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 lp->huptimer = 0;
1186 if (mlp)
1187 mlp->huptimer = 0;
1188 }
1189 skb_pull(skb, 4);
1190#else /* CONFIG_IPPP_FILTER */
1191 lp->huptimer = 0;
1192 if (mlp)
1193 mlp->huptimer = 0;
1194#endif /* CONFIG_IPPP_FILTER */
1195 skb->dev = dev;
Arnaldo Carvalho de Melo459a98e2007-03-19 15:30:44 -07001196 skb_reset_mac_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197 netif_rx(skb);
1198 /* net_dev->local->stats.rx_packets++; done in isdn_net.c */
1199 return;
1200
Joe Perches475be4d2012-02-19 19:52:38 -08001201drop_packet:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202 net_dev->local->stats.rx_dropped++;
1203 kfree_skb(skb);
1204}
1205
1206/*
1207 * isdn_ppp_skb_push ..
1208 * checks whether we have enough space at the beginning of the skb
1209 * and allocs a new SKB if necessary
1210 */
Joe Perches475be4d2012-02-19 19:52:38 -08001211static unsigned char *isdn_ppp_skb_push(struct sk_buff **skb_p, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212{
1213 struct sk_buff *skb = *skb_p;
1214
Joe Perches475be4d2012-02-19 19:52:38 -08001215 if (skb_headroom(skb) < len) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216 struct sk_buff *nskb = skb_realloc_headroom(skb, len);
1217
1218 if (!nskb) {
1219 printk(KERN_ERR "isdn_ppp_skb_push: can't realloc headroom!\n");
1220 dev_kfree_skb(skb);
1221 return NULL;
1222 }
Joe Perches475be4d2012-02-19 19:52:38 -08001223 printk(KERN_DEBUG "isdn_ppp_skb_push:under %d %d\n", skb_headroom(skb), len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 dev_kfree_skb(skb);
1225 *skb_p = nskb;
1226 return skb_push(nskb, len);
1227 }
Joe Perches475be4d2012-02-19 19:52:38 -08001228 return skb_push(skb, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229}
1230
1231/*
1232 * send ppp frame .. we expect a PIDCOMPressable proto --
1233 * (here: currently always PPP_IP,PPP_VJC_COMP,PPP_VJC_UNCOMP)
1234 *
1235 * VJ compression may change skb pointer!!! .. requeue with old
1236 * skb isn't allowed!!
1237 */
1238
1239int
1240isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev)
1241{
Joe Perches475be4d2012-02-19 19:52:38 -08001242 isdn_net_local *lp, *mlp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243 isdn_net_dev *nd;
1244 unsigned int proto = PPP_IP; /* 0x21 */
Joe Perches475be4d2012-02-19 19:52:38 -08001245 struct ippp_struct *ipt, *ipts;
Patrick McHardyec634fe2009-07-05 19:23:38 -07001246 int slot, retval = NETDEV_TX_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247
Joe Perchesa17531f2010-11-15 11:12:24 +00001248 mlp = netdev_priv(netdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249 nd = mlp->netdev; /* get master lp */
1250
1251 slot = mlp->ppp_slot;
1252 if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
1253 printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot(%d)\n",
Joe Perches475be4d2012-02-19 19:52:38 -08001254 mlp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255 kfree_skb(skb);
1256 goto out;
1257 }
1258 ipts = ippp_table[slot];
1259
1260 if (!(ipts->pppcfg & SC_ENABLE_IP)) { /* PPP connected ? */
1261 if (ipts->debug & 0x1)
1262 printk(KERN_INFO "%s: IP frame delayed.\n", netdev->name);
Patrick McHardyec634fe2009-07-05 19:23:38 -07001263 retval = NETDEV_TX_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264 goto out;
1265 }
1266
1267 switch (ntohs(skb->protocol)) {
Joe Perches475be4d2012-02-19 19:52:38 -08001268 case ETH_P_IP:
1269 proto = PPP_IP;
1270 break;
1271 case ETH_P_IPX:
1272 proto = PPP_IPX; /* untested */
1273 break;
1274 default:
1275 printk(KERN_ERR "isdn_ppp: skipped unsupported protocol: %#x.\n",
1276 skb->protocol);
1277 dev_kfree_skb(skb);
1278 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279 }
1280
1281 lp = isdn_net_get_locked_lp(nd);
1282 if (!lp) {
1283 printk(KERN_WARNING "%s: all channels busy - requeuing!\n", netdev->name);
Patrick McHardyec634fe2009-07-05 19:23:38 -07001284 retval = NETDEV_TX_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285 goto out;
1286 }
1287 /* we have our lp locked from now on */
1288
1289 slot = lp->ppp_slot;
Eric Sesterhenn052bb882006-04-11 17:29:17 -07001290 if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291 printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot(%d)\n",
Joe Perches475be4d2012-02-19 19:52:38 -08001292 lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293 kfree_skb(skb);
1294 goto unlock;
1295 }
1296 ipt = ippp_table[slot];
1297
1298 /*
1299 * after this line .. requeueing in the device queue is no longer allowed!!!
1300 */
1301
1302 /* Pull off the fake header we stuck on earlier to keep
1303 * the fragmentation code happy.
1304 */
Joe Perches475be4d2012-02-19 19:52:38 -08001305 skb_pull(skb, IPPP_MAX_HEADER);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306
1307#ifdef CONFIG_IPPP_FILTER
1308 /* check if we should pass this packet
1309 * the filter instructions are constructed assuming
1310 * a four-byte PPP header on each packet */
Karsten Keild8470b72005-04-21 08:30:30 -07001311 *skb_push(skb, 4) = 1; /* indicate outbound */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312
1313 {
Harvey Harrisonc19d0362008-11-20 04:10:51 -08001314 __be16 *p = (__be16 *)skb->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315
Karsten Keild8470b72005-04-21 08:30:30 -07001316 p++;
Harvey Harrisonc19d0362008-11-20 04:10:51 -08001317 *p = htons(proto);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318 }
1319
1320 if (ipt->pass_filter
Alexei Starovoitov7ae457c2014-07-30 20:34:16 -07001321 && BPF_PROG_RUN(ipt->pass_filter, skb) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 if (ipt->debug & 0x4)
1323 printk(KERN_DEBUG "IPPP: outbound frame filtered.\n");
1324 kfree_skb(skb);
1325 goto unlock;
1326 }
1327 if (!(ipt->active_filter
Alexei Starovoitov7ae457c2014-07-30 20:34:16 -07001328 && BPF_PROG_RUN(ipt->active_filter, skb) == 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 if (ipt->debug & 0x4)
Masanari Iidaee556fe2012-02-11 01:49:28 +00001330 printk(KERN_DEBUG "IPPP: link-active filter: resetting huptimer.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331 lp->huptimer = 0;
1332 }
1333 skb_pull(skb, 4);
1334#else /* CONFIG_IPPP_FILTER */
1335 lp->huptimer = 0;
1336#endif /* CONFIG_IPPP_FILTER */
1337
1338 if (ipt->debug & 0x4)
1339 printk(KERN_DEBUG "xmit skb, len %d\n", (int) skb->len);
Joe Perches475be4d2012-02-19 19:52:38 -08001340 if (ipts->debug & 0x40)
1341 isdn_ppp_frame_log("xmit0", skb->data, skb->len, 32, ipts->unit, lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342
1343#ifdef CONFIG_ISDN_PPP_VJ
1344 if (proto == PPP_IP && ipts->pppcfg & SC_COMP_TCP) { /* ipts here? probably yes, but check this again */
1345 struct sk_buff *new_skb;
Joe Perches475be4d2012-02-19 19:52:38 -08001346 unsigned short hl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347 /*
André Goddard Rosaaf901ca2009-11-14 13:09:05 -02001348 * we need to reserve enough space in front of
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 * sk_buff. old call to dev_alloc_skb only reserved
1350 * 16 bytes, now we are looking what the driver want.
1351 */
1352 hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen + IPPP_MAX_HEADER;
Joe Perches475be4d2012-02-19 19:52:38 -08001353 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 * Note: hl might still be insufficient because the method
1355 * above does not account for a possibible MPPP slave channel
1356 * which had larger HL header space requirements than the
1357 * master.
1358 */
Joe Perches475be4d2012-02-19 19:52:38 -08001359 new_skb = alloc_skb(hl + skb->len, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360 if (new_skb) {
1361 u_char *buf;
1362 int pktlen;
1363
1364 skb_reserve(new_skb, hl);
1365 new_skb->dev = skb->dev;
1366 skb_put(new_skb, skb->len);
1367 buf = skb->data;
1368
1369 pktlen = slhc_compress(ipts->slcomp, skb->data, skb->len, new_skb->data,
Joe Perches475be4d2012-02-19 19:52:38 -08001370 &buf, !(ipts->pppcfg & SC_NO_TCP_CCID));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371
Joe Perches475be4d2012-02-19 19:52:38 -08001372 if (buf != skb->data) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 if (new_skb->data != buf)
1374 printk(KERN_ERR "isdn_ppp: FATAL error after slhc_compress!!\n");
1375 dev_kfree_skb(skb);
1376 skb = new_skb;
1377 } else {
1378 dev_kfree_skb(new_skb);
1379 }
1380
1381 skb_trim(skb, pktlen);
1382 if (skb->data[0] & SL_TYPE_COMPRESSED_TCP) { /* cslip? style -> PPP */
1383 proto = PPP_VJC_COMP;
1384 skb->data[0] ^= SL_TYPE_COMPRESSED_TCP;
1385 } else {
1386 if (skb->data[0] >= SL_TYPE_UNCOMPRESSED_TCP)
1387 proto = PPP_VJC_UNCOMP;
1388 skb->data[0] = (skb->data[0] & 0x0f) | 0x40;
1389 }
1390 }
1391 }
1392#endif
1393
1394 /*
1395 * normal (single link) or bundle compression
1396 */
Joe Perches475be4d2012-02-19 19:52:38 -08001397 if (ipts->compflags & SC_COMP_ON) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398 /* We send compressed only if both down- und upstream
1399 compression is negotiated, that means, CCP is up */
Joe Perches475be4d2012-02-19 19:52:38 -08001400 if (ipts->compflags & SC_DECOMP_ON) {
1401 skb = isdn_ppp_compress(skb, &proto, ipt, ipts, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402 } else {
1403 printk(KERN_DEBUG "isdn_ppp: CCP not yet up - sending as-is\n");
1404 }
1405 }
1406
1407 if (ipt->debug & 0x24)
1408 printk(KERN_DEBUG "xmit2 skb, len %d, proto %04x\n", (int) skb->len, proto);
1409
1410#ifdef CONFIG_ISDN_MPP
1411 if (ipt->mpppcfg & SC_MP_PROT) {
1412 /* we get mp_seqno from static isdn_net_local */
1413 long mp_seqno = ipts->mp_seqno;
1414 ipts->mp_seqno++;
1415 if (ipt->mpppcfg & SC_OUT_SHORT_SEQ) {
1416 unsigned char *data = isdn_ppp_skb_push(&skb, 3);
Joe Perches475be4d2012-02-19 19:52:38 -08001417 if (!data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418 goto unlock;
1419 mp_seqno &= 0xfff;
1420 data[0] = MP_BEGIN_FRAG | MP_END_FRAG | ((mp_seqno >> 8) & 0xf); /* (B)egin & (E)ndbit .. */
1421 data[1] = mp_seqno & 0xff;
1422 data[2] = proto; /* PID compression */
1423 } else {
1424 unsigned char *data = isdn_ppp_skb_push(&skb, 5);
Joe Perches475be4d2012-02-19 19:52:38 -08001425 if (!data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426 goto unlock;
1427 data[0] = MP_BEGIN_FRAG | MP_END_FRAG; /* (B)egin & (E)ndbit .. */
1428 data[1] = (mp_seqno >> 16) & 0xff; /* sequence number: 24bit */
1429 data[2] = (mp_seqno >> 8) & 0xff;
1430 data[3] = (mp_seqno >> 0) & 0xff;
1431 data[4] = proto; /* PID compression */
1432 }
1433 proto = PPP_MP; /* MP Protocol, 0x003d */
1434 }
1435#endif
1436
1437 /*
1438 * 'link in bundle' compression ...
1439 */
Joe Perches475be4d2012-02-19 19:52:38 -08001440 if (ipt->compflags & SC_LINK_COMP_ON)
1441 skb = isdn_ppp_compress(skb, &proto, ipt, ipts, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442
Joe Perches475be4d2012-02-19 19:52:38 -08001443 if ((ipt->pppcfg & SC_COMP_PROT) && (proto <= 0xff)) {
1444 unsigned char *data = isdn_ppp_skb_push(&skb, 1);
1445 if (!data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446 goto unlock;
1447 data[0] = proto & 0xff;
1448 }
1449 else {
Joe Perches475be4d2012-02-19 19:52:38 -08001450 unsigned char *data = isdn_ppp_skb_push(&skb, 2);
1451 if (!data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452 goto unlock;
1453 data[0] = (proto >> 8) & 0xff;
1454 data[1] = proto & 0xff;
1455 }
Joe Perches475be4d2012-02-19 19:52:38 -08001456 if (!(ipt->pppcfg & SC_COMP_AC)) {
1457 unsigned char *data = isdn_ppp_skb_push(&skb, 2);
1458 if (!data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459 goto unlock;
1460 data[0] = 0xff; /* All Stations */
1461 data[1] = 0x03; /* Unnumbered information */
1462 }
1463
1464 /* tx-stats are now updated via BSENT-callback */
1465
1466 if (ipts->debug & 0x40) {
1467 printk(KERN_DEBUG "skb xmit: len: %d\n", (int) skb->len);
Joe Perches475be4d2012-02-19 19:52:38 -08001468 isdn_ppp_frame_log("xmit", skb->data, skb->len, 32, ipt->unit, lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469 }
Joe Perches475be4d2012-02-19 19:52:38 -08001470
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471 isdn_net_writebuf_skb(lp, skb);
1472
Joe Perches475be4d2012-02-19 19:52:38 -08001473unlock:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474 spin_unlock_bh(&lp->xmit_lock);
Joe Perches475be4d2012-02-19 19:52:38 -08001475out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 return retval;
1477}
1478
1479#ifdef CONFIG_IPPP_FILTER
1480/*
1481 * check if this packet may trigger auto-dial.
1482 */
1483
1484int isdn_ppp_autodial_filter(struct sk_buff *skb, isdn_net_local *lp)
1485{
1486 struct ippp_struct *is = ippp_table[lp->ppp_slot];
1487 u_int16_t proto;
1488 int drop = 0;
1489
1490 switch (ntohs(skb->protocol)) {
1491 case ETH_P_IP:
1492 proto = PPP_IP;
1493 break;
1494 case ETH_P_IPX:
1495 proto = PPP_IPX;
1496 break;
1497 default:
1498 printk(KERN_ERR "isdn_ppp_autodial_filter: unsupported protocol 0x%x.\n",
1499 skb->protocol);
1500 return 1;
1501 }
1502
1503 /* the filter instructions are constructed assuming
1504 * a four-byte PPP header on each packet. we have to
1505 * temporarily remove part of the fake header stuck on
1506 * earlier.
1507 */
Karsten Keild8470b72005-04-21 08:30:30 -07001508 *skb_pull(skb, IPPP_MAX_HEADER - 4) = 1; /* indicate outbound */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509
1510 {
Harvey Harrisonc19d0362008-11-20 04:10:51 -08001511 __be16 *p = (__be16 *)skb->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512
Karsten Keild8470b72005-04-21 08:30:30 -07001513 p++;
Harvey Harrisonc19d0362008-11-20 04:10:51 -08001514 *p = htons(proto);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515 }
Joe Perches475be4d2012-02-19 19:52:38 -08001516
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517 drop |= is->pass_filter
Alexei Starovoitov7ae457c2014-07-30 20:34:16 -07001518 && BPF_PROG_RUN(is->pass_filter, skb) == 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519 drop |= is->active_filter
Alexei Starovoitov7ae457c2014-07-30 20:34:16 -07001520 && BPF_PROG_RUN(is->active_filter, skb) == 0;
Joe Perches475be4d2012-02-19 19:52:38 -08001521
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522 skb_push(skb, IPPP_MAX_HEADER - 4);
1523 return drop;
1524}
1525#endif
1526#ifdef CONFIG_ISDN_MPP
1527
1528/* this is _not_ rfc1990 header, but something we convert both short and long
1529 * headers to for convinience's sake:
Joe Perches475be4d2012-02-19 19:52:38 -08001530 * byte 0 is flags as in rfc1990
1531 * bytes 1...4 is 24-bit seqence number converted to host byte order
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 */
1533#define MP_HEADER_LEN 5
1534
1535#define MP_LONGSEQ_MASK 0x00ffffff
1536#define MP_SHORTSEQ_MASK 0x00000fff
1537#define MP_LONGSEQ_MAX MP_LONGSEQ_MASK
1538#define MP_SHORTSEQ_MAX MP_SHORTSEQ_MASK
Joe Perches475be4d2012-02-19 19:52:38 -08001539#define MP_LONGSEQ_MAXBIT ((MP_LONGSEQ_MASK + 1) >> 1)
1540#define MP_SHORTSEQ_MAXBIT ((MP_SHORTSEQ_MASK + 1) >> 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541
Lucas De Marchi25985ed2011-03-30 22:57:33 -03001542/* sequence-wrap safe comparisons (for long sequence)*/
Joe Perches475be4d2012-02-19 19:52:38 -08001543#define MP_LT(a, b) ((a - b) & MP_LONGSEQ_MAXBIT)
1544#define MP_LE(a, b) !((b - a) & MP_LONGSEQ_MAXBIT)
1545#define MP_GT(a, b) ((b - a) & MP_LONGSEQ_MAXBIT)
1546#define MP_GE(a, b) !((a - b) & MP_LONGSEQ_MAXBIT)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547
Joe Perches475be4d2012-02-19 19:52:38 -08001548#define MP_SEQ(f) ((*(u32 *)(f->data + 1)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549#define MP_FLAGS(f) (f->data[0])
1550
1551static int isdn_ppp_mp_bundle_array_init(void)
1552{
1553 int i;
Joe Perches475be4d2012-02-19 19:52:38 -08001554 int sz = ISDN_MAX_CHANNELS * sizeof(ippp_bundle);
1555 if ((isdn_ppp_bundle_arr = kzalloc(sz, GFP_KERNEL)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556 return -ENOMEM;
Joe Perches475be4d2012-02-19 19:52:38 -08001557 for (i = 0; i < ISDN_MAX_CHANNELS; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558 spin_lock_init(&isdn_ppp_bundle_arr[i].lock);
1559 return 0;
1560}
1561
Joe Perches475be4d2012-02-19 19:52:38 -08001562static ippp_bundle *isdn_ppp_mp_bundle_alloc(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563{
1564 int i;
Joe Perches475be4d2012-02-19 19:52:38 -08001565 for (i = 0; i < ISDN_MAX_CHANNELS; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566 if (isdn_ppp_bundle_arr[i].ref_ct <= 0)
1567 return (isdn_ppp_bundle_arr + i);
1568 return NULL;
1569}
1570
Joe Perches475be4d2012-02-19 19:52:38 -08001571static int isdn_ppp_mp_init(isdn_net_local *lp, ippp_bundle *add_to)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572{
Joe Perches475be4d2012-02-19 19:52:38 -08001573 struct ippp_struct *is;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574
1575 if (lp->ppp_slot < 0) {
1576 printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
Joe Perches475be4d2012-02-19 19:52:38 -08001577 __func__, lp->ppp_slot);
1578 return (-EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 }
1580
1581 is = ippp_table[lp->ppp_slot];
1582 if (add_to) {
Joe Perches475be4d2012-02-19 19:52:38 -08001583 if (lp->netdev->pb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584 lp->netdev->pb->ref_ct--;
1585 lp->netdev->pb = add_to;
1586 } else { /* first link in a bundle */
1587 is->mp_seqno = 0;
1588 if ((lp->netdev->pb = isdn_ppp_mp_bundle_alloc()) == NULL)
1589 return -ENOMEM;
1590 lp->next = lp->last = lp; /* nobody else in a queue */
David S. Millere29d4362009-11-15 22:23:47 -08001591 lp->netdev->pb->frags = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592 lp->netdev->pb->frames = 0;
1593 lp->netdev->pb->seq = UINT_MAX;
1594 }
1595 lp->netdev->pb->ref_ct++;
Joe Perches475be4d2012-02-19 19:52:38 -08001596
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597 is->last_link_seqno = 0;
1598 return 0;
1599}
1600
Joe Perches475be4d2012-02-19 19:52:38 -08001601static u32 isdn_ppp_mp_get_seq(int short_seq,
1602 struct sk_buff *skb, u32 last_seq);
1603static struct sk_buff *isdn_ppp_mp_discard(ippp_bundle *mp,
1604 struct sk_buff *from, struct sk_buff *to);
1605static void isdn_ppp_mp_reassembly(isdn_net_dev *net_dev, isdn_net_local *lp,
1606 struct sk_buff *from, struct sk_buff *to);
1607static void isdn_ppp_mp_free_skb(ippp_bundle *mp, struct sk_buff *skb);
1608static void isdn_ppp_mp_print_recv_pkt(int slot, struct sk_buff *skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609
Joe Perches475be4d2012-02-19 19:52:38 -08001610static void isdn_ppp_mp_receive(isdn_net_dev *net_dev, isdn_net_local *lp,
1611 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612{
David S. Miller38783e62008-09-22 01:15:02 -07001613 struct ippp_struct *is;
Joe Perches475be4d2012-02-19 19:52:38 -08001614 isdn_net_local *lpq;
1615 ippp_bundle *mp;
1616 isdn_mppp_stats *stats;
1617 struct sk_buff *newfrag, *frag, *start, *nextf;
David S. Millere29d4362009-11-15 22:23:47 -08001618 u32 newseq, minseq, thisseq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619 unsigned long flags;
1620 int slot;
1621
1622 spin_lock_irqsave(&net_dev->pb->lock, flags);
Joe Perches475be4d2012-02-19 19:52:38 -08001623 mp = net_dev->pb;
1624 stats = &mp->stats;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625 slot = lp->ppp_slot;
Eric Sesterhenn052bb882006-04-11 17:29:17 -07001626 if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627 printk(KERN_ERR "%s: lp->ppp_slot(%d)\n",
Joe Perches475be4d2012-02-19 19:52:38 -08001628 __func__, lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629 stats->frame_drops++;
1630 dev_kfree_skb(skb);
1631 spin_unlock_irqrestore(&mp->lock, flags);
1632 return;
1633 }
1634 is = ippp_table[slot];
Joe Perches475be4d2012-02-19 19:52:38 -08001635 if (++mp->frames > stats->max_queue_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636 stats->max_queue_len = mp->frames;
Joe Perches475be4d2012-02-19 19:52:38 -08001637
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638 if (is->debug & 0x8)
1639 isdn_ppp_mp_print_recv_pkt(lp->ppp_slot, skb);
1640
Joe Perches475be4d2012-02-19 19:52:38 -08001641 newseq = isdn_ppp_mp_get_seq(is->mpppcfg & SC_IN_SHORT_SEQ,
1642 skb, is->last_link_seqno);
David S. Millere29d4362009-11-15 22:23:47 -08001643
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644
1645 /* if this packet seq # is less than last already processed one,
Joe Perches475be4d2012-02-19 19:52:38 -08001646 * toss it right away, but check for sequence start case first
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647 */
Joe Perches475be4d2012-02-19 19:52:38 -08001648 if (mp->seq > MP_LONGSEQ_MAX && (newseq & MP_LONGSEQ_MAXBIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649 mp->seq = newseq; /* the first packet: required for
1650 * rfc1990 non-compliant clients --
1651 * prevents constant packet toss */
Joe Perches475be4d2012-02-19 19:52:38 -08001652 } else if (MP_LT(newseq, mp->seq)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653 stats->frame_drops++;
1654 isdn_ppp_mp_free_skb(mp, skb);
1655 spin_unlock_irqrestore(&mp->lock, flags);
1656 return;
1657 }
Joe Perches475be4d2012-02-19 19:52:38 -08001658
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659 /* find the minimum received sequence number over all links */
1660 is->last_link_seqno = minseq = newseq;
1661 for (lpq = net_dev->queue;;) {
1662 slot = lpq->ppp_slot;
Eric Sesterhenn052bb882006-04-11 17:29:17 -07001663 if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664 printk(KERN_ERR "%s: lpq->ppp_slot(%d)\n",
Joe Perches475be4d2012-02-19 19:52:38 -08001665 __func__, lpq->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666 } else {
1667 u32 lls = ippp_table[slot]->last_link_seqno;
1668 if (MP_LT(lls, minseq))
1669 minseq = lls;
1670 }
1671 if ((lpq = lpq->next) == net_dev->queue)
1672 break;
1673 }
1674 if (MP_LT(minseq, mp->seq))
1675 minseq = mp->seq; /* can't go beyond already processed
1676 * packets */
1677 newfrag = skb;
1678
Joe Perches475be4d2012-02-19 19:52:38 -08001679 /* if this new fragment is before the first one, then enqueue it now. */
1680 if ((frag = mp->frags) == NULL || MP_LT(newseq, MP_SEQ(frag))) {
David S. Millere29d4362009-11-15 22:23:47 -08001681 newfrag->next = frag;
Joe Perches475be4d2012-02-19 19:52:38 -08001682 mp->frags = frag = newfrag;
1683 newfrag = NULL;
1684 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685
Joe Perches475be4d2012-02-19 19:52:38 -08001686 start = MP_FLAGS(frag) & MP_BEGIN_FRAG &&
1687 MP_SEQ(frag) == mp->seq ? frag : NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001688
Joe Perches475be4d2012-02-19 19:52:38 -08001689 /*
David S. Millere29d4362009-11-15 22:23:47 -08001690 * main fragment traversing loop
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691 *
1692 * try to accomplish several tasks:
David S. Millere29d4362009-11-15 22:23:47 -08001693 * - insert new fragment into the proper sequence slot (once that's done
1694 * newfrag will be set to NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695 * - reassemble any complete fragment sequence (non-null 'start'
André Goddard Rosaaf901ca2009-11-14 13:09:05 -02001696 * indicates there is a contiguous sequence present)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697 * - discard any incomplete sequences that are below minseq -- due
1698 * to the fact that sender always increment sequence number, if there
1699 * is an incomplete sequence below minseq, no new fragments would
1700 * come to complete such sequence and it should be discarded
1701 *
1702 * loop completes when we accomplished the following tasks:
Joe Perches475be4d2012-02-19 19:52:38 -08001703 * - new fragment is inserted in the proper sequence ('newfrag' is
David S. Millere29d4362009-11-15 22:23:47 -08001704 * set to NULL)
Joe Perches475be4d2012-02-19 19:52:38 -08001705 * - we hit a gap in the sequence, so no reassembly/processing is
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706 * possible ('start' would be set to NULL)
1707 *
Robert P. J. Dayd08df602007-02-17 19:07:33 +01001708 * algorithm for this code is derived from code in the book
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 * 'PPP Design And Debugging' by James Carlson (Addison-Wesley)
1710 */
Joe Perches475be4d2012-02-19 19:52:38 -08001711 while (start != NULL || newfrag != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712
Joe Perches475be4d2012-02-19 19:52:38 -08001713 thisseq = MP_SEQ(frag);
1714 nextf = frag->next;
David S. Millere29d4362009-11-15 22:23:47 -08001715
Joe Perches475be4d2012-02-19 19:52:38 -08001716 /* drop any duplicate fragments */
1717 if (newfrag != NULL && thisseq == newseq) {
1718 isdn_ppp_mp_free_skb(mp, newfrag);
1719 newfrag = NULL;
1720 }
David S. Millere29d4362009-11-15 22:23:47 -08001721
Joe Perches475be4d2012-02-19 19:52:38 -08001722 /* insert new fragment before next element if possible. */
1723 if (newfrag != NULL && (nextf == NULL ||
1724 MP_LT(newseq, MP_SEQ(nextf)))) {
1725 newfrag->next = nextf;
1726 frag->next = nextf = newfrag;
1727 newfrag = NULL;
1728 }
David S. Millere29d4362009-11-15 22:23:47 -08001729
Joe Perches475be4d2012-02-19 19:52:38 -08001730 if (start != NULL) {
1731 /* check for misplaced start */
1732 if (start != frag && (MP_FLAGS(frag) & MP_BEGIN_FRAG)) {
David S. Millere29d4362009-11-15 22:23:47 -08001733 printk(KERN_WARNING"isdn_mppp(seq %d): new "
Joe Perches475be4d2012-02-19 19:52:38 -08001734 "BEGIN flag with no prior END", thisseq);
David S. Millere29d4362009-11-15 22:23:47 -08001735 stats->seqerrs++;
1736 stats->frame_drops++;
Joe Perches475be4d2012-02-19 19:52:38 -08001737 start = isdn_ppp_mp_discard(mp, start, frag);
David S. Millere29d4362009-11-15 22:23:47 -08001738 nextf = frag->next;
Joe Perches475be4d2012-02-19 19:52:38 -08001739 }
1740 } else if (MP_LE(thisseq, minseq)) {
1741 if (MP_FLAGS(frag) & MP_BEGIN_FRAG)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742 start = frag;
Joe Perches475be4d2012-02-19 19:52:38 -08001743 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744 if (MP_FLAGS(frag) & MP_END_FRAG)
Joe Perches475be4d2012-02-19 19:52:38 -08001745 stats->frame_drops++;
1746 if (mp->frags == frag)
1747 mp->frags = nextf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748 isdn_ppp_mp_free_skb(mp, frag);
David S. Millere29d4362009-11-15 22:23:47 -08001749 frag = nextf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750 continue;
Joe Perches475be4d2012-02-19 19:52:38 -08001751 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752 }
Joe Perches475be4d2012-02-19 19:52:38 -08001753
David S. Millere29d4362009-11-15 22:23:47 -08001754 /* if start is non-null and we have end fragment, then
Joe Perches475be4d2012-02-19 19:52:38 -08001755 * we have full reassembly sequence -- reassemble
David S. Millere29d4362009-11-15 22:23:47 -08001756 * and process packet now
David S. Miller38783e62008-09-22 01:15:02 -07001757 */
Joe Perches475be4d2012-02-19 19:52:38 -08001758 if (start != NULL && (MP_FLAGS(frag) & MP_END_FRAG)) {
1759 minseq = mp->seq = (thisseq + 1) & MP_LONGSEQ_MASK;
1760 /* Reassemble the packet then dispatch it */
David S. Millere29d4362009-11-15 22:23:47 -08001761 isdn_ppp_mp_reassembly(net_dev, lp, start, nextf);
David S. Miller38783e62008-09-22 01:15:02 -07001762
Joe Perches475be4d2012-02-19 19:52:38 -08001763 start = NULL;
1764 frag = NULL;
1765
1766 mp->frags = nextf;
1767 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768
1769 /* check if need to update start pointer: if we just
1770 * reassembled the packet and sequence is contiguous
1771 * then next fragment should be the start of new reassembly
1772 * if sequence is contiguous, but we haven't reassembled yet,
1773 * keep going.
Lucas De Marchi25985ed2011-03-30 22:57:33 -03001774 * if sequence is not contiguous, either clear everything
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775 * below low watermark and set start to the next frag or
1776 * clear start ptr.
Joe Perches475be4d2012-02-19 19:52:38 -08001777 */
1778 if (nextf != NULL &&
1779 ((thisseq + 1) & MP_LONGSEQ_MASK) == MP_SEQ(nextf)) {
1780 /* if we just reassembled and the next one is here,
David S. Millere29d4362009-11-15 22:23:47 -08001781 * then start another reassembly. */
1782
Joe Perches475be4d2012-02-19 19:52:38 -08001783 if (frag == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784 if (MP_FLAGS(nextf) & MP_BEGIN_FRAG)
Joe Perches475be4d2012-02-19 19:52:38 -08001785 start = nextf;
David S. Millere29d4362009-11-15 22:23:47 -08001786 else
1787 {
Joe Perches475be4d2012-02-19 19:52:38 -08001788 printk(KERN_WARNING"isdn_mppp(seq %d):"
1789 " END flag with no following "
1790 "BEGIN", thisseq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791 stats->seqerrs++;
1792 }
1793 }
David S. Millere29d4362009-11-15 22:23:47 -08001794
Joe Perches475be4d2012-02-19 19:52:38 -08001795 } else {
1796 if (nextf != NULL && frag != NULL &&
1797 MP_LT(thisseq, minseq)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798 /* we've got a break in the sequence
1799 * and we not at the end yet
1800 * and we did not just reassembled
1801 *(if we did, there wouldn't be anything before)
Joe Perches475be4d2012-02-19 19:52:38 -08001802 * and we below the low watermark
1803 * discard all the frames below low watermark
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804 * and start over */
1805 stats->frame_drops++;
Joe Perches475be4d2012-02-19 19:52:38 -08001806 mp->frags = isdn_ppp_mp_discard(mp, start, nextf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807 }
1808 /* break in the sequence, no reassembly */
Joe Perches475be4d2012-02-19 19:52:38 -08001809 start = NULL;
1810 }
1811
1812 frag = nextf;
1813 } /* while -- main loop */
1814
1815 if (mp->frags == NULL)
1816 mp->frags = frag;
1817
1818 /* rather straighforward way to deal with (not very) possible
David S. Millere29d4362009-11-15 22:23:47 -08001819 * queue overflow */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820 if (mp->frames > MP_MAX_QUEUE_LEN) {
1821 stats->overflows++;
David S. Millere29d4362009-11-15 22:23:47 -08001822 while (mp->frames > MP_MAX_QUEUE_LEN) {
1823 frag = mp->frags->next;
1824 isdn_ppp_mp_free_skb(mp, mp->frags);
1825 mp->frags = frag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826 }
1827 }
1828 spin_unlock_irqrestore(&mp->lock, flags);
1829}
1830
Joe Perches475be4d2012-02-19 19:52:38 -08001831static void isdn_ppp_mp_cleanup(isdn_net_local *lp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832{
Joe Perches475be4d2012-02-19 19:52:38 -08001833 struct sk_buff *frag = lp->netdev->pb->frags;
1834 struct sk_buff *nextfrag;
1835 while (frag) {
David S. Millere29d4362009-11-15 22:23:47 -08001836 nextfrag = frag->next;
1837 isdn_ppp_mp_free_skb(lp->netdev->pb, frag);
1838 frag = nextfrag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839 }
David S. Millere29d4362009-11-15 22:23:47 -08001840 lp->netdev->pb->frags = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841}
1842
Joe Perches475be4d2012-02-19 19:52:38 -08001843static u32 isdn_ppp_mp_get_seq(int short_seq,
1844 struct sk_buff *skb, u32 last_seq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845{
1846 u32 seq;
1847 int flags = skb->data[0] & (MP_BEGIN_FRAG | MP_END_FRAG);
Joe Perches475be4d2012-02-19 19:52:38 -08001848
1849 if (!short_seq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850 {
Harvey Harrisonc19d0362008-11-20 04:10:51 -08001851 seq = ntohl(*(__be32 *)skb->data) & MP_LONGSEQ_MASK;
Joe Perches475be4d2012-02-19 19:52:38 -08001852 skb_push(skb, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853 }
1854 else
1855 {
Joe Perches475be4d2012-02-19 19:52:38 -08001856 /* convert 12-bit short seq number to 24-bit long one
1857 */
Harvey Harrisonc19d0362008-11-20 04:10:51 -08001858 seq = ntohs(*(__be16 *)skb->data) & MP_SHORTSEQ_MASK;
Joe Perches475be4d2012-02-19 19:52:38 -08001859
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860 /* check for seqence wrap */
Joe Perches475be4d2012-02-19 19:52:38 -08001861 if (!(seq & MP_SHORTSEQ_MAXBIT) &&
1862 (last_seq & MP_SHORTSEQ_MAXBIT) &&
1863 (unsigned long)last_seq <= MP_LONGSEQ_MAX)
1864 seq |= (last_seq + MP_SHORTSEQ_MAX + 1) &
1865 (~MP_SHORTSEQ_MASK & MP_LONGSEQ_MASK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866 else
1867 seq |= last_seq & (~MP_SHORTSEQ_MASK & MP_LONGSEQ_MASK);
Joe Perches475be4d2012-02-19 19:52:38 -08001868
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869 skb_push(skb, 3); /* put converted seqence back in skb */
1870 }
Joe Perches475be4d2012-02-19 19:52:38 -08001871 *(u32 *)(skb->data + 1) = seq; /* put seqence back in _host_ byte
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872 * order */
1873 skb->data[0] = flags; /* restore flags */
1874 return seq;
1875}
1876
Joe Perches475be4d2012-02-19 19:52:38 -08001877struct sk_buff *isdn_ppp_mp_discard(ippp_bundle *mp,
1878 struct sk_buff *from, struct sk_buff *to)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879{
Joe Perches475be4d2012-02-19 19:52:38 -08001880 if (from)
David S. Millere29d4362009-11-15 22:23:47 -08001881 while (from != to) {
Joe Perches475be4d2012-02-19 19:52:38 -08001882 struct sk_buff *next = from->next;
David S. Millere29d4362009-11-15 22:23:47 -08001883 isdn_ppp_mp_free_skb(mp, from);
Joe Perches475be4d2012-02-19 19:52:38 -08001884 from = next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885 }
David S. Millere29d4362009-11-15 22:23:47 -08001886 return from;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887}
1888
Joe Perches475be4d2012-02-19 19:52:38 -08001889void isdn_ppp_mp_reassembly(isdn_net_dev *net_dev, isdn_net_local *lp,
1890 struct sk_buff *from, struct sk_buff *to)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891{
Joe Perches475be4d2012-02-19 19:52:38 -08001892 ippp_bundle *mp = net_dev->pb;
David S. Miller38783e62008-09-22 01:15:02 -07001893 int proto;
Joe Perches475be4d2012-02-19 19:52:38 -08001894 struct sk_buff *skb;
David S. Millere29d4362009-11-15 22:23:47 -08001895 unsigned int tot_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896
1897 if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
1898 printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
Joe Perches475be4d2012-02-19 19:52:38 -08001899 __func__, lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900 return;
1901 }
Joe Perches475be4d2012-02-19 19:52:38 -08001902 if (MP_FLAGS(from) == (MP_BEGIN_FRAG | MP_END_FRAG)) {
1903 if (ippp_table[lp->ppp_slot]->debug & 0x40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904 printk(KERN_DEBUG "isdn_mppp: reassembly: frame %d, "
Joe Perches475be4d2012-02-19 19:52:38 -08001905 "len %d\n", MP_SEQ(from), from->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906 skb = from;
1907 skb_pull(skb, MP_HEADER_LEN);
Joe Perches475be4d2012-02-19 19:52:38 -08001908 mp->frames--;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909 } else {
Joe Perches475be4d2012-02-19 19:52:38 -08001910 struct sk_buff *frag;
David S. Millere29d4362009-11-15 22:23:47 -08001911 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912
Joe Perches475be4d2012-02-19 19:52:38 -08001913 for (tot_len = n = 0, frag = from; frag != to; frag = frag->next, n++)
David S. Millere29d4362009-11-15 22:23:47 -08001914 tot_len += frag->len - MP_HEADER_LEN;
1915
Joe Perches475be4d2012-02-19 19:52:38 -08001916 if (ippp_table[lp->ppp_slot]->debug & 0x40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917 printk(KERN_DEBUG"isdn_mppp: reassembling frames %d "
Joe Perches475be4d2012-02-19 19:52:38 -08001918 "to %d, len %d\n", MP_SEQ(from),
1919 (MP_SEQ(from) + n - 1) & MP_LONGSEQ_MASK, tot_len);
1920 if ((skb = dev_alloc_skb(tot_len)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921 printk(KERN_ERR "isdn_mppp: cannot allocate sk buff "
Joe Perches475be4d2012-02-19 19:52:38 -08001922 "of size %d\n", tot_len);
David S. Millere29d4362009-11-15 22:23:47 -08001923 isdn_ppp_mp_discard(mp, from, to);
1924 return;
1925 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926
Joe Perches475be4d2012-02-19 19:52:38 -08001927 while (from != to) {
David S. Millere29d4362009-11-15 22:23:47 -08001928 unsigned int len = from->len - MP_HEADER_LEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929
David S. Millere29d4362009-11-15 22:23:47 -08001930 skb_copy_from_linear_data_offset(from, MP_HEADER_LEN,
Joe Perches475be4d2012-02-19 19:52:38 -08001931 skb_put(skb, len),
David S. Millere29d4362009-11-15 22:23:47 -08001932 len);
1933 frag = from->next;
1934 isdn_ppp_mp_free_skb(mp, from);
Joe Perches475be4d2012-02-19 19:52:38 -08001935 from = frag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936 }
1937 }
Joe Perches475be4d2012-02-19 19:52:38 -08001938 proto = isdn_ppp_strip_proto(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939 isdn_ppp_push_higher(net_dev, lp, skb, proto);
1940}
1941
Joe Perches475be4d2012-02-19 19:52:38 -08001942static void isdn_ppp_mp_free_skb(ippp_bundle *mp, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943{
1944 dev_kfree_skb(skb);
1945 mp->frames--;
1946}
1947
Joe Perches475be4d2012-02-19 19:52:38 -08001948static void isdn_ppp_mp_print_recv_pkt(int slot, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949{
Joe Perches475be4d2012-02-19 19:52:38 -08001950 printk(KERN_DEBUG "mp_recv: %d/%d -> %02x %02x %02x %02x %02x %02x\n",
1951 slot, (int) skb->len,
1952 (int) skb->data[0], (int) skb->data[1], (int) skb->data[2],
1953 (int) skb->data[3], (int) skb->data[4], (int) skb->data[5]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954}
1955
1956static int
1957isdn_ppp_bundle(struct ippp_struct *is, int unit)
1958{
1959 char ifn[IFNAMSIZ + 1];
1960 isdn_net_dev *p;
1961 isdn_net_local *lp, *nlp;
1962 int rc;
1963 unsigned long flags;
1964
1965 sprintf(ifn, "ippp%d", unit);
1966 p = isdn_net_findif(ifn);
1967 if (!p) {
1968 printk(KERN_ERR "ippp_bundle: cannot find %s\n", ifn);
1969 return -EINVAL;
1970 }
1971
Joe Perches475be4d2012-02-19 19:52:38 -08001972 spin_lock_irqsave(&p->pb->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973
1974 nlp = is->lp;
1975 lp = p->queue;
Joe Perches475be4d2012-02-19 19:52:38 -08001976 if (nlp->ppp_slot < 0 || nlp->ppp_slot >= ISDN_MAX_CHANNELS ||
1977 lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001978 printk(KERN_ERR "ippp_bundle: binding to invalid slot %d\n",
Joe Perches475be4d2012-02-19 19:52:38 -08001979 nlp->ppp_slot < 0 || nlp->ppp_slot >= ISDN_MAX_CHANNELS ?
1980 nlp->ppp_slot : lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981 rc = -EINVAL;
1982 goto out;
Joe Perches475be4d2012-02-19 19:52:38 -08001983 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984
1985 isdn_net_add_to_bundle(p, nlp);
1986
1987 ippp_table[nlp->ppp_slot]->unit = ippp_table[lp->ppp_slot]->unit;
1988
1989 /* maybe also SC_CCP stuff */
1990 ippp_table[nlp->ppp_slot]->pppcfg |= ippp_table[lp->ppp_slot]->pppcfg &
1991 (SC_ENABLE_IP | SC_NO_TCP_CCID | SC_REJ_COMP_TCP);
1992 ippp_table[nlp->ppp_slot]->mpppcfg |= ippp_table[lp->ppp_slot]->mpppcfg &
1993 (SC_MP_PROT | SC_REJ_MP_PROT | SC_OUT_SHORT_SEQ | SC_IN_SHORT_SEQ);
1994 rc = isdn_ppp_mp_init(nlp, p->pb);
1995out:
1996 spin_unlock_irqrestore(&p->pb->lock, flags);
1997 return rc;
1998}
Joe Perches475be4d2012-02-19 19:52:38 -08001999
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000#endif /* CONFIG_ISDN_MPP */
Joe Perches475be4d2012-02-19 19:52:38 -08002001
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002/*
2003 * network device ioctl handlers
2004 */
2005
2006static int
2007isdn_ppp_dev_ioctl_stats(int slot, struct ifreq *ifr, struct net_device *dev)
2008{
2009 struct ppp_stats __user *res = ifr->ifr_data;
2010 struct ppp_stats t;
Joe Perchesa17531f2010-11-15 11:12:24 +00002011 isdn_net_local *lp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002012
2013 if (!access_ok(VERIFY_WRITE, res, sizeof(struct ppp_stats)))
2014 return -EFAULT;
2015
2016 /* build a temporary stat struct and copy it to user space */
2017
2018 memset(&t, 0, sizeof(struct ppp_stats));
2019 if (dev->flags & IFF_UP) {
2020 t.p.ppp_ipackets = lp->stats.rx_packets;
2021 t.p.ppp_ibytes = lp->stats.rx_bytes;
2022 t.p.ppp_ierrors = lp->stats.rx_errors;
2023 t.p.ppp_opackets = lp->stats.tx_packets;
2024 t.p.ppp_obytes = lp->stats.tx_bytes;
2025 t.p.ppp_oerrors = lp->stats.tx_errors;
2026#ifdef CONFIG_ISDN_PPP_VJ
2027 if (slot >= 0 && ippp_table[slot]->slcomp) {
2028 struct slcompress *slcomp = ippp_table[slot]->slcomp;
2029 t.vj.vjs_packets = slcomp->sls_o_compressed + slcomp->sls_o_uncompressed;
2030 t.vj.vjs_compressed = slcomp->sls_o_compressed;
2031 t.vj.vjs_searches = slcomp->sls_o_searches;
2032 t.vj.vjs_misses = slcomp->sls_o_misses;
2033 t.vj.vjs_errorin = slcomp->sls_i_error;
2034 t.vj.vjs_tossed = slcomp->sls_i_tossed;
2035 t.vj.vjs_uncompressedin = slcomp->sls_i_uncompressed;
2036 t.vj.vjs_compressedin = slcomp->sls_i_compressed;
2037 }
2038#endif
2039 }
2040 if (copy_to_user(res, &t, sizeof(struct ppp_stats)))
2041 return -EFAULT;
2042 return 0;
2043}
2044
2045int
2046isdn_ppp_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
2047{
Joe Perches475be4d2012-02-19 19:52:38 -08002048 int error = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049 int len;
Joe Perchesa17531f2010-11-15 11:12:24 +00002050 isdn_net_local *lp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002051
2052
2053 if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP)
2054 return -EINVAL;
2055
2056 switch (cmd) {
2057#define PPP_VERSION "2.3.7"
Joe Perches475be4d2012-02-19 19:52:38 -08002058 case SIOCGPPPVER:
2059 len = strlen(PPP_VERSION) + 1;
2060 if (copy_to_user(ifr->ifr_data, PPP_VERSION, len))
2061 error = -EFAULT;
2062 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002063
Joe Perches475be4d2012-02-19 19:52:38 -08002064 case SIOCGPPPSTATS:
2065 error = isdn_ppp_dev_ioctl_stats(lp->ppp_slot, ifr, dev);
2066 break;
2067 default:
2068 error = -EINVAL;
2069 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070 }
2071 return error;
2072}
2073
2074static int
2075isdn_ppp_if_get_unit(char *name)
2076{
2077 int len,
Joe Perches475be4d2012-02-19 19:52:38 -08002078 i,
2079 unit = 0,
2080 deci;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002081
2082 len = strlen(name);
2083
2084 if (strncmp("ippp", name, 4) || len > 8)
2085 return -1;
2086
2087 for (i = 0, deci = 1; i < len; i++, deci *= 10) {
2088 char a = name[len - i - 1];
2089 if (a >= '0' && a <= '9')
2090 unit += (a - '0') * deci;
2091 else
2092 break;
2093 }
2094 if (!i || len - i != 4)
2095 unit = -1;
2096
2097 return unit;
2098}
2099
2100
2101int
2102isdn_ppp_dial_slave(char *name)
2103{
2104#ifdef CONFIG_ISDN_MPP
2105 isdn_net_dev *ndev;
2106 isdn_net_local *lp;
2107 struct net_device *sdev;
2108
2109 if (!(ndev = isdn_net_findif(name)))
2110 return 1;
2111 lp = ndev->local;
2112 if (!(lp->flags & ISDN_NET_CONNECTED))
2113 return 5;
2114
2115 sdev = lp->slave;
2116 while (sdev) {
Joe Perchesa17531f2010-11-15 11:12:24 +00002117 isdn_net_local *mlp = netdev_priv(sdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118 if (!(mlp->flags & ISDN_NET_CONNECTED))
2119 break;
2120 sdev = mlp->slave;
2121 }
2122 if (!sdev)
2123 return 2;
2124
Joe Perchesa17531f2010-11-15 11:12:24 +00002125 isdn_net_dial_req(netdev_priv(sdev));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002126 return 0;
2127#else
2128 return -1;
2129#endif
2130}
2131
2132int
2133isdn_ppp_hangup_slave(char *name)
2134{
2135#ifdef CONFIG_ISDN_MPP
2136 isdn_net_dev *ndev;
2137 isdn_net_local *lp;
2138 struct net_device *sdev;
2139
2140 if (!(ndev = isdn_net_findif(name)))
2141 return 1;
2142 lp = ndev->local;
2143 if (!(lp->flags & ISDN_NET_CONNECTED))
2144 return 5;
2145
2146 sdev = lp->slave;
2147 while (sdev) {
Joe Perchesa17531f2010-11-15 11:12:24 +00002148 isdn_net_local *mlp = netdev_priv(sdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002149
2150 if (mlp->slave) { /* find last connected link in chain */
Wang Chen838361f2008-12-03 15:49:46 -08002151 isdn_net_local *nlp = ISDN_SLAVE_PRIV(mlp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002152
2153 if (!(nlp->flags & ISDN_NET_CONNECTED))
2154 break;
2155 } else if (mlp->flags & ISDN_NET_CONNECTED)
2156 break;
Joe Perches475be4d2012-02-19 19:52:38 -08002157
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158 sdev = mlp->slave;
2159 }
2160 if (!sdev)
2161 return 2;
2162
2163 isdn_net_hangup(sdev);
2164 return 0;
2165#else
2166 return -1;
2167#endif
2168}
2169
2170/*
2171 * PPP compression stuff
2172 */
2173
2174
2175/* Push an empty CCP Data Frame up to the daemon to wake it up and let it
2176 generate a CCP Reset-Request or tear down CCP altogether */
2177
2178static void isdn_ppp_ccp_kickup(struct ippp_struct *is)
2179{
2180 isdn_ppp_fill_rq(NULL, 0, PPP_COMP, is->lp->ppp_slot);
2181}
2182
2183/* In-kernel handling of CCP Reset-Request and Reset-Ack is necessary,
2184 but absolutely nontrivial. The most abstruse problem we are facing is
2185 that the generation, reception and all the handling of timeouts and
2186 resends including proper request id management should be entirely left
2187 to the (de)compressor, but indeed is not covered by the current API to
2188 the (de)compressor. The API is a prototype version from PPP where only
2189 some (de)compressors have yet been implemented and all of them are
2190 rather simple in their reset handling. Especially, their is only one
2191 outstanding ResetAck at a time with all of them and ResetReq/-Acks do
2192 not have parameters. For this very special case it was sufficient to
2193 just return an error code from the decompressor and have a single
2194 reset() entry to communicate all the necessary information between
2195 the framework and the (de)compressor. Bad enough, LZS is different
2196 (and any other compressor may be different, too). It has multiple
2197 histories (eventually) and needs to Reset each of them independently
2198 and thus uses multiple outstanding Acks and history numbers as an
2199 additional parameter to Reqs/Acks.
2200 All that makes it harder to port the reset state engine into the
2201 kernel because it is not just the same simple one as in (i)pppd but
2202 it must be able to pass additional parameters and have multiple out-
2203 standing Acks. We are trying to achieve the impossible by handling
2204 reset transactions independent by their id. The id MUST change when
2205 the data portion changes, thus any (de)compressor who uses more than
2206 one resettable state must provide and recognize individual ids for
2207 each individual reset transaction. The framework itself does _only_
2208 differentiate them by id, because it has no other semantics like the
2209 (de)compressor might.
2210 This looks like a major redesign of the interface would be nice,
2211 but I don't have an idea how to do it better. */
2212
2213/* Send a CCP Reset-Request or Reset-Ack directly from the kernel. This is
2214 getting that lengthy because there is no simple "send-this-frame-out"
2215 function above but every wrapper does a bit different. Hope I guess
2216 correct in this hack... */
2217
2218static void isdn_ppp_ccp_xmit_reset(struct ippp_struct *is, int proto,
2219 unsigned char code, unsigned char id,
2220 unsigned char *data, int len)
2221{
2222 struct sk_buff *skb;
2223 unsigned char *p;
2224 int hl;
2225 int cnt = 0;
2226 isdn_net_local *lp = is->lp;
2227
2228 /* Alloc large enough skb */
2229 hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen;
Joe Perches475be4d2012-02-19 19:52:38 -08002230 skb = alloc_skb(len + hl + 16, GFP_ATOMIC);
2231 if (!skb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232 printk(KERN_WARNING
2233 "ippp: CCP cannot send reset - out of memory\n");
2234 return;
2235 }
2236 skb_reserve(skb, hl);
2237
2238 /* We may need to stuff an address and control field first */
Joe Perches475be4d2012-02-19 19:52:38 -08002239 if (!(is->pppcfg & SC_COMP_AC)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002240 p = skb_put(skb, 2);
2241 *p++ = 0xff;
2242 *p++ = 0x03;
2243 }
2244
2245 /* Stuff proto, code, id and length */
2246 p = skb_put(skb, 6);
2247 *p++ = (proto >> 8);
2248 *p++ = (proto & 0xff);
2249 *p++ = code;
2250 *p++ = id;
2251 cnt = 4 + len;
2252 *p++ = (cnt >> 8);
2253 *p++ = (cnt & 0xff);
2254
2255 /* Now stuff remaining bytes */
Joe Perches475be4d2012-02-19 19:52:38 -08002256 if (len) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257 p = skb_put(skb, len);
2258 memcpy(p, data, len);
2259 }
2260
2261 /* skb is now ready for xmit */
2262 printk(KERN_DEBUG "Sending CCP Frame:\n");
Joe Perches475be4d2012-02-19 19:52:38 -08002263 isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit, lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002264
2265 isdn_net_write_super(lp, skb);
2266}
2267
2268/* Allocate the reset state vector */
2269static struct ippp_ccp_reset *isdn_ppp_ccp_reset_alloc(struct ippp_struct *is)
2270{
2271 struct ippp_ccp_reset *r;
Burman Yan41f96932006-12-08 02:39:35 -08002272 r = kzalloc(sizeof(struct ippp_ccp_reset), GFP_KERNEL);
Joe Perches475be4d2012-02-19 19:52:38 -08002273 if (!r) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274 printk(KERN_ERR "ippp_ccp: failed to allocate reset data"
2275 " structure - no mem\n");
2276 return NULL;
2277 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002278 printk(KERN_DEBUG "ippp_ccp: allocated reset data structure %p\n", r);
2279 is->reset = r;
2280 return r;
2281}
2282
2283/* Destroy the reset state vector. Kill all pending timers first. */
2284static void isdn_ppp_ccp_reset_free(struct ippp_struct *is)
2285{
2286 unsigned int id;
2287
2288 printk(KERN_DEBUG "ippp_ccp: freeing reset data structure %p\n",
2289 is->reset);
Joe Perches475be4d2012-02-19 19:52:38 -08002290 for (id = 0; id < 256; id++) {
2291 if (is->reset->rs[id]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002292 isdn_ppp_ccp_reset_free_state(is, (unsigned char)id);
2293 }
2294 }
2295 kfree(is->reset);
2296 is->reset = NULL;
2297}
2298
2299/* Free a given state and clear everything up for later reallocation */
2300static void isdn_ppp_ccp_reset_free_state(struct ippp_struct *is,
2301 unsigned char id)
2302{
2303 struct ippp_ccp_reset_state *rs;
2304
Joe Perches475be4d2012-02-19 19:52:38 -08002305 if (is->reset->rs[id]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306 printk(KERN_DEBUG "ippp_ccp: freeing state for id %d\n", id);
2307 rs = is->reset->rs[id];
2308 /* Make sure the kernel will not call back later */
Joe Perches475be4d2012-02-19 19:52:38 -08002309 if (rs->ta)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310 del_timer(&rs->timer);
2311 is->reset->rs[id] = NULL;
2312 kfree(rs);
2313 } else {
2314 printk(KERN_WARNING "ippp_ccp: id %d is not allocated\n", id);
2315 }
2316}
2317
2318/* The timer callback function which is called when a ResetReq has timed out,
2319 aka has never been answered by a ResetAck */
2320static void isdn_ppp_ccp_timer_callback(unsigned long closure)
2321{
2322 struct ippp_ccp_reset_state *rs =
2323 (struct ippp_ccp_reset_state *)closure;
2324
Joe Perches475be4d2012-02-19 19:52:38 -08002325 if (!rs) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002326 printk(KERN_ERR "ippp_ccp: timer cb with zero closure.\n");
2327 return;
2328 }
Joe Perches475be4d2012-02-19 19:52:38 -08002329 if (rs->ta && rs->state == CCPResetSentReq) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002330 /* We are correct here */
Joe Perches475be4d2012-02-19 19:52:38 -08002331 if (!rs->expra) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002332 /* Hmm, there is no Ack really expected. We can clean
2333 up the state now, it will be reallocated if the
2334 decompressor insists on another reset */
2335 rs->ta = 0;
2336 isdn_ppp_ccp_reset_free_state(rs->is, rs->id);
2337 return;
2338 }
2339 printk(KERN_DEBUG "ippp_ccp: CCP Reset timed out for id %d\n",
2340 rs->id);
2341 /* Push it again */
2342 isdn_ppp_ccp_xmit_reset(rs->is, PPP_CCP, CCP_RESETREQ, rs->id,
2343 rs->data, rs->dlen);
2344 /* Restart timer */
Joe Perches475be4d2012-02-19 19:52:38 -08002345 rs->timer.expires = jiffies + HZ * 5;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002346 add_timer(&rs->timer);
2347 } else {
2348 printk(KERN_WARNING "ippp_ccp: timer cb in wrong state %d\n",
2349 rs->state);
2350 }
2351}
2352
2353/* Allocate a new reset transaction state */
2354static struct ippp_ccp_reset_state *isdn_ppp_ccp_reset_alloc_state(struct ippp_struct *is,
Joe Perches475be4d2012-02-19 19:52:38 -08002355 unsigned char id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002356{
2357 struct ippp_ccp_reset_state *rs;
Joe Perches475be4d2012-02-19 19:52:38 -08002358 if (is->reset->rs[id]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359 printk(KERN_WARNING "ippp_ccp: old state exists for id %d\n",
2360 id);
2361 return NULL;
2362 } else {
Burman Yan41f96932006-12-08 02:39:35 -08002363 rs = kzalloc(sizeof(struct ippp_ccp_reset_state), GFP_KERNEL);
Joe Perches475be4d2012-02-19 19:52:38 -08002364 if (!rs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002365 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002366 rs->state = CCPResetIdle;
2367 rs->is = is;
2368 rs->id = id;
Marcel Holtmanndab6df62006-12-21 23:06:24 +01002369 init_timer(&rs->timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002370 rs->timer.data = (unsigned long)rs;
2371 rs->timer.function = isdn_ppp_ccp_timer_callback;
2372 is->reset->rs[id] = rs;
2373 }
2374 return rs;
2375}
2376
2377
2378/* A decompressor wants a reset with a set of parameters - do what is
2379 necessary to fulfill it */
2380static void isdn_ppp_ccp_reset_trans(struct ippp_struct *is,
2381 struct isdn_ppp_resetparams *rp)
2382{
2383 struct ippp_ccp_reset_state *rs;
2384
Joe Perches475be4d2012-02-19 19:52:38 -08002385 if (rp->valid) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386 /* The decompressor defines parameters by itself */
Joe Perches475be4d2012-02-19 19:52:38 -08002387 if (rp->rsend) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002388 /* And he wants us to send a request */
Joe Perches475be4d2012-02-19 19:52:38 -08002389 if (!(rp->idval)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002390 printk(KERN_ERR "ippp_ccp: decompressor must"
2391 " specify reset id\n");
2392 return;
2393 }
Joe Perches475be4d2012-02-19 19:52:38 -08002394 if (is->reset->rs[rp->id]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395 /* There is already a transaction in existence
2396 for this id. May be still waiting for a
2397 Ack or may be wrong. */
2398 rs = is->reset->rs[rp->id];
Joe Perches475be4d2012-02-19 19:52:38 -08002399 if (rs->state == CCPResetSentReq && rs->ta) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002400 printk(KERN_DEBUG "ippp_ccp: reset"
2401 " trans still in progress"
2402 " for id %d\n", rp->id);
2403 } else {
2404 printk(KERN_WARNING "ippp_ccp: reset"
2405 " trans in wrong state %d for"
2406 " id %d\n", rs->state, rp->id);
2407 }
2408 } else {
2409 /* Ok, this is a new transaction */
2410 printk(KERN_DEBUG "ippp_ccp: new trans for id"
2411 " %d to be started\n", rp->id);
2412 rs = isdn_ppp_ccp_reset_alloc_state(is, rp->id);
Joe Perches475be4d2012-02-19 19:52:38 -08002413 if (!rs) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002414 printk(KERN_ERR "ippp_ccp: out of mem"
2415 " allocing ccp trans\n");
2416 return;
2417 }
2418 rs->state = CCPResetSentReq;
2419 rs->expra = rp->expra;
Joe Perches475be4d2012-02-19 19:52:38 -08002420 if (rp->dtval) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002421 rs->dlen = rp->dlen;
2422 memcpy(rs->data, rp->data, rp->dlen);
2423 }
2424 /* HACK TODO - add link comp here */
2425 isdn_ppp_ccp_xmit_reset(is, PPP_CCP,
2426 CCP_RESETREQ, rs->id,
2427 rs->data, rs->dlen);
2428 /* Start the timer */
Joe Perches475be4d2012-02-19 19:52:38 -08002429 rs->timer.expires = jiffies + 5 * HZ;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430 add_timer(&rs->timer);
2431 rs->ta = 1;
2432 }
2433 } else {
2434 printk(KERN_DEBUG "ippp_ccp: no reset sent\n");
2435 }
2436 } else {
2437 /* The reset params are invalid. The decompressor does not
2438 care about them, so we just send the minimal requests
2439 and increase ids only when an Ack is received for a
2440 given id */
Joe Perches475be4d2012-02-19 19:52:38 -08002441 if (is->reset->rs[is->reset->lastid]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442 /* There is already a transaction in existence
2443 for this id. May be still waiting for a
2444 Ack or may be wrong. */
2445 rs = is->reset->rs[is->reset->lastid];
Joe Perches475be4d2012-02-19 19:52:38 -08002446 if (rs->state == CCPResetSentReq && rs->ta) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002447 printk(KERN_DEBUG "ippp_ccp: reset"
2448 " trans still in progress"
2449 " for id %d\n", rp->id);
2450 } else {
2451 printk(KERN_WARNING "ippp_ccp: reset"
2452 " trans in wrong state %d for"
2453 " id %d\n", rs->state, rp->id);
2454 }
2455 } else {
2456 printk(KERN_DEBUG "ippp_ccp: new trans for id"
2457 " %d to be started\n", is->reset->lastid);
2458 rs = isdn_ppp_ccp_reset_alloc_state(is,
2459 is->reset->lastid);
Joe Perches475be4d2012-02-19 19:52:38 -08002460 if (!rs) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461 printk(KERN_ERR "ippp_ccp: out of mem"
2462 " allocing ccp trans\n");
2463 return;
2464 }
2465 rs->state = CCPResetSentReq;
2466 /* We always expect an Ack if the decompressor doesn't
2467 know better */
2468 rs->expra = 1;
2469 rs->dlen = 0;
2470 /* HACK TODO - add link comp here */
2471 isdn_ppp_ccp_xmit_reset(is, PPP_CCP, CCP_RESETREQ,
2472 rs->id, NULL, 0);
2473 /* Start the timer */
Joe Perches475be4d2012-02-19 19:52:38 -08002474 rs->timer.expires = jiffies + 5 * HZ;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002475 add_timer(&rs->timer);
2476 rs->ta = 1;
2477 }
2478 }
2479}
2480
2481/* An Ack was received for this id. This means we stop the timer and clean
2482 up the state prior to calling the decompressors reset routine. */
2483static void isdn_ppp_ccp_reset_ack_rcvd(struct ippp_struct *is,
2484 unsigned char id)
2485{
2486 struct ippp_ccp_reset_state *rs = is->reset->rs[id];
2487
Joe Perches475be4d2012-02-19 19:52:38 -08002488 if (rs) {
2489 if (rs->ta && rs->state == CCPResetSentReq) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002490 /* Great, we are correct */
Joe Perches475be4d2012-02-19 19:52:38 -08002491 if (!rs->expra)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492 printk(KERN_DEBUG "ippp_ccp: ResetAck received"
2493 " for id %d but not expected\n", id);
2494 } else {
2495 printk(KERN_INFO "ippp_ccp: ResetAck received out of"
2496 "sync for id %d\n", id);
2497 }
Joe Perches475be4d2012-02-19 19:52:38 -08002498 if (rs->ta) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499 rs->ta = 0;
2500 del_timer(&rs->timer);
2501 }
2502 isdn_ppp_ccp_reset_free_state(is, id);
2503 } else {
2504 printk(KERN_INFO "ippp_ccp: ResetAck received for unknown id"
2505 " %d\n", id);
2506 }
2507 /* Make sure the simple reset stuff uses a new id next time */
2508 is->reset->lastid++;
2509}
2510
Joe Perches475be4d2012-02-19 19:52:38 -08002511/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002512 * decompress packet
2513 *
2514 * if master = 0, we're trying to uncompress an per-link compressed packet,
2515 * as opposed to an compressed reconstructed-from-MPPP packet.
2516 * proto is updated to protocol field of uncompressed packet.
2517 *
2518 * retval: decompressed packet,
2519 * same packet if uncompressed,
2520 * NULL if decompression error
2521 */
2522
Joe Perches475be4d2012-02-19 19:52:38 -08002523static struct sk_buff *isdn_ppp_decompress(struct sk_buff *skb, struct ippp_struct *is, struct ippp_struct *master,
2524 int *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002525{
2526 void *stat = NULL;
2527 struct isdn_ppp_compressor *ipc = NULL;
2528 struct sk_buff *skb_out;
2529 int len;
2530 struct ippp_struct *ri;
2531 struct isdn_ppp_resetparams rsparm;
2532 unsigned char rsdata[IPPP_RESET_MAXDATABYTES];
2533
Joe Perches475be4d2012-02-19 19:52:38 -08002534 if (!master) {
2535 // per-link decompression
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536 stat = is->link_decomp_stat;
2537 ipc = is->link_decompressor;
2538 ri = is;
2539 } else {
2540 stat = master->decomp_stat;
2541 ipc = master->decompressor;
2542 ri = master;
2543 }
2544
2545 if (!ipc) {
2546 // no decompressor -> we can't decompress.
2547 printk(KERN_DEBUG "ippp: no decompressor defined!\n");
2548 return skb;
2549 }
Eric Sesterhenn6dd44a72006-03-26 18:19:26 +02002550 BUG_ON(!stat); // if we have a compressor, stat has been set as well
Linus Torvalds1da177e2005-04-16 15:20:36 -07002551
Joe Perches475be4d2012-02-19 19:52:38 -08002552 if ((master && *proto == PPP_COMP) || (!master && *proto == PPP_COMPFRAG)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002553 // compressed packets are compressed by their protocol type
2554
2555 // Set up reset params for the decompressor
Joe Perches475be4d2012-02-19 19:52:38 -08002556 memset(&rsparm, 0, sizeof(rsparm));
2557 rsparm.data = rsdata;
2558 rsparm.maxdlen = IPPP_RESET_MAXDATABYTES;
2559
2560 skb_out = dev_alloc_skb(is->mru + PPP_HDRLEN);
2561 if (!skb_out) {
2562 kfree_skb(skb);
2563 printk(KERN_ERR "ippp: decomp memory allocation failure\n");
Jesper Juhlf6e2cdc2006-12-08 02:39:34 -08002564 return NULL;
Joe Perches475be4d2012-02-19 19:52:38 -08002565 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002566 len = ipc->decompress(stat, skb, skb_out, &rsparm);
2567 kfree_skb(skb);
2568 if (len <= 0) {
Joe Perches475be4d2012-02-19 19:52:38 -08002569 switch (len) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002570 case DECOMP_ERROR:
2571 printk(KERN_INFO "ippp: decomp wants reset %s params\n",
2572 rsparm.valid ? "with" : "without");
Joe Perches475be4d2012-02-19 19:52:38 -08002573
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574 isdn_ppp_ccp_reset_trans(ri, &rsparm);
2575 break;
2576 case DECOMP_FATALERROR:
2577 ri->pppcfg |= SC_DC_FERROR;
2578 /* Kick ipppd to recognize the error */
2579 isdn_ppp_ccp_kickup(ri);
2580 break;
2581 }
2582 kfree_skb(skb_out);
2583 return NULL;
2584 }
2585 *proto = isdn_ppp_strip_proto(skb_out);
2586 if (*proto < 0) {
2587 kfree_skb(skb_out);
2588 return NULL;
2589 }
2590 return skb_out;
Joe Perches475be4d2012-02-19 19:52:38 -08002591 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592 // uncompressed packets are fed through the decompressor to
2593 // update the decompressor state
2594 ipc->incomp(stat, skb, *proto);
2595 return skb;
2596 }
2597}
2598
2599/*
Joe Perches475be4d2012-02-19 19:52:38 -08002600 * compress a frame
Linus Torvalds1da177e2005-04-16 15:20:36 -07002601 * type=0: normal/bundle compression
2602 * =1: link compression
2603 * returns original skb if we haven't compressed the frame
2604 * and a new skb pointer if we've done it
2605 */
Joe Perches475be4d2012-02-19 19:52:38 -08002606static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in, int *proto,
2607 struct ippp_struct *is, struct ippp_struct *master, int type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608{
Joe Perches475be4d2012-02-19 19:52:38 -08002609 int ret;
2610 int new_proto;
2611 struct isdn_ppp_compressor *compressor;
2612 void *stat;
2613 struct sk_buff *skb_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614
2615 /* we do not compress control protocols */
Joe Perches475be4d2012-02-19 19:52:38 -08002616 if (*proto < 0 || *proto > 0x3fff) {
2617 return skb_in;
2618 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002619
Joe Perches475be4d2012-02-19 19:52:38 -08002620 if (type) { /* type=1 => Link compression */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621 return skb_in;
2622 }
2623 else {
Joe Perches475be4d2012-02-19 19:52:38 -08002624 if (!master) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625 compressor = is->compressor;
2626 stat = is->comp_stat;
2627 }
2628 else {
2629 compressor = master->compressor;
2630 stat = master->comp_stat;
2631 }
2632 new_proto = PPP_COMP;
2633 }
2634
Joe Perches475be4d2012-02-19 19:52:38 -08002635 if (!compressor) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636 printk(KERN_ERR "isdn_ppp: No compressor set!\n");
2637 return skb_in;
2638 }
Joe Perches475be4d2012-02-19 19:52:38 -08002639 if (!stat) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640 printk(KERN_ERR "isdn_ppp: Compressor not initialized?\n");
2641 return skb_in;
2642 }
2643
2644 /* Allow for at least 150 % expansion (for now) */
Joe Perches475be4d2012-02-19 19:52:38 -08002645 skb_out = alloc_skb(skb_in->len + skb_in->len / 2 + 32 +
2646 skb_headroom(skb_in), GFP_ATOMIC);
2647 if (!skb_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648 return skb_in;
2649 skb_reserve(skb_out, skb_headroom(skb_in));
2650
Joe Perches475be4d2012-02-19 19:52:38 -08002651 ret = (compressor->compress)(stat, skb_in, skb_out, *proto);
2652 if (!ret) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653 dev_kfree_skb(skb_out);
2654 return skb_in;
2655 }
Joe Perches475be4d2012-02-19 19:52:38 -08002656
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657 dev_kfree_skb(skb_in);
2658 *proto = new_proto;
2659 return skb_out;
2660}
2661
2662/*
Joe Perches475be4d2012-02-19 19:52:38 -08002663 * we received a CCP frame ..
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664 * not a clean solution, but we MUST handle a few cases in the kernel
2665 */
2666static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp,
Joe Perches475be4d2012-02-19 19:52:38 -08002667 struct sk_buff *skb, int proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002668{
2669 struct ippp_struct *is;
2670 struct ippp_struct *mis;
2671 int len;
2672 struct isdn_ppp_resetparams rsparm;
Joe Perches475be4d2012-02-19 19:52:38 -08002673 unsigned char rsdata[IPPP_RESET_MAXDATABYTES];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002674
2675 printk(KERN_DEBUG "Received CCP frame from peer slot(%d)\n",
Joe Perches475be4d2012-02-19 19:52:38 -08002676 lp->ppp_slot);
Eric Sesterhenn052bb882006-04-11 17:29:17 -07002677 if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678 printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
Joe Perches475be4d2012-02-19 19:52:38 -08002679 __func__, lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680 return;
2681 }
2682 is = ippp_table[lp->ppp_slot];
Joe Perches475be4d2012-02-19 19:52:38 -08002683 isdn_ppp_frame_log("ccp-rcv", skb->data, skb->len, 32, is->unit, lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684
Joe Perches475be4d2012-02-19 19:52:38 -08002685 if (lp->master) {
Wang Chen838361f2008-12-03 15:49:46 -08002686 int slot = ISDN_MASTER_PRIV(lp)->ppp_slot;
Eric Sesterhenn052bb882006-04-11 17:29:17 -07002687 if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002688 printk(KERN_ERR "%s: slot(%d) out of range\n",
Joe Perches475be4d2012-02-19 19:52:38 -08002689 __func__, slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690 return;
Joe Perches475be4d2012-02-19 19:52:38 -08002691 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692 mis = ippp_table[slot];
2693 } else
2694 mis = is;
2695
Joe Perches475be4d2012-02-19 19:52:38 -08002696 switch (skb->data[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697 case CCP_CONFREQ:
Joe Perches475be4d2012-02-19 19:52:38 -08002698 if (is->debug & 0x10)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699 printk(KERN_DEBUG "Disable compression here!\n");
Joe Perches475be4d2012-02-19 19:52:38 -08002700 if (proto == PPP_CCP)
2701 mis->compflags &= ~SC_COMP_ON;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702 else
Joe Perches475be4d2012-02-19 19:52:38 -08002703 is->compflags &= ~SC_LINK_COMP_ON;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704 break;
2705 case CCP_TERMREQ:
2706 case CCP_TERMACK:
Joe Perches475be4d2012-02-19 19:52:38 -08002707 if (is->debug & 0x10)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708 printk(KERN_DEBUG "Disable (de)compression here!\n");
Joe Perches475be4d2012-02-19 19:52:38 -08002709 if (proto == PPP_CCP)
2710 mis->compflags &= ~(SC_DECOMP_ON | SC_COMP_ON);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002711 else
Joe Perches475be4d2012-02-19 19:52:38 -08002712 is->compflags &= ~(SC_LINK_DECOMP_ON | SC_LINK_COMP_ON);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002713 break;
2714 case CCP_CONFACK:
2715 /* if we RECEIVE an ackowledge we enable the decompressor */
Joe Perches475be4d2012-02-19 19:52:38 -08002716 if (is->debug & 0x10)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717 printk(KERN_DEBUG "Enable decompression here!\n");
Joe Perches475be4d2012-02-19 19:52:38 -08002718 if (proto == PPP_CCP) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719 if (!mis->decompressor)
2720 break;
2721 mis->compflags |= SC_DECOMP_ON;
2722 } else {
2723 if (!is->decompressor)
2724 break;
2725 is->compflags |= SC_LINK_DECOMP_ON;
2726 }
2727 break;
2728
2729 case CCP_RESETACK:
2730 printk(KERN_DEBUG "Received ResetAck from peer\n");
2731 len = (skb->data[2] << 8) | skb->data[3];
2732 len -= 4;
2733
Joe Perches475be4d2012-02-19 19:52:38 -08002734 if (proto == PPP_CCP) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735 /* If a reset Ack was outstanding for this id, then
2736 clean up the state engine */
2737 isdn_ppp_ccp_reset_ack_rcvd(mis, skb->data[1]);
Joe Perches475be4d2012-02-19 19:52:38 -08002738 if (mis->decompressor && mis->decomp_stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739 mis->decompressor->
2740 reset(mis->decomp_stat,
2741 skb->data[0],
2742 skb->data[1],
2743 len ? &skb->data[4] : NULL,
2744 len, NULL);
2745 /* TODO: This is not easy to decide here */
2746 mis->compflags &= ~SC_DECOMP_DISCARD;
2747 }
2748 else {
2749 isdn_ppp_ccp_reset_ack_rcvd(is, skb->data[1]);
Joe Perches475be4d2012-02-19 19:52:38 -08002750 if (is->link_decompressor && is->link_decomp_stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002751 is->link_decompressor->
2752 reset(is->link_decomp_stat,
2753 skb->data[0],
2754 skb->data[1],
2755 len ? &skb->data[4] : NULL,
2756 len, NULL);
2757 /* TODO: neither here */
2758 is->compflags &= ~SC_LINK_DECOMP_DISCARD;
2759 }
2760 break;
2761
2762 case CCP_RESETREQ:
2763 printk(KERN_DEBUG "Received ResetReq from peer\n");
2764 /* Receiving a ResetReq means we must reset our compressor */
2765 /* Set up reset params for the reset entry */
2766 memset(&rsparm, 0, sizeof(rsparm));
2767 rsparm.data = rsdata;
Joe Perches475be4d2012-02-19 19:52:38 -08002768 rsparm.maxdlen = IPPP_RESET_MAXDATABYTES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002769 /* Isolate data length */
2770 len = (skb->data[2] << 8) | skb->data[3];
2771 len -= 4;
Joe Perches475be4d2012-02-19 19:52:38 -08002772 if (proto == PPP_CCP) {
2773 if (mis->compressor && mis->comp_stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774 mis->compressor->
2775 reset(mis->comp_stat,
2776 skb->data[0],
2777 skb->data[1],
2778 len ? &skb->data[4] : NULL,
2779 len, &rsparm);
2780 }
2781 else {
Joe Perches475be4d2012-02-19 19:52:38 -08002782 if (is->link_compressor && is->link_comp_stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783 is->link_compressor->
2784 reset(is->link_comp_stat,
2785 skb->data[0],
2786 skb->data[1],
2787 len ? &skb->data[4] : NULL,
2788 len, &rsparm);
2789 }
2790 /* Ack the Req as specified by rsparm */
Joe Perches475be4d2012-02-19 19:52:38 -08002791 if (rsparm.valid) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792 /* Compressor reset handler decided how to answer */
Joe Perches475be4d2012-02-19 19:52:38 -08002793 if (rsparm.rsend) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794 /* We should send a Frame */
2795 isdn_ppp_ccp_xmit_reset(is, proto, CCP_RESETACK,
2796 rsparm.idval ? rsparm.id
2797 : skb->data[1],
2798 rsparm.dtval ?
2799 rsparm.data : NULL,
2800 rsparm.dtval ?
2801 rsparm.dlen : 0);
2802 } else {
2803 printk(KERN_DEBUG "ResetAck suppressed\n");
2804 }
2805 } else {
2806 /* We answer with a straight reflected Ack */
2807 isdn_ppp_ccp_xmit_reset(is, proto, CCP_RESETACK,
2808 skb->data[1],
2809 len ? &skb->data[4] : NULL,
2810 len);
2811 }
2812 break;
2813 }
2814}
2815
2816
2817/*
2818 * Daemon sends a CCP frame ...
2819 */
2820
2821/* TODO: Clean this up with new Reset semantics */
2822
2823/* I believe the CCP handling as-is is done wrong. Compressed frames
2824 * should only be sent/received after CCP reaches UP state, which means
2825 * both sides have sent CONF_ACK. Currently, we handle both directions
2826 * independently, which means we may accept compressed frames too early
2827 * (supposedly not a problem), but may also mean we send compressed frames
2828 * too early, which may turn out to be a problem.
2829 * This part of state machine should actually be handled by (i)pppd, but
2830 * that's too big of a change now. --kai
2831 */
2832
2833/* Actually, we might turn this into an advantage: deal with the RFC in
2834 * the old tradition of beeing generous on what we accept, but beeing
2835 * strict on what we send. Thus we should just
2836 * - accept compressed frames as soon as decompression is negotiated
2837 * - send compressed frames only when decomp *and* comp are negotiated
2838 * - drop rx compressed frames if we cannot decomp (instead of pushing them
2839 * up to ipppd)
2840 * and I tried to modify this file according to that. --abp
2841 */
2842
2843static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *skb)
2844{
Joe Perches475be4d2012-02-19 19:52:38 -08002845 struct ippp_struct *mis, *is;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002846 int proto, slot = lp->ppp_slot;
2847 unsigned char *data;
2848
Joe Perches475be4d2012-02-19 19:52:38 -08002849 if (!skb || skb->len < 3)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002850 return;
2851 if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
2852 printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
Joe Perches475be4d2012-02-19 19:52:38 -08002853 __func__, slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002854 return;
Joe Perches475be4d2012-02-19 19:52:38 -08002855 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002856 is = ippp_table[slot];
2857 /* Daemon may send with or without address and control field comp */
2858 data = skb->data;
Joe Perches475be4d2012-02-19 19:52:38 -08002859 if (!(is->pppcfg & SC_COMP_AC) && data[0] == 0xff && data[1] == 0x03) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002860 data += 2;
Joe Perches475be4d2012-02-19 19:52:38 -08002861 if (skb->len < 5)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002862 return;
2863 }
2864
Joe Perches475be4d2012-02-19 19:52:38 -08002865 proto = ((int)data[0]<<8) + data[1];
2866 if (proto != PPP_CCP && proto != PPP_CCPFRAG)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002867 return;
2868
2869 printk(KERN_DEBUG "Received CCP frame from daemon:\n");
Joe Perches475be4d2012-02-19 19:52:38 -08002870 isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit, lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002871
2872 if (lp->master) {
Wang Chen838361f2008-12-03 15:49:46 -08002873 slot = ISDN_MASTER_PRIV(lp)->ppp_slot;
Eric Sesterhenn052bb882006-04-11 17:29:17 -07002874 if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875 printk(KERN_ERR "%s: slot(%d) out of range\n",
Joe Perches475be4d2012-02-19 19:52:38 -08002876 __func__, slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877 return;
Joe Perches475be4d2012-02-19 19:52:38 -08002878 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002879 mis = ippp_table[slot];
2880 } else
2881 mis = is;
2882 if (mis != is)
2883 printk(KERN_DEBUG "isdn_ppp: Ouch! Master CCP sends on slave slot!\n");
Joe Perches475be4d2012-02-19 19:52:38 -08002884
2885 switch (data[2]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002886 case CCP_CONFREQ:
Joe Perches475be4d2012-02-19 19:52:38 -08002887 if (is->debug & 0x10)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002888 printk(KERN_DEBUG "Disable decompression here!\n");
Joe Perches475be4d2012-02-19 19:52:38 -08002889 if (proto == PPP_CCP)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002890 is->compflags &= ~SC_DECOMP_ON;
2891 else
2892 is->compflags &= ~SC_LINK_DECOMP_ON;
2893 break;
2894 case CCP_TERMREQ:
2895 case CCP_TERMACK:
Joe Perches475be4d2012-02-19 19:52:38 -08002896 if (is->debug & 0x10)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002897 printk(KERN_DEBUG "Disable (de)compression here!\n");
Joe Perches475be4d2012-02-19 19:52:38 -08002898 if (proto == PPP_CCP)
2899 is->compflags &= ~(SC_DECOMP_ON | SC_COMP_ON);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002900 else
Joe Perches475be4d2012-02-19 19:52:38 -08002901 is->compflags &= ~(SC_LINK_DECOMP_ON | SC_LINK_COMP_ON);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002902 break;
2903 case CCP_CONFACK:
2904 /* if we SEND an ackowledge we can/must enable the compressor */
Joe Perches475be4d2012-02-19 19:52:38 -08002905 if (is->debug & 0x10)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002906 printk(KERN_DEBUG "Enable compression here!\n");
Joe Perches475be4d2012-02-19 19:52:38 -08002907 if (proto == PPP_CCP) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002908 if (!is->compressor)
2909 break;
2910 is->compflags |= SC_COMP_ON;
2911 } else {
2912 if (!is->compressor)
2913 break;
2914 is->compflags |= SC_LINK_COMP_ON;
2915 }
2916 break;
2917 case CCP_RESETACK:
2918 /* If we send a ACK we should reset our compressor */
Joe Perches475be4d2012-02-19 19:52:38 -08002919 if (is->debug & 0x10)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002920 printk(KERN_DEBUG "Reset decompression state here!\n");
2921 printk(KERN_DEBUG "ResetAck from daemon passed by\n");
Joe Perches475be4d2012-02-19 19:52:38 -08002922 if (proto == PPP_CCP) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002923 /* link to master? */
Joe Perches475be4d2012-02-19 19:52:38 -08002924 if (is->compressor && is->comp_stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002925 is->compressor->reset(is->comp_stat, 0, 0,
2926 NULL, 0, NULL);
Joe Perches475be4d2012-02-19 19:52:38 -08002927 is->compflags &= ~SC_COMP_DISCARD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002928 }
2929 else {
Joe Perches475be4d2012-02-19 19:52:38 -08002930 if (is->link_compressor && is->link_comp_stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002931 is->link_compressor->reset(is->link_comp_stat,
2932 0, 0, NULL, 0, NULL);
Joe Perches475be4d2012-02-19 19:52:38 -08002933 is->compflags &= ~SC_LINK_COMP_DISCARD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002934 }
2935 break;
2936 case CCP_RESETREQ:
2937 /* Just let it pass by */
2938 printk(KERN_DEBUG "ResetReq from daemon passed by\n");
2939 break;
2940 }
2941}
2942
2943int isdn_ppp_register_compressor(struct isdn_ppp_compressor *ipc)
2944{
2945 ipc->next = ipc_head;
2946 ipc->prev = NULL;
Joe Perches475be4d2012-02-19 19:52:38 -08002947 if (ipc_head) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002948 ipc_head->prev = ipc;
2949 }
2950 ipc_head = ipc;
2951 return 0;
2952}
2953
2954int isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *ipc)
2955{
Joe Perches475be4d2012-02-19 19:52:38 -08002956 if (ipc->prev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957 ipc->prev->next = ipc->next;
2958 else
2959 ipc_head = ipc->next;
Joe Perches475be4d2012-02-19 19:52:38 -08002960 if (ipc->next)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002961 ipc->next->prev = ipc->prev;
2962 ipc->prev = ipc->next = NULL;
2963 return 0;
2964}
2965
2966static int isdn_ppp_set_compressor(struct ippp_struct *is, struct isdn_ppp_comp_data *data)
2967{
2968 struct isdn_ppp_compressor *ipc = ipc_head;
2969 int ret;
2970 void *stat;
2971 int num = data->num;
2972
Joe Perches475be4d2012-02-19 19:52:38 -08002973 if (is->debug & 0x10)
2974 printk(KERN_DEBUG "[%d] Set %s type %d\n", is->unit,
2975 (data->flags & IPPP_COMP_FLAG_XMIT) ? "compressor" : "decompressor", num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002976
2977 /* If is has no valid reset state vector, we cannot allocate a
2978 decompressor. The decompressor would cause reset transactions
2979 sooner or later, and they need that vector. */
2980
Joe Perches475be4d2012-02-19 19:52:38 -08002981 if (!(data->flags & IPPP_COMP_FLAG_XMIT) && !is->reset) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002982 printk(KERN_ERR "ippp_ccp: no reset data structure - can't"
2983 " allow decompression.\n");
2984 return -ENOMEM;
2985 }
2986
Joe Perches475be4d2012-02-19 19:52:38 -08002987 while (ipc) {
2988 if (ipc->num == num) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002989 stat = ipc->alloc(data);
Joe Perches475be4d2012-02-19 19:52:38 -08002990 if (stat) {
2991 ret = ipc->init(stat, data, is->unit, 0);
2992 if (!ret) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002993 printk(KERN_ERR "Can't init (de)compression!\n");
2994 ipc->free(stat);
2995 stat = NULL;
2996 break;
2997 }
2998 }
2999 else {
3000 printk(KERN_ERR "Can't alloc (de)compression!\n");
3001 break;
3002 }
3003
Joe Perches475be4d2012-02-19 19:52:38 -08003004 if (data->flags & IPPP_COMP_FLAG_XMIT) {
3005 if (data->flags & IPPP_COMP_FLAG_LINK) {
3006 if (is->link_comp_stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003007 is->link_compressor->free(is->link_comp_stat);
3008 is->link_comp_stat = stat;
Joe Perches475be4d2012-02-19 19:52:38 -08003009 is->link_compressor = ipc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010 }
3011 else {
Joe Perches475be4d2012-02-19 19:52:38 -08003012 if (is->comp_stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003013 is->compressor->free(is->comp_stat);
3014 is->comp_stat = stat;
Joe Perches475be4d2012-02-19 19:52:38 -08003015 is->compressor = ipc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003016 }
3017 }
Joe Perches475be4d2012-02-19 19:52:38 -08003018 else {
3019 if (data->flags & IPPP_COMP_FLAG_LINK) {
3020 if (is->link_decomp_stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003021 is->link_decompressor->free(is->link_decomp_stat);
3022 is->link_decomp_stat = stat;
Joe Perches475be4d2012-02-19 19:52:38 -08003023 is->link_decompressor = ipc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003024 }
3025 else {
Joe Perches475be4d2012-02-19 19:52:38 -08003026 if (is->decomp_stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003027 is->decompressor->free(is->decomp_stat);
3028 is->decomp_stat = stat;
Joe Perches475be4d2012-02-19 19:52:38 -08003029 is->decompressor = ipc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003030 }
3031 }
3032 return 0;
3033 }
3034 ipc = ipc->next;
3035 }
3036 return -EINVAL;
3037}