GeoNetworking (GN)

GeoNetworking is the routing layer of the V2X protocol stack. Unlike traditional IP routing that uses addresses, GeoNetworking routes messages based on geographic areas — perfect for vehicular scenarios where you want to reach “all vehicles within 500 meters” rather than specific IP addresses.

Note

GeoNetworking is defined in ETSI EN 302 636-4-1. It sits between the Link Layer (below) and BTP/Facilities layers (above).

What GeoNetworking Does

  • 📍 Geographic addressing — Send to areas, not addresses

  • 🔄 Position management — Tracks your vehicle’s location

  • 📦 Packet forwarding — Routes packets based on position

  • 🗺️ Location table — Maintains positions of nearby stations

Architecture

GeoNetworking connects the Link Layer to upper protocol layers:

        flowchart LR
 BTP["Basic Transport Protocol (BTP)"]
 GN["Geonetworking"]
 LL["Link Layer"]
 BTP -->|"GNDataRequest"| GN
 GN -->|"GNDataIndication"| BTP
 GN -->|"send(packet: bytes)"| LL
 LL -->|"receive_callback(packet: bytes)"| GN
 LS["Location Service"]
 LS -->|GPSD TPV| GN
    

Key Components

Component

Description

GN Router

Main routing engine that processes incoming/outgoing packets

MIB

Management Information Base — configuration parameters

GN Address

Unique identifier combining station type and MAC address

Location Table

Cache of known neighbor positions (updated from received packets)


Getting Started

Step 1: Configure the MIB

The MIB (Management Information Base) holds configuration for your GeoNetworking station. The most important setting is your GN Address:

from flexstack.geonet.mib import MIB
from flexstack.geonet.gn_address import GNAddress, M, ST, MID

# Your station's MAC address (6 bytes)
MAC_ADDRESS = b'\x00\x11\x22\x33\x44\x55'

# Configure the MIB with your GN Address
mib = MIB(
    itsGnLocalGnAddr=GNAddress(
        m=M.GN_MULTICAST,      # Addressing mode
        st=ST.CYCLIST,         # Station type (see table below)
        mid=MID(MAC_ADDRESS),  # Mobile ID from MAC
    ),
)

Station Types (ST):

Value

Constant

Description

0

UNKNOWN

Unknown station type

1

PEDESTRIAN

Pedestrian

2

CYCLIST

Cyclist

3

MOPED

Moped

4

MOTORCYCLE

Motorcycle

5

PASSENGER_CAR

Passenger car

6

BUS

Bus

7

LIGHT_TRUCK

Light truck

8

HEAVY_TRUCK

Heavy truck

15

RSU

Road Side Unit

Step 2: Create the Router

from flexstack.geonet.router import Router as GNRouter

# Create the GeoNetworking router
gn_router = GNRouter(mib=mib, sign_service=None)

Tip

The sign_service parameter is for security. Set to None for unsigned packets, or pass a security service for signed V2X messages.

Step 3: Provide Position Updates

GeoNetworking needs to know your current position. You can either:

Option A: Manual updates (for testing)

# GPSD-TPV format position data
position = {
    'time': "2005-07-08T11:28:07.114Z",  # ISO 8601 timestamp
    'lat': 52.5200,    # Latitude (degrees)
    'lon': 13.4050,    # Longitude (degrees)
    'alt': 34.0,       # Altitude (meters)
    'speed': 0.0,      # Speed (m/s)
    'climb': 0.0,      # Vertical speed (m/s)
    'track': 0.0,      # Heading (degrees from north)
    'mode': 3          # Fix type: 3 = 3D fix
}

gn_router.refresh_ego_position_vector(position)

There is the ThreadStaticLocationService in flexstack.utils.static_location_service module that can be used to provide periodic manual updates.

from flexstack.utils.static_location_service import ThreadStaticLocationService

# Create location service
location_service = ThreadStaticLocationService(
    period=1000,  # milliseconds
    latitude=2.112104,
    longitude=41.386931,
)
# Register callback to update GN router
location_service.add_callback(gn_router.refresh_ego_position_vector)

Option B: Automatic updates (recommended)

from flexstack.utils.static_location_service import GPSDLocationService

# Create location service
location_service = GPSDLocationService(
     gpsd_host="localhost",
     gpsd_port=2947,
 )

# Register callback for automatic updates
location_service.add_callback(gn_router.refresh_ego_position_vector)

Sending Packets

To send a GeoNetworking packet, create a GNDataRequest with all necessary parameters:

from flexstack.geonet.service_access_point import (
    GNDataRequest,
    CommonNH,
    PacketTransportType,
    CommunicationProfile,
    SecurityProfile,
    TrafficClass,
)

# Your payload
payload = b"Hello, GeoNetworking!"

# Create the request
gn_request = GNDataRequest(
    upper_protocol_entity=CommonNH.ANY,
    packet_transport_type=PacketTransportType(),  # Default: Single Hop Broadcast
    communication_profile=CommunicationProfile.UNSPECIFIED,
    security_profile=SecurityProfile.NO_SECURITY,
    its_aid=0,
    security_permissions=b"\x00",
    traffic_class=TrafficClass(),
    length=len(payload),
    data=payload,
)

# Send it!
gn_router.gn_data_request(gn_request)

GNDataRequest Parameters:

Parameter

Description

upper_protocol_entity

Next header type (usually CommonNH.BTP_A or CommonNH.BTP_B)

packet_transport_type

How to route: broadcast, unicast, geo-broadcast, etc.

communication_profile

