Link a PAN to br-lan: default gateway not set

Hi everyone,
I'm trying to setup a PAN on my wireless AP.
So far, I've succeeded making the connection to br-lan, and the device gets a valid IP.
But, when I run "ip route list" on the device, the default gateway (192.168.177.1) isn't set.
The subnet 192.168.177.0, however, appears on the list,
and it looks like it got the DNS servers as well (when I run tcpdump on the bnep interface, I can see a http request tries to query a DNS server, and it gets a response)
Any clue how I should learn the device "use 192.168.177.1 as default gateway"?
I run dhcpd 4.4.2

Please run the following commands (copy-paste the whole block) and paste the output here, using the "Preformatted text </> " button:
grafik
Remember to redact passwords, MAC addresses and any public IP addresses you may have

ubus call system board; \
uci export network; uci export wireless; \
uci export dhcp; uci export firewall; \
head -n -0 /etc/firewall.user; \
ip -4 addr ; ip -4 ro li tab all ; ip -4 ru; \
ls -l  /etc/resolv.* /tmp/resolv.* /tmp/resolv.*/* ; head -n -0 /etc/resolv.* /tmp/resolv.* /tmp/resolv.*/*
~# ubus call system board; \
> uci export network; uci export wireless; \
> uci export dhcp; uci export firewall; \
> head -n -0 /etc/firewall.user; \
> ip -4 addr ; ip -4 ro li tab all ; ip -4 ru; \
> ls -l  /etc/resolv.* /tmp/resolv.* /tmp/resolv.*/* ; head -n -0 /etc/resolv.* /tmp/resolv.* /tmp/resolv.*/*
{
        "kernel": "5.15.80",
        "hostname": "apbureau",
        "system": "ARMv8 Processor rev 4",
        "model": "Bananapi BPI-R64",
        "board_name": "bananapi,bpi-r64",
        "rootfs_type": "squashfs",
        "release": {
                "distribution": "OpenWrt",
                "version": "SNAPSHOT",
                "revision": "r21374-366bcffa0e",
                "target": "mediatek/mt7622",
                "description": "OpenWrt SNAPSHOT r21374-366bcffa0e"
        }
}
package network

config interface 'loopback'
        option device 'lo'
        option proto 'static'
        option ipaddr '127.0.0.1'
        option netmask '255.0.0.0'

config globals 'globals'
        option packet_steering '1'

config device
        option name 'br-lan'
        option type 'bridge'
        list ports 'eth2'
        list ports 'lan1'
        list ports 'lan2'
        list ports 'lan3'
        list ports 'lan4'
        list ports 'wan'
        option mtu '4000'

config interface 'lan'
        option device 'br-lan'
        option proto 'static'
        option netmask '255.255.255.0'
        option ipaddr '192.168.177.26'
        option gateway '192.168.177.1'
        option ip6assign '64'

config device
        option name 'eth2'
        option mtu '4000'

config device
        option name 'lan1'
        option mtu '4000'

config device
        option name 'lan2'
        option mtu '4000'

config device
        option name 'lan3'
        option mtu '4000'

config device
        option name 'lan4'
        option mtu '4000'

config device
        option name 'wan'
        option mtu '4000'

config device
        option name 'eth0'
        option mtu '4096'

config device
        option name 'wl0-ap0'
        option mtu '4000'

config device
        option name 'wl1-ap0'
        option mtu '4000'

config interface 'lan6'
        option proto 'dhcpv6'
        option device 'br-lan'
        option reqaddress 'try'
        option reqprefix 'auto'

package wireless

config wifi-device 'radio0'
        option type 'mac80211'
        option path '1a143000.pcie/pci0000:00/0000:00:00.0/0000:01:00.0'
        option band '5g'
        option cell_density '0'
        option channel '36'
        option htmode 'VHT80'
        option country 'PT'

config wifi-device 'radio1'
        option type 'mac80211'
        option path 'platform/18000000.wmac'
        option channel '1'
        option band '2g'
        option htmode 'HT20'
        option country 'BE'
        option cell_density '0'

config wifi-iface 'wifinet0'
        option device 'radio0'
        option mode 'ap'
        option ssid 'FRITZ!Box'
        option encryption 'psk2+tkip+ccmp'
        option key '#####'
        option network 'lan'
        option ieee80211r '1'
        option ft_over_ds '0'
        option ft_psk_generate_local '1'

config wifi-iface 'wifinet1'
        option device 'radio1'
        option mode 'ap'
        option ssid 'FRITZ!Box'
        option encryption 'psk2+tkip+ccmp'
        option key '####'
        option network 'lan'
        option ieee80211r '1'
        option ft_over_ds '0'
        option ft_psk_generate_local '1'

