File indexing completed on 2024-12-01 03:45:00

0001 /*
0002     SPDX-FileCopyrightText: 2008, 2011 Will Stephenson <wstephenson@kde.org>
0003     SPDX-FileCopyrightText: 2011-2013 Lamarque V. Souza <lamarque@kde.org>
0004     SPDX-FileCopyrightText: 2013 Daniel Nicoletti <dantti12@gmail.com>
0005     SPDX-FileCopyrightText: 2013 Jan Grulich <jgrulich@redhat.com>
0006 
0007     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0008 */
0009 
0010 #ifndef NETWORKMANAGERQT_DEVICE_H
0011 #define NETWORKMANAGERQT_DEVICE_H
0012 
0013 #include <QObject>
0014 #include <QSharedPointer>
0015 
0016 #include "activeconnection.h"
0017 #include "devicestatistics.h"
0018 #include "dhcp4config.h"
0019 #include "dhcp6config.h"
0020 #include "generictypes.h"
0021 #include "ipconfig.h"
0022 #include <networkmanagerqt/networkmanagerqt_export.h>
0023 
0024 namespace NetworkManager
0025 {
0026 class DevicePrivate;
0027 class DeviceStateReason;
0028 class DeviceStateReasonPrivate;
0029 
0030 /**
0031  * This class represents a common device interface
0032  */
0033 class NETWORKMANAGERQT_EXPORT Device : public QObject
0034 {
0035     Q_OBJECT
0036 
0037     Q_PROPERTY(QString uni READ uni)
0038     Q_PROPERTY(QString interfaceName READ interfaceName)
0039     Q_PROPERTY(QString ipInterfaceName READ ipInterfaceName)
0040     Q_PROPERTY(QString driver READ driver)
0041     Q_PROPERTY(QString driverVersion READ driverVersion)
0042     Q_PROPERTY(QString firmwareVersion READ firmwareVersion)
0043     Q_PROPERTY(QVariant genericCapabilities READ capabilitiesV)
0044     Q_PROPERTY(QHostAddress ipV4Address READ ipV4Address)
0045     Q_PROPERTY(bool managed READ managed)
0046     Q_PROPERTY(uint mtu READ mtu)
0047     Q_PROPERTY(Interfaceflags InterfaceFlags READ interfaceFlags)
0048     Q_PROPERTY(bool nmPluginMissing READ nmPluginMissing)
0049     Q_PROPERTY(MeteredStatus metered READ metered)
0050     Q_PROPERTY(QString udi READ udi)
0051     Q_PROPERTY(bool firmwareMissing READ firmwareMissing)
0052     Q_PROPERTY(bool autoconnect READ autoconnect WRITE setAutoconnect)
0053     Q_PROPERTY(DeviceStateReason stateReason READ stateReason)
0054     Q_PROPERTY(State state READ state)
0055     Q_PROPERTY(NetworkManager::DeviceStatistics::Ptr deviceStatistics READ deviceStatistics)
0056 
0057 public:
0058     typedef QSharedPointer<Device> Ptr;
0059     typedef QList<Ptr> List;
0060     /**
0061      * Device connection states describe the possible states of a
0062      * network connection from the user's point of view.  For
0063      * simplicity, states from several different layers are present -
0064      * this is a high level view
0065      */
0066     enum State {
0067         UnknownState = 0, /**< The device is in an unknown state */
0068         Unmanaged = 10, /**< The device is recognized but not managed by NetworkManager */
0069         Unavailable = 20, /**< The device cannot be used (carrier off, rfkill, etc) */
0070         Disconnected = 30, /**< The device is not connected */
0071         Preparing = 40, /**< The device is preparing to connect */
0072         ConfiguringHardware = 50, /**< The device is being configured */
0073         NeedAuth = 60, /**< The device is awaiting secrets necessary to continue connection */
0074         ConfiguringIp = 70, /**< The IP settings of the device are being requested and configured */
0075         CheckingIp = 80, /**< The device's IP connectivity ability is being determined */
0076         WaitingForSecondaries = 90, /**< The device is waiting for secondary connections to be activated */
0077         Activated = 100, /**< The device is active */
0078         Deactivating = 110, /**< The device's network connection is being torn down */
0079         Failed = 120, /**< The device is in a failure state following an attempt to activate it */
0080     };
0081     Q_ENUM(State)
0082 
0083     /**
0084      * Enums describing the reason for a connection state change
0085      * @note StateChangeReasons NewActivation, ParentChanged, ParentManagedChanged are available in runtime NM >= 1.0.4
0086      */
0087     enum StateChangeReason {
0088         UnknownReason = 0,
0089         NoReason = 1,
0090         NowManagedReason = 2,
0091         NowUnmanagedReason = 3,
0092         ConfigFailedReason = 4,
0093         ConfigUnavailableReason = 5,
0094         ConfigExpiredReason = 6,
0095         NoSecretsReason = 7,
0096         AuthSupplicantDisconnectReason = 8,
0097         AuthSupplicantConfigFailedReason = 9,
0098         AuthSupplicantFailedReason = 10,
0099         AuthSupplicantTimeoutReason = 11,
0100         PppStartFailedReason = 12,
0101         PppDisconnectReason = 13,
0102         PppFailedReason = 14,
0103         DhcpStartFailedReason = 15,
0104         DhcpErrorReason = 16,
0105         DhcpFailedReason = 17,
0106         SharedStartFailedReason = 18,
0107         SharedFailedReason = 19,
0108         AutoIpStartFailedReason = 20,
0109         AutoIpErrorReason = 21,
0110         AutoIpFailedReason = 22,
0111         ModemBusyReason = 23,
0112         ModemNoDialToneReason = 24,
0113         ModemNoCarrierReason = 25,
0114         ModemDialTimeoutReason = 26,
0115         ModemDialFailedReason = 27,
0116         ModemInitFailedReason = 28,
0117         GsmApnSelectFailedReason = 29,
0118         GsmNotSearchingReason = 30,
0119         GsmRegistrationDeniedReason = 31,
0120         GsmRegistrationTimeoutReason = 32,
0121         GsmRegistrationFailedReason = 33,
0122         GsmPinCheckFailedReason = 34,
0123         FirmwareMissingReason = 35,
0124         DeviceRemovedReason = 36,
0125         SleepingReason = 37,
0126         ConnectionRemovedReason = 38,
0127         UserRequestedReason = 39,
0128         CarrierReason = 40,
0129         ConnectionAssumedReason = 41,
0130         SupplicantAvailableReason = 42,
0131         ModemNotFoundReason = 43,
0132         BluetoothFailedReason = 44,
0133         GsmSimNotInserted = 45,
0134         GsmSimPinRequired = 46,
0135         GsmSimPukRequired = 47,
0136         GsmSimWrong = 48,
0137         InfiniBandMode = 49,
0138         DependencyFailed = 50,
0139         Br2684Failed = 51,
0140         ModemManagerUnavailable = 52,
0141         SsidNotFound = 53,
0142         SecondaryConnectionFailed = 54,
0143         DcbFcoeFailed = 55,
0144         TeamdControlFailed = 56,
0145         ModemFailed = 57,
0146         ModemAvailable = 58,
0147         SimPinIncorrect = 59,
0148         NewActivation = 60,
0149         ParentChanged = 61,
0150         ParentManagedChanged = 62,
0151         Reserved = 65536,
0152     };
0153     Q_ENUM(StateChangeReason)
0154 
0155     enum MeteredStatus {
0156         UnknownStatus = 0, /**< The device metered status is unknown. */
0157         Yes = 1, /**< The device is metered and the value was statically set. */
0158         No = 2, /**< The device is not metered and the value was statically set. */
0159         GuessYes = 3, /**< The device is metered and the value was guessed. */
0160         GuessNo = 4, /**< The device is not metered and the value was guessed. */
0161     };
0162     Q_ENUM(MeteredStatus)
0163 
0164     /**
0165      * Possible device capabilities
0166      */
0167     enum Capability {
0168         IsManageable = 0x1, /**< denotes that the device can be controlled by this API */
0169         SupportsCarrierDetect = 0x2, /**< the device informs us when it is plugged in to the medium */
0170     };
0171     Q_ENUM(Capability)
0172     Q_DECLARE_FLAGS(Capabilities, Capability)
0173     Q_FLAG(Capabilities)
0174 
0175     /**
0176      * Possible device interfaceflags
0177      */
0178     enum Interfaceflag {
0179         None = NM_DEVICE_INTERFACE_FLAG_NONE,                   /**< no flags set */
0180         Up = NM_DEVICE_INTERFACE_FLAG_UP,                       /**< Corresponds to kernel IFF_UP */
0181         LowerUp = NM_DEVICE_INTERFACE_FLAG_LOWER_UP,            /**< Corresponds to kernel IFF_LOWER_UP */
0182         Carrier = NM_DEVICE_INTERFACE_FLAG_CARRIER              /**< the interface has carrier */
0183     };
0184     Q_ENUM(Interfaceflag)
0185     Q_DECLARE_FLAGS(Interfaceflags, Interfaceflag)
0186     Q_FLAG(Interfaceflags)
0187 
0188     /**
0189      * Device type
0190      */
0191     enum Type {
0192         UnknownType = NM_DEVICE_TYPE_UNKNOWN, /**< Unknown device type */
0193         Ethernet = NM_DEVICE_TYPE_ETHERNET, /**< Ieee8023 wired ethernet */
0194         Wifi = NM_DEVICE_TYPE_WIFI, /**< the Ieee80211 family of wireless networks */
0195         Unused1 = NM_DEVICE_TYPE_UNUSED1, /**< Currently unused */
0196         Unused2 = NM_DEVICE_TYPE_UNUSED2, /**< Currently unused */
0197         Bluetooth = NM_DEVICE_TYPE_BT, /**< network bluetooth device (usually a cell phone) */
0198         OlpcMesh = NM_DEVICE_TYPE_OLPC_MESH, /**< OLPC Mesh networking device */
0199         Wimax = NM_DEVICE_TYPE_WIMAX, /**< WiMax WWAN technology */
0200         Modem = NM_DEVICE_TYPE_MODEM, /**< POTS, GSM, CDMA or LTE modems */
0201         InfiniBand = NM_DEVICE_TYPE_INFINIBAND, /**< Infiniband network device */
0202         Bond = NM_DEVICE_TYPE_BOND, /**< Bond virtual device */
0203         Vlan = NM_DEVICE_TYPE_VLAN, /**< Vlan virtual device */
0204         Adsl = NM_DEVICE_TYPE_ADSL, /**< ADSL modem device */
0205         Bridge = NM_DEVICE_TYPE_BRIDGE, /**< Bridge virtual device */
0206         Generic = NM_DEVICE_TYPE_GENERIC, /**< Generic device @since 1.0.0 */
0207         Team = NM_DEVICE_TYPE_TEAM, /**< Team master device @since 1.0.0 */
0208         Gre, /**< Gre virtual device @since 1.2.0, @deprecated use IpTunnel instead*/
0209         MacVlan, /**< MacVlan virtual device @since 1.2.0 */
0210         Tun, /**< Tun virtual device @since 1.2.0 */
0211         Veth, /**< Veth virtual device @since 1.2.0 */
0212         IpTunnel, /**< IP Tunneling Device @since 1.2.0 */
0213         VxLan, /**< Vxlan Device @since 1.2.0 */
0214         MacSec, /**< MacSec Device @since 1.6.0 */
0215         Dummy, /**< Dummy Device @since 1.8.0 */
0216         Ppp, /**< Ppp Device @since 1.10 */
0217         OvsInterface, /**< OvsInterface Device @since 1.10 */
0218         OvsPort, /**< OvsPort Device @since 1.10 */
0219         OvsBridge, /**< OvsBridge Device @since 1.10 */
0220         Wpan, /**< Wpan Device @since 1.14 */
0221         Lowpan, /**< Lowpan Device @since 1.14 */
0222         WireGuard, /**< WireGuard Device @since 1.14 */
0223         WifiP2P, /**< WifiP2P Device @since 1.16 */
0224     };
0225     Q_ENUM(Type)
0226     Q_DECLARE_FLAGS(Types, Type)
0227     Q_FLAG(Types)
0228 
0229     /**
0230      * Creates a new device object.
0231      *
0232      * @param path UNI of the device
0233      */
0234     explicit Device(const QString &path, QObject *parent = nullptr);
0235     /**
0236      * Destroys a device object.
0237      */
0238     ~Device() override;
0239     /**
0240      * Retrieves the interface type.  This is a virtual function that will return the
0241      * proper type of all sub-classes.
0242      *
0243      * @returns the NetworkManager::Device::Type that corresponds to this device.
0244      */
0245     virtual Type type() const;
0246     /**
0247      * Retrieves the Unique Network Identifier (UNI) of the device.
0248      * This identifier is unique for each network and network interface in the system.
0249      *
0250      * @returns the Unique Network Identifier of the current device
0251      */
0252     QString uni() const;
0253     /**
0254      * The current active connection for this device
0255      *
0256      * @returns A valid ActiveConnection object or NULL if no active connection was found
0257      */
0258     NetworkManager::ActiveConnection::Ptr activeConnection() const;
0259     /**
0260      * Returns available connections for this device
0261      *
0262      * @returns List of availables connection
0263      */
0264     Connection::List availableConnections();
0265     /**
0266      * The system name for the network device
0267      */
0268     QString interfaceName() const;
0269     /**
0270      * The name of the device's data interface when available. This property
0271      * may not refer to the actual data interface until the device has
0272      * successfully established a data connection, indicated by the device's
0273      * state() becoming ACTIVATED.
0274      */
0275     QString ipInterfaceName() const;
0276     /**
0277      * Handle for the system driver controlling this network interface
0278      */
0279     QString driver() const;
0280     /**
0281      * The driver version.
0282      */
0283     QString driverVersion() const;
0284     /**
0285      * The firmware version.
0286      */
0287     QString firmwareVersion() const;
0288     /**
0289      * Reapplies connection settings on the interface.
0290      */
0291     QDBusPendingReply<> reapplyConnection(const NMVariantMapMap &connection, qulonglong version_id, uint flags);
0292     /**
0293      * Disconnects a device and prevents the device from automatically
0294      * activating further connections without user intervention.
0295      */
0296     QDBusPendingReply<> disconnectInterface();
0297     /**
0298      * Deletes a software device from NetworkManager and removes the interface from the system.
0299      * The method returns an error when called for a hardware device.
0300      *
0301      * @since 5.8.0
0302      *
0303      */
0304     QDBusPendingReply<> deleteInterface();
0305     /**
0306      * returns the current IPv4 address without the prefix
0307      * \sa ipV4Config()
0308      * \sa ipV6Config()
0309      * @deprecated
0310      */
0311     QHostAddress ipV4Address() const;
0312     /**
0313      * Get the current IPv4 configuration of this device.
0314      * Only valid when device is Activated.
0315      */
0316     IpConfig ipV4Config() const;
0317     /**
0318      * Get the current IPv6 configuration of this device.
0319      * Only valid when device is Activated.
0320      */
0321     IpConfig ipV6Config() const;
0322 
0323     /**
0324      * Get the DHCP options returned by the DHCP server
0325      * or a null pointer if the device is not Activated or does not
0326      * use DHCP configuration.
0327      */
0328     Dhcp4Config::Ptr dhcp4Config() const;
0329 
0330     /**
0331      * Get the DHCP options returned by the DHCP server
0332      * or a null pointer if the device is not Activated or does not
0333      * use DHCP configuration.
0334      */
0335     Dhcp6Config::Ptr dhcp6Config() const;
0336 
0337     /**
0338      * Retrieves the activation status of this network interface.
0339      *
0340      * @return true if this network interface is active, false otherwise
0341      */
0342     bool isActive() const;
0343 
0344     /**
0345      * Retrieves the device is valid.
0346      *
0347      * @return true if this device interface is valid, false otherwise
0348      */
0349     bool isValid() const;
0350 
0351     /**
0352      * Retrieves the current state of the device.
0353      * This is a high level view of the device. It is user oriented, so
0354      * actually it provides state coming from different layers.
0355      *
0356      * @return the current connection state
0357      * @see Device::State
0358      */
0359     State state() const;
0360     /**
0361      * Retrieves the maximum speed as reported by the device.
0362      * Note that this is only a design related piece of information, and that
0363      * the device might not reach this maximum.
0364      *
0365      * @return the device's maximum speed
0366      */
0367     int designSpeed() const;
0368     /**
0369      * Retrieves the capabilities supported by this device.
0370      *
0371      * @return the capabilities of the device
0372      */
0373     Capabilities capabilities() const;
0374     QVariant capabilitiesV() const;
0375     /**
0376      * Is the device currently being managed by NetworkManager?
0377      */
0378     bool managed() const;
0379     /**
0380       * The up or down flag for the device
0381       */
0382     Interfaceflags interfaceFlags() const;
0383     /**
0384      * Is the firmware needed by the device missing?
0385      */
0386     bool firmwareMissing() const;
0387     /**
0388      * If the device is allowed to autoconnect.
0389      */
0390     bool autoconnect() const;
0391     /**
0392      * The current state and reason for changing to that state.
0393      */
0394     DeviceStateReason stateReason() const;
0395     /**
0396      * Retrieves the Unique Device Identifier (UDI) of the device.
0397      * This identifier is unique for each device in the system.
0398      */
0399     QString udi() const;
0400 
0401     /**
0402      * @return If non-empty, an (opaque) indicator of the physical network
0403      * port associated with the device. This can be used to recognize
0404      * when two seemingly-separate hardware devices are actually just
0405      * different virtual interfaces to the same physical port.
0406      *
0407      * @since 0.9.9.0
0408      */
0409     QString physicalPortId() const;
0410     /**
0411      * The device MTU (maximum transmission unit)
0412      * @since 0.9.9.0
0413      *
0414      */
0415     uint mtu() const;
0416 
0417     /**
0418      * @return If TRUE, indicates the NetworkManager plugin for the device is likely
0419      * missing or misconfigured.
0420      * @since 5.14.0
0421      */
0422     bool nmPluginMissing() const;
0423 
0424     /**
0425      * @return Whether the amount of traffic flowing through the device is
0426      * subject to limitations, for example set by service providers.
0427      * @since 5.14.0
0428      */
0429     MeteredStatus metered() const;
0430 
0431     /**
0432      * If true, indicates the device is allowed to autoconnect.
0433      * If false, manual intervention is required before the device
0434      * will automatically connect to a known network, such as activating
0435      * a connection using the device, or setting this property to @p true.
0436      */
0437     void setAutoconnect(bool autoconnect);
0438 
0439     /**
0440      * Returns Device Statistics interface
0441      */
0442     DeviceStatistics::Ptr deviceStatistics() const;
0443 
0444     /**
0445      * Retrieves a specialized interface to interact with the device corresponding
0446      * to a given device interface.
0447      *
0448      * @returns a pointer to the device interface if it exists, @p 0 otherwise
0449      */
0450     template<class DevIface>
0451     DevIface *as()
0452     {
0453         return qobject_cast<DevIface *>(this);
0454     }
0455 
0456     /**
0457      * Retrieves a specialized interface to interact with the device corresponding
0458      * to a given device interface.
0459      *
0460      * @returns a pointer to the device interface if it exists, 0 otherwise
0461      */
0462     template<class DevIface>
0463     const DevIface *as() const
0464     {
0465         return qobject_cast<const DevIface *>(this);
0466     }
0467 
0468 Q_SIGNALS:
0469     /**
0470      * This signal is emitted when the device's link status changed.
0471      *
0472      * @param newstate the new state of the connection
0473      * @param oldstate the previous state of the connection
0474      * @param reason the reason for the state change, if any.  ReasonNone where the backend
0475      * provides no reason.
0476      * @see Device::State
0477      * @see Device::StateChangeReason
0478      */
0479     void stateChanged(NetworkManager::Device::State newstate, NetworkManager::Device::State oldstate, NetworkManager::Device::StateChangeReason reason);
0480 
0481     /**
0482      * Emitted when the autoconnect of this network has changed.
0483      */
0484     void activeConnectionChanged();
0485 
0486     /**
0487      * Emitted when the autoconnect of this network has changed.
0488      */
0489     void autoconnectChanged();
0490 
0491     /**
0492      * Emitted when the list of avaiable connections of this network has changed.
0493      */
0494     void availableConnectionChanged();
0495 
0496     /**
0497      * Emitted when a new connection is available
0498      */
0499     void availableConnectionAppeared(const QString &connection);
0500 
0501     /**
0502      * Emitted when the connection is no longer available
0503      */
0504     void availableConnectionDisappeared(const QString &connection);
0505 
0506     /**
0507      * Emitted when the capabilities of this network has changed.
0508      */
0509     void capabilitiesChanged();
0510 
0511     /**
0512      * Emitted when the DHCP configuration for IPv4 of this network has changed.
0513      */
0514     void dhcp4ConfigChanged();
0515 
0516     /**
0517      * Emitted when the DHCP configuration for IPv6 of this network has changed.
0518      */
0519     void dhcp6ConfigChanged();
0520 
0521     /**
0522      * Emitted when the driver of this network has changed.
0523      */
0524     void driverChanged();
0525 
0526     /**
0527      * Emitted when the driver version of this network has changed.
0528      */
0529     void driverVersionChanged();
0530 
0531     /**
0532      * Emitted when the firmware missing state of this network has changed.
0533      */
0534     void firmwareMissingChanged();
0535 
0536     /**
0537      * Emitted when the firmware version of this network has changed.
0538      */
0539     void firmwareVersionChanged();
0540 
0541     /**
0542      * Emitted when the interface name of this network has changed.
0543      */
0544     void interfaceNameChanged();
0545 
0546     /**
0547      * Emitted when the IPv4 address of this network has changed.
0548      */
0549     void ipV4AddressChanged();
0550 
0551     /**
0552      * Emitted when the IPv4 configuration of this network has changed.
0553      */
0554     void ipV4ConfigChanged();
0555 
0556     /**
0557      * Emitted when the IPv6 configuration of this network has changed.
0558      */
0559     void ipV6ConfigChanged();
0560 
0561     /**
0562      * Emitted when the ip interface name of this network has changed.
0563      */
0564     void ipInterfaceChanged();
0565 
0566     /**
0567      * Emitted when the managed state of this network has changed.
0568      */
0569     void managedChanged();
0570 
0571     /**
0572       * Emitted when the up or down state of the device
0573       * @since 1.22
0574       * @note will always return NM_DEVICE_INTERFACE_FLAG_NONE when runtime NM < 1.22
0575       */
0576     void interfaceFlagsChanged();
0577 
0578     /**
0579      * Emitted when the physical port ID changes.
0580      * @see physicalPortId()
0581      * @since 0.9.9.0
0582      */
0583     void physicalPortIdChanged();
0584 
0585     /**
0586      * Emitted when the maximum transmission unit has changed
0587      * @since 0.9.9.0
0588      */
0589     void mtuChanged();
0590 
0591     /**
0592      * Emitted when NmPluginMissing property has changed
0593      * @since 5.14.0
0594      * @see nmPluginMissing
0595      */
0596     void nmPluginMissingChanged(bool nmPluginMissing);
0597 
0598     /**
0599      * Emitted when metered property has changed
0600      * @since 5.14.0
0601      * @see metered
0602      */
0603     void meteredChanged(MeteredStatus metered);
0604 
0605     /**
0606      * Emitted when the connection state of this network has changed.
0607      */
0608     void connectionStateChanged();
0609 
0610     /**
0611      * Emitted when the state reason of this network has changed.
0612      */
0613     void stateReasonChanged();
0614 
0615     /**
0616      * Emitted when the Unique Device Identifier of this device has changed.
0617      */
0618     void udiChanged();
0619 
0620 protected:
0621     NETWORKMANAGERQT_NO_EXPORT Device(DevicePrivate &dd, QObject *parent);
0622 
0623     DevicePrivate *const d_ptr;
0624 
0625 private:
0626     Q_DECLARE_PRIVATE(Device)
0627 };
0628 
0629 Q_DECLARE_OPERATORS_FOR_FLAGS(Device::Capabilities)
0630 Q_DECLARE_OPERATORS_FOR_FLAGS(Device::Types)
0631 Q_DECLARE_OPERATORS_FOR_FLAGS(Device::Interfaceflags)
0632 
0633 class NETWORKMANAGERQT_EXPORT DeviceStateReason
0634 {
0635 public:
0636     DeviceStateReason(Device::State state, Device::StateChangeReason reason);
0637     DeviceStateReason(const DeviceStateReason &);
0638     ~DeviceStateReason();
0639     Device::State state() const;
0640     Device::StateChangeReason reason() const;
0641     DeviceStateReason &operator=(const DeviceStateReason &);
0642 
0643 private:
0644     Q_DECLARE_PRIVATE(DeviceStateReason)
0645 
0646     DeviceStateReasonPrivate *const d_ptr;
0647 };
0648 
0649 }
0650 
0651 #endif