blob: 64b586458d3dbecaf887cc18e70e5ff2234aa9b1 [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);
Ben Hutchings0baa57d2015-11-01 16:21:24 +0000304 if (!is->reset)
305 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306
307 is->lp = NULL;
308 is->mp_seqno = 0; /* MP sequence number */
309 is->pppcfg = 0; /* ppp configuration */
310 is->mpppcfg = 0; /* mppp configuration */
311 is->last_link_seqno = -1; /* MP: maybe set to Bundle-MIN, when joining a bundle ?? */
312 is->unit = -1; /* set, when we have our interface */
313 is->mru = 1524; /* MRU, default 1524 */
314 is->maxcid = 16; /* VJ: maxcid */
315 is->tk = current;
316 init_waitqueue_head(&is->wq);
317 is->first = is->rq + NUM_RCV_BUFFS - 1; /* receive queue */
318 is->last = is->rq;
319 is->minor = min;
320#ifdef CONFIG_ISDN_PPP_VJ
321 /*
322 * VJ header compression init
323 */
324 is->slcomp = slhc_init(16, 16); /* not necessary for 2. link in bundle */
Ben Hutchings4ab42d72015-11-01 16:22:53 +0000325 if (IS_ERR(is->slcomp)) {
Ben Hutchings0baa57d2015-11-01 16:21:24 +0000326 isdn_ppp_ccp_reset_free(is);
Ben Hutchings4ab42d72015-11-01 16:22:53 +0000327 return PTR_ERR(is->slcomp);
Ben Hutchings0baa57d2015-11-01 16:21:24 +0000328 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329#endif
330#ifdef CONFIG_IPPP_FILTER
331 is->pass_filter = NULL;
332 is->active_filter = NULL;
333#endif
334 is->state = IPPP_OPEN;
335
336 return 0;
337}
338
339/*
340 * release ippp device
341 */
342void
343isdn_ppp_release(int min, struct file *file)
344{
345 int i;
346 struct ippp_struct *is;
347
348 if (min < 0 || min >= ISDN_MAX_CHANNELS)
349 return;
350 is = file->private_data;
351
352 if (!is) {
Harvey Harrison156f1ed2008-04-28 02:14:40 -0700353 printk(KERN_ERR "%s: no file->private_data\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 return;
355 }
356 if (is->debug & 0x1)
357 printk(KERN_DEBUG "ippp: release, minor: %d %lx\n", min, (long) is->lp);
358
359 if (is->lp) { /* a lp address says: this link is still up */
360 isdn_net_dev *p = is->lp->netdev;
361
362 if (!p) {
Harvey Harrison156f1ed2008-04-28 02:14:40 -0700363 printk(KERN_ERR "%s: no lp->netdev\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364 return;
365 }
366 is->state &= ~IPPP_CONNECT; /* -> effect: no call of wakeup */
367 /*
368 * isdn_net_hangup() calls isdn_ppp_free()
369 * isdn_ppp_free() sets is->lp to NULL and lp->ppp_slot to -1
370 * removing the IPPP_CONNECT flag omits calling of isdn_ppp_wakeup_daemon()
371 */
Karsten Keild62a38d2007-10-08 20:37:11 -0700372 isdn_net_hangup(p->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 }
374 for (i = 0; i < NUM_RCV_BUFFS; i++) {
Jesper Juhl3c7208f2005-11-07 01:01:29 -0800375 kfree(is->rq[i].buf);
376 is->rq[i].buf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 }
378 is->first = is->rq + NUM_RCV_BUFFS - 1; /* receive queue */
379 is->last = is->rq;
380
381#ifdef CONFIG_ISDN_PPP_VJ
382/* TODO: if this was the previous master: link the slcomp to the new master */
383 slhc_free(is->slcomp);
384 is->slcomp = NULL;
385#endif
386#ifdef CONFIG_IPPP_FILTER
Daniel Borkmann77e01142014-03-28 18:58:24 +0100387 if (is->pass_filter) {
Alexei Starovoitov7ae457c2014-07-30 20:34:16 -0700388 bpf_prog_destroy(is->pass_filter);
Daniel Borkmann77e01142014-03-28 18:58:24 +0100389 is->pass_filter = NULL;
390 }
391
392 if (is->active_filter) {
Alexei Starovoitov7ae457c2014-07-30 20:34:16 -0700393 bpf_prog_destroy(is->active_filter);
Daniel Borkmann77e01142014-03-28 18:58:24 +0100394 is->active_filter = NULL;
395 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396#endif
397
398/* TODO: if this was the previous master: link the stuff to the new master */
Joe Perches475be4d2012-02-19 19:52:38 -0800399 if (is->comp_stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 is->compressor->free(is->comp_stat);
Joe Perches475be4d2012-02-19 19:52:38 -0800401 if (is->link_comp_stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 is->link_compressor->free(is->link_comp_stat);
Joe Perches475be4d2012-02-19 19:52:38 -0800403 if (is->link_decomp_stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 is->link_decompressor->free(is->link_decomp_stat);
Joe Perches475be4d2012-02-19 19:52:38 -0800405 if (is->decomp_stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 is->decompressor->free(is->decomp_stat);
Joe Perches475be4d2012-02-19 19:52:38 -0800407 is->compressor = is->link_compressor = NULL;
408 is->decompressor = is->link_decompressor = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 is->comp_stat = is->link_comp_stat = NULL;
Joe Perches475be4d2012-02-19 19:52:38 -0800410 is->decomp_stat = is->link_decomp_stat = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411
412 /* Clean up if necessary */
Joe Perches475be4d2012-02-19 19:52:38 -0800413 if (is->reset)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 isdn_ppp_ccp_reset_free(is);
415
416 /* this slot is ready for new connections */
417 is->state = 0;
418}
419
420/*
421 * get_arg .. ioctl helper
422 */
423static int
424get_arg(void __user *b, void *val, int len)
425{
426 if (len <= 0)
427 len = sizeof(void *);
428 if (copy_from_user(val, b, len))
429 return -EFAULT;
430 return 0;
431}
432
433/*
434 * set arg .. ioctl helper
435 */
436static int
Joe Perches475be4d2012-02-19 19:52:38 -0800437set_arg(void __user *b, void *val, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438{
Joe Perches475be4d2012-02-19 19:52:38 -0800439 if (len <= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 len = sizeof(void *);
441 if (copy_to_user(b, val, len))
442 return -EFAULT;
443 return 0;
444}
445
Daniele Venzano26285ba2009-01-26 12:24:38 -0800446#ifdef CONFIG_IPPP_FILTER
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447static int get_filter(void __user *arg, struct sock_filter **p)
448{
449 struct sock_fprog uprog;
450 struct sock_filter *code = NULL;
Christoph Schulz3916a312014-07-14 08:01:10 +0200451 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452
453 if (copy_from_user(&uprog, arg, sizeof(uprog)))
454 return -EFAULT;
455
456 if (!uprog.len) {
457 *p = NULL;
458 return 0;
459 }
460
461 /* uprog.len is unsigned short, so no overflow here */
462 len = uprog.len * sizeof(struct sock_filter);
Julia Lawall024cb8a2010-05-21 22:26:42 +0000463 code = memdup_user(uprog.filter, len);
464 if (IS_ERR(code))
465 return PTR_ERR(code);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 *p = code;
468 return uprog.len;
469}
Daniele Venzano26285ba2009-01-26 12:24:38 -0800470#endif /* CONFIG_IPPP_FILTER */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471
472/*
473 * ippp device ioctl
474 */
475int
476isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
477{
478 unsigned long val;
Joe Perches475be4d2012-02-19 19:52:38 -0800479 int r, i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 struct ippp_struct *is;
481 isdn_net_local *lp;
482 struct isdn_ppp_comp_data data;
483 void __user *argp = (void __user *)arg;
484
Joe Perches54cbb1c2010-07-12 10:50:02 +0000485 is = file->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 lp = is->lp;
487
488 if (is->debug & 0x1)
489 printk(KERN_DEBUG "isdn_ppp_ioctl: minor: %d cmd: %x state: %x\n", min, cmd, is->state);
490
491 if (!(is->state & IPPP_OPEN))
492 return -EINVAL;
493
494 switch (cmd) {
Joe Perches475be4d2012-02-19 19:52:38 -0800495 case PPPIOCBUNDLE:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496#ifdef CONFIG_ISDN_MPP
Joe Perches475be4d2012-02-19 19:52:38 -0800497 if (!(is->state & IPPP_CONNECT))
498 return -EINVAL;
499 if ((r = get_arg(argp, &val, sizeof(val))))
500 return r;
501 printk(KERN_DEBUG "iPPP-bundle: minor: %d, slave unit: %d, master unit: %d\n",
502 (int) min, (int) is->unit, (int) val);
503 return isdn_ppp_bundle(is, val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504#else
Joe Perches475be4d2012-02-19 19:52:38 -0800505 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506#endif
Joe Perches475be4d2012-02-19 19:52:38 -0800507 break;
508 case PPPIOCGUNIT: /* get ppp/isdn unit number */
509 if ((r = set_arg(argp, &is->unit, sizeof(is->unit))))
510 return r;
511 break;
512 case PPPIOCGIFNAME:
513 if (!lp)
514 return -EINVAL;
515 if ((r = set_arg(argp, lp->netdev->dev->name,
516 strlen(lp->netdev->dev->name))))
517 return r;
518 break;
519 case PPPIOCGMPFLAGS: /* get configuration flags */
520 if ((r = set_arg(argp, &is->mpppcfg, sizeof(is->mpppcfg))))
521 return r;
522 break;
523 case PPPIOCSMPFLAGS: /* set configuration flags */
524 if ((r = get_arg(argp, &val, sizeof(val))))
525 return r;
526 is->mpppcfg = val;
527 break;
528 case PPPIOCGFLAGS: /* get configuration flags */
529 if ((r = set_arg(argp, &is->pppcfg, sizeof(is->pppcfg))))
530 return r;
531 break;
532 case PPPIOCSFLAGS: /* set configuration flags */
533 if ((r = get_arg(argp, &val, sizeof(val)))) {
534 return r;
535 }
536 if (val & SC_ENABLE_IP && !(is->pppcfg & SC_ENABLE_IP) && (is->state & IPPP_CONNECT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 if (lp) {
Joe Perches475be4d2012-02-19 19:52:38 -0800538 /* OK .. we are ready to send buffers */
539 is->pppcfg = val; /* isdn_ppp_xmit test for SC_ENABLE_IP !!! */
540 netif_wake_queue(lp->netdev->dev);
541 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 }
Joe Perches475be4d2012-02-19 19:52:38 -0800543 }
544 is->pppcfg = val;
545 break;
546 case PPPIOCGIDLE: /* get idle time information */
547 if (lp) {
548 struct ppp_idle pidle;
549 pidle.xmit_idle = pidle.recv_idle = lp->huptimer;
550 if ((r = set_arg(argp, &pidle, sizeof(struct ppp_idle))))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 return r;
Joe Perches475be4d2012-02-19 19:52:38 -0800552 }
553 break;
554 case PPPIOCSMRU: /* set receive unit size for PPP */
555 if ((r = get_arg(argp, &val, sizeof(val))))
556 return r;
557 is->mru = val;
558 break;
559 case PPPIOCSMPMRU:
560 break;
561 case PPPIOCSMPMTU:
562 break;
563 case PPPIOCSMAXCID: /* set the maximum compression slot id */
564 if ((r = get_arg(argp, &val, sizeof(val))))
565 return r;
566 val++;
567 if (is->maxcid != val) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568#ifdef CONFIG_ISDN_PPP_VJ
Joe Perches475be4d2012-02-19 19:52:38 -0800569 struct slcompress *sltmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570#endif
Joe Perches475be4d2012-02-19 19:52:38 -0800571 if (is->debug & 0x1)
572 printk(KERN_DEBUG "ippp, ioctl: changed MAXCID to %ld\n", val);
573 is->maxcid = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574#ifdef CONFIG_ISDN_PPP_VJ
Joe Perches475be4d2012-02-19 19:52:38 -0800575 sltmp = slhc_init(16, val);
Ben Hutchings4ab42d72015-11-01 16:22:53 +0000576 if (IS_ERR(sltmp))
577 return PTR_ERR(sltmp);
Joe Perches475be4d2012-02-19 19:52:38 -0800578 if (is->slcomp)
579 slhc_free(is->slcomp);
580 is->slcomp = sltmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581#endif
Joe Perches475be4d2012-02-19 19:52:38 -0800582 }
583 break;
584 case PPPIOCGDEBUG:
585 if ((r = set_arg(argp, &is->debug, sizeof(is->debug))))
586 return r;
587 break;
588 case PPPIOCSDEBUG:
589 if ((r = get_arg(argp, &val, sizeof(val))))
590 return r;
591 is->debug = val;
592 break;
593 case PPPIOCGCOMPRESSORS:
594 {
595 unsigned long protos[8] = {0,};
596 struct isdn_ppp_compressor *ipc = ipc_head;
597 while (ipc) {
598 j = ipc->num / (sizeof(long) * 8);
599 i = ipc->num % (sizeof(long) * 8);
600 if (j < 8)
Dan Carpenter435f08a2012-10-09 23:42:18 +0000601 protos[j] |= (1UL << i);
Joe Perches475be4d2012-02-19 19:52:38 -0800602 ipc = ipc->next;
603 }
604 if ((r = set_arg(argp, protos, 8 * sizeof(long))))
605 return r;
606 }
607 break;
608 case PPPIOCSCOMPRESSOR:
609 if ((r = get_arg(argp, &data, sizeof(struct isdn_ppp_comp_data))))
610 return r;
611 return isdn_ppp_set_compressor(is, &data);
612 case PPPIOCGCALLINFO:
613 {
614 struct pppcallinfo pci;
615 memset((char *)&pci, 0, sizeof(struct pppcallinfo));
616 if (lp)
617 {
618 strncpy(pci.local_num, lp->msn, 63);
619 if (lp->dial) {
620 strncpy(pci.remote_num, lp->dial->num, 63);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 }
Joe Perches475be4d2012-02-19 19:52:38 -0800622 pci.charge_units = lp->charge;
623 if (lp->outgoing)
624 pci.calltype = CALLTYPE_OUTGOING;
625 else
626 pci.calltype = CALLTYPE_INCOMING;
627 if (lp->flags & ISDN_NET_CALLBACK)
628 pci.calltype |= CALLTYPE_CALLBACK;
629 }
630 return set_arg(argp, &pci, sizeof(struct pppcallinfo));
631 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632#ifdef CONFIG_IPPP_FILTER
Joe Perches475be4d2012-02-19 19:52:38 -0800633 case PPPIOCSPASS:
634 {
Daniel Borkmannb1fcd352014-05-23 18:43:58 +0200635 struct sock_fprog_kern fprog;
Joe Perches475be4d2012-02-19 19:52:38 -0800636 struct sock_filter *code;
Daniel Borkmann77e01142014-03-28 18:58:24 +0100637 int err, len = get_filter(argp, &code);
638
Joe Perches475be4d2012-02-19 19:52:38 -0800639 if (len < 0)
640 return len;
Daniel Borkmann77e01142014-03-28 18:58:24 +0100641
642 fprog.len = len;
643 fprog.filter = code;
644
Christoph Schulzcc25eaa2014-07-16 22:10:29 +0200645 if (is->pass_filter) {
Alexei Starovoitov7ae457c2014-07-30 20:34:16 -0700646 bpf_prog_destroy(is->pass_filter);
Christoph Schulzcc25eaa2014-07-16 22:10:29 +0200647 is->pass_filter = NULL;
648 }
649 if (fprog.filter != NULL)
Alexei Starovoitov7ae457c2014-07-30 20:34:16 -0700650 err = bpf_prog_create(&is->pass_filter, &fprog);
Christoph Schulzcc25eaa2014-07-16 22:10:29 +0200651 else
652 err = 0;
Daniel Borkmann77e01142014-03-28 18:58:24 +0100653 kfree(code);
654
655 return err;
Joe Perches475be4d2012-02-19 19:52:38 -0800656 }
657 case PPPIOCSACTIVE:
658 {
Daniel Borkmannb1fcd352014-05-23 18:43:58 +0200659 struct sock_fprog_kern fprog;
Joe Perches475be4d2012-02-19 19:52:38 -0800660 struct sock_filter *code;
Daniel Borkmann77e01142014-03-28 18:58:24 +0100661 int err, len = get_filter(argp, &code);
662
Joe Perches475be4d2012-02-19 19:52:38 -0800663 if (len < 0)
664 return len;
Daniel Borkmann77e01142014-03-28 18:58:24 +0100665
666 fprog.len = len;
667 fprog.filter = code;
668
Christoph Schulzcc25eaa2014-07-16 22:10:29 +0200669 if (is->active_filter) {
Alexei Starovoitov7ae457c2014-07-30 20:34:16 -0700670 bpf_prog_destroy(is->active_filter);
Christoph Schulzcc25eaa2014-07-16 22:10:29 +0200671 is->active_filter = NULL;
672 }
673 if (fprog.filter != NULL)
Alexei Starovoitov7ae457c2014-07-30 20:34:16 -0700674 err = bpf_prog_create(&is->active_filter, &fprog);
Christoph Schulzcc25eaa2014-07-16 22:10:29 +0200675 else
676 err = 0;
Daniel Borkmann77e01142014-03-28 18:58:24 +0100677 kfree(code);
678
679 return err;
Joe Perches475be4d2012-02-19 19:52:38 -0800680 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681#endif /* CONFIG_IPPP_FILTER */
Joe Perches475be4d2012-02-19 19:52:38 -0800682 default:
683 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 }
685 return 0;
686}
687
688unsigned int
Joe Perches475be4d2012-02-19 19:52:38 -0800689isdn_ppp_poll(struct file *file, poll_table *wait)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690{
691 u_int mask;
692 struct ippp_buf_queue *bf, *bl;
693 u_long flags;
694 struct ippp_struct *is;
695
696 is = file->private_data;
697
698 if (is->debug & 0x2)
699 printk(KERN_DEBUG "isdn_ppp_poll: minor: %d\n",
Al Viro496ad9a2013-01-23 17:07:38 -0500700 iminor(file_inode(file)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701
702 /* just registers wait_queue hook. This doesn't really wait. */
703 poll_wait(file, &is->wq, wait);
704
705 if (!(is->state & IPPP_OPEN)) {
Joe Perches475be4d2012-02-19 19:52:38 -0800706 if (is->state == IPPP_CLOSEWAIT)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 return POLLHUP;
708 printk(KERN_DEBUG "isdn_ppp: device not open\n");
709 return POLLERR;
710 }
711 /* we're always ready to send .. */
712 mask = POLLOUT | POLLWRNORM;
713
714 spin_lock_irqsave(&is->buflock, flags);
715 bl = is->last;
716 bf = is->first;
717 /*
718 * if IPPP_NOBLOCK is set we return even if we have nothing to read
719 */
720 if (bf->next != bl || (is->state & IPPP_NOBLOCK)) {
721 is->state &= ~IPPP_NOBLOCK;
722 mask |= POLLIN | POLLRDNORM;
723 }
724 spin_unlock_irqrestore(&is->buflock, flags);
725 return mask;
726}
727
728/*
729 * fill up isdn_ppp_read() queue ..
730 */
731
732static int
733isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot)
734{
735 struct ippp_buf_queue *bf, *bl;
736 u_long flags;
737 u_char *nbuf;
738 struct ippp_struct *is;
739
740 if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
741 printk(KERN_WARNING "ippp: illegal slot(%d).\n", slot);
742 return 0;
743 }
744 is = ippp_table[slot];
745
746 if (!(is->state & IPPP_CONNECT)) {
747 printk(KERN_DEBUG "ippp: device not activated.\n");
748 return 0;
749 }
Robert P. J. Day5cbded52006-12-13 00:35:56 -0800750 nbuf = kmalloc(len + 4, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 if (!nbuf) {
752 printk(KERN_WARNING "ippp: Can't alloc buf\n");
753 return 0;
754 }
755 nbuf[0] = PPP_ALLSTATIONS;
756 nbuf[1] = PPP_UI;
757 nbuf[2] = proto >> 8;
758 nbuf[3] = proto & 0xff;
759 memcpy(nbuf + 4, buf, len);
760
761 spin_lock_irqsave(&is->buflock, flags);
762 bf = is->first;
763 bl = is->last;
764
765 if (bf == bl) {
766 printk(KERN_WARNING "ippp: Queue is full; discarding first buffer\n");
767 bf = bf->next;
768 kfree(bf->buf);
769 is->first = bf;
770 }
771 bl->buf = (char *) nbuf;
772 bl->len = len + 4;
773
774 is->last = bl->next;
775 spin_unlock_irqrestore(&is->buflock, flags);
776 wake_up_interruptible(&is->wq);
777 return len;
778}
779
780/*
781 * read() .. non-blocking: ipppd calls it only after select()
782 * reports, that there is data
783 */
784
785int
786isdn_ppp_read(int min, struct file *file, char __user *buf, int count)
787{
788 struct ippp_struct *is;
789 struct ippp_buf_queue *b;
790 u_long flags;
791 u_char *save_buf;
792
793 is = file->private_data;
794
795 if (!(is->state & IPPP_OPEN))
796 return 0;
797
798 if (!access_ok(VERIFY_WRITE, buf, count))
799 return -EFAULT;
800
801 spin_lock_irqsave(&is->buflock, flags);
802 b = is->first->next;
803 save_buf = b->buf;
804 if (!save_buf) {
805 spin_unlock_irqrestore(&is->buflock, flags);
806 return -EAGAIN;
807 }
808 if (b->len < count)
809 count = b->len;
810 b->buf = NULL;
811 is->first = b;
812
813 spin_unlock_irqrestore(&is->buflock, flags);
Jesper Juhlc41a24c2006-03-25 03:07:02 -0800814 if (copy_to_user(buf, save_buf, count))
815 count = -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 kfree(save_buf);
817
818 return count;
819}
820
821/*
822 * ipppd wanna write a packet to the card .. non-blocking
823 */
824
825int
826isdn_ppp_write(int min, struct file *file, const char __user *buf, int count)
827{
828 isdn_net_local *lp;
829 struct ippp_struct *is;
830 int proto;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831
832 is = file->private_data;
833
834 if (!(is->state & IPPP_CONNECT))
835 return 0;
836
837 lp = is->lp;
838
839 /* -> push it directly to the lowlevel interface */
840
841 if (!lp)
842 printk(KERN_DEBUG "isdn_ppp_write: lp == NULL\n");
843 else {
Meng Xu93eef212017-09-19 21:49:55 -0400844 if (lp->isdn_device < 0 || lp->isdn_channel < 0) {
845 unsigned char protobuf[4];
846 /*
847 * Don't reset huptimer for
848 * LCP packets. (Echo requests).
849 */
850 if (copy_from_user(protobuf, buf, 4))
851 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852
Meng Xu93eef212017-09-19 21:49:55 -0400853 proto = PPP_PROTOCOL(protobuf);
854 if (proto != PPP_LCP)
855 lp->huptimer = 0;
856
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 return 0;
Meng Xu93eef212017-09-19 21:49:55 -0400858 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859
860 if ((dev->drv[lp->isdn_device]->flags & DRV_FLAG_RUNNING) &&
Joe Perches475be4d2012-02-19 19:52:38 -0800861 lp->dialstate == 0 &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 (lp->flags & ISDN_NET_CONNECTED)) {
863 unsigned short hl;
864 struct sk_buff *skb;
Meng Xu93eef212017-09-19 21:49:55 -0400865 unsigned char *cpy_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 /*
André Goddard Rosaaf901ca2009-11-14 13:09:05 -0200867 * we need to reserve enough space in front of
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 * sk_buff. old call to dev_alloc_skb only reserved
869 * 16 bytes, now we are looking what the driver want
870 */
871 hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen;
Joe Perches475be4d2012-02-19 19:52:38 -0800872 skb = alloc_skb(hl + count, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 if (!skb) {
874 printk(KERN_WARNING "isdn_ppp_write: out of memory!\n");
875 return count;
876 }
877 skb_reserve(skb, hl);
Meng Xu93eef212017-09-19 21:49:55 -0400878 cpy_buf = skb_put(skb, count);
879 if (copy_from_user(cpy_buf, buf, count))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 {
881 kfree_skb(skb);
882 return -EFAULT;
883 }
Meng Xu93eef212017-09-19 21:49:55 -0400884
885 /*
886 * Don't reset huptimer for
887 * LCP packets. (Echo requests).
888 */
889 proto = PPP_PROTOCOL(cpy_buf);
890 if (proto != PPP_LCP)
891 lp->huptimer = 0;
892
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 if (is->debug & 0x40) {
894 printk(KERN_DEBUG "ppp xmit: len %d\n", (int) skb->len);
Joe Perches475be4d2012-02-19 19:52:38 -0800895 isdn_ppp_frame_log("xmit", skb->data, skb->len, 32, is->unit, lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 }
897
Joe Perches475be4d2012-02-19 19:52:38 -0800898 isdn_ppp_send_ccp(lp->netdev, lp, skb); /* keeps CCP/compression states in sync */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899
900 isdn_net_write_super(lp, skb);
901 }
902 }
903 return count;
904}
905
906/*
907 * init memory, structures etc.
908 */
909
910int
911isdn_ppp_init(void)
912{
913 int i,
Joe Perches475be4d2012-02-19 19:52:38 -0800914 j;
915
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916#ifdef CONFIG_ISDN_MPP
Joe Perches475be4d2012-02-19 19:52:38 -0800917 if (isdn_ppp_mp_bundle_array_init() < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 return -ENOMEM;
919#endif /* CONFIG_ISDN_MPP */
920
921 for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
Burman Yan41f96932006-12-08 02:39:35 -0800922 if (!(ippp_table[i] = kzalloc(sizeof(struct ippp_struct), GFP_KERNEL))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 printk(KERN_WARNING "isdn_ppp_init: Could not alloc ippp_table\n");
924 for (j = 0; j < i; j++)
925 kfree(ippp_table[j]);
926 return -1;
927 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928 spin_lock_init(&ippp_table[i]->buflock);
929 ippp_table[i]->state = 0;
930 ippp_table[i]->first = ippp_table[i]->rq + NUM_RCV_BUFFS - 1;
931 ippp_table[i]->last = ippp_table[i]->rq;
932
933 for (j = 0; j < NUM_RCV_BUFFS; j++) {
934 ippp_table[i]->rq[j].buf = NULL;
935 ippp_table[i]->rq[j].last = ippp_table[i]->rq +
Joe Perches475be4d2012-02-19 19:52:38 -0800936 (NUM_RCV_BUFFS + j - 1) % NUM_RCV_BUFFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937 ippp_table[i]->rq[j].next = ippp_table[i]->rq + (j + 1) % NUM_RCV_BUFFS;
938 }
939 }
940 return 0;
941}
942
943void
944isdn_ppp_cleanup(void)
945{
946 int i;
947
948 for (i = 0; i < ISDN_MAX_CHANNELS; i++)
949 kfree(ippp_table[i]);
950
951#ifdef CONFIG_ISDN_MPP
Jesper Juhl3c7208f2005-11-07 01:01:29 -0800952 kfree(isdn_ppp_bundle_arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953#endif /* CONFIG_ISDN_MPP */
954
955}
956
957/*
958 * check for address/control field and skip if allowed
959 * retval != 0 -> discard packet silently
960 */
Joe Perches475be4d2012-02-19 19:52:38 -0800961static int isdn_ppp_skip_ac(struct ippp_struct *is, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962{
963 if (skb->len < 1)
964 return -1;
965
966 if (skb->data[0] == 0xff) {
967 if (skb->len < 2)
968 return -1;
969
970 if (skb->data[1] != 0x03)
971 return -1;
972
973 // skip address/control (AC) field
974 skb_pull(skb, 2);
Joe Perches475be4d2012-02-19 19:52:38 -0800975 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 if (is->pppcfg & SC_REJ_COMP_AC)
977 // if AC compression was not negotiated, but used, discard packet
978 return -1;
979 }
980 return 0;
981}
982
983/*
984 * get the PPP protocol header and pull skb
985 * retval < 0 -> discard packet silently
986 */
Joe Perches475be4d2012-02-19 19:52:38 -0800987static int isdn_ppp_strip_proto(struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988{
989 int proto;
Joe Perches475be4d2012-02-19 19:52:38 -0800990
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 if (skb->len < 1)
992 return -1;
993
994 if (skb->data[0] & 0x1) {
995 // protocol field is compressed
996 proto = skb->data[0];
997 skb_pull(skb, 1);
998 } else {
999 if (skb->len < 2)
1000 return -1;
1001 proto = ((int) skb->data[0] << 8) + skb->data[1];
1002 skb_pull(skb, 2);
1003 }
1004 return proto;
1005}
1006
1007
1008/*
1009 * handler for incoming packets on a syncPPP interface
1010 */
Joe Perches475be4d2012-02-19 19:52:38 -08001011void isdn_ppp_receive(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012{
1013 struct ippp_struct *is;
1014 int slot;
1015 int proto;
1016
Eric Sesterhenn6dd44a72006-03-26 18:19:26 +02001017 BUG_ON(net_dev->local->master); // we're called with the master device always
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018
1019 slot = lp->ppp_slot;
1020 if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
1021 printk(KERN_ERR "isdn_ppp_receive: lp->ppp_slot(%d)\n",
Joe Perches475be4d2012-02-19 19:52:38 -08001022 lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023 kfree_skb(skb);
1024 return;
1025 }
1026 is = ippp_table[slot];
1027
1028 if (is->debug & 0x4) {
1029 printk(KERN_DEBUG "ippp_receive: is:%08lx lp:%08lx slot:%d unit:%d len:%d\n",
Joe Perches475be4d2012-02-19 19:52:38 -08001030 (long)is, (long)lp, lp->ppp_slot, is->unit, (int)skb->len);
1031 isdn_ppp_frame_log("receive", skb->data, skb->len, 32, is->unit, lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 }
1033
Joe Perches475be4d2012-02-19 19:52:38 -08001034 if (isdn_ppp_skip_ac(is, skb) < 0) {
1035 kfree_skb(skb);
1036 return;
1037 }
1038 proto = isdn_ppp_strip_proto(skb);
1039 if (proto < 0) {
1040 kfree_skb(skb);
1041 return;
1042 }
1043
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044#ifdef CONFIG_ISDN_MPP
Joe Perches475be4d2012-02-19 19:52:38 -08001045 if (is->compflags & SC_LINK_DECOMP_ON) {
1046 skb = isdn_ppp_decompress(skb, is, NULL, &proto);
1047 if (!skb) // decompression error
1048 return;
1049 }
1050
1051 if (!(is->mpppcfg & SC_REJ_MP_PROT)) { // we agreed to receive MPPP
1052 if (proto == PPP_MP) {
1053 isdn_ppp_mp_receive(net_dev, lp, skb);
1054 return;
1055 }
1056 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057#endif
Joe Perches475be4d2012-02-19 19:52:38 -08001058 isdn_ppp_push_higher(net_dev, lp, skb, proto);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059}
1060
1061/*
1062 * we receive a reassembled frame, MPPP has been taken care of before.
1063 * address/control and protocol have been stripped from the skb
1064 * note: net_dev has to be master net_dev
1065 */
1066static void
Joe Perches475be4d2012-02-19 19:52:38 -08001067isdn_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 -07001068{
Karsten Keild62a38d2007-10-08 20:37:11 -07001069 struct net_device *dev = net_dev->dev;
Joe Perches475be4d2012-02-19 19:52:38 -08001070 struct ippp_struct *is, *mis;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 isdn_net_local *mlp = NULL;
1072 int slot;
1073
1074 slot = lp->ppp_slot;
1075 if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
1076 printk(KERN_ERR "isdn_ppp_push_higher: lp->ppp_slot(%d)\n",
Joe Perches475be4d2012-02-19 19:52:38 -08001077 lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 goto drop_packet;
1079 }
1080 is = ippp_table[slot];
Joe Perches475be4d2012-02-19 19:52:38 -08001081
1082 if (lp->master) { // FIXME?
Wang Chen838361f2008-12-03 15:49:46 -08001083 mlp = ISDN_MASTER_PRIV(lp);
Joe Perches475be4d2012-02-19 19:52:38 -08001084 slot = mlp->ppp_slot;
1085 if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
1086 printk(KERN_ERR "isdn_ppp_push_higher: master->ppp_slot(%d)\n",
1087 lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 goto drop_packet;
Joe Perches475be4d2012-02-19 19:52:38 -08001089 }
1090 }
1091 mis = ippp_table[slot];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092
1093 if (is->debug & 0x10) {
1094 printk(KERN_DEBUG "push, skb %d %04x\n", (int) skb->len, proto);
Joe Perches475be4d2012-02-19 19:52:38 -08001095 isdn_ppp_frame_log("rpush", skb->data, skb->len, 32, is->unit, lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 }
1097 if (mis->compflags & SC_DECOMP_ON) {
1098 skb = isdn_ppp_decompress(skb, is, mis, &proto);
1099 if (!skb) // decompression error
Joe Perches475be4d2012-02-19 19:52:38 -08001100 return;
1101 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 switch (proto) {
Joe Perches475be4d2012-02-19 19:52:38 -08001103 case PPP_IPX: /* untested */
1104 if (is->debug & 0x20)
1105 printk(KERN_DEBUG "isdn_ppp: IPX\n");
1106 skb->protocol = htons(ETH_P_IPX);
1107 break;
1108 case PPP_IP:
1109 if (is->debug & 0x20)
1110 printk(KERN_DEBUG "isdn_ppp: IP\n");
1111 skb->protocol = htons(ETH_P_IP);
1112 break;
1113 case PPP_COMP:
1114 case PPP_COMPFRAG:
1115 printk(KERN_INFO "isdn_ppp: unexpected compressed frame dropped\n");
1116 goto drop_packet;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117#ifdef CONFIG_ISDN_PPP_VJ
Joe Perches475be4d2012-02-19 19:52:38 -08001118 case PPP_VJC_UNCOMP:
1119 if (is->debug & 0x20)
1120 printk(KERN_DEBUG "isdn_ppp: VJC_UNCOMP\n");
1121 if (net_dev->local->ppp_slot < 0) {
1122 printk(KERN_ERR "%s: net_dev->local->ppp_slot(%d) out of range\n",
1123 __func__, net_dev->local->ppp_slot);
1124 goto drop_packet;
1125 }
1126 if (slhc_remember(ippp_table[net_dev->local->ppp_slot]->slcomp, skb->data, skb->len) <= 0) {
1127 printk(KERN_WARNING "isdn_ppp: received illegal VJC_UNCOMP frame!\n");
1128 goto drop_packet;
1129 }
1130 skb->protocol = htons(ETH_P_IP);
1131 break;
1132 case PPP_VJC_COMP:
1133 if (is->debug & 0x20)
1134 printk(KERN_DEBUG "isdn_ppp: VJC_COMP\n");
1135 {
1136 struct sk_buff *skb_old = skb;
1137 int pkt_len;
1138 skb = dev_alloc_skb(skb_old->len + 128);
1139
1140 if (!skb) {
1141 printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
1142 skb = skb_old;
1143 goto drop_packet;
1144 }
1145 skb_put(skb, skb_old->len + 128);
1146 skb_copy_from_linear_data(skb_old, skb->data,
1147 skb_old->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 if (net_dev->local->ppp_slot < 0) {
1149 printk(KERN_ERR "%s: net_dev->local->ppp_slot(%d) out of range\n",
Joe Perches475be4d2012-02-19 19:52:38 -08001150 __func__, net_dev->local->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 goto drop_packet;
1152 }
Joe Perches475be4d2012-02-19 19:52:38 -08001153 pkt_len = slhc_uncompress(ippp_table[net_dev->local->ppp_slot]->slcomp,
1154 skb->data, skb_old->len);
1155 kfree_skb(skb_old);
1156 if (pkt_len < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157 goto drop_packet;
Joe Perches475be4d2012-02-19 19:52:38 -08001158
1159 skb_trim(skb, pkt_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 skb->protocol = htons(ETH_P_IP);
Joe Perches475be4d2012-02-19 19:52:38 -08001161 }
1162 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163#endif
Joe Perches475be4d2012-02-19 19:52:38 -08001164 case PPP_CCP:
1165 case PPP_CCPFRAG:
1166 isdn_ppp_receive_ccp(net_dev, lp, skb, proto);
1167 /* Dont pop up ResetReq/Ack stuff to the daemon any
1168 longer - the job is done already */
1169 if (skb->data[0] == CCP_RESETREQ ||
1170 skb->data[0] == CCP_RESETACK)
1171 break;
1172 /* fall through */
1173 default:
1174 isdn_ppp_fill_rq(skb->data, skb->len, proto, lp->ppp_slot); /* push data to pppd device */
1175 kfree_skb(skb);
1176 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177 }
1178
1179#ifdef CONFIG_IPPP_FILTER
1180 /* check if the packet passes the pass and active filters
1181 * the filter instructions are constructed assuming
1182 * a four-byte PPP header on each packet (which is still present) */
1183 skb_push(skb, 4);
1184
1185 {
1186 u_int16_t *p = (u_int16_t *) skb->data;
1187
Karsten Keild8470b72005-04-21 08:30:30 -07001188 *p = 0; /* indicate inbound */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189 }
1190
1191 if (is->pass_filter
Alexei Starovoitov7ae457c2014-07-30 20:34:16 -07001192 && BPF_PROG_RUN(is->pass_filter, skb) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193 if (is->debug & 0x2)
1194 printk(KERN_DEBUG "IPPP: inbound frame filtered.\n");
1195 kfree_skb(skb);
1196 return;
1197 }
1198 if (!(is->active_filter
Alexei Starovoitov7ae457c2014-07-30 20:34:16 -07001199 && BPF_PROG_RUN(is->active_filter, skb) == 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200 if (is->debug & 0x2)
Masanari Iidaee556fe2012-02-11 01:49:28 +00001201 printk(KERN_DEBUG "IPPP: link-active filter: resetting huptimer.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202 lp->huptimer = 0;
1203 if (mlp)
1204 mlp->huptimer = 0;
1205 }
1206 skb_pull(skb, 4);
1207#else /* CONFIG_IPPP_FILTER */
1208 lp->huptimer = 0;
1209 if (mlp)
1210 mlp->huptimer = 0;
1211#endif /* CONFIG_IPPP_FILTER */
1212 skb->dev = dev;
Arnaldo Carvalho de Melo459a98e2007-03-19 15:30:44 -07001213 skb_reset_mac_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214 netif_rx(skb);
1215 /* net_dev->local->stats.rx_packets++; done in isdn_net.c */
1216 return;
1217
Joe Perches475be4d2012-02-19 19:52:38 -08001218drop_packet:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219 net_dev->local->stats.rx_dropped++;
1220 kfree_skb(skb);
1221}
1222
1223/*
1224 * isdn_ppp_skb_push ..
1225 * checks whether we have enough space at the beginning of the skb
1226 * and allocs a new SKB if necessary
1227 */
Joe Perches475be4d2012-02-19 19:52:38 -08001228static unsigned char *isdn_ppp_skb_push(struct sk_buff **skb_p, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229{
1230 struct sk_buff *skb = *skb_p;
1231
Joe Perches475be4d2012-02-19 19:52:38 -08001232 if (skb_headroom(skb) < len) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233 struct sk_buff *nskb = skb_realloc_headroom(skb, len);
1234
1235 if (!nskb) {
1236 printk(KERN_ERR "isdn_ppp_skb_push: can't realloc headroom!\n");
1237 dev_kfree_skb(skb);
1238 return NULL;
1239 }
Joe Perches475be4d2012-02-19 19:52:38 -08001240 printk(KERN_DEBUG "isdn_ppp_skb_push:under %d %d\n", skb_headroom(skb), len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 dev_kfree_skb(skb);
1242 *skb_p = nskb;
1243 return skb_push(nskb, len);
1244 }
Joe Perches475be4d2012-02-19 19:52:38 -08001245 return skb_push(skb, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246}
1247
1248/*
1249 * send ppp frame .. we expect a PIDCOMPressable proto --
1250 * (here: currently always PPP_IP,PPP_VJC_COMP,PPP_VJC_UNCOMP)
1251 *
1252 * VJ compression may change skb pointer!!! .. requeue with old
1253 * skb isn't allowed!!
1254 */
1255
1256int
1257isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev)
1258{
Joe Perches475be4d2012-02-19 19:52:38 -08001259 isdn_net_local *lp, *mlp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260 isdn_net_dev *nd;
1261 unsigned int proto = PPP_IP; /* 0x21 */
Joe Perches475be4d2012-02-19 19:52:38 -08001262 struct ippp_struct *ipt, *ipts;
Patrick McHardyec634fe2009-07-05 19:23:38 -07001263 int slot, retval = NETDEV_TX_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264
Joe Perchesa17531f2010-11-15 11:12:24 +00001265 mlp = netdev_priv(netdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266 nd = mlp->netdev; /* get master lp */
1267
1268 slot = mlp->ppp_slot;
1269 if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
1270 printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot(%d)\n",
Joe Perches475be4d2012-02-19 19:52:38 -08001271 mlp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272 kfree_skb(skb);
1273 goto out;
1274 }
1275 ipts = ippp_table[slot];
1276
1277 if (!(ipts->pppcfg & SC_ENABLE_IP)) { /* PPP connected ? */
1278 if (ipts->debug & 0x1)
1279 printk(KERN_INFO "%s: IP frame delayed.\n", netdev->name);
Patrick McHardyec634fe2009-07-05 19:23:38 -07001280 retval = NETDEV_TX_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281 goto out;
1282 }
1283
1284 switch (ntohs(skb->protocol)) {
Joe Perches475be4d2012-02-19 19:52:38 -08001285 case ETH_P_IP:
1286 proto = PPP_IP;
1287 break;
1288 case ETH_P_IPX:
1289 proto = PPP_IPX; /* untested */
1290 break;
1291 default:
1292 printk(KERN_ERR "isdn_ppp: skipped unsupported protocol: %#x.\n",
1293 skb->protocol);
1294 dev_kfree_skb(skb);
1295 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296 }
1297
1298 lp = isdn_net_get_locked_lp(nd);
1299 if (!lp) {
1300 printk(KERN_WARNING "%s: all channels busy - requeuing!\n", netdev->name);
Patrick McHardyec634fe2009-07-05 19:23:38 -07001301 retval = NETDEV_TX_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 goto out;
1303 }
1304 /* we have our lp locked from now on */
1305
1306 slot = lp->ppp_slot;
Eric Sesterhenn052bb882006-04-11 17:29:17 -07001307 if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot(%d)\n",
Joe Perches475be4d2012-02-19 19:52:38 -08001309 lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310 kfree_skb(skb);
1311 goto unlock;
1312 }
1313 ipt = ippp_table[slot];
1314
1315 /*
1316 * after this line .. requeueing in the device queue is no longer allowed!!!
1317 */
1318
1319 /* Pull off the fake header we stuck on earlier to keep
1320 * the fragmentation code happy.
1321 */
Joe Perches475be4d2012-02-19 19:52:38 -08001322 skb_pull(skb, IPPP_MAX_HEADER);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323
1324#ifdef CONFIG_IPPP_FILTER
1325 /* check if we should pass this packet
1326 * the filter instructions are constructed assuming
1327 * a four-byte PPP header on each packet */
Karsten Keild8470b72005-04-21 08:30:30 -07001328 *skb_push(skb, 4) = 1; /* indicate outbound */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329
1330 {
Harvey Harrisonc19d0362008-11-20 04:10:51 -08001331 __be16 *p = (__be16 *)skb->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332
Karsten Keild8470b72005-04-21 08:30:30 -07001333 p++;
Harvey Harrisonc19d0362008-11-20 04:10:51 -08001334 *p = htons(proto);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335 }
1336
1337 if (ipt->pass_filter
Alexei Starovoitov7ae457c2014-07-30 20:34:16 -07001338 && BPF_PROG_RUN(ipt->pass_filter, skb) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339 if (ipt->debug & 0x4)
1340 printk(KERN_DEBUG "IPPP: outbound frame filtered.\n");
1341 kfree_skb(skb);
1342 goto unlock;
1343 }
1344 if (!(ipt->active_filter
Alexei Starovoitov7ae457c2014-07-30 20:34:16 -07001345 && BPF_PROG_RUN(ipt->active_filter, skb) == 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346 if (ipt->debug & 0x4)
Masanari Iidaee556fe2012-02-11 01:49:28 +00001347 printk(KERN_DEBUG "IPPP: link-active filter: resetting huptimer.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348 lp->huptimer = 0;
1349 }
1350 skb_pull(skb, 4);
1351#else /* CONFIG_IPPP_FILTER */
1352 lp->huptimer = 0;
1353#endif /* CONFIG_IPPP_FILTER */
1354
1355 if (ipt->debug & 0x4)
1356 printk(KERN_DEBUG "xmit skb, len %d\n", (int) skb->len);
Joe Perches475be4d2012-02-19 19:52:38 -08001357 if (ipts->debug & 0x40)
1358 isdn_ppp_frame_log("xmit0", skb->data, skb->len, 32, ipts->unit, lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359
1360#ifdef CONFIG_ISDN_PPP_VJ
1361 if (proto == PPP_IP && ipts->pppcfg & SC_COMP_TCP) { /* ipts here? probably yes, but check this again */
1362 struct sk_buff *new_skb;
Joe Perches475be4d2012-02-19 19:52:38 -08001363 unsigned short hl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364 /*
André Goddard Rosaaf901ca2009-11-14 13:09:05 -02001365 * we need to reserve enough space in front of
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366 * sk_buff. old call to dev_alloc_skb only reserved
1367 * 16 bytes, now we are looking what the driver want.
1368 */
1369 hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen + IPPP_MAX_HEADER;
Joe Perches475be4d2012-02-19 19:52:38 -08001370 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 * Note: hl might still be insufficient because the method
1372 * above does not account for a possibible MPPP slave channel
1373 * which had larger HL header space requirements than the
1374 * master.
1375 */
Joe Perches475be4d2012-02-19 19:52:38 -08001376 new_skb = alloc_skb(hl + skb->len, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377 if (new_skb) {
1378 u_char *buf;
1379 int pktlen;
1380
1381 skb_reserve(new_skb, hl);
1382 new_skb->dev = skb->dev;
1383 skb_put(new_skb, skb->len);
1384 buf = skb->data;
1385
1386 pktlen = slhc_compress(ipts->slcomp, skb->data, skb->len, new_skb->data,
Joe Perches475be4d2012-02-19 19:52:38 -08001387 &buf, !(ipts->pppcfg & SC_NO_TCP_CCID));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388
Joe Perches475be4d2012-02-19 19:52:38 -08001389 if (buf != skb->data) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390 if (new_skb->data != buf)
1391 printk(KERN_ERR "isdn_ppp: FATAL error after slhc_compress!!\n");
1392 dev_kfree_skb(skb);
1393 skb = new_skb;
1394 } else {
1395 dev_kfree_skb(new_skb);
1396 }
1397
1398 skb_trim(skb, pktlen);
1399 if (skb->data[0] & SL_TYPE_COMPRESSED_TCP) { /* cslip? style -> PPP */
1400 proto = PPP_VJC_COMP;
1401 skb->data[0] ^= SL_TYPE_COMPRESSED_TCP;
1402 } else {
1403 if (skb->data[0] >= SL_TYPE_UNCOMPRESSED_TCP)
1404 proto = PPP_VJC_UNCOMP;
1405 skb->data[0] = (skb->data[0] & 0x0f) | 0x40;
1406 }
1407 }
1408 }
1409#endif
1410
1411 /*
1412 * normal (single link) or bundle compression
1413 */
Joe Perches475be4d2012-02-19 19:52:38 -08001414 if (ipts->compflags & SC_COMP_ON) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415 /* We send compressed only if both down- und upstream
1416 compression is negotiated, that means, CCP is up */
Joe Perches475be4d2012-02-19 19:52:38 -08001417 if (ipts->compflags & SC_DECOMP_ON) {
1418 skb = isdn_ppp_compress(skb, &proto, ipt, ipts, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419 } else {
1420 printk(KERN_DEBUG "isdn_ppp: CCP not yet up - sending as-is\n");
1421 }
1422 }
1423
1424 if (ipt->debug & 0x24)
1425 printk(KERN_DEBUG "xmit2 skb, len %d, proto %04x\n", (int) skb->len, proto);
1426
1427#ifdef CONFIG_ISDN_MPP
1428 if (ipt->mpppcfg & SC_MP_PROT) {
1429 /* we get mp_seqno from static isdn_net_local */
1430 long mp_seqno = ipts->mp_seqno;
1431 ipts->mp_seqno++;
1432 if (ipt->mpppcfg & SC_OUT_SHORT_SEQ) {
1433 unsigned char *data = isdn_ppp_skb_push(&skb, 3);
Joe Perches475be4d2012-02-19 19:52:38 -08001434 if (!data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435 goto unlock;
1436 mp_seqno &= 0xfff;
1437 data[0] = MP_BEGIN_FRAG | MP_END_FRAG | ((mp_seqno >> 8) & 0xf); /* (B)egin & (E)ndbit .. */
1438 data[1] = mp_seqno & 0xff;
1439 data[2] = proto; /* PID compression */
1440 } else {
1441 unsigned char *data = isdn_ppp_skb_push(&skb, 5);
Joe Perches475be4d2012-02-19 19:52:38 -08001442 if (!data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443 goto unlock;
1444 data[0] = MP_BEGIN_FRAG | MP_END_FRAG; /* (B)egin & (E)ndbit .. */
1445 data[1] = (mp_seqno >> 16) & 0xff; /* sequence number: 24bit */
1446 data[2] = (mp_seqno >> 8) & 0xff;
1447 data[3] = (mp_seqno >> 0) & 0xff;
1448 data[4] = proto; /* PID compression */
1449 }
1450 proto = PPP_MP; /* MP Protocol, 0x003d */
1451 }
1452#endif
1453
1454 /*
1455 * 'link in bundle' compression ...
1456 */
Joe Perches475be4d2012-02-19 19:52:38 -08001457 if (ipt->compflags & SC_LINK_COMP_ON)
1458 skb = isdn_ppp_compress(skb, &proto, ipt, ipts, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459
Joe Perches475be4d2012-02-19 19:52:38 -08001460 if ((ipt->pppcfg & SC_COMP_PROT) && (proto <= 0xff)) {
1461 unsigned char *data = isdn_ppp_skb_push(&skb, 1);
1462 if (!data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463 goto unlock;
1464 data[0] = proto & 0xff;
1465 }
1466 else {
Joe Perches475be4d2012-02-19 19:52:38 -08001467 unsigned char *data = isdn_ppp_skb_push(&skb, 2);
1468 if (!data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469 goto unlock;
1470 data[0] = (proto >> 8) & 0xff;
1471 data[1] = proto & 0xff;
1472 }
Joe Perches475be4d2012-02-19 19:52:38 -08001473 if (!(ipt->pppcfg & SC_COMP_AC)) {
1474 unsigned char *data = isdn_ppp_skb_push(&skb, 2);
1475 if (!data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 goto unlock;
1477 data[0] = 0xff; /* All Stations */
1478 data[1] = 0x03; /* Unnumbered information */
1479 }
1480
1481 /* tx-stats are now updated via BSENT-callback */
1482
1483 if (ipts->debug & 0x40) {
1484 printk(KERN_DEBUG "skb xmit: len: %d\n", (int) skb->len);
Joe Perches475be4d2012-02-19 19:52:38 -08001485 isdn_ppp_frame_log("xmit", skb->data, skb->len, 32, ipt->unit, lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486 }
Joe Perches475be4d2012-02-19 19:52:38 -08001487
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488 isdn_net_writebuf_skb(lp, skb);
1489
Joe Perches475be4d2012-02-19 19:52:38 -08001490unlock:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491 spin_unlock_bh(&lp->xmit_lock);
Joe Perches475be4d2012-02-19 19:52:38 -08001492out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493 return retval;
1494}
1495
1496#ifdef CONFIG_IPPP_FILTER
1497/*
1498 * check if this packet may trigger auto-dial.
1499 */
1500
1501int isdn_ppp_autodial_filter(struct sk_buff *skb, isdn_net_local *lp)
1502{
1503 struct ippp_struct *is = ippp_table[lp->ppp_slot];
1504 u_int16_t proto;
1505 int drop = 0;
1506
1507 switch (ntohs(skb->protocol)) {
1508 case ETH_P_IP:
1509 proto = PPP_IP;
1510 break;
1511 case ETH_P_IPX:
1512 proto = PPP_IPX;
1513 break;
1514 default:
1515 printk(KERN_ERR "isdn_ppp_autodial_filter: unsupported protocol 0x%x.\n",
1516 skb->protocol);
1517 return 1;
1518 }
1519
1520 /* the filter instructions are constructed assuming
1521 * a four-byte PPP header on each packet. we have to
1522 * temporarily remove part of the fake header stuck on
1523 * earlier.
1524 */
Karsten Keild8470b72005-04-21 08:30:30 -07001525 *skb_pull(skb, IPPP_MAX_HEADER - 4) = 1; /* indicate outbound */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526
1527 {
Harvey Harrisonc19d0362008-11-20 04:10:51 -08001528 __be16 *p = (__be16 *)skb->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529
Karsten Keild8470b72005-04-21 08:30:30 -07001530 p++;
Harvey Harrisonc19d0362008-11-20 04:10:51 -08001531 *p = htons(proto);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 }
Joe Perches475be4d2012-02-19 19:52:38 -08001533
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534 drop |= is->pass_filter
Alexei Starovoitov7ae457c2014-07-30 20:34:16 -07001535 && BPF_PROG_RUN(is->pass_filter, skb) == 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 drop |= is->active_filter
Alexei Starovoitov7ae457c2014-07-30 20:34:16 -07001537 && BPF_PROG_RUN(is->active_filter, skb) == 0;
Joe Perches475be4d2012-02-19 19:52:38 -08001538
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 skb_push(skb, IPPP_MAX_HEADER - 4);
1540 return drop;
1541}
1542#endif
1543#ifdef CONFIG_ISDN_MPP
1544
1545/* this is _not_ rfc1990 header, but something we convert both short and long
1546 * headers to for convinience's sake:
Joe Perches475be4d2012-02-19 19:52:38 -08001547 * byte 0 is flags as in rfc1990
1548 * bytes 1...4 is 24-bit seqence number converted to host byte order
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 */
1550#define MP_HEADER_LEN 5
1551
1552#define MP_LONGSEQ_MASK 0x00ffffff
1553#define MP_SHORTSEQ_MASK 0x00000fff
1554#define MP_LONGSEQ_MAX MP_LONGSEQ_MASK
1555#define MP_SHORTSEQ_MAX MP_SHORTSEQ_MASK
Joe Perches475be4d2012-02-19 19:52:38 -08001556#define MP_LONGSEQ_MAXBIT ((MP_LONGSEQ_MASK + 1) >> 1)
1557#define MP_SHORTSEQ_MAXBIT ((MP_SHORTSEQ_MASK + 1) >> 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558
Lucas De Marchi25985ed2011-03-30 22:57:33 -03001559/* sequence-wrap safe comparisons (for long sequence)*/
Joe Perches475be4d2012-02-19 19:52:38 -08001560#define MP_LT(a, b) ((a - b) & MP_LONGSEQ_MAXBIT)
1561#define MP_LE(a, b) !((b - a) & MP_LONGSEQ_MAXBIT)
1562#define MP_GT(a, b) ((b - a) & MP_LONGSEQ_MAXBIT)
1563#define MP_GE(a, b) !((a - b) & MP_LONGSEQ_MAXBIT)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564
Joe Perches475be4d2012-02-19 19:52:38 -08001565#define MP_SEQ(f) ((*(u32 *)(f->data + 1)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566#define MP_FLAGS(f) (f->data[0])
1567
1568static int isdn_ppp_mp_bundle_array_init(void)
1569{
1570 int i;
Joe Perches475be4d2012-02-19 19:52:38 -08001571 int sz = ISDN_MAX_CHANNELS * sizeof(ippp_bundle);
1572 if ((isdn_ppp_bundle_arr = kzalloc(sz, GFP_KERNEL)) == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 return -ENOMEM;
Joe Perches475be4d2012-02-19 19:52:38 -08001574 for (i = 0; i < ISDN_MAX_CHANNELS; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575 spin_lock_init(&isdn_ppp_bundle_arr[i].lock);
1576 return 0;
1577}
1578
Joe Perches475be4d2012-02-19 19:52:38 -08001579static ippp_bundle *isdn_ppp_mp_bundle_alloc(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580{
1581 int i;
Joe Perches475be4d2012-02-19 19:52:38 -08001582 for (i = 0; i < ISDN_MAX_CHANNELS; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583 if (isdn_ppp_bundle_arr[i].ref_ct <= 0)
1584 return (isdn_ppp_bundle_arr + i);
1585 return NULL;
1586}
1587
Joe Perches475be4d2012-02-19 19:52:38 -08001588static int isdn_ppp_mp_init(isdn_net_local *lp, ippp_bundle *add_to)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589{
Joe Perches475be4d2012-02-19 19:52:38 -08001590 struct ippp_struct *is;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591
1592 if (lp->ppp_slot < 0) {
1593 printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
Joe Perches475be4d2012-02-19 19:52:38 -08001594 __func__, lp->ppp_slot);
1595 return (-EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596 }
1597
1598 is = ippp_table[lp->ppp_slot];
1599 if (add_to) {
Joe Perches475be4d2012-02-19 19:52:38 -08001600 if (lp->netdev->pb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601 lp->netdev->pb->ref_ct--;
1602 lp->netdev->pb = add_to;
1603 } else { /* first link in a bundle */
1604 is->mp_seqno = 0;
1605 if ((lp->netdev->pb = isdn_ppp_mp_bundle_alloc()) == NULL)
1606 return -ENOMEM;
1607 lp->next = lp->last = lp; /* nobody else in a queue */
David S. Millere29d4362009-11-15 22:23:47 -08001608 lp->netdev->pb->frags = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609 lp->netdev->pb->frames = 0;
1610 lp->netdev->pb->seq = UINT_MAX;
1611 }
1612 lp->netdev->pb->ref_ct++;
Joe Perches475be4d2012-02-19 19:52:38 -08001613
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614 is->last_link_seqno = 0;
1615 return 0;
1616}
1617
Joe Perches475be4d2012-02-19 19:52:38 -08001618static u32 isdn_ppp_mp_get_seq(int short_seq,
1619 struct sk_buff *skb, u32 last_seq);
1620static struct sk_buff *isdn_ppp_mp_discard(ippp_bundle *mp,
1621 struct sk_buff *from, struct sk_buff *to);
1622static void isdn_ppp_mp_reassembly(isdn_net_dev *net_dev, isdn_net_local *lp,
1623 struct sk_buff *from, struct sk_buff *to);
1624static void isdn_ppp_mp_free_skb(ippp_bundle *mp, struct sk_buff *skb);
1625static void isdn_ppp_mp_print_recv_pkt(int slot, struct sk_buff *skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626
Joe Perches475be4d2012-02-19 19:52:38 -08001627static void isdn_ppp_mp_receive(isdn_net_dev *net_dev, isdn_net_local *lp,
1628 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629{
David S. Miller38783e62008-09-22 01:15:02 -07001630 struct ippp_struct *is;
Joe Perches475be4d2012-02-19 19:52:38 -08001631 isdn_net_local *lpq;
1632 ippp_bundle *mp;
1633 isdn_mppp_stats *stats;
1634 struct sk_buff *newfrag, *frag, *start, *nextf;
David S. Millere29d4362009-11-15 22:23:47 -08001635 u32 newseq, minseq, thisseq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636 unsigned long flags;
1637 int slot;
1638
1639 spin_lock_irqsave(&net_dev->pb->lock, flags);
Joe Perches475be4d2012-02-19 19:52:38 -08001640 mp = net_dev->pb;
1641 stats = &mp->stats;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642 slot = lp->ppp_slot;
Eric Sesterhenn052bb882006-04-11 17:29:17 -07001643 if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644 printk(KERN_ERR "%s: lp->ppp_slot(%d)\n",
Joe Perches475be4d2012-02-19 19:52:38 -08001645 __func__, lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646 stats->frame_drops++;
1647 dev_kfree_skb(skb);
1648 spin_unlock_irqrestore(&mp->lock, flags);
1649 return;
1650 }
1651 is = ippp_table[slot];
Joe Perches475be4d2012-02-19 19:52:38 -08001652 if (++mp->frames > stats->max_queue_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653 stats->max_queue_len = mp->frames;
Joe Perches475be4d2012-02-19 19:52:38 -08001654
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655 if (is->debug & 0x8)
1656 isdn_ppp_mp_print_recv_pkt(lp->ppp_slot, skb);
1657
Joe Perches475be4d2012-02-19 19:52:38 -08001658 newseq = isdn_ppp_mp_get_seq(is->mpppcfg & SC_IN_SHORT_SEQ,
1659 skb, is->last_link_seqno);
David S. Millere29d4362009-11-15 22:23:47 -08001660
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661
1662 /* if this packet seq # is less than last already processed one,
Joe Perches475be4d2012-02-19 19:52:38 -08001663 * toss it right away, but check for sequence start case first
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664 */
Joe Perches475be4d2012-02-19 19:52:38 -08001665 if (mp->seq > MP_LONGSEQ_MAX && (newseq & MP_LONGSEQ_MAXBIT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666 mp->seq = newseq; /* the first packet: required for
1667 * rfc1990 non-compliant clients --
1668 * prevents constant packet toss */
Joe Perches475be4d2012-02-19 19:52:38 -08001669 } else if (MP_LT(newseq, mp->seq)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670 stats->frame_drops++;
1671 isdn_ppp_mp_free_skb(mp, skb);
1672 spin_unlock_irqrestore(&mp->lock, flags);
1673 return;
1674 }
Joe Perches475be4d2012-02-19 19:52:38 -08001675
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676 /* find the minimum received sequence number over all links */
1677 is->last_link_seqno = minseq = newseq;
1678 for (lpq = net_dev->queue;;) {
1679 slot = lpq->ppp_slot;
Eric Sesterhenn052bb882006-04-11 17:29:17 -07001680 if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681 printk(KERN_ERR "%s: lpq->ppp_slot(%d)\n",
Joe Perches475be4d2012-02-19 19:52:38 -08001682 __func__, lpq->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683 } else {
1684 u32 lls = ippp_table[slot]->last_link_seqno;
1685 if (MP_LT(lls, minseq))
1686 minseq = lls;
1687 }
1688 if ((lpq = lpq->next) == net_dev->queue)
1689 break;
1690 }
1691 if (MP_LT(minseq, mp->seq))
1692 minseq = mp->seq; /* can't go beyond already processed
1693 * packets */
1694 newfrag = skb;
1695
Joe Perches475be4d2012-02-19 19:52:38 -08001696 /* if this new fragment is before the first one, then enqueue it now. */
1697 if ((frag = mp->frags) == NULL || MP_LT(newseq, MP_SEQ(frag))) {
David S. Millere29d4362009-11-15 22:23:47 -08001698 newfrag->next = frag;
Joe Perches475be4d2012-02-19 19:52:38 -08001699 mp->frags = frag = newfrag;
1700 newfrag = NULL;
1701 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702
Joe Perches475be4d2012-02-19 19:52:38 -08001703 start = MP_FLAGS(frag) & MP_BEGIN_FRAG &&
1704 MP_SEQ(frag) == mp->seq ? frag : NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705
Joe Perches475be4d2012-02-19 19:52:38 -08001706 /*
David S. Millere29d4362009-11-15 22:23:47 -08001707 * main fragment traversing loop
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708 *
1709 * try to accomplish several tasks:
David S. Millere29d4362009-11-15 22:23:47 -08001710 * - insert new fragment into the proper sequence slot (once that's done
1711 * newfrag will be set to NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712 * - reassemble any complete fragment sequence (non-null 'start'
André Goddard Rosaaf901ca2009-11-14 13:09:05 -02001713 * indicates there is a contiguous sequence present)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714 * - discard any incomplete sequences that are below minseq -- due
1715 * to the fact that sender always increment sequence number, if there
1716 * is an incomplete sequence below minseq, no new fragments would
1717 * come to complete such sequence and it should be discarded
1718 *
1719 * loop completes when we accomplished the following tasks:
Joe Perches475be4d2012-02-19 19:52:38 -08001720 * - new fragment is inserted in the proper sequence ('newfrag' is
David S. Millere29d4362009-11-15 22:23:47 -08001721 * set to NULL)
Joe Perches475be4d2012-02-19 19:52:38 -08001722 * - we hit a gap in the sequence, so no reassembly/processing is
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 * possible ('start' would be set to NULL)
1724 *
Robert P. J. Dayd08df602007-02-17 19:07:33 +01001725 * algorithm for this code is derived from code in the book
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726 * 'PPP Design And Debugging' by James Carlson (Addison-Wesley)
1727 */
Joe Perches475be4d2012-02-19 19:52:38 -08001728 while (start != NULL || newfrag != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729
Joe Perches475be4d2012-02-19 19:52:38 -08001730 thisseq = MP_SEQ(frag);
1731 nextf = frag->next;
David S. Millere29d4362009-11-15 22:23:47 -08001732
Joe Perches475be4d2012-02-19 19:52:38 -08001733 /* drop any duplicate fragments */
1734 if (newfrag != NULL && thisseq == newseq) {
1735 isdn_ppp_mp_free_skb(mp, newfrag);
1736 newfrag = NULL;
1737 }
David S. Millere29d4362009-11-15 22:23:47 -08001738
Joe Perches475be4d2012-02-19 19:52:38 -08001739 /* insert new fragment before next element if possible. */
1740 if (newfrag != NULL && (nextf == NULL ||
1741 MP_LT(newseq, MP_SEQ(nextf)))) {
1742 newfrag->next = nextf;
1743 frag->next = nextf = newfrag;
1744 newfrag = NULL;
1745 }
David S. Millere29d4362009-11-15 22:23:47 -08001746
Joe Perches475be4d2012-02-19 19:52:38 -08001747 if (start != NULL) {
1748 /* check for misplaced start */
1749 if (start != frag && (MP_FLAGS(frag) & MP_BEGIN_FRAG)) {
David S. Millere29d4362009-11-15 22:23:47 -08001750 printk(KERN_WARNING"isdn_mppp(seq %d): new "
Joe Perches475be4d2012-02-19 19:52:38 -08001751 "BEGIN flag with no prior END", thisseq);
David S. Millere29d4362009-11-15 22:23:47 -08001752 stats->seqerrs++;
1753 stats->frame_drops++;
Joe Perches475be4d2012-02-19 19:52:38 -08001754 start = isdn_ppp_mp_discard(mp, start, frag);
David S. Millere29d4362009-11-15 22:23:47 -08001755 nextf = frag->next;
Joe Perches475be4d2012-02-19 19:52:38 -08001756 }
1757 } else if (MP_LE(thisseq, minseq)) {
1758 if (MP_FLAGS(frag) & MP_BEGIN_FRAG)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759 start = frag;
Joe Perches475be4d2012-02-19 19:52:38 -08001760 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761 if (MP_FLAGS(frag) & MP_END_FRAG)
Joe Perches475be4d2012-02-19 19:52:38 -08001762 stats->frame_drops++;
1763 if (mp->frags == frag)
1764 mp->frags = nextf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765 isdn_ppp_mp_free_skb(mp, frag);
David S. Millere29d4362009-11-15 22:23:47 -08001766 frag = nextf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767 continue;
Joe Perches475be4d2012-02-19 19:52:38 -08001768 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769 }
Joe Perches475be4d2012-02-19 19:52:38 -08001770
David S. Millere29d4362009-11-15 22:23:47 -08001771 /* if start is non-null and we have end fragment, then
Joe Perches475be4d2012-02-19 19:52:38 -08001772 * we have full reassembly sequence -- reassemble
David S. Millere29d4362009-11-15 22:23:47 -08001773 * and process packet now
David S. Miller38783e62008-09-22 01:15:02 -07001774 */
Joe Perches475be4d2012-02-19 19:52:38 -08001775 if (start != NULL && (MP_FLAGS(frag) & MP_END_FRAG)) {
1776 minseq = mp->seq = (thisseq + 1) & MP_LONGSEQ_MASK;
1777 /* Reassemble the packet then dispatch it */
David S. Millere29d4362009-11-15 22:23:47 -08001778 isdn_ppp_mp_reassembly(net_dev, lp, start, nextf);
David S. Miller38783e62008-09-22 01:15:02 -07001779
Joe Perches475be4d2012-02-19 19:52:38 -08001780 start = NULL;
1781 frag = NULL;
1782
1783 mp->frags = nextf;
1784 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785
1786 /* check if need to update start pointer: if we just
1787 * reassembled the packet and sequence is contiguous
1788 * then next fragment should be the start of new reassembly
1789 * if sequence is contiguous, but we haven't reassembled yet,
1790 * keep going.
Lucas De Marchi25985ed2011-03-30 22:57:33 -03001791 * if sequence is not contiguous, either clear everything
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792 * below low watermark and set start to the next frag or
1793 * clear start ptr.
Joe Perches475be4d2012-02-19 19:52:38 -08001794 */
1795 if (nextf != NULL &&
1796 ((thisseq + 1) & MP_LONGSEQ_MASK) == MP_SEQ(nextf)) {
1797 /* if we just reassembled and the next one is here,
David S. Millere29d4362009-11-15 22:23:47 -08001798 * then start another reassembly. */
1799
Joe Perches475be4d2012-02-19 19:52:38 -08001800 if (frag == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801 if (MP_FLAGS(nextf) & MP_BEGIN_FRAG)
Joe Perches475be4d2012-02-19 19:52:38 -08001802 start = nextf;
David S. Millere29d4362009-11-15 22:23:47 -08001803 else
1804 {
Joe Perches475be4d2012-02-19 19:52:38 -08001805 printk(KERN_WARNING"isdn_mppp(seq %d):"
1806 " END flag with no following "
1807 "BEGIN", thisseq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808 stats->seqerrs++;
1809 }
1810 }
David S. Millere29d4362009-11-15 22:23:47 -08001811
Joe Perches475be4d2012-02-19 19:52:38 -08001812 } else {
1813 if (nextf != NULL && frag != NULL &&
1814 MP_LT(thisseq, minseq)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815 /* we've got a break in the sequence
1816 * and we not at the end yet
1817 * and we did not just reassembled
1818 *(if we did, there wouldn't be anything before)
Joe Perches475be4d2012-02-19 19:52:38 -08001819 * and we below the low watermark
1820 * discard all the frames below low watermark
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821 * and start over */
1822 stats->frame_drops++;
Joe Perches475be4d2012-02-19 19:52:38 -08001823 mp->frags = isdn_ppp_mp_discard(mp, start, nextf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824 }
1825 /* break in the sequence, no reassembly */
Joe Perches475be4d2012-02-19 19:52:38 -08001826 start = NULL;
1827 }
1828
1829 frag = nextf;
1830 } /* while -- main loop */
1831
1832 if (mp->frags == NULL)
1833 mp->frags = frag;
1834
1835 /* rather straighforward way to deal with (not very) possible
David S. Millere29d4362009-11-15 22:23:47 -08001836 * queue overflow */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837 if (mp->frames > MP_MAX_QUEUE_LEN) {
1838 stats->overflows++;
David S. Millere29d4362009-11-15 22:23:47 -08001839 while (mp->frames > MP_MAX_QUEUE_LEN) {
1840 frag = mp->frags->next;
1841 isdn_ppp_mp_free_skb(mp, mp->frags);
1842 mp->frags = frag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 }
1844 }
1845 spin_unlock_irqrestore(&mp->lock, flags);
1846}
1847
Joe Perches475be4d2012-02-19 19:52:38 -08001848static void isdn_ppp_mp_cleanup(isdn_net_local *lp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849{
Joe Perches475be4d2012-02-19 19:52:38 -08001850 struct sk_buff *frag = lp->netdev->pb->frags;
1851 struct sk_buff *nextfrag;
1852 while (frag) {
David S. Millere29d4362009-11-15 22:23:47 -08001853 nextfrag = frag->next;
1854 isdn_ppp_mp_free_skb(lp->netdev->pb, frag);
1855 frag = nextfrag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856 }
David S. Millere29d4362009-11-15 22:23:47 -08001857 lp->netdev->pb->frags = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858}
1859
Joe Perches475be4d2012-02-19 19:52:38 -08001860static u32 isdn_ppp_mp_get_seq(int short_seq,
1861 struct sk_buff *skb, u32 last_seq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862{
1863 u32 seq;
1864 int flags = skb->data[0] & (MP_BEGIN_FRAG | MP_END_FRAG);
Joe Perches475be4d2012-02-19 19:52:38 -08001865
1866 if (!short_seq)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867 {
Harvey Harrisonc19d0362008-11-20 04:10:51 -08001868 seq = ntohl(*(__be32 *)skb->data) & MP_LONGSEQ_MASK;
Joe Perches475be4d2012-02-19 19:52:38 -08001869 skb_push(skb, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870 }
1871 else
1872 {
Joe Perches475be4d2012-02-19 19:52:38 -08001873 /* convert 12-bit short seq number to 24-bit long one
1874 */
Harvey Harrisonc19d0362008-11-20 04:10:51 -08001875 seq = ntohs(*(__be16 *)skb->data) & MP_SHORTSEQ_MASK;
Joe Perches475be4d2012-02-19 19:52:38 -08001876
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877 /* check for seqence wrap */
Joe Perches475be4d2012-02-19 19:52:38 -08001878 if (!(seq & MP_SHORTSEQ_MAXBIT) &&
1879 (last_seq & MP_SHORTSEQ_MAXBIT) &&
1880 (unsigned long)last_seq <= MP_LONGSEQ_MAX)
1881 seq |= (last_seq + MP_SHORTSEQ_MAX + 1) &
1882 (~MP_SHORTSEQ_MASK & MP_LONGSEQ_MASK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883 else
1884 seq |= last_seq & (~MP_SHORTSEQ_MASK & MP_LONGSEQ_MASK);
Joe Perches475be4d2012-02-19 19:52:38 -08001885
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886 skb_push(skb, 3); /* put converted seqence back in skb */
1887 }
Joe Perches475be4d2012-02-19 19:52:38 -08001888 *(u32 *)(skb->data + 1) = seq; /* put seqence back in _host_ byte
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889 * order */
1890 skb->data[0] = flags; /* restore flags */
1891 return seq;
1892}
1893
Joe Perches475be4d2012-02-19 19:52:38 -08001894struct sk_buff *isdn_ppp_mp_discard(ippp_bundle *mp,
1895 struct sk_buff *from, struct sk_buff *to)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896{
Joe Perches475be4d2012-02-19 19:52:38 -08001897 if (from)
David S. Millere29d4362009-11-15 22:23:47 -08001898 while (from != to) {
Joe Perches475be4d2012-02-19 19:52:38 -08001899 struct sk_buff *next = from->next;
David S. Millere29d4362009-11-15 22:23:47 -08001900 isdn_ppp_mp_free_skb(mp, from);
Joe Perches475be4d2012-02-19 19:52:38 -08001901 from = next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902 }
David S. Millere29d4362009-11-15 22:23:47 -08001903 return from;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904}
1905
Joe Perches475be4d2012-02-19 19:52:38 -08001906void isdn_ppp_mp_reassembly(isdn_net_dev *net_dev, isdn_net_local *lp,
1907 struct sk_buff *from, struct sk_buff *to)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908{
Joe Perches475be4d2012-02-19 19:52:38 -08001909 ippp_bundle *mp = net_dev->pb;
David S. Miller38783e62008-09-22 01:15:02 -07001910 int proto;
Joe Perches475be4d2012-02-19 19:52:38 -08001911 struct sk_buff *skb;
David S. Millere29d4362009-11-15 22:23:47 -08001912 unsigned int tot_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913
1914 if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
1915 printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
Joe Perches475be4d2012-02-19 19:52:38 -08001916 __func__, lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917 return;
1918 }
Joe Perches475be4d2012-02-19 19:52:38 -08001919 if (MP_FLAGS(from) == (MP_BEGIN_FRAG | MP_END_FRAG)) {
1920 if (ippp_table[lp->ppp_slot]->debug & 0x40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921 printk(KERN_DEBUG "isdn_mppp: reassembly: frame %d, "
Joe Perches475be4d2012-02-19 19:52:38 -08001922 "len %d\n", MP_SEQ(from), from->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923 skb = from;
1924 skb_pull(skb, MP_HEADER_LEN);
Joe Perches475be4d2012-02-19 19:52:38 -08001925 mp->frames--;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926 } else {
Joe Perches475be4d2012-02-19 19:52:38 -08001927 struct sk_buff *frag;
David S. Millere29d4362009-11-15 22:23:47 -08001928 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929
Joe Perches475be4d2012-02-19 19:52:38 -08001930 for (tot_len = n = 0, frag = from; frag != to; frag = frag->next, n++)
David S. Millere29d4362009-11-15 22:23:47 -08001931 tot_len += frag->len - MP_HEADER_LEN;
1932
Joe Perches475be4d2012-02-19 19:52:38 -08001933 if (ippp_table[lp->ppp_slot]->debug & 0x40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934 printk(KERN_DEBUG"isdn_mppp: reassembling frames %d "
Joe Perches475be4d2012-02-19 19:52:38 -08001935 "to %d, len %d\n", MP_SEQ(from),
1936 (MP_SEQ(from) + n - 1) & MP_LONGSEQ_MASK, tot_len);
1937 if ((skb = dev_alloc_skb(tot_len)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938 printk(KERN_ERR "isdn_mppp: cannot allocate sk buff "
Joe Perches475be4d2012-02-19 19:52:38 -08001939 "of size %d\n", tot_len);
David S. Millere29d4362009-11-15 22:23:47 -08001940 isdn_ppp_mp_discard(mp, from, to);
1941 return;
1942 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943
Joe Perches475be4d2012-02-19 19:52:38 -08001944 while (from != to) {
David S. Millere29d4362009-11-15 22:23:47 -08001945 unsigned int len = from->len - MP_HEADER_LEN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946
David S. Millere29d4362009-11-15 22:23:47 -08001947 skb_copy_from_linear_data_offset(from, MP_HEADER_LEN,
Joe Perches475be4d2012-02-19 19:52:38 -08001948 skb_put(skb, len),
David S. Millere29d4362009-11-15 22:23:47 -08001949 len);
1950 frag = from->next;
1951 isdn_ppp_mp_free_skb(mp, from);
Joe Perches475be4d2012-02-19 19:52:38 -08001952 from = frag;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953 }
1954 }
Joe Perches475be4d2012-02-19 19:52:38 -08001955 proto = isdn_ppp_strip_proto(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956 isdn_ppp_push_higher(net_dev, lp, skb, proto);
1957}
1958
Joe Perches475be4d2012-02-19 19:52:38 -08001959static void isdn_ppp_mp_free_skb(ippp_bundle *mp, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960{
1961 dev_kfree_skb(skb);
1962 mp->frames--;
1963}
1964
Joe Perches475be4d2012-02-19 19:52:38 -08001965static void isdn_ppp_mp_print_recv_pkt(int slot, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001966{
Joe Perches475be4d2012-02-19 19:52:38 -08001967 printk(KERN_DEBUG "mp_recv: %d/%d -> %02x %02x %02x %02x %02x %02x\n",
1968 slot, (int) skb->len,
1969 (int) skb->data[0], (int) skb->data[1], (int) skb->data[2],
1970 (int) skb->data[3], (int) skb->data[4], (int) skb->data[5]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971}
1972
1973static int
1974isdn_ppp_bundle(struct ippp_struct *is, int unit)
1975{
1976 char ifn[IFNAMSIZ + 1];
1977 isdn_net_dev *p;
1978 isdn_net_local *lp, *nlp;
1979 int rc;
1980 unsigned long flags;
1981
1982 sprintf(ifn, "ippp%d", unit);
1983 p = isdn_net_findif(ifn);
1984 if (!p) {
1985 printk(KERN_ERR "ippp_bundle: cannot find %s\n", ifn);
1986 return -EINVAL;
1987 }
1988
Joe Perches475be4d2012-02-19 19:52:38 -08001989 spin_lock_irqsave(&p->pb->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990
1991 nlp = is->lp;
1992 lp = p->queue;
Joe Perches475be4d2012-02-19 19:52:38 -08001993 if (nlp->ppp_slot < 0 || nlp->ppp_slot >= ISDN_MAX_CHANNELS ||
1994 lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995 printk(KERN_ERR "ippp_bundle: binding to invalid slot %d\n",
Joe Perches475be4d2012-02-19 19:52:38 -08001996 nlp->ppp_slot < 0 || nlp->ppp_slot >= ISDN_MAX_CHANNELS ?
1997 nlp->ppp_slot : lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998 rc = -EINVAL;
1999 goto out;
Joe Perches475be4d2012-02-19 19:52:38 -08002000 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001
2002 isdn_net_add_to_bundle(p, nlp);
2003
2004 ippp_table[nlp->ppp_slot]->unit = ippp_table[lp->ppp_slot]->unit;
2005
2006 /* maybe also SC_CCP stuff */
2007 ippp_table[nlp->ppp_slot]->pppcfg |= ippp_table[lp->ppp_slot]->pppcfg &
2008 (SC_ENABLE_IP | SC_NO_TCP_CCID | SC_REJ_COMP_TCP);
2009 ippp_table[nlp->ppp_slot]->mpppcfg |= ippp_table[lp->ppp_slot]->mpppcfg &
2010 (SC_MP_PROT | SC_REJ_MP_PROT | SC_OUT_SHORT_SEQ | SC_IN_SHORT_SEQ);
2011 rc = isdn_ppp_mp_init(nlp, p->pb);
2012out:
2013 spin_unlock_irqrestore(&p->pb->lock, flags);
2014 return rc;
2015}
Joe Perches475be4d2012-02-19 19:52:38 -08002016
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017#endif /* CONFIG_ISDN_MPP */
Joe Perches475be4d2012-02-19 19:52:38 -08002018
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019/*
2020 * network device ioctl handlers
2021 */
2022
2023static int
2024isdn_ppp_dev_ioctl_stats(int slot, struct ifreq *ifr, struct net_device *dev)
2025{
2026 struct ppp_stats __user *res = ifr->ifr_data;
2027 struct ppp_stats t;
Joe Perchesa17531f2010-11-15 11:12:24 +00002028 isdn_net_local *lp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029
2030 if (!access_ok(VERIFY_WRITE, res, sizeof(struct ppp_stats)))
2031 return -EFAULT;
2032
2033 /* build a temporary stat struct and copy it to user space */
2034
2035 memset(&t, 0, sizeof(struct ppp_stats));
2036 if (dev->flags & IFF_UP) {
2037 t.p.ppp_ipackets = lp->stats.rx_packets;
2038 t.p.ppp_ibytes = lp->stats.rx_bytes;
2039 t.p.ppp_ierrors = lp->stats.rx_errors;
2040 t.p.ppp_opackets = lp->stats.tx_packets;
2041 t.p.ppp_obytes = lp->stats.tx_bytes;
2042 t.p.ppp_oerrors = lp->stats.tx_errors;
2043#ifdef CONFIG_ISDN_PPP_VJ
2044 if (slot >= 0 && ippp_table[slot]->slcomp) {
2045 struct slcompress *slcomp = ippp_table[slot]->slcomp;
2046 t.vj.vjs_packets = slcomp->sls_o_compressed + slcomp->sls_o_uncompressed;
2047 t.vj.vjs_compressed = slcomp->sls_o_compressed;
2048 t.vj.vjs_searches = slcomp->sls_o_searches;
2049 t.vj.vjs_misses = slcomp->sls_o_misses;
2050 t.vj.vjs_errorin = slcomp->sls_i_error;
2051 t.vj.vjs_tossed = slcomp->sls_i_tossed;
2052 t.vj.vjs_uncompressedin = slcomp->sls_i_uncompressed;
2053 t.vj.vjs_compressedin = slcomp->sls_i_compressed;
2054 }
2055#endif
2056 }
2057 if (copy_to_user(res, &t, sizeof(struct ppp_stats)))
2058 return -EFAULT;
2059 return 0;
2060}
2061
2062int
2063isdn_ppp_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
2064{
Joe Perches475be4d2012-02-19 19:52:38 -08002065 int error = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066 int len;
Joe Perchesa17531f2010-11-15 11:12:24 +00002067 isdn_net_local *lp = netdev_priv(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068
2069
2070 if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP)
2071 return -EINVAL;
2072
2073 switch (cmd) {
2074#define PPP_VERSION "2.3.7"
Joe Perches475be4d2012-02-19 19:52:38 -08002075 case SIOCGPPPVER:
2076 len = strlen(PPP_VERSION) + 1;
2077 if (copy_to_user(ifr->ifr_data, PPP_VERSION, len))
2078 error = -EFAULT;
2079 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002080
Joe Perches475be4d2012-02-19 19:52:38 -08002081 case SIOCGPPPSTATS:
2082 error = isdn_ppp_dev_ioctl_stats(lp->ppp_slot, ifr, dev);
2083 break;
2084 default:
2085 error = -EINVAL;
2086 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002087 }
2088 return error;
2089}
2090
2091static int
2092isdn_ppp_if_get_unit(char *name)
2093{
2094 int len,
Joe Perches475be4d2012-02-19 19:52:38 -08002095 i,
2096 unit = 0,
2097 deci;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098
2099 len = strlen(name);
2100
2101 if (strncmp("ippp", name, 4) || len > 8)
2102 return -1;
2103
2104 for (i = 0, deci = 1; i < len; i++, deci *= 10) {
2105 char a = name[len - i - 1];
2106 if (a >= '0' && a <= '9')
2107 unit += (a - '0') * deci;
2108 else
2109 break;
2110 }
2111 if (!i || len - i != 4)
2112 unit = -1;
2113
2114 return unit;
2115}
2116
2117
2118int
2119isdn_ppp_dial_slave(char *name)
2120{
2121#ifdef CONFIG_ISDN_MPP
2122 isdn_net_dev *ndev;
2123 isdn_net_local *lp;
2124 struct net_device *sdev;
2125
2126 if (!(ndev = isdn_net_findif(name)))
2127 return 1;
2128 lp = ndev->local;
2129 if (!(lp->flags & ISDN_NET_CONNECTED))
2130 return 5;
2131
2132 sdev = lp->slave;
2133 while (sdev) {
Joe Perchesa17531f2010-11-15 11:12:24 +00002134 isdn_net_local *mlp = netdev_priv(sdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002135 if (!(mlp->flags & ISDN_NET_CONNECTED))
2136 break;
2137 sdev = mlp->slave;
2138 }
2139 if (!sdev)
2140 return 2;
2141
Joe Perchesa17531f2010-11-15 11:12:24 +00002142 isdn_net_dial_req(netdev_priv(sdev));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002143 return 0;
2144#else
2145 return -1;
2146#endif
2147}
2148
2149int
2150isdn_ppp_hangup_slave(char *name)
2151{
2152#ifdef CONFIG_ISDN_MPP
2153 isdn_net_dev *ndev;
2154 isdn_net_local *lp;
2155 struct net_device *sdev;
2156
2157 if (!(ndev = isdn_net_findif(name)))
2158 return 1;
2159 lp = ndev->local;
2160 if (!(lp->flags & ISDN_NET_CONNECTED))
2161 return 5;
2162
2163 sdev = lp->slave;
2164 while (sdev) {
Joe Perchesa17531f2010-11-15 11:12:24 +00002165 isdn_net_local *mlp = netdev_priv(sdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166
2167 if (mlp->slave) { /* find last connected link in chain */
Wang Chen838361f2008-12-03 15:49:46 -08002168 isdn_net_local *nlp = ISDN_SLAVE_PRIV(mlp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002169
2170 if (!(nlp->flags & ISDN_NET_CONNECTED))
2171 break;
2172 } else if (mlp->flags & ISDN_NET_CONNECTED)
2173 break;
Joe Perches475be4d2012-02-19 19:52:38 -08002174
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175 sdev = mlp->slave;
2176 }
2177 if (!sdev)
2178 return 2;
2179
2180 isdn_net_hangup(sdev);
2181 return 0;
2182#else
2183 return -1;
2184#endif
2185}
2186
2187/*
2188 * PPP compression stuff
2189 */
2190
2191
2192/* Push an empty CCP Data Frame up to the daemon to wake it up and let it
2193 generate a CCP Reset-Request or tear down CCP altogether */
2194
2195static void isdn_ppp_ccp_kickup(struct ippp_struct *is)
2196{
2197 isdn_ppp_fill_rq(NULL, 0, PPP_COMP, is->lp->ppp_slot);
2198}
2199
2200/* In-kernel handling of CCP Reset-Request and Reset-Ack is necessary,
2201 but absolutely nontrivial. The most abstruse problem we are facing is
2202 that the generation, reception and all the handling of timeouts and
2203 resends including proper request id management should be entirely left
2204 to the (de)compressor, but indeed is not covered by the current API to
2205 the (de)compressor. The API is a prototype version from PPP where only
2206 some (de)compressors have yet been implemented and all of them are
2207 rather simple in their reset handling. Especially, their is only one
2208 outstanding ResetAck at a time with all of them and ResetReq/-Acks do
2209 not have parameters. For this very special case it was sufficient to
2210 just return an error code from the decompressor and have a single
2211 reset() entry to communicate all the necessary information between
2212 the framework and the (de)compressor. Bad enough, LZS is different
2213 (and any other compressor may be different, too). It has multiple
2214 histories (eventually) and needs to Reset each of them independently
2215 and thus uses multiple outstanding Acks and history numbers as an
2216 additional parameter to Reqs/Acks.
2217 All that makes it harder to port the reset state engine into the
2218 kernel because it is not just the same simple one as in (i)pppd but
2219 it must be able to pass additional parameters and have multiple out-
2220 standing Acks. We are trying to achieve the impossible by handling
2221 reset transactions independent by their id. The id MUST change when
2222 the data portion changes, thus any (de)compressor who uses more than
2223 one resettable state must provide and recognize individual ids for
2224 each individual reset transaction. The framework itself does _only_
2225 differentiate them by id, because it has no other semantics like the
2226 (de)compressor might.
2227 This looks like a major redesign of the interface would be nice,
2228 but I don't have an idea how to do it better. */
2229
2230/* Send a CCP Reset-Request or Reset-Ack directly from the kernel. This is
2231 getting that lengthy because there is no simple "send-this-frame-out"
2232 function above but every wrapper does a bit different. Hope I guess
2233 correct in this hack... */
2234
2235static void isdn_ppp_ccp_xmit_reset(struct ippp_struct *is, int proto,
2236 unsigned char code, unsigned char id,
2237 unsigned char *data, int len)
2238{
2239 struct sk_buff *skb;
2240 unsigned char *p;
2241 int hl;
2242 int cnt = 0;
2243 isdn_net_local *lp = is->lp;
2244
2245 /* Alloc large enough skb */
2246 hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen;
Joe Perches475be4d2012-02-19 19:52:38 -08002247 skb = alloc_skb(len + hl + 16, GFP_ATOMIC);
2248 if (!skb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002249 printk(KERN_WARNING
2250 "ippp: CCP cannot send reset - out of memory\n");
2251 return;
2252 }
2253 skb_reserve(skb, hl);
2254
2255 /* We may need to stuff an address and control field first */
Joe Perches475be4d2012-02-19 19:52:38 -08002256 if (!(is->pppcfg & SC_COMP_AC)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257 p = skb_put(skb, 2);
2258 *p++ = 0xff;
2259 *p++ = 0x03;
2260 }
2261
2262 /* Stuff proto, code, id and length */
2263 p = skb_put(skb, 6);
2264 *p++ = (proto >> 8);
2265 *p++ = (proto & 0xff);
2266 *p++ = code;
2267 *p++ = id;
2268 cnt = 4 + len;
2269 *p++ = (cnt >> 8);
2270 *p++ = (cnt & 0xff);
2271
2272 /* Now stuff remaining bytes */
Joe Perches475be4d2012-02-19 19:52:38 -08002273 if (len) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274 p = skb_put(skb, len);
2275 memcpy(p, data, len);
2276 }
2277
2278 /* skb is now ready for xmit */
2279 printk(KERN_DEBUG "Sending CCP Frame:\n");
Joe Perches475be4d2012-02-19 19:52:38 -08002280 isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit, lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002281
2282 isdn_net_write_super(lp, skb);
2283}
2284
2285/* Allocate the reset state vector */
2286static struct ippp_ccp_reset *isdn_ppp_ccp_reset_alloc(struct ippp_struct *is)
2287{
2288 struct ippp_ccp_reset *r;
Burman Yan41f96932006-12-08 02:39:35 -08002289 r = kzalloc(sizeof(struct ippp_ccp_reset), GFP_KERNEL);
Joe Perches475be4d2012-02-19 19:52:38 -08002290 if (!r) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291 printk(KERN_ERR "ippp_ccp: failed to allocate reset data"
2292 " structure - no mem\n");
2293 return NULL;
2294 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295 printk(KERN_DEBUG "ippp_ccp: allocated reset data structure %p\n", r);
2296 is->reset = r;
2297 return r;
2298}
2299
2300/* Destroy the reset state vector. Kill all pending timers first. */
2301static void isdn_ppp_ccp_reset_free(struct ippp_struct *is)
2302{
2303 unsigned int id;
2304
2305 printk(KERN_DEBUG "ippp_ccp: freeing reset data structure %p\n",
2306 is->reset);
Joe Perches475be4d2012-02-19 19:52:38 -08002307 for (id = 0; id < 256; id++) {
2308 if (is->reset->rs[id]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309 isdn_ppp_ccp_reset_free_state(is, (unsigned char)id);
2310 }
2311 }
2312 kfree(is->reset);
2313 is->reset = NULL;
2314}
2315
2316/* Free a given state and clear everything up for later reallocation */
2317static void isdn_ppp_ccp_reset_free_state(struct ippp_struct *is,
2318 unsigned char id)
2319{
2320 struct ippp_ccp_reset_state *rs;
2321
Joe Perches475be4d2012-02-19 19:52:38 -08002322 if (is->reset->rs[id]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323 printk(KERN_DEBUG "ippp_ccp: freeing state for id %d\n", id);
2324 rs = is->reset->rs[id];
2325 /* Make sure the kernel will not call back later */
Joe Perches475be4d2012-02-19 19:52:38 -08002326 if (rs->ta)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002327 del_timer(&rs->timer);
2328 is->reset->rs[id] = NULL;
2329 kfree(rs);
2330 } else {
2331 printk(KERN_WARNING "ippp_ccp: id %d is not allocated\n", id);
2332 }
2333}
2334
2335/* The timer callback function which is called when a ResetReq has timed out,
2336 aka has never been answered by a ResetAck */
2337static void isdn_ppp_ccp_timer_callback(unsigned long closure)
2338{
2339 struct ippp_ccp_reset_state *rs =
2340 (struct ippp_ccp_reset_state *)closure;
2341
Joe Perches475be4d2012-02-19 19:52:38 -08002342 if (!rs) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002343 printk(KERN_ERR "ippp_ccp: timer cb with zero closure.\n");
2344 return;
2345 }
Joe Perches475be4d2012-02-19 19:52:38 -08002346 if (rs->ta && rs->state == CCPResetSentReq) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002347 /* We are correct here */
Joe Perches475be4d2012-02-19 19:52:38 -08002348 if (!rs->expra) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002349 /* Hmm, there is no Ack really expected. We can clean
2350 up the state now, it will be reallocated if the
2351 decompressor insists on another reset */
2352 rs->ta = 0;
2353 isdn_ppp_ccp_reset_free_state(rs->is, rs->id);
2354 return;
2355 }
2356 printk(KERN_DEBUG "ippp_ccp: CCP Reset timed out for id %d\n",
2357 rs->id);
2358 /* Push it again */
2359 isdn_ppp_ccp_xmit_reset(rs->is, PPP_CCP, CCP_RESETREQ, rs->id,
2360 rs->data, rs->dlen);
2361 /* Restart timer */
Joe Perches475be4d2012-02-19 19:52:38 -08002362 rs->timer.expires = jiffies + HZ * 5;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002363 add_timer(&rs->timer);
2364 } else {
2365 printk(KERN_WARNING "ippp_ccp: timer cb in wrong state %d\n",
2366 rs->state);
2367 }
2368}
2369
2370/* Allocate a new reset transaction state */
2371static struct ippp_ccp_reset_state *isdn_ppp_ccp_reset_alloc_state(struct ippp_struct *is,
Joe Perches475be4d2012-02-19 19:52:38 -08002372 unsigned char id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373{
2374 struct ippp_ccp_reset_state *rs;
Joe Perches475be4d2012-02-19 19:52:38 -08002375 if (is->reset->rs[id]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376 printk(KERN_WARNING "ippp_ccp: old state exists for id %d\n",
2377 id);
2378 return NULL;
2379 } else {
Jia-Ju Baib7568622017-05-31 09:40:11 +08002380 rs = kzalloc(sizeof(struct ippp_ccp_reset_state), GFP_ATOMIC);
Joe Perches475be4d2012-02-19 19:52:38 -08002381 if (!rs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383 rs->state = CCPResetIdle;
2384 rs->is = is;
2385 rs->id = id;
Marcel Holtmanndab6df62006-12-21 23:06:24 +01002386 init_timer(&rs->timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387 rs->timer.data = (unsigned long)rs;
2388 rs->timer.function = isdn_ppp_ccp_timer_callback;
2389 is->reset->rs[id] = rs;
2390 }
2391 return rs;
2392}
2393
2394
2395/* A decompressor wants a reset with a set of parameters - do what is
2396 necessary to fulfill it */
2397static void isdn_ppp_ccp_reset_trans(struct ippp_struct *is,
2398 struct isdn_ppp_resetparams *rp)
2399{
2400 struct ippp_ccp_reset_state *rs;
2401
Joe Perches475be4d2012-02-19 19:52:38 -08002402 if (rp->valid) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403 /* The decompressor defines parameters by itself */
Joe Perches475be4d2012-02-19 19:52:38 -08002404 if (rp->rsend) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002405 /* And he wants us to send a request */
Joe Perches475be4d2012-02-19 19:52:38 -08002406 if (!(rp->idval)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407 printk(KERN_ERR "ippp_ccp: decompressor must"
2408 " specify reset id\n");
2409 return;
2410 }
Joe Perches475be4d2012-02-19 19:52:38 -08002411 if (is->reset->rs[rp->id]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412 /* There is already a transaction in existence
2413 for this id. May be still waiting for a
2414 Ack or may be wrong. */
2415 rs = is->reset->rs[rp->id];
Joe Perches475be4d2012-02-19 19:52:38 -08002416 if (rs->state == CCPResetSentReq && rs->ta) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002417 printk(KERN_DEBUG "ippp_ccp: reset"
2418 " trans still in progress"
2419 " for id %d\n", rp->id);
2420 } else {
2421 printk(KERN_WARNING "ippp_ccp: reset"
2422 " trans in wrong state %d for"
2423 " id %d\n", rs->state, rp->id);
2424 }
2425 } else {
2426 /* Ok, this is a new transaction */
2427 printk(KERN_DEBUG "ippp_ccp: new trans for id"
2428 " %d to be started\n", rp->id);
2429 rs = isdn_ppp_ccp_reset_alloc_state(is, rp->id);
Joe Perches475be4d2012-02-19 19:52:38 -08002430 if (!rs) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002431 printk(KERN_ERR "ippp_ccp: out of mem"
2432 " allocing ccp trans\n");
2433 return;
2434 }
2435 rs->state = CCPResetSentReq;
2436 rs->expra = rp->expra;
Joe Perches475be4d2012-02-19 19:52:38 -08002437 if (rp->dtval) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002438 rs->dlen = rp->dlen;
2439 memcpy(rs->data, rp->data, rp->dlen);
2440 }
2441 /* HACK TODO - add link comp here */
2442 isdn_ppp_ccp_xmit_reset(is, PPP_CCP,
2443 CCP_RESETREQ, rs->id,
2444 rs->data, rs->dlen);
2445 /* Start the timer */
Joe Perches475be4d2012-02-19 19:52:38 -08002446 rs->timer.expires = jiffies + 5 * HZ;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002447 add_timer(&rs->timer);
2448 rs->ta = 1;
2449 }
2450 } else {
2451 printk(KERN_DEBUG "ippp_ccp: no reset sent\n");
2452 }
2453 } else {
2454 /* The reset params are invalid. The decompressor does not
2455 care about them, so we just send the minimal requests
2456 and increase ids only when an Ack is received for a
2457 given id */
Joe Perches475be4d2012-02-19 19:52:38 -08002458 if (is->reset->rs[is->reset->lastid]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002459 /* There is already a transaction in existence
2460 for this id. May be still waiting for a
2461 Ack or may be wrong. */
2462 rs = is->reset->rs[is->reset->lastid];
Joe Perches475be4d2012-02-19 19:52:38 -08002463 if (rs->state == CCPResetSentReq && rs->ta) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464 printk(KERN_DEBUG "ippp_ccp: reset"
2465 " trans still in progress"
2466 " for id %d\n", rp->id);
2467 } else {
2468 printk(KERN_WARNING "ippp_ccp: reset"
2469 " trans in wrong state %d for"
2470 " id %d\n", rs->state, rp->id);
2471 }
2472 } else {
2473 printk(KERN_DEBUG "ippp_ccp: new trans for id"
2474 " %d to be started\n", is->reset->lastid);
2475 rs = isdn_ppp_ccp_reset_alloc_state(is,
2476 is->reset->lastid);
Joe Perches475be4d2012-02-19 19:52:38 -08002477 if (!rs) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478 printk(KERN_ERR "ippp_ccp: out of mem"
2479 " allocing ccp trans\n");
2480 return;
2481 }
2482 rs->state = CCPResetSentReq;
2483 /* We always expect an Ack if the decompressor doesn't
2484 know better */
2485 rs->expra = 1;
2486 rs->dlen = 0;
2487 /* HACK TODO - add link comp here */
2488 isdn_ppp_ccp_xmit_reset(is, PPP_CCP, CCP_RESETREQ,
2489 rs->id, NULL, 0);
2490 /* Start the timer */
Joe Perches475be4d2012-02-19 19:52:38 -08002491 rs->timer.expires = jiffies + 5 * HZ;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492 add_timer(&rs->timer);
2493 rs->ta = 1;
2494 }
2495 }
2496}
2497
2498/* An Ack was received for this id. This means we stop the timer and clean
2499 up the state prior to calling the decompressors reset routine. */
2500static void isdn_ppp_ccp_reset_ack_rcvd(struct ippp_struct *is,
2501 unsigned char id)
2502{
2503 struct ippp_ccp_reset_state *rs = is->reset->rs[id];
2504
Joe Perches475be4d2012-02-19 19:52:38 -08002505 if (rs) {
2506 if (rs->ta && rs->state == CCPResetSentReq) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002507 /* Great, we are correct */
Joe Perches475be4d2012-02-19 19:52:38 -08002508 if (!rs->expra)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509 printk(KERN_DEBUG "ippp_ccp: ResetAck received"
2510 " for id %d but not expected\n", id);
2511 } else {
2512 printk(KERN_INFO "ippp_ccp: ResetAck received out of"
2513 "sync for id %d\n", id);
2514 }
Joe Perches475be4d2012-02-19 19:52:38 -08002515 if (rs->ta) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002516 rs->ta = 0;
2517 del_timer(&rs->timer);
2518 }
2519 isdn_ppp_ccp_reset_free_state(is, id);
2520 } else {
2521 printk(KERN_INFO "ippp_ccp: ResetAck received for unknown id"
2522 " %d\n", id);
2523 }
2524 /* Make sure the simple reset stuff uses a new id next time */
2525 is->reset->lastid++;
2526}
2527
Joe Perches475be4d2012-02-19 19:52:38 -08002528/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529 * decompress packet
2530 *
2531 * if master = 0, we're trying to uncompress an per-link compressed packet,
2532 * as opposed to an compressed reconstructed-from-MPPP packet.
2533 * proto is updated to protocol field of uncompressed packet.
2534 *
2535 * retval: decompressed packet,
2536 * same packet if uncompressed,
2537 * NULL if decompression error
2538 */
2539
Joe Perches475be4d2012-02-19 19:52:38 -08002540static struct sk_buff *isdn_ppp_decompress(struct sk_buff *skb, struct ippp_struct *is, struct ippp_struct *master,
2541 int *proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002542{
2543 void *stat = NULL;
2544 struct isdn_ppp_compressor *ipc = NULL;
2545 struct sk_buff *skb_out;
2546 int len;
2547 struct ippp_struct *ri;
2548 struct isdn_ppp_resetparams rsparm;
2549 unsigned char rsdata[IPPP_RESET_MAXDATABYTES];
2550
Joe Perches475be4d2012-02-19 19:52:38 -08002551 if (!master) {
2552 // per-link decompression
Linus Torvalds1da177e2005-04-16 15:20:36 -07002553 stat = is->link_decomp_stat;
2554 ipc = is->link_decompressor;
2555 ri = is;
2556 } else {
2557 stat = master->decomp_stat;
2558 ipc = master->decompressor;
2559 ri = master;
2560 }
2561
2562 if (!ipc) {
2563 // no decompressor -> we can't decompress.
2564 printk(KERN_DEBUG "ippp: no decompressor defined!\n");
2565 return skb;
2566 }
Eric Sesterhenn6dd44a72006-03-26 18:19:26 +02002567 BUG_ON(!stat); // if we have a compressor, stat has been set as well
Linus Torvalds1da177e2005-04-16 15:20:36 -07002568
Joe Perches475be4d2012-02-19 19:52:38 -08002569 if ((master && *proto == PPP_COMP) || (!master && *proto == PPP_COMPFRAG)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002570 // compressed packets are compressed by their protocol type
2571
2572 // Set up reset params for the decompressor
Joe Perches475be4d2012-02-19 19:52:38 -08002573 memset(&rsparm, 0, sizeof(rsparm));
2574 rsparm.data = rsdata;
2575 rsparm.maxdlen = IPPP_RESET_MAXDATABYTES;
2576
2577 skb_out = dev_alloc_skb(is->mru + PPP_HDRLEN);
2578 if (!skb_out) {
2579 kfree_skb(skb);
2580 printk(KERN_ERR "ippp: decomp memory allocation failure\n");
Jesper Juhlf6e2cdc2006-12-08 02:39:34 -08002581 return NULL;
Joe Perches475be4d2012-02-19 19:52:38 -08002582 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002583 len = ipc->decompress(stat, skb, skb_out, &rsparm);
2584 kfree_skb(skb);
2585 if (len <= 0) {
Joe Perches475be4d2012-02-19 19:52:38 -08002586 switch (len) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587 case DECOMP_ERROR:
2588 printk(KERN_INFO "ippp: decomp wants reset %s params\n",
2589 rsparm.valid ? "with" : "without");
Joe Perches475be4d2012-02-19 19:52:38 -08002590
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591 isdn_ppp_ccp_reset_trans(ri, &rsparm);
2592 break;
2593 case DECOMP_FATALERROR:
2594 ri->pppcfg |= SC_DC_FERROR;
2595 /* Kick ipppd to recognize the error */
2596 isdn_ppp_ccp_kickup(ri);
2597 break;
2598 }
2599 kfree_skb(skb_out);
2600 return NULL;
2601 }
2602 *proto = isdn_ppp_strip_proto(skb_out);
2603 if (*proto < 0) {
2604 kfree_skb(skb_out);
2605 return NULL;
2606 }
2607 return skb_out;
Joe Perches475be4d2012-02-19 19:52:38 -08002608 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609 // uncompressed packets are fed through the decompressor to
2610 // update the decompressor state
2611 ipc->incomp(stat, skb, *proto);
2612 return skb;
2613 }
2614}
2615
2616/*
Joe Perches475be4d2012-02-19 19:52:38 -08002617 * compress a frame
Linus Torvalds1da177e2005-04-16 15:20:36 -07002618 * type=0: normal/bundle compression
2619 * =1: link compression
2620 * returns original skb if we haven't compressed the frame
2621 * and a new skb pointer if we've done it
2622 */
Joe Perches475be4d2012-02-19 19:52:38 -08002623static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in, int *proto,
2624 struct ippp_struct *is, struct ippp_struct *master, int type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625{
Joe Perches475be4d2012-02-19 19:52:38 -08002626 int ret;
2627 int new_proto;
2628 struct isdn_ppp_compressor *compressor;
2629 void *stat;
2630 struct sk_buff *skb_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002631
2632 /* we do not compress control protocols */
Joe Perches475be4d2012-02-19 19:52:38 -08002633 if (*proto < 0 || *proto > 0x3fff) {
2634 return skb_in;
2635 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636
Joe Perches475be4d2012-02-19 19:52:38 -08002637 if (type) { /* type=1 => Link compression */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002638 return skb_in;
2639 }
2640 else {
Joe Perches475be4d2012-02-19 19:52:38 -08002641 if (!master) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642 compressor = is->compressor;
2643 stat = is->comp_stat;
2644 }
2645 else {
2646 compressor = master->compressor;
2647 stat = master->comp_stat;
2648 }
2649 new_proto = PPP_COMP;
2650 }
2651
Joe Perches475be4d2012-02-19 19:52:38 -08002652 if (!compressor) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653 printk(KERN_ERR "isdn_ppp: No compressor set!\n");
2654 return skb_in;
2655 }
Joe Perches475be4d2012-02-19 19:52:38 -08002656 if (!stat) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657 printk(KERN_ERR "isdn_ppp: Compressor not initialized?\n");
2658 return skb_in;
2659 }
2660
2661 /* Allow for at least 150 % expansion (for now) */
Joe Perches475be4d2012-02-19 19:52:38 -08002662 skb_out = alloc_skb(skb_in->len + skb_in->len / 2 + 32 +
2663 skb_headroom(skb_in), GFP_ATOMIC);
2664 if (!skb_out)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002665 return skb_in;
2666 skb_reserve(skb_out, skb_headroom(skb_in));
2667
Joe Perches475be4d2012-02-19 19:52:38 -08002668 ret = (compressor->compress)(stat, skb_in, skb_out, *proto);
2669 if (!ret) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670 dev_kfree_skb(skb_out);
2671 return skb_in;
2672 }
Joe Perches475be4d2012-02-19 19:52:38 -08002673
Linus Torvalds1da177e2005-04-16 15:20:36 -07002674 dev_kfree_skb(skb_in);
2675 *proto = new_proto;
2676 return skb_out;
2677}
2678
2679/*
Joe Perches475be4d2012-02-19 19:52:38 -08002680 * we received a CCP frame ..
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681 * not a clean solution, but we MUST handle a few cases in the kernel
2682 */
2683static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp,
Joe Perches475be4d2012-02-19 19:52:38 -08002684 struct sk_buff *skb, int proto)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002685{
2686 struct ippp_struct *is;
2687 struct ippp_struct *mis;
2688 int len;
2689 struct isdn_ppp_resetparams rsparm;
Joe Perches475be4d2012-02-19 19:52:38 -08002690 unsigned char rsdata[IPPP_RESET_MAXDATABYTES];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002691
2692 printk(KERN_DEBUG "Received CCP frame from peer slot(%d)\n",
Joe Perches475be4d2012-02-19 19:52:38 -08002693 lp->ppp_slot);
Eric Sesterhenn052bb882006-04-11 17:29:17 -07002694 if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695 printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
Joe Perches475be4d2012-02-19 19:52:38 -08002696 __func__, lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697 return;
2698 }
2699 is = ippp_table[lp->ppp_slot];
Joe Perches475be4d2012-02-19 19:52:38 -08002700 isdn_ppp_frame_log("ccp-rcv", skb->data, skb->len, 32, is->unit, lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701
Joe Perches475be4d2012-02-19 19:52:38 -08002702 if (lp->master) {
Wang Chen838361f2008-12-03 15:49:46 -08002703 int slot = ISDN_MASTER_PRIV(lp)->ppp_slot;
Eric Sesterhenn052bb882006-04-11 17:29:17 -07002704 if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705 printk(KERN_ERR "%s: slot(%d) out of range\n",
Joe Perches475be4d2012-02-19 19:52:38 -08002706 __func__, slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707 return;
Joe Perches475be4d2012-02-19 19:52:38 -08002708 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709 mis = ippp_table[slot];
2710 } else
2711 mis = is;
2712
Joe Perches475be4d2012-02-19 19:52:38 -08002713 switch (skb->data[0]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714 case CCP_CONFREQ:
Joe Perches475be4d2012-02-19 19:52:38 -08002715 if (is->debug & 0x10)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716 printk(KERN_DEBUG "Disable compression here!\n");
Joe Perches475be4d2012-02-19 19:52:38 -08002717 if (proto == PPP_CCP)
2718 mis->compflags &= ~SC_COMP_ON;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719 else
Joe Perches475be4d2012-02-19 19:52:38 -08002720 is->compflags &= ~SC_LINK_COMP_ON;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002721 break;
2722 case CCP_TERMREQ:
2723 case CCP_TERMACK:
Joe Perches475be4d2012-02-19 19:52:38 -08002724 if (is->debug & 0x10)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725 printk(KERN_DEBUG "Disable (de)compression here!\n");
Joe Perches475be4d2012-02-19 19:52:38 -08002726 if (proto == PPP_CCP)
2727 mis->compflags &= ~(SC_DECOMP_ON | SC_COMP_ON);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728 else
Joe Perches475be4d2012-02-19 19:52:38 -08002729 is->compflags &= ~(SC_LINK_DECOMP_ON | SC_LINK_COMP_ON);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730 break;
2731 case CCP_CONFACK:
2732 /* if we RECEIVE an ackowledge we enable the decompressor */
Joe Perches475be4d2012-02-19 19:52:38 -08002733 if (is->debug & 0x10)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734 printk(KERN_DEBUG "Enable decompression here!\n");
Joe Perches475be4d2012-02-19 19:52:38 -08002735 if (proto == PPP_CCP) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736 if (!mis->decompressor)
2737 break;
2738 mis->compflags |= SC_DECOMP_ON;
2739 } else {
2740 if (!is->decompressor)
2741 break;
2742 is->compflags |= SC_LINK_DECOMP_ON;
2743 }
2744 break;
2745
2746 case CCP_RESETACK:
2747 printk(KERN_DEBUG "Received ResetAck from peer\n");
2748 len = (skb->data[2] << 8) | skb->data[3];
2749 len -= 4;
2750
Joe Perches475be4d2012-02-19 19:52:38 -08002751 if (proto == PPP_CCP) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002752 /* If a reset Ack was outstanding for this id, then
2753 clean up the state engine */
2754 isdn_ppp_ccp_reset_ack_rcvd(mis, skb->data[1]);
Joe Perches475be4d2012-02-19 19:52:38 -08002755 if (mis->decompressor && mis->decomp_stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756 mis->decompressor->
2757 reset(mis->decomp_stat,
2758 skb->data[0],
2759 skb->data[1],
2760 len ? &skb->data[4] : NULL,
2761 len, NULL);
2762 /* TODO: This is not easy to decide here */
2763 mis->compflags &= ~SC_DECOMP_DISCARD;
2764 }
2765 else {
2766 isdn_ppp_ccp_reset_ack_rcvd(is, skb->data[1]);
Joe Perches475be4d2012-02-19 19:52:38 -08002767 if (is->link_decompressor && is->link_decomp_stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768 is->link_decompressor->
2769 reset(is->link_decomp_stat,
2770 skb->data[0],
2771 skb->data[1],
2772 len ? &skb->data[4] : NULL,
2773 len, NULL);
2774 /* TODO: neither here */
2775 is->compflags &= ~SC_LINK_DECOMP_DISCARD;
2776 }
2777 break;
2778
2779 case CCP_RESETREQ:
2780 printk(KERN_DEBUG "Received ResetReq from peer\n");
2781 /* Receiving a ResetReq means we must reset our compressor */
2782 /* Set up reset params for the reset entry */
2783 memset(&rsparm, 0, sizeof(rsparm));
2784 rsparm.data = rsdata;
Joe Perches475be4d2012-02-19 19:52:38 -08002785 rsparm.maxdlen = IPPP_RESET_MAXDATABYTES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002786 /* Isolate data length */
2787 len = (skb->data[2] << 8) | skb->data[3];
2788 len -= 4;
Joe Perches475be4d2012-02-19 19:52:38 -08002789 if (proto == PPP_CCP) {
2790 if (mis->compressor && mis->comp_stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002791 mis->compressor->
2792 reset(mis->comp_stat,
2793 skb->data[0],
2794 skb->data[1],
2795 len ? &skb->data[4] : NULL,
2796 len, &rsparm);
2797 }
2798 else {
Joe Perches475be4d2012-02-19 19:52:38 -08002799 if (is->link_compressor && is->link_comp_stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800 is->link_compressor->
2801 reset(is->link_comp_stat,
2802 skb->data[0],
2803 skb->data[1],
2804 len ? &skb->data[4] : NULL,
2805 len, &rsparm);
2806 }
2807 /* Ack the Req as specified by rsparm */
Joe Perches475be4d2012-02-19 19:52:38 -08002808 if (rsparm.valid) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002809 /* Compressor reset handler decided how to answer */
Joe Perches475be4d2012-02-19 19:52:38 -08002810 if (rsparm.rsend) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002811 /* We should send a Frame */
2812 isdn_ppp_ccp_xmit_reset(is, proto, CCP_RESETACK,
2813 rsparm.idval ? rsparm.id
2814 : skb->data[1],
2815 rsparm.dtval ?
2816 rsparm.data : NULL,
2817 rsparm.dtval ?
2818 rsparm.dlen : 0);
2819 } else {
2820 printk(KERN_DEBUG "ResetAck suppressed\n");
2821 }
2822 } else {
2823 /* We answer with a straight reflected Ack */
2824 isdn_ppp_ccp_xmit_reset(is, proto, CCP_RESETACK,
2825 skb->data[1],
2826 len ? &skb->data[4] : NULL,
2827 len);
2828 }
2829 break;
2830 }
2831}
2832
2833
2834/*
2835 * Daemon sends a CCP frame ...
2836 */
2837
2838/* TODO: Clean this up with new Reset semantics */
2839
2840/* I believe the CCP handling as-is is done wrong. Compressed frames
2841 * should only be sent/received after CCP reaches UP state, which means
2842 * both sides have sent CONF_ACK. Currently, we handle both directions
2843 * independently, which means we may accept compressed frames too early
2844 * (supposedly not a problem), but may also mean we send compressed frames
2845 * too early, which may turn out to be a problem.
2846 * This part of state machine should actually be handled by (i)pppd, but
2847 * that's too big of a change now. --kai
2848 */
2849
2850/* Actually, we might turn this into an advantage: deal with the RFC in
2851 * the old tradition of beeing generous on what we accept, but beeing
2852 * strict on what we send. Thus we should just
2853 * - accept compressed frames as soon as decompression is negotiated
2854 * - send compressed frames only when decomp *and* comp are negotiated
2855 * - drop rx compressed frames if we cannot decomp (instead of pushing them
2856 * up to ipppd)
2857 * and I tried to modify this file according to that. --abp
2858 */
2859
2860static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *skb)
2861{
Joe Perches475be4d2012-02-19 19:52:38 -08002862 struct ippp_struct *mis, *is;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002863 int proto, slot = lp->ppp_slot;
2864 unsigned char *data;
2865
Joe Perches475be4d2012-02-19 19:52:38 -08002866 if (!skb || skb->len < 3)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002867 return;
2868 if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
2869 printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
Joe Perches475be4d2012-02-19 19:52:38 -08002870 __func__, slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002871 return;
Joe Perches475be4d2012-02-19 19:52:38 -08002872 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002873 is = ippp_table[slot];
2874 /* Daemon may send with or without address and control field comp */
2875 data = skb->data;
Joe Perches475be4d2012-02-19 19:52:38 -08002876 if (!(is->pppcfg & SC_COMP_AC) && data[0] == 0xff && data[1] == 0x03) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877 data += 2;
Joe Perches475be4d2012-02-19 19:52:38 -08002878 if (skb->len < 5)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002879 return;
2880 }
2881
Joe Perches475be4d2012-02-19 19:52:38 -08002882 proto = ((int)data[0]<<8) + data[1];
2883 if (proto != PPP_CCP && proto != PPP_CCPFRAG)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002884 return;
2885
2886 printk(KERN_DEBUG "Received CCP frame from daemon:\n");
Joe Perches475be4d2012-02-19 19:52:38 -08002887 isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit, lp->ppp_slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002888
2889 if (lp->master) {
Wang Chen838361f2008-12-03 15:49:46 -08002890 slot = ISDN_MASTER_PRIV(lp)->ppp_slot;
Eric Sesterhenn052bb882006-04-11 17:29:17 -07002891 if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002892 printk(KERN_ERR "%s: slot(%d) out of range\n",
Joe Perches475be4d2012-02-19 19:52:38 -08002893 __func__, slot);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002894 return;
Joe Perches475be4d2012-02-19 19:52:38 -08002895 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002896 mis = ippp_table[slot];
2897 } else
2898 mis = is;
2899 if (mis != is)
2900 printk(KERN_DEBUG "isdn_ppp: Ouch! Master CCP sends on slave slot!\n");
Joe Perches475be4d2012-02-19 19:52:38 -08002901
2902 switch (data[2]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002903 case CCP_CONFREQ:
Joe Perches475be4d2012-02-19 19:52:38 -08002904 if (is->debug & 0x10)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002905 printk(KERN_DEBUG "Disable decompression here!\n");
Joe Perches475be4d2012-02-19 19:52:38 -08002906 if (proto == PPP_CCP)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002907 is->compflags &= ~SC_DECOMP_ON;
2908 else
2909 is->compflags &= ~SC_LINK_DECOMP_ON;
2910 break;
2911 case CCP_TERMREQ:
2912 case CCP_TERMACK:
Joe Perches475be4d2012-02-19 19:52:38 -08002913 if (is->debug & 0x10)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002914 printk(KERN_DEBUG "Disable (de)compression here!\n");
Joe Perches475be4d2012-02-19 19:52:38 -08002915 if (proto == PPP_CCP)
2916 is->compflags &= ~(SC_DECOMP_ON | SC_COMP_ON);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002917 else
Joe Perches475be4d2012-02-19 19:52:38 -08002918 is->compflags &= ~(SC_LINK_DECOMP_ON | SC_LINK_COMP_ON);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002919 break;
2920 case CCP_CONFACK:
2921 /* if we SEND an ackowledge we can/must enable the compressor */
Joe Perches475be4d2012-02-19 19:52:38 -08002922 if (is->debug & 0x10)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002923 printk(KERN_DEBUG "Enable compression here!\n");
Joe Perches475be4d2012-02-19 19:52:38 -08002924 if (proto == PPP_CCP) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002925 if (!is->compressor)
2926 break;
2927 is->compflags |= SC_COMP_ON;
2928 } else {
2929 if (!is->compressor)
2930 break;
2931 is->compflags |= SC_LINK_COMP_ON;
2932 }
2933 break;
2934 case CCP_RESETACK:
2935 /* If we send a ACK we should reset our compressor */
Joe Perches475be4d2012-02-19 19:52:38 -08002936 if (is->debug & 0x10)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002937 printk(KERN_DEBUG "Reset decompression state here!\n");
2938 printk(KERN_DEBUG "ResetAck from daemon passed by\n");
Joe Perches475be4d2012-02-19 19:52:38 -08002939 if (proto == PPP_CCP) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002940 /* link to master? */
Joe Perches475be4d2012-02-19 19:52:38 -08002941 if (is->compressor && is->comp_stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002942 is->compressor->reset(is->comp_stat, 0, 0,
2943 NULL, 0, NULL);
Joe Perches475be4d2012-02-19 19:52:38 -08002944 is->compflags &= ~SC_COMP_DISCARD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945 }
2946 else {
Joe Perches475be4d2012-02-19 19:52:38 -08002947 if (is->link_compressor && is->link_comp_stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002948 is->link_compressor->reset(is->link_comp_stat,
2949 0, 0, NULL, 0, NULL);
Joe Perches475be4d2012-02-19 19:52:38 -08002950 is->compflags &= ~SC_LINK_COMP_DISCARD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951 }
2952 break;
2953 case CCP_RESETREQ:
2954 /* Just let it pass by */
2955 printk(KERN_DEBUG "ResetReq from daemon passed by\n");
2956 break;
2957 }
2958}
2959
2960int isdn_ppp_register_compressor(struct isdn_ppp_compressor *ipc)
2961{
2962 ipc->next = ipc_head;
2963 ipc->prev = NULL;
Joe Perches475be4d2012-02-19 19:52:38 -08002964 if (ipc_head) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002965 ipc_head->prev = ipc;
2966 }
2967 ipc_head = ipc;
2968 return 0;
2969}
2970
2971int isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *ipc)
2972{
Joe Perches475be4d2012-02-19 19:52:38 -08002973 if (ipc->prev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002974 ipc->prev->next = ipc->next;
2975 else
2976 ipc_head = ipc->next;
Joe Perches475be4d2012-02-19 19:52:38 -08002977 if (ipc->next)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002978 ipc->next->prev = ipc->prev;
2979 ipc->prev = ipc->next = NULL;
2980 return 0;
2981}
2982
2983static int isdn_ppp_set_compressor(struct ippp_struct *is, struct isdn_ppp_comp_data *data)
2984{
2985 struct isdn_ppp_compressor *ipc = ipc_head;
2986 int ret;
2987 void *stat;
2988 int num = data->num;
2989
Joe Perches475be4d2012-02-19 19:52:38 -08002990 if (is->debug & 0x10)
2991 printk(KERN_DEBUG "[%d] Set %s type %d\n", is->unit,
2992 (data->flags & IPPP_COMP_FLAG_XMIT) ? "compressor" : "decompressor", num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002993
2994 /* If is has no valid reset state vector, we cannot allocate a
2995 decompressor. The decompressor would cause reset transactions
2996 sooner or later, and they need that vector. */
2997
Joe Perches475be4d2012-02-19 19:52:38 -08002998 if (!(data->flags & IPPP_COMP_FLAG_XMIT) && !is->reset) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002999 printk(KERN_ERR "ippp_ccp: no reset data structure - can't"
3000 " allow decompression.\n");
3001 return -ENOMEM;
3002 }
3003
Joe Perches475be4d2012-02-19 19:52:38 -08003004 while (ipc) {
3005 if (ipc->num == num) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003006 stat = ipc->alloc(data);
Joe Perches475be4d2012-02-19 19:52:38 -08003007 if (stat) {
3008 ret = ipc->init(stat, data, is->unit, 0);
3009 if (!ret) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010 printk(KERN_ERR "Can't init (de)compression!\n");
3011 ipc->free(stat);
3012 stat = NULL;
3013 break;
3014 }
3015 }
3016 else {
3017 printk(KERN_ERR "Can't alloc (de)compression!\n");
3018 break;
3019 }
3020
Joe Perches475be4d2012-02-19 19:52:38 -08003021 if (data->flags & IPPP_COMP_FLAG_XMIT) {
3022 if (data->flags & IPPP_COMP_FLAG_LINK) {
3023 if (is->link_comp_stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003024 is->link_compressor->free(is->link_comp_stat);
3025 is->link_comp_stat = stat;
Joe Perches475be4d2012-02-19 19:52:38 -08003026 is->link_compressor = ipc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003027 }
3028 else {
Joe Perches475be4d2012-02-19 19:52:38 -08003029 if (is->comp_stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003030 is->compressor->free(is->comp_stat);
3031 is->comp_stat = stat;
Joe Perches475be4d2012-02-19 19:52:38 -08003032 is->compressor = ipc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003033 }
3034 }
Joe Perches475be4d2012-02-19 19:52:38 -08003035 else {
3036 if (data->flags & IPPP_COMP_FLAG_LINK) {
3037 if (is->link_decomp_stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003038 is->link_decompressor->free(is->link_decomp_stat);
3039 is->link_decomp_stat = stat;
Joe Perches475be4d2012-02-19 19:52:38 -08003040 is->link_decompressor = ipc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041 }
3042 else {
Joe Perches475be4d2012-02-19 19:52:38 -08003043 if (is->decomp_stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003044 is->decompressor->free(is->decomp_stat);
3045 is->decomp_stat = stat;
Joe Perches475be4d2012-02-19 19:52:38 -08003046 is->decompressor = ipc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003047 }
3048 }
3049 return 0;
3050 }
3051 ipc = ipc->next;
3052 }
3053 return -EINVAL;
3054}