package dhcp

config isc_dhcpd 'isc_dhcpd'
        option authoritative '1'
        option default_lease_time '3600'
        option max_lease_time '86400'

package firewall

config defaults
        option syn_flood '1'
        option input 'ACCEPT'
        option output 'ACCEPT'
        option forward 'REJECT'

config zone
        option name 'lan'
        option input 'ACCEPT'
        option output 'ACCEPT'
        option forward 'ACCEPT'
        list network 'lan'

config zone
        option name 'wan'
        option input 'REJECT'
        option output 'ACCEPT'
        option forward 'REJECT'
        option masq '1'
        option mtu_fix '1'

config forwarding
        option src 'lan'
        option dest 'wan'

config rule
        option name 'Allow-DHCP-Renew'
        option src 'wan'
        option proto 'udp'
        option dest_port '68'
        option target 'ACCEPT'
        option family 'ipv4'

config rule
        option name 'Allow-Ping'
        option src 'wan'
        option proto 'icmp'
        option icmp_type 'echo-request'
        option family 'ipv4'
        option target 'ACCEPT'

config rule
        option name 'Allow-IGMP'
        option src 'wan'
        option proto 'igmp'
        option family 'ipv4'
        option target 'ACCEPT'

config rule
        option name 'Allow-DHCPv6'
        option src 'wan'
        option proto 'udp'
        option dest_port '546'
        option family 'ipv6'
        option target 'ACCEPT'

config rule
        option name 'Allow-MLD'
        option src 'wan'
        option proto 'icmp'
        option src_ip 'fe80::/10'
        list icmp_type '130/0'
        list icmp_type '131/0'
        list icmp_type '132/0'
        list icmp_type '143/0'
        option family 'ipv6'
        option target 'ACCEPT'

config rule
        option name 'Allow-ICMPv6-Input'
        option src 'wan'
        option proto 'icmp'
        list icmp_type 'echo-request'
        list icmp_type 'echo-reply'
        list icmp_type 'destination-unreachable'
        list icmp_type 'packet-too-big'
        list icmp_type 'time-exceeded'
        list icmp_type 'bad-header'
        list icmp_type 'unknown-header-type'
        list icmp_type 'router-solicitation'
        list icmp_type 'neighbour-solicitation'
        list icmp_type 'router-advertisement'
        list icmp_type 'neighbour-advertisement'
        option limit '1000/sec'
        option family 'ipv6'
        option target 'ACCEPT'

config rule
        option name 'Allow-ICMPv6-Forward'
        option src 'wan'
        option dest '*'
        option proto 'icmp'
        list icmp_type 'echo-request'
        list icmp_type 'echo-reply'
        list icmp_type 'destination-unreachable'
        list icmp_type 'packet-too-big'
        list icmp_type 'time-exceeded'
        list icmp_type 'bad-header'
        list icmp_type 'unknown-header-type'
        option limit '1000/sec'
        option family 'ipv6'
        option target 'ACCEPT'

config rule
        option name 'Allow-IPSec-ESP'
        option src 'wan'
        option dest 'lan'
        option proto 'esp'
        option target 'ACCEPT'

config rule
        option name 'Allow-ISAKMP'
        option src 'wan'
        option dest 'lan'
        option dest_port '500'
        option proto 'udp'
        option target 'ACCEPT'

config rule
        option name 'Support-UDP-Traceroute'
        option src 'wan'
        option dest_port '33434:33689'
        option proto 'udp'
        option family 'ipv4'
        option target 'REJECT'
        option enabled 'false'

config include
        option path '/etc/firewall.user'

config include 'miniupnpd'
        option type 'script'
        option path '/usr/share/miniupnpd/firewall.include'

# This file is interpreted as shell script.
# Put your custom iptables rules here, they will
# be executed with each firewall (re-)start.

# Internal uci firewall chains are flushed and recreated on reload, so
# put custom rules into the root chains e.g. INPUT or FORWARD or into the
# special user chains, e.g. input_wan_rule or postrouting_lan_rule.
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
13: br-lan: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 4000 qdisc noqueue state UP group default qlen 1000
    inet 192.168.177.26/24 brd 192.168.177.255 scope global br-lan
       valid_lft forever preferred_lft forever
