blob: a25216bf475e5483fe0332f4d11416cfe0825d7d [file] [log] [blame]
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -08001/*
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>,
Tilman Schmidt70440cf2006-04-10 22:55:14 -07006 * Stefan Eilers.
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -08007 *
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 * =====================================================================
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -080014 */
15
16#include "gigaset.h"
17#include <linux/crc-ccitt.h>
Akinobu Mita17b3cff2006-12-08 02:36:30 -080018#include <linux/bitrev.h>
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -080019
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -080020/* check if byte must be stuffed/escaped
21 * I'm not sure which data should be encoded.
22 * Therefore I will go the hard way and decode every value
23 * less than 0x20, the flag sequence and the control escape char.
24 */
25static inline int muststuff(unsigned char c)
26{
27 if (c < PPP_TRANS) return 1;
28 if (c == PPP_FLAG) return 1;
29 if (c == PPP_ESCAPE) return 1;
30 /* other possible candidates: */
31 /* 0x91: XON with parity set */
32 /* 0x93: XOFF with parity set */
33 return 0;
34}
35
36/* == data input =========================================================== */
37
38/* process a block of received bytes in command mode (modem response)
39 * Return value:
40 * number of processed bytes
41 */
42static inline int cmd_loop(unsigned char c, unsigned char *src, int numbytes,
Tilman Schmidt784d5852006-04-10 22:55:04 -070043 struct inbuf_t *inbuf)
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -080044{
45 struct cardstate *cs = inbuf->cs;
46 unsigned cbytes = cs->cbytes;
47 int inputstate = inbuf->inputstate;
48 int startbytes = numbytes;
49
50 for (;;) {
51 cs->respdata[cbytes] = c;
52 if (c == 10 || c == 13) {
Tilman Schmidt784d5852006-04-10 22:55:04 -070053 gig_dbg(DEBUG_TRANSCMD, "%s: End of Command (%d Bytes)",
54 __func__, cbytes);
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -080055 cs->cbytes = cbytes;
Tilman Schmidt917f5082006-04-10 22:55:00 -070056 gigaset_handle_modem_response(cs); /* can change
57 cs->dle */
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -080058 cbytes = 0;
59
60 if (cs->dle &&
61 !(inputstate & INS_DLE_command)) {
62 inputstate &= ~INS_command;
63 break;
64 }
65 } else {
66 /* advance in line buffer, checking for overflow */
67 if (cbytes < MAX_RESP_SIZE - 1)
68 cbytes++;
69 else
Tilman Schmidt784d5852006-04-10 22:55:04 -070070 dev_warn(cs->dev, "response too large\n");
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -080071 }
72
73 if (!numbytes)
74 break;
75 c = *src++;
76 --numbytes;
77 if (c == DLE_FLAG &&
78 (cs->dle || inputstate & INS_DLE_command)) {
79 inputstate |= INS_DLE_char;
80 break;
81 }
82 }
83
84 cs->cbytes = cbytes;
85 inbuf->inputstate = inputstate;
86
87 return startbytes - numbytes;
88}
89
90/* process a block of received bytes in lock mode (tty i/f)
91 * Return value:
92 * number of processed bytes
93 */
94static inline int lock_loop(unsigned char *src, int numbytes,
Tilman Schmidt784d5852006-04-10 22:55:04 -070095 struct inbuf_t *inbuf)
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -080096{
97 struct cardstate *cs = inbuf->cs;
98
Tilman Schmidt917f5082006-04-10 22:55:00 -070099 gigaset_dbg_buffer(DEBUG_LOCKCMD, "received response",
Tilman Schmidt01371502006-04-10 22:55:11 -0700100 numbytes, src);
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800101 gigaset_if_receive(cs, src, numbytes);
102
103 return numbytes;
104}
105
106/* process a block of received bytes in HDLC data mode
107 * Collect HDLC frames, undoing byte stuffing and watching for DLE escapes.
108 * When a frame is complete, check the FCS and pass valid frames to the LL.
109 * If DLE is encountered, return immediately to let the caller handle it.
110 * Return value:
111 * number of processed bytes
112 * numbytes (all bytes processed) on error --FIXME
113 */
114static inline int hdlc_loop(unsigned char c, unsigned char *src, int numbytes,
Tilman Schmidt784d5852006-04-10 22:55:04 -0700115 struct inbuf_t *inbuf)
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800116{
117 struct cardstate *cs = inbuf->cs;
118 struct bc_state *bcs = inbuf->bcs;
Tilman Schmidtd48c7782006-04-10 22:55:08 -0700119 int inputstate = bcs->inputstate;
120 __u16 fcs = bcs->fcs;
121 struct sk_buff *skb = bcs->skb;
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800122 int startbytes = numbytes;
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800123
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800124 if (unlikely(inputstate & INS_byte_stuff)) {
125 inputstate &= ~INS_byte_stuff;
126 goto byte_stuff;
127 }
128 for (;;) {
129 if (unlikely(c == PPP_ESCAPE)) {
130 if (unlikely(!numbytes)) {
131 inputstate |= INS_byte_stuff;
132 break;
133 }
134 c = *src++;
135 --numbytes;
136 if (unlikely(c == DLE_FLAG &&
137 (cs->dle ||
138 inbuf->inputstate & INS_DLE_command))) {
139 inbuf->inputstate |= INS_DLE_char;
140 inputstate |= INS_byte_stuff;
141 break;
142 }
143byte_stuff:
144 c ^= PPP_TRANS;
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800145 if (unlikely(!muststuff(c)))
Tilman Schmidt784d5852006-04-10 22:55:04 -0700146 gig_dbg(DEBUG_HDLC, "byte stuffed: 0x%02x", c);
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800147 } else if (unlikely(c == PPP_FLAG)) {
148 if (unlikely(inputstate & INS_skip_frame)) {
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800149#ifdef CONFIG_GIGASET_DEBUG
Tilman Schmidt236b87c2008-12-26 01:22:03 -0800150 if (!(inputstate & INS_have_data)) { /* 7E 7E */
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800151 ++bcs->emptycount;
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800152 } else
Tilman Schmidt784d5852006-04-10 22:55:04 -0700153 gig_dbg(DEBUG_HDLC,
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800154 "7e----------------------------");
Tilman Schmidt236b87c2008-12-26 01:22:03 -0800155#endif
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800156
157 /* end of frame */
Tilman Schmidt088ec0c2009-10-06 12:19:07 +0000158 gigaset_isdn_rcv_err(bcs);
159 dev_kfree_skb(skb);
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800160 } else if (!(inputstate & INS_have_data)) { /* 7E 7E */
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800161#ifdef CONFIG_GIGASET_DEBUG
162 ++bcs->emptycount;
163#endif
164 break;
165 } else {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700166 gig_dbg(DEBUG_HDLC,
167 "7e----------------------------");
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800168
169 /* end of frame */
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800170 if (unlikely(fcs != PPP_GOODFCS)) {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700171 dev_err(cs->dev,
Tilman Schmidt0a305722009-05-13 12:44:18 +0000172 "Checksum failed, %u bytes corrupted!\n",
173 skb->len);
Tilman Schmidt088ec0c2009-10-06 12:19:07 +0000174 gigaset_isdn_rcv_err(bcs);
175 dev_kfree_skb(skb);
176 } else if (likely(skb->len > 2)) {
177 __skb_trim(skb, skb->len - 2);
178 gigaset_skb_rcvd(bcs, skb);
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800179 } else {
Tilman Schmidt088ec0c2009-10-06 12:19:07 +0000180 if (skb->len) {
181 dev_err(cs->dev,
182 "invalid packet size (%d)\n", skb->len);
183 gigaset_isdn_rcv_err(bcs);
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800184 }
Tilman Schmidt088ec0c2009-10-06 12:19:07 +0000185 dev_kfree_skb(skb);
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800186 }
187 }
188
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800189 fcs = PPP_INITFCS;
190 inputstate &= ~(INS_have_data | INS_skip_frame);
191 if (unlikely(bcs->ignore)) {
192 inputstate |= INS_skip_frame;
193 skb = NULL;
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800194 } else {
Tilman Schmidt088ec0c2009-10-06 12:19:07 +0000195 skb = dev_alloc_skb(SBUFSIZE + cs->hw_hdr_len);
196 if (skb != NULL) {
197 skb_reserve(skb, cs->hw_hdr_len);
198 } else {
199 dev_warn(cs->dev,
200 "could not allocate new skb\n");
201 inputstate |= INS_skip_frame;
202 }
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800203 }
204
205 break;
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800206 } else if (unlikely(muststuff(c))) {
207 /* Should not happen. Possible after ZDLE=1<CR><LF>. */
Tilman Schmidt784d5852006-04-10 22:55:04 -0700208 gig_dbg(DEBUG_HDLC, "not byte stuffed: 0x%02x", c);
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800209 }
210
211 /* add character */
212
213#ifdef CONFIG_GIGASET_DEBUG
214 if (unlikely(!(inputstate & INS_have_data))) {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700215 gig_dbg(DEBUG_HDLC, "7e (%d x) ================",
216 bcs->emptycount);
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800217 bcs->emptycount = 0;
218 }
219#endif
220
221 inputstate |= INS_have_data;
222
223 if (likely(!(inputstate & INS_skip_frame))) {
224 if (unlikely(skb->len == SBUFSIZE)) {
Tilman Schmidt784d5852006-04-10 22:55:04 -0700225 dev_warn(cs->dev, "received packet too long\n");
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800226 dev_kfree_skb_any(skb);
227 skb = NULL;
228 inputstate |= INS_skip_frame;
229 break;
230 }
Tilman Schmidt443e1f42006-04-10 22:55:13 -0700231 *__skb_put(skb, 1) = c;
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800232 fcs = crc_ccitt_byte(fcs, c);
233 }
234
235 if (unlikely(!numbytes))
236 break;
237 c = *src++;
238 --numbytes;
239 if (unlikely(c == DLE_FLAG &&
240 (cs->dle ||
241 inbuf->inputstate & INS_DLE_command))) {
242 inbuf->inputstate |= INS_DLE_char;
243 break;
244 }
245 }
246 bcs->inputstate = inputstate;
247 bcs->fcs = fcs;
248 bcs->skb = skb;
249 return startbytes - numbytes;
250}
251
252/* process a block of received bytes in transparent data mode
253 * Invert bytes, undoing byte stuffing and watching for DLE escapes.
254 * If DLE is encountered, return immediately to let the caller handle it.
255 * Return value:
256 * number of processed bytes
257 * numbytes (all bytes processed) on error --FIXME
258 */
259static inline int iraw_loop(unsigned char c, unsigned char *src, int numbytes,
Tilman Schmidt784d5852006-04-10 22:55:04 -0700260 struct inbuf_t *inbuf)
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800261{
262 struct cardstate *cs = inbuf->cs;
263 struct bc_state *bcs = inbuf->bcs;
Tilman Schmidtd48c7782006-04-10 22:55:08 -0700264 int inputstate = bcs->inputstate;
265 struct sk_buff *skb = bcs->skb;
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800266 int startbytes = numbytes;
267
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800268 for (;;) {
269 /* add character */
270 inputstate |= INS_have_data;
271
272 if (likely(!(inputstate & INS_skip_frame))) {
273 if (unlikely(skb->len == SBUFSIZE)) {
274 //FIXME just pass skb up and allocate a new one
Tilman Schmidt784d5852006-04-10 22:55:04 -0700275 dev_warn(cs->dev, "received packet too long\n");
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800276 dev_kfree_skb_any(skb);
277 skb = NULL;
278 inputstate |= INS_skip_frame;
279 break;
280 }
Akinobu Mita17b3cff2006-12-08 02:36:30 -0800281 *__skb_put(skb, 1) = bitrev8(c);
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800282 }
283
284 if (unlikely(!numbytes))
285 break;
286 c = *src++;
287 --numbytes;
288 if (unlikely(c == DLE_FLAG &&
289 (cs->dle ||
290 inbuf->inputstate & INS_DLE_command))) {
291 inbuf->inputstate |= INS_DLE_char;
292 break;
293 }
294 }
295
296 /* pass data up */
297 if (likely(inputstate & INS_have_data)) {
298 if (likely(!(inputstate & INS_skip_frame))) {
Tilman Schmidt088ec0c2009-10-06 12:19:07 +0000299 gigaset_skb_rcvd(bcs, skb);
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800300 }
301 inputstate &= ~(INS_have_data | INS_skip_frame);
302 if (unlikely(bcs->ignore)) {
303 inputstate |= INS_skip_frame;
304 skb = NULL;
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800305 } else {
Tilman Schmidt088ec0c2009-10-06 12:19:07 +0000306 skb = dev_alloc_skb(SBUFSIZE + cs->hw_hdr_len);
307 if (skb != NULL) {
308 skb_reserve(skb, cs->hw_hdr_len);
309 } else {
310 dev_warn(cs->dev,
311 "could not allocate new skb\n");
312 inputstate |= INS_skip_frame;
313 }
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800314 }
315 }
316
317 bcs->inputstate = inputstate;
318 bcs->skb = skb;
319 return startbytes - numbytes;
320}
321
Tilman Schmidt1cec9722009-10-06 12:19:01 +0000322/**
323 * gigaset_m10x_input() - process a block of data received from the device
324 * @inbuf: received data and device descriptor structure.
325 *
326 * Called by hardware module {ser,usb}_gigaset with a block of received
327 * bytes. Separates the bytes received over the serial data channel into
328 * user data and command replies (locked/unlocked) according to the
329 * current state of the interface.
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800330 */
331void gigaset_m10x_input(struct inbuf_t *inbuf)
332{
333 struct cardstate *cs;
334 unsigned tail, head, numbytes;
335 unsigned char *src, c;
336 int procbytes;
337
Tilman Schmidt9d4bee22008-02-06 01:38:28 -0800338 head = inbuf->head;
339 tail = inbuf->tail;
Tilman Schmidt784d5852006-04-10 22:55:04 -0700340 gig_dbg(DEBUG_INTR, "buffer state: %u -> %u", head, tail);
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800341
342 if (head != tail) {
343 cs = inbuf->cs;
344 src = inbuf->data + head;
345 numbytes = (head > tail ? RBUFSIZE : tail) - head;
Tilman Schmidt784d5852006-04-10 22:55:04 -0700346 gig_dbg(DEBUG_INTR, "processing %u bytes", numbytes);
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800347
348 while (numbytes) {
Tilman Schmidt9d4bee22008-02-06 01:38:28 -0800349 if (cs->mstate == MS_LOCKED) {
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800350 procbytes = lock_loop(src, numbytes, inbuf);
351 src += procbytes;
352 numbytes -= procbytes;
353 } else {
354 c = *src++;
355 --numbytes;
356 if (c == DLE_FLAG && (cs->dle ||
357 inbuf->inputstate & INS_DLE_command)) {
358 if (!(inbuf->inputstate & INS_DLE_char)) {
359 inbuf->inputstate |= INS_DLE_char;
360 goto nextbyte;
361 }
362 /* <DLE> <DLE> => <DLE> in data stream */
363 inbuf->inputstate &= ~INS_DLE_char;
364 }
365
366 if (!(inbuf->inputstate & INS_DLE_char)) {
367
Tilman Schmidt917f5082006-04-10 22:55:00 -0700368 /* FIXME use function pointers? */
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800369 if (inbuf->inputstate & INS_command)
370 procbytes = cmd_loop(c, src, numbytes, inbuf);
Tilman Schmidt088ec0c2009-10-06 12:19:07 +0000371 else if (inbuf->bcs->proto2 == L2_HDLC)
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800372 procbytes = hdlc_loop(c, src, numbytes, inbuf);
373 else
374 procbytes = iraw_loop(c, src, numbytes, inbuf);
375
376 src += procbytes;
377 numbytes -= procbytes;
Tilman Schmidt784d5852006-04-10 22:55:04 -0700378 } else { /* DLE char */
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800379 inbuf->inputstate &= ~INS_DLE_char;
380 switch (c) {
381 case 'X': /*begin of command*/
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800382 if (inbuf->inputstate & INS_command)
Tilman Schmidt236b87c2008-12-26 01:22:03 -0800383 dev_warn(cs->dev,
Tilman Schmidt784d5852006-04-10 22:55:04 -0700384 "received <DLE> 'X' in command mode\n");
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800385 inbuf->inputstate |=
386 INS_command | INS_DLE_command;
387 break;
388 case '.': /*end of command*/
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800389 if (!(inbuf->inputstate & INS_command))
Tilman Schmidt236b87c2008-12-26 01:22:03 -0800390 dev_warn(cs->dev,
Tilman Schmidt784d5852006-04-10 22:55:04 -0700391 "received <DLE> '.' in hdlc mode\n");
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800392 inbuf->inputstate &= cs->dle ?
393 ~(INS_DLE_command|INS_command)
394 : ~INS_DLE_command;
395 break;
396 //case DLE_FLAG: /*DLE_FLAG in data stream*/ /* schon oben behandelt! */
397 default:
Tilman Schmidt784d5852006-04-10 22:55:04 -0700398 dev_err(cs->dev,
399 "received 0x10 0x%02x!\n",
400 (int) c);
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800401 /* FIXME: reset driver?? */
402 }
403 }
404 }
405nextbyte:
406 if (!numbytes) {
407 /* end of buffer, check for wrap */
408 if (head > tail) {
409 head = 0;
410 src = inbuf->data;
411 numbytes = tail;
412 } else {
413 head = tail;
414 break;
415 }
416 }
417 }
418
Tilman Schmidt784d5852006-04-10 22:55:04 -0700419 gig_dbg(DEBUG_INTR, "setting head to %u", head);
Tilman Schmidt9d4bee22008-02-06 01:38:28 -0800420 inbuf->head = head;
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800421 }
422}
Adrian Bunkd5c16822007-02-20 13:58:17 -0800423EXPORT_SYMBOL_GPL(gigaset_m10x_input);
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800424
425
426/* == data output ========================================================== */
427
Tilman Schmidt088ec0c2009-10-06 12:19:07 +0000428/*
429 * Encode a data packet into an octet stuffed HDLC frame with FCS,
430 * opening and closing flags, preserving headroom data.
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800431 * parameters:
Tilman Schmidt088ec0c2009-10-06 12:19:07 +0000432 * skb skb containing original packet (freed upon return)
433 * headroom number of headroom bytes to preserve
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800434 * Return value:
435 * pointer to newly allocated skb containing the result frame
436 */
Tilman Schmidt088ec0c2009-10-06 12:19:07 +0000437static struct sk_buff *HDLC_Encode(struct sk_buff *skb, int headroom)
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800438{
439 struct sk_buff *hdlc_skb;
440 __u16 fcs;
441 unsigned char c;
442 unsigned char *cp;
443 int len;
444 unsigned int stuf_cnt;
445
446 stuf_cnt = 0;
447 fcs = PPP_INITFCS;
448 cp = skb->data;
449 len = skb->len;
450 while (len--) {
451 if (muststuff(*cp))
452 stuf_cnt++;
453 fcs = crc_ccitt_byte(fcs, *cp++);
454 }
Tilman Schmidt784d5852006-04-10 22:55:04 -0700455 fcs ^= 0xffff; /* complement */
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800456
457 /* size of new buffer: original size + number of stuffing bytes
458 * + 2 bytes FCS + 2 stuffing bytes for FCS (if needed) + 2 flag bytes
Tilman Schmidt088ec0c2009-10-06 12:19:07 +0000459 * + room for acknowledgement header
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800460 */
Tilman Schmidt088ec0c2009-10-06 12:19:07 +0000461 hdlc_skb = dev_alloc_skb(skb->len + stuf_cnt + 6 + headroom);
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800462 if (!hdlc_skb) {
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800463 dev_kfree_skb(skb);
464 return NULL;
465 }
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800466
Tilman Schmidt088ec0c2009-10-06 12:19:07 +0000467 /* Copy acknowledgement header into new skb */
468 skb_reserve(hdlc_skb, headroom);
469 memcpy(hdlc_skb->head, skb->head, headroom);
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800470
471 /* Add flag sequence in front of everything.. */
472 *(skb_put(hdlc_skb, 1)) = PPP_FLAG;
473
474 /* Perform byte stuffing while copying data. */
475 while (skb->len--) {
476 if (muststuff(*skb->data)) {
477 *(skb_put(hdlc_skb, 1)) = PPP_ESCAPE;
478 *(skb_put(hdlc_skb, 1)) = (*skb->data++) ^ PPP_TRANS;
479 } else
480 *(skb_put(hdlc_skb, 1)) = *skb->data++;
481 }
482
483 /* Finally add FCS (byte stuffed) and flag sequence */
Tilman Schmidt784d5852006-04-10 22:55:04 -0700484 c = (fcs & 0x00ff); /* least significant byte first */
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800485 if (muststuff(c)) {
486 *(skb_put(hdlc_skb, 1)) = PPP_ESCAPE;
487 c ^= PPP_TRANS;
488 }
489 *(skb_put(hdlc_skb, 1)) = c;
490
491 c = ((fcs >> 8) & 0x00ff);
492 if (muststuff(c)) {
493 *(skb_put(hdlc_skb, 1)) = PPP_ESCAPE;
494 c ^= PPP_TRANS;
495 }
496 *(skb_put(hdlc_skb, 1)) = c;
497
498 *(skb_put(hdlc_skb, 1)) = PPP_FLAG;
499
500 dev_kfree_skb(skb);
501 return hdlc_skb;
502}
503
Tilman Schmidt088ec0c2009-10-06 12:19:07 +0000504/*
505 * Encode a data packet into an octet stuffed raw bit inverted frame,
506 * preserving headroom data.
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800507 * parameters:
Tilman Schmidt088ec0c2009-10-06 12:19:07 +0000508 * skb skb containing original packet (freed upon return)
509 * headroom number of headroom bytes to preserve
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800510 * Return value:
511 * pointer to newly allocated skb containing the result frame
512 */
Tilman Schmidt088ec0c2009-10-06 12:19:07 +0000513static struct sk_buff *iraw_encode(struct sk_buff *skb, int headroom)
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800514{
515 struct sk_buff *iraw_skb;
516 unsigned char c;
517 unsigned char *cp;
518 int len;
519
520 /* worst case: every byte must be stuffed */
Tilman Schmidt088ec0c2009-10-06 12:19:07 +0000521 iraw_skb = dev_alloc_skb(2*skb->len + headroom);
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800522 if (!iraw_skb) {
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800523 dev_kfree_skb(skb);
524 return NULL;
525 }
Tilman Schmidt088ec0c2009-10-06 12:19:07 +0000526
527 /* Copy acknowledgement header into new skb */
528 skb_reserve(iraw_skb, headroom);
529 memcpy(iraw_skb->head, skb->head, headroom);
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800530
531 cp = skb->data;
532 len = skb->len;
533 while (len--) {
Akinobu Mita17b3cff2006-12-08 02:36:30 -0800534 c = bitrev8(*cp++);
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800535 if (c == DLE_FLAG)
536 *(skb_put(iraw_skb, 1)) = c;
537 *(skb_put(iraw_skb, 1)) = c;
538 }
539 dev_kfree_skb(skb);
540 return iraw_skb;
541}
542
Tilman Schmidt1cec9722009-10-06 12:19:01 +0000543/**
544 * gigaset_m10x_send_skb() - queue an skb for sending
545 * @bcs: B channel descriptor structure.
546 * @skb: data to send.
547 *
Tilman Schmidt088ec0c2009-10-06 12:19:07 +0000548 * Called by LL to encode and queue an skb for sending, and start
Tilman Schmidt1cec9722009-10-06 12:19:01 +0000549 * transmission if necessary.
Tilman Schmidt088ec0c2009-10-06 12:19:07 +0000550 * Once the payload data has been transmitted completely, gigaset_skb_sent()
551 * will be called with the first cs->hw_hdr_len bytes of skb->head preserved.
Tilman Schmidt1cec9722009-10-06 12:19:01 +0000552 *
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800553 * Return value:
Tilman Schmidt1cec9722009-10-06 12:19:01 +0000554 * number of bytes accepted for sending (skb->len) if ok,
555 * error code < 0 (eg. -ENOMEM) on error
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800556 */
557int gigaset_m10x_send_skb(struct bc_state *bcs, struct sk_buff *skb)
558{
Tilman Schmidtd48c7782006-04-10 22:55:08 -0700559 unsigned len = skb->len;
Tilman Schmidt69049cc2006-04-10 22:55:16 -0700560 unsigned long flags;
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800561
Tilman Schmidt088ec0c2009-10-06 12:19:07 +0000562 if (bcs->proto2 == L2_HDLC)
563 skb = HDLC_Encode(skb, bcs->cs->hw_hdr_len);
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800564 else
Tilman Schmidt088ec0c2009-10-06 12:19:07 +0000565 skb = iraw_encode(skb, bcs->cs->hw_hdr_len);
Tilman Schmidt784d5852006-04-10 22:55:04 -0700566 if (!skb) {
Tilman Schmidt50027792008-07-23 21:28:27 -0700567 dev_err(bcs->cs->dev,
568 "unable to allocate memory for encoding!\n");
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800569 return -ENOMEM;
Tilman Schmidt784d5852006-04-10 22:55:04 -0700570 }
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800571
572 skb_queue_tail(&bcs->squeue, skb);
Tilman Schmidt69049cc2006-04-10 22:55:16 -0700573 spin_lock_irqsave(&bcs->cs->lock, flags);
574 if (bcs->cs->connected)
575 tasklet_schedule(&bcs->cs->write_tasklet);
576 spin_unlock_irqrestore(&bcs->cs->lock, flags);
Hansjoerg Lipp07dc1f92006-03-26 01:38:37 -0800577
578 return len; /* ok so far */
579}
Adrian Bunkd5c16822007-02-20 13:58:17 -0800580EXPORT_SYMBOL_GPL(gigaset_m10x_send_skb);