VOGONS


First post, by superfury

User metadata
Rank l33t++
Rank
l33t++

How is the client's subnet mask used when receiving a packet (from the internet)? The clients are all on ppp connections with their configured subnet masks.
What happens when the modem (for example with multiple clients and an external link (default gateway)) receives packets from the ppp clients' network address (it's host bits are cleared)? How does the router handle that?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 1 of 5, by jakethompson1

User metadata
Rank Oldbie
Rank
Oldbie

It uses bitwise AND.
The router's own IP address on a given interface AND the subnet mask produces the network number. For example, 192.168.95.148 AND 255.255.255.0 = 192.168.95.0.
When routing a packet, the destination address also gets ANDed the same way each interface to see if it produces the same network number and if so, it's considered within that network and goes out on that interface.
This is an oversimplification, since it actually uses the routes listed in the routing table, and there can be overlapping routes (the "metric" number breaks ties).

Reply 2 of 5, by superfury

User metadata
Rank l33t++
Rank
l33t++

So that happens for both packets sent by a PPP client and packets received from other clients(also on PPP) or from the gateway or other non-PPP IPv4 clients on the network?

Right now, my implementation (which has multiple PPP clients connected to a real network with other clients and a router (the default gateway, which is it's default gateway if it can't match the host network and not matched to the clients' own network ID)).

Most of the handling is performed by the ARP (or virtual ARP if it's on the server's internal network (which has all connected PPP clients on it)).

The ARP routine for sending a packet checks:
- Destination on the clients' network numer (same subnet)? Then send to the internal loopback (to be received by all clients, defaulting to a special reserved MAC address for handling such a case, the clients each have MAC addresses following that to keep them seperate).
-- If the above matches and it's a broadcast within the subnet, change the destination MAC address to broadcast instead.
Otherwise:
- Host network matched for the PC that the server is running on? Then
-- Network address matched (for example for a /24 host network this is ending in .0)? Then invalidate the 'ARP' request and broadcast instead.
-- Otherwise, perform an actual ARP for the destination IP address. It can replace the IP address of the requester and it's MAC address with the configured default gateway (to simulate it coming from the router or otherwise the host if that's not configured)
-- The answer for the ARP is waited for 500ms. If obtained within, give the result. Otherwise, retry. It has a 30 second timeout on the ARP timer, to prevent the (new) cached value from going stale (so after 30 seconds the single-entry cache is effectively cleared).
-- If the ARP request times out (after 500ms), it fails the request and sends it to the host's MAC address instead.
- Finally, if the host network isn't matched, it simple tries to send it to the default gateway.

All sending of packets is through a global packet sending routine:
- If IP and not broadcasting, perform ARP (using the above algorithm). If it has an ARP address, replace it in the packet to send. If loopback is returned, perform a loopback into the packet receiver directly (not sending on the host network).
-- Otherwise, if IP packet to non-broadcast IP, If sending to the clients or hosts broadcast address (including subnets):
-- Change MAC to broadcast.
--- If sending to the client's broadcast address (or it's subnet's broadcast), perform a loopback. Otherwise, discard.
- If none of the above apply, or loopback, loopback the packet into a buffer (used by the pcap receiver). Otherwise, if possible, send the packet onto the host computer's network using pcap.

The pcap receiver (in another CPU thread) receives packets from either the loopback buffer or the host's pcap interface. The loopback buffer has priority on receiving packets.
If it receives a packet, it registers it internally for use and when from the pcap interface, it discards packets to it's loopback adapter's MAC address (it's an indicator loopback is used, so to prevent conflicts the packets from the host machine are ignored when from that MAC address). Otherwise, continue to the next step.

The next step is that the EtherType field is examined. If it's incompatible with what the virtual modem supports, it's ignored and discarded. Otherwise, it starts into the first phase of the receiver handling.

The first phase of the receiver handling checks for any eligible clients that can receive the packet. If all clients that are eligible are clear to receive the packet, the receiver continues to proceed to move the buffer over to the global receiver buffer for all clients that are connected.
This step also filters eligible clients by:
- If not the clients' IP or broadcast address zero (0.0.0.0) then if it isn't a broadcast address, it's not eligible for the client.
- Otherwise, if it's the host machine's subnet-based broadcast address and not from the loopback, it's ignored for the client.
Next, there's also a little check that checks not the local (reserved) MAC and broadcast MAC. If that happens and it's an IPv4 packet with the local reserved MAC (thus loopback special cased), it's ignored for the client.
Next, if all above succeed, ARP replies are checked and registered for the ARP handler if it receives a reply for it's current request.
Next it checks for DHCP pending (for future implementation) and aborts further processing if so. Right now this shouldn't happen yet.
Up next is that it checks the MAC address of the destination for not being the client's own MAC or broadcast MAC. If that's the case, ignore if the packets is addressed to the local reserved MAC and it's an IP packet (in other words, a loopback to ourselves).
Next, it processed ARP requests and sends back a reply using the same loopback or the real ethernet, depending on it's source.
Then it checks if the packet server client is in it's active state (communicating with the host using PPP IP/IPX/other protocol packets. If not, ignore the packet for this client.
Otherwise, check if the packet buffer of the client is empty to receive it (3 buffers, one for IPv4, one for EFD5 and one for all other packet types (in this case IPX for current builds)).
If it's indeed empty, proceed to the final phase of receiving: move the packet to the buffer and for IPX packets increase hop count and discard if exceeded. The loopback buffer is emptied at this point as well (as it's properly parsed).

The main routine performs much the same, but for each client in parallel. It empties the filled global 3 packet buffers into the all client's 3 packet buffer, then lets the client parse it in it's own time (according to it's transmission timing with the connected cleint etc.).
The main difference here is that it has no ARP handling, handles PPPOE (if used on the host network for passthrough PPPOE connections), parses the packets once again using the same checks (to make sure each client that matches receives the packet in parallel with all other clients, making receiving multicast possible) and handles the connected clients' PPP connections (or SLIP-based connection using ethernet packets (it has an official name, which I can't remember atm) and all the stuff for the other protocols (like EDFS, IPX etc.) as well as PPP packet encryption.
It also performs the actual routing to the host network for physical IPX/IPv4/EDFS packets using the Ethernet II protocol encapsulation, a text (ASCII) terminal on the client's connection for logging in, half implemented DHCP support (disabled).

Then in the outside connection handling (outside the client loop), there's a loop handling timed data I/O to all TCP connections (which are virtual modems like Dosbox, UniPCemu etc. dialing into the server).
One nice little thing it also supports is that the whole modem interface can be turned inside-out, with instead of the serial modem's interface being connected to a serial port inside the x86 emulator, it's instead connected to a real (or virtual if drivers are installed on the host) serial port, allowing other devices (or funnily enough, even the host itself if using a loopback serial port of sorts, like I tested and use with com0com for example, providing the same dial-up network to the windows machine for connecting to it's clients the same way (and sharing a seperate network, that's inside the real network that Windows is on as well (unless the server is configured to be in loopback mode) 🤣 )).