default via 192.168.177.1 dev br-lan proto static 
192.168.177.0/24 dev br-lan proto kernel scope link src 192.168.177.26 
local 127.0.0.0/8 dev lo table local proto kernel scope host src 127.0.0.1 
local 127.0.0.1 dev lo table local proto kernel scope host src 127.0.0.1 
broadcast 127.255.255.255 dev lo table local proto kernel scope link src 127.0.0.1 
local 192.168.177.26 dev br-lan table local proto kernel scope host src 192.168.177.26 
broadcast 192.168.177.255 dev br-lan table local proto kernel scope link src 192.168.177.26 
0:      from all lookup local
32766:  from all lookup main
32767:  from all lookup default
-rw-r--r--    1 root     root           123 Nov 11 16:33 /etc/resolv.conf
-rw-r--r--    1 root     root            67 Dec  1 15:08 /tmp/resolv.conf
-rw-r--r--    1 root     root           199 Dec  1 15:08 /tmp/resolv.conf.d/resolv.conf.auto

/tmp/resolv.conf.d:
-rw-r--r--    1 root     root           199 Dec  1 15:08 resolv.conf.auto
==> /etc/resolv.conf <==
search mydomain1.local mydomain2.local
nameserver 192.168.177.26
nameserver 192.168.177.30
nameserver 192.168.177.29

==> /tmp/resolv.conf <==
# This file is generated by the DHCPD service
nameserver 127.0.0.1

==> /tmp/resolv.conf.d <==
head: /tmp/resolv.conf.d: I/O error

==> /tmp/resolv.conf.d/resolv.conf.auto <==
# Interface lan6
nameserver fe80::e2d5:5eff:fe2a:d63c%br-lan
nameserver fe80::2c0:8ff:fe9d:6460%br-lan
nameserver fe80::8293:4dff:fe9b:9ed1%br-lan
search mydomain1.local
search mydomain2.local

here you go :slight_smile:

EDIT to avoid confusion: the openwrt is the NAP, whereby bluez connects the PANU android phone (called "device" in the first post) to the br-lan bridge.
the android phone gets a valid IP, and apparently DNS settings as well, but it doesn't get the default gateway from the DHCP server

So the only dhcp server is dhcpd running on the banana-pi?
There is no dhcpd running on the isp router .177.1 ?
Other wireless or cabled hosts on banana-pi get the proper settings?
I believe there is the pool part of the dhcpd configuration missing.

Actually, no, I have 2 dhcpd servers in a failover config.
I'm posting one of the configs here:

option domain-name "mydomain1.local";
option domain-name-servers neo3.mydomain1.local, openwrt.mydomain1.local, linuxserver.mydomain1.local;

include "/etc/dhcp/mydomain.key";

omapi-port 7911;
omapi-key ddns.mydomain1.local;

default-lease-time 2400;
max-lease-time 3600;
min-lease-time 1200;

# Use this to enble / disable dynamic dns updates globally.
ddns-update-style standard;
ddns-domainname "mydomain1.local";
update-static-leases on;
ignore client-updates;
ddns-dual-stack-mixed-mode on;
ddns-other-guard-is-dynamic on;
ddns-guard-id-must-match off;
update-optimization false;
update-conflict-detection false;
allow booting;
allow bootp;
authoritative;

failover peer "openwrt" {
     primary;
     address neo3.mydomain1.local;
     port 519;
     peer address openwrt.mydomain1.local
     peer port 520;
     max-response-delay 60;
     max-unacked-updates 10;
     split 128;
     mclt 3600;
     load balance max seconds 3;
}

subnet 192.168.177.0 netmask 255.255.255.0 {
  pool {
  range 192.168.177.80 192.168.177.200;
  failover peer "openwrt";
  }
  next-server openwrt.mydomain1.local;
  option subnet-mask 255.255.255.0;
  option domain-name "mydomain1.local";
  option domain-search "mydomain1.local", "mydomain2.local";
  option routers router.mydomain1.local;
#  option broadcast-address 10.5.5.31;
#  default-lease-time 600;
#  max-lease-time 7200;
}

and just to be complete: here's the offer from the DHCP server (captured using tcpdump) when the xiaomi mobile phone connects via bluetooth:

Dynamic Host Configuration Protocol (Offer)
    Message type: Boot Reply (2)
    Hardware type: Ethernet (0x01)
    Hardware address length: 6
    Hops: 0
    Transaction ID: 0x040b5f7c
    Seconds elapsed: 0
    Bootp flags: 0x0000 (Unicast)
    Client IP address: 0.0.0.0
    Your (client) IP address: 192.168.177.152
    Next server IP address: 192.168.177.26
    Relay agent IP address: 0.0.0.0
    Client MAC address: XiaomiCo_92:13:5c (4c:02:20:92:13:5c)
    Client hardware address padding: 00000000000000000000
    Server host name not given
    Boot file name not given
    Magic cookie: DHCP
    Option: (53) DHCP Message Type (Offer)
        Length: 1
        DHCP: Offer (2)
    Option: (54) DHCP Server Identifier (192.168.177.30)
    Option: (51) IP Address Lease Time
        Length: 4
        IP Address Lease Time: (2400s) 40 minutes
    Option: (1) Subnet Mask (255.255.255.0)
    Option: (3) Router
        Length: 4
        Router: 192.168.177.1
    Option: (6) Domain Name Server
        Length: 12
        Domain Name Server: 192.168.177.30
        Domain Name Server: 192.168.177.26
        Domain Name Server: 192.168.177.29
    Option: (15) Domain Name
    Option: (255) End

