Beispiel #1
0
    def write_packet(self,
                     packet: NetRomPacket,
                     forward: bool = False) -> bool:
        possible_routes = self.router.route(packet)
        routed = False
        for route in possible_routes:
            neighbor = self.router.neighbors.get(str(route))
            if neighbor is None:
                self.logger.warning(f"No neighbor for route {route}")
                continue
            #print(f"Trying route {route} to neighbor {neighbor}")
            data_link = self.data_links.get(neighbor.port)

            if data_link.link_state(neighbor.call) == AX25StateType.Connected:
                data_link.dl_data_request(neighbor.call, L3Protocol.NetRom,
                                          packet.buffer)
                routed = True
                EventBus.emit("netrom.outbound", [packet])
                if forward:
                    # Log this transmission differently if it's being forwarded
                    self.logger.info(
                        f"[L3 Route={route} Neighbor={neighbor.call}] TX: {packet}"
                    )
                else:
                    self.debug(f"TX: {packet}")
                    packet_logger.info(f"TX: {packet}")
                break

        if not routed:
            self.warning(
                f"Could not route packet to {packet.dest}. Possible routes were {possible_routes}"
            )
            pass

        return routed
Beispiel #2
0
    def _loop_sync(self, frame: FrameData):
        try:
            packet = decode_ax25_packet(frame.data)
            if packet.dest == AX25Call("NODES"):
                self.debug(f"RX: {packet}")
            else:
                self.debug(f"RX: {packet}")
            packet_logger.info(f"RX: {packet}")
            EventBus.emit("packet", [packet])
        except Exception:
            self.error(f"Had an error parsing packet: {frame}")
            return

        try:
            # Check if this is a special L3 message
            should_continue = True
            for l3 in self.l3_handlers:
                should_continue = l3.maybe_handle_special(frame.port, packet)
                if not should_continue:
                    self.debug(f"Handled by L3 {l3}")
                    break

            # If it has not been handled by L3
            if should_continue:
                if not packet.dest == self.link_call:
                    self.warning(
                        f"Discarding packet not for us {packet}. We are {self.link_call}"
                    )
                else:
                    self.state_machine.handle_packet(packet)
            else:
                self.debug(
                    "Not continuing because this packet was handled by L3")
        except Exception:
            self.error(f"Had handling packet {packet}")
Beispiel #3
0
    def bind(self, l4_call: AX25Call, l4_alias: str):
        self.router.listen_for_address(l4_call, l4_alias)
        self.l3_apps[l4_call] = l4_alias

        # Need to bind this here so the application can start sending packets right away
        EventBus.bind(
            EventListener(
                f"netrom.{l4_call}.outbound", f"netrom_{l4_call}_outbound",
                lambda remote_call, data: self.nl_data_request(
                    remote_call, l4_call, data)), True)
Beispiel #4
0
 def nl_data_indication(self, my_circuit_idx: int, my_circuit_id: int,
                        remote_call: AX25Call, local_call: AX25Call,
                        data: bytes):
     # Called from the state machine to indicate data to higher layers
     EventBus.emit(f"netrom.{local_call}.inbound", my_circuit_idx,
                   remote_call, data)
     if my_circuit_idx in self.l3_connections:
         self.l3_connections[my_circuit_idx][1].data_received(data)
     else:
         self.warning(
             f"Data indication for unknown circuit {my_circuit_idx}")
Beispiel #5
0
    def nl_disconnect_indication(self, my_circuit_idx: int, my_circuit_id: int,
                                 remote_call: AX25Call, local_call: AX25Call):
        EventBus.emit(f"netrom.{local_call}.disconnect", my_circuit_idx,
                      remote_call)

        if local_call in self.l3_servers:
            if my_circuit_idx in self.l3_connections:
                self.l3_connections[my_circuit_idx][1].connection_lost(None)
                del self.l3_connections[my_circuit_idx]
            else:
                self.warning(
                    f"Disconnect indication received for unknown circuit {my_circuit_idx}"
                )
Beispiel #6
0
 def maybe_handle_special(self, port: int, packet: AX25Packet) -> bool:
     """L3Handler.maybe_handle_special"""
     if type(packet) == UIFrame:
         ui = cast(UIFrame, packet)
         if ui.protocol == L3Protocol.NetRom and ui.dest == AX25Call(
                 "NODES"):
             # Parse this NODES packet and mark it as handled
             nodes = parse_netrom_nodes(ui.info)
             EventBus.emit("netrom.nodes", [nodes])
             asyncio.get_event_loop().create_task(
                 self._update_nodes(packet.source, port, nodes))
             # Stop further processing
             return False
     return True
Beispiel #7
0
    def dl_data_indication(self, remote_call: AX25Call, local_call: AX25Call,
                           protocol: L3Protocol, data: bytes):
        EventBus.emit(f"link.{local_call}.inbound", remote_call, protocol,
                      data)
        handled = False
        for l3 in self.l3_handlers:
            if l3.can_handle(protocol):
                handled = l3.handle(self.link_port, remote_call, data)
            if handled:
                break

        if not handled:
            self.debug(
                f"No handler defined for protocol {repr(protocol)}. Discarding"
            )
