rXg Knowledge Base

Wireless Printer -- Losing IP Due to Session Timeout and Account Limits

April 08, 2026

Overview

Covers diagnosing and resolving wireless printer (or other headless device) connectivity loss where the device connects successfully but loses its routable IP after a period of time. The most common causes are session timeout without auto-re-login, max_sessions or max_devices set to 1 on a multi-device account, and idle timeout sweeping low-traffic devices. Applies to any rXg deployment with headless devices (printers, IoT sensors, smart displays) on accounts shared with other devices.

Problem

  • Wireless printer connected to WiFi but has no routable IP / no internet
  • Printer worked for approximately one hour before losing connectivity
  • Rebooting the laptop on the same account did not resolve the issue
  • The account has two wireless devices: a laptop and a printer
  • Printer MAC OUI may map to embedded Wi-Fi module suppliers (e.g., Murata Manufacturing 7c:b8:da)

Root Cause

When a LoginSession is destroyed (for any reason), the rXg executes this callback chain: 1. debit_account -- debits usage from account 2. destroy_vlan_tag_assignments -- removes VLAN assignment (if expire_vtas_at_logout is true) 3. flush_pf_states -- creates a DeadIp record, flushing all PF firewall state for the IP 4. radius_accounting_stop -- sends RADIUS Accounting-Stop 5. destroy_upnp_port_forwards -- removes any UPnP forwards

The expire_sessions daemon (Perl, runs every ~1 second) destroys sessions for: - Session-Timeout -- expires_at has passed (configured via Landing Portal session_minutes or RADIUS realm) - Idle-Timeout -- device traffic fell below threshold for idle_minutes - Sessions-Exceeded -- account's max_sessions limit was breached - MAC-Mismatch -- another device acquired the IP - Quota-Exceeded -- usage limits exhausted

The Account model defaults max_sessions and max_devices to 1 when unlimited_sessions/unlimited_devices is false (account.rb:3055). A multi-device account MUST have both set to >= 2.

Printers cannot interact with a captive portal. Once a session expires, the printer stays offline unless: - Account has automatic_login: true, AND - Landing Portal has background_automatic_login: "mac"

Without both, the expire_sessions daemon cannot re-create the session.

Ranked hypotheses for "worked for an hour then stopped":

Root Cause Hypotheses
âââ #1 Session timeout (~60 min) + no auto-re-login [HIGH]
â   âââ "Worked for an hour" matches 60-min session_minutes
âââ #2 max_sessions = 1 (default) [HIGH]
â   âââ Laptop's session destroys printer's session
âââ #3 Idle timeout [MEDIUM]
â   âââ Printers idle most of the time
âââ #4 max_devices = 1 [MEDIUM]
â   âââ Adding laptop triggers Device.cleanup_account_devices
âââ #5 Usage expiration [LOW]
    âââ no_usage_expiration: false and usage window passed

Solution

1. Pull the destroy_reason from Login Session Log

This single command confirms the exact root cause:

/usr/local/bin/bundle exec rails runner "
  LoginSessionLog.where(mac: '<printer-mac>')
    .order(login_at: :desc).limit(10)
    .each { |l| puts \"#{l.login_at} -> #{l.logout_at} | reason: #{l.destroy_reason} | IP: #{l.ip}\" }
" --environment production

2. Audit the Account Configuration

/usr/local/bin/bundle exec rails runner "
  a = Account.find_by(login: '<account-login>')
  puts 'State: ' + a.state.to_s
  puts 'max_sessions: ' + a.max_sessions.to_s + ' (unlimited: ' + a.unlimited_sessions.to_s + ')'
  puts 'max_devices: ' + a.max_devices.to_s + ' (unlimited: ' + a.unlimited_devices.to_s + ')'
  puts 'automatic_login: ' + a.automatic_login.to_s
  puts 'no_usage_expiration: ' + a.no_usage_expiration.to_s
  puts 'Devices: ' + a.devices.pluck(:mac, :name).map { |m,n| \"#{m} (#{n})\" }.join(', ')
  puts 'Active sessions: ' + a.login_sessions.count.to_s
" --environment production

3. Check the Landing Portal and RADIUS Realm

/usr/local/bin/bundle exec rails runner "
  a = Account.find_by(login: '<account-login>')
  lp = a.policy&.landing_portal
  if lp
    puts 'Portal: ' + lp.name
    puts '  session_minutes: ' + lp.session_minutes.to_s + ' (unlimited: ' + lp.unlimited_session_minutes.to_s + ')'
    puts '  idle_minutes: ' + lp.idle_minutes.to_s + ' (unlimited: ' + lp.unlimited_idle_minutes.to_s + ')'
    puts '  bg_auto_login: ' + lp.background_automatic_login.to_s
  end
  a.policy&.radius_servers&.each { |rs|
    puts 'Realm: ' + rs.name + ' session_min=' + rs.session_minutes.to_s + ' expire_vtas=' + rs.expire_vtas_at_logout.to_s
  }
" --environment production

4. Apply Fix Based on destroy_reason

destroy_reason Fix
Session-Timeout Enable automatic_login on account + set background_automatic_login: mac on Landing Portal. Optionally increase session_minutes.
Sessions-Exceeded or Account-IP-Changed Increase max_sessions to >= 2 on the account.
Idle-Timeout Enable unlimited_idle_minutes on Landing Portal, or increase idle_minutes significantly.
No session log exists Check max_devices -- Device record may have been destroyed. Re-add printer MAC and increase max_devices.

The most likely fix is a combination of: 1. Set max_sessions >= 2 on the account 2. Set max_devices >= 2 on the account 3. Enable automatic_login on the account 4. Set background_automatic_login: mac on the Landing Portal

All changes are immediate -- no service restart or downtime required.

5. Verify Recovery

  1. Confirm both devices show active Login Sessions in Identities > Sessions
  2. Confirm the printer MAC has a NAT assignment (routable IP)
  3. Have the user print a test page from the laptop
  4. Wait 2+ hours and re-check -- confirm the printer's session persists or auto-renews

CLI Verification

Check login session logs for the printer: bash /usr/local/bin/bundle exec rails runner " LoginSessionLog.where(mac: '<printer-mac>') .order(login_at: :desc).limit(10) .each { |l| puts \"#{l.login_at} -> #{l.logout_at} | reason: #{l.destroy_reason} | IP: #{l.ip}\" } " --environment production

Check account limits and auto-login settings: bash /usr/local/bin/bundle exec rails runner " a = Account.find_by(login: '<account-login>') puts 'max_sessions: ' + a.max_sessions.to_s puts 'max_devices: ' + a.max_devices.to_s puts 'automatic_login: ' + a.automatic_login.to_s puts 'Active sessions: ' + a.login_sessions.count.to_s " --environment production

Code references: - account.rb:2801 -- enforce_max_sessions - account.rb:910 -- can_be_online? - device.rb:272 -- cleanup_account_devices - login_session.rb:239 -- session destroy callbacks - rxgd/bin/expire_sessions -- session expiry daemon


Cookies help us deliver our services. By using our services, you agree to our use of cookies.