ITS communication profile

security_profile

Whether to sign/encrypt the packet

its_aid

ITS Application ID (identifies the service)

traffic_class

Priority and channel settings

data

The actual payload bytes

Sending GeoBroadcast Packets

To send a GeoBroadcast packet to a specific geographic area, set the packet_transport_type accordingly:

from flexstack.geonet.service_access_point import GNDataRequest
from flexstack.geonet.service_access_point import (
   GNDataRequest,
   CommonNH,
   PacketTransportType,
   CommunicationProfile,
   Area,
   GeoBroadcastHST,
   HeaderType,
)

payload = b"example_payload_data"

gn_request = GNDataRequest(
   upper_protocol_entity = CommonNH.ANY,
   packet_transport_type = PacketTransportType(
               header_subtype=GeoBroadcastHST.GEOBROADCAST_CIRCLE,
               header_type=HeaderType.GEOBROADCAST,
            ),
   area=Area(
      a=1000,  # Radius in meters
      b=0,
      angle=0,
      latitude=int(2.112104*10**7), # Latitude in 1e-7 degrees
      longitude=int(41.386931*10**7), # Longitude in 1e-7 degrees
   ),
   communication_profile=CommunicationProfile.UNSPECIFIED,
   data=payload,
   length=len(payload),
)

# Send the GeoBroadcast packet
gn_router.gn_data_request(gn_request)

Receiving Packets

Register a callback to handle incoming GeoNetworking packets:

from flexstack.geonet.service_access_point import GNDataIndication

def on_gn_packet_received(indication: GNDataIndication):
    """Called when a GeoNetworking packet arrives."""
    print(f"📥 Received GN packet!")
    print(f"   Source: {indication.source_position_vector}")
    print(f"   Data: {indication.data.hex()}")

# Register the callback
gn_router.register_indication_callback(on_gn_packet_received)

Note

In practice, you rarely handle GN packets directly. Instead, you connect a BTP Router which demultiplexes packets to the appropriate facilities service (CAM, DENM, etc.).


Complete Example

Here’s a complete script that sends and receives GeoNetworking packets:

  1#!/usr/bin/env python3
  2"""
  3GeoNetworking Example
  4
  5Demonstrates sending and receiving GN packets over a Raw Link Layer.
  6"""
  7
  8import time
  9from flexstack.linklayer.raw_link_layer import RawLinkLayer
 10from flexstack.geonet.router import Router as GNRouter
 11from flexstack.geonet.mib import MIB
 12from flexstack.geonet.gn_address import GNAddress, M, ST, MID
 13from flexstack.geonet.service_access_point import (
 14   GNDataRequest,
 15   GNDataIndication,
 16   CommonNH,
 17   PacketTransportType,
 18   CommunicationProfile,
 19   SecurityProfile,
 20   TrafficClass,
 21)
 22
 23MAC_ADDRESS = b'\x00\x11\x22\x33\x44\x55'
 24
 25
 26def on_gn_packet_received(indication: GNDataIndication):
 27   """Handle incoming GeoNetworking packets."""
 28   print(f"📥 Received GN packet: {indication.data[:20].hex()}...")
 29
 30
 31def main():
 32   # Step 1: Configure MIB
 33   mib = MIB(
 34      itsGnLocalGnAddr=GNAddress(
 35            m=M.GN_MULTICAST,
 36            st=ST.CYCLIST,
 37            mid=MID(MAC_ADDRESS),
 38      ),
 39   )
 40
 41   # Step 2: Create GN Router
 42   gn_router = GNRouter(mib=mib, sign_service=None)
 43   gn_router.register_indication_callback(on_gn_packet_received)
 44
 45   # Step 3: Provide position (manual for this example)
 46   position = {
 47      'time': "2005-07-08T11:28:07.114Z",
 48      'lat': 52.5200,
 49      'lon': 13.4050,
 50      'alt': 34.0,
 51      'speed': 0.0,
 52      'climb': 0.0,
 53      'track': 0.0,
 54      'mode': 3
 55   }
 56   gn_router.refresh_ego_position_vector(position)
 57
 58   # Step 4: Connect Link Layer
 59   link_layer = RawLinkLayer(
 60      iface="lo",
 61      mac_address=MAC_ADDRESS,
 62      receive_callback=gn_router.gn_data_indicate
 63   )
 64   gn_router.link_layer = link_layer
 65
 66   print("✅ GeoNetworking router active")
 67   print("📡 Sending packets every second...")
 68   print("Press Ctrl+C to exit\n")
 69
 70   try:
 71      while True:
 72            # Create payload
 73            payload = bytes([i % 256 for i in range(100)])
 74
 75            # Build GN request
 76            gn_request = GNDataRequest(
 77               upper_protocol_entity=CommonNH.ANY,
 78               packet_transport_type=PacketTransportType(),
 79               communication_profile=CommunicationProfile.UNSPECIFIED,
 80               security_profile=SecurityProfile.NO_SECURITY,
 81               its_aid=0,
 82               security_permissions=b"\x00",
 83               traffic_class=TrafficClass(),
 84               length=len(payload),
 85               data=payload,
 86            )
 87
 88            # Send packet
 89            gn_router.gn_data_request(gn_request)
 90            print(f"📤 Sent GN packet: {payload[:20].hex()}...")
 91
 92            time.sleep(1)
 93
 94   except KeyboardInterrupt:
 95      print("\n👋 Shutting down...")
 96   print("✅ Shutdown complete")
 97
 98
 99if __name__ == "__main__":
100   main()

See Also