int processVLANPacket(const void * data, int size, int length, PEtherHeader ether) { PSoderoPeriodResult result = getPeriodResult(); const PVLANPacket packet = (PVLANPacket) data; void * payload_data = VLAN_OVERLOAD_DATA(data); int payload_size = VLAN_OVERLOAD_SIZE(size); processA(&gVLAN, length); processA(&result->protocol.l2.vlan.total, size); long id = VLAN_ID(packet->vlan.value); PSoderoSingleDatum datum = (PSoderoSingleDatum) sodero_map_ensure(getPeriodResult()->items.vlan, &id); processSD(datum, size); switch(packet->vlan.type) { case ETHER_TYPE_IPv4: processA(&result->protocol.l2.ether.ipv4, payload_size); payload_size = processIPv4Packet(payload_data, payload_size, length, ether, id); return payload_size; case ETHER_TYPE_MPLS: processA(&result->protocol.l2.ether.mpls, size); payload_size = processMPLSPacket(payload_data, payload_size, length, ether, id); return payload_size; } return 0; }
/* * Lookup the vlan id of the given frame. If it is a vlan-tagged frame, * then the vlan-id is available in the tag; otherwise, its vlan id is * implicitly obtained based on the caller (destination of the frame: * VSW_VNETPORT or VSW_LOCALDEV). * The vlan id determined is returned in vidp. * Returns: B_TRUE if it is a tagged frame; B_FALSE if it is untagged. */ boolean_t vsw_frame_lookup_vid(void *arg, int caller, struct ether_header *ehp, uint16_t *vidp) { struct ether_vlan_header *evhp; vsw_t *vswp; vsw_port_t *portp; /* If it's a tagged frame, get the vid from vlan header */ if (ehp->ether_type == ETHERTYPE_VLAN) { evhp = (struct ether_vlan_header *)ehp; *vidp = VLAN_ID(ntohs(evhp->ether_tci)); return (B_TRUE); } /* Untagged frame; determine vlan id based on caller */ switch (caller) { case VSW_VNETPORT: /* * packet destined to a vnet; vlan-id is pvid of vnet-port. */ portp = (vsw_port_t *)arg; *vidp = portp->pvid; break; case VSW_LOCALDEV: /* * packet destined to vsw interface; * vlan-id is port-vlan-id of vsw device. */ vswp = (vsw_t *)arg; *vidp = vswp->pvid; break; } return (B_FALSE); }
uint_t interpret_ether(int flags, char *header, int elen, int origlen) { struct ether_header *e = (struct ether_header *)header; uchar_t *off, *ieeestart; int len; int ieee8023 = 0; extern char *dst_name; int ethertype; struct ether_vlan_extinfo *evx = NULL; int blen = MAX(origlen, ETHERMTU); boolean_t trillpkt = B_FALSE; uint16_t tci = 0; if (data != NULL && datalen != 0 && datalen < blen) { free(data); data = NULL; datalen = 0; } if (!data) { data = (char *)malloc(blen); if (!data) pr_err("Warning: malloc failure"); datalen = blen; } inner_pkt: if (origlen < 14) { if (flags & F_SUM) { (void) sprintf(get_sum_line(), "RUNT (short packet - %d bytes)", origlen); } if (flags & F_DTAIL) show_header("RUNT: ", "Short packet", origlen); return (elen); } if (elen < 14) return (elen); if (memcmp(&e->ether_dhost, ðer_broadcast, sizeof (struct ether_addr)) == 0) dst_name = "(broadcast)"; else if (e->ether_dhost.ether_addr_octet[0] & 1) dst_name = "(multicast)"; ethertype = ntohs(e->ether_type); /* * The 14 byte ether header screws up alignment * of the rest of the packet for 32 bit aligned * architectures like SPARC. Alas, we have to copy * the rest of the packet in order to align it. */ len = elen - sizeof (struct ether_header); off = (uchar_t *)(e + 1); if (ethertype == ETHERTYPE_VLAN) { if (origlen < sizeof (struct ether_vlan_header)) { if (flags & F_SUM) { (void) sprintf(get_sum_line(), "RUNT (short VLAN packet - %d bytes)", origlen); } if (flags & F_DTAIL) { show_header("RUNT: ", "Short VLAN packet", origlen); } return (elen); } if (len < sizeof (struct ether_vlan_extinfo)) return (elen); evx = (struct ether_vlan_extinfo *)off; off += sizeof (struct ether_vlan_extinfo); len -= sizeof (struct ether_vlan_extinfo); ethertype = ntohs(evx->ether_type); tci = ntohs(evx->ether_tci); } if (ethertype <= 1514) { /* * Fake out the IEEE 802.3 packets. * Should be DSAP=0xAA, SSAP=0xAA, control=0x03 * then three padding bytes of zero (OUI), * followed by a normal ethernet-type packet. */ ieee8023 = ethertype; ieeestart = off; if (off[0] == 0xAA && off[1] == 0xAA) { ethertype = ntohs(*(ushort_t *)(off + 6)); off += 8; len -= 8; } else { ethertype = 0; off += 3; len -= 3; } } if (flags & F_SUM) { /* * Set the flag that says don't display VLAN information. * If it needs to change, that will be done later if the * packet is VLAN tagged and if snoop is in its default * summary mode. */ set_vlan_id(0); if (evx == NULL) { if (ethertype == 0 && ieee8023 > 0) { (void) sprintf(get_sum_line(), "ETHER 802.3 SSAP %02X DSAP %02X, " "size=%d bytes", ieeestart[0], ieeestart[1], origlen); } else { (void) sprintf(get_sum_line(), "ETHER Type=%04X (%s), size=%d bytes", ethertype, print_ethertype(ethertype), origlen); } } else { if (ethertype == 0 && ieee8023 > 0) { (void) sprintf(get_sum_line(), "ETHER 802.3 SSAP %02X DSAP %02X, " "VLAN ID=%hu, size=%d bytes", ieeestart[0], ieeestart[1], VLAN_ID(tci), origlen); } else { (void) sprintf(get_sum_line(), "ETHER Type=%04X (%s), VLAN ID=%hu, " "size=%d bytes", ethertype, print_ethertype(ethertype), VLAN_ID(tci), origlen); } if (!(flags & F_ALLSUM)) set_vlan_id(VLAN_ID(tci)); } } if (flags & F_DTAIL) { show_header("ETHER: ", "Ether Header", elen); show_space(); if (!trillpkt) { (void) sprintf(get_line(0, 0), "Packet %d arrived at %d:%02d:%d.%05d", pi_frame, pi_time_hour, pi_time_min, pi_time_sec, pi_time_usec / 10); (void) sprintf(get_line(0, 0), "Packet size = %d bytes", elen, elen); } (void) sprintf(get_line(0, 6), "Destination = %s, %s", printether(&e->ether_dhost), print_etherinfo(&e->ether_dhost)); (void) sprintf(get_line(6, 6), "Source = %s, %s", printether(&e->ether_shost), print_etherinfo(&e->ether_shost)); if (evx != NULL) { (void) sprintf(get_line(0, 0), "VLAN ID = %hu", VLAN_ID(tci)); (void) sprintf(get_line(0, 0), "VLAN Priority = %hu", VLAN_PRI(tci)); } if (ieee8023 > 0) { (void) sprintf(get_line(12, 2), "IEEE 802.3 length = %d bytes", ieee8023); /* Print LLC only for non-TCP/IP packets */ if (ethertype == 0) { (void) snprintf(get_line(0, 0), get_line_remain(), "SSAP = %02X, DSAP = %02X, CTRL = %02X", ieeestart[0], ieeestart[1], ieeestart[2]); } } if (ethertype != 0 || ieee8023 == 0) (void) sprintf(get_line(12, 2), "Ethertype = %04X (%s)", ethertype, print_ethertype(ethertype)); show_space(); } /* * We cannot trust the length field in the header to be correct. * But we should continue to process the packet. Then user can * notice something funny in the header. * Go to the next protocol layer only if data have been * copied. */ if (len > 0 && (off + len <= (uchar_t *)e + elen)) { (void) memmove(data, off, len); if (!trillpkt && ethertype == ETHERTYPE_TRILL) { ethertype = interpret_trill(flags, &e, data, &len); /* Decode inner Ethernet frame */ if (ethertype != 0) { evx = NULL; trillpkt = B_TRUE; (void) memmove(data, e, len); e = (struct ether_header *)data; origlen = len; elen = len; goto inner_pkt; } } switch (ethertype) { case ETHERTYPE_IP: (void) interpret_ip(flags, (struct ip *)data, len); break; /* Just in case it is decided to add this type */ case ETHERTYPE_IPV6: (void) interpret_ipv6(flags, (ip6_t *)data, len); break; case ETHERTYPE_ARP: case ETHERTYPE_REVARP: interpret_arp(flags, (struct arphdr *)data, len); break; case ETHERTYPE_PPPOED: case ETHERTYPE_PPPOES: (void) interpret_pppoe(flags, (poep_t *)data, len); break; case ETHERTYPE_AARP: /* AppleTalk */ interpret_aarp(flags, data, len); break; case ETHERTYPE_AT: interpret_at(flags, (struct ddp_hdr *)data, len); break; case 0: if (ieee8023 == 0) break; switch (ieeestart[0]) { case 0xFE: interpret_isis(flags, data, len, memcmp(&e->ether_dhost, &all_isis_rbridges, sizeof (struct ether_addr)) == 0); break; case 0x42: interpret_bpdu(flags, data, len); break; } break; } } return (elen); }
/** * @ingroup lwip_nosys * Process received ethernet frames. Using this function instead of directly * calling ip_input and passing ARP frames through etharp in ethernetif_input, * the ARP cache is protected from concurrent access.\n * Don't call directly, pass to netif_add() and call netif->input(). * * @param p the received packet, p->payload pointing to the ethernet header * @param netif the network interface on which the packet was received * * @see LWIP_HOOK_UNKNOWN_ETH_PROTOCOL * @see ETHARP_SUPPORT_VLAN * @see LWIP_HOOK_VLAN_CHECK */ err_t ethernet_input(struct pbuf *p, struct netif *netif) { struct eth_hdr* ethhdr; u16_t type; #if LWIP_ARP || ETHARP_SUPPORT_VLAN || LWIP_IPV6 s16_t ip_hdr_offset = SIZEOF_ETH_HDR; #endif /* LWIP_ARP || ETHARP_SUPPORT_VLAN */ if (p->len <= SIZEOF_ETH_HDR) { /* a packet with only an ethernet header (or less) is not valid for us */ ETHARP_STATS_INC(etharp.proterr); ETHARP_STATS_INC(etharp.drop); MIB2_STATS_NETIF_INC(netif, ifinerrors); goto free_and_return; } /* points to packet payload, which starts with an Ethernet header */ ethhdr = (struct eth_hdr *)p->payload; LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("ethernet_input: dest:%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F", src:%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F", type:%"X16_F"\n", (unsigned)ethhdr->dest.addr[0], (unsigned)ethhdr->dest.addr[1], (unsigned)ethhdr->dest.addr[2], (unsigned)ethhdr->dest.addr[3], (unsigned)ethhdr->dest.addr[4], (unsigned)ethhdr->dest.addr[5], (unsigned)ethhdr->src.addr[0], (unsigned)ethhdr->src.addr[1], (unsigned)ethhdr->src.addr[2], (unsigned)ethhdr->src.addr[3], (unsigned)ethhdr->src.addr[4], (unsigned)ethhdr->src.addr[5], lwip_htons(ethhdr->type))); type = ethhdr->type; #if ETHARP_SUPPORT_VLAN if (type == PP_HTONS(ETHTYPE_VLAN)) { struct eth_vlan_hdr *vlan = (struct eth_vlan_hdr*)(((char*)ethhdr) + SIZEOF_ETH_HDR); if (p->len <= SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR) { /* a packet with only an ethernet/vlan header (or less) is not valid for us */ ETHARP_STATS_INC(etharp.proterr); ETHARP_STATS_INC(etharp.drop); MIB2_STATS_NETIF_INC(netif, ifinerrors); goto free_and_return; } #if defined(LWIP_HOOK_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK_FN) /* if not, allow all VLANs */ #ifdef LWIP_HOOK_VLAN_CHECK if (!LWIP_HOOK_VLAN_CHECK(netif, ethhdr, vlan)) { #elif defined(ETHARP_VLAN_CHECK_FN) if (!ETHARP_VLAN_CHECK_FN(ethhdr, vlan)) { #elif defined(ETHARP_VLAN_CHECK) if (VLAN_ID(vlan) != ETHARP_VLAN_CHECK) { #endif /* silently ignore this packet: not for our VLAN */ pbuf_free(p); return ERR_OK; } #endif /* defined(LWIP_HOOK_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK_FN) */ type = vlan->tpid; ip_hdr_offset = SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR; } #endif /* ETHARP_SUPPORT_VLAN */ #if LWIP_ARP_FILTER_NETIF netif = LWIP_ARP_FILTER_NETIF_FN(p, netif, lwip_htons(type)); #endif /* LWIP_ARP_FILTER_NETIF*/ if (ethhdr->dest.addr[0] & 1) { /* this might be a multicast or broadcast packet */ if (ethhdr->dest.addr[0] == LL_IP4_MULTICAST_ADDR_0) { #if LWIP_IPV4 if ((ethhdr->dest.addr[1] == LL_IP4_MULTICAST_ADDR_1) && (ethhdr->dest.addr[2] == LL_IP4_MULTICAST_ADDR_2)) { /* mark the pbuf as link-layer multicast */ p->flags |= PBUF_FLAG_LLMCAST; } #endif /* LWIP_IPV4 */ } #if LWIP_IPV6 else if ((ethhdr->dest.addr[0] == LL_IP6_MULTICAST_ADDR_0) && (ethhdr->dest.addr[1] == LL_IP6_MULTICAST_ADDR_1)) { /* mark the pbuf as link-layer multicast */ p->flags |= PBUF_FLAG_LLMCAST; } #endif /* LWIP_IPV6 */ else if (eth_addr_cmp(ðhdr->dest, ðbroadcast)) { /* mark the pbuf as link-layer broadcast */ p->flags |= PBUF_FLAG_LLBCAST; } } switch (type) { #if LWIP_IPV4 && LWIP_ARP /* IP packet? */ case PP_HTONS(ETHTYPE_IP): if (!(netif->flags & NETIF_FLAG_ETHARP)) { goto free_and_return; } /* skip Ethernet header */ if ((p->len < ip_hdr_offset) || pbuf_header(p, (s16_t)-ip_hdr_offset)) { LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("ethernet_input: IPv4 packet dropped, too short (%"S16_F"/%"S16_F")\n", p->tot_len, ip_hdr_offset)); LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("Can't move over header in packet")); goto free_and_return; } else { /* pass to IP layer */ ip4_input(p, netif); } break; case PP_HTONS(ETHTYPE_ARP): if (!(netif->flags & NETIF_FLAG_ETHARP)) { goto free_and_return; } /* skip Ethernet header */ if ((p->len < ip_hdr_offset) || pbuf_header(p, (s16_t)-ip_hdr_offset)) { LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("ethernet_input: ARP response packet dropped, too short (%"S16_F"/%"S16_F")\n", p->tot_len, ip_hdr_offset)); LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("Can't move over header in packet")); ETHARP_STATS_INC(etharp.lenerr); ETHARP_STATS_INC(etharp.drop); goto free_and_return; } else { /* pass p to ARP module */ etharp_input(p, netif); } break; #endif /* LWIP_IPV4 && LWIP_ARP */ #if PPPOE_SUPPORT case PP_HTONS(ETHTYPE_PPPOEDISC): /* PPP Over Ethernet Discovery Stage */ pppoe_disc_input(netif, p); break; case PP_HTONS(ETHTYPE_PPPOE): /* PPP Over Ethernet Session Stage */ pppoe_data_input(netif, p); break; #endif /* PPPOE_SUPPORT */ #if LWIP_IPV6 case PP_HTONS(ETHTYPE_IPV6): /* IPv6 */ /* skip Ethernet header */ if ((p->len < ip_hdr_offset) || pbuf_header(p, (s16_t)-ip_hdr_offset)) { LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("ethernet_input: IPv6 packet dropped, too short (%"S16_F"/%"S16_F")\n", p->tot_len, ip_hdr_offset)); goto free_and_return; } else { /* pass to IPv6 layer */ ip6_input(p, netif); } break; #endif /* LWIP_IPV6 */ default: #ifdef LWIP_HOOK_UNKNOWN_ETH_PROTOCOL if(LWIP_HOOK_UNKNOWN_ETH_PROTOCOL(p, netif) == ERR_OK) { break; } #endif ETHARP_STATS_INC(etharp.proterr); ETHARP_STATS_INC(etharp.drop); MIB2_STATS_NETIF_INC(netif, ifinunknownprotos); goto free_and_return; } /* This means the pbuf is freed or consumed, so the caller doesn't have to free it again */ return ERR_OK; free_and_return: pbuf_free(p); return ERR_OK; } /** * @ingroup ethernet * Send an ethernet packet on the network using netif->linkoutput(). * The ethernet header is filled in before sending. * * @see LWIP_HOOK_VLAN_SET * * @param netif the lwIP network interface on which to send the packet * @param p the packet to send. pbuf layer must be @ref PBUF_LINK. * @param src the source MAC address to be copied into the ethernet header * @param dst the destination MAC address to be copied into the ethernet header * @param eth_type ethernet type (@ref eth_type) * @return ERR_OK if the packet was sent, any other err_t on failure */ err_t ethernet_output(struct netif* netif, struct pbuf* p, const struct eth_addr* src, const struct eth_addr* dst, u16_t eth_type) { struct eth_hdr* ethhdr; u16_t eth_type_be = lwip_htons(eth_type); #if ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) s32_t vlan_prio_vid = LWIP_HOOK_VLAN_SET(netif, p, src, dst, eth_type); if (vlan_prio_vid >= 0) { struct eth_vlan_hdr* vlanhdr; LWIP_ASSERT("prio_vid must be <= 0xFFFF", vlan_prio_vid <= 0xFFFF); if (pbuf_header(p, SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR) != 0) { goto pbuf_header_failed; } vlanhdr = (struct eth_vlan_hdr*)(((u8_t*)p->payload) + SIZEOF_ETH_HDR); vlanhdr->tpid = eth_type_be; vlanhdr->prio_vid = lwip_htons((u16_t)vlan_prio_vid); eth_type_be = PP_HTONS(ETHTYPE_VLAN); } else #endif /* ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) */ { if (pbuf_header(p, SIZEOF_ETH_HDR) != 0) { goto pbuf_header_failed; } } ethhdr = (struct eth_hdr*)p->payload; ethhdr->type = eth_type_be; ETHADDR32_COPY(ðhdr->dest, dst); ETHADDR16_COPY(ðhdr->src, src); LWIP_ASSERT("netif->hwaddr_len must be 6 for ethernet_output!", (netif->hwaddr_len == ETH_HWADDR_LEN)); LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("ethernet_output: sending packet %p\n", (void *)p)); /* send the packet */ return netif->linkoutput(netif, p); pbuf_header_failed: LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("ethernet_output: could not allocate room for header.\n")); LINK_STATS_INC(link.lenerr); return ERR_BUF; }
/** * Process received ethernet frames. Using this function instead of directly * calling ip_input and passing ARP frames through etharp in ethernetif_input, * the ARP cache is protected from concurrent access. * * @param p the recevied packet, p->payload pointing to the ethernet header * @param netif the network interface on which the packet was received */ err_t ethernet_input(struct pbuf *p, struct netif *netif) { struct eth_hdr* ethhdr; u16_t type; /* points to packet payload, which starts with an Ethernet header */ ethhdr = p->payload; LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("ethernet_input: dest:%02x:%02x:%02x:%02x:%02x:%02x, src:%02x:%02x:%02x:%02x:%02x:%02x, type:%2x"NEWLINE, (unsigned )ethhdr->dest.addr[0], (unsigned )ethhdr->dest.addr[1], (unsigned )ethhdr->dest.addr[2], (unsigned )ethhdr->dest.addr[3], (unsigned )ethhdr->dest.addr[4], (unsigned )ethhdr->dest.addr[5], (unsigned )ethhdr->src.addr[0], (unsigned )ethhdr->src.addr[1], (unsigned )ethhdr->src.addr[2], (unsigned )ethhdr->src.addr[3], (unsigned )ethhdr->src.addr[4], (unsigned )ethhdr->src.addr[5], (unsigned )htons(ethhdr->type))); netif->rxpackets++; netif->rxbytes += p->tot_len; type = htons(ethhdr->type); #if ETHARP_SUPPORT_VLAN if (type == ETHTYPE_VLAN) { struct eth_vlan_hdr *vlan = (struct eth_vlan_hdr*)(((char*)ethhdr) + SIZEOF_ETH_HDR); #ifdef ETHARP_VLAN_CHECK /* if not, allow all VLANs */ if (VLAN_ID(vlan) != ETHARP_VLAN_CHECK) { /* silently ignore this packet: not for our VLAN */ pbuf_free(p); return ERR_OK; } #endif /* ETHARP_VLAN_CHECK */ type = htons(vlan->tpid); } #endif /* ETHARP_SUPPORT_VLAN */ //acquireMutex(comStackMutex); switch (type) { /* IP packet? */ case ETHTYPE_IPV4: #if ETHARP_TRUST_IP_MAC /* update ARP table */ ethar_ip_input(netif, p); #endif /* ETHARP_TRUST_IP_MAC */ /* skip Ethernet header */ if (pbuf_header(p, -(s16_t) SIZEOF_ETH_HDR)) { LWIP_ASSERT("Can't move over header in packet", 0); pbuf_free(p); p = NULL; } else { /* pass to IP layer */ ip4_input(p, netif); } break; case ETHTYPE_IPV6: #if ETHARP_TRUST_IP_MAC /* update AR table */ ethar_ip_input(netif, p); #endif /* ETHARP_TRUST_IP_MAC */ if (pbuf_header(p, -(s16_t) SIZEOF_ETH_HDR)) { LWIP_ASSERT("Can't move over header in packet", 0); pbuf_free(p); p = NULL; } else { ip6_input(p, netif); } break; #if LWIP_ARP case ETHTYPE_ARP: /* pass p to ARP module */ etharp_arp_input(netif, (struct eth_addr*) (netif->hwaddr), p); break; #endif #if PPPOE_SUPPORT case ETHTYPE_PPPOEDISC: /* PPP Over Ethernet Discovery Stage */ pppoe_disc_input(netif, p); break; case ETHTYPE_PPPOE: /* PPP Over Ethernet Session Stage */ pppoe_data_input(netif, p); break; #endif /* PPPOE_SUPPORT */ default: ETHARP_STATS_INC(etharp.proterr); ETHARP_STATS_INC(etharp.drop); pbuf_free(p); break; } //releaseMutex(comStackMutex); /* This means the pbuf is freed or consumed, so the caller doesn't have to free it again */ return (ERR_OK); }