asyncdata.c revision 917f5085ddb3498033551e711fb22f48ddeb8378
1/*
2 * Common data handling layer for ser_gigaset and usb_gigaset
3 *
4 * Copyright (c) 2005 by Tilman Schmidt <tilman@imap.cc>,
5 *                       Hansjoerg Lipp <hjlipp@web.de>,
6 *                       Stefan Eilers <Eilers.Stefan@epost.de>.
7 *
8 * =====================================================================
9 *	This program is free software; you can redistribute it and/or
10 *	modify it under the terms of the GNU General Public License as
11 *	published by the Free Software Foundation; either version 2 of
12 *	the License, or (at your option) any later version.
13 * =====================================================================
14 */
15
16#include "gigaset.h"
17#include <linux/crc-ccitt.h>
18
19//#define GIG_M10x_STUFF_VOICE_DATA
20
21/* check if byte must be stuffed/escaped
22 * I'm not sure which data should be encoded.
23 * Therefore I will go the hard way and decode every value
24 * less than 0x20, the flag sequence and the control escape char.
25 */
26static inline int muststuff(unsigned char c)
27{
28	if (c < PPP_TRANS) return 1;
29	if (c == PPP_FLAG) return 1;
30	if (c == PPP_ESCAPE) return 1;
31	/* other possible candidates: */
32	/* 0x91: XON with parity set */
33	/* 0x93: XOFF with parity set */
34	return 0;
35}
36
37/* == data input =========================================================== */
38
39/* process a block of received bytes in command mode (modem response)
40 * Return value:
41 *	number of processed bytes
42 */
43static inline int cmd_loop(unsigned char c, unsigned char *src, int numbytes,
44                           struct inbuf_t *inbuf)
45{
46	struct cardstate *cs = inbuf->cs;
47	unsigned cbytes      = cs->cbytes;
48	int inputstate = inbuf->inputstate;
49	int startbytes = numbytes;
50
51	for (;;) {
52		cs->respdata[cbytes] = c;
53		if (c == 10 || c == 13) {
54			dbg(DEBUG_TRANSCMD, "%s: End of Command (%d Bytes)",
55			    __func__, cbytes);
56			cs->cbytes = cbytes;
57			gigaset_handle_modem_response(cs); /* can change
58							      cs->dle */
59			cbytes = 0;
60
61			if (cs->dle &&
62			    !(inputstate & INS_DLE_command)) {
63				inputstate &= ~INS_command;
64				break;
65			}
66		} else {
67			/* advance in line buffer, checking for overflow */
68			if (cbytes < MAX_RESP_SIZE - 1)
69				cbytes++;
70			else
71				warn("response too large");
72		}
73
74		if (!numbytes)
75			break;
76		c = *src++;
77		--numbytes;
78		if (c == DLE_FLAG &&
79		    (cs->dle || inputstate & INS_DLE_command)) {
80			inputstate |= INS_DLE_char;
81			break;
82		}
83	}
84
85	cs->cbytes = cbytes;
86	inbuf->inputstate = inputstate;
87
88	return startbytes - numbytes;
89}
90
91/* process a block of received bytes in lock mode (tty i/f)
92 * Return value:
93 *	number of processed bytes
94 */
95static inline int lock_loop(unsigned char *src, int numbytes,
96                            struct inbuf_t *inbuf)
97{
98	struct cardstate *cs = inbuf->cs;
99
100	gigaset_dbg_buffer(DEBUG_LOCKCMD, "received response",
101			   numbytes, src, 0);
102	gigaset_if_receive(cs, src, numbytes);
103
104	return numbytes;
105}
106
107/* process a block of received bytes in HDLC data mode
108 * Collect HDLC frames, undoing byte stuffing and watching for DLE escapes.
109 * When a frame is complete, check the FCS and pass valid frames to the LL.
110 * If DLE is encountered, return immediately to let the caller handle it.
111 * Return value:
112 *	number of processed bytes
113 *	numbytes (all bytes processed) on error --FIXME
114 */
115static inline int hdlc_loop(unsigned char c, unsigned char *src, int numbytes,
116                            struct inbuf_t *inbuf)
117{
118	struct cardstate *cs = inbuf->cs;
119	struct bc_state *bcs = inbuf->bcs;
120	int inputstate;
121	__u16 fcs;
122	struct sk_buff *skb;
123	unsigned char error;
124	struct sk_buff *compskb;
125	int startbytes = numbytes;
126	int l;
127
128	IFNULLRETVAL(bcs, numbytes);
129	inputstate = bcs->inputstate;
130	fcs = bcs->fcs;
131	skb = bcs->skb;
132	IFNULLRETVAL(skb, numbytes);
133
134	if (unlikely(inputstate & INS_byte_stuff)) {
135		inputstate &= ~INS_byte_stuff;
136		goto byte_stuff;
137	}
138	for (;;) {
139		if (unlikely(c == PPP_ESCAPE)) {
140			if (unlikely(!numbytes)) {
141				inputstate |= INS_byte_stuff;
142				break;
143			}
144			c = *src++;
145			--numbytes;
146			if (unlikely(c == DLE_FLAG &&
147				     (cs->dle ||
148				      inbuf->inputstate & INS_DLE_command))) {
149				inbuf->inputstate |= INS_DLE_char;
150				inputstate |= INS_byte_stuff;
151				break;
152			}
153byte_stuff:
154			c ^= PPP_TRANS;
155#ifdef CONFIG_GIGASET_DEBUG
156			if (unlikely(!muststuff(c)))
157				dbg(DEBUG_HDLC,
158				    "byte stuffed: 0x%02x", c);
159#endif
160		} else if (unlikely(c == PPP_FLAG)) {
161			if (unlikely(inputstate & INS_skip_frame)) {
162				if (!(inputstate & INS_have_data)) { /* 7E 7E */
163					//dbg(DEBUG_HDLC, "(7e)7e------------------------");
164#ifdef CONFIG_GIGASET_DEBUG
165					++bcs->emptycount;
166#endif
167				} else
168					dbg(DEBUG_HDLC,
169					    "7e----------------------------");
170
171				/* end of frame */
172				error = 1;
173				gigaset_rcv_error(NULL, cs, bcs);
174			} else if (!(inputstate & INS_have_data)) { /* 7E 7E */
175				//dbg(DEBUG_HDLC, "(7e)7e------------------------");
176#ifdef CONFIG_GIGASET_DEBUG
177				++bcs->emptycount;
178#endif
179				break;
180			} else {
181				dbg(DEBUG_HDLC,
182				    "7e----------------------------");
183
184				/* end of frame */
185				error = 0;
186
187				if (unlikely(fcs != PPP_GOODFCS)) {
188					err("Packet checksum at %lu failed, "
189					    "packet is corrupted (%u bytes)!",
190					    bcs->rcvbytes, skb->len);
191					compskb = NULL;
192					gigaset_rcv_error(compskb, cs, bcs);
193					error = 1;
194				} else {
195					if (likely((l = skb->len) > 2)) {
196						skb->tail -= 2;
197						skb->len -= 2;
198					} else {
199						dev_kfree_skb(skb);
200						skb = NULL;
201						inputstate |= INS_skip_frame;
202						if (l == 1) {
203							err("invalid packet size (1)!");
204							error = 1;
205							gigaset_rcv_error(NULL, cs, bcs);
206						}
207					}
208					if (likely(!(error ||
209						     (inputstate &
210						      INS_skip_frame)))) {
211						gigaset_rcv_skb(skb, cs, bcs);
212					}
213				}
214			}
215
216			if (unlikely(error))
217				if (skb)
218					dev_kfree_skb(skb);
219
220			fcs = PPP_INITFCS;
221			inputstate &= ~(INS_have_data | INS_skip_frame);
222			if (unlikely(bcs->ignore)) {
223				inputstate |= INS_skip_frame;
224				skb = NULL;
225			} else if (likely((skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL)) {
226				skb_reserve(skb, HW_HDR_LEN);
227			} else {
228				warn("could not allocate new skb");
229				inputstate |= INS_skip_frame;
230			}
231
232			break;
233#ifdef CONFIG_GIGASET_DEBUG
234		} else if (unlikely(muststuff(c))) {
235			/* Should not happen. Possible after ZDLE=1<CR><LF>. */
236			dbg(DEBUG_HDLC, "not byte stuffed: 0x%02x", c);
237#endif
238		}
239
240		/* add character */
241
242#ifdef CONFIG_GIGASET_DEBUG
243		if (unlikely(!(inputstate & INS_have_data))) {
244			dbg(DEBUG_HDLC,
245			    "7e (%d x) ================", bcs->emptycount);
246			bcs->emptycount = 0;
247		}
248#endif
249
250		inputstate |= INS_have_data;
251
252		if (likely(!(inputstate & INS_skip_frame))) {
253			if (unlikely(skb->len == SBUFSIZE)) {
254				warn("received packet too long");
255				dev_kfree_skb_any(skb);
256				skb = NULL;
257				inputstate |= INS_skip_frame;
258				break;
259			}
260			*gigaset_skb_put_quick(skb, 1) = c;
261			/* *__skb_put (skb, 1) = c; */
262			fcs = crc_ccitt_byte(fcs, c);
263		}
264
265		if (unlikely(!numbytes))
266			break;
267		c = *src++;
268		--numbytes;
269		if (unlikely(c == DLE_FLAG &&
270			     (cs->dle ||
271			      inbuf->inputstate & INS_DLE_command))) {
272			inbuf->inputstate |= INS_DLE_char;
273			break;
274		}
275	}
276	bcs->inputstate = inputstate;
277	bcs->fcs = fcs;
278	bcs->skb = skb;
279	return startbytes - numbytes;
280}
281
282/* process a block of received bytes in transparent data mode
283 * Invert bytes, undoing byte stuffing and watching for DLE escapes.
284 * If DLE is encountered, return immediately to let the caller handle it.
285 * Return value:
286 *	number of processed bytes
287 *	numbytes (all bytes processed) on error --FIXME
288 */
289static inline int iraw_loop(unsigned char c, unsigned char *src, int numbytes,
290                            struct inbuf_t *inbuf)
291{
292	struct cardstate *cs = inbuf->cs;
293	struct bc_state *bcs = inbuf->bcs;
294	int inputstate;
295	struct sk_buff *skb;
296	int startbytes = numbytes;
297
298	IFNULLRETVAL(bcs, numbytes);
299	inputstate = bcs->inputstate;
300	skb = bcs->skb;
301	IFNULLRETVAL(skb, numbytes);
302
303	for (;;) {
304		/* add character */
305		inputstate |= INS_have_data;
306
307		if (likely(!(inputstate & INS_skip_frame))) {
308			if (unlikely(skb->len == SBUFSIZE)) {
309				//FIXME just pass skb up and allocate a new one
310				warn("received packet too long");
311				dev_kfree_skb_any(skb);
312				skb = NULL;
313				inputstate |= INS_skip_frame;
314				break;
315			}
316			*gigaset_skb_put_quick(skb, 1) = gigaset_invtab[c];
317		}
318
319		if (unlikely(!numbytes))
320			break;
321		c = *src++;
322		--numbytes;
323		if (unlikely(c == DLE_FLAG &&
324			     (cs->dle ||
325			      inbuf->inputstate & INS_DLE_command))) {
326			inbuf->inputstate |= INS_DLE_char;
327			break;
328		}
329	}
330
331	/* pass data up */
332	if (likely(inputstate & INS_have_data)) {
333		if (likely(!(inputstate & INS_skip_frame))) {
334			gigaset_rcv_skb(skb, cs, bcs);
335		}
336		inputstate &= ~(INS_have_data | INS_skip_frame);
337		if (unlikely(bcs->ignore)) {
338			inputstate |= INS_skip_frame;
339			skb = NULL;
340		} else if (likely((skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN))
341				  != NULL)) {
342			skb_reserve(skb, HW_HDR_LEN);
343		} else {
344			warn("could not allocate new skb");
345			inputstate |= INS_skip_frame;
346		}
347	}
348
349	bcs->inputstate = inputstate;
350	bcs->skb = skb;
351	return startbytes - numbytes;
352}
353
354/* process a block of data received from the device
355 */
356void gigaset_m10x_input(struct inbuf_t *inbuf)
357{
358	struct cardstate *cs;
359	unsigned tail, head, numbytes;
360	unsigned char *src, c;
361	int procbytes;
362
363	head = atomic_read(&inbuf->head);
364	tail = atomic_read(&inbuf->tail);
365	dbg(DEBUG_INTR, "buffer state: %u -> %u", head, tail);
366
367	if (head != tail) {
368		cs = inbuf->cs;
369		src = inbuf->data + head;
370		numbytes = (head > tail ? RBUFSIZE : tail) - head;
371		dbg(DEBUG_INTR, "processing %u bytes", numbytes);
372
373		while (numbytes) {
374			if (atomic_read(&cs->mstate) == MS_LOCKED) {
375				procbytes = lock_loop(src, numbytes, inbuf);
376				src += procbytes;
377				numbytes -= procbytes;
378			} else {
379				c = *src++;
380				--numbytes;
381				if (c == DLE_FLAG && (cs->dle ||
382				    inbuf->inputstate & INS_DLE_command)) {
383					if (!(inbuf->inputstate & INS_DLE_char)) {
384						inbuf->inputstate |= INS_DLE_char;
385						goto nextbyte;
386					}
387					/* <DLE> <DLE> => <DLE> in data stream */
388					inbuf->inputstate &= ~INS_DLE_char;
389				}
390
391				if (!(inbuf->inputstate & INS_DLE_char)) {
392
393					/* FIXME use function pointers?  */
394					if (inbuf->inputstate & INS_command)
395						procbytes = cmd_loop(c, src, numbytes, inbuf);
396					else if (inbuf->bcs->proto2 == ISDN_PROTO_L2_HDLC)
397						procbytes = hdlc_loop(c, src, numbytes, inbuf);
398					else
399						procbytes = iraw_loop(c, src, numbytes, inbuf);
400
401					src += procbytes;
402					numbytes -= procbytes;
403				} else {  /* DLE-char */
404					inbuf->inputstate &= ~INS_DLE_char;
405					switch (c) {
406					case 'X': /*begin of command*/
407#ifdef CONFIG_GIGASET_DEBUG
408						if (inbuf->inputstate & INS_command)
409							err("received <DLE> 'X' in command mode");
410#endif
411						inbuf->inputstate |=
412							INS_command | INS_DLE_command;
413						break;
414					case '.': /*end of command*/
415#ifdef CONFIG_GIGASET_DEBUG
416						if (!(inbuf->inputstate & INS_command))
417							err("received <DLE> '.' in hdlc mode");
418#endif
419						inbuf->inputstate &= cs->dle ?
420							~(INS_DLE_command|INS_command)
421							: ~INS_DLE_command;
422						break;
423					//case DLE_FLAG: /*DLE_FLAG in data stream*/ /* schon oben behandelt! */
424					default:
425						err("received 0x10 0x%02x!", (int) c);
426						/* FIXME: reset driver?? */
427					}
428				}
429			}
430nextbyte:
431			if (!numbytes) {
432				/* end of buffer, check for wrap */
433				if (head > tail) {
434					head = 0;
435					src = inbuf->data;
436					numbytes = tail;
437				} else {
438					head = tail;
439					break;
440				}
441			}
442		}
443
444		dbg(DEBUG_INTR, "setting head to %u", head);
445		atomic_set(&inbuf->head, head);
446	}
447}
448
449
450/* == data output ========================================================== */
451
452/* Encoding of a PPP packet into an octet stuffed HDLC frame
453 * with FCS, opening and closing flags.
454 * parameters:
455 *	skb	skb containing original packet (freed upon return)
456 *	head	number of headroom bytes to allocate in result skb
457 *	tail	number of tailroom bytes to allocate in result skb
458 * Return value:
459 *	pointer to newly allocated skb containing the result frame
460 */
461static struct sk_buff *HDLC_Encode(struct sk_buff *skb, int head, int tail)
462{
463	struct sk_buff *hdlc_skb;
464	__u16 fcs;
465	unsigned char c;
466	unsigned char *cp;
467	int len;
468	unsigned int stuf_cnt;
469
470	stuf_cnt = 0;
471	fcs = PPP_INITFCS;
472	cp = skb->data;
473	len = skb->len;
474	while (len--) {
475		if (muststuff(*cp))
476			stuf_cnt++;
477		fcs = crc_ccitt_byte(fcs, *cp++);
478	}
479	fcs ^= 0xffff;                 /* complement */
480
481	/* size of new buffer: original size + number of stuffing bytes
482	 * + 2 bytes FCS + 2 stuffing bytes for FCS (if needed) + 2 flag bytes
483	 */
484	hdlc_skb = dev_alloc_skb(skb->len + stuf_cnt + 6 + tail + head);
485	if (!hdlc_skb) {
486		err("unable to allocate memory for HDLC encoding!");
487		dev_kfree_skb(skb);
488		return NULL;
489	}
490	skb_reserve(hdlc_skb, head);
491
492	/* Copy acknowledge request into new skb */
493	memcpy(hdlc_skb->head, skb->head, 2);
494
495	/* Add flag sequence in front of everything.. */
496	*(skb_put(hdlc_skb, 1)) = PPP_FLAG;
497
498	/* Perform byte stuffing while copying data. */
499	while (skb->len--) {
500		if (muststuff(*skb->data)) {
501			*(skb_put(hdlc_skb, 1)) = PPP_ESCAPE;
502			*(skb_put(hdlc_skb, 1)) = (*skb->data++) ^ PPP_TRANS;
503		} else
504			*(skb_put(hdlc_skb, 1)) = *skb->data++;
505	}
506
507	/* Finally add FCS (byte stuffed) and flag sequence */
508	c = (fcs & 0x00ff);      /* least significant byte first */
509	if (muststuff(c)) {
510		*(skb_put(hdlc_skb, 1)) = PPP_ESCAPE;
511		c ^= PPP_TRANS;
512	}
513	*(skb_put(hdlc_skb, 1)) = c;
514
515	c = ((fcs >> 8) & 0x00ff);
516	if (muststuff(c)) {
517		*(skb_put(hdlc_skb, 1)) = PPP_ESCAPE;
518		c ^= PPP_TRANS;
519	}
520	*(skb_put(hdlc_skb, 1)) = c;
521
522	*(skb_put(hdlc_skb, 1)) = PPP_FLAG;
523
524	dev_kfree_skb(skb);
525	return hdlc_skb;
526}
527
528/* Encoding of a raw packet into an octet stuffed bit inverted frame
529 * parameters:
530 *	skb	skb containing original packet (freed upon return)
531 *	head	number of headroom bytes to allocate in result skb
532 *	tail	number of tailroom bytes to allocate in result skb
533 * Return value:
534 *	pointer to newly allocated skb containing the result frame
535 */
536static struct sk_buff *iraw_encode(struct sk_buff *skb, int head, int tail)
537{
538	struct sk_buff *iraw_skb;
539	unsigned char c;
540	unsigned char *cp;
541	int len;
542
543	/* worst case: every byte must be stuffed */
544	iraw_skb = dev_alloc_skb(2*skb->len + tail + head);
545	if (!iraw_skb) {
546		err("unable to allocate memory for HDLC encoding!");
547		dev_kfree_skb(skb);
548		return NULL;
549	}
550	skb_reserve(iraw_skb, head);
551
552	cp = skb->data;
553	len = skb->len;
554	while (len--) {
555		c = gigaset_invtab[*cp++];
556		if (c == DLE_FLAG)
557			*(skb_put(iraw_skb, 1)) = c;
558		*(skb_put(iraw_skb, 1)) = c;
559	}
560	dev_kfree_skb(skb);
561	return iraw_skb;
562}
563
564/* gigaset_send_skb
565 * called by common.c to queue an skb for sending
566 * and start transmission if necessary
567 * parameters:
568 *	B Channel control structure
569 *	skb
570 * Return value:
571 *	number of bytes accepted for sending
572 *	(skb->len if ok, 0 if out of buffer space)
573 *	or error code (< 0, eg. -EINVAL)
574 */
575int gigaset_m10x_send_skb(struct bc_state *bcs, struct sk_buff *skb)
576{
577	unsigned len;
578
579	IFNULLRETVAL(bcs, -EFAULT);
580	IFNULLRETVAL(skb, -EFAULT);
581	len = skb->len;
582
583	if (bcs->proto2 == ISDN_PROTO_L2_HDLC)
584		skb = HDLC_Encode(skb, HW_HDR_LEN, 0);
585	else
586		skb = iraw_encode(skb, HW_HDR_LEN, 0);
587	if (!skb)
588		return -ENOMEM;
589
590	skb_queue_tail(&bcs->squeue, skb);
591	tasklet_schedule(&bcs->cs->write_tasklet);
592
593	return len;	/* ok so far */
594}
595