-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add WLAN Integration #32530
base: main
Are you sure you want to change the base?
Add WLAN Integration #32530
Changes from 45 commits
5cf9df3
cee3dc7
ab922dd
5489368
793c18e
a1c7883
ad2ecb0
53e0b27
5464143
b3f5bcd
14eb513
d51b070
2c1255f
0c80439
2349626
716fa50
c3d520c
cb4dd20
e710c95
fad7499
d9a29d5
8c437d2
4b34493
7d5a8ed
c368719
3f3887c
c07f239
b1e9719
b10fd02
330ddfd
b04671f
6501a7b
d316b8f
0d71bbe
49273ed
90132cd
a906f6a
b6546af
cf71066
008a33d
8713675
9466007
496af02
ca5d1e8
427309c
2bcecb1
c6b6b31
16a8f3f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
// Unless explicitly stated otherwise all files in this repository are licensed | ||
// under the Apache License Version 2.0. | ||
// This product includes software developed at Datadog (https://www.datadoghq.com/). | ||
// Copyright 2016-present Datadog, Inc. | ||
|
||
//nolint:revive // TODO(PLINT) Fix revive linter | ||
package wlan | ||
|
||
import ( | ||
"strings" | ||
"time" | ||
|
||
"github.com/DataDog/datadog-agent/pkg/collector/check" | ||
core "github.com/DataDog/datadog-agent/pkg/collector/corechecks" | ||
"github.com/DataDog/datadog-agent/pkg/util/log" | ||
"github.com/DataDog/datadog-agent/pkg/util/optional" | ||
) | ||
|
||
const ( | ||
CheckName = "wlan" | ||
defaultMinCollectionInterval = 15 | ||
) | ||
|
||
var getWiFiInfo = GetWiFiInfo | ||
|
||
// WiFiInfo contains information about the WiFi connection as defined in wlan_darwin.h | ||
type WiFiInfo struct { | ||
Rssi int | ||
Ssid string | ||
Bssid string | ||
Channel int | ||
Noise int | ||
TransmitRate float64 | ||
HardwareAddress string | ||
// See: https://developer.apple.com/documentation/corewlan/cwphymode?language=objc | ||
ActivePHYMode int | ||
} | ||
|
||
// WLANCheck monitors the status of the WLAN interface | ||
type WLANCheck struct { | ||
core.CheckBase | ||
lastChannelID int | ||
lastBSSID string | ||
lastSSID string | ||
warmedUp bool | ||
} | ||
|
||
func (c *WLANCheck) String() string { | ||
return "wlan" | ||
} | ||
|
||
// Run runs the check | ||
func (c *WLANCheck) Run() error { | ||
sender, err := c.GetSender() | ||
if err != nil { | ||
return err | ||
} | ||
wifiInfo, err := getWiFiInfo() | ||
if err != nil { | ||
log.Error(err) | ||
return err | ||
} | ||
|
||
if wifiInfo.ActivePHYMode == 0 { | ||
log.Warn("No active Wi-Fi interface detected: ActivePHYMode is none.") | ||
return nil | ||
} | ||
|
||
ssid := wifiInfo.Ssid | ||
if ssid == "" { | ||
ssid = "unknown" | ||
} | ||
bssid := wifiInfo.Bssid | ||
if bssid == "" { | ||
bssid = "unknown" | ||
} | ||
hardwareAddress := strings.ToLower(strings.Replace(wifiInfo.HardwareAddress, " ", "_", -1)) | ||
|
||
tags := []string{} | ||
tags = append(tags, "ssid:"+ssid) | ||
tags = append(tags, "bssid:"+bssid) | ||
tags = append(tags, "mac_address:"+hardwareAddress) | ||
|
||
sender.Gauge("wlan.rssi", float64(wifiInfo.Rssi), "", tags) | ||
sender.Gauge("wlan.noise", float64(wifiInfo.Noise), "", tags) | ||
sender.Gauge("wlan.transmit_rate", float64(wifiInfo.TransmitRate), "", tags) | ||
|
||
// channel swap events | ||
if c.warmedUp && c.lastChannelID != wifiInfo.Channel { | ||
sender.Count("wlan.channel_swap_events", 1.0, "", tags) | ||
} else { | ||
sender.Count("wlan.channel_swap_events", 0.0, "", tags) | ||
} | ||
|
||
// roaming events / ssid swap events | ||
if c.warmedUp && c.lastBSSID != "" && c.lastSSID != "" && c.lastBSSID == wifiInfo.Bssid && c.lastSSID != wifiInfo.Ssid { | ||
sender.Count("wlan.roaming_events", 1.0, "", tags) | ||
} else { | ||
sender.Count("wlan.roaming_events", 0.0, "", tags) | ||
} | ||
|
||
// update last values | ||
c.lastChannelID = wifiInfo.Channel | ||
c.lastBSSID = wifiInfo.Bssid | ||
c.lastSSID = wifiInfo.Ssid | ||
c.warmedUp = true | ||
|
||
sender.Commit() | ||
return nil | ||
} | ||
|
||
// Factory creates a new check factory | ||
func Factory() optional.Option[func() check.Check] { | ||
return optional.NewOption(newCheck) | ||
} | ||
|
||
func newCheck() check.Check { | ||
return &WLANCheck{ | ||
CheckBase: core.NewCheckBaseWithInterval(CheckName, time.Duration(defaultMinCollectionInterval)*time.Second), | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
// Unless explicitly stated otherwise all files in this repository are licensed | ||
// under the Apache License Version 2.0. | ||
// This product includes software developed at Datadog (https://www.datadoghq.com/). | ||
// Copyright 2016-present Datadog, Inc. | ||
|
||
//go:build darwin | ||
|
||
//nolint:revive // TODO(PLINT) Fix revive linter | ||
package wlan | ||
|
||
/* | ||
#cgo CFLAGS: -I . | ||
#cgo LDFLAGS: -framework CoreWLAN -framework CoreLocation -framework Foundation | ||
#include "wlan_darwin.h" | ||
*/ | ||
import "C" | ||
import ( | ||
"github.com/DataDog/datadog-agent/pkg/util/log" | ||
) | ||
|
||
func GetWiFiInfo() (WiFiInfo, error) { | ||
C.InitLocationServices() | ||
log.Info("Initialized Location Manager") | ||
|
||
info := C.GetWiFiInformation() | ||
return WiFiInfo{ | ||
Rssi: int(info.rssi), | ||
Ssid: C.GoString(info.ssid), | ||
Bssid: C.GoString(info.bssid), | ||
Channel: int(info.channel), | ||
Noise: int(info.noise), | ||
TransmitRate: float64(info.transmitRate), | ||
HardwareAddress: C.GoString(info.hardwareAddress), | ||
ActivePHYMode: int(info.activePHYMode), | ||
}, nil | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
#ifndef WLAN_DARWIN_H | ||
#define WLAN_DARWIN_H | ||
|
||
typedef struct { | ||
int rssi; | ||
const char *ssid; | ||
const char *bssid; | ||
int channel; | ||
int noise; | ||
double transmitRate; | ||
const char *hardwareAddress; | ||
int activePHYMode; | ||
} WiFiInfo; | ||
|
||
WiFiInfo GetWiFiInformation(); | ||
void InitLocationServices(); | ||
|
||
#endif |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
// Unless explicitly stated otherwise all files in this repository are licensed | ||
// under the Apache License Version 2.0. | ||
// This product includes software developed at Datadog (https://www.datadoghq.com/). | ||
// Copyright 2016-present Datadog, Inc. | ||
|
||
#include <Foundation/Foundation.h> | ||
#include <CoreWLAN/CoreWLAN.h> | ||
#include <CoreLocation/CoreLocation.h> | ||
#include "wlan_darwin.h" | ||
|
||
|
||
@interface LocationManager : NSObject <CLLocationManagerDelegate> | ||
@property (nonatomic, strong) CLLocationManager *locationManager; | ||
@end | ||
|
||
@implementation LocationManager | ||
|
||
- (instancetype)init { | ||
self = [super init]; | ||
if (self) { | ||
[self setupLocationServices]; | ||
} | ||
return self; | ||
} | ||
|
||
- (void)setupLocationServices { | ||
self.locationManager = [[CLLocationManager alloc] init]; | ||
self.locationManager.delegate = self; | ||
|
||
if (@available(macOS 11.0, *)) { | ||
if (self.locationManager.authorizationStatus == kCLAuthorizationStatusNotDetermined) { | ||
[self.locationManager requestWhenInUseAuthorization]; | ||
} | ||
} else { | ||
NSLog(@"Location services not available on this OS version"); | ||
} | ||
} | ||
|
||
#pragma mark - CLLocationManagerDelegate | ||
|
||
- (void)locationManagerDidChangeAuthorization:(CLLocationManager *)manager { | ||
if (@available(macOS 11.0, *)) { | ||
CLAuthorizationStatus status = manager.authorizationStatus; | ||
|
||
switch (status) { | ||
case kCLAuthorizationStatusAuthorizedAlways: | ||
NSLog(@"Location services authorized!"); | ||
[self.locationManager startUpdatingLocation]; | ||
break; | ||
|
||
case kCLAuthorizationStatusDenied: | ||
NSLog(@"Location services denied by user"); | ||
break; | ||
|
||
case kCLAuthorizationStatusRestricted: | ||
NSLog(@"Location services restricted"); | ||
break; | ||
default: | ||
NSLog(@"Location services status undetermined: %d", status); | ||
break; | ||
} | ||
} else { | ||
NSLog(@"Location services not available on this OS version"); | ||
} | ||
} | ||
|
||
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations { | ||
CLLocation *location = [locations lastObject]; | ||
NSLog(@"Location updated: %@", location); | ||
} | ||
|
||
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error { | ||
NSLog(@"Location update failed with error: %@", error.localizedDescription); | ||
} | ||
|
||
@end | ||
|
||
// Wrapper function to start location updates | ||
void InitLocationServices() { | ||
LocationManager *locationManager = [[LocationManager alloc] init]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This gets called every check run, is this allocating a new object every time? Will those be released automatically? |
||
} | ||
|
||
// GetWiFiInformation return wifi data | ||
WiFiInfo GetWiFiInformation() { | ||
CWInterface *wifiInterface = [[CWWiFiClient sharedWiFiClient] interface]; | ||
|
||
WiFiInfo info; | ||
|
||
info.rssi = (int)wifiInterface.rssiValue; | ||
info.ssid = [[wifiInterface ssid] UTF8String]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not very familiar with objective c, is |
||
info.bssid = [[wifiInterface bssid] UTF8String]; | ||
info.channel = (int)wifiInterface.wlanChannel.channelNumber; | ||
info.noise = (int)wifiInterface.noiseMeasurement; | ||
info.transmitRate = wifiInterface.transmitRate; | ||
info.hardwareAddress = [[wifiInterface hardwareAddress] UTF8String]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
info.activePHYMode = (int)wifiInterface.activePHYMode; | ||
|
||
return info; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
// Unless explicitly stated otherwise all files in this repository are licensed | ||
// under the Apache License Version 2.0. | ||
// This product includes software developed at Datadog (https://www.datadoghq.com/). | ||
// Copyright 2016-present Datadog, Inc. | ||
|
||
//go:build !darwin | ||
|
||
//nolint:revive // TODO(PLINT) Fix revive linter | ||
package wlan | ||
|
||
import "fmt" | ||
|
||
func GetWiFiInfo() (WiFiInfo, error) { | ||
return WiFiInfo{}, fmt.Errorf("wifi info only supported on macOS") | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where do these messages end up? Would it make sense to use agent logging facilities instead?