/* * ether_input() * * Called from the device driver at interrupt level to deliver * a packet to a client. It is assumed that the buffer contains * a contiguous ethernet header (up to the datalink header in * length, so a snap/sap maximum) and is short-aligned. * * The ifphys lock is held throughput this function, as it * traverses clients lists and calls the input routine for them. */ int ether_input(struct ifphys_i802 *ifpp, struct mbuf *m, void *param) { struct i802_client *icp = NULL; struct i802_etherhdr *hdr = mtod(m, struct i802_etherhdr *); int (*ic_fn)(struct mbuf *, void *); int encaps = 0;/* passed up to promisc clients, if any */ int notours = FALSE; u_int16_t host_etype = ntohs(hdr->ether_type); int xmode_notours = 1; int error = 0; M_STAMP(m); I802_IFP_REFERENCED(ifpp); /* * If the device is in promiscuous mode, this might be Somebody Else's * Packet. If so, skip the protocol client search, and go straight * to the promiscuous client processing. */ if (((ifpp->i_phys.ifp_flags & IFP_PROMISC) || (ifpp->i_phys.ifp_devflags & I802F_NONPERFECT_UNI)) && (!(hdr->ether_dhost[0] & 1)) && ((xmode_notours = bcmp6(hdr->ether_dhost, ifpp->i_phys.ifp_info.ifpi_macaddr)))) { /* test extra unicast addresses */ struct i802_uni *unip; LIST_FOREACH(unip, &ifpp->i_uni, iu_list) { if (!bcmp6(unip->iu_addr, hdr->ether_dhost)) { /* matched one of ours */ break; } } if (unip) { xmode_notours = 0; } else { /* it's not ours */ notours = TRUE; if (!(ifpp->i_phys.ifp_flags & IFP_XMODE)) { goto process_promisc; } } } if ((ifpp->i_phys.ifp_flags & IFP_XMODE) && (!xmode_notours)) { m->m_flags |= M_LOCAL; } /* * Process type-II first */ if (host_etype > ETHERMTU) { /* * dix ethertype - scan the list */ encaps = i802_ENCAPS_DIX; LIST_FOREACH(icp, &ifpp->i_dixclients, ic_list) { /* * The ethertype is stored in network * byte order to allow direct comparisons */ if (hdr->ether_type == icp->ic_ethertype) { break; } } } else { /* * Process 802.3 packets after a length check. Ignore * trailing space in the mbuf. */ if ((u_int) m->m_pkthdr.len >= (host_etype + sizeof (struct i802_etherhdr))) { int found = FALSE; struct llc *llc = (struct llc *) (hdr + 1); struct i802_client *listcp; /* * Loop through the clients */ for (listcp = LIST_FIRST(&ifpp->i_sapclients); listcp != NULL; listcp = LIST_NEXT(listcp, ic_list)) { switch (listcp->ic_encaps) { case i802_ENCAPS_NOVELL: if ((llc->llc_ssap == 0xff) && (llc->llc_dsap == 0xff)) { found = TRUE; } break; case i802_ENCAPS_LLC1: if ((llc->llc_control == LLC_UI) && (listcp->ic_dsap == llc->llc_dsap)) { found = TRUE; } break; case i802_ENCAPS_LLC2: if ((llc->llc_control != LLC_UI) && (listcp->ic_dsap == llc->llc_dsap)) { found = TRUE; } break; case i802_ENCAPS_SNAP: if ((llc->llc_ssap == LLC_SNAP_LSAP) && (llc->llc_dsap == LLC_SNAP_LSAP) && (llc->llc_control == LLC_UI) && (bcmp(listcp->ic_snap, llc->llc_snap.org_code, 5) == 0)) { found = TRUE; } break; } if (found == TRUE) { encaps = listcp->ic_encaps; icp = listcp; break; } } } } process_promisc: /* * If there's no client already identified, set up to deliver * to an L2 promiscouous client (if there is one). */ if (icp == NULL) { icp = ifpp->i_phys.ifp_l2promisc; } /* * Pass all packets to clients who have registered to receive all * encapsulations. If the packet is not required by a protocol * client, the passed mbuf will be transferred to the last * promiscuous client. Otherwise the mbuf will be left unchanged. * (This is mainly an optimisation for pure bridge ports, where * there will be a single promiscuous client - a buffer copy is * avoided in this case.) * * Ordering here is important. This processing must be done * before the MAC header is (possibly) stripped. */ if (!LIST_EMPTY(&ifpp->i_promisc)) { struct i802_promisc *lp; struct mbuf *m0 = NULL; /* * Find the encapsulation if it's not known. */ if (encaps == 0) { if (host_etype > ETHERMTU) { /* standard Ethernet encapsulation */ encaps = i802_ENCAPS_DIX; } else { struct llc *llc = (struct llc *) (hdr + 1); switch (llc->llc_dsap) { case 0xff: encaps = i802_ENCAPS_NOVELL; break; case LLC_SNAP_LSAP: encaps = i802_ENCAPS_SNAP; break; default: /* LLC1 or LLC2 */ switch (llc->llc_control) { case LLC_UI: case LLC_UI_P: case LLC_TEST: case LLC_TEST_P: case LLC_XID: case LLC_XID_P: encaps = i802_ENCAPS_LLC1; break; default: encaps = i802_ENCAPS_LLC2; break; } break; } } } /* encaps == 0 */ LIST_FOREACH(lp, &ifpp->i_promisc, ipr_list) { if (icp == NULL && LIST_NEXT(lp, ipr_list) == NULL) { if (ether_filter_check(hdr, lp, encaps, 0) == i802_FILTER_ACTION_DISCARD) { continue; } /* pass packet to promiscuous listener */ m0 = m; m = NULL;/* we'll consume the mbuf */ } else { /* * Check if the promisc client wants the * packet in the presence of other clients. */ if (icp != NULL && (lp->ipr_flags & i802_IPR_EXCLUSIVE)) { continue; } if (ether_filter_check(hdr, lp, encaps, 0) == i802_FILTER_ACTION_DISCARD) { continue; } /* pass packet to promiscuous listener */ m0 = m_copym(m, 0, M_COPYALL, M_DONTWAIT); /* * If allocation failed, m will be freed below. */ if (m0 == NULL) { break; } } /* * It would be nice to release the lock here, but we * can't rely on the ifphys promisc client list * to stay the same if we do. */ (*lp->ipr_client)(m0, lp->ipr_param, encaps, notours); } } if (icp != NULL) { /* * Strip off the link-layer header if required, set the * appropriate flags, and call the protocol client. */ if (icp->ic_inchdr == FALSE) { m_adj(m, icp->ic_hdrlen); } if (hdr->ether_dhost[0] & 1) { if (!bcmp6(ether_broadcastaddr, hdr->ether_dhost)) { m->m_flags |= M_BCAST; } else { m->m_flags |= M_MCAST; #ifdef IP_CLUSTERING /* * Mark multicast packet for potential * load-balancing ONLY if clustering is * actually running. */ if (!LIST_EMPTY(&ifpp->i_cluster)) { m->m_flags |= M_CLUSTER; } #endif /* IP_CLUSTERING */ } } #ifdef IP_CLUSTERING /* * In this cluster multicast list match, if dest. mac * address matches w/one of the multicast list node, * set the flag, and copy the corresponding cluster * information into the mbuf's pkthdr. */ if (!LIST_EMPTY(&ifpp->i_cluster)) { struct i802_cluster *lp; LIST_FOREACH(lp, &ifpp->i_cluster, ic_list) { if (!bcmp6(lp->ic_addr, hdr->ether_dhost)) { /* * Mark as a cluster packet */ m->m_flags |= M_CLUSTER; /* * Clear the multicast flag * so it will not be dropped as layer 2 * multicast check later. */ m->m_flags &= ~M_MCAST; /* * Copy the cluster information */ m->m_loadb.lb_cluster_info = *(u_int32_t *) &hdr->ether_dhost[2]; break; } } } #endif /* IP_CLUSTERING */ /* * Hold the client structure to preserve it while * the ifphys lock is released. */ ic_fn = icp->ic_client; i802_client_hold(icp); I802_IFP_UNLOCK(ifpp); error = (*ic_fn)(m, icp); I802_IFP_LOCK(ifpp); i802_client_release(icp); } else { /* * No client: discard the packet and increment the * unknown protocol counter */ m_freem(m); ifpp->i_phys.ifp_stats.ifs_noproto++; } return (error); } /* * ether_open_rx() * * Called by a protocol client to add its client handler on an ethernet * device. The i802_client structure is owned by the ethernet code * until the client releases it with a call to ether_close_rx(). No fields * of the struct should be modified by the client after this call. * The client handler will be called to handle all packets for that protocol * on this phys ethernet device (or vlan "channel" of this device.) * * This code is called via management, so we only need to lock when * changing the ifphys, not when reading. */ static int ether_open_rx(struct ifphys *physp, struct iffamily *iff, void *param) { struct ifphys_i802 *ifpp = (struct ifphys_i802 *) physp; struct i802_client *ticp, *icp = (struct i802_client *) param; int found; struct i802_vlan_client *vcp = NULL; u_int16_tvlan_id = VLAN_NULL; /* * The entry must be unique - check to see if someone has * already opened a port with the same encapsulation. If * they are opening a port on a VLAN, check the per-vlan * list of clients for dups to this new one. */ if (icp->ic_encaps == i802_ENCAPS_DIX) { /* * Convert to net byte order to allow direct comparisons */ icp->ic_ethertype = htons(icp->ic_ethertype); /* * Setup to scan down the list of clients. * If we are opening on a VLAN, scan that VLAN's list of * clients. If not, scan the clients on this phys. */ if ((vlan_id = icp->ic_vlan_id) != VLAN_NULL) { if (vlan_id > VID_MAX) return (ENODEV); LIST_FOREACH(ticp, &ifpp->i_dixclients, ic_list) { if (ticp->ic_ethertype == ntohs(ETHERTYPE_VLAN)) break; } /* * If this is the first VLAN "channel" on this ifphys, * create the vlan client structure and hook it in * as another dixclient. */ if (ticp == NULL) { /* * Allocate the VLAN client using the * I802 client routine, as it has an i802 * client embedded in it. */ vcp = (struct i802_vlan_client *) i802_client_alloc(sizeof (*vcp)); if (vcp == NULL) return (ENOMEM); /* * ether_vlan_input needs the full L2 header. */ vcp->v_ic.ic_inchdr = TRUE; vcp->v_ic.ic_encaps = i802_ENCAPS_DIX; vcp->v_ic.ic_client = ether_vlan_input; vcp->v_ic.ic_ethertype = ntohs(ETHERTYPE_VLAN); vcp->v_ic.ic_param = vcp; vcp->v_ifpp = ifpp; I802_IFP_LOCK(ifpp); ifpp->i_vcp = vcp; LIST_INSERT_HEAD(&ifpp->i_dixclients, &vcp->v_ic, ic_list); I802_IFP_UNLOCK(ifpp); } else { vcp = (struct i802_vlan_client *) ticp; } ticp = VLAN_FIRST(vcp, vlan_id); } else { ticp = LIST_FIRST(&ifpp->i_dixclients); } while (ticp != NULL) { if (icp->ic_ethertype == ticp->ic_ethertype) break; ticp = LIST_NEXT(ticp, ic_list); } if (ticp != NULL) { return (EEXIST); } } else if (icp->ic_encaps == i802_ENCAPS_PROMISC) { if (ifpp->i_phys.ifp_l2promisc) return (EEXIST); } else { for (ticp = LIST_FIRST(&ifpp->i_sapclients), found = FALSE; ticp != NULL && !found; ticp = LIST_NEXT(ticp, ic_list)) { if (ticp->ic_encaps == icp->ic_encaps) { switch (icp->ic_encaps) { case i802_ENCAPS_LLC1: case i802_ENCAPS_LLC2: if (ticp->ic_dsap == icp->ic_dsap) { found = TRUE; } break; case i802_ENCAPS_SNAP: if (bcmp(ticp->ic_snap, icp->ic_snap, 5) == 0) { found = TRUE; } break; case i802_ENCAPS_NOVELL: /* * Can only be one raw 802.3 client */ found = TRUE; break; default: panic("ether_openrx: unknown encaps"); } } } if (found == TRUE) { return (EEXIST); } } icp->ic_iff = iff; /* set family */ /* * hard-code the number of bytes to strip from the incoming * ethernet frame */ switch (icp->ic_encaps) { case i802_ENCAPS_DIX: if (vlan_id != VLAN_NULL) icp->ic_hdrlen = 18; else icp->ic_hdrlen = 14; /* 6 + 6 + 2 type */ break; case i802_ENCAPS_LLC1: icp->ic_hdrlen = 17; /* 6 + 6 + 2 len + 3 ssap/dsap/ctl */ break; case i802_ENCAPS_LLC2: icp->ic_hdrlen = 14; /* 6 + 6 + 2 len */ break; /* ssap + dsap passed to client */ case i802_ENCAPS_SNAP: icp->ic_hdrlen = 22; /* 6 + 6 + 2 len + 3 ssap/dsap/ctl */ break; /* + 3 oui + 2 pid */ case i802_ENCAPS_NOVELL: icp->ic_hdrlen = 14; /* 6 + 6 + 2 len */ break; case i802_ENCAPS_PROMISC: icp->ic_hdrlen = 0; I802_IFP_LOCK(ifpp); ifpp->i_phys.ifp_l2promisc = icp; ifphys_hold(&ifpp->i_phys);/* hold for promisc. client */ I802_IFP_UNLOCK(ifpp); return (0); } /* * Insert onto the appropriate queue, and violate the golden rule of * no protocol references in the datalink code by always making sure * the cash cow is at the head of the DIX list */ I802_IFP_LOCK(ifpp); if (icp->ic_encaps == i802_ENCAPS_DIX) { if (vlan_id != VLAN_NULL) { if ((icp->ic_ethertype == ntohs(ETHERTYPE_IP)) || (VLAN_FIRST(vcp, vlan_id) == NULL)) { LIST_INSERT_HEAD( &vcp->v_clients[vlan_id].i_dixclients, icp, ic_list); } else { LIST_INSERT_AFTER(VLAN_FIRST(vcp, vlan_id), icp, ic_list); } vlan_client_hold(vcp); } else {/* non-vlan */ if ((icp->ic_ethertype == ntohs(ETHERTYPE_IP)) || LIST_EMPTY(&ifpp->i_dixclients)) { LIST_INSERT_HEAD(&ifpp->i_dixclients, icp, ic_list); } else { LIST_INSERT_AFTER( LIST_FIRST(&ifpp->i_dixclients), icp, ic_list); } } } else { LIST_INSERT_HEAD(&ifpp->i_sapclients, icp, ic_list); } ifphys_hold(&ifpp->i_phys);/* hold for client */ I802_IFP_UNLOCK(ifpp); return (0); }