Skip to content

Commit fcfbd45

Browse files
author
Matthias Melcher
committed
All right, this is the first version of the User Mode Ethernet connection that works ok. Still far from a public release, this at least proves the concept and more.
1 parent bd37548 commit fcfbd45

File tree

3 files changed

+147
-15
lines changed

3 files changed

+147
-15
lines changed

Emulator/Network/TUsermodeNetwork.cp

Lines changed: 113 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@
9898
#include <net/if.h>
9999
#include <netinet/in.h>
100100
#include <unistd.h>
101+
#include <ifaddrs.h>
101102

102103

103104

@@ -116,7 +117,8 @@ public:
116117
static const KUInt16 TCPFlagFIN = 0x0001;
117118

118119
/** Used in GetType(). */
119-
static const KUInt16 NetTypeIP = 0x0800;
120+
static const KUInt16 NetTypeIP = 0x0800;
121+
static const KUInt16 NetTypeARP = 0x0806;
120122

121123
/** Used in GetIPProtocol() */
122124
static const KUInt8 IPProtocolTCP = 6;
@@ -139,8 +141,13 @@ public:
139141
}
140142
mCopy = 1;
141143
} else {
142-
mData = data;
143-
mCopy = 0;
144+
if (data) {
145+
mData = data;
146+
mCopy = 0;
147+
} else {
148+
mData = (KUInt8*)calloc(size, 1);
149+
mCopy = 1;
150+
}
144151
}
145152
mSize = size;
146153
}
@@ -179,13 +186,15 @@ public:
179186
mData[i+3] = v>>16;
180187
mData[i+4] = v>>8;
181188
mData[i+5] = v; }
189+
182190
/** Get a 32-bit word in network order. */
183191
KUInt32 Get32(KUInt32 i) { return (mData[i]<<24)|(mData[i+1]<<16)|(mData[i+2]<<8)|(mData[i+3]); }
184192
void Set32(KUInt32 i, KUInt32 v) {
185193
mData[i+0] = v>>24;
186194
mData[i+1] = v>>16;
187195
mData[i+2] = v>>8;
188196
mData[i+3] = v; }
197+
189198
/** Get a 16-bit word in network order. */
190199
KUInt16 Get16(KUInt32 i) { return (mData[i]<<8)|(mData[i+1]); }
191200
void Set16(KUInt32 i, KUInt16 v) {
@@ -232,6 +241,16 @@ public:
232241
KUInt8 *GetUDPPayloadStart(){ return mData + 42; }
233242
KUInt32 GetUDPPayloadSize() { return mSize - 42; }
234243

244+
KUInt16 GetARPHType() { return Get16(14); }
245+
KUInt16 GetARPPType() { return Get16(16); }
246+
KUInt8 GetARPHLen() { return mData[18]; }
247+
KUInt8 GetARPPLen() { return mData[19]; }
248+
KUInt16 GetARPOp() { return Get16(20); }
249+
KUInt64 GetARPSHA() { return Get48(22); }
250+
KUInt32 GetARPSPA() { return Get32(28); }
251+
KUInt64 GetARPTHA() { return Get48(32); }
252+
KUInt32 GetARPTPA() { return Get32(38); }
253+
235254

236255
void SetDstMAC(KUInt64 v) { Set48(0, v); }
237256
void SetSrcMAC(KUInt64 v) { Set48(6, v); }
@@ -267,6 +286,16 @@ public:
267286
void SetUDPChecksum(KUInt16 v) { Set16(40, v); }
268287
void SetUDPPayload(KUInt8 *, KUInt32);
269288

289+
void SetARPHType(KUInt16 v) { Set16(14, v); }
290+
void SetARPPType(KUInt16 v) { Set16(16, v); }
291+
void SetARPHLen(KUInt8 v) { mData[18] = v; }
292+
void SetARPPLen(KUInt8 v) { mData[19] = v; }
293+
void SetARPOp(KUInt16 v) { Set16(20, v); }
294+
void SetARPSHA(KUInt64 v) { Set48(22, v); }
295+
void SetARPSPA(KUInt32 v) { Set32(28, v); }
296+
void SetARPTHA(KUInt64 v) { Set48(32, v); }
297+
void SetARPTPA(KUInt32 v) { Set32(38, v); }
298+
270299
Packet *prev, *next;
271300

272301
private:
@@ -628,12 +657,12 @@ public:
628657
* Create a UDP packet handler.
629658
*/
630659
UDPPacketHandler(TUsermodeNetwork *h, Packet &packet) :
631-
PacketHandler(h),
632-
myMAC(0), theirMAC(0),
633-
myIP(0), theirIP(0),
634-
myPort(0), theirPort(0),
635-
theirID(0),
636-
mSocket(-1)
660+
PacketHandler(h),
661+
myMAC(0), theirMAC(0),
662+
myIP(0), theirIP(0),
663+
myPort(0), theirPort(0),
664+
theirID(0),
665+
mSocket(-1)
637666
{
638667
myMAC = packet.GetSrcMAC();
639668
myIP = packet.GetIPSrcIP();
@@ -691,7 +720,7 @@ public:
691720
net->SetIPv4Checksum(p->Data(), p->Size());
692721
net->SetUDPChecksum(p->Data(), p->Size());
693722
}
694-
723+
695724
/**
696725
* Send a Newton packet to the outside world.
697726
* \param packet send this packet
@@ -720,8 +749,8 @@ public:
720749
theirSockAddr.sin_port = htons(theirPort);
721750
}
722751
int ret =
723-
sendto(mSocket, packet.GetUDPPayloadStart(), packet.GetUDPPayloadSize(),
724-
0, (struct sockaddr*)&theirSockAddr, sizeof(theirSockAddr));
752+
sendto(mSocket, packet.GetUDPPayloadStart(), packet.GetUDPPayloadSize(),
753+
0, (struct sockaddr*)&theirSockAddr, sizeof(theirSockAddr));
725754
if (ret==-1)
726755
return -1;
727756
return 1;
@@ -740,7 +769,7 @@ public:
740769
if (mSocket==-1)
741770
return;
742771
int avail =
743-
recvfrom(mSocket, buf, sizeof(buf), 0, (struct sockaddr*)&theirSockAddr, &addrLen);
772+
recvfrom(mSocket, buf, sizeof(buf), 0, (struct sockaddr*)&theirSockAddr, &addrLen);
744773
if (avail<1)
745774
return;
746775

@@ -781,6 +810,55 @@ public:
781810

782811

783812

813+
/**
814+
* This class handles UDP packets.
815+
*/
816+
class ARPPacketHandler : public PacketHandler
817+
{
818+
public:
819+
820+
/**
821+
* Can we handle the given package?
822+
* \param packet the Newton packet that could be sent
823+
* \param n the network interface
824+
* \return 0 if we can not handle this packet
825+
* \return 1 if we can handled it and it need not to be propagated any further
826+
* \return -1 if an error occurred an no other handler should handle this packet
827+
*/
828+
static int canHandle(Packet &packet, TUsermodeNetwork *net) {
829+
if ( packet.GetType() != Packet::NetTypeARP )
830+
return 0;
831+
printf("---> Newt wants to send some ARP request.\n");
832+
if ( packet.GetARPOp() != 1 ) // is this a request?
833+
return 0;
834+
if ( packet.GetARPHType() != 1 ) // is this an Ethernet MAC address?
835+
return 0;
836+
if ( packet.GetARPPType() != 0x0800 ) // Which upper layer protocol? IP?
837+
return 0;
838+
if ( packet.GetARPHLen() != 6 ) // Length of MAC Address?
839+
return 0;
840+
if ( packet.GetARPPLen() != 4 ) // Length of IP Address?
841+
return 0;
842+
Packet *reply = new Packet(0L, 42);
843+
reply->SetSrcMAC( packet.GetDstMAC() );
844+
reply->SetDstMAC( packet.GetSrcMAC() );
845+
reply->SetType( Packet::NetTypeARP );
846+
reply->SetARPHType( 1 );
847+
reply->SetARPPType( 0x0800 );
848+
reply->SetARPHLen( 6 );
849+
reply->SetARPPLen( 4 );
850+
reply->SetARPOp( 2 ); // reply
851+
reply->SetARPSHA( 0x000000fa00000000ULL | packet.GetARPTPA() ); // faking a MAC address
852+
reply->SetARPSPA( packet.GetARPTPA() );
853+
reply->SetARPTHA( packet.GetARPSHA() );
854+
reply->SetARPTPA( packet.GetARPSPA() );
855+
net->Enqueue(reply);
856+
return 1;
857+
}
858+
};
859+
860+
861+
784862
/**
785863
* Create an interface betweenthe Newton network driver and Einstein.
786864
*/
@@ -790,6 +868,23 @@ TUsermodeNetwork::TUsermodeNetwork(TLog* inLog) :
790868
mFirstPacket( 0L ),
791869
mLastPacket( 0L )
792870
{
871+
// http://www.developerweb.net/forum/showthread.php?t=5085
872+
/*
873+
struct ifaddrs *interfaces;
874+
int ret = getifaddrs(&interfaces);
875+
if (ret==0) {
876+
struct ifaddrs *ifa = interfaces;
877+
while (ifa) {
878+
if (ifa->ifa_name && strcmp(ifa->ifa_name, "en1")==0) {
879+
printf("Network adapter found\n");
880+
struct if_data *ifd = (struct if_data *)ifa->ifa_data;
881+
int x = ifd->ifi_obytes;
882+
}
883+
ifa = ifa->ifa_next;
884+
}
885+
freeifaddrs(interfaces);
886+
}
887+
*/
793888
}
794889

795890

@@ -840,6 +935,11 @@ int TUsermodeNetwork::SendPacket(KUInt8 *data, KUInt32 size)
840935
case 1: return 0; // packet was handled successfuly, leave
841936
case 0: break; // another handler should deal with this packet
842937
}
938+
switch( ARPPacketHandler::canHandle(packet, this) ) {
939+
case -1: return -1; // an error occured, packet must not be handled
940+
case 1: return 0; // packet was handled successfuly, leave
941+
case 0: break; // another handler should deal with this packet
942+
}
843943

