Hi,
As some of you may have noticed, this week was my Linux-IrDA
week (next week I'll be back on Wireless LANs).
While testing things around, I did notice a few limitations
and bugs in irdadump :
o Ultra decoding is not supported
o Obex decoding can mix up command and response frames
o Obex try to decode frames containing no Obex payload
o If a IAS query fails, we assume that all further connections
to the IAS sockets are TTP connection (this one was funny).
o Obex type header not supported
o Obex target header not supported
o Don't fully decode success frames
o Don't handle connect frames that don't have parameters
o Lenght miscalculated on connect frames (probably alignement)
Patch attached (of course) ;-)
Voila...
Jean
diff -u -p irda-utils-0.9.10/irdadump/src/irdadump.d1.h
irda-utils-0.9.10/irdadump/src/irdadump.h
--- irda-utils-0.9.10/irdadump/src/irdadump.d1.h Wed Nov 8 11:49:46 2000
+++ irda-utils-0.9.10/irdadump/src/irdadump.h Wed Nov 8 11:54:23 2000
@@ -192,8 +192,9 @@ struct lsap_state {
guint8 dlsap_sel; /* Destination logical service access point */
};
-inline void parse_obex(struct lsap_state *conn, GNetBuf *buf, GString *str);
-inline void parse_irlmp(GNetBuf *buf, GString *str, int type);
+inline void parse_obex(struct lsap_state *conn, GNetBuf *buf, GString *str,
+ int cmd);
+inline void parse_irlmp(GNetBuf *buf, GString *str, int type, int cmd);
inline void parse_ui_irlmp(GNetBuf *buf, GString *str, int type);
#endif /* IRDADUMP_H */
diff -u -p irda-utils-0.9.10/irdadump/src/irdadump.d1.c
irda-utils-0.9.10/irdadump/src/irdadump.c
--- irda-utils-0.9.10/irdadump/src/irdadump.d1.c Wed Nov 8 11:49:29 2000
+++ irda-utils-0.9.10/irdadump/src/irdadump.c Wed Nov 8 11:50:43 2000
@@ -323,7 +323,7 @@ inline void parse_i_frame(guint8 caddr,
/* Check if we should print IrLMP information */
if (config_print_irlmp)
- parse_irlmp(buf, str, type);
+ parse_irlmp(buf, str, type, cmd);
if (config_print_lost_frames) {
diff -u -p irda-utils-0.9.10/irdadump/src/irlmp.d1.c
irda-utils-0.9.10/irdadump/src/irlmp.c
--- irda-utils-0.9.10/irdadump/src/irlmp.d1.c Wed Nov 8 11:49:41 2000
+++ irda-utils-0.9.10/irdadump/src/irlmp.c Wed Nov 8 17:40:35 2000
@@ -75,6 +75,8 @@ inline void parse_iriap_command(GNetBuf
last_ias.ttp = 1;
else
last_ias.ttp = 0;
+ /* Reset to undefined (handle IAS failures properly) */
+ last_ias.lsap_sel = LSAP_ANY;
/* Check if this is a OBEX lookup */
if (strstr(name, "OBEX"))
@@ -227,7 +229,7 @@ inline void parse_iriap_response(GNetBuf
* Parse IrLMP frame
*
*/
-inline void parse_irlmp(GNetBuf *buf, GString *str, int type)
+inline void parse_irlmp(GNetBuf *buf, GString *str, int type, int cmd)
{
guint8 slsap_sel, dlsap_sel;
int ctrl;
@@ -325,7 +327,7 @@ inline void parse_irlmp(GNetBuf *buf, GS
if (conn[i].valid && conn[i].ttp)
parse_irttp(buf, str);
if (conn[i].valid && conn[i].obex)
- parse_obex(&conn[0], buf, str);
+ parse_obex(&conn[0], buf, str, cmd);
#if 0
if (conn[i].valid && conn[i].ircomm)
parse_ircomm(&conn[0], buf, str);
@@ -356,4 +358,13 @@ inline void parse_ui_irlmp(GNetBuf *buf,
g_string_sprintfa(str, "LM slsap=%02x dlsap=%02x ", slsap_sel,
dlsap_sel);
+
+ /* Let's see if it's Ultra, and decode it - Jean II */
+ if((slsap_sel == 0x70) && (dlsap_sel == 0x70))
+ {
+ int upid = buf->data[0] & 0x7F;
+ g_netbuf_pull(buf, 1);
+
+ g_string_sprintfa(str, " Ultra-PID=%02x ", upid);
+ }
}
diff -u -p irda-utils-0.9.10/irdadump/src/obex.d1.h
irda-utils-0.9.10/irdadump/src/obex.h
--- irda-utils-0.9.10/irdadump/src/obex.d1.h Wed Nov 8 11:49:21 2000
+++ irda-utils-0.9.10/irdadump/src/obex.h Wed Nov 8 11:50:03 2000
@@ -55,10 +55,11 @@
#define HEADER_COUNT 0xc0
#define HEADER_NAME 0x01 /* - */
-#define HEADER_TYPE 0x42
+#define HEADER_TYPE 0x42 /* - */
#define HEADER_TIME 0x44
#define HEADER_LENGTH 0xc3 /* - */
#define HEADER_DESCRIPTION 0x05 /* - */
+#define HEADER_TARGET 0x46 /* - */
#define HEADER_BODY 0x48 /* - */
#define HEADER_BODY_END 0x49 /* - */
@@ -77,6 +78,12 @@ struct obex_connect_frame {
guint8 version;
guint8 flags;
guint16 mtu;
+} __attribute__((packed));
+
+/* Minimal Obex header */
+struct obex_minimal_frame {
+ guint8 opcode;
+ guint16 len;
} __attribute__((packed));
#endif
diff -u -p irda-utils-0.9.10/irdadump/src/obex.d1.c
irda-utils-0.9.10/irdadump/src/obex.c
--- irda-utils-0.9.10/irdadump/src/obex.d1.c Wed Nov 8 11:49:17 2000
+++ irda-utils-0.9.10/irdadump/src/obex.c Wed Nov 8 17:15:57 2000
@@ -48,7 +48,7 @@ void unicode_to_char(guint8 *buf)
*
*
*/
-int parse_obex_header(GNetBuf *buf, GString *str)
+int parse_obex_header(GNetBuf *buf, GString *str, int istext)
{
char string[255];
guint32 tmp_int;
@@ -69,14 +69,19 @@ int parse_obex_header(GNetBuf *buf, GStr
len += tmp_short;
/* g_print("%s ", string);fflush(stdout); */
- g_string_sprintfa(str, "%s ", string);
+ g_string_sprintfa(str, "\"%s\" ", string);
break;
case OBEX_BYTE_STREAM:
/* g_print("OBEX_BYTE_STREAM");fflush(stdout); */
memcpy(&tmp_short, buf->data+1, 2); /* Align value */
tmp_short = GINT16_FROM_BE(tmp_short) - 3;
len += tmp_short + 3;
- g_string_append(str, "[byte stream]");
+ if(istext) {
+ memcpy(string, buf->data+3, tmp_short);
+ string[tmp_short] = '\0';
+ g_string_sprintfa(str, "\"%s\" ", string);
+ } else
+ g_string_sprintfa(str, "[%d bytes] ", tmp_short);
break;
case OBEX_BYTE:
/* g_print("OBEX_BYTE");fflush(stdout); */
@@ -106,16 +111,18 @@ int parse_obex_header(GNetBuf *buf, GStr
*/
inline void parse_obex_headers(GNetBuf *buf, GString *str)
{
+ struct obex_minimal_frame *frame;
int final;
guint16 size;
int len;
+ frame = (struct obex_minimal_frame *) buf->data;
+
/* We know it's a put frame, but we have to check if it's the final */
- final = buf->data[0] & OBEX_FINAL;
+ final = frame->opcode & OBEX_FINAL;
/* Length of this frame */
- memcpy(&size, buf+1, 2);
- size = ntohs(size);
+ size = ntohs(frame->len);
/* Remove the OBEX common header */
g_netbuf_pull(buf, 3);
@@ -129,27 +136,35 @@ inline void parse_obex_headers(GNetBuf *
switch (buf->data[0]) {
case HEADER_NAME:
g_string_append(str, "Name=");
- len = parse_obex_header(buf, str);
+ len = parse_obex_header(buf, str, 0);
break;
case HEADER_DESCRIPTION:
g_string_append(str, "Description=");
- len = parse_obex_header(buf, str);
+ len = parse_obex_header(buf, str, 0);
break;
case HEADER_LENGTH:
g_string_append(str, "Lenght=");
- len = parse_obex_header(buf, str);
+ len = parse_obex_header(buf, str, 0);
+ break;
+ case HEADER_TYPE:
+ g_string_append(str, "Type=");
+ len = parse_obex_header(buf, str, 1);
+ break;
+ case HEADER_TARGET:
+ g_string_append(str, "Target=");
+ len = parse_obex_header(buf, str, 1);
break;
case HEADER_BODY:
g_string_append(str, "body=");
- len = parse_obex_header(buf, str);
+ len = parse_obex_header(buf, str, 0);
break;
case HEADER_BODY_END:
- g_string_append(str, "body end=");
- len = parse_obex_header(buf, str);
+ g_string_append(str, "body-end=");
+ len = parse_obex_header(buf, str, 0);
break;
default:
g_string_append(str, "custom=");
- len = parse_obex_header(buf, str);
+ len = parse_obex_header(buf, str, 0);
break;
}
/* g_print("len=%d\n", len);fflush(stdout); */
@@ -168,13 +183,49 @@ inline void parse_obex_connect(GNetBuf *
frame = (struct obex_connect_frame *) buf->data;
length = ntohs(frame->len);
- version = frame->version;
- flags = frame->flags;
- mtu = ntohs(frame->mtu);
-
- g_string_sprintfa(str, "CONNECT len=%d ver=%d.%d flags=%d mtu=%d ",
- length, ((version & 0xf0) >> 4), version & 0x0f,
- flags, mtu);
+
+ /* Check if it contains connection setup parameters - Jean II */
+ if(length == 7) {
+ version = frame->version;
+ flags = frame->flags;
+ mtu = ntohs(frame->mtu);
+
+ g_string_sprintfa(str,
+ "CONNECT len=%d ver=%d.%d flags=%d mtu=%d ",
+ length, ((version & 0xf0) >> 4),
+ version & 0x0f, flags, mtu);
+ } else
+ g_string_sprintfa(str, "CONNECT len=%d ", length);
+}
+
+/*
+ * The first success frame contains the negociated Obex parameters
+ * Jean II
+ */
+inline void parse_obex_success(GNetBuf *buf, GString *str)
+{
+ struct obex_connect_frame *frame;
+ guint16 length;
+ guint8 version;
+ int flags;
+ guint16 mtu;
+
+ frame = (struct obex_connect_frame *) buf->data;
+
+ length = ntohs(frame->len);
+
+ /* Check if it contains connection setup parameters */
+ if(length == 7) {
+ version = frame->version;
+ flags = frame->flags;
+ mtu = ntohs(frame->mtu);
+
+ g_string_sprintfa(str,
+ "SUCCESS len=%d ver=%d.%d flags=%d mtu=%d ",
+ length, ((version & 0xf0) >> 4),
+ version & 0x0f, flags, mtu);
+ } else
+ g_string_sprintfa(str, "SUCCESS len=%d ", length);
}
/*
@@ -183,9 +234,16 @@ inline void parse_obex_connect(GNetBuf *
* Parse OBEX commands and responses
*
*/
-inline void parse_obex(struct lsap_state *conn, GNetBuf *buf, GString *str)
+inline void parse_obex(struct lsap_state *conn, GNetBuf *buf, GString *str,
+ int cmd)
{
- guint8 opcode;
+ guint8 opcode;
+ int len;
+
+ /* Check for empty frames - Jean II */
+ len = g_netbuf_get_len(buf);
+ if(len == 0)
+ return;
/* g_print(__FUNCTION__);fflush(stdout); */
@@ -193,7 +251,8 @@ inline void parse_obex(struct lsap_state
opcode = buf->data[0] & ~OBEX_FINAL; /* Remove final bit */
- if (conn->obex_rsp) {
+ /* Check if it's a command or response frame - Jean II */
+ if (!cmd) {
switch (opcode) {
case OBEX_CONTINUE:
g_string_append(str, "CONTINUE ");
@@ -202,7 +261,7 @@ inline void parse_obex(struct lsap_state
g_string_append(str, "SWITCH_PRO ");
break;
case OBEX_SUCCESS:
- g_string_append(str, "SUCCESS ");
+ parse_obex_success(buf, str);
break;
case OBEX_CREATED:
g_string_append(str, "CREATED ");
@@ -221,7 +280,7 @@ inline void parse_obex(struct lsap_state
opcode);
break;
}
- /* Next frame is a command */
+ /* Next frame is a command (maybe) */
conn->obex_rsp = 0;
} else {
switch (opcode) {
@@ -255,7 +314,7 @@ inline void parse_obex(struct lsap_state
opcode);
break;
}
- /* Next frame should be a response */
+ /* Next frame should be a response (maybe) */
conn->obex_rsp = 1;
}
}