mirror of https://github.com/ipxe/ipxe.git
				
				
				
			Add untested support for UNDI transmit and receive.
							parent
							
								
									e42eba4af4
								
							
						
					
					
						commit
						332614a382
					
				|  | @ -30,6 +30,8 @@ struct arp_net_protocol { | ||||||
| #define __arp_net_protocol \ | #define __arp_net_protocol \ | ||||||
| 	__table ( struct arp_net_protocol, arp_net_protocols, 01 ) | 	__table ( struct arp_net_protocol, arp_net_protocols, 01 ) | ||||||
| 
 | 
 | ||||||
|  | extern struct net_protocol arp_protocol; | ||||||
|  | 
 | ||||||
| extern int arp_resolve ( struct net_device *netdev, | extern int arp_resolve ( struct net_device *netdev, | ||||||
| 			 struct net_protocol *net_protocol, | 			 struct net_protocol *net_protocol, | ||||||
| 			 const void *dest_net_addr, | 			 const void *dest_net_addr, | ||||||
|  |  | ||||||
|  | @ -122,6 +122,8 @@ struct ll_protocol { | ||||||
| 	uint16_t ll_proto; | 	uint16_t ll_proto; | ||||||
| 	/** Link-layer address length */ | 	/** Link-layer address length */ | ||||||
| 	uint8_t ll_addr_len; | 	uint8_t ll_addr_len; | ||||||
|  | 	/** Link-layer header length */ | ||||||
|  | 	uint8_t ll_header_len; | ||||||
| 	/** Link-layer broadcast address */ | 	/** Link-layer broadcast address */ | ||||||
| 	const uint8_t *ll_broadcast; | 	const uint8_t *ll_broadcast; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -0,0 +1,14 @@ | ||||||
|  | #ifndef _GPXE_RARP_H | ||||||
|  | #define _GPXE_RARP_H | ||||||
|  | 
 | ||||||
|  | /** @file
 | ||||||
|  |  * | ||||||
|  |  * Reverse Address Resolution Protocol | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | struct net_protocol; | ||||||
|  | 
 | ||||||
|  | extern struct net_protocol rarp_protocol; | ||||||
|  | 
 | ||||||
|  | #endif /* _GPXE_RARP_H */ | ||||||
|  | @ -23,12 +23,18 @@ | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
|  | #include <stdio.h> | ||||||
| #include <string.h> | #include <string.h> | ||||||
| #include <byteswap.h> | #include <byteswap.h> | ||||||
|  | #include <basemem_packet.h> | ||||||
| #include <gpxe/netdevice.h> | #include <gpxe/netdevice.h> | ||||||
|  | #include <gpxe/iobuf.h> | ||||||
| #include <gpxe/device.h> | #include <gpxe/device.h> | ||||||
| #include <gpxe/pci.h> | #include <gpxe/pci.h> | ||||||
| #include <gpxe/if_ether.h> | #include <gpxe/if_ether.h> | ||||||
|  | #include <gpxe/ip.h> | ||||||
|  | #include <gpxe/arp.h> | ||||||
|  | #include <gpxe/rarp.h> | ||||||
| #include <gpxe/shutdown.h> | #include <gpxe/shutdown.h> | ||||||
| #include "pxe.h" | #include "pxe.h" | ||||||
| 
 | 
 | ||||||
|  | @ -128,61 +134,76 @@ PXENV_EXIT_t pxenv_undi_close ( struct s_PXENV_UNDI_CLOSE *undi_close ) { | ||||||
|  */ |  */ | ||||||
| PXENV_EXIT_t pxenv_undi_transmit ( struct s_PXENV_UNDI_TRANSMIT | PXENV_EXIT_t pxenv_undi_transmit ( struct s_PXENV_UNDI_TRANSMIT | ||||||
| 				   *undi_transmit ) { | 				   *undi_transmit ) { | ||||||
| 	struct s_PXENV_UNDI_TBD *tbd; | 	struct s_PXENV_UNDI_TBD tbd; | ||||||
| 	const char *dest; | 	struct DataBlk *datablk; | ||||||
| 	unsigned int type; | 	struct io_buffer *iobuf; | ||||||
| 	unsigned int length; | 	struct net_protocol *net_protocol; | ||||||
| 	const char *data; | 	char destaddr[MAX_LL_ADDR_LEN]; | ||||||
|  | 	const void *ll_dest; | ||||||
|  | 	size_t len; | ||||||
|  | 	unsigned int i; | ||||||
|  | 	int rc; | ||||||
| 
 | 
 | ||||||
| 	DBG ( "PXENV_UNDI_TRANSMIT" ); | 	DBG ( "PXENV_UNDI_TRANSMIT" ); | ||||||
| 
 | 
 | ||||||
| #if 0 | 	/* Identify network-layer protocol */ | ||||||
| 	/* We support only the "immediate" portion of the TBD.  Who
 |  | ||||||
| 	 * knows what Intel's "engineers" were smoking when they came |  | ||||||
| 	 * up with the array of transmit data blocks... |  | ||||||
| 	 */ |  | ||||||
| 	tbd = SEGOFF16_TO_PTR ( undi_transmit->TBD ); |  | ||||||
| 	if ( tbd->DataBlkCount > 0 ) { |  | ||||||
| 		undi_transmit->Status = PXENV_STATUS_UNDI_INVALID_PARAMETER; |  | ||||||
| 		return PXENV_EXIT_FAILURE; |  | ||||||
| 	} |  | ||||||
| 	data = SEGOFF16_TO_PTR ( tbd->Xmit ); |  | ||||||
| 	length = tbd->ImmedLength; |  | ||||||
| 
 |  | ||||||
| 	/* If destination is broadcast, we need to supply the MAC address */ |  | ||||||
| 	if ( undi_transmit->XmitFlag == XMT_BROADCAST ) { |  | ||||||
| 		dest = broadcast_mac; |  | ||||||
| 	} else { |  | ||||||
| 		dest = SEGOFF16_TO_PTR ( undi_transmit->DestAddr ); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/* We can't properly support P_UNKNOWN without rewriting all
 |  | ||||||
| 	 * the driver transmit() methods, so we cheat: if P_UNKNOWN is |  | ||||||
| 	 * specified we rip the destination address and type out of |  | ||||||
| 	 * the pre-assembled packet, then skip over the header. |  | ||||||
| 	 */ |  | ||||||
| 	switch ( undi_transmit->Protocol ) { | 	switch ( undi_transmit->Protocol ) { | ||||||
| 	case P_IP:	type = ETH_P_IP;	break; | 	case P_IP:	net_protocol = &ipv4_protocol;	break; | ||||||
| 	case P_ARP:	type = ETH_P_ARP;	break; | 	case P_ARP:	net_protocol = &arp_protocol;	break; | ||||||
| 	case P_RARP:	type = ETH_P_RARP;	break; | 	case P_RARP:	net_protocol = &rarp_protocol;	break; | ||||||
| 	case P_UNKNOWN: | 	case P_UNKNOWN:	net_protocol = NULL;		break; | ||||||
| 		media_header = (media_header_t*)data; |  | ||||||
| 		dest = media_header->dest; |  | ||||||
| 		type = ntohs ( media_header->nstype ); |  | ||||||
| 		data += ETH_HLEN; |  | ||||||
| 		length -= ETH_HLEN; |  | ||||||
| 		break; |  | ||||||
| 	default: | 	default: | ||||||
| 		undi_transmit->Status = PXENV_STATUS_UNDI_INVALID_PARAMETER; | 		undi_transmit->Status = PXENV_STATUS_UNDI_INVALID_PARAMETER; | ||||||
| 		return PXENV_EXIT_FAILURE; | 		return PXENV_EXIT_FAILURE; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/* Send the packet */ | 	/* Calculate total packet length */ | ||||||
| 	eth_transmit ( dest, type, length, data ); | 	copy_from_real ( &tbd, undi_transmit->TBD.segment, | ||||||
| #endif | 			 undi_transmit->TBD.offset, sizeof ( tbd ) ); | ||||||
|  | 	len = tbd.ImmedLength; | ||||||
|  | 	for ( i = 0 ; i < tbd.DataBlkCount ; i++ ) { | ||||||
|  | 		datablk = &tbd.DataBlock[i]; | ||||||
|  | 		len += datablk->TDDataLen; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	undi_transmit->Status = PXENV_STATUS_SUCCESS; | 	/* Allocate and fill I/O buffer */ | ||||||
| 	return PXENV_EXIT_SUCCESS; | 	iobuf = alloc_iob ( len ); | ||||||
|  | 	if ( ! iobuf ) { | ||||||
|  | 		undi_transmit->Status = PXENV_STATUS_OUT_OF_RESOURCES; | ||||||
|  | 		return PXENV_EXIT_FAILURE; | ||||||
|  | 	} | ||||||
|  | 	copy_from_real ( iob_put ( iobuf, tbd.ImmedLength ), tbd.Xmit.segment, | ||||||
|  | 			 tbd.Xmit.offset, tbd.ImmedLength ); | ||||||
|  | 	for ( i = 0 ; i < tbd.DataBlkCount ; i++ ) { | ||||||
|  | 		datablk = &tbd.DataBlock[i]; | ||||||
|  | 		copy_from_real ( iob_put ( iobuf, datablk->TDDataLen ), | ||||||
|  | 				 datablk->TDDataPtr.segment, | ||||||
|  | 				 datablk->TDDataPtr.offset, | ||||||
|  | 				 datablk->TDDataLen ); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/* Transmit packet */ | ||||||
|  | 	if ( net_protocol == NULL ) { | ||||||
|  | 		/* Link-layer header already present */ | ||||||
|  | 		rc = netdev_tx ( pxe_netdev, iobuf ); | ||||||
|  | 	} else { | ||||||
|  | 		/* Calculate destination address */ | ||||||
|  | 		if ( undi_transmit->XmitFlag == XMT_DESTADDR ) { | ||||||
|  | 			copy_from_real ( destaddr, | ||||||
|  | 					 undi_transmit->DestAddr.segment, | ||||||
|  | 					 undi_transmit->DestAddr.offset, | ||||||
|  | 					 pxe_netdev->ll_protocol->ll_addr_len ); | ||||||
|  | 			ll_dest = destaddr; | ||||||
|  | 		} else { | ||||||
|  | 			ll_dest = pxe_netdev->ll_protocol->ll_broadcast; | ||||||
|  | 		} | ||||||
|  | 		rc = net_tx ( iobuf, pxe_netdev, net_protocol, ll_dest ); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | #warning "TX completion?" | ||||||
|  | 
 | ||||||
|  | 	undi_transmit->Status = PXENV_STATUS ( rc ); | ||||||
|  | 	return ( ( rc == 0 ) ? PXENV_EXIT_SUCCESS : PXENV_EXIT_FAILURE ); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* PXENV_UNDI_SET_MCAST_ADDRESS
 | /* PXENV_UNDI_SET_MCAST_ADDRESS
 | ||||||
|  | @ -405,16 +426,15 @@ PXENV_EXIT_t pxenv_undi_get_iface_info ( struct s_PXENV_UNDI_GET_IFACE_INFO | ||||||
| 					 *undi_get_iface_info ) { | 					 *undi_get_iface_info ) { | ||||||
| 	DBG ( "PXENV_UNDI_GET_IFACE_INFO" ); | 	DBG ( "PXENV_UNDI_GET_IFACE_INFO" ); | ||||||
| 
 | 
 | ||||||
| #if 0 |  | ||||||
| 	/* Just hand back some info, doesn't really matter what it is.
 | 	/* Just hand back some info, doesn't really matter what it is.
 | ||||||
| 	 * Most PXE stacks seem to take this approach. | 	 * Most PXE stacks seem to take this approach. | ||||||
| 	 */ | 	 */ | ||||||
| 	sprintf ( undi_get_iface_info->IfaceType, "Etherboot" ); | 	snprintf ( ( char * ) undi_get_iface_info->IfaceType, | ||||||
|  | 		   sizeof ( undi_get_iface_info->IfaceType ), "Etherboot" ); | ||||||
| 	undi_get_iface_info->LinkSpeed = 10000000; /* 10 Mbps */ | 	undi_get_iface_info->LinkSpeed = 10000000; /* 10 Mbps */ | ||||||
| 	undi_get_iface_info->ServiceFlags = 0; | 	undi_get_iface_info->ServiceFlags = 0; | ||||||
| 	memset ( undi_get_iface_info->Reserved, 0, | 	memset ( undi_get_iface_info->Reserved, 0, | ||||||
| 		 sizeof(undi_get_iface_info->Reserved) ); | 		 sizeof(undi_get_iface_info->Reserved) ); | ||||||
| #endif |  | ||||||
| 
 | 
 | ||||||
| 	undi_get_iface_info->Status = PXENV_STATUS_SUCCESS; | 	undi_get_iface_info->Status = PXENV_STATUS_SUCCESS; | ||||||
| 	return PXENV_EXIT_SUCCESS; | 	return PXENV_EXIT_SUCCESS; | ||||||
|  | @ -437,17 +457,10 @@ PXENV_EXIT_t pxenv_undi_get_state ( struct s_PXENV_UNDI_GET_STATE | ||||||
|  * Status: working |  * Status: working | ||||||
|  */ |  */ | ||||||
| PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) { | PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) { | ||||||
| 	DBG ( "PXENV_UNDI_ISR" ); | 	struct io_buffer *iobuf; | ||||||
|  | 	size_t len; | ||||||
| 
 | 
 | ||||||
| #if 0 | 	DBG ( "PXENV_UNDI_ISR" ); | ||||||
| 	/* We can't call ENSURE_READY, because this could be being
 |  | ||||||
| 	 * called as part of an interrupt service routine.  Instead, |  | ||||||
| 	 * we should simply die if we're not READY. |  | ||||||
| 	 */ |  | ||||||
| 	if ( ( pxe_stack == NULL ) || ( pxe_stack->state < READY ) ) { |  | ||||||
| 		undi_isr->Status = PXENV_STATUS_UNDI_INVALID_STATE; |  | ||||||
| 		return PXENV_EXIT_FAILURE; |  | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	/* Just in case some idiot actually looks at these fields when
 | 	/* Just in case some idiot actually looks at these fields when
 | ||||||
| 	 * we weren't meant to fill them in... | 	 * we weren't meant to fill them in... | ||||||
|  | @ -460,18 +473,14 @@ PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) { | ||||||
| 
 | 
 | ||||||
| 	switch ( undi_isr->FuncFlag ) { | 	switch ( undi_isr->FuncFlag ) { | ||||||
| 	case PXENV_UNDI_ISR_IN_START : | 	case PXENV_UNDI_ISR_IN_START : | ||||||
| 		/* Is there a packet waiting?  If so, disable
 |  | ||||||
| 		 * interrupts on the NIC and return "it's ours".  Do |  | ||||||
| 		 * *not* necessarily acknowledge the interrupt; this |  | ||||||
| 		 * can happen later when eth_poll(1) is called.  As |  | ||||||
| 		 * long as the interrupt is masked off so that it |  | ||||||
| 		 * doesn't immediately retrigger the 8259A then all |  | ||||||
| 		 * should be well. |  | ||||||
| 		 */ |  | ||||||
| 		DBG ( " START" ); | 		DBG ( " START" ); | ||||||
| 		if ( eth_poll ( 0 ) ) { | 
 | ||||||
|  | 		/* Call poll().  This should acknowledge the device
 | ||||||
|  | 		 * interrupt and queue up any received packet. | ||||||
|  | 		 */ | ||||||
|  | 		if ( netdev_poll ( pxe_netdev, -1U ) ) { | ||||||
|  | 			/* Packet waiting in queue */ | ||||||
| 			DBG ( " OURS" ); | 			DBG ( " OURS" ); | ||||||
| 			eth_irq ( DISABLE ); |  | ||||||
| 			undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_OURS; | 			undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_OURS; | ||||||
| 		} else { | 		} else { | ||||||
| 			DBG ( " NOT_OURS" ); | 			DBG ( " NOT_OURS" ); | ||||||
|  | @ -479,62 +488,48 @@ PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) { | ||||||
| 		} | 		} | ||||||
| 		break; | 		break; | ||||||
| 	case PXENV_UNDI_ISR_IN_PROCESS : | 	case PXENV_UNDI_ISR_IN_PROCESS : | ||||||
| 		/* Call poll(), return packet.  If no packet, return "done".
 | 	case PXENV_UNDI_ISR_IN_GET_NEXT : | ||||||
| 		 */ | 		DBG ( " PROCESS/GET_NEXT" ); | ||||||
| 		DBG ( " PROCESS" ); | 		 | ||||||
| 		if ( eth_poll ( 1 ) ) { | 		/* Remove first packet from netdev RX queue */ | ||||||
| 			DBG ( " RECEIVE %d", nic.packetlen ); | 		iobuf = netdev_rx_dequeue ( pxe_netdev ); | ||||||
| 			if ( nic.packetlen > sizeof(pxe_stack->packet) ) { | 		if ( ! iobuf ) { | ||||||
|  | 			/* No more packets remaining */ | ||||||
|  | 			undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE; | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		/* Copy packet to base memory buffer */ | ||||||
|  | 		len = iob_len ( iobuf ); | ||||||
|  | 		DBG ( " RECEIVE %zd", len ); | ||||||
|  | 		if ( len > sizeof ( basemem_packet ) ) { | ||||||
| 			/* Should never happen */ | 			/* Should never happen */ | ||||||
| 			undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE; | 			undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE; | ||||||
| 				undi_isr->Status = | 			undi_isr->Status = PXENV_STATUS_OUT_OF_RESOURCES; | ||||||
| 					PXENV_STATUS_OUT_OF_RESOURCES; |  | ||||||
| 			return PXENV_EXIT_FAILURE; | 			return PXENV_EXIT_FAILURE; | ||||||
| 		} | 		} | ||||||
|  | 		memcpy ( basemem_packet, iobuf->data, len ); | ||||||
|  | 
 | ||||||
| 		undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_RECEIVE; | 		undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_RECEIVE; | ||||||
| 			undi_isr->BufferLength = nic.packetlen; | 		undi_isr->BufferLength = len; | ||||||
| 			undi_isr->FrameLength = nic.packetlen; | 		undi_isr->FrameLength = len; | ||||||
| 			undi_isr->FrameHeaderLength = ETH_HLEN; | 		undi_isr->FrameHeaderLength = | ||||||
| 			memcpy ( pxe_stack->packet, nic.packet, nic.packetlen); | 			pxe_netdev->ll_protocol->ll_header_len; | ||||||
| 			PTR_TO_SEGOFF16 ( pxe_stack->packet, undi_isr->Frame ); | 		undi_isr->Frame.segment = rm_ds; | ||||||
| 			switch ( ntohs(media_header->nstype) ) { | 		undi_isr->Frame.offset = | ||||||
| 			case ETH_P_IP:	undi_isr->ProtType = P_IP;	break; | 			( ( unsigned ) & __from_data16 ( basemem_packet ) ); | ||||||
| 			case ETH_P_ARP:	undi_isr->ProtType = P_ARP;	break; | 		/* Probably ought to fill in packet type */ | ||||||
| 			case ETH_P_RARP: undi_isr->ProtType = P_RARP;	break; | 		undi_isr->ProtType = P_UNKNOWN; | ||||||
| 			default :	undi_isr->ProtType = P_UNKNOWN; |  | ||||||
| 			} |  | ||||||
| 			if ( memcmp ( media_header->dest, broadcast_mac, |  | ||||||
| 				      sizeof(broadcast_mac) ) ) { |  | ||||||
| 				undi_isr->PktType = XMT_BROADCAST; |  | ||||||
| 			} else { |  | ||||||
| 		undi_isr->PktType = XMT_DESTADDR; | 		undi_isr->PktType = XMT_DESTADDR; | ||||||
| 			} |  | ||||||
| 			break; |  | ||||||
| 		} else { |  | ||||||
| 			/* No break - fall through to IN_GET_NEXT */ |  | ||||||
| 		} |  | ||||||
| 	case PXENV_UNDI_ISR_IN_GET_NEXT : |  | ||||||
| 		/* We only ever return one frame at a time */ |  | ||||||
| 		DBG ( " GET_NEXT DONE" ); |  | ||||||
| 		/* Re-enable interrupts */ |  | ||||||
| 		eth_irq ( ENABLE ); |  | ||||||
| 		/* Force an interrupt if there's a packet still
 |  | ||||||
| 		 * waiting, since we only handle one packet per |  | ||||||
| 		 * interrupt. |  | ||||||
| 		 */ |  | ||||||
| 		if ( eth_poll ( 0 ) ) { |  | ||||||
| 			DBG ( " (RETRIGGER)" ); |  | ||||||
| 			eth_irq ( FORCE ); |  | ||||||
| 		} |  | ||||||
| 		undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE; |  | ||||||
| 		break; | 		break; | ||||||
| 	default : | 	default : | ||||||
|  | 		DBG ( " INVALID(%04x)", undi_isr->FuncFlag ); | ||||||
|  | 
 | ||||||
| 		/* Should never happen */ | 		/* Should never happen */ | ||||||
| 		undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE; | 		undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE; | ||||||
| 		undi_isr->Status = PXENV_STATUS_UNDI_INVALID_PARAMETER; | 		undi_isr->Status = PXENV_STATUS_UNDI_INVALID_PARAMETER; | ||||||
| 		return PXENV_EXIT_FAILURE; | 		return PXENV_EXIT_FAILURE; | ||||||
| 	} | 	} | ||||||
| #endif |  | ||||||
| 
 | 
 | ||||||
| 	undi_isr->Status = PXENV_STATUS_SUCCESS; | 	undi_isr->Status = PXENV_STATUS_SUCCESS; | ||||||
| 	return PXENV_EXIT_SUCCESS; | 	return PXENV_EXIT_SUCCESS; | ||||||
|  |  | ||||||
|  | @ -281,8 +281,7 @@ static int arp_rx ( struct io_buffer *iobuf, struct net_device *netdev, | ||||||
|  * |  * | ||||||
|  * This operation is meaningless for the ARP protocol. |  * This operation is meaningless for the ARP protocol. | ||||||
|  */ |  */ | ||||||
| static const char * | static const char * arp_ntoa ( const void *net_addr __unused ) { | ||||||
| arp_ntoa ( const void *net_addr __attribute__ (( unused )) ) { |  | ||||||
| 	return "<ARP>"; | 	return "<ARP>"; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -108,6 +108,7 @@ struct ll_protocol ethernet_protocol __ll_protocol = { | ||||||
| 	.name		= "Ethernet", | 	.name		= "Ethernet", | ||||||
| 	.ll_proto	= htons ( ARPHRD_ETHER ), | 	.ll_proto	= htons ( ARPHRD_ETHER ), | ||||||
| 	.ll_addr_len	= ETH_ALEN, | 	.ll_addr_len	= ETH_ALEN, | ||||||
|  | 	.ll_header_len	= ETH_HLEN, | ||||||
| 	.ll_broadcast	= eth_broadcast, | 	.ll_broadcast	= eth_broadcast, | ||||||
| 	.tx		= eth_tx, | 	.tx		= eth_tx, | ||||||
| 	.rx		= eth_rx, | 	.rx		= eth_rx, | ||||||
|  |  | ||||||
|  | @ -0,0 +1,68 @@ | ||||||
|  | /*
 | ||||||
|  |  * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>. | ||||||
|  |  * | ||||||
|  |  * 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 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 <stdint.h> | ||||||
|  | #include <byteswap.h> | ||||||
|  | #include <gpxe/netdevice.h> | ||||||
|  | #include <gpxe/iobuf.h> | ||||||
|  | #include <gpxe/if_ether.h> | ||||||
|  | #include <gpxe/rarp.h> | ||||||
|  | 
 | ||||||
|  | /** @file
 | ||||||
|  |  * | ||||||
|  |  * Reverse Address Resolution Protocol | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Process incoming ARP packets | ||||||
|  |  * | ||||||
|  |  * @v iobuf		I/O buffer | ||||||
|  |  * @v netdev		Network device | ||||||
|  |  * @v ll_source		Link-layer source address | ||||||
|  |  * @ret rc		Return status code | ||||||
|  |  * | ||||||
|  |  * This is a dummy method which simply discards RARP packets. | ||||||
|  |  */ | ||||||
|  | static int rarp_rx ( struct io_buffer *iobuf, | ||||||
|  | 		     struct net_device *netdev __unused, | ||||||
|  | 		     const void *ll_source __unused ) { | ||||||
|  | 	free_iob ( iobuf ); | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Transcribe RARP address | ||||||
|  |  * | ||||||
|  |  * @v net_addr	RARP address | ||||||
|  |  * @ret string	"<RARP>" | ||||||
|  |  * | ||||||
|  |  * This operation is meaningless for the RARP protocol. | ||||||
|  |  */ | ||||||
|  | static const char * rarp_ntoa ( const void *net_addr __unused ) { | ||||||
|  | 	return "<RARP>"; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** RARP protocol */ | ||||||
|  | struct net_protocol rarp_protocol __net_protocol = { | ||||||
|  | 	.name = "RARP", | ||||||
|  | 	.net_proto = htons ( ETH_P_RARP ), | ||||||
|  | 	.rx = rarp_rx, | ||||||
|  | 	.ntoa = rarp_ntoa, | ||||||
|  | }; | ||||||
		Loading…
	
		Reference in New Issue