[U-Boot] [PATCH v2 04/11] net: tftpput: Add support for receiving ICMP packets

Simon Glass sjg at chromium.org
Tue Oct 25 06:00:01 CEST 2011


ICMP packets can tell you when there is no server at the other end. It
is useful for tftp to figure this out, so that a quick error can be
displayed, rather than pointlessly retrying.

This adds an ICMP packet handler to the net interface.

Signed-off-by: Simon Glass <sjg at chromium.org>
---
 include/net.h |   19 +++++++++++++++++++
 net/net.c     |   27 ++++++++++++++++++++++++---
 2 files changed, 43 insertions(+), 3 deletions(-)

diff --git a/include/net.h b/include/net.h
index d5d37b6..d7ff068 100644
--- a/include/net.h
+++ b/include/net.h
@@ -48,6 +48,19 @@ typedef void rxhand_f(uchar *pkt, unsigned dport,
 		      IPaddr_t sip, unsigned sport,
 		      unsigned len);
 
+/**
+ * An incoming ICMP packet handler.
+ * @param type	ICMP type
+ * @param code	ICMP code
+ * @param dport	destination UDP port
+ * @param sip	source IP address
+ * @param sport	source UDP port
+ * @param pkt	pointer to the ICMP packet data
+ * @param len	packet length
+ */
+typedef void rxhand_icmp_f(unsigned type, unsigned code, unsigned dport,
+		IPaddr_t sip, unsigned sport, uchar *pkt, unsigned len);
+
 /*
  *	A timeout handler.  Called after time interval has expired.
  */
@@ -244,6 +257,7 @@ typedef struct
  * ICMP stuff (just enough to handle (host) redirect messages)
  */
 #define ICMP_ECHO_REPLY		0	/* Echo reply			*/
+#define ICMP_NOT_REACH		3	/* Detination unreachable	*/
 #define ICMP_REDIRECT		5	/* Redirect (change route)	*/
 #define ICMP_ECHO_REQUEST	8	/* Echo request			*/
 
@@ -251,6 +265,9 @@ typedef struct
 #define ICMP_REDIR_NET		0	/* Redirect Net			*/
 #define ICMP_REDIR_HOST		1	/* Redirect Host		*/
 
+/* Codes for NOT_REACH */
+#define ICMP_NOT_REACH_PORT	3	/* Port unreachable		*/
+
 typedef struct icmphdr {
 	uchar		type;
 	uchar		code;
@@ -265,6 +282,7 @@ typedef struct icmphdr {
 			ushort	__unused;
 			ushort	mtu;
 		} frag;
+		uchar data[0];
 	} un;
 } ICMP_t;
 
@@ -397,6 +415,7 @@ extern uint	NetCksum(uchar *, int);		/* Calculate the checksum	*/
 
 /* Set callbacks */
 extern void	NetSetHandler(rxhand_f *);	/* Set RX packet handler	*/
+extern void net_set_icmp_handler(rxhand_icmp_f *f); /* Set ICMP RX handler */
 extern void	NetSetTimeout(ulong, thand_f *);/* Set timeout handler		*/
 
 /* Transmit "NetTxPacket" */
diff --git a/net/net.c b/net/net.c
index 266b953..f6afb64 100644
--- a/net/net.c
+++ b/net/net.c
@@ -215,6 +215,7 @@ volatile uchar *NetRxPackets[PKTBUFSRX];
 
 /* Current RX packet handler */
 static rxhand_f *packetHandler;
+static rxhand_icmp_f *packet_icmp_handler;	/* Current ICMP rx handler */
 /* Current timeout handler */
 static thand_f *timeHandler;
 /* Time base value */
@@ -344,6 +345,7 @@ int
 NetLoop(proto_t protocol)
 {
 	bd_t *bd = gd->bd;
+	int ret = -1;
 
 	NetRestarted = 0;
 	NetDevExists = 0;
@@ -512,7 +514,7 @@ restart:
 		if (ctrlc()) {
 			eth_halt();
 			puts("\nAbort\n");
-			return -1;
+			goto done;
 		}
 
 		ArpTimeoutCheck();
@@ -564,12 +566,19 @@ restart:
 				setenv("fileaddr", buf);
 			}
 			eth_halt();
-			return NetBootFileXferSize;
+			ret = NetBootFileXferSize;
+			goto done;
 
 		case NETLOOP_FAIL:
-			return -1;
+			goto done;
 		}
 	}
+
+done:
+	/* Clear out the handlers */
+	NetSetHandler(NULL);
+	net_set_icmp_handler(NULL);
+	return ret;
 }
 
 /**********************************************************************/
@@ -643,6 +652,10 @@ NetSetHandler(rxhand_f *f)
 	packetHandler = f;
 }
 
+void net_set_icmp_handler(rxhand_icmp_f *f)
+{
+	packet_icmp_handler = f;
+}
 
 void
 NetSetTimeout(ulong iv, thand_f *f)
@@ -1383,6 +1396,10 @@ static void receive_icmp(IP_t *ip, int len, IPaddr_t src_ip, Ethernet_t *et)
 		break;
 #endif
 	default:
+		if (packet_icmp_handler)
+			packet_icmp_handler(icmph->type, icmph->code,
+				ntohs(ip->udp_dst), src_ip, ntohs(ip->udp_src),
+				icmph->un.data, ntohs(ip->udp_len));
 		break;
 	}
 }
@@ -1671,6 +1688,10 @@ NetReceive(volatile uchar *inpkt, int len)
 		 * subnet. So this is probably a warning that your
 		 * configuration might be wrong. But I'm not really
 		 * sure if there aren't any other situations.
+		 *
+		 * Simon Glass <sjg at chromium.org>: We get an ICMP when
+		 * we send a tftp packet to a dead connection, or when
+		 * there is no server at the other end.
 		 */
 		if (ip->ip_p == IPPROTO_ICMP) {
 			receive_icmp(ip, len, src_ip, et);
-- 
1.7.3.1



More information about the U-Boot mailing list