From a667bf044a37f9e96830f1f35627829860f7019f Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 15 Jul 2011 18:48:46 +0100 Subject: [PATCH] [netdevice] Allow link layer to report broadcast/multicast packets via pull() Allow the link layer to directly report whether or not a packet is multicast or broadcast at the time of calling pull(), rather than relying on heuristics to determine this at a later stage. Signed-off-by: Michael Brown --- src/arch/i386/interface/pxe/pxe_undi.c | 14 ++++++------- src/drivers/net/ipoib.c | 5 ++++- src/include/ipxe/netdevice.h | 28 +++++++++++++++++--------- src/interface/efi/efi_snp.c | 4 +++- src/net/80211/net80211.c | 10 +++++++-- src/net/aoe.c | 5 +++-- src/net/arp.c | 4 +++- src/net/eapol.c | 4 +++- src/net/eth_slow.c | 4 +++- src/net/ethernet.c | 8 +++++++- src/net/fcoe.c | 8 ++++++-- src/net/ipv4.c | 13 +++++++----- src/net/ipv6.c | 4 +++- src/net/netdevice.c | 12 +++++++---- src/net/rarp.c | 4 +++- src/net/vlan.c | 7 +++++-- src/usr/lotest.c | 8 ++++++-- 17 files changed, 99 insertions(+), 43 deletions(-) diff --git a/src/arch/i386/interface/pxe/pxe_undi.c b/src/arch/i386/interface/pxe/pxe_undi.c index 3938207f..cf8820a0 100644 --- a/src/arch/i386/interface/pxe/pxe_undi.c +++ b/src/arch/i386/interface/pxe/pxe_undi.c @@ -652,6 +652,7 @@ PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) { const void *ll_dest; const void *ll_source; uint16_t net_proto; + unsigned int flags; size_t ll_hlen; struct net_protocol *net_protocol; unsigned int prottype; @@ -753,7 +754,8 @@ PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) { /* Strip link-layer header */ ll_protocol = pxe_netdev->ll_protocol; if ( ( rc = ll_protocol->pull ( pxe_netdev, iobuf, &ll_dest, - &ll_source, &net_proto )) !=0){ + &ll_source, &net_proto, + &flags ) ) != 0 ) { /* Assume unknown net_proto and no ll_source */ net_proto = 0; ll_source = NULL; @@ -788,14 +790,12 @@ PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) { undi_isr->Frame.segment = rm_ds; undi_isr->Frame.offset = __from_data16 ( basemem_packet ); undi_isr->ProtType = prottype; - if ( memcmp ( ll_dest, pxe_netdev->ll_addr, - ll_protocol->ll_addr_len ) == 0 ) { - undi_isr->PktType = P_DIRECTED; - } else if ( memcmp ( ll_dest, pxe_netdev->ll_broadcast, - ll_protocol->ll_addr_len ) == 0 ) { + if ( flags & LL_BROADCAST ) { undi_isr->PktType = P_BROADCAST; - } else { + } else if ( flags & LL_MULTICAST ) { undi_isr->PktType = P_MULTICAST; + } else { + undi_isr->PktType = P_DIRECTED; } DBGC2 ( &pxenv_undi_isr, " %04x:%04x+%x(%x) %s hlen %d", undi_isr->Frame.segment, undi_isr->Frame.offset, diff --git a/src/drivers/net/ipoib.c b/src/drivers/net/ipoib.c index 4917b58e..bc71a456 100644 --- a/src/drivers/net/ipoib.c +++ b/src/drivers/net/ipoib.c @@ -224,11 +224,13 @@ static int ipoib_push ( struct net_device *netdev __unused, * @ret ll_dest Link-layer destination address * @ret ll_source Source link-layer address * @ret net_proto Network-layer protocol, in network-byte order + * @ret flags Packet flags * @ret rc Return status code */ static int ipoib_pull ( struct net_device *netdev, struct io_buffer *iobuf, const void **ll_dest, - const void **ll_source, uint16_t *net_proto ) { + const void **ll_source, uint16_t *net_proto, + unsigned int *flags ) { struct ipoib_device *ipoib = netdev->priv; struct ipoib_hdr *ipoib_hdr = iobuf->data; struct ipoib_peer *dest; @@ -255,6 +257,7 @@ static int ipoib_pull ( struct net_device *netdev, *ll_dest = ( dest ? &dest->mac : &ipoib->broadcast ); *ll_source = ( source ? &source->mac : &ipoib->broadcast ); *net_proto = ipoib_hdr->proto; + *flags = ( ( *ll_dest == &ipoib->broadcast ) ? LL_BROADCAST : 0 ); return 0; } diff --git a/src/include/ipxe/netdevice.h b/src/include/ipxe/netdevice.h index 64285984..3633a165 100644 --- a/src/include/ipxe/netdevice.h +++ b/src/include/ipxe/netdevice.h @@ -66,20 +66,23 @@ struct net_protocol { /** * Process received packet * - * @v iobuf I/O buffer - * @v netdev Network device - * @v ll_dest Link-layer destination address - * @v ll_source Link-layer source address + * @v iobuf I/O buffer + * @v netdev Network device + * @v ll_dest Link-layer destination address + * @v ll_source Link-layer source address + * @v flags Packet flags + * @ret rc Return status code * * This method takes ownership of the I/O buffer. */ int ( * rx ) ( struct io_buffer *iobuf, struct net_device *netdev, - const void *ll_dest, const void *ll_source ); + const void *ll_dest, const void *ll_source, + unsigned int flags ); /** * Transcribe network-layer address * - * @v net_addr Network-layer address - * @ret string Human-readable transcription of address + * @v net_addr Network-layer address + * @ret string Human-readable transcription of address * * This method should convert the network-layer address into a * human-readable format (e.g. dotted quad notation for IPv4). @@ -97,6 +100,12 @@ struct net_protocol { uint8_t net_addr_len; }; +/** Packet is a multicast (including broadcast) packet */ +#define LL_MULTICAST 0x0001 + +/** Packet is a broadcast packet */ +#define LL_BROADCAST 0x0002 + /** * A link-layer protocol * @@ -125,11 +134,12 @@ struct ll_protocol { * @ret ll_dest Link-layer destination address * @ret ll_source Source link-layer address * @ret net_proto Network-layer protocol, in network-byte order + * @ret flags Packet flags * @ret rc Return status code */ int ( * pull ) ( struct net_device *netdev, struct io_buffer *iobuf, const void **ll_dest, const void **ll_source, - uint16_t *net_proto ); + uint16_t *net_proto, unsigned int *flags ); /** * Initialise link-layer address * @@ -611,7 +621,7 @@ extern int net_tx ( struct io_buffer *iobuf, struct net_device *netdev, const void *ll_source ); extern int net_rx ( struct io_buffer *iobuf, struct net_device *netdev, uint16_t net_proto, const void *ll_dest, - const void *ll_source ); + const void *ll_source, unsigned int flags ); extern void net_poll ( void ); /** diff --git a/src/interface/efi/efi_snp.c b/src/interface/efi/efi_snp.c index bc6c0919..4c499826 100644 --- a/src/interface/efi/efi_snp.c +++ b/src/interface/efi/efi_snp.c @@ -658,6 +658,7 @@ efi_snp_receive ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, const void *iob_ll_dest; const void *iob_ll_src; uint16_t iob_net_proto; + unsigned int iob_flags; int rc; EFI_STATUS efirc; @@ -682,7 +683,8 @@ efi_snp_receive ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, /* Attempt to decode link-layer header */ if ( ( rc = ll_protocol->pull ( snpdev->netdev, iobuf, &iob_ll_dest, - &iob_ll_src, &iob_net_proto ) ) != 0 ){ + &iob_ll_src, &iob_net_proto, + &iob_flags ) ) != 0 ) { DBGC ( snpdev, "SNPDEV %p could not parse header: %s\n", snpdev, strerror ( rc ) ); efirc = RC_TO_EFIRC ( rc ); diff --git a/src/net/80211/net80211.c b/src/net/80211/net80211.c index 466d1243..c00363cd 100644 --- a/src/net/80211/net80211.c +++ b/src/net/80211/net80211.c @@ -135,7 +135,8 @@ static int net80211_ll_push ( struct net_device *netdev, const void *ll_source, uint16_t net_proto ); static int net80211_ll_pull ( struct net_device *netdev, struct io_buffer *iobuf, const void **ll_dest, - const void **ll_source, uint16_t * net_proto ); + const void **ll_source, uint16_t * net_proto, + unsigned int *flags ); /** @} */ /** @@ -529,6 +530,7 @@ static int net80211_ll_push ( struct net_device *netdev, * @ret ll_dest Link-layer destination address * @ret ll_source Link-layer source * @ret net_proto Network-layer protocol, in network byte order + * @ret flags Packet flags * @ret rc Return status code * * This expects and removes both the 802.11 frame header and the 802.2 @@ -537,7 +539,7 @@ static int net80211_ll_push ( struct net_device *netdev, static int net80211_ll_pull ( struct net_device *netdev __unused, struct io_buffer *iobuf, const void **ll_dest, const void **ll_source, - uint16_t * net_proto ) + uint16_t * net_proto, unsigned int *flags ) { struct ieee80211_frame *hdr = iobuf->data; struct ieee80211_llc_snap_header *lhdr = @@ -586,6 +588,10 @@ static int net80211_ll_pull ( struct net_device *netdev __unused, *ll_dest = hdr->addr1; *ll_source = hdr->addr3; *net_proto = lhdr->ethertype; + *flags = ( ( is_multicast_ether_addr ( hdr->addr1 ) ? + LL_MULTICAST : 0 ) | + ( is_broadcast_ether_addr ( hdr->addr1 ) ? + LL_BROADCAST : 0 ) ); return 0; } diff --git a/src/net/aoe.c b/src/net/aoe.c index 3b1953a2..1016b250 100644 --- a/src/net/aoe.c +++ b/src/net/aoe.c @@ -906,13 +906,14 @@ static int aoedev_open ( struct interface *parent, struct net_device *netdev, * @v netdev Network device * @v ll_dest Link-layer destination address * @v ll_source Link-layer source address + * @v flags Packet flags * @ret rc Return status code - * */ static int aoe_rx ( struct io_buffer *iobuf, struct net_device *netdev __unused, const void *ll_dest __unused, - const void *ll_source ) { + const void *ll_source, + unsigned int flags __unused ) { struct aoehdr *aoehdr = iobuf->data; struct aoe_command *aoecmd; int rc; diff --git a/src/net/arp.c b/src/net/arp.c index 9b5fd220..ef30d5ec 100644 --- a/src/net/arp.c +++ b/src/net/arp.c @@ -186,6 +186,7 @@ static struct arp_net_protocol * arp_find_protocol ( uint16_t net_proto ) { * @v iobuf I/O buffer * @v netdev Network device * @v ll_source Link-layer source address + * @v flags Packet flags * @ret rc Return status code * * This handles ARP requests and responses as detailed in RFC826. The @@ -196,7 +197,8 @@ static struct arp_net_protocol * arp_find_protocol ( uint16_t net_proto ) { */ static int arp_rx ( struct io_buffer *iobuf, struct net_device *netdev, const void *ll_dest __unused, - const void *ll_source __unused ) { + const void *ll_source __unused, + unsigned int flags __unused ) { struct arphdr *arphdr = iobuf->data; struct arp_net_protocol *arp_net_protocol; struct net_protocol *net_protocol; diff --git a/src/net/eapol.c b/src/net/eapol.c index 9e5f2640..dd042083 100644 --- a/src/net/eapol.c +++ b/src/net/eapol.c @@ -38,11 +38,13 @@ FILE_LICENCE ( GPL2_OR_LATER ); * @v netdev Network device * @v ll_dest Link-layer destination address * @v ll_source Link-layer source address + * @v flags Packet flags * * This function takes ownership of the I/O buffer passed to it. */ static int eapol_rx ( struct io_buffer *iob, struct net_device *netdev, - const void *ll_dest, const void *ll_source ) { + const void *ll_dest, const void *ll_source, + unsigned int flags __unused ) { struct eapol_frame *eapol = iob->data; struct eapol_handler *handler; diff --git a/src/net/eth_slow.c b/src/net/eth_slow.c index 9e68939c..593e45bc 100644 --- a/src/net/eth_slow.c +++ b/src/net/eth_slow.c @@ -234,12 +234,14 @@ static int eth_slow_marker_rx ( struct io_buffer *iobuf, * @v netdev Network device * @v ll_dest Link-layer destination address * @v ll_source Link-layer source address + * @v flags Packet flags * @ret rc Return status code */ static int eth_slow_rx ( struct io_buffer *iobuf, struct net_device *netdev, const void *ll_dest __unused, - const void *ll_source __unused ) { + const void *ll_source __unused, + unsigned int flags __unused ) { union eth_slow_packet *eth_slow = iobuf->data; /* Sanity checks */ diff --git a/src/net/ethernet.c b/src/net/ethernet.c index d14cfefc..c63fd9bc 100644 --- a/src/net/ethernet.c +++ b/src/net/ethernet.c @@ -71,11 +71,13 @@ static int eth_push ( struct net_device *netdev __unused, * @ret ll_dest Link-layer destination address * @ret ll_source Source link-layer address * @ret net_proto Network-layer protocol, in network-byte order + * @ret flags Packet flags * @ret rc Return status code */ static int eth_pull ( struct net_device *netdev __unused, struct io_buffer *iobuf, const void **ll_dest, - const void **ll_source, uint16_t *net_proto ) { + const void **ll_source, uint16_t *net_proto, + unsigned int *flags ) { struct ethhdr *ethhdr = iobuf->data; /* Sanity check */ @@ -92,6 +94,10 @@ static int eth_pull ( struct net_device *netdev __unused, *ll_dest = ethhdr->h_dest; *ll_source = ethhdr->h_source; *net_proto = ethhdr->h_protocol; + *flags = ( ( is_multicast_ether_addr ( ethhdr->h_dest ) ? + LL_MULTICAST : 0 ) | + ( is_broadcast_ether_addr ( ethhdr->h_dest ) ? + LL_BROADCAST : 0 ) ); return 0; } diff --git a/src/net/fcoe.c b/src/net/fcoe.c index db2fc980..c54d1b47 100644 --- a/src/net/fcoe.c +++ b/src/net/fcoe.c @@ -331,10 +331,12 @@ static struct io_buffer * fcoe_alloc_iob ( struct fcoe_port *fcoe __unused, * @v netdev Network device * @v ll_dest Link-layer destination address * @v ll_source Link-layer source address + * @v flags Packet flags * @ret rc Return status code */ static int fcoe_rx ( struct io_buffer *iobuf, struct net_device *netdev, - const void *ll_dest, const void *ll_source ) { + const void *ll_dest, const void *ll_source, + unsigned int flags __unused ) { struct fcoe_header *fcoehdr; struct fcoe_footer *fcoeftr; struct fcoe_port *fcoe; @@ -924,12 +926,14 @@ static struct fip_handler fip_handlers[] = { * @v netdev Network device * @v ll_dest Link-layer destination address * @v ll_source Link-layer source address + * @v flags Packet flags * @ret rc Return status code */ static int fcoe_fip_rx ( struct io_buffer *iobuf, struct net_device *netdev, const void *ll_dest, - const void *ll_source __unused ) { + const void *ll_source __unused, + unsigned int flags __unused ) { struct fip_header *fiphdr = iobuf->data; struct fip_descriptors descs; struct fip_handler *handler; diff --git a/src/net/ipv4.c b/src/net/ipv4.c index 5bb48f61..01eca09d 100644 --- a/src/net/ipv4.c +++ b/src/net/ipv4.c @@ -381,10 +381,12 @@ static int ipv4_tx ( struct io_buffer *iobuf, /** * Process incoming packets * - * @v iobuf I/O buffer - * @v netdev Network device - * @v ll_dest Link-layer destination address - * @v ll_source Link-layer destination source + * @v iobuf I/O buffer + * @v netdev Network device + * @v ll_dest Link-layer destination address + * @v ll_source Link-layer destination source + * @v flags Packet flags + * @ret rc Return status code * * This function expects an IP4 network datagram. It processes the headers * and sends it to the transport layer. @@ -392,7 +394,8 @@ static int ipv4_tx ( struct io_buffer *iobuf, static int ipv4_rx ( struct io_buffer *iobuf, struct net_device *netdev __unused, const void *ll_dest __unused, - const void *ll_source __unused ) { + const void *ll_source __unused, + unsigned int flags __unused ) { struct iphdr *iphdr = iobuf->data; size_t hdrlen; size_t len; diff --git a/src/net/ipv6.c b/src/net/ipv6.c index 712aa49e..57bf94d8 100644 --- a/src/net/ipv6.c +++ b/src/net/ipv6.c @@ -288,13 +288,15 @@ static int ipv6_process_nxt_hdr ( struct io_buffer *iobuf, uint8_t nxt_hdr, * @v netdev Network device * @v ll_dest Link-layer destination address * @v ll_source Link-layer source address + * @v flags Packet flags * * This function processes a IPv6 packet */ static int ipv6_rx ( struct io_buffer *iobuf, __unused struct net_device *netdev, __unused const void *ll_dest, - __unused const void *ll_source ) { + __unused const void *ll_source, + __unused unsigned int flags ) { struct ip6_header *ip6hdr = iobuf->data; union { diff --git a/src/net/netdevice.c b/src/net/netdevice.c index 52ad8292..f5ec4191 100644 --- a/src/net/netdevice.c +++ b/src/net/netdevice.c @@ -678,17 +678,19 @@ int net_tx ( struct io_buffer *iobuf, struct net_device *netdev, * @v net_proto Network-layer protocol, in network-byte order * @v ll_dest Destination link-layer address * @v ll_source Source link-layer address + * @v flags Packet flags * @ret rc Return status code */ int net_rx ( struct io_buffer *iobuf, struct net_device *netdev, - uint16_t net_proto, const void *ll_dest, const void *ll_source ) { + uint16_t net_proto, const void *ll_dest, const void *ll_source, + unsigned int flags ) { struct net_protocol *net_protocol; /* Hand off to network-layer protocol, if any */ for_each_table_entry ( net_protocol, NET_PROTOCOLS ) { if ( net_protocol->net_proto == net_proto ) return net_protocol->rx ( iobuf, netdev, ll_dest, - ll_source ); + ll_source, flags ); } DBGC ( netdev, "NETDEV %s unknown network protocol %04x\n", @@ -710,6 +712,7 @@ void net_poll ( void ) { const void *ll_dest; const void *ll_source; uint16_t net_proto; + unsigned int flags; int rc; /* Poll and process each network device */ @@ -743,7 +746,8 @@ void net_poll ( void ) { ll_protocol = netdev->ll_protocol; if ( ( rc = ll_protocol->pull ( netdev, iobuf, &ll_dest, &ll_source, - &net_proto ) ) != 0 ) { + &net_proto, + &flags ) ) != 0 ) { free_iob ( iobuf ); continue; } @@ -751,7 +755,7 @@ void net_poll ( void ) { /* Hand packet to network layer */ if ( ( rc = net_rx ( iob_disown ( iobuf ), netdev, net_proto, ll_dest, - ll_source ) ) != 0 ) { + ll_source, flags ) ) != 0 ) { /* Record error for diagnosis */ netdev_rx_err ( netdev, NULL, rc ); } diff --git a/src/net/rarp.c b/src/net/rarp.c index da67c459..59cb1d07 100644 --- a/src/net/rarp.c +++ b/src/net/rarp.c @@ -38,6 +38,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); * @v netdev Network device * @v ll_dest Link-layer destination address * @v ll_source Link-layer source address + * @v flags Packet flags * @ret rc Return status code * * This is a dummy method which simply discards RARP packets. @@ -45,7 +46,8 @@ FILE_LICENCE ( GPL2_OR_LATER ); static int rarp_rx ( struct io_buffer *iobuf, struct net_device *netdev __unused, const void *ll_dest __unused, - const void *ll_source __unused ) { + const void *ll_source __unused, + unsigned int flags __unused ) { free_iob ( iobuf ); return 0; } diff --git a/src/net/vlan.c b/src/net/vlan.c index 9ac560f1..2147f91c 100644 --- a/src/net/vlan.c +++ b/src/net/vlan.c @@ -91,12 +91,13 @@ static int vlan_transmit ( struct net_device *netdev, const void *ll_dest; const void *ll_source; uint16_t net_proto; + unsigned int flags; int rc; /* Strip link-layer header and preserve link-layer header fields */ ll_protocol = netdev->ll_protocol; if ( ( rc = ll_protocol->pull ( netdev, iobuf, &ll_dest, &ll_source, - &net_proto ) ) != 0 ) { + &net_proto, &flags ) ) != 0 ) { DBGC ( netdev, "VLAN %s could not parse link-layer header: " "%s\n", netdev->name, strerror ( rc ) ); return rc; @@ -214,10 +215,12 @@ struct net_device * vlan_find ( struct net_device *trunk, unsigned int tag ) { * @v trunk Trunk network device * @v ll_dest Link-layer destination address * @v ll_source Link-layer source address + * @v flags Packet flags * @ret rc Return status code */ static int vlan_rx ( struct io_buffer *iobuf, struct net_device *trunk, - const void *ll_dest, const void *ll_source ) { + const void *ll_dest, const void *ll_source, + unsigned int flags __unused ) { struct vlan_header *vlanhdr = iobuf->data; struct net_device *netdev; struct ll_protocol *ll_protocol; diff --git a/src/usr/lotest.c b/src/usr/lotest.c index 7f9f2fd0..6ed31ea5 100644 --- a/src/usr/lotest.c +++ b/src/usr/lotest.c @@ -47,12 +47,14 @@ FILE_LICENCE ( GPL2_OR_LATER ); * @v netdev Network device * @v ll_dest Link-layer destination address * @v ll_source Link-layer source address + * @v flags Packet flags * @ret rc Return status code */ static int lotest_rx ( struct io_buffer *iobuf, struct net_device *netdev __unused, const void *ll_dest __unused, - const void *ll_source __unused ) { + const void *ll_source __unused, + unsigned int flags __unused ) { free_iob ( iobuf ); return -ENOTSUP; } @@ -97,6 +99,7 @@ int loopback_test ( struct net_device *sender, struct net_device *receiver, const void *ll_dest; const void *ll_source; uint16_t net_proto; + unsigned int flags; unsigned int i; unsigned int successes; int rc; @@ -166,7 +169,8 @@ int loopback_test ( struct net_device *sender, struct net_device *receiver, /* Check received packet */ if ( ( rc = receiver->ll_protocol->pull ( receiver, iobuf, &ll_dest, &ll_source, - &net_proto ) ) != 0 ){ + &net_proto, + &flags ) ) != 0 ) { printf ( "\nFailed to strip link-layer header: %s", strerror ( rc ) ); goto done;