Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 12 May 2007 15:52:53 GMT
From:      Alexey Tarasov <taleks@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 119729 for review
Message-ID:  <200705121552.l4CFqrNQ070356@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=119729

Change 119729 by taleks@taleks_th on 2007/05/12 15:52:16

	Added modules for working with ARP packets, updated pxe_core (function code and added MAC_ADDR member to pxe_packet structure). Now ISR and receiving cycle are separated. First is done in pxe_isr in vm86 mode (there is also stub pxe_core_isr(), that is for experiments only). Receiving cycle is started by pxe_core_recv_packets() call. Current ideas of packet receiving mechanism may be seen in pxe_arp_ip4mac() function.

Affected files ...

.. //depot/projects/soc2007/taleks-pxe_http/pxe_arp.c#1 add
.. //depot/projects/soc2007/taleks-pxe_http/pxe_arp.h#1 add
.. //depot/projects/soc2007/taleks-pxe_http/pxe_core.c#6 edit
.. //depot/projects/soc2007/taleks-pxe_http/pxe_core.h#6 edit

Differences ...

==== //depot/projects/soc2007/taleks-pxe_http/pxe_core.c#6 (text+ko) ====

@@ -4,15 +4,15 @@
 #include "btxv86.h"
 #include "pxe.h"
 
+#include "pxe_arp.h"
 #include "pxe_core.h"
 #include "pxe_ip.h"
+#include "pxe_isr.h"
 #include "pxe_mem.h"
 #include "pxe_mutex.h"
 
 /* PXE API calls here will be made in same way as in pxeboot.
  * the only difference - installation of isr, that was not needed in pxe.c.
- * main problem is that, v86 monitors reflects interrupts,
- * we need to change IDT, for correct irq and call pxe_core_isr() from it.
  */
 
 /* NOTE: to think about using of this buffers */
@@ -39,6 +39,7 @@
 
 /* NIC info */
 pxe_ipaddr          nic_ip = {0};
+MAC_ADDR	    nic_mac;	/* may be init it also by zero? */
 
 /* core packet statistics */
 uint32_t   	    packets_dropped = 0;
@@ -168,6 +169,11 @@
 
 	/* 3. additional start UNDI */
 
+	/* saving information about NIC */
+	nic_ip.ip=bootplayer.yip;	/* my ip */
+					/* my MAC */
+	pxe_memcpy(&nic_mac, bootplayer.CAddr, MAC_ADDR_LEN);
+
 	return (1);
 }
 
@@ -185,31 +191,52 @@
 	pxe_core_call(PXENV_UNDI_GET_INFORMATION);
 
 	if (undi_info->Status != 0) {
-		printf("pxe_isr_install: failed %x\n", undi_info->Status);
+		printf("pxe_core_install_isr(): failed %x\n", undi_info->Status);
 		return;
 	}
 
-	irq=(uint8_t)(undi_info->IntNumber);
+	__pxe_nic_irq=(uint16_t)(undi_info->IntNumber);
 
 #ifdef PXE_DEBUG
-	printf("pxe_isr_install() info:\n");
+	printf("pxe_core_install_isr() info:\n");
 	printf("IRQ: %d\n", undi_info->IntNumber);
 	printf("Base io: %d\n", undi_info->BaseIo);
 	printf("MTU: %d\n", undi_info->MaxTranUnit);
 	printf("RX buffer queue: %d\n", undi_info->RxBufCt);
 	printf("TX buffer queue: %d\n", undi_info->TxBufCt);
-	printf("installing ISR\n");
 #endif
+
+#ifndef PXE_PMBRANCH
+	/* main branch - ISR is handled in vm86, so installed also there
+	 * __isr_install uses __pxe_nic_irq to determine interrupt number.
+	 * Well, it may be simplified, cause interrupt number may be got
+	 * in this code (as bellow int_num for PM).
+	 * TODO: simplify pxe_isr.S code.
+	 */
+	bzero(&v86, sizeof(v86));
+
+	v86.ctl  = V86_ADDR | V86_CALLF | V86_FLAGS;
+	v86.addr = (VTOPSEG(__isr_install) << 16) | VTOPOFF(__isr_install);
+	v86.ebx  = func;
+	v86int();
+	v86.ctl  = V86_FLAGS;
+#else
 	uint16_t int_num=(irq < 8) ? irq + 0x08 : irq + 0x68;
 
 	caddr_t isr_addr=pxe_isr-__base;
 	printf("setting interrupt: %d for 0x%x (0x%x, base = 0x%x)\n",
 		int_num, pxe_isr, isr_addr, __base);
 