but there must be a reason why "router" isn't understood here :s

EDIT: to make it even more funny: the ARP from the mobile phone:

Address Resolution Protocol (request)
    Hardware type: Ethernet (1)
    Protocol type: IPv4 (0x0800)
    Hardware size: 6
    Protocol size: 4
    Opcode: request (1)
    Sender MAC address: XiaomiCo_92:13:5c (4c:02:20:92:13:5c)
    Sender IP address: 192.168.177.152
    Target MAC address: 00:00:00_00:00:00 (00:00:00:00:00:00)
    Target IP address: 192.168.177.1

And the reply from the router:

Address Resolution Protocol (reply)
    Hardware type: Ethernet (1)
    Protocol type: IPv4 (0x0800)
    Hardware size: 6
    Protocol size: 4
    Opcode: reply (2)
    Sender MAC address: AVMAudio_0a:7c:7c (3c:a6:2f:0a:7c:7c)
    Sender IP address: 192.168.177.1
    Target MAC address: XiaomiCo_92:13:5c (4c:02:20:92:13:5c)
    Target IP address: 192.168.177.152

With all this, I don't see how we can help you here. The fact that the telephone is not installing the default route, even though it gets the dhcp packets, makes it out of the scope of the forum.

You're missing the point:
This happens on a tablet, a phone and a windows pc.
When using bluetooth thethering on an android phone, they work as expected.
Why?

Do a tcpdump on the router or a wireshark on the windows pc and verify that it gets the correct DHCP offer with router. If option 3 is there there is not much I can say.

Any idea who could?
If windows, android 12 (lineageos) and android 13 (samsung one ui 5) all show this behaviour, chances are real there must be an extra dhcp option in the offer

EDIT : maybe it expects some router advertisement via mdns ... Is that possible?

Router advertisement is not performed by mdns.
Since you have a windows pc with the same problem, run a wireshark capture and filter for dhcp packets. Then share the capture here to verify if it is sent properly.

... which partially solved the problem:
I saw the discoverable timeout was > 0, when I turned that to 0, it magically started working ...
... on windows PCs only
For android, it still doesn't work.... time to do some nasty hacking:
I have one of the android devices rooted, so I performed a tcpdump, and copied it to my device. I saw:

Frame 117: 91 bytes on wire (728 bits), 91 bytes captured (728 bits)
    Encapsulation type: Linux cooked-mode capture v1 (25)
    Arrival Time: Dec  2, 2022 13:50:57.777443000 CET
    [Time shift for this packet: 0.000000000 seconds]
    Epoch Time: 1669985457.777443000 seconds
    [Time delta from previous captured frame: 0.000030000 seconds]
    [Time delta from previous displayed frame: 0.000030000 seconds]
    [Time since reference or first frame: 8.561034000 seconds]
    Frame Number: 117
    Frame Length: 91 bytes (728 bits)
    Capture Length: 91 bytes (728 bits)
    [Frame is marked: False]
    [Frame is ignored: False]
    [Protocols in frame: sll:ethertype:ip:udp:dns]
    [Coloring Rule Name: UDP]
    [Coloring Rule String: udp]

and this query (and almost all others) are never answered!
there are 3 DNS servers on the network, but NONE answer those requests
when I perform a DNS lookup on my pc using dig it works flawlessly. Not sure whether this leads to the solution, but it may be the reason why routing tables are not installed when connectivity check fails

EDIT: "tcpdump -i bnep0 udp" on the openwrt AP shows the dns servers are actually answering, but somehow the answer never reaches the android target udp stack (according to tcpdump). Any suggestion here? why does "tcpdump -i bnep0 udp" show an answer on the openwrt AP and "tcpdump -i bt-pan" on the rooted phone no answer?

EDIT2 further investigation shows many packets are dropped on the line: both on nap and panu packets are sent which are on visible at the pcap at the other side. Any suggestion how I should reduce the package loss?

to show some statistics:
on openwrt side, only 11% of a pcap of 240 packets is from the android phone's mac (so openwrt receives it)
on android side, only 8% of a pcap of 180 packets is to the android phone's mac (so android receives it)
any idea how to reduce the package loss?