Commit 63e055d1 authored by Tilman Schmidt's avatar Tilman Schmidt Committed by David S. Miller

bas_gigaset: collapse CR/LF at end of AT response

Copy the mechanism from ser_/usb_gigaset to avoid producing
spurious empty responses for CR/LF sequences from the device.
Add a comment in all drivers documenting that behaviour.
Correct an off by one error that might result in a one byte
buffer overflow when receiving an unexpectedly long reply.

Impact: minor bugfix
Signed-off-by: default avatarTilman Schmidt <tilman@imap.cc>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 2ac2ed5f
...@@ -40,6 +40,8 @@ static inline int muststuff(unsigned char c) ...@@ -40,6 +40,8 @@ static inline int muststuff(unsigned char c)
* Append received bytes to the command response buffer and forward them * Append received bytes to the command response buffer and forward them
* line by line to the response handler. Exit whenever a mode/state change * line by line to the response handler. Exit whenever a mode/state change
* might have occurred. * might have occurred.
* Note: Received lines may be terminated by CR, LF, or CR LF, which will be
* removed before passing the line to the response handler.
* Return value: * Return value:
* number of processed bytes * number of processed bytes
*/ */
......
...@@ -38,7 +38,7 @@ ...@@ -38,7 +38,7 @@
#define GIG_COMPAT {0, 4, 0, 0} #define GIG_COMPAT {0, 4, 0, 0}
#define MAX_REC_PARAMS 10 /* Max. number of params in response string */ #define MAX_REC_PARAMS 10 /* Max. number of params in response string */
#define MAX_RESP_SIZE 512 /* Max. size of a response string */ #define MAX_RESP_SIZE 511 /* Max. size of a response string */
#define MAX_EVENTS 64 /* size of event queue */ #define MAX_EVENTS 64 /* size of event queue */
...@@ -498,7 +498,7 @@ struct cardstate { ...@@ -498,7 +498,7 @@ struct cardstate {
spinlock_t ev_lock; spinlock_t ev_lock;
/* current modem response */ /* current modem response */
unsigned char respdata[MAX_RESP_SIZE]; unsigned char respdata[MAX_RESP_SIZE+1];
unsigned cbytes; unsigned cbytes;
/* private data of hardware drivers */ /* private data of hardware drivers */
......
...@@ -905,28 +905,48 @@ void gigaset_isoc_receive(unsigned char *src, unsigned count, ...@@ -905,28 +905,48 @@ void gigaset_isoc_receive(unsigned char *src, unsigned count,
/* == data input =========================================================== */ /* == data input =========================================================== */
/* process a block of received bytes in command mode (mstate != MS_LOCKED)
* Append received bytes to the command response buffer and forward them
* line by line to the response handler.
* Note: Received lines may be terminated by CR, LF, or CR LF, which will be
* removed before passing the line to the response handler.
*/
static void cmd_loop(unsigned char *src, int numbytes, struct inbuf_t *inbuf) static void cmd_loop(unsigned char *src, int numbytes, struct inbuf_t *inbuf)
{ {
struct cardstate *cs = inbuf->cs; struct cardstate *cs = inbuf->cs;
unsigned cbytes = cs->cbytes; unsigned cbytes = cs->cbytes;
unsigned char c;
while (numbytes--) { while (numbytes--) {
/* copy next character, check for end of line */ c = *src++;
switch (cs->respdata[cbytes] = *src++) { switch (c) {
case '\r':
case '\n': case '\n':
/* end of line */ if (cbytes == 0 && cs->respdata[0] == '\r') {
gig_dbg(DEBUG_TRANSCMD, "%s: End of Command (%d Bytes)", /* collapse LF with preceding CR */
__func__, cbytes); cs->respdata[0] = 0;
if (cbytes >= MAX_RESP_SIZE - 1) break;
dev_warn(cs->dev, "response too large\n"); }
/* --v-- fall through --v-- */
case '\r':
/* end of message line, pass to response handler */
if (cbytes >= MAX_RESP_SIZE) {
dev_warn(cs->dev, "response too large (%d)\n",
cbytes);
cbytes = MAX_RESP_SIZE;
}
cs->cbytes = cbytes; cs->cbytes = cbytes;
gigaset_dbg_buffer(DEBUG_TRANSCMD, "received response",
cbytes, cs->respdata);
gigaset_handle_modem_response(cs); gigaset_handle_modem_response(cs);
cbytes = 0; cbytes = 0;
/* store EOL byte for CRLF collapsing */
cs->respdata[0] = c;
break; break;
default: default:
/* advance in line buffer, checking for overflow */ /* append to line buffer if possible */
if (cbytes < MAX_RESP_SIZE - 1) if (cbytes < MAX_RESP_SIZE)
cs->respdata[cbytes] = c;
cbytes++; cbytes++;
} }
} }
...@@ -958,8 +978,6 @@ void gigaset_isoc_input(struct inbuf_t *inbuf) ...@@ -958,8 +978,6 @@ void gigaset_isoc_input(struct inbuf_t *inbuf)
numbytes, src); numbytes, src);
gigaset_if_receive(inbuf->cs, src, numbytes); gigaset_if_receive(inbuf->cs, src, numbytes);
} else { } else {
gigaset_dbg_buffer(DEBUG_CMD, "received response",
numbytes, src);
cmd_loop(src, numbytes, inbuf); cmd_loop(src, numbytes, inbuf);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment