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 station type |
1 |
|
Pedestrian |
2 |
|
Cyclist |
3 |
|
Moped |
4 |
|
Motorcycle |
5 |
|
Passenger car |
6 |
|
Bus |
7 |
|
Light truck |
8 |
|
Heavy truck |
15 |
|
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)
Step 4: Connect to Link Layer
The GN Router needs a Link Layer to actually send and receive packets:
from flexstack.linklayer.raw_link_layer import RawLinkLayer
# Create link layer (receives packets → forwards to GN router)
link_layer = RawLinkLayer(
iface="lo",
mac_address=MAC_ADDRESS,
receive_callback=gn_router.gn_data_indicate # 👈 Incoming packets
)
# Connect GN router to link layer (for outgoing packets)
gn_router.link_layer = link_layer # 👈 Outgoing packets
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 |
|---|---|
|
Next header type (usually |
|
How to route: broadcast, unicast, geo-broadcast, etc. |
|
ITS communication profile |
|
Whether to sign/encrypt the packet |
|
ITS Application ID (identifies the service) |
|
Priority and channel settings |
|
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
Getting Started — Complete tutorial building a V2X application
Link Layer — Link Layer implementations (RawLinkLayer, C-V2X)
Basic Transport Protocol (BTP) — Basic Transport Protocol for port multiplexing