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: Tilman Schmidt <tilman@imap.cc> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Родитель
2ac2ed5f2d
Коммит
63e055d1c6
|
@ -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 @@
|
||||||
#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 {
|
||||||
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,29 +905,49 @@ 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)
|
||||||
cbytes++;
|
cs->respdata[cbytes] = c;
|
||||||
|
cbytes++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче