xref: /haiku/src/system/boot/platform/pxe_ia32/network.cpp (revision 1acbe440b8dd798953bec31d18ee589aa3f71b73)
1 /*
2  * Copyright 2006, Marcus Overhagen <marcus@overhagen.de. All rights reserved.
3  * Copyright 2005, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
4  * Distributed under the terms of the MIT License.
5  */
6 
7 #include <new>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 
12 #include <KernelExport.h>
13 
14 #include "network.h"
15 #include "pxe_undi.h"
16 
17 //#define TRACE_NETWORK
18 #ifdef TRACE_NETWORK
19 #	define TRACE(x...) dprintf(x)
20 #else
21 #	define TRACE(x...)
22 #endif
23 
24 #ifdef TRACE_NETWORK
25 
26 static void
27 hex_dump(const void *_data, int length)
28 {
29 	uint8 *data = (uint8*)_data;
30 	for (int i = 0; i < length; i++) {
31 		if (i % 4 == 0) {
32 			if (i % 32 == 0) {
33 				if (i != 0)
34 					TRACE("\n");
35 				TRACE("%03x: ", i);
36 			} else
37 				TRACE(" ");
38 		}
39 
40 		TRACE("%02x", data[i]);
41 	}
42 	TRACE("\n");
43 }
44 
45 #else	// !TRACE_NETWORK
46 
47 #define hex_dump(data, length)
48 
49 #endif	// !TRACE_NETWORK
50 
51 
52 UNDI::UNDI()
53  :	fMACAddress()
54  ,	fRxFinished(true)
55  ,	fPxeData(NULL)
56 {
57 	TRACE("UNDI::UNDI\n");
58 
59 	fPxeData = pxe_undi_find_data();
60 	if (!fPxeData)
61 		panic("can't find !PXE structure");
62 
63 	dprintf("PXE API entrypoint at %04x:%04x\n", fPxeData->EntryPointSP.seg, fPxeData->EntryPointSP.ofs);
64 }
65 
66 
67 UNDI::~UNDI()
68 {
69 	TRACE("UNDI::~UNDI\n");
70 }
71 
72 
73 status_t
74 UNDI::Init()
75 {
76 	TRACE("UNDI::Init\n");
77 
78 	PXENV_GET_CACHED_INFO cached_info;
79 	PXENV_UNDI_GET_INFORMATION get_info;
80 	PXENV_UNDI_GET_STATE get_state;
81 	PXENV_UNDI_OPEN undi_open;
82 	uint16 res;
83 
84 	cached_info.PacketType = PXENV_PACKET_TYPE_CACHED_REPLY;
85 	cached_info.BufferSize = 0;
86 	cached_info.BufferLimit = 0;
87 	cached_info.Buffer.seg = 0;
88 	cached_info.Buffer.ofs = 0;
89 	res = call_pxe_bios(fPxeData, GET_CACHED_INFO, &cached_info);
90 	if (res != 0 || cached_info.Status != 0) {
91 		char s[100];
92 		snprintf(s, sizeof(s), "Can't determine IP address! PXENV_GET_CACHED_INFO res %x, status %x\n", res, cached_info.Status);
93 		panic(s);
94 	}
95 
96 	char *buf = (char *)(cached_info.Buffer.seg * 16 + cached_info.Buffer.ofs);
97 	ip_addr_t ipClient = ntohl(*(ip_addr_t *)(buf + 16));
98 	ip_addr_t ipServer = ntohl(*(ip_addr_t *)(buf + 20));
99 
100 	dprintf("client-ip: %lu.%lu.%lu.%lu, server-ip: %lu.%lu.%lu.%lu\n",
101 		(ipClient >> 24) & 0xff, (ipClient >> 16) & 0xff, (ipClient >> 8) & 0xff, ipClient & 0xff,
102 		(ipServer >> 24) & 0xff, (ipServer >> 16) & 0xff, (ipServer >> 8) & 0xff, ipServer & 0xff);
103 
104 	SetIPAddress(ipClient);
105 
106 	undi_open.OpenFlag = 0;
107 	undi_open.PktFilter = FLTR_DIRECTED | FLTR_BRDCST | FLTR_PRMSCS;
108 	undi_open.R_Mcast_Buf.MCastAddrCount = 0;
109 
110 	res = call_pxe_bios(fPxeData, UNDI_OPEN, &undi_open);
111 	if (res != 0 || undi_open.Status != 0) {
112 		dprintf("PXENV_UNDI_OPEN failed, res %x, status %x, ignoring\n", res, undi_open.Status);
113 	}
114 
115 	res = call_pxe_bios(fPxeData, UNDI_GET_STATE, &get_state);
116 	if (res != 0 || get_state.Status != 0) {
117 		dprintf("PXENV_UNDI_GET_STATE failed, res %x, status %x, ignoring\n", res, get_state.Status);
118 	} else {
119 		switch (get_state.UNDIstate) {
120 			case PXE_UNDI_GET_STATE_STARTED:
121 				TRACE("PXE_UNDI_GET_STATE_STARTED\n");
122 				break;
123 			case PXE_UNDI_GET_STATE_INITIALIZED:
124 				TRACE("PXE_UNDI_GET_STATE_INITIALIZED\n");
125 				break;
126 			case PXE_UNDI_GET_STATE_OPENED:
127 				TRACE("PXE_UNDI_GET_STATE_OPENED\n");
128 				break;
129 			default:
130 				TRACE("unknown undi state 0x%02x\n", get_state.UNDIstate);
131 				break;
132 		}
133 	}
134 
135 	res = call_pxe_bios(fPxeData, UNDI_GET_INFORMATION, &get_info);
136 	if (res != 0 || get_info.Status != 0) {
137 		dprintf("PXENV_UNDI_GET_INFORMATION failed, res %x, status %x\n", res, get_info.Status);
138 		return B_ERROR;
139 	}
140 
141 	TRACE("Status = %x\n", get_info.Status);
142 	TRACE("BaseIo = %x\n", get_info.BaseIo);
143 	TRACE("IntNumber = %x\n", get_info.IntNumber);
144 	TRACE("MaxTranUnit = %x\n", get_info.MaxTranUnit);
145 	TRACE("HwType = %x\n", get_info.HwType);
146 	TRACE("HwAddrLen = %x\n", get_info.HwAddrLen);
147 	TRACE("RxBufCt = %x\n", get_info.RxBufCt);
148 	TRACE("TxBufCt = %x\n", get_info.TxBufCt);
149 
150 	fMACAddress = get_info.CurrentNodeAddress;
151 
152 	TRACE("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", fMACAddress[0], fMACAddress[1], fMACAddress[2], fMACAddress[3], fMACAddress[4], fMACAddress[5]);
153 
154 	return B_OK;
155 }
156 
157 
158 mac_addr_t
159 UNDI::MACAddress() const
160 {
161 	return fMACAddress;
162 }
163 
164 
165 void *
166 UNDI::AllocateSendReceiveBuffer(size_t size)
167 {
168 	TRACE("UNDI::AllocateSendReceiveBuffer, size %ld\n", size);
169 	if (size > 0x3000)
170 		return NULL;
171 
172 	return (void *)0x500;
173 }
174 
175 
176 void
177 UNDI::FreeSendReceiveBuffer(void *buffer)
178 {
179 	TRACE("UNDI::FreeSendReceiveBuffer\n");
180 }
181 
182 
183 ssize_t
184 UNDI::Send(const void *buffer, size_t size)
185 {
186 	TRACE("UNDI::Send, buffer %p, size %ld\n", buffer, size);
187 
188 //	hex_dump(buffer, size);
189 
190 	PXENV_UNDI_TRANSMIT undi_tx;
191 	PXENV_UNDI_TBD undi_tbd;
192 
193 	undi_tx.Protocol = P_UNKNOWN;
194 	undi_tx.XmitFlag = XMT_DESTADDR;
195 	undi_tx.DestAddr.seg = SEG((char *)buffer + 16);
196 	undi_tx.DestAddr.ofs = OFS((char *)buffer + 16);
197 	undi_tx.TBD.seg = SEG(&undi_tbd);
198 	undi_tx.TBD.ofs = OFS(&undi_tbd);
199 
200 	undi_tbd.ImmedLength = size;
201 	undi_tbd.Xmit.seg = SEG(buffer);
202 	undi_tbd.Xmit.ofs = OFS(buffer);
203 	undi_tbd.DataBlkCount = 0;
204 
205 	uint16 res = call_pxe_bios(fPxeData, UNDI_TRANSMIT, &undi_tx);
206 	if (res != 0 || undi_tx.Status != 0) {
207 		dprintf("UNDI_TRANSMIT failed, res %x, status %x\n", res, undi_tx.Status);
208 		return 0;
209 	}
210 
211 	TRACE("UNDI_TRANSMIT success\n");
212 
213 	return size;
214 }
215 
216 
217 ssize_t
218 UNDI::Receive(void *buffer, size_t size)
219 {
220 	//TRACE("UNDI::Receive, buffer %p, size %ld\n", buffer, size);
221 
222 	PXENV_UNDI_ISR undi_isr;
223 	uint16 res;
224 
225 	if (!fRxFinished) {
226 		TRACE("continue receive...\n");
227 
228 		undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT;
229 		res = call_pxe_bios(fPxeData, UNDI_ISR, &undi_isr);
230 		if (res != 0 || undi_isr.Status != 0) {
231 			dprintf("PXENV_UNDI_ISR_IN_GET_NEXT failed, res %x, status %x\n", res, undi_isr.Status);
232 			fRxFinished = true;
233 			return 0;
234 		}
235 
236 	} else {
237 
238 		undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_START;
239 
240 		res = call_pxe_bios(fPxeData, UNDI_ISR, &undi_isr);
241 		if (res != 0 || undi_isr.Status != 0) {
242 			dprintf("PXENV_UNDI_ISR_IN_START failed, res %x, status %x\n", res, undi_isr.Status);
243 			return -1;
244 		}
245 
246 		if (undi_isr.FuncFlag != PXENV_UNDI_ISR_OUT_OURS) {
247 //			TRACE("not ours\n");
248 			return -1;
249 		}
250 
251 		// send EOI to pic ?
252 
253 //		TRACE("PXENV_UNDI_ISR_OUT_OURS\n");
254 
255 		undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_PROCESS;
256 		res = call_pxe_bios(fPxeData, UNDI_ISR, &undi_isr);
257 		if (res != 0 || undi_isr.Status != 0) {
258 			dprintf("PXENV_UNDI_ISR_IN_PROCESS failed, res %x, status %x\n", res, undi_isr.Status);
259 			return -1;
260 		}
261 	}
262 
263 	switch (undi_isr.FuncFlag) {
264 		case PXENV_UNDI_ISR_OUT_TRANSMIT:
265 			TRACE("PXENV_UNDI_ISR_OUT_TRANSMIT\n");
266 			fRxFinished = false;
267 			return 0;
268 
269 		case PXENV_UNDI_ISR_OUT_RECEIVE:
270 			TRACE("PXENV_UNDI_ISR_OUT_RECEIVE\n");
271 //			TRACE("BufferLength %d\n", undi_isr.BufferLength);
272 //			TRACE("FrameLength %d\n", undi_isr.FrameLength);
273 //			TRACE("FrameHeaderLength %d\n", undi_isr.FrameHeaderLength);
274 			if (undi_isr.FrameLength > undi_isr.BufferLength)
275 				panic("UNDI::Receive: multi buffer frames not supported");
276 			if (size > undi_isr.BufferLength)
277 				size = undi_isr.BufferLength;
278 			memcpy(buffer, (const void *)(undi_isr.Frame.seg * 16 + undi_isr.Frame.ofs), size);
279 //			hex_dump(buffer, size);
280 			fRxFinished = false;
281 			return size;
282 
283 		case PXENV_UNDI_ISR_OUT_BUSY:
284 			TRACE("PXENV_UNDI_ISR_OUT_BUSY\n");
285 			fRxFinished = true;
286 			return -1;
287 
288 		case PXENV_UNDI_ISR_OUT_DONE:
289 			TRACE("PXENV_UNDI_ISR_OUT_DONE\n");
290 			fRxFinished = true;
291 			return -1;
292 
293 		default:
294 			TRACE("default!!!\n");
295 			return -1;
296 	}
297 }
298 
299 
300 status_t
301 platform_net_stack_init()
302 {
303 	TRACE("platform_net_stack_init\n");
304 
305 	UNDI *interface = new(nothrow) UNDI;
306 	if (!interface)
307 		return B_NO_MEMORY;
308 
309 	status_t error = interface->Init();
310 	if (error != B_OK) {
311 		TRACE("platform_net_stack_init: interface init failed\n");
312 		delete interface;
313 		return error;
314 	}
315 
316 	error = NetStack::Default()->AddEthernetInterface(interface);
317 	if (error != B_OK) {
318 		delete interface;
319 		return error;
320 	}
321 
322 	return B_OK;
323 }
324