#include "interface.h"
#include "addrtoname.h"
#include "ethertype.h"
+#include "llc.h"
#include "nlpid.h"
#include "extract.h"
#include "oui.h"
{ 0, NULL }
};
-/* Finds out Q.922 address length, DLCI and flags. Returns 0 on success
+/* Finds out Q.922 address length, DLCI and flags. Returns 1 on success,
+ * 0 on invalid address, -1 on truncated packet
* save the flags dep. on address length
*/
-static int parse_q922_addr(const u_char *p, u_int *dlci,
- u_int *addr_len, uint8_t *flags)
+static int parse_q922_addr(netdissect_options *ndo,
+ const u_char *p, u_int *dlci,
+ u_int *addr_len, uint8_t *flags, u_int length)
{
- if ((p[0] & FR_EA_BIT))
+ if (!ND_TTEST(p[0]) || length < 1)
return -1;
+ if ((p[0] & FR_EA_BIT))
+ return 0;
+ if (!ND_TTEST(p[1]) || length < 2)
+ return -1;
*addr_len = 2;
*dlci = ((p[0] & 0xFC) << 2) | ((p[1] & 0xF0) >> 4);
flags[3] = 0;
if (p[1] & FR_EA_BIT)
- return 0; /* 2-byte Q.922 address */
+ return 1; /* 2-byte Q.922 address */
p += 2;
+ length -= 2;
+ if (!ND_TTEST(p[0]) || length < 1)
+ return -1;
(*addr_len)++; /* 3- or 4-byte Q.922 address */
if ((p[0] & FR_EA_BIT) == 0) {
*dlci = (*dlci << 7) | (p[0] >> 1);
(*addr_len)++; /* 4-byte Q.922 address */
p++;
+ length--;
}
+ if (!ND_TTEST(p[0]) || length < 1)
+ return -1;
if ((p[0] & FR_EA_BIT) == 0)
- return -1; /* more than 4 bytes of Q.922 address? */
+ return 0; /* more than 4 bytes of Q.922 address? */
flags[3] = p[0] & 0x02;
*dlci = (*dlci << 6) | (p[0] >> 2);
- return 0;
+ return 1;
}
-char *q922_string(const u_char *p) {
+char *q922_string(netdissect_options *ndo, const u_char *p, u_int length) {
static u_int dlci, addr_len;
static uint8_t flags[4];
static char buffer[sizeof("DLCI xxxxxxxxxx")];
memset(buffer, 0, sizeof(buffer));
- if (parse_q922_addr(p, &dlci, &addr_len, flags) == 0){
+ if (parse_q922_addr(ndo, p, &dlci, &addr_len, flags, length) == 1){
snprintf(buffer, sizeof(buffer), "DLCI %u", dlci);
}
may optionally be increased to three or four octets.
*/
-static u_int
-fr_hdrlen(const u_char *p, u_int addr_len)
-{
- if (!p[addr_len + 1] /* pad exist */)
- return addr_len + 1 /* UI */ + 1 /* pad */ + 1 /* NLPID */;
- else
- return addr_len + 1 /* UI */ + 1 /* NLPID */;
-}
-
static void
fr_hdr_print(netdissect_options *ndo,
int length, u_int addr_len, u_int dlci, uint8_t *flags, uint16_t nlpid)
fr_print(netdissect_options *ndo,
register const u_char *p, u_int length)
{
+ int ret;
uint16_t extracted_ethertype;
u_int dlci;
u_int addr_len;
u_int hdr_len;
uint8_t flags[4];
- if (parse_q922_addr(p, &dlci, &addr_len, flags)) {
+ ret = parse_q922_addr(ndo, p, &dlci, &addr_len, flags, length);
+ if (ret == -1)
+ goto trunc;
+ if (ret == 0) {
ND_PRINT((ndo, "Q.922, invalid address"));
return 0;
}
- ND_TCHECK2(*p, addr_len+1+1);
- hdr_len = fr_hdrlen(p, addr_len);
- ND_TCHECK2(*p, hdr_len);
+ ND_TCHECK(p[addr_len]);
+ if (length < addr_len + 1)
+ goto trunc;
- if (p[addr_len] != 0x03 && dlci != 0) {
-
- /* lets figure out if we have cisco style encapsulation: */
- extracted_ethertype = EXTRACT_16BITS(p+addr_len);
-
- if (ndo->ndo_eflag)
- fr_hdr_print(ndo, length, addr_len, dlci, flags, extracted_ethertype);
-
- if (ethertype_print(ndo, extracted_ethertype,
- p+addr_len+ETHERTYPE_LEN,
- length-addr_len-ETHERTYPE_LEN,
- length-addr_len-ETHERTYPE_LEN) == 0)
- /* ether_type not known, probably it wasn't one */
- ND_PRINT((ndo, "UI %02x! ", p[addr_len]));
- else
- return hdr_len;
+ if (p[addr_len] != LLC_UI && dlci != 0) {
+ /*
+ * Let's figure out if we have Cisco-style encapsulation,
+ * with an Ethernet type (Cisco HDLC type?) following the
+ * address.
+ */
+ if (!ND_TTEST2(p[addr_len], 2) || length < addr_len + 2) {
+ /* no Ethertype */
+ ND_PRINT((ndo, "UI %02x! ", p[addr_len]));
+ } else {
+ extracted_ethertype = EXTRACT_16BITS(p+addr_len);
+
+ if (ndo->ndo_eflag)
+ fr_hdr_print(ndo, length, addr_len, dlci,
+ flags, extracted_ethertype);
+
+ if (ethertype_print(ndo, extracted_ethertype,
+ p+addr_len+ETHERTYPE_LEN,
+ length-addr_len-ETHERTYPE_LEN,
+ length-addr_len-ETHERTYPE_LEN) == 0)
+ /* ether_type not known, probably it wasn't one */
+ ND_PRINT((ndo, "UI %02x! ", p[addr_len]));
+ else
+ return addr_len + 2;
+ }
}
- if (!p[addr_len + 1]) { /* pad byte should be used with 3-byte Q.922 */
+ ND_TCHECK(p[addr_len+1]);
+ if (length < addr_len + 2)
+ goto trunc;
+
+ if (p[addr_len + 1] == 0) {
+ /*
+ * Assume a pad byte after the control (UI) byte.
+ * A pad byte should only be used with 3-byte Q.922.
+ */
if (addr_len != 3)
ND_PRINT((ndo, "Pad! "));
- } else if (addr_len == 3)
- ND_PRINT((ndo, "No pad! "));
+ hdr_len = addr_len + 1 /* UI */ + 1 /* pad */ + 1 /* NLPID */;
+ } else {
+ /*
+ * Not a pad byte.
+ * A pad byte should be used with 3-byte Q.922.
+ */
+ if (addr_len == 3)
+ ND_PRINT((ndo, "No pad! "));
+ hdr_len = addr_len + 1 /* UI */ + 1 /* NLPID */;
+ }
+ ND_TCHECK(p[hdr_len - 1]);
+ if (length < hdr_len)
+ goto trunc;
nlpid = p[hdr_len - 1];
if (ndo->ndo_eflag)