Commit 38fea30d authored by Jean Tourrilhes's avatar Jean Tourrilhes Committed by Linus Torvalds

irda update 5/6:

        o [FEATURE] Fix some comments
        o [FEATURE] printk warning when we detect buggy QoS from peer
        o [CORRECT] Workaround NULL QoS bitfields
        o [CORRECT] Workaround oversized QoS bitfields
        o [FEATURE] Add sysctl "max_tx_window" to limit IrLAP Tx Window
parent d2dfa7d9
...@@ -35,7 +35,7 @@ ...@@ -35,7 +35,7 @@
#define NET_IRDA 412 /* Random number */ #define NET_IRDA 412 /* Random number */
enum { DISCOVERY=1, DEVNAME, DEBUG, FAST_POLL, DISCOVERY_SLOTS, enum { DISCOVERY=1, DEVNAME, DEBUG, FAST_POLL, DISCOVERY_SLOTS,
DISCOVERY_TIMEOUT, SLOT_TIMEOUT, MAX_BAUD_RATE, MIN_TX_TURN_TIME, DISCOVERY_TIMEOUT, SLOT_TIMEOUT, MAX_BAUD_RATE, MIN_TX_TURN_TIME,
MAX_TX_DATA_SIZE, MAX_NOREPLY_TIME, WARN_NOREPLY_TIME, MAX_TX_DATA_SIZE, MAX_TX_WINDOW, MAX_NOREPLY_TIME, WARN_NOREPLY_TIME,
LAP_KEEPALIVE_TIME }; LAP_KEEPALIVE_TIME };
extern int sysctl_discovery; extern int sysctl_discovery;
...@@ -48,6 +48,7 @@ extern char sysctl_devname[]; ...@@ -48,6 +48,7 @@ extern char sysctl_devname[];
extern int sysctl_max_baud_rate; extern int sysctl_max_baud_rate;
extern int sysctl_min_tx_turn_time; extern int sysctl_min_tx_turn_time;
extern int sysctl_max_tx_data_size; extern int sysctl_max_tx_data_size;
extern int sysctl_max_tx_window;
extern int sysctl_max_noreply_time; extern int sysctl_max_noreply_time;
extern int sysctl_warn_noreply_time; extern int sysctl_warn_noreply_time;
extern int sysctl_lap_keepalive_time; extern int sysctl_lap_keepalive_time;
...@@ -69,6 +70,8 @@ static int max_min_tx_turn_time = 10000; /* See qos.c - IrLAP spec */ ...@@ -69,6 +70,8 @@ static int max_min_tx_turn_time = 10000; /* See qos.c - IrLAP spec */
static int min_min_tx_turn_time = 0; static int min_min_tx_turn_time = 0;
static int max_max_tx_data_size = 2048; /* See qos.c - IrLAP spec */ static int max_max_tx_data_size = 2048; /* See qos.c - IrLAP spec */
static int min_max_tx_data_size = 64; static int min_max_tx_data_size = 64;
static int max_max_tx_window = 7; /* See qos.c - IrLAP spec */
static int min_max_tx_window = 1;
static int max_max_noreply_time = 40; /* See qos.c - IrLAP spec */ static int max_max_noreply_time = 40; /* See qos.c - IrLAP spec */
static int min_max_noreply_time = 3; static int min_max_noreply_time = 3;
static int max_warn_noreply_time = 3; /* 3s == standard */ static int max_warn_noreply_time = 3; /* 3s == standard */
...@@ -125,6 +128,9 @@ static ctl_table irda_table[] = { ...@@ -125,6 +128,9 @@ static ctl_table irda_table[] = {
{ MAX_TX_DATA_SIZE, "max_tx_data_size", &sysctl_max_tx_data_size, { MAX_TX_DATA_SIZE, "max_tx_data_size", &sysctl_max_tx_data_size,
sizeof(int), 0644, NULL, &proc_dointvec_minmax, &sysctl_intvec, sizeof(int), 0644, NULL, &proc_dointvec_minmax, &sysctl_intvec,
NULL, &min_max_tx_data_size, &max_max_tx_data_size }, NULL, &min_max_tx_data_size, &max_max_tx_data_size },
{ MAX_TX_WINDOW, "max_tx_window", &sysctl_max_tx_window,
sizeof(int), 0644, NULL, &proc_dointvec_minmax, &sysctl_intvec,
NULL, &min_max_tx_window, &max_max_tx_window },
{ MAX_NOREPLY_TIME, "max_noreply_time", &sysctl_max_noreply_time, { MAX_NOREPLY_TIME, "max_noreply_time", &sysctl_max_noreply_time,
sizeof(int), 0644, NULL, &proc_dointvec_minmax, &sysctl_intvec, sizeof(int), 0644, NULL, &proc_dointvec_minmax, &sysctl_intvec,
NULL, &min_max_noreply_time, &max_max_noreply_time }, NULL, &min_max_noreply_time, &max_max_noreply_time },
......
...@@ -200,11 +200,13 @@ static int irda_extract_integer(void *self, __u8 *buf, int len, __u8 pi, ...@@ -200,11 +200,13 @@ static int irda_extract_integer(void *self, __u8 *buf, int len, __u8 pi,
{ {
irda_param_t p; irda_param_t p;
int n = 0; int n = 0;
int extract_len; /* Real lenght we extract */
int err; int err;
p.pi = pi; /* In case handler needs to know */ p.pi = pi; /* In case handler needs to know */
p.pl = buf[1]; /* Extract lenght of value */ p.pl = buf[1]; /* Extract lenght of value */
p.pv.i = 0; /* Clear value */ p.pv.i = 0; /* Clear value */
extract_len = p.pl; /* Default : extract all */
/* Check if buffer is long enough for parsing */ /* Check if buffer is long enough for parsing */
if (len < (2+p.pl)) { if (len < (2+p.pl)) {
...@@ -217,18 +219,30 @@ static int irda_extract_integer(void *self, __u8 *buf, int len, __u8 pi, ...@@ -217,18 +219,30 @@ static int irda_extract_integer(void *self, __u8 *buf, int len, __u8 pi,
/* /*
* Check that the integer length is what we expect it to be. If the * Check that the integer length is what we expect it to be. If the
* handler want a 16 bits integer then a 32 bits is not good enough * handler want a 16 bits integer then a 32 bits is not good enough
* PV_INTEGER means that the handler is flexible.
*/ */
if (((type & PV_MASK) != PV_INTEGER) && ((type & PV_MASK) != p.pl)) { if (((type & PV_MASK) != PV_INTEGER) && ((type & PV_MASK) != p.pl)) {
ERROR("%s: invalid parameter length! " ERROR("%s: invalid parameter length! "
"Expected %d bytes, but value had %d bytes!\n", "Expected %d bytes, but value had %d bytes!\n",
__FUNCTION__, type & PV_MASK, p.pl); __FUNCTION__, type & PV_MASK, p.pl);
/* Skip parameter */ /* Most parameters are bit/byte fields or little endian,
return p.pl+2; * so it's ok to only extract a subset of it (the subset
* that the handler expect). This is necessary, as some
* broken implementations seems to add extra undefined bits.
* If the parameter is shorter than we expect or is big
* endian, we can't play those tricks. Jean II */
if((p.pl < (type & PV_MASK)) || (type & PV_BIG_ENDIAN)) {
/* Skip parameter */
return p.pl+2;
} else {
/* Extract subset of it, fallthrough */
extract_len = type & PV_MASK;
}
} }
switch (p.pl) { switch (extract_len) {
case 1: case 1:
n += irda_param_unpack(buf+2, "b", &p.pv.i); n += irda_param_unpack(buf+2, "b", &p.pv.i);
break; break;
......
...@@ -70,13 +70,18 @@ unsigned sysctl_min_tx_turn_time = 10; ...@@ -70,13 +70,18 @@ unsigned sysctl_min_tx_turn_time = 10;
* 1.2, chapt 5.3.2.1, p41). But, this number includes the LAP header * 1.2, chapt 5.3.2.1, p41). But, this number includes the LAP header
* (2 bytes), and CRC (32 bits at 4 Mb/s). So, for the I field (LAP * (2 bytes), and CRC (32 bits at 4 Mb/s). So, for the I field (LAP
* payload), that's only 2042 bytes. Oups ! * payload), that's only 2042 bytes. Oups !
* I've had trouble trouble transmitting 2048 bytes frames with USB * My nsc-ircc hardware has troubles receiving 2048 bytes frames at 4 Mb/s,
* dongles and nsc-ircc at 4 Mb/s, so adjust to 2042... I don't know * so adjust to 2042... I don't know if this bug applies only for 2048
* if this bug applies only for 2048 bytes frames or all negociated * bytes frames or all negociated frame sizes, but you can use the sysctl
* frame sizes, but all hardware seem to support "2048 bytes" frames. * to play with this value anyway.
* You can use the sysctl to play with this value anyway.
* Jean II */ * Jean II */
unsigned sysctl_max_tx_data_size = 2042; unsigned sysctl_max_tx_data_size = 2042;
/*
* Maximum transmit window, i.e. number of LAP frames between turn-around.
* This allow to override what the peer told us. Some peers are buggy and
* don't always support what they tell us.
* Jean II */
unsigned sysctl_max_tx_window = 7;
static int irlap_param_baud_rate(void *instance, irda_param_t *param, int get); static int irlap_param_baud_rate(void *instance, irda_param_t *param, int get);
static int irlap_param_link_disconnect(void *instance, irda_param_t *parm, static int irlap_param_link_disconnect(void *instance, irda_param_t *parm,
...@@ -184,7 +189,19 @@ int msb_index (__u16 word) ...@@ -184,7 +189,19 @@ int msb_index (__u16 word)
{ {
__u16 msb = 0x8000; __u16 msb = 0x8000;
int index = 15; /* Current MSB */ int index = 15; /* Current MSB */
/* Check for buggy peers.
* Note : there is a small probability that it could be us, but I
* would expect driver authors to catch that pretty early and be
* able to check precisely what's going on. If a end user sees this,
* it's very likely the peer. - Jean II */
if (word == 0) {
WARNING("%s(), Detected buggy peer, adjust null PV to 0x1!\n",
__FUNCTION__);
/* The only safe choice (we don't know the array size) */
word = 0x1;
}
while (msb) { while (msb) {
if (word & msb) if (word & msb)
break; /* Found it! */ break; /* Found it! */
...@@ -335,10 +352,14 @@ void irlap_adjust_qos_settings(struct qos_info *qos) ...@@ -335,10 +352,14 @@ void irlap_adjust_qos_settings(struct qos_info *qos)
/* /*
* Make sure the mintt is sensible. * Make sure the mintt is sensible.
* Main culprit : Ericsson T39. - Jean II
*/ */
if (sysctl_min_tx_turn_time > qos->min_turn_time.value) { if (sysctl_min_tx_turn_time > qos->min_turn_time.value) {
int i; int i;
WARNING("%s(), Detected buggy peer, adjust mtt to %dus!\n",
__FUNCTION__, sysctl_min_tx_turn_time);
/* We don't really need bits, but easier this way */ /* We don't really need bits, but easier this way */
i = value_highest_bit(sysctl_min_tx_turn_time, min_turn_times, i = value_highest_bit(sysctl_min_tx_turn_time, min_turn_times,
8, &qos->min_turn_time.bits); 8, &qos->min_turn_time.bits);
...@@ -398,6 +419,11 @@ void irlap_adjust_qos_settings(struct qos_info *qos) ...@@ -398,6 +419,11 @@ void irlap_adjust_qos_settings(struct qos_info *qos)
if (qos->data_size.value > sysctl_max_tx_data_size) if (qos->data_size.value > sysctl_max_tx_data_size)
/* Allow non discrete adjustement to avoid loosing capacity */ /* Allow non discrete adjustement to avoid loosing capacity */
qos->data_size.value = sysctl_max_tx_data_size; qos->data_size.value = sysctl_max_tx_data_size;
/*
* Override Tx window if user request it. - Jean II
*/
if (qos->window_size.value > sysctl_max_tx_window)
qos->window_size.value = sysctl_max_tx_window;
} }
/* /*
......
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