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