Beispiel #8
0
    async def _handle_packet_async(self, netrom_packet: NetRomPacket):
        """If packet is for us, handle it, otherwise forward it using our L3 routing table"""

        EventBus.emit("netrom.incoming", [netrom_packet])
        self.debug(f"RX: {netrom_packet}")
        packet_logger.info(f"RX: {netrom_packet}")

        if netrom_packet.dest == AX25Call("KEEPLI-0"):
            # What are these?? Just ignore them
            pass
        elif netrom_packet.dest == AX25Call.parse(self.config.node_call()):
            # Destination is this node
            self.sm.handle_packet(netrom_packet)
        elif netrom_packet.dest in self.l3_apps:
            # Destination is an app served by this node
            self.sm.handle_packet(netrom_packet)
        elif netrom_packet.dest in self.l3_servers:
            # Destination is an app served by this node
            self.sm.handle_packet(netrom_packet)
        else:
            # Destination is somewhere else
            self.write_packet(netrom_packet, forward=True)
Beispiel #9
0
    def nl_connect_indication(self, my_circuit_idx: int, my_circuit_id: int,
                              remote_call: AX25Call, local_call: AX25Call,
                              origin_node: AX25Call, origin_user: AX25Call):
        # Send a connect event
        EventBus.emit(f"netrom.{local_call}.connect", my_circuit_idx,
                      remote_call)

        if my_circuit_idx in self.l3_half_open:
            # Complete a half-opened connection
            protocol_factory = self.l3_half_open[my_circuit_idx]
            protocol = protocol_factory()
            transport = NetworkTransport(self, local_call, remote_call,
                                         my_circuit_idx, origin_node,
                                         origin_user)
            protocol.connection_made(transport)
            self.l3_connections[my_circuit_idx] = (transport, protocol)
            del self.l3_half_open[my_circuit_idx]
        elif local_call in self.l3_servers:
            if my_circuit_idx in self.l3_connections:
                # An existing connection, re-connect it
                self.l3_connections[my_circuit_idx][1].connection_lost(
                    RuntimeError("Remote end reconnected"))
                self.l3_connections[my_circuit_idx][1].connection_made(
                    self.l3_connections[my_circuit_idx][0])
            else:
                # This a new connection, create the transport and protocol
                transport = NetworkTransport(self, local_call, remote_call,
                                             my_circuit_idx, origin_node,
                                             origin_user)
                protocol = self.l3_servers[local_call]()
                protocol.connection_made(transport)
                self.l3_connections[my_circuit_idx] = (transport, protocol)
        else:
            self.warning(
                f"Got unexpected connection from {remote_call} at {local_call}:{my_circuit_idx}"
            )
Beispiel #10
0
 def __init__(self, my_call: str, my_alias: str, remote_call, nl: NetRom):
     self.local_call = AX25Call.parse(my_call)
     self.local_alias = AX25Call(callsign=my_alias)
     self.remote_call = AX25Call.parse(remote_call)
     self.nl = nl
     self.stdin_queue = Queue()
     self.connected = False
     self.circuit_id = None
     EventBus.bind(
         EventListener(f"netrom.{my_call}.connect",
                       f"netrom_{my_call}_connect", self.handle_connect))
     EventBus.bind(
         EventListener(f"netrom.{my_call}.disconnect",
                       f"netrom_{my_call}_disconnect",
                       self.handle_disconnect))
     EventBus.bind(
         EventListener(f"netrom.{my_call}.inbound",
                       f"netrom_{my_call}_inbound", self.handle_data))
Beispiel #11
0
 def __init__(self, local_call: str, remote_call: str,
              datalink: DataLinkManager):
     self.local_call = AX25Call.parse(local_call)
     self.remote_call = AX25Call.parse(remote_call)
     self.dl = datalink
     self.stdin_queue = Queue()
     self.connected = False
     self.circuit_id = None
     EventBus.bind(
         EventListener(f"link.{local_call}.connect",
                       f"link_{local_call}_connect", self.handle_connect))
     EventBus.bind(
         EventListener(f"link.{local_call}.disconnect",
                       f"link_{local_call}_disconnect",
                       self.handle_disconnect))
     EventBus.bind(
         EventListener(f"link.{local_call}.inbound",
                       f"link_{local_call}_inbound", self.handle_data))
Beispiel #12
0
 def dl_disconnect_indication(self, remote_call: AX25Call,
                              local_call: AX25Call):
     EventBus.emit(f"link.{local_call}.disconnect", remote_call)
Beispiel #13
0
 def dl_error(self, remote_call: AX25Call, local_call: AX25Call,
              error_code: str):
     EventBus.emit(f"link.{local_call}.error", error_code)