int DecodeMPLS(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint32_t len, PacketQueue *pq) { uint32_t shim; int label; int event = 0; StatsIncr(tv, dtv->counter_mpls); do { if (len < MPLS_HEADER_LEN) { ENGINE_SET_INVALID_EVENT(p, MPLS_HEADER_TOO_SMALL); return TM_ECODE_FAILED; } memcpy(&shim, pkt, sizeof(shim)); pkt += MPLS_HEADER_LEN; len -= MPLS_HEADER_LEN; } while (MPLS_BOTTOM(shim) == 0); label = MPLS_LABEL(shim); if (label == MPLS_LABEL_IPV4) { if (len > USHRT_MAX) { return TM_ECODE_FAILED; } return DecodeIPV4(tv, dtv, p, pkt, len, pq); } else if (label == MPLS_LABEL_ROUTER_ALERT) { /* Not valid at the bottom of the stack. */ event = MPLS_BAD_LABEL_ROUTER_ALERT; } else if (label == MPLS_LABEL_IPV6) { if (len > USHRT_MAX) { return TM_ECODE_FAILED; } return DecodeIPV6(tv, dtv, p, pkt, len, pq); } else if (label == MPLS_LABEL_NULL) { /* Shouldn't appear on the wire. */ event = MPLS_BAD_LABEL_IMPLICIT_NULL; } else if (label < MPLS_MAX_RESERVED_LABEL) { event = MPLS_BAD_LABEL_RESERVED; } if (event) { goto end; } // Make sure we still have enough data. While we only need 1 byte to test // for IPv4 and IPv4, we need for to check for ethernet. if (len < MPLS_PW_LEN) { ENGINE_SET_INVALID_EVENT(p, MPLS_PKT_TOO_SMALL); return TM_ECODE_FAILED; } /* Best guess at inner packet. */ switch (pkt[0] >> 4) { case MPLS_PROTO_IPV4: if (len > USHRT_MAX) { return TM_ECODE_FAILED; } DecodeIPV4(tv, dtv, p, pkt, len, pq); break; case MPLS_PROTO_IPV6: if (len > USHRT_MAX) { return TM_ECODE_FAILED; } DecodeIPV6(tv, dtv, p, pkt, len, pq); break; case MPLS_PROTO_ETHERNET_PW: DecodeEthernet(tv, dtv, p, pkt + MPLS_PW_LEN, len - MPLS_PW_LEN, pq); break; default: ENGINE_SET_INVALID_EVENT(p, MPLS_UNKNOWN_PAYLOAD_TYPE); return TM_ECODE_OK; } end: if (event) { ENGINE_SET_EVENT(p, event); } return TM_ECODE_OK; }
int DecodeMPLS(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq) { uint32_t shim; int label; int event = 0; StatsIncr(tv, dtv->counter_mpls); do { if (len < MPLS_HEADER_LEN) { ENGINE_SET_INVALID_EVENT(p, MPLS_HEADER_TOO_SMALL); return TM_ECODE_FAILED; } shim = *(uint32_t *)pkt; pkt += MPLS_HEADER_LEN; len -= MPLS_HEADER_LEN; } while (MPLS_BOTTOM(shim) == 0); label = MPLS_LABEL(shim); if (label == MPLS_LABEL_IPV4) { return DecodeIPV4(tv, dtv, p, pkt, len, pq); } else if (label == MPLS_LABEL_ROUTER_ALERT) { /* Not valid at the bottom of the stack. */ event = MPLS_BAD_LABEL_ROUTER_ALERT; } else if (label == MPLS_LABEL_IPV6) { return DecodeIPV6(tv, dtv, p, pkt, len, pq); } else if (label == MPLS_LABEL_NULL) { /* Shouldn't appear on the wire. */ event = MPLS_BAD_LABEL_IMPLICIT_NULL; } else if (label < MPLS_MAX_RESERVED_LABEL) { event = MPLS_BAD_LABEL_RESERVED; } if (event) { goto end; } /* Best guess at inner packet. */ switch (pkt[0] >> 4) { case MPLS_PROTO_IPV4: DecodeIPV4(tv, dtv, p, pkt, len, pq); break; case MPLS_PROTO_IPV6: DecodeIPV6(tv, dtv, p, pkt, len, pq); break; case MPLS_PROTO_ETHERNET_PW: DecodeEthernet(tv, dtv, p, pkt + MPLS_PW_LEN, len - MPLS_PW_LEN, pq); break; default: ENGINE_SET_INVALID_EVENT(p, MPLS_UNKNOWN_PAYLOAD_TYPE); return TM_ECODE_OK; } end: if (event) { ENGINE_SET_EVENT(p, event); } return TM_ECODE_OK; }