That's basically how it works right now.

The host and client broadcast addresses are detected in a simple way, using the known netmasks and addresses:
There's a function that checks if the address is a broadcast address for the client (priority) or the host.
There's a function that checks if an IP is the client's subnet IP (destination and client IP addresses match when masked using the client's subnet mask).
There's a function for getting the client's broadcast address (when subnet mask isn't all-ones, it's giving the client's IP, subnet masked and the host bits all set).
There's a function for validating incoming multicast addresses (first 3 bits of the top 4 bits set). Right now all multicast addresses are considered valid (unknown how to handle them right now).
Much like there's a function to get the client's broadcast address, there's one for the host machine as well.
Then the main check is the client broadcast address validation function. It matches if:
- destination IP masked matches client IP masked and client IP is non-zero, then if masked with host bits set, it's the broadcast address for the client's network (broadcast type 1). Otherwise, check more below.
- If multicast, then multicast (type 3).
- If zero address (0.0.0.0), count the same as 255.255.255.255 below.
- If 255.255.255.255 broadcast, report broadcast type 2.
- Otherwise, give no broadcast (type 0).

The host function performs much the same, but using the host address and subnet mask instead.

That's pretty much roughly how it's implemented right now.

Last edited by superfury on 2025-03-13, 00:22. Edited 1 time in total.

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 3 of 5, by jakethompson1

User metadata
Rank Oldbie
Rank
Oldbie

PPP is a trivial case because it is a "point-to-point" link; the subnet mask will be something like 255.255.255.252.

But yes, whatever machine that is doing the routing has to deal with this, especially if it's supporting multiple PPP connections. While they are up and running you should be able to run route -n or route print (on windows) and see the routing table.

Reply 4 of 5, by superfury

User metadata
Rank l33t++
Rank
l33t++

I updated my last post with the specifics of the modem-router to host network interface I implemented right now.
There's filtering support on the other protocols as well, but I left out most of it.

The PPP receiving packet handling performs just a few little extra checks on top of the already-mentioned:
- Checks if IPCP is open. if not, discard.
- Checks minimum packet length (ethernet header + 16 + 4), if not, discard.
- If not the IP of the client, or broadcast, discard non-client broadast. Otherwise, if multicast, validate and discard if invalidated.
- Finally, if IP packets are suppressed by the client from receiving those (by the client rejecting the IPv4 packet protocol), discard the packet.
- It then knows that the client can receive the packet on PPP, so it enters into general PPP sender logic (same for EDFS and IPX). It waits for the PPP transmitter to be able to send a packet (by the client's transmitter buffer emptying, signifying that the last PPP packet has been transmitted). It then fills it with the packet received and PPP headers/footers, which is then sent to the client using it's TCP connection (basically it's dial-up serial line that's connected to it's virtual modem listening on it's TCP data).

Sending a packet from PPP or SLIP simply extracts it, encapsulates it into a matching ethernet II frame and uses the same generic pcap-compatible (and loopback as well as ARP-ing if it can for IPv4) packet sending routine that's used with the ARP packets being sent for requests.

And the ARP routine for requesting and handling the answers the receiver parses will return the result of the ARP request (or it's timeout) to actually send the packet to loopback, pcap or forced loopback (if the special server mode for loopback if enabled, which is setting -2 (-1 being no packet server and 0+ using the pcap network card for sending/receiving)).

One funny thing I managed to do is make Windows 10 connect to the dial-up server (although it's in loopback mode) using the loopback serial port and using the modem to connect using the virtual connnection (using TCP) to the packet server. Windows managed to properly dial the emulated modem in my application, then connecting using PPP to my packet server (which is basically running TCP over the same host network from my emulator (modem) to itself (the packet server), so yet another loopback 🤣 ).
So then you get: Windows 10 <- virtual serial-> UniPCemu runing virtual dial-up modem <- TCP -> UniPCemu running the packet server <-> real network (if not loopback mode) or internal network (if loopback mode).

Oddly enough I couldn't get the UniPCemu's Dosbox Windows 95 dialed to it communicate with Windows 10 properly when using SMB for example. Although simple Windows PING seemed to work properly, as does the other plain IPv4 connections (like normal TCP etc.). I think it's a problem related to the subnet, as SMB uses some weird (subnet) broadcasting it seems? Something is missing there at least.

Edit: Although it only assumes 1 IP address allocated for each PPP client. Perhaps it should increase that range if it detects the subnet mask's host part being more than 1 bit in size (each detected final bit size(2 bit, 3 final bits, 4 final bits etc.) increasing the allocated IP address range by a multiplier of 2 and substract 2 for the IP addresses block to allocate)?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 5 of 5, by superfury

User metadata
Rank l33t++
Rank
l33t++

How is host 0 of a subnet handled? So for example a packet with from 192.168.178.1 to IP 192.168.178.0 with subnet mask 255.255.255.0?
Does it perform the same as 192.168.168.255 (broadcast, that's what my packet server performs right now) when the next hop on PPP receives it?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io