From 38441bb561924736ff983c4750fb4a7dfdd6db3c Mon Sep 17 00:00:00 2001 From: Daniel Abbatt Date: Wed, 9 Sep 2026 13:34:32 +0100 Subject: [PATCH] fix: map seven nested response objects the API returns The same sweep of unmapped-member reports that found the scalars in 1.70.135 also found seven nested objects with no model property. Callers who set JsonMissingMemberHandling.ThrowOnError were getting a failed deserialization rather than an ignored field: TwoPointFourGhzSettings.Dot11ax and FiveGhzSettings.Dot11ax SwitchPort.PerpetualPoe and .FastPoe NetworkApplianceSsidRadiusServer.Radsec Admin.OtherOrganizationAccounts VpnBgp.Ipv6 and .TunnelDownTermination Ten new classes back them, named after their owners in line with the existing SwitchPortDot3az / ConfigTemplateSwitchProfilePortDot3az split. Dot11ax on both bands and both PoE objects are in the v1.74.0 OpenAPI spec on request bodies as well as responses, so Dot11ax is read/write and the PoE objects are read/update, matching their endpoints. The spec also marks axEnabled deprecated in favour of dot11ax.enabled on both bands, which the XML docs now say. Radsec, OtherOrganizationAccounts, Ipv6 and TunnelDownTermination appear nowhere in the spec and are mapped read-only from the observed responses. MissingMemberNestedFieldTests covers all seven, deserializing the observed payloads with MissingMemberHandling.Error; the CI step added in 1.70.135 runs them. --- CHANGELOG.md | 27 +++ .../Data/MissingMemberNestedFieldTests.cs | 224 ++++++++++++++++++ Meraki.Api/Data/Admin.cs | 7 + .../Data/AdminOtherOrganizationAccounts.cs | 15 ++ .../AdminOtherOrganizationAccountsLockout.cs | 15 ++ Meraki.Api/Data/FiveGhzSettings.cs | 8 + Meraki.Api/Data/FiveGhzSettingsDot11ax.cs | 15 ++ .../Data/NetworkApplianceSsidRadiusServer.cs | 7 + .../NetworkApplianceSsidRadiusServerRadsec.cs | 22 ++ Meraki.Api/Data/SwitchPort.cs | 14 ++ Meraki.Api/Data/SwitchPortFastPoe.cs | 15 ++ Meraki.Api/Data/SwitchPortPerpetualPoe.cs | 15 ++ Meraki.Api/Data/TwoPointFourGhzSettings.cs | 8 + .../Data/TwoPointFourGhzSettingsDot11ax.cs | 15 ++ Meraki.Api/Data/VpnBgp.cs | 14 ++ Meraki.Api/Data/VpnBgpIpv6.cs | 15 ++ Meraki.Api/Data/VpnBgpIpv6SinglePeering.cs | 15 ++ .../Data/VpnBgpTunnelDownTermination.cs | 15 ++ 18 files changed, 466 insertions(+) create mode 100644 Meraki.Api.Test/Data/MissingMemberNestedFieldTests.cs create mode 100644 Meraki.Api/Data/AdminOtherOrganizationAccounts.cs create mode 100644 Meraki.Api/Data/AdminOtherOrganizationAccountsLockout.cs create mode 100644 Meraki.Api/Data/FiveGhzSettingsDot11ax.cs create mode 100644 Meraki.Api/Data/NetworkApplianceSsidRadiusServerRadsec.cs create mode 100644 Meraki.Api/Data/SwitchPortFastPoe.cs create mode 100644 Meraki.Api/Data/SwitchPortPerpetualPoe.cs create mode 100644 Meraki.Api/Data/TwoPointFourGhzSettingsDot11ax.cs create mode 100644 Meraki.Api/Data/VpnBgpIpv6.cs create mode 100644 Meraki.Api/Data/VpnBgpIpv6SinglePeering.cs create mode 100644 Meraki.Api/Data/VpnBgpTunnelDownTermination.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index ead78a4da..d1a2d90a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,32 @@ # Changelog +## 1.70.136 + +- **Seven more response fields the Dashboard API returns are now mapped**, each of them a nested + object that needed a new model class. As with the scalars in 1.70.135, callers who set + `JsonMissingMemberHandling.ThrowOnError` were getting a failed deserialization rather than an + ignored field: + `TwoPointFourGhzSettings.Dot11ax` and `FiveGhzSettings.Dot11ax`, `SwitchPort.PerpetualPoe` and + `.FastPoe`, `NetworkApplianceSsidRadiusServer.Radsec`, `Admin.OtherOrganizationAccounts`, and + `VpnBgp.Ipv6` and `.TunnelDownTermination`. + + Ten new classes back them: `TwoPointFourGhzSettingsDot11ax`, `FiveGhzSettingsDot11ax`, + `SwitchPortPerpetualPoe`, `SwitchPortFastPoe`, `NetworkApplianceSsidRadiusServerRadsec`, + `AdminOtherOrganizationAccounts` and `AdminOtherOrganizationAccountsLockout`, `VpnBgpIpv6`, + `VpnBgpIpv6SinglePeering` and `VpnBgpTunnelDownTermination`. + + `Dot11ax` on both bands and both PoE objects are in the v1.74.0 OpenAPI spec on request bodies as + well as responses, so they are writable: `Dot11ax` is read/write and the two PoE objects are + read/update, matching their endpoints. The spec also marks `axEnabled` deprecated in favour of + `dot11ax.enabled` on both bands, which the XML docs now say. `Radsec`, + `OtherOrganizationAccounts`, `Ipv6` and `TunnelDownTermination` appear nowhere in the spec and are + mapped read-only from the observed responses. + +- **These mappings have credential-free regression tests** in + `Meraki.Api.Test.Data.MissingMemberNestedFieldTests`, deserializing the observed payloads (with + identifying values replaced) using `MissingMemberHandling.Error`. The CI step added in 1.70.135 + runs them. + ## 1.70.135 - **Seven more response fields the Dashboard API returns are now mapped**, all of them simple diff --git a/Meraki.Api.Test/Data/MissingMemberNestedFieldTests.cs b/Meraki.Api.Test/Data/MissingMemberNestedFieldTests.cs new file mode 100644 index 000000000..96670c50e --- /dev/null +++ b/Meraki.Api.Test/Data/MissingMemberNestedFieldTests.cs @@ -0,0 +1,224 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace Meraki.Api.Test.Data; + +/// +/// Regression tests for the nested response objects that live organizations were observed to return +/// with no matching model property. Each payload keeps the shape of a real Dashboard API response +/// with identifying values replaced, and each test deserializes it with the same settings +/// uses, so an unmapped field fails the test +/// rather than being silently dropped. +/// +public class MissingMemberNestedFieldTests +{ + private static readonly JsonSerializerSettings ThrowOnMissingMember = new() + { + NullValueHandling = NullValueHandling.Ignore, + MissingMemberHandling = MissingMemberHandling.Error, + Converters = [new StringEnumConverter()] + }; + + private static T Deserialize(string json) + { + var result = JsonConvert.DeserializeObject(json, ThrowOnMissingMember); + _ = result.Should().NotBeNull(); + return result!; + } + + // twoFourGhzSettings from GET /networks/{networkId}/wireless/rfProfiles + [Fact] + public void Deserialize_TwoPointFourGhzSettings_MapsDot11ax() + { + const string json = """ + { + "maxPower": 30, + "minPower": 5, + "minBitrate": 11, + "rxsop": null, + "validAutoChannels": [ 1, 6, 11 ], + "axEnabled": true, + "dot11ax": { + "enabled": true + } + } + """; + + var settings = Deserialize(json); + + _ = settings.Dot11ax.Should().NotBeNull(); + _ = settings.Dot11ax!.Enabled.Should().BeTrue(); + } + + // fiveGhzSettings from GET /networks/{networkId}/wireless/rfProfiles + [Fact] + public void Deserialize_FiveGhzSettings_MapsDot11ax() + { + const string json = """ + { + "maxPower": 30, + "minPower": 8, + "minBitrate": 12, + "rxsop": null, + "validAutoChannels": [ 36, 40, 44, 48, 149, 153, 157, 161 ], + "channelWidth": "auto", + "dot11ax": { + "enabled": true + } + } + """; + + var settings = Deserialize(json); + + _ = settings.Dot11ax.Should().NotBeNull(); + _ = settings.Dot11ax!.Enabled.Should().BeTrue(); + } + + // GET /devices/{serial}/switch/ports + [Fact] + public void Deserialize_SwitchPort_MapsPerpetualPoeAndFastPoe() + { + const string json = """ + { + "portId": "1", + "name": "Access Port", + "tags": [], + "enabled": true, + "poeEnabled": true, + "perpetualPoe": { + "enabled": false + }, + "fastPoe": { + "enabled": false + }, + "type": "trunk", + "vlan": 1, + "voiceVlan": null, + "allowedVlans": "all", + "activeVlans": "1-4094", + "isolationEnabled": false, + "rstpEnabled": true, + "stpGuard": "disabled", + "linkNegotiation": "Auto negotiate", + "portScheduleId": null, + "schedule": null, + "udld": "Alert only", + "linkNegotiationCapabilities": [ + "Auto negotiate", + "1 Gigabit full duplex (auto)" + ], + "accessPolicyType": "Open", + "daiTrusted": false, + "profile": { + "enabled": false, + "id": "", + "iname": null + }, + "module": { + "model": null + }, + "mirror": { + "mode": "Not mirroring traffic" + } + } + """; + + var port = Deserialize(json); + + _ = port.PerpetualPoe.Should().NotBeNull(); + _ = port.PerpetualPoe!.Enabled.Should().BeFalse(); + _ = port.FastPoe.Should().NotBeNull(); + _ = port.FastPoe!.Enabled.Should().BeFalse(); + } + + // radiusServers from GET /networks/{networkId}/appliance/ssids + [Fact] + public void Deserialize_NetworkApplianceSsidRadiusServer_MapsRadsec() + { + const string json = """ + { + "host": "192.0.2.10", + "port": 2654, + "id": "1234567890123456789", + "openRoamingCertificateId": null, + "caCertificate": null, + "radsec": { + "enabled": false, + "tlsIdleTimeout": 900 + } + } + """; + + var radiusServer = Deserialize(json); + + _ = radiusServer.Radsec.Should().NotBeNull(); + _ = radiusServer.Radsec!.Enabled.Should().BeFalse(); + _ = radiusServer.Radsec.TlsIdleTimeout.Should().Be(900); + } + + // GET /organizations/{organizationId}/admins + [Fact] + public void Deserialize_Admin_MapsOtherOrganizationAccounts() + { + const string json = """ + { + "id": "1234567890123456789", + "name": "Example Administrator", + "email": "admin@example.com", + "authenticationMethod": "Email", + "orgAccess": "full", + "accountStatus": "ok", + "otherOrganizationAccounts": { + "lockout": { + "isLocked": false + } + }, + "twoFactorAuthEnabled": false, + "hasApiKey": true, + "lastActive": "2026-09-04T10:23:23Z", + "networks": [], + "tags": [] + } + """; + + var admin = Deserialize(json); + + _ = admin.OtherOrganizationAccounts.Should().NotBeNull(); + _ = admin.OtherOrganizationAccounts!.Lockout.Should().NotBeNull(); + _ = admin.OtherOrganizationAccounts.Lockout!.IsLocked.Should().BeFalse(); + } + + // GET /networks/{networkId}/appliance/vpn/bgp - the whole observed response, including the + // PriorityRoute scalar mapped alongside these two nested objects. + [Fact] + public void Deserialize_VpnBgp_MapsIpv6AndTunnelDownTermination() + { + const string json = """ + { + "enabled": false, + "ibgpHoldTimer": 240, + "asNumber": 64512, + "routerId": null, + "priorityRoute": "Auto VPN", + "ipv6": { + "singlePeering": { + "enabled": false + } + }, + "tunnelDownTermination": { + "enabled": null + }, + "neighbors": [] + } + """; + + var bgp = Deserialize(json); + + _ = bgp.PriorityRoute.Should().Be("Auto VPN"); + _ = bgp.Ipv6.Should().NotBeNull(); + _ = bgp.Ipv6!.SinglePeering.Should().NotBeNull(); + _ = bgp.Ipv6.SinglePeering!.Enabled.Should().BeFalse(); + _ = bgp.TunnelDownTermination.Should().NotBeNull(); + _ = bgp.TunnelDownTermination!.Enabled.Should().BeNull(); + } +} diff --git a/Meraki.Api/Data/Admin.cs b/Meraki.Api/Data/Admin.cs index 884ec7fca..80848a56b 100644 --- a/Meraki.Api/Data/Admin.cs +++ b/Meraki.Api/Data/Admin.cs @@ -75,4 +75,11 @@ public class Admin : NamedIdentifiedItem [ApiAccess(ApiAccess.ReadCreate)] [DataMember(Name = "camera")] public List? Camera { get; set; } + + /// + /// The administrator's accounts in other organizations - Undocumented, observed in responses only + /// + [ApiAccess(ApiAccess.Read)] + [DataMember(Name = "otherOrganizationAccounts")] + public AdminOtherOrganizationAccounts? OtherOrganizationAccounts { get; set; } } diff --git a/Meraki.Api/Data/AdminOtherOrganizationAccounts.cs b/Meraki.Api/Data/AdminOtherOrganizationAccounts.cs new file mode 100644 index 000000000..c21e3f87b --- /dev/null +++ b/Meraki.Api/Data/AdminOtherOrganizationAccounts.cs @@ -0,0 +1,15 @@ +namespace Meraki.Api.Data; + +/// +/// The administrator's accounts in other organizations - Undocumented, observed in responses only +/// +[DataContract] +public class AdminOtherOrganizationAccounts +{ + /// + /// The lockout state of the administrator's accounts in other organizations + /// + [ApiAccess(ApiAccess.Read)] + [DataMember(Name = "lockout")] + public AdminOtherOrganizationAccountsLockout? Lockout { get; set; } +} diff --git a/Meraki.Api/Data/AdminOtherOrganizationAccountsLockout.cs b/Meraki.Api/Data/AdminOtherOrganizationAccountsLockout.cs new file mode 100644 index 000000000..b7878adee --- /dev/null +++ b/Meraki.Api/Data/AdminOtherOrganizationAccountsLockout.cs @@ -0,0 +1,15 @@ +namespace Meraki.Api.Data; + +/// +/// The lockout state of an administrator's accounts in other organizations +/// +[DataContract] +public class AdminOtherOrganizationAccountsLockout +{ + /// + /// Whether the administrator is locked out of their accounts in other organizations + /// + [ApiAccess(ApiAccess.Read)] + [DataMember(Name = "isLocked")] + public bool? IsLocked { get; set; } +} diff --git a/Meraki.Api/Data/FiveGhzSettings.cs b/Meraki.Api/Data/FiveGhzSettings.cs index 95966ee2c..9175d6353 100644 --- a/Meraki.Api/Data/FiveGhzSettings.cs +++ b/Meraki.Api/Data/FiveGhzSettings.cs @@ -57,8 +57,16 @@ public class FiveGhzSettings /// /// Determines whether 802.11ax is enabled. Undocumented property. + /// Deprecated by the API in favour of . /// [ApiAccess(ApiAccess.ReadWrite)] [DataMember(Name = "axEnabled")] public bool? AxEnabled { get; set; } + + /// + /// IEEE 802.11ax (Wi-Fi 6) settings. + /// + [ApiAccess(ApiAccess.ReadWrite)] + [DataMember(Name = "dot11ax")] + public FiveGhzSettingsDot11ax? Dot11ax { get; set; } } diff --git a/Meraki.Api/Data/FiveGhzSettingsDot11ax.cs b/Meraki.Api/Data/FiveGhzSettingsDot11ax.cs new file mode 100644 index 000000000..74a0ae030 --- /dev/null +++ b/Meraki.Api/Data/FiveGhzSettingsDot11ax.cs @@ -0,0 +1,15 @@ +namespace Meraki.Api.Data; + +/// +/// IEEE 802.11ax (Wi-Fi 6) settings for the 5Ghz band +/// +[DataContract] +public class FiveGhzSettingsDot11ax +{ + /// + /// Determines whether IEEE 802.11ax (Wi-Fi 6) on the 5 GHz band is enabled. Can be either true or false. If false, we highly recommend disabling band steering. If omitted, the existing 5 GHz IEEE 802.11ax setting is preserved. + /// + [ApiAccess(ApiAccess.ReadWrite)] + [DataMember(Name = "enabled")] + public bool? Enabled { get; set; } +} diff --git a/Meraki.Api/Data/NetworkApplianceSsidRadiusServer.cs b/Meraki.Api/Data/NetworkApplianceSsidRadiusServer.cs index 397ae22a3..1a68569fa 100644 --- a/Meraki.Api/Data/NetworkApplianceSsidRadiusServer.cs +++ b/Meraki.Api/Data/NetworkApplianceSsidRadiusServer.cs @@ -47,4 +47,11 @@ public class NetworkApplianceSsidRadiusServer [ApiAccess(ApiAccess.ReadWrite)] [DataMember(Name = "secret")] public string? Secret { get; set; } + + /// + /// RADSEC settings for the RADIUS server - Undocumented, observed in responses only + /// + [ApiAccess(ApiAccess.Read)] + [DataMember(Name = "radsec")] + public NetworkApplianceSsidRadiusServerRadsec? Radsec { get; set; } } diff --git a/Meraki.Api/Data/NetworkApplianceSsidRadiusServerRadsec.cs b/Meraki.Api/Data/NetworkApplianceSsidRadiusServerRadsec.cs new file mode 100644 index 000000000..d4aed84f8 --- /dev/null +++ b/Meraki.Api/Data/NetworkApplianceSsidRadiusServerRadsec.cs @@ -0,0 +1,22 @@ +namespace Meraki.Api.Data; + +/// +/// RADSEC settings for an appliance SSID RADIUS server - Undocumented, observed in responses only +/// +[DataContract] +public class NetworkApplianceSsidRadiusServerRadsec +{ + /// + /// Whether RADSEC is enabled for the RADIUS server + /// + [ApiAccess(ApiAccess.Read)] + [DataMember(Name = "enabled")] + public bool? Enabled { get; set; } + + /// + /// The interval (in seconds) that determines how long a TLS session can remain idle for a RADSec server before it is automatically terminated + /// + [ApiAccess(ApiAccess.Read)] + [DataMember(Name = "tlsIdleTimeout")] + public int? TlsIdleTimeout { get; set; } +} diff --git a/Meraki.Api/Data/SwitchPort.cs b/Meraki.Api/Data/SwitchPort.cs index d6d4529e0..8846993fd 100644 --- a/Meraki.Api/Data/SwitchPort.cs +++ b/Meraki.Api/Data/SwitchPort.cs @@ -42,6 +42,20 @@ public class SwitchPort : NamedItem [DataMember(Name = "poeEnabled")] public bool PoeEnabled { get; set; } + /// + /// Perpetual PoE settings for the switch port. + /// + [ApiAccess(ApiAccess.ReadUpdate)] + [DataMember(Name = "perpetualPoe")] + public SwitchPortPerpetualPoe? PerpetualPoe { get; set; } + + /// + /// Fast PoE settings for the switch port. + /// + [ApiAccess(ApiAccess.ReadUpdate)] + [DataMember(Name = "fastPoe")] + public SwitchPortFastPoe? FastPoe { get; set; } + /// /// The type of the switch port ('trunk' or 'access') /// diff --git a/Meraki.Api/Data/SwitchPortFastPoe.cs b/Meraki.Api/Data/SwitchPortFastPoe.cs new file mode 100644 index 000000000..d82c058b3 --- /dev/null +++ b/Meraki.Api/Data/SwitchPortFastPoe.cs @@ -0,0 +1,15 @@ +namespace Meraki.Api.Data; + +/// +/// Fast PoE settings for the switch port +/// +[DataContract] +public class SwitchPortFastPoe +{ + /// + /// Whether Fast PoE is enabled. Fast PoE requires Perpetual PoE to be enabled. This field is returned for all physical switch ports, but can only be enabled on ports that support PoE HA. + /// + [ApiAccess(ApiAccess.ReadUpdate)] + [DataMember(Name = "enabled")] + public bool? Enabled { get; set; } +} diff --git a/Meraki.Api/Data/SwitchPortPerpetualPoe.cs b/Meraki.Api/Data/SwitchPortPerpetualPoe.cs new file mode 100644 index 000000000..cd59e8b0e --- /dev/null +++ b/Meraki.Api/Data/SwitchPortPerpetualPoe.cs @@ -0,0 +1,15 @@ +namespace Meraki.Api.Data; + +/// +/// Perpetual PoE settings for the switch port +/// +[DataContract] +public class SwitchPortPerpetualPoe +{ + /// + /// Whether Perpetual PoE is enabled. This field is returned for all physical switch ports, but can only be enabled on ports that support PoE HA. + /// + [ApiAccess(ApiAccess.ReadUpdate)] + [DataMember(Name = "enabled")] + public bool? Enabled { get; set; } +} diff --git a/Meraki.Api/Data/TwoPointFourGhzSettings.cs b/Meraki.Api/Data/TwoPointFourGhzSettings.cs index e044a9008..c806f6562 100644 --- a/Meraki.Api/Data/TwoPointFourGhzSettings.cs +++ b/Meraki.Api/Data/TwoPointFourGhzSettings.cs @@ -36,11 +36,19 @@ public class TwoPointFourGhzSettings /// /// Determines whether ax radio on 2.4Ghz band is on or off. Can be either true or false. If false, we highly recommend disabling band steering. Defaults to true. + /// Deprecated by the API in favour of . /// [ApiAccess(ApiAccess.ReadWrite)] [DataMember(Name = "axEnabled")] public bool? AxEnabled { get; set; } + /// + /// IEEE 802.11ax (Wi-Fi 6) settings. + /// + [ApiAccess(ApiAccess.ReadWrite)] + [DataMember(Name = "dot11ax")] + public TwoPointFourGhzSettingsDot11ax? Dot11ax { get; set; } + /// /// The RX-SOP level controls the sensitivity of the radio. It is strongly recommended to use RX-SOP only after consulting a wireless expert. RX-SOP can be configured in the range of -65 to -95 (dBm). A value of null will reset this to the default. /// diff --git a/Meraki.Api/Data/TwoPointFourGhzSettingsDot11ax.cs b/Meraki.Api/Data/TwoPointFourGhzSettingsDot11ax.cs new file mode 100644 index 000000000..0cf0395ab --- /dev/null +++ b/Meraki.Api/Data/TwoPointFourGhzSettingsDot11ax.cs @@ -0,0 +1,15 @@ +namespace Meraki.Api.Data; + +/// +/// IEEE 802.11ax (Wi-Fi 6) settings for the 2.4Ghz band +/// +[DataContract] +public class TwoPointFourGhzSettingsDot11ax +{ + /// + /// Determines whether IEEE 802.11ax (Wi-Fi 6) on the 2.4 GHz band is enabled. Can be either true or false. If false, we highly recommend disabling band steering. If omitted, the existing 2.4 GHz IEEE 802.11ax setting is preserved. + /// + [ApiAccess(ApiAccess.ReadWrite)] + [DataMember(Name = "enabled")] + public bool? Enabled { get; set; } +} diff --git a/Meraki.Api/Data/VpnBgp.cs b/Meraki.Api/Data/VpnBgp.cs index ae6a68f86..100dba521 100644 --- a/Meraki.Api/Data/VpnBgp.cs +++ b/Meraki.Api/Data/VpnBgp.cs @@ -41,6 +41,20 @@ public class VpnBgp [DataMember(Name = "priorityRoute")] public string? PriorityRoute { get; set; } + /// + /// IPv6 BGP settings. Undocumented property, observed in responses only. + /// + [ApiAccess(ApiAccess.Read)] + [DataMember(Name = "ipv6")] + public VpnBgpIpv6? Ipv6 { get; set; } + + /// + /// BGP tunnel down termination settings. Undocumented property, observed in responses only. + /// + [ApiAccess(ApiAccess.Read)] + [DataMember(Name = "tunnelDownTermination")] + public VpnBgpTunnelDownTermination? TunnelDownTermination { get; set; } + /// /// List of BGP neighbors. This list replaces the existing set of neighbors. When absent, this field is not updated. /// diff --git a/Meraki.Api/Data/VpnBgpIpv6.cs b/Meraki.Api/Data/VpnBgpIpv6.cs new file mode 100644 index 000000000..af7f80c0f --- /dev/null +++ b/Meraki.Api/Data/VpnBgpIpv6.cs @@ -0,0 +1,15 @@ +namespace Meraki.Api.Data; + +/// +/// IPv6 BGP settings - Undocumented, observed in responses only +/// +[DataContract] +public class VpnBgpIpv6 +{ + /// + /// Single peering settings for IPv6 BGP + /// + [ApiAccess(ApiAccess.Read)] + [DataMember(Name = "singlePeering")] + public VpnBgpIpv6SinglePeering? SinglePeering { get; set; } +} diff --git a/Meraki.Api/Data/VpnBgpIpv6SinglePeering.cs b/Meraki.Api/Data/VpnBgpIpv6SinglePeering.cs new file mode 100644 index 000000000..bf4af1bb0 --- /dev/null +++ b/Meraki.Api/Data/VpnBgpIpv6SinglePeering.cs @@ -0,0 +1,15 @@ +namespace Meraki.Api.Data; + +/// +/// Single peering settings for IPv6 BGP +/// +[DataContract] +public class VpnBgpIpv6SinglePeering +{ + /// + /// Whether a single IPv6 BGP peering session is used + /// + [ApiAccess(ApiAccess.Read)] + [DataMember(Name = "enabled")] + public bool? Enabled { get; set; } +} diff --git a/Meraki.Api/Data/VpnBgpTunnelDownTermination.cs b/Meraki.Api/Data/VpnBgpTunnelDownTermination.cs new file mode 100644 index 000000000..102a2e14e --- /dev/null +++ b/Meraki.Api/Data/VpnBgpTunnelDownTermination.cs @@ -0,0 +1,15 @@ +namespace Meraki.Api.Data; + +/// +/// BGP tunnel down termination settings - Undocumented, observed in responses only +/// +[DataContract] +public class VpnBgpTunnelDownTermination +{ + /// + /// Whether BGP sessions are terminated when the tunnel goes down + /// + [ApiAccess(ApiAccess.Read)] + [DataMember(Name = "enabled")] + public bool? Enabled { get; set; } +}