static void mpls_forward(struct mbuf *m) { struct sockaddr_mpls *smpls; struct mpls *mpls; struct route *cache_rt = &mplsforward_rt[mycpuid]; mpls_label_t label; struct ifnet *ifp; struct sockaddr *dst; int error; KASSERT(m->m_len >= sizeof(struct mpls), ("mpls_forward: mpls header not in one mbuf")); mpls = mtod(m, struct mpls *); label = MPLS_LABEL(ntohl(mpls->mpls_shim)); smpls = (struct sockaddr_mpls *) &cache_rt->ro_dst; if (cache_rt->ro_rt == NULL || smpls->smpls_label != label) { if (cache_rt->ro_rt != NULL) { RTFREE(cache_rt->ro_rt); cache_rt->ro_rt = NULL; } smpls->smpls_family = AF_MPLS; smpls->smpls_len = sizeof(struct sockaddr_mpls); smpls->smpls_label = htonl(label); rtalloc(cache_rt); if (cache_rt->ro_rt == NULL) { /* route not found */ return; } } ifp = cache_rt->ro_rt->rt_ifp; dst = cache_rt->ro_rt->rt_gateway; error = mpls_output(m, cache_rt->ro_rt); if (error) goto bad; error = (*ifp->if_output)(ifp, m, dst, cache_rt->ro_rt); if (error) goto bad; mplsstat.mplss_forwarded++; return; bad: m_freem(m); }
void mpls_hashfn(struct mbuf **mp, int hoff) { struct mbuf *m = *mp; struct mpls *mpls; mpls_label_t label; struct ifnet *ifp; mpls_lengthcheck(mp, hoff); if ((m = *mp) == NULL) return; mpls = mtodoff(m, struct mpls *, hoff); label = MPLS_LABEL(ntohl(mpls->mpls_shim)); ifp = m->m_pkthdr.rcvif; m->m_pkthdr.hash = MPLSP_MPORT_HASH(label, ifp->if_index); m->m_flags |= M_HASH; }
s32 mpls_echo_input(struct sk_buff * skb) { s32 err = 0; s32 temp = 0; u32 saddr = 0; struct timeval tv; mpls_echo_hdr * echo; struct ethhdr * eth ; struct fib_mg_res res ; struct iphdr *iph = skb->nh.iph; struct udphdr * udph = skb->h.uh; echo = (mpls_echo_hdr *)(skb->data + sizeof(struct udphdr)); skb_push(skb, iph->ihl * 4); err = fib_mg_lookup(if_dev_vrf(skb->dev)->vrf_id, iph->saddr, 32, &res); if (err) { printk("mpls_echo_input -fib_mg_lookup drop.\n"); goto drop; } temp = iph->daddr; iph->daddr = iph->saddr; if (res.dev) { iph->saddr = inet_select_addr(res.dev, res.nexthop, RT_SCOPE_LINK); } else { iph->saddr = temp; } iph->ttl = 255; iph->check = 0; iph->check = ip_fast_csum(iph, iph->ihl); echo->type = MPLS_ECHO_REPLY; do_gettimeofday(&tv); echo->t_rcvd[0] = htonl(tv.tv_sec+JAN_1970); echo->t_rcvd[1] = NTPFRAC(tv.tv_usec); temp = udph->source; udph->source = udph->dest; udph->dest = temp; if (MPLS_MODE_DO_NOT_REPLY == echo->mode) { printk("mpls_echo_input -not reply mode drop.\n"); goto drop; } if (MPLS_MODE_IPX_UDP_ALERT == echo->mode) { //Push router alert to ip option. } skb->protocol = htons(ETH_P_IP); if (FIB_MG_TYPE_FTN_BASIC == res.type) { if (MPLS_IMPLICIT_NULL != MPLS_LABEL(res.glabel)) { skb->protocol = htons(ETH_P_MPLS_UC) ; skb_push_label(skb, 128, res.glabel, 1); } if (2 == res.count) { if (MPLS_IMPLICIT_NULL != MPLS_LABEL(res.glabel2)) { skb->protocol = htons(ETH_P_MPLS_UC) ; skb_push_label(skb, 128, res.glabel2, 0); } } } else { skb->protocol = htons(ETH_P_MPLS_UC) ; skb_push_label(skb, 128, res.label, 1); if (MPLS_IMPLICIT_NULL != MPLS_LABEL(res.glabel)) { skb_push_label(skb, 128, res.glabel, 0); } if (3 == res.count) { if (MPLS_IMPLICIT_NULL != MPLS_LABEL(res.glabel2)) { skb->protocol = htons(ETH_P_MPLS_UC) ; skb_push_label(skb, 128, res.glabel2, 0); } } } if (MPLS_MODE_CTRL_CHANNEL == echo->mode) { skb_push_label(skb, 128, 1, 0); } skb->nh.raw = skb->data; skb->dev = res.dev; if (!res.neigh) { res.neigh = __neigh_arp_lookup(&arp_tbl, &res.nexthop, NULL, res.dev, NEIGHBOUR_CREAT); } read_lock_bh(&res.neigh->lock); if (!(res.neigh->nud_state&(NUD_CONNECTED|NUD_DELAY|NUD_PROBE))) { saddr = inet_select_addr(res.dev, res.nexthop, RT_SCOPE_LINK); arp_send(ARPOP_REQUEST, ETH_P_ARP, res.nexthop, res.dev, saddr, res.neigh->ha, res.dev->dev_addr, NULL); read_unlock_bh(&res.neigh->lock); printk("mpls_echo_input -neigh invalid drop.\n"); goto drop; } eth = (struct ethhdr *)skb_push(skb, ETH_HLEN); eth->h_proto = (ETH_P_802_3 != skb->protocol) ? htons(skb->protocol) : htons(skb->len); memcpy(eth->h_source, res.dev->dev_addr, res.dev->addr_len); memcpy(eth->h_dest, res.neigh->ha, res.dev->addr_len); skb->mac.raw = skb->data ; skb->mac_len = ETH_HLEN; read_unlock_bh(&res.neigh->lock); neigh_release(res.neigh); dev_queue_xmit(skb); return 0; drop: kfree_skb(skb); return -1; }
void icmp_print(const u_char *bp, u_int plen, const u_char *bp2, int fragmented) { char *cp; const struct icmp *dp; const struct icmp_ext_t *ext_dp; const struct ip *ip; const char *str, *fmt; const struct ip *oip; const struct udphdr *ouh; const u_int8_t *obj_tptr; u_int32_t raw_label; const u_char *snapend_save; const struct icmp_mpls_ext_object_header_t *icmp_mpls_ext_object_header; u_int hlen, dport, mtu, obj_tlen, obj_class_num, obj_ctype; char buf[MAXHOSTNAMELEN + 100]; dp = (struct icmp *)bp; ext_dp = (struct icmp_ext_t *)bp; ip = (struct ip *)bp2; str = buf; TCHECK(dp->icmp_code); switch (dp->icmp_type) { case ICMP_ECHO: case ICMP_ECHOREPLY: TCHECK(dp->icmp_seq); (void)snprintf(buf, sizeof(buf), "echo %s, id %u, seq %u", dp->icmp_type == ICMP_ECHO ? "request" : "reply", EXTRACT_16BITS(&dp->icmp_id), EXTRACT_16BITS(&dp->icmp_seq)); break; case ICMP_UNREACH: TCHECK(dp->icmp_ip.ip_dst); switch (dp->icmp_code) { case ICMP_UNREACH_PROTOCOL: TCHECK(dp->icmp_ip.ip_p); (void)snprintf(buf, sizeof(buf), "%s protocol %d unreachable", ipaddr_string(&dp->icmp_ip.ip_dst), dp->icmp_ip.ip_p); break; case ICMP_UNREACH_PORT: TCHECK(dp->icmp_ip.ip_p); oip = &dp->icmp_ip; hlen = IP_HL(oip) * 4; ouh = (struct udphdr *)(((u_char *)oip) + hlen); TCHECK(ouh->uh_dport); dport = EXTRACT_16BITS(&ouh->uh_dport); switch (oip->ip_p) { case IPPROTO_TCP: (void)snprintf(buf, sizeof(buf), "%s tcp port %s unreachable", ipaddr_string(&oip->ip_dst), tcpport_string(dport)); break; case IPPROTO_UDP: (void)snprintf(buf, sizeof(buf), "%s udp port %s unreachable", ipaddr_string(&oip->ip_dst), udpport_string(dport)); break; default: (void)snprintf(buf, sizeof(buf), "%s protocol %d port %d unreachable", ipaddr_string(&oip->ip_dst), oip->ip_p, dport); break; } break; case ICMP_UNREACH_NEEDFRAG: { register const struct mtu_discovery *mp; mp = (struct mtu_discovery *)(u_char *)&dp->icmp_void; mtu = EXTRACT_16BITS(&mp->nexthopmtu); if (mtu) { (void)snprintf(buf, sizeof(buf), "%s unreachable - need to frag (mtu %d)", ipaddr_string(&dp->icmp_ip.ip_dst), mtu); } else { (void)snprintf(buf, sizeof(buf), "%s unreachable - need to frag", ipaddr_string(&dp->icmp_ip.ip_dst)); } } break; default: fmt = tok2str(unreach2str, "#%d %%s unreachable", dp->icmp_code); (void)snprintf(buf, sizeof(buf), fmt, ipaddr_string(&dp->icmp_ip.ip_dst)); break; } break; case ICMP_REDIRECT: TCHECK(dp->icmp_ip.ip_dst); fmt = tok2str(type2str, "redirect-#%d %%s to net %%s", dp->icmp_code); (void)snprintf(buf, sizeof(buf), fmt, ipaddr_string(&dp->icmp_ip.ip_dst), ipaddr_string(&dp->icmp_gwaddr)); break; case ICMP_ROUTERADVERT: { register const struct ih_rdiscovery *ihp; register const struct id_rdiscovery *idp; u_int lifetime, num, size; (void)snprintf(buf, sizeof(buf), "router advertisement"); cp = buf + strlen(buf); ihp = (struct ih_rdiscovery *)&dp->icmp_void; TCHECK(*ihp); (void)strncpy(cp, " lifetime ", sizeof(buf) - (cp - buf)); cp = buf + strlen(buf); lifetime = EXTRACT_16BITS(&ihp->ird_lifetime); if (lifetime < 60) { (void)snprintf(cp, sizeof(buf) - (cp - buf), "%u", lifetime); } else if (lifetime < 60 * 60) { (void)snprintf(cp, sizeof(buf) - (cp - buf), "%u:%02u", lifetime / 60, lifetime % 60); } else { (void)snprintf(cp, sizeof(buf) - (cp - buf), "%u:%02u:%02u", lifetime / 3600, (lifetime % 3600) / 60, lifetime % 60); } cp = buf + strlen(buf); num = ihp->ird_addrnum; (void)snprintf(cp, sizeof(buf) - (cp - buf), " %d:", num); cp = buf + strlen(buf); size = ihp->ird_addrsiz; if (size != 2) { (void)snprintf(cp, sizeof(buf) - (cp - buf), " [size %d]", size); break; } idp = (struct id_rdiscovery *)&dp->icmp_data; while (num-- > 0) { TCHECK(*idp); (void)snprintf(cp, sizeof(buf) - (cp - buf), " {%s %u}", ipaddr_string(&idp->ird_addr), EXTRACT_32BITS(&idp->ird_pref)); cp = buf + strlen(buf); ++idp; } } break; case ICMP_TIMXCEED: TCHECK(dp->icmp_ip.ip_dst); switch (dp->icmp_code) { case ICMP_TIMXCEED_INTRANS: str = "time exceeded in-transit"; break; case ICMP_TIMXCEED_REASS: str = "ip reassembly time exceeded"; break; default: (void)snprintf(buf, sizeof(buf), "time exceeded-#%d", dp->icmp_code); break; } break; case ICMP_PARAMPROB: if (dp->icmp_code) (void)snprintf(buf, sizeof(buf), "parameter problem - code %d", dp->icmp_code); else { TCHECK(dp->icmp_pptr); (void)snprintf(buf, sizeof(buf), "parameter problem - octet %d", dp->icmp_pptr); } break; case ICMP_MASKREPLY: TCHECK(dp->icmp_mask); (void)snprintf(buf, sizeof(buf), "address mask is 0x%08x", EXTRACT_32BITS(&dp->icmp_mask)); break; case ICMP_TSTAMP: TCHECK(dp->icmp_seq); (void)snprintf(buf, sizeof(buf), "time stamp query id %u seq %u", EXTRACT_16BITS(&dp->icmp_id), EXTRACT_16BITS(&dp->icmp_seq)); break; case ICMP_TSTAMPREPLY: TCHECK(dp->icmp_ttime); (void)snprintf(buf, sizeof(buf), "time stamp reply id %u seq %u: org %s", EXTRACT_16BITS(&dp->icmp_id), EXTRACT_16BITS(&dp->icmp_seq), icmp_tstamp_print(EXTRACT_32BITS(&dp->icmp_otime))); (void)snprintf(buf+strlen(buf),sizeof(buf)-strlen(buf),", recv %s", icmp_tstamp_print(EXTRACT_32BITS(&dp->icmp_rtime))); (void)snprintf(buf+strlen(buf),sizeof(buf)-strlen(buf),", xmit %s", icmp_tstamp_print(EXTRACT_32BITS(&dp->icmp_ttime))); break; default: str = tok2str(icmp2str, "type-#%d", dp->icmp_type); break; } (void)printf("ICMP %s, length %u", str, plen); if (vflag && !fragmented) { /* don't attempt checksumming if this is a frag */ u_int16_t sum, icmp_sum; if (TTEST2(*bp, plen)) { sum = in_cksum((u_short*)dp, plen, 0); if (sum != 0) { icmp_sum = EXTRACT_16BITS(&dp->icmp_cksum); (void)printf(" (wrong icmp cksum %x (->%x)!)", icmp_sum, in_cksum_shouldbe(icmp_sum, sum)); } } } /* * print the remnants of the IP packet. * save the snaplength as this may get overidden in the IP printer. */ if (vflag >= 1 && !ICMP_INFOTYPE(dp->icmp_type)) { bp += 8; (void)printf("\n\t"); ip = (struct ip *)bp; snaplen = snapend - bp; snapend_save = snapend; ip_print(gndo, bp, EXTRACT_16BITS(&ip->ip_len)); snapend = snapend_save; } /* * Attempt to decode the MPLS extensions only for some ICMP types. */ if (vflag >= 1 && plen > ICMP_EXTD_MINLEN && ICMP_MPLS_EXT_TYPE(dp->icmp_type)) { TCHECK(*ext_dp); /* * Check first if the mpls extension header shows a non-zero length. * If the length field is not set then silently verify the checksum * to check if an extension header is present. This is expedient, * however not all implementations set the length field proper. */ if (!ext_dp->icmp_length && in_cksum((const u_short *)&ext_dp->icmp_ext_version_res, plen - ICMP_EXTD_MINLEN, 0)) { return; } printf("\n\tMPLS extension v%u", ICMP_MPLS_EXT_EXTRACT_VERSION(*(ext_dp->icmp_ext_version_res))); /* * Sanity checking of the header. */ if (ICMP_MPLS_EXT_EXTRACT_VERSION(*(ext_dp->icmp_ext_version_res)) != ICMP_MPLS_EXT_VERSION) { printf(" packet not supported"); return; } hlen = plen - ICMP_EXTD_MINLEN; printf(", checksum 0x%04x (%scorrect), length %u", EXTRACT_16BITS(ext_dp->icmp_ext_checksum), in_cksum((const u_short *)&ext_dp->icmp_ext_version_res, plen - ICMP_EXTD_MINLEN, 0) ? "in" : "", hlen); hlen -= 4; /* subtract common header size */ obj_tptr = (u_int8_t *)ext_dp->icmp_ext_data; while (hlen > sizeof(struct icmp_mpls_ext_object_header_t)) { icmp_mpls_ext_object_header = (struct icmp_mpls_ext_object_header_t *)obj_tptr; TCHECK(*icmp_mpls_ext_object_header); obj_tlen = EXTRACT_16BITS(icmp_mpls_ext_object_header->length); obj_class_num = icmp_mpls_ext_object_header->class_num; obj_ctype = icmp_mpls_ext_object_header->ctype; obj_tptr += sizeof(struct icmp_mpls_ext_object_header_t); printf("\n\t %s Object (%u), Class-Type: %u, length %u", tok2str(icmp_mpls_ext_obj_values,"unknown",obj_class_num), obj_class_num, obj_ctype, obj_tlen); hlen-=sizeof(struct icmp_mpls_ext_object_header_t); /* length field includes tlv header */ /* infinite loop protection */ if ((obj_class_num == 0) || (obj_tlen < sizeof(struct icmp_mpls_ext_object_header_t))) { return; } obj_tlen-=sizeof(struct icmp_mpls_ext_object_header_t); switch (obj_class_num) { case 1: switch(obj_ctype) { case 1: TCHECK2(*obj_tptr, 4); raw_label = EXTRACT_32BITS(obj_tptr); printf("\n\t label %u, exp %u", MPLS_LABEL(raw_label), MPLS_EXP(raw_label)); if (MPLS_STACK(raw_label)) printf(", [S]"); printf(", ttl %u", MPLS_TTL(raw_label)); break; default: print_unknown_data(obj_tptr, "\n\t ", obj_tlen); } break; /* * FIXME those are the defined objects that lack a decoder * you are welcome to contribute code ;-) */ case 2: default: print_unknown_data(obj_tptr, "\n\t ", obj_tlen); break; } if (hlen < obj_tlen) break; hlen -= obj_tlen; obj_tptr += obj_tlen; } } return; trunc: fputs("[|icmp]", stdout); }
/* * RFC3032: MPLS label stack encoding */ void mpls_print(netdissect_options *ndo, const u_char *bp, u_int length) { const u_char *p; uint32_t label_entry; uint16_t label_stack_depth = 0; enum mpls_packet_type pt = PT_UNKNOWN; p = bp; ND_PRINT((ndo, "MPLS")); do { ND_TCHECK2(*p, sizeof(label_entry)); label_entry = EXTRACT_32BITS(p); ND_PRINT((ndo, "%s(label %u", (label_stack_depth && ndo->ndo_vflag) ? "\n\t" : " ", MPLS_LABEL(label_entry))); label_stack_depth++; if (ndo->ndo_vflag && MPLS_LABEL(label_entry) < sizeof(mpls_labelname) / sizeof(mpls_labelname[0])) ND_PRINT((ndo, " (%s)", mpls_labelname[MPLS_LABEL(label_entry)])); ND_PRINT((ndo, ", exp %u", MPLS_EXP(label_entry))); if (MPLS_STACK(label_entry)) ND_PRINT((ndo, ", [S]")); ND_PRINT((ndo, ", ttl %u)", MPLS_TTL(label_entry))); p += sizeof(label_entry); } while (!MPLS_STACK(label_entry)); /* * Try to figure out the packet type. */ switch (MPLS_LABEL(label_entry)) { case 0: /* IPv4 explicit NULL label */ case 3: /* IPv4 implicit NULL label */ pt = PT_IPV4; break; case 2: /* IPv6 explicit NULL label */ pt = PT_IPV6; break; default: /* * Generally there's no indication of protocol in MPLS label * encoding. * * However, draft-hsmit-isis-aal5mux-00.txt describes a * technique for encapsulating IS-IS and IP traffic on the * same ATM virtual circuit; you look at the first payload * byte to determine the network layer protocol, based on * the fact that * * 1) the first byte of an IP header is 0x45-0x4f * for IPv4 and 0x60-0x6f for IPv6; * * 2) the first byte of an OSI CLNP packet is 0x81, * the first byte of an OSI ES-IS packet is 0x82, * and the first byte of an OSI IS-IS packet is * 0x83; * * so the network layer protocol can be inferred from the * first byte of the packet, if the protocol is one of the * ones listed above. * * Cisco sends control-plane traffic MPLS-encapsulated in * this fashion. */ switch(*p) { case 0x45: case 0x46: case 0x47: case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f: pt = PT_IPV4; break; case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67: case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f: pt = PT_IPV6; break; case 0x81: case 0x82: case 0x83: pt = PT_OSI; break; default: /* ok bail out - we did not figure out what it is*/ break; } } /* * Print the payload. */ if (pt == PT_UNKNOWN) { if (!ndo->ndo_suppress_default_print) ND_DEFAULTPRINT(p, length - (p - bp)); return; } ND_PRINT((ndo, ndo->ndo_vflag ? "\n\t" : " ")); switch (pt) { case PT_IPV4: ip_print(ndo, p, length - (p - bp)); break; case PT_IPV6: ip6_print(ndo, p, length - (p - bp)); break; case PT_OSI: isoclns_print(ndo, p, length - (p - bp), length - (p - bp)); break; default: break; } return; trunc: ND_PRINT((ndo, "[|MPLS]")); }
/* * RFC3032: MPLS label stack encoding */ void mpls_print(const u_char *bp, u_int length) { const u_char *p; u_int32_t label_entry; u_int16_t label_stack_depth = 0; p = bp; printf("MPLS"); do { TCHECK2(*p, sizeof(label_entry)); label_entry = EXTRACT_32BITS(p); printf("%s(label %u", label_stack_depth ? "\n\t" : " ", MPLS_LABEL(label_entry)); label_stack_depth++; if (vflag && MPLS_LABEL(label_entry) < sizeof(mpls_labelname) / sizeof(mpls_labelname[0])) printf(" (%s)", mpls_labelname[MPLS_LABEL(label_entry)]); printf(", exp %u", MPLS_EXP(label_entry)); if (MPLS_STACK(label_entry)) printf(", [S]"); printf(", ttl %u)", MPLS_TTL(label_entry)); p += sizeof(label_entry); } while (!MPLS_STACK(label_entry)); switch (MPLS_LABEL(label_entry)) { case 0: /* IPv4 explicit NULL label */ case 3: /* IPv4 implicit NULL label */ if (vflag>0) { printf("\n\t"); ip_print(gndo, p, length - (p - bp)); } else printf(", IP, length: %u",length); break; #ifdef INET6 case 2: /* IPv6 explicit NULL label */ if (vflag>0) { printf("\n\t"); ip6_print(p, length - (p - bp)); } else printf(", IPv6, length: %u",length); break; #endif default: /* * Generally there's no indication of protocol in MPLS label * encoding, however draft-hsmit-isis-aal5mux-00.txt describes * a technique that looks at the first payload byte if the BOS (bottom of stack) * bit is set and tries to determine the network layer protocol * 0x45-0x4f is IPv4 * 0x60-0x6f is IPv6 * 0x81-0x83 is OSI (CLNP,ES-IS,IS-IS) * this technique is sometimes known as NULL encapsulation * and decoding is particularly useful for control-plane traffic [BGP] * which cisco by default sends MPLS encapsulated */ if (MPLS_STACK(label_entry)) { /* only do this if the stack bit is set */ switch(*p) { case 0x45: case 0x46: case 0x47: case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f: if (vflag>0) { printf("\n\t"); ip_print(gndo, p, length - (p - bp)); } else printf(", IP, length: %u",length); break; #ifdef INET6 case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67: case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f: if (vflag>0) { printf("\n\t"); ip6_print(p, length - (p - bp)); } else printf(", IPv6, length: %u",length); break; #endif case 0x81: case 0x82: case 0x83: if (vflag>0) { printf("\n\t"); isoclns_print(p, length - (p - bp), length - (p - bp)); } else printf(", OSI, length: %u",length); break; default: /* ok bail out - we did not figure out what it is*/ break; } } return; } trunc: printf("[|MPLS]"); }
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; }
void mpls_input(struct mbuf *m) { struct mpls *mpls = NULL; mpls_label_t label; M_ASSERTPKTHDR(m); mplsstat.mplss_total++; /* length checks already performed at mpls_demux() */ KASSERT(m->m_pkthdr.len >= sizeof(struct mpls), ("mpls_input: mpls header too small")); again: if (m->m_len < sizeof(struct mpls)) { m = m_pullup(m, sizeof(struct mpls)); if (m == NULL) { mplsstat.mplss_toosmall++; return; } } mpls = mtod(m, struct mpls*); label = MPLS_LABEL(ntohl(mpls->mpls_shim)); switch (label) { case 0: /* * Label 0: represents "IPv4 Explicit NULL Label". */ if (MPLS_STACK(ntohl(mpls->mpls_shim))) { /* Decapsulate the ip datagram from the mpls frame. */ m_adj(m, sizeof(struct mpls)); netisr_queue(NETISR_IP, m); return; } goto again; /* If not the bottom label, per RFC4182. */ case 1: /* * Label 1: represents "Router Alert Label" and is valid * anywhere except at the bottom of the stack. */ break; case 2: /* * Label 2: represents "IPv6 Explicit NULL Label". */ if (MPLS_STACK(ntohl(mpls->mpls_shim))) { /* Decapsulate the ip datagram from the mpls frame. */ m_adj(m, sizeof(struct mpls)); netisr_queue(NETISR_IPV6, m); return; } goto again; /* If not the bottom label, per RFC4182. */ case 3: /* * Label 3: represents the "Implicit NULL Label" and must not * appear on the wire. */ break; default: /* * Labels 4 - 15: reserved, drop them. */ if (label <= 15) { mplsstat.mplss_reserved++; m_freem(m); return; } if (mplsforwarding) { mpls_forward(m); return; } else { mplsstat.mplss_cantforward++; m_freem(m); return; } } mplsstat.mplss_invalid++; m_freem(m); }
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; }