diff options
author | Tilman Schmidt <tilman@imap.cc> | 2010-02-22 08:09:22 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-02-26 04:24:23 -0500 |
commit | 63e055d1c6e3a5f6d370cc841d621d5fa4d5d834 (patch) | |
tree | 80f645c85bbc012d3b1b45ab66ee7dd8938de49b | |
parent | 2ac2ed5f2dfc97ae9ed9f446ad6e064fa821ef6d (diff) |
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>
-rw-r--r-- | drivers/isdn/gigaset/asyncdata.c | 2 | ||||
-rw-r--r-- | drivers/isdn/gigaset/gigaset.h | 4 | ||||
-rw-r--r-- | drivers/isdn/gigaset/isocdata.c | 44 |
3 files changed, 35 insertions, 15 deletions
diff --git a/drivers/isdn/gigaset/asyncdata.c b/drivers/isdn/gigaset/asyncdata.c index ccb2a7b7c41d..e913beb63f24 100644 --- a/drivers/isdn/gigaset/asyncdata.c +++ b/drivers/isdn/gigaset/asyncdata.c | |||
@@ -40,6 +40,8 @@ static inline int muststuff(unsigned char c) | |||
40 | * Append received bytes to the command response buffer and forward them | 40 | * Append received bytes to the command response buffer and forward them |
41 | * line by line to the response handler. Exit whenever a mode/state change | 41 | * line by line to the response handler. Exit whenever a mode/state change |
42 | * might have occurred. | 42 | * might have occurred. |
43 | * Note: Received lines may be terminated by CR, LF, or CR LF, which will be | ||
44 | * removed before passing the line to the response handler. | ||
43 | * Return value: | 45 | * Return value: |
44 | * number of processed bytes | 46 | * number of processed bytes |
45 | */ | 47 | */ |
diff --git a/drivers/isdn/gigaset/gigaset.h b/drivers/isdn/gigaset/gigaset.h index e963a6c2e86d..c9ccf7de2275 100644 --- a/drivers/isdn/gigaset/gigaset.h +++ b/drivers/isdn/gigaset/gigaset.h | |||
@@ -38,7 +38,7 @@ | |||
38 | #define GIG_COMPAT {0, 4, 0, 0} | 38 | #define GIG_COMPAT {0, 4, 0, 0} |
39 | 39 | ||
40 | #define MAX_REC_PARAMS 10 /* Max. number of params in response string */ | 40 | #define MAX_REC_PARAMS 10 /* Max. number of params in response string */ |
41 | #define MAX_RESP_SIZE 512 /* Max. size of a response string */ | 41 | #define MAX_RESP_SIZE 511 /* Max. size of a response string */ |
42 | 42 | ||
43 | #define MAX_EVENTS 64 /* size of event queue */ | 43 | #define MAX_EVENTS 64 /* size of event queue */ |
44 | 44 | ||
@@ -498,7 +498,7 @@ struct cardstate { | |||
498 | spinlock_t ev_lock; | 498 | spinlock_t ev_lock; |
499 | 499 | ||
500 | /* current modem response */ | 500 | /* current modem response */ |
501 | unsigned char respdata[MAX_RESP_SIZE]; | 501 | unsigned char respdata[MAX_RESP_SIZE+1]; |
502 | unsigned cbytes; | 502 | unsigned cbytes; |
503 | 503 | ||
504 | /* private data of hardware drivers */ | 504 | /* private data of hardware drivers */ |
diff --git a/drivers/isdn/gigaset/isocdata.c b/drivers/isdn/gigaset/isocdata.c index 85394a6ebae8..16fd3bd48883 100644 --- a/drivers/isdn/gigaset/isocdata.c +++ b/drivers/isdn/gigaset/isocdata.c | |||
@@ -905,29 +905,49 @@ void gigaset_isoc_receive(unsigned char *src, unsigned count, | |||
905 | 905 | ||
906 | /* == data input =========================================================== */ | 906 | /* == data input =========================================================== */ |
907 | 907 | ||
908 | /* process a block of received bytes in command mode (mstate != MS_LOCKED) | ||
909 | * Append received bytes to the command response buffer and forward them | ||
910 | * line by line to the response handler. | ||
911 | * Note: Received lines may be terminated by CR, LF, or CR LF, which will be | ||
912 | * removed before passing the line to the response handler. | ||
913 | */ | ||
908 | static void cmd_loop(unsigned char *src, int numbytes, struct inbuf_t *inbuf) | 914 | static void cmd_loop(unsigned char *src, int numbytes, struct inbuf_t *inbuf) |
909 | { | 915 | { |
910 | struct cardstate *cs = inbuf->cs; | 916 | struct cardstate *cs = inbuf->cs; |
911 | unsigned cbytes = cs->cbytes; | 917 | unsigned cbytes = cs->cbytes; |
918 | unsigned char c; | ||
912 | 919 | ||
913 | while (numbytes--) { | 920 | while (numbytes--) { |
914 | /* copy next character, check for end of line */ | 921 | c = *src++; |
915 | switch (cs->respdata[cbytes] = *src++) { | 922 | switch (c) { |
916 | case '\r': | ||
917 | case '\n': | 923 | case '\n': |
918 | /* end of line */ | 924 | if (cbytes == 0 && cs->respdata[0] == '\r') { |
919 | gig_dbg(DEBUG_TRANSCMD, "%s: End of Command (%d Bytes)", | 925 | /* collapse LF with preceding CR */ |
920 | __func__, cbytes); | 926 | cs->respdata[0] = 0; |
921 | if (cbytes >= MAX_RESP_SIZE - 1) | 927 | break; |
922 | dev_warn(cs->dev, "response too large\n"); | 928 | } |
929 | /* --v-- fall through --v-- */ | ||
930 | case '\r': | ||
931 | /* end of message line, pass to response handler */ | ||
932 | if (cbytes >= MAX_RESP_SIZE) { | ||
933 | dev_warn(cs->dev, "response too large (%d)\n", | ||
934 | cbytes); | ||
935 | cbytes = MAX_RESP_SIZE; | ||
936 | } | ||
923 | cs->cbytes = cbytes; | 937 | cs->cbytes = cbytes; |
938 | gigaset_dbg_buffer(DEBUG_TRANSCMD, "received response", | ||
939 | cbytes, cs->respdata); | ||
924 | gigaset_handle_modem_response(cs); | 940 | gigaset_handle_modem_response(cs); |
925 | cbytes = 0; | 941 | cbytes = 0; |
942 | |||
943 | /* store EOL byte for CRLF collapsing */ | ||
944 | cs->respdata[0] = c; | ||
926 | break; | 945 | break; |
927 | default: | 946 | default: |
928 | /* advance in line buffer, checking for overflow */ | 947 | /* append to line buffer if possible */ |
929 | if (cbytes < MAX_RESP_SIZE - 1) | 948 | if (cbytes < MAX_RESP_SIZE) |
930 | cbytes++; | 949 | cs->respdata[cbytes] = c; |
950 | cbytes++; | ||
931 | } | 951 | } |
932 | } | 952 | } |
933 | 953 | ||
@@ -958,8 +978,6 @@ void gigaset_isoc_input(struct inbuf_t *inbuf) | |||
958 | numbytes, src); | 978 | numbytes, src); |
959 | gigaset_if_receive(inbuf->cs, src, numbytes); | 979 | gigaset_if_receive(inbuf->cs, src, numbytes); |
960 | } else { | 980 | } else { |
961 | gigaset_dbg_buffer(DEBUG_CMD, "received response", | ||
962 | numbytes, src); | ||
963 | cmd_loop(src, numbytes, inbuf); | 981 | cmd_loop(src, numbytes, inbuf); |
964 | } | 982 | } |
965 | 983 | ||