public RPCResult <bool> PacketReceived(byte[] packet, int dev_no, int payload_offset, int payload_len, p_addr src) { ushort htype = net.ReadWord(packet, payload_offset); ushort ptype = net.ReadWord(packet, payload_offset + 2); byte hlen = packet[payload_offset + 4]; byte plen = packet[payload_offset + 5]; ushort oper = net.ReadWord(packet, payload_offset + 6); if (htype != 1) { System.Diagnostics.Debugger.Log(0, null, "Packet with unknown HTYPE: " + htype.ToString("X4")); return(false); } if (hlen != 6) { System.Diagnostics.Debugger.Log(0, null, "Invalid HLEN: " + hlen.ToString()); return(false); } HWAddr sha = net.ReadHWAddr(packet, payload_offset + 8); HWAddr tha = net.ReadHWAddr(packet, payload_offset + 8 + hlen + plen); var nd = net.devs[dev_no]; // Reject those packets sent by ourselves (don't reply to our own // announce packets) if (sha.Equals(nd.HWAddr)) { return(false); } switch (ptype) { case 0x0800: // IPv4 { if (plen != 4) { System.Diagnostics.Debugger.Log(0, null, "Invalid HLEN: " + hlen.ToString()); return(false); } IPv4Address spa = net.ReadIPv4Addr(packet, payload_offset + 14); IPv4Address tpa = net.ReadIPv4Addr(packet, payload_offset + 24); System.Diagnostics.Debugger.Log(0, null, "Received IPv4 packet: oper: " + oper.ToString() + ", SHA: " + sha.ToString() + ", SPA: " + spa.ToString() + ", THA: " + tha.ToString() + ", TPA: " + tpa.ToString()); if (oper == 1) { /* Is it a request for our own IP address? */ //var addr = net.devs[dev_no].a as IPv4Address if (net.devs[dev_no].a.Equals(tpa)) { System.Diagnostics.Debugger.Log(0, null, "Received ARP request for our IP"); // build a response packet. We are usually directly above // the link layer in the stack, so only need to reserve space // for ethernet headers (if we are not big enough, the // ethernet layer will do this for us anyway, but it involves // a memcpy and so is less efficient) byte[] ret = new byte[100]; int packet_offset = 32; int packet_len = 0; ret[packet_offset + packet_len++] = 0x00; // HTYPE ret[packet_offset + packet_len++] = 0x01; ret[packet_offset + packet_len++] = 0x08; // PTYPE ret[packet_offset + packet_len++] = 0x00; ret[packet_offset + packet_len++] = 0x06; // HLEN ret[packet_offset + packet_len++] = 0x04; // PLEN ret[packet_offset + packet_len++] = 0x00; // OPER ret[packet_offset + packet_len++] = 0x02; // SHA for (int i = 0; i < 6; i++) { ret[packet_offset + packet_len++] = net.devs[dev_no].HWAddr.MAC[i]; } // SPA for (int i = 0; i < 4; i++) { ret[packet_offset + packet_len++] = tpa.Octets[i]; } // THA for (int i = 0; i < 6; i++) { ret[packet_offset + packet_len++] = sha.MAC[i]; } // TPA for (int i = 0; i < 4; i++) { ret[packet_offset + packet_len++] = spa.Octets[i]; } /*net.InvokeAsync("TransmitPacket", * new object[] { ret, dev_no, packet_offset, packet_len, sha }, * net.sig_packet);*/ net.TransmitEthernetPacket(ret, dev_no, packet_offset, packet_len, sha, 0x0806); } else if (tpa.Equals(spa) && tha.Equals(HWAddr.Zero)) { // This is a gratuitous request (announce) packet // Interpret it as a response oper = 2; } } if (oper == 2) { /* This is a reply to a previous request, or an announcement */ // Cache the current response System.Diagnostics.Debugger.Log(0, null, "Cacheing " + spa.ToString() + " to " + sha.ToString()); GetProtocolDictionary(dev_no, 0x0800)[spa] = sha; // Fulfil pending requests var pending_list = GetPendingRequestList(dev_no, 0x0800, spa); while (pending_list.Count > 0) { var e = pending_list[pending_list.Count - 1]; System.Diagnostics.Debugger.Log(0, null, "Handling pending request"); ((RPCResult <HWAddr>)e.result).Result = sha; e.result.Set(); pending_list.RemoveAt(pending_list.Count - 1); } // Remove the pointer to the pending list so it is collected pending_reqs[dev_no][0x0800].Remove(spa); } } break; default: System.Diagnostics.Debugger.Log(0, null, "Packet with unknown PTYPE: " + htype.ToString("X4")); return(false); } return(true); }
public RPCResult <bool> PacketReceived(byte[] packet, int dev_no, int payload_offset, int payload_len, p_addr src) { /* Parse the provided packet */ // check version uint ver = (uint)(packet[payload_offset] >> 4) & 0xfU; if (ver != 4) { System.Diagnostics.Debugger.Log(0, null, "Packet dropped as version incorrect: " + ver.ToString()); return(false); } // get header length (in bytes) int hlen = (int)((packet[payload_offset] & 0xfU) * 4); // checksum uint csum = calc_checksum(packet, payload_offset, hlen); if (csum != 0) { StringBuilder sb = new StringBuilder(); sb.Append("Packet dropped as checksum incorrect: "); sb.Append(csum.ToString()); sb.Append(". Packet header length: "); sb.Append(hlen.ToString()); sb.Append(", words: "); for (int i = 0; i < hlen; i += 2) { if (i != 0) { sb.Append(" "); } sb.Append(net.ReadWord(packet, payload_offset + i).ToString("X4")); } System.Diagnostics.Debugger.Log(0, null, sb.ToString()); return(false); } // get packet length (excluding header) int plen = net.ReadWord(packet, payload_offset + 2) - hlen; // get fragment offset and flags field ushort frag_off_flags = net.ReadWord(packet, payload_offset + 6); uint flags = (uint)(frag_off_flags >> 13) & 0x3U; // don't handle fragmented packets yet if (flags != 0) { System.Diagnostics.Debugger.Log(0, null, "Packet dropped as fragmented"); return(false); } // get protocol byte prot = packet[payload_offset + 9]; // get source and dest IPs IPv4Address spa = net.ReadIPv4Addr(packet, payload_offset + 12); IPv4Address dpa = net.ReadIPv4Addr(packet, payload_offset + 16); System.Diagnostics.Debugger.Log(0, null, "Received packet from " + spa.ToString() + " to " + dpa.ToString() + ", protocol 0x" + prot.ToString("X2")); // Do we accept the destination address? bool found = false; foreach (var addr in net.addrs) { // check octet by octet so we also catch broadcast addresses IPv4Address tpa = addr.Key as IPv4Address; if (tpa != null) { bool pass = true; for (int i = 0; i < 4; i++) { uint mask = 0xffU << ((3 - i) * 8); uint dpa_masked = dpa.addr & mask; if (dpa_masked != mask && dpa_masked != (tpa.addr & mask)) { pass = false; break; } } if (pass) { found = true; break; } } } if (found) { IPacketHandler prot_handler; if (packet_handlers.TryGetValue(prot, out prot_handler)) { prot_handler.PacketReceived(packet, dev_no, payload_offset + hlen, plen, spa); } } return(true); }