+	/* PMBRANCH - is subproject, which goal to use ISR in PM
+	 *     it's not main branch, so just for my own interests
+	 *	this __isr_install is syscall
+	 */
 	__isr_install(isr_addr, int_num);
 
+#endif
+
 #ifdef PXE_DEBUG
-	printf("pxe_isr_install(): success\n");
+	printf("pxe_core_install_isr(): success\n");
 #endif
 }
 
@@ -217,6 +244,19 @@
 pxe_core_remove_isr()
 {
 
+#ifdef PXE_PMBRANCH
+	/* here must be something */
+#else
+
+	bzero(&v86, sizeof(v86));
+
+	v86.ctl  = V86_ADDR | V86_CALLF | V86_FLAGS;
+	v86.addr = (VTOPSEG(__isr_uninstall) << 16) | VTOPOFF(__isr_uninstall);
+	v86.ebx  = func;
+	v86int();
+	v86.ctl  = V86_FLAGS;
+
+#endif
 }
 
 int
@@ -275,32 +315,37 @@
 int
 pxe_core_transmit(pxe_packet *pack)
 {
+	/* NOTE:all provided data must be in base segment of PXE,
+	 *   if it's not here, it must be copied here (TO IMPLEMENT)
+	 */
 	t_PXENV_UNDI_TRANSMIT *undi_send =
 		(t_PXENV_UNDI_TRANSMIT *)scratch_buffer;
 
 	bzero(undi_send, sizeof(*undi_info));
 
-	/* media address */
-	uint_8_t	media_addr[6] = {0,0,0,0,0,0};
-
 	t_PXENV_UNDI_TBD	tbd;
 	tbd.ImmedLength = pack->data_size;	/* packet length */
 	tbd.Xmit.segment = VTOPSEG(pack->data);	/* immediate transmit buffer */
 	tbd.Xmit.offset = VTOPOFF(pack->data);
-	tbd.DataBlkCount = 1 ;			/* one block */
-	tbd.DataBlk[0].TDPtrType = 1;		/* segment:offset type */
-	tbd.DataBlk[0].TDRsvdByte = 0;		/* reserved */
+	tbd.DataBlkCount = 0 ;			/* only immediate data */
+
+	undi_send->Protocol = pack->protocol;
+	undi_send->DestAddr.segment = VTOPSEG(pack->dest_mac);
+	undi_send->DestAddr.offset  = VTOPOFF(pack->dest_mac);
+	undi_send->TBD.segment = VTOPSEG(&tbd);	/* SEGOFF16 to xmit block data*/
+	undi_send->TBD.offset = VTOPOFF(&tbd);
+
+/* NOTE: is it needed? we use only immediate block */
 
-	/* NOTE: if it will work? Check params*/
+/*	we've inited undi_info with zero, so two lines below are not needed */
+/*	tbd.DataBlk[0].TDRsvdByte = 0;		/* reserved */
+/*	tbd.DataBlk[1].TDRsvdByte = 0;		/* reserved */
 	tbd.DataBlk[0].TDDataLen=tbd.ImmedLength; /* size of packet*/
+	tbd.DataBlk[0].TDPtrType = 1;		/* segment:offset type */
 	tbd.DataBlk[0].TDDataPtr.segment = VTOPSEG(pack->data);;
 	tbd.DataBlk[0].TDDataPtr.offset = VTOPOFF(pack->data);;
 
-	undi_send->Protocol = P_IP;
-	undi_send->DestAddr.segment = VTOPSEG(media_addr);
-	undi_send->DestAddr.offset  = VTOPOFF(media_addr);
-
-	pxe_core_call(PXENV_UNDI_GET_INFORMATION);
+	pxe_core_call(PXENV_UNDI_TRANSMIT_PACKET);
 
 	if (undi_send->Status != 0) {
 		printf("pxe_core_transmit(): failed %x\n", undi_info->Status);
@@ -414,32 +459,48 @@
 	return (1);
 }
 
+/* NOTE: now it's handled in real mode ISR, look pxe_isr.S */
 void
 pxe_core_isr()
 {
+
+	if (!pxe_core_is_ours()) {
+		return;		/* not ours interrupt, handling is over */
+	}
+}
+
+/*
+ * recieves one packet, if there is any waiting in receiving queue.
+ * in:
+ *    none
+ * out:
+ *     0  -  there is no packets in receiving queue, or it's not interesting for us.
+ *     positive  -  there were packets in queue and some protocol handler was interested in it.
+ */
+int
+pxe_core_recv_packets()
+{
+
 	/*
-	 * NOTE: code here it must be redone to separate receiving thread
-	 *       and interrupt handler.
-	 *       in fact real mode ISR implements pxe_core_is_ours()
-	 *       and modifies __pxe_isr_occured, which must be checked
-	 *	 in receiving queue.
+	 * TODO: make it simplier to understand, too many ifs, many lines.
 	 */
 	int	buffer_size = 0;  /* total size of packet*/
 	int	protocol = 0;     /* protocol */
-	int	recieved = 0;     /* bytes received to buffer */
+	int	received = 0;     /* bytes received to buffer */
 
 	void	*frame_data = NULL;/* pointer to frame data */
 	int	frame_size = 0;    /* size of frame */
+	int	drop_flag = 0;
+	int	processed_packets = 0;
 
 	pxe_packet *pack=NULL;	/* allocated packet */
 	pxe_packet dummy_pack;	/* temporary struct, used to mimic
 				 * real packet struct
 				 */
+	if (__pxe_isr_occured == 0) /* there are no packets for us to handle */
+		return (0);
 
-	if (!pxe_core_is_ours()) {
-		return;		/* not ours interrupt, handling is over */
-	}
-
+	__pxe_isr_occured = 0;
 
 	t_PXENV_UNDI_ISR *undi_isr =
 		(t_PXENV_UNDI_ISR *)scratch_buffer;
@@ -447,8 +508,17 @@
 	bzero(undi_isr, sizeof(*undi_isr));
 
 	/* starting packet receive cycle */
-	if (0 -- pxe_core_get_packet(PXENV_UNDI_ISR_IN_PROCESS, undi_isr)) {
-		return;
+	/* NOTE: pxe_core_recv_packet() name is similar tp pxe_core_get_packet(),
+	 *       may be renaming is needed.
+	 */
+	int func = PXENV_UNDI_ISR_IN_PROCESS;
+
+packet_start:
+
+	drop_flag = 0;
+
+	if (0 == pxe_core_get_packet(func, undi_isr)) {
+		return (processed_packets);
 	}
 
 	buffer_size = undi_isr->BufferLength;
@@ -458,60 +528,75 @@
 /* how to get in this address from userspace, which starts at 0xa800?*/
 /*	frame_data = undi_isr->Frame.segment << 4 + undi_isr->Frame.offset; */
 
+	/* we are interested in ARP & IP packets */
 
-	/* we are yet not interested in non-ip packets */
+	if ( (protocol == PXE_PROTOCOL_UNKNOWN) || (protocol == PXE_PROTOCOL_RARP) ) {
 
-	if (protocol != PXE_PROTOCOL_IP) {
 		++packets_dropped;
-		return;
+		drop_flag = 1;		/* clear queue, receiving all frames of packet */
 	}
 
 	/* checking first fragment, this may help to avoid memory allocation
 	 * and memblock copy
 	 */
 
-/*	if (buffer_size == frame_size) {*/
+	if (!drop_flag) {
+
+		pxe_ip *iphdr = (pxe_ip *)frame_data;
+
+		dummy_pack.protocol = protocol;
+		dummy_pack.state = PXE_PACKET_STATE_USING;
+		dummy_pack.data = frame_data;
+		dummy_pack.data_size = frame_size;
+		dummy_pack.user_data = NULL;
+
+		if (protocol == PXE_PROTOCOL_ARP) {
+	
+			pxe_arp_protocol(&dummy_pack, PXE_CORE_FRAG, NULL);
+			++processed_packets;
 
-	pxe_ip *iphdr = (pxe_ip *)frame_data;
+			/* aasume ARP packet always in opne fragment */
+		
+			func = PXE_UNDI_ISR_IN_GET_NEXT;
 
-	dummy_pack.protocol = protocol;
-	dummy_pack.state = PXE_PACKET_STATE_USING;
-	dummy_pack.data = frame_data;
-	dummy_pack.data_size = frame_size;
-	dummy_pack.user_data = NULL;
+			goto packet_start;
+		}
 
         /* TODO: calc ip checksum */
 
-	if (core_protocol[iphdr->protocol]) {
-		if (core_protocol[iphdr->protocol](&dummy_pack,
-			PXE_CORE_FRAG, NULL)) {
-			return;
-		}
-	}
-/*	}*/
+		if  ( (!core_protocol[iphdr->protocol]) ||
+		      (!core_protocol[iphdr->protocol](&dummy_pack,
+				PXE_CORE_FRAG, NULL)) ) {
+
+			drop_flag = 1;
+		} else {
+
+			pack = pxe_core_alloc_packet(buffer_size);
 
-	pack = pxe_core_alloc_packet(buffer_size);
+			if (pack == NULL) {
+				pxe_core_flush_packets();
 
-	if (pack == NULL) {
-		pxe_core_flush_packets();
+				/* trying to get free packets by sending and dropping */
+				pack = pxe_core_alloc_packet(buffer_size);
 
-		/* trying to get free packets by sending and dropping */
-		pack = pxe_core_alloc_packet(buffer_size);
+				/* failed to alloc packet, dropping packet */
+				if (pack == NULL) {
+					++packets_dropped;
+					drop_flag = 1;
+				}
+			}
 
-		/* failed to alloc packet, dropping packet */
-		if (pack == NULL) {
-			++packets_dropped;
-			return;
-		}
-	}
 
 	/*  pointing user_data to beginning of data.
 	 * It's used by pxe_core_receive() during receiving packet.
 	 */
 
-	pack->user_data = pack->data;
+			if (pack != NULL)
+				pack->user_data = pack->data;
+		}
+	}
 
-	while (recieved < buffer_size) {
+	while (received < buffer_size) {
 
 		if (!pxe_core_get_packet(PXENV_UNDI_ISR_GET_NEXT, undi_isr))
 			break;
@@ -521,33 +606,46 @@
 /*	frame_data = undi_isr->Frame.segment << 4 + undi_isr->Frame.offset; */
 
 
-		pxe_core_recieve(pack, frame_data, frame_size);
+		if (!drop_flag)
+			pxe_core_recieve(pack, frame_data, frame_size);
 
-		recieved += frame_size;
+		received += frame_size;
 	}
 
-	if (recieved < buffer_size) { /* pxe_core_get_packet() in cycle failed */
-		pxe_core_drop(pack);
-		return;
+	if (received < buffer_size) { /* pxe_core_get_packet() in cycle failed */
+
+		if (!drop_flag)
+			pxe_core_drop(pack);
+
+		return (processed_packets);	/* it's failed, finish receive cycle */
 	}
 
-	pack->user_data = NULL;
-	++packets_received;
+	if (!drop_flag) {
+
+		pack->user_data = NULL;
+		++packets_received;
 
-	pxe_ip *iphdr=(pxe_ip *)pack->data;
+		pxe_ip *iphdr=(pxe_ip *)pack->data;
 
-	/* TODO: calc ip checksum */
-	pack->protocol = protocol;
+		/* TODO: calc ip checksum */
+		pack->protocol = protocol;
 
-	if (core_protocol[iphdr->protocol]) { /* protocol registered */
-		if (core_protocol[iphdr->protocol](pack, PXE_CORE_HANDLE,
-		    NULL)) {
-			return;
+		if ( (!core_protocol[iphdr->protocol]) ||
+		     (!core_protocol[iphdr->protocol](pack, PXE_CORE_HANDLE, NULL)) ) {
+				/* protocol not interested in it */
+			pxe_core_drop(pack);
 		}
 	}
 
-	/* no such protocol registered or protocol not interested in it */
-	pxe_core_drop(pack);
+	++processed_packets;
+	/* received one or more packets, but need check if there are any others */
+	
+	func = PXE_UNDI_ISR_IN_GET_NEXT;
+
+	goto packet_start;
+
+	/* never getting here */
+	return (0);	
 }
 
 /*
@@ -638,5 +736,12 @@
 pxe_get_myip32()
 {
 
-    return nic_ip.ip;
+	return nic_ip.ip;
+}
+
+const MAC_ADDR*
+pxe_get_mymac()
+{
+	return &nic_mac;
 }
+

==== //depot/projects/soc2007/taleks-pxe_http/pxe_core.h#6 (text+ko) ====

@@ -35,6 +35,8 @@
 
     void*       data;       /* pointer to buffer with packet data */
     size_t      data_size;  /* size of packet data */
+                            
+    const MAC_ADDR *dest_mac;   /* destination media address */
 
     void*       user_data;  /* pointer to user data.
 			     * used by higher level protocols
@@ -64,6 +66,8 @@
 
 /* interrupt handler function, that used to get new packets */
 void pxe_core_isr();
+/* recieves one packet if it's waiting */
+int pxe_core_recv_packets();
 
 /* calls PXE/UNDI API, registers of processor must be filled in with
  *  appropriate values.
@@ -91,9 +95,11 @@
 typedef int (*pxe_protocol_call)(pxe_packet *pack, uint8_t function, void *data);
 
 /* registers protocol */
-void pxe_core_register(uint8_t proto, pxe_protocol_call proc);
+void pxe_core_register(uint8_t ip_proto, pxe_protocol_call proc);
 
 /* returns NIC ip */
 uint32_t pxe_get_myip32();
+/* returns NIC MAC */
+const MAC_ADDR *pxe_get_mymac();
 
 #endif // PXE_CORE_H_INCLUDED



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200705121552.l4CFqrNQ070356>