844944
// FIXME: simulate the ARP request for now
845945
// see: man 3 getaddrinfo()

Emulator/Network/TUsermodeNetwork.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ class TUsermodeNetwork : public TNetworkManager
4545
{
4646
public:
4747

48-
static const int kMaxTxBuffer = 1514;
49-
static const int kMaxRxBuffer = 1518;
48+
static const int kMaxTxBuffer = 16384;//1514;
49+
static const int kMaxRxBuffer = 16384;//1518;
5050

5151
TUsermodeNetwork(TLog* inLog);
5252

README.ne2000

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
2+
This version of Einstein features emulation for an NE2000
3+
networking PCMCIA card. There are still a lot of missing
4+
features and bugs, but for testing, you can do this:
5+
6+
- compile and run this version of Einstein
7+
- in preferences, set the Network Driver to "User Mode"
8+
- launch the emulation
9+
- install all ethernet related packages from NIE 2.0
10+
- install "./Drivers/NE2000Driver/NE2K.pkg"
11+
- install "Courier" and its libraries
12+
- "insert" the NE2000 card by choosing "Platform->Insert NE2000 Card"
13+
from the Einstein Menu
14+
- the "PCMCIA Ethernet" dialog should appear, close it
15+
- in "Extras", open "Internet Setup"
16+
- click "New -> Generic Setup"
17+
- configure manually and set the local IP to the IP of the host
18+
- set the Mask, Gateway, and DNS (no DHCP yet!)
19+
- close the dialog
20+
- run Courier
21+
- click the single arrow [->o]
22+
- enter "borg.org" as a destination (some random minimal web site)
23+
- in the connection dialog, choose your internet setup, then choose
24+
"PCMCIA Ethernet" as your Card, and tap on "Connect"
25+
- after 10 to 20 seconds, Mr. Borg will give you the disappointing
26+
information that he is no fan of Captain Kirk.
27+
28+
Please let me know if your connection works. I'll be happy to hear
29+
from you. Email einstein at matthiasm dot com.
30+
31+
Matthias
32+

0 commit comments

Comments
 (0)