/*** * * stack/eth.c - Ethernet-specific functions * * Copyright (C) 2002 Ulrich Marx * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include #include #include #include #include /* * Create the Ethernet MAC header for an arbitrary protocol layer * * saddr=NULL means use device source address * daddr=NULL means leave destination address (eg unresolved arp) */ int rt_eth_header(struct rtskb *skb, struct rtnet_device *rtdev, unsigned short type, void *daddr, void *saddr, unsigned len) { struct ethhdr *eth = (struct ethhdr *)rtskb_push(skb, ETH_HLEN); /* * Set rtskb mac field */ skb->mac.ethernet = eth; /* * Set the protocol type. For a packet of type ETH_P_802_3 we put the length * in here instead. It is up to the 802.2 layer to carry protocol information. */ if (type != ETH_P_802_3) eth->h_proto = htons(type); else eth->h_proto = htons(len); /* * Set the source hardware address. */ if (saddr) memcpy(eth->h_source, saddr, rtdev->addr_len); else memcpy(eth->h_source, rtdev->dev_addr, rtdev->addr_len); if (rtdev->flags & (IFF_LOOPBACK | IFF_NOARP)) { memset(eth->h_dest, 0, rtdev->addr_len); return rtdev->hard_header_len; } if (daddr) { memcpy(eth->h_dest, daddr, rtdev->addr_len); return rtdev->hard_header_len; } return -rtdev->hard_header_len; } unsigned short rt_eth_type_trans(struct rtskb *skb, struct rtnet_device *rtdev) { struct ethhdr *eth; unsigned char *rawp; rtcap_mark_incoming(skb); skb->mac.raw = skb->data; rtskb_pull(skb, rtdev->hard_header_len); eth = skb->mac.ethernet; if (*eth->h_dest & 1) { if (memcmp(eth->h_dest, rtdev->broadcast, ETH_ALEN) == 0) skb->pkt_type = PACKET_BROADCAST; else skb->pkt_type = PACKET_MULTICAST; } /* * This ALLMULTI check should be redundant by 1.4 * so don't forget to remove it. * * Seems, you forgot to remove it. All silly devices * seems to set IFF_PROMISC. */ else if (1 /*rtdev->flags&IFF_PROMISC*/) { if (memcmp(eth->h_dest, rtdev->dev_addr, ETH_ALEN)) skb->pkt_type = PACKET_OTHERHOST; } if (ntohs(eth->h_proto) >= 1536) return eth->h_proto; rawp = skb->data; /* * This is a magic hack to spot IPX packets. Older Novell breaks * the protocol design and runs IPX over 802.3 without an 802.2 LLC * layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This * won't work for fault tolerant netware but does for the rest. */ if (*(unsigned short *)rawp == 0xFFFF) return htons(ETH_P_802_3); /* * Real 802.2 LLC */ return htons(ETH_P_802_2); } EXPORT_SYMBOL_GPL(rt_eth_header); EXPORT_SYMBOL_GPL(rt_eth_type_trans);