| /* |
| * Fundamental constants relating to IP Protocol |
| * |
| * Copyright (C) 2020, 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. |
| * |
| * |
| * <<Broadcom-WL-IPTag/Dual:>> |
| */ |
| |
| #ifndef _bcmproto_h_ |
| #define _bcmproto_h_ |
| |
| #ifndef _TYPEDEFS_H_ |
| #include <typedefs.h> |
| #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_ */ |