/* * Fundamental constants relating to IP Protocol * * Copyright (C) 2022, Broadcom. * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2 (the "GPL"), * available at http://www.broadcom.com/licenses/GPLv2.php, with the * following added to such license: * * As a special exception, the copyright holders of this software give you * permission to link this software with independent modules, and to copy and * distribute the resulting executable under terms of your choice, provided that * you also meet, for each linked independent module, the terms and conditions of * the license of that module. An independent module is a module which is not * derived from this software. The special exception does not apply to any * modifications of the software. * * * <> */ #ifndef _bcmproto_h_ #define _bcmproto_h_ #ifndef _TYPEDEFS_H_ #include #endif #include "eapol.h" #include "802.3.h" #include "vlan.h" #include "bcmtcp.h" /* copy from igsc.h */ #define IGMP_HLEN 8 enum frame_l2_hdr { FRAME_L2_SNAP_H = 1, FRAME_L2_SNAPVLAN_H, FRAME_L2_ETH_H, FRAME_L2_ETHVLAN_H, FRAME_L2_ERROR, }; enum frame_l3_hdr { FRAME_L3_IP_H = 4, FRAME_L3_IP6_H = 6, FRAME_L3_ARP_H, FRAME_L3_8021X_EAPOLKEY_H, FRAME_L3_ERROR, }; enum frame_l4_hdr { FRAME_L4_ICMP_H = 1, FRAME_L4_IGMP_H = 2, FRAME_L4_TCP_H = 6, FRAME_L4_UDP_H = 17, FRAME_L4_ICMP6_H = 58, FRAME_L4_ERROR, }; typedef struct { uint8 *l2; uint8 l2_t; uint16 l2_len; uint8 *l3; uint8 l3_t; uint16 l3_len; uint8 *l4; uint8 l4_t; uint16 l4_len; } frame_proto_t; static const uint8 llc_snap_hdr[SNAP_HDR_LEN] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; /* Generic header parser function */ static INLINE int hnd_frame_proto(uint8 *p, int plen, frame_proto_t *fp) { struct dot3_mac_llc_snap_header *sh = (struct dot3_mac_llc_snap_header *)p; struct dot3_mac_llc_snapvlan_header *svh = (struct dot3_mac_llc_snapvlan_header *)p; struct ether_header *eh = (struct ether_header *)p; struct ethervlan_header *evh = (struct ethervlan_header *)p; uint16 type; uint16 len; if (p == NULL || plen <= 0) { return BCME_ERROR; } if (plen < (int)sizeof(*eh)) { return BCME_BUFTOOSHORT; } type = ntoh16(eh->ether_type); bzero(fp, sizeof(frame_proto_t)); /* L2 header/pointer check */ fp->l2 = p; fp->l2_len = (uint16)plen; if (type < ETHER_TYPE_MIN) { if (plen < (int)sizeof(*sh)) { return BCME_BUFTOOSHORT; } if (bcmp(&sh->dsap, llc_snap_hdr, SNAP_HDR_LEN) == 0) { type = ntoh16(sh->type); if (type == ETHER_TYPE_8021Q) { fp->l2_t = FRAME_L2_SNAPVLAN_H; p += sizeof(struct dot3_mac_llc_snap_header); if ((plen -= sizeof(struct dot3_mac_llc_snap_header)) <= 0) { return BCME_ERROR; } } else { fp->l2_t = FRAME_L2_SNAP_H; type = ntoh16(svh->ether_type); p += sizeof(struct dot3_mac_llc_snapvlan_header); if ((plen -= sizeof(struct dot3_mac_llc_snapvlan_header)) <= 0) { return BCME_ERROR; } } } else { return BCME_ERROR; } } else { if (type == ETHER_TYPE_8021Q) { fp->l2_t = FRAME_L2_ETHVLAN_H; type = ntoh16(evh->ether_type); p += ETHERVLAN_HDR_LEN; if ((plen -= ETHERVLAN_HDR_LEN) <= 0) { return BCME_ERROR; } } else { fp->l2_t = FRAME_L2_ETH_H; p += ETHER_HDR_LEN; if ((plen -= ETHER_HDR_LEN) <= 0) { return BCME_ERROR; } } } /* L3 header/pointer check */ fp->l3 = p; fp->l3_len = (uint16)plen; switch (type) { case ETHER_TYPE_ARP: { if ((plen -= ARP_DATA_LEN) < 0) { return BCME_ERROR; } fp->l3_t = FRAME_L3_ARP_H; /* no layer 4 protocol, return */ return BCME_OK; break; } case ETHER_TYPE_IP: { struct ipv4_hdr *iph = (struct ipv4_hdr *)p; len = IPV4_HLEN(iph); if ((plen -= len) <= 0) { return BCME_ERROR; } if (IP_VER(iph) == IP_VER_4 && len >= IPV4_MIN_HEADER_LEN) { fp->l3_t = FRAME_L3_IP_H; type = IPV4_PROT(iph); p += len; } else { /* not a valid ipv4 packet */ return BCME_ERROR; } break; } case ETHER_TYPE_IPV6: { struct ipv6_hdr *ip6h = (struct ipv6_hdr *)p; if ((plen -= IPV6_MIN_HLEN) <= 0) { return BCME_ERROR; } if (IP_VER(ip6h) == IP_VER_6) { fp->l3_t = FRAME_L3_IP6_H; type = IPV6_PROT(ip6h); p += IPV6_MIN_HLEN; if (IPV6_EXTHDR(type)) { uint8 proto = 0; int32 exth_len = ipv6_exthdr_len_check(p, plen, &proto); if (exth_len < 0 || ((plen -= exth_len) <= 0)) return BCME_ERROR; type = proto; p += exth_len; } } else { /* not a valid ipv6 packet */ return BCME_ERROR; } break; } case ETHER_TYPE_802_1X: { eapol_hdr_t *eapolh = (eapol_hdr_t *)p; if ((plen -= EAPOL_HDR_LEN) <= 0) { return BCME_ERROR; } if (eapolh->type == EAPOL_KEY) { fp->l3_t = FRAME_L3_8021X_EAPOLKEY_H; return BCME_OK; } else { /* not a valid ipv6 packet */ return BCME_ERROR; } break; } default: /* not interesting case */ return BCME_ERROR; break; } /* L4 header/pointer check */ fp->l4 = p; fp->l4_len = (uint16)plen; switch (type) { case IP_PROT_ICMP: fp->l4_t = FRAME_L4_ICMP_H; if ((plen -= sizeof(struct bcmicmp_hdr)) < 0) { return BCME_ERROR; } break; case IP_PROT_IGMP: fp->l4_t = FRAME_L4_IGMP_H; if ((plen -= IGMP_HLEN) < 0) { return BCME_ERROR; } break; case IP_PROT_TCP: fp->l4_t = FRAME_L4_TCP_H; if ((plen -= sizeof(struct bcmtcp_hdr)) < 0) { return BCME_ERROR; } break; case IP_PROT_UDP: fp->l4_t = FRAME_L4_UDP_H; if ((plen -= sizeof(struct bcmudp_hdr)) < 0) { return BCME_ERROR; } break; case IP_PROT_ICMP6: fp->l4_t = FRAME_L4_ICMP6_H; if ((plen -= sizeof(struct icmp6_hdr)) < 0) { return BCME_ERROR; } break; default: break; } return BCME_OK; } #define SNAP_HDR_LEN 6 /* 802.3 LLC/SNAP header length */ #define FRAME_DROP 0 #define FRAME_NOP 1 #define FRAME_TAKEN 2 #endif /* _bcmproto_h_ */