mirror of
				https://github.com/Telecominfraproject/wlan-cloud-rrm.git
				synced 2025-11-04 12:37:47 +00:00 
			
		
		
		
	Compare commits
	
		
			35 Commits
		
	
	
		
			token_refr
			...
			release/v2
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					787ef196d2 | ||
| 
						 | 
					73693c07ef | ||
| 
						 | 
					9e22796758 | ||
| 
						 | 
					f1c488eac8 | ||
| 
						 | 
					066c523df5 | ||
| 
						 | 
					ba8c156e72 | ||
| 
						 | 
					d73eb23920 | ||
| 
						 | 
					ac5a1c8887 | ||
| 
						 | 
					ea3a13e98c | ||
| 
						 | 
					c1511e8e91 | ||
| 
						 | 
					05c36a535f | ||
| 
						 | 
					c94c31cb63 | ||
| 
						 | 
					404934eda9 | ||
| 
						 | 
					80626388c8 | ||
| 
						 | 
					a79359c69d | ||
| 
						 | 
					a638d70fd6 | ||
| 
						 | 
					e3705699b4 | ||
| 
						 | 
					35eddf73cf | ||
| 
						 | 
					f031027684 | ||
| 
						 | 
					a54f9a48be | ||
| 
						 | 
					c22ebeea31 | ||
| 
						 | 
					e1b9052ecc | ||
| 
						 | 
					c635af6c1d | ||
| 
						 | 
					37a904087d | ||
| 
						 | 
					6df81b7fef | ||
| 
						 | 
					8171cc74ae | ||
| 
						 | 
					215d73fee5 | ||
| 
						 | 
					ecbf8fa644 | ||
| 
						 | 
					19928e0286 | ||
| 
						 | 
					da978611d0 | ||
| 
						 | 
					e42eaa747b | ||
| 
						 | 
					264f114be2 | ||
| 
						 | 
					dd2b485b00 | ||
| 
						 | 
					033d93beff | ||
| 
						 | 
					e5d5f7d5c0 | 
							
								
								
									
										4
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							@@ -26,7 +26,7 @@ jobs:
 | 
				
			|||||||
      DOCKER_REGISTRY_USERNAME: ucentral
 | 
					      DOCKER_REGISTRY_USERNAME: ucentral
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
    - name: Checkout actions repo
 | 
					    - name: Checkout actions repo
 | 
				
			||||||
      uses: actions/checkout@v2
 | 
					      uses: actions/checkout@v3
 | 
				
			||||||
      with:
 | 
					      with:
 | 
				
			||||||
        repository: Telecominfraproject/.github
 | 
					        repository: Telecominfraproject/.github
 | 
				
			||||||
        path: github
 | 
					        path: github
 | 
				
			||||||
@@ -57,7 +57,7 @@ jobs:
 | 
				
			|||||||
      - docker
 | 
					      - docker
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
    - name: Checkout actions repo
 | 
					    - name: Checkout actions repo
 | 
				
			||||||
      uses: actions/checkout@v2
 | 
					      uses: actions/checkout@v3
 | 
				
			||||||
      with:
 | 
					      with:
 | 
				
			||||||
        repository: Telecominfraproject/.github
 | 
					        repository: Telecominfraproject/.github
 | 
				
			||||||
        path: github
 | 
					        path: github
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								.github/workflows/deploy-gh-pages.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/deploy-gh-pages.yml
									
									
									
									
										vendored
									
									
								
							@@ -18,7 +18,7 @@ jobs:
 | 
				
			|||||||
          distribution: 'adopt'
 | 
					          distribution: 'adopt'
 | 
				
			||||||
          cache: maven
 | 
					          cache: maven
 | 
				
			||||||
      - name: Build with Maven
 | 
					      - name: Build with Maven
 | 
				
			||||||
        run: mvn javadoc:javadoc
 | 
					        run: mvn javadoc:aggregate
 | 
				
			||||||
      - name: Deploy to GitHub Pages
 | 
					      - name: Deploy to GitHub Pages
 | 
				
			||||||
        uses: peaceiris/actions-gh-pages@v3
 | 
					        uses: peaceiris/actions-gh-pages@v3
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								.github/workflows/enforce-jira-issue-key.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/enforce-jira-issue-key.yml
									
									
									
									
										vendored
									
									
								
							@@ -11,7 +11,7 @@ jobs:
 | 
				
			|||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - name: Checkout actions repo
 | 
					      - name: Checkout actions repo
 | 
				
			||||||
        uses: actions/checkout@v2
 | 
					        uses: actions/checkout@v3
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          repository: Telecominfraproject/.github
 | 
					          repository: Telecominfraproject/.github
 | 
				
			||||||
          path: github
 | 
					          path: github
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							@@ -17,7 +17,7 @@ jobs:
 | 
				
			|||||||
      HELM_REPO_USERNAME: ucentral
 | 
					      HELM_REPO_USERNAME: ucentral
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - name: Checkout uCentral assembly chart repo
 | 
					      - name: Checkout uCentral assembly chart repo
 | 
				
			||||||
        uses: actions/checkout@v2
 | 
					        uses: actions/checkout@v3
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          path: wlan-cloud-rrm
 | 
					          path: wlan-cloud-rrm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										22
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										22
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -1,12 +1,15 @@
 | 
				
			|||||||
/target
 | 
					/target/
 | 
				
			||||||
/*.log*
 | 
					*/target/
 | 
				
			||||||
/device_config.json
 | 
					
 | 
				
			||||||
/settings.json
 | 
					# owrrm specific
 | 
				
			||||||
/topology.json
 | 
					*.log*
 | 
				
			||||||
 | 
					device_config.json
 | 
				
			||||||
 | 
					settings.json
 | 
				
			||||||
 | 
					topology.json
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Eclipse
 | 
					# Eclipse
 | 
				
			||||||
/.settings/
 | 
					.settings/
 | 
				
			||||||
/bin/
 | 
					bin/
 | 
				
			||||||
.metadata
 | 
					.metadata
 | 
				
			||||||
.classpath
 | 
					.classpath
 | 
				
			||||||
.project
 | 
					.project
 | 
				
			||||||
@@ -17,3 +20,8 @@
 | 
				
			|||||||
*.iml
 | 
					*.iml
 | 
				
			||||||
*.iws
 | 
					*.iws
 | 
				
			||||||
*.ipr
 | 
					*.ipr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Miscellaneous files thzt should not be checked in
 | 
				
			||||||
 | 
					temp/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.DS_Store
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										24
									
								
								Dockerfile
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								Dockerfile
									
									
									
									
									
								
							@@ -1,20 +1,22 @@
 | 
				
			|||||||
FROM maven:3-jdk-11 as build
 | 
					FROM maven:3-eclipse-temurin-11 as build
 | 
				
			||||||
WORKDIR /usr/src/java
 | 
					WORKDIR /usr/src/java
 | 
				
			||||||
COPY . .
 | 
					COPY . .
 | 
				
			||||||
RUN mvn clean package -DappendVersionString="$(./scripts/get_build_version.sh)"
 | 
					RUN mvn clean package -pl owrrm -am -DappendVersionString="$(./scripts/get_build_version.sh)"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
FROM adoptopenjdk/openjdk11-openj9:latest
 | 
					FROM ibm-semeru-runtimes:open-11-jre
 | 
				
			||||||
RUN apt-get update && apt-get install -y gettext-base wget
 | 
					RUN apt-get update && apt-get install -y gettext-base
 | 
				
			||||||
RUN wget https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentral-deploy/main/docker-compose/certs/restapi-ca.pem \
 | 
					ADD https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentral-deploy/main/docker-compose/certs/restapi-ca.pem \
 | 
				
			||||||
    -O /usr/local/share/ca-certificates/restapi-ca-selfsigned.pem
 | 
					  /usr/local/share/ca-certificates/restapi-ca-selfsigned.pem
 | 
				
			||||||
RUN mkdir /owrrm-data
 | 
					RUN mkdir /owrrm-data
 | 
				
			||||||
WORKDIR /usr/src/java
 | 
					WORKDIR /usr/src/java
 | 
				
			||||||
COPY docker-entrypoint.sh /
 | 
					COPY docker-entrypoint.sh /
 | 
				
			||||||
COPY --from=build /usr/src/java/target/openwifi-rrm.jar /usr/local/bin/
 | 
					COPY runner.sh /
 | 
				
			||||||
EXPOSE 16789
 | 
					COPY --from=build /usr/src/java/owrrm/target/openwifi-rrm.jar /usr/local/bin/
 | 
				
			||||||
 | 
					EXPOSE 16789 16790
 | 
				
			||||||
ENTRYPOINT ["/docker-entrypoint.sh"]
 | 
					ENTRYPOINT ["/docker-entrypoint.sh"]
 | 
				
			||||||
CMD ["java", "-XX:+IdleTuningGcOnIdle", "-Xtune:virtualized", \
 | 
					ENV JVM_IMPL=openj9
 | 
				
			||||||
     "-jar", "/usr/local/bin/openwifi-rrm.jar", \
 | 
					CMD ["/runner.sh", "java", "/usr/local/bin/openwifi-rrm.jar", \
 | 
				
			||||||
     "run", "--config-env", \
 | 
					    "run", \
 | 
				
			||||||
 | 
					    "--config-env", \
 | 
				
			||||||
    "-t", "/owrrm-data/topology.json", \
 | 
					    "-t", "/owrrm-data/topology.json", \
 | 
				
			||||||
    "-d", "/owrrm-data/device_config.json"]
 | 
					    "-d", "/owrrm-data/device_config.json"]
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										28
									
								
								Dockerfile-hotspot
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								Dockerfile-hotspot
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
				
			|||||||
 | 
					FROM maven:3-eclipse-temurin-11 as build
 | 
				
			||||||
 | 
					WORKDIR /usr/src/java
 | 
				
			||||||
 | 
					COPY . .
 | 
				
			||||||
 | 
					RUN mvn clean package -pl owrrm -am -DappendVersionString="$(./scripts/get_build_version.sh)"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					FROM eclipse-temurin:11-jre-jammy
 | 
				
			||||||
 | 
					RUN apt-get update && apt-get install -y gettext-base
 | 
				
			||||||
 | 
					ADD https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentral-deploy/main/docker-compose/certs/restapi-ca.pem \
 | 
				
			||||||
 | 
					  /usr/local/share/ca-certificates/restapi-ca-selfsigned.pem
 | 
				
			||||||
 | 
					RUN mkdir /owrrm-data
 | 
				
			||||||
 | 
					WORKDIR /usr/src/java
 | 
				
			||||||
 | 
					COPY docker-entrypoint.sh /
 | 
				
			||||||
 | 
					COPY runner.sh /
 | 
				
			||||||
 | 
					COPY --from=build /usr/src/java/owrrm/target/openwifi-rrm.jar /usr/local/bin/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# generate Application CDS
 | 
				
			||||||
 | 
					RUN java -Xshare:off -XX:DumpLoadedClassList=static-cds.lst -jar /usr/local/bin/openwifi-rrm.jar --help  && \
 | 
				
			||||||
 | 
					    java -Xshare:dump -XX:SharedClassListFile=static-cds.lst -XX:SharedArchiveFile=static-cds.jsa -jar /usr/local/bin/openwifi-rrm.jar
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					EXPOSE 16789 16790
 | 
				
			||||||
 | 
					ENTRYPOINT ["/docker-entrypoint.sh"]
 | 
				
			||||||
 | 
					ENV JVM_IMPL=hotspot
 | 
				
			||||||
 | 
					ENV EXTRA_JVM_FLAGS="-XX:SharedArchiveFile=static-cds.jsa -Xshare:auto"
 | 
				
			||||||
 | 
					CMD ["/runner.sh", "java", "/usr/local/bin/openwifi-rrm.jar", \
 | 
				
			||||||
 | 
					    "run", \
 | 
				
			||||||
 | 
					    "--config-env", \
 | 
				
			||||||
 | 
					    "-t", "/owrrm-data/topology.json", \
 | 
				
			||||||
 | 
					    "-d", "/owrrm-data/device_config.json"]
 | 
				
			||||||
							
								
								
									
										43
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										43
									
								
								README.md
									
									
									
									
									
								
							@@ -1,12 +1,10 @@
 | 
				
			|||||||
# OpenWiFi RRM Service
 | 
					# OpenWiFi RRM Service
 | 
				
			||||||
OpenWiFi uCentral-based radio resource management (RRM) service, providing a
 | 
					[See here](owrrm/README.md) for details.
 | 
				
			||||||
cloud-based Wi-Fi RRM layer for APs running the OpenWiFi SDK.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
This service collects data from OpenWiFi APs (e.g. Wi-Fi scans, stats,
 | 
					## Project Structure
 | 
				
			||||||
capabilities) via the uCentral Gateway and Kafka, and integrates with the
 | 
					This is an [Apache Maven] project with the following modules:
 | 
				
			||||||
OpenWiFi Provisioning service to perform optimization across configured
 | 
					* `lib-cloudsdk` - OpenWiFi CloudSDK Java Library
 | 
				
			||||||
"venues". It pushes new device configuration parameters to APs after RRM
 | 
					* `owrrm` - OpenWiFi RRM Service
 | 
				
			||||||
algorithms are run (manually or periodically).
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Requirements
 | 
					## Requirements
 | 
				
			||||||
* **Running:** JRE 11.
 | 
					* **Running:** JRE 11.
 | 
				
			||||||
@@ -16,7 +14,7 @@ algorithms are run (manually or periodically).
 | 
				
			|||||||
```
 | 
					```
 | 
				
			||||||
$ mvn package [-DskipTests]
 | 
					$ mvn package [-DskipTests]
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
This will build a runnable JAR located at `target/openwifi-rrm.jar`.
 | 
					This will build a runnable JAR located at `owrrm/target/openwifi-rrm.jar`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Alternatively, Docker builds can be launched using the provided
 | 
					Alternatively, Docker builds can be launched using the provided
 | 
				
			||||||
[Dockerfile](Dockerfile).
 | 
					[Dockerfile](Dockerfile).
 | 
				
			||||||
@@ -27,34 +25,7 @@ $ mvn test
 | 
				
			|||||||
```
 | 
					```
 | 
				
			||||||
Unit tests are written using [JUnit 5].
 | 
					Unit tests are written using [JUnit 5].
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Usage
 | 
					## Code Style
 | 
				
			||||||
```
 | 
					 | 
				
			||||||
$ java -jar openwifi-rrm.jar [-h]
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
To start the service, use the `run` command while providing configuration via
 | 
					 | 
				
			||||||
either environment variables (`--config-env`) or a static JSON file
 | 
					 | 
				
			||||||
(`--config-file`, default `settings.json`). The following data is *required*:
 | 
					 | 
				
			||||||
* Service configuration
 | 
					 | 
				
			||||||
    * Env: `SERVICECONFIG_PRIVATEENDPOINT`, `SERVICECONFIG_PUBLICENDPOINT`
 | 
					 | 
				
			||||||
    * JSON: `serviceConfig` structure
 | 
					 | 
				
			||||||
* Kafka broker URL
 | 
					 | 
				
			||||||
    * Env: `KAFKACONFIG_BOOTSTRAPSERVER`
 | 
					 | 
				
			||||||
    * JSON: `kafkaConfig` structure
 | 
					 | 
				
			||||||
* MySQL database credentials
 | 
					 | 
				
			||||||
    * Env: `DATABASECONFIG_SERVER`, `DATABASECONFIG_USER`, `DATABASECONFIG_PASSWORD`
 | 
					 | 
				
			||||||
    * JSON: `databaseConfig` structure
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## OpenAPI
 | 
					 | 
				
			||||||
This service provides an OpenAPI HTTP interface on the port specified in the
 | 
					 | 
				
			||||||
service configuration (`moduleConfig.apiServerParams`). An auto-generated
 | 
					 | 
				
			||||||
OpenAPI 3.0 document is hosted at the endpoints `/openapi.{yaml,json}` and is
 | 
					 | 
				
			||||||
written to [openapi.yaml](openapi.yaml) during the Maven "compile" phase.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## For Developers
 | 
					 | 
				
			||||||
See [IMPLEMENTATION.md](IMPLEMENTATION.md) for service architecture details and
 | 
					 | 
				
			||||||
[ALGORITHMS.md](ALGORITHMS.md) for descriptions of the RRM algorithms.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Code is auto-formatted using [Spotless] with a custom Eclipse style config (see
 | 
					Code is auto-formatted using [Spotless] with a custom Eclipse style config (see
 | 
				
			||||||
[spotless/eclipse-java-formatter.xml](spotless/eclipse-java-formatter.xml)).
 | 
					[spotless/eclipse-java-formatter.xml](spotless/eclipse-java-formatter.xml)).
 | 
				
			||||||
This can be applied via Maven (but is *not* enforced at build time):
 | 
					This can be applied via Maven (but is *not* enforced at build time):
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,7 +9,7 @@ fullnameOverride: ""
 | 
				
			|||||||
images:
 | 
					images:
 | 
				
			||||||
  owrrm:
 | 
					  owrrm:
 | 
				
			||||||
    repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owrrm
 | 
					    repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owrrm
 | 
				
			||||||
    tag: main
 | 
					    tag: v2.8.0
 | 
				
			||||||
    pullPolicy: Always
 | 
					    pullPolicy: Always
 | 
				
			||||||
#    regcred:
 | 
					#    regcred:
 | 
				
			||||||
#      registry: tip-tip-wlan-cloud-ucentral.jfrog.io
 | 
					#      registry: tip-tip-wlan-cloud-ucentral.jfrog.io
 | 
				
			||||||
@@ -29,8 +29,8 @@ services:
 | 
				
			|||||||
        targetPort: 16789
 | 
					        targetPort: 16789
 | 
				
			||||||
        protocol: TCP
 | 
					        protocol: TCP
 | 
				
			||||||
      restapiinternal:
 | 
					      restapiinternal:
 | 
				
			||||||
        servicePort: 17007
 | 
					        servicePort: 16790
 | 
				
			||||||
        targetPort: 17007
 | 
					        targetPort: 16790
 | 
				
			||||||
        protocol: TCP
 | 
					        protocol: TCP
 | 
				
			||||||
 | 
					
 | 
				
			||||||
checks:
 | 
					checks:
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										3
									
								
								lib-cloudsdk/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								lib-cloudsdk/README.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					# OpenWiFi CloudSDK Java Library
 | 
				
			||||||
 | 
					A Java library providing clients and models for the OpenWiFi uCentral-based
 | 
				
			||||||
 | 
					CloudSDK.
 | 
				
			||||||
							
								
								
									
										80
									
								
								lib-cloudsdk/pom.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								lib-cloudsdk/pom.xml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,80 @@
 | 
				
			|||||||
 | 
					<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 | 
				
			||||||
 | 
					  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
 | 
				
			||||||
 | 
					  <modelVersion>4.0.0</modelVersion>
 | 
				
			||||||
 | 
					  <artifactId>openwifi-cloudsdk</artifactId>
 | 
				
			||||||
 | 
					  <packaging>jar</packaging>
 | 
				
			||||||
 | 
					  <parent>
 | 
				
			||||||
 | 
					    <groupId>com.facebook</groupId>
 | 
				
			||||||
 | 
					    <artifactId>openwifi-base</artifactId>
 | 
				
			||||||
 | 
					    <version>2.7.0</version>
 | 
				
			||||||
 | 
					  </parent>
 | 
				
			||||||
 | 
					  <properties>
 | 
				
			||||||
 | 
					    <!-- Hack for static files located in root project -->
 | 
				
			||||||
 | 
					    <myproject.root>${project.basedir}/..</myproject.root>
 | 
				
			||||||
 | 
					  </properties>
 | 
				
			||||||
 | 
					  <build>
 | 
				
			||||||
 | 
					    <finalName>openwifi-cloudsdk</finalName>
 | 
				
			||||||
 | 
					    <resources>
 | 
				
			||||||
 | 
					      <resource>
 | 
				
			||||||
 | 
					        <directory>src/main/resources</directory>
 | 
				
			||||||
 | 
					        <includes>
 | 
				
			||||||
 | 
					          <include>**/*</include>
 | 
				
			||||||
 | 
					        </includes>
 | 
				
			||||||
 | 
					      </resource>
 | 
				
			||||||
 | 
					    </resources>
 | 
				
			||||||
 | 
					    <plugins>
 | 
				
			||||||
 | 
					      <plugin>
 | 
				
			||||||
 | 
					        <groupId>org.apache.maven.plugins</groupId>
 | 
				
			||||||
 | 
					        <artifactId>maven-compiler-plugin</artifactId>
 | 
				
			||||||
 | 
					      </plugin>
 | 
				
			||||||
 | 
					      <plugin>
 | 
				
			||||||
 | 
					        <groupId>org.apache.maven.plugins</groupId>
 | 
				
			||||||
 | 
					        <artifactId>maven-surefire-plugin</artifactId>
 | 
				
			||||||
 | 
					      </plugin>
 | 
				
			||||||
 | 
					      <plugin>
 | 
				
			||||||
 | 
					        <groupId>org.apache.maven.plugins</groupId>
 | 
				
			||||||
 | 
					        <artifactId>maven-javadoc-plugin</artifactId>
 | 
				
			||||||
 | 
					      </plugin>
 | 
				
			||||||
 | 
					      <plugin>
 | 
				
			||||||
 | 
					        <groupId>com.diffplug.spotless</groupId>
 | 
				
			||||||
 | 
					        <artifactId>spotless-maven-plugin</artifactId>
 | 
				
			||||||
 | 
					      </plugin>
 | 
				
			||||||
 | 
					    </plugins>
 | 
				
			||||||
 | 
					  </build>
 | 
				
			||||||
 | 
					  <dependencies>
 | 
				
			||||||
 | 
					    <dependency>
 | 
				
			||||||
 | 
					      <groupId>org.slf4j</groupId>
 | 
				
			||||||
 | 
					      <artifactId>slf4j-api</artifactId>
 | 
				
			||||||
 | 
					    </dependency>
 | 
				
			||||||
 | 
					    <dependency>
 | 
				
			||||||
 | 
					      <groupId>org.slf4j</groupId>
 | 
				
			||||||
 | 
					      <artifactId>slf4j-log4j12</artifactId>
 | 
				
			||||||
 | 
					    </dependency>
 | 
				
			||||||
 | 
					    <dependency>
 | 
				
			||||||
 | 
					      <groupId>org.junit.jupiter</groupId>
 | 
				
			||||||
 | 
					      <artifactId>junit-jupiter-api</artifactId>
 | 
				
			||||||
 | 
					      <scope>test</scope>
 | 
				
			||||||
 | 
					    </dependency>
 | 
				
			||||||
 | 
					    <dependency>
 | 
				
			||||||
 | 
					      <groupId>org.junit.jupiter</groupId>
 | 
				
			||||||
 | 
					      <artifactId>junit-jupiter-engine</artifactId>
 | 
				
			||||||
 | 
					      <scope>test</scope>
 | 
				
			||||||
 | 
					    </dependency>
 | 
				
			||||||
 | 
					    <dependency>
 | 
				
			||||||
 | 
					      <groupId>org.json</groupId>
 | 
				
			||||||
 | 
					      <artifactId>json</artifactId>
 | 
				
			||||||
 | 
					    </dependency>
 | 
				
			||||||
 | 
					    <dependency>
 | 
				
			||||||
 | 
					      <groupId>com.google.code.gson</groupId>
 | 
				
			||||||
 | 
					      <artifactId>gson</artifactId>
 | 
				
			||||||
 | 
					    </dependency>
 | 
				
			||||||
 | 
					    <dependency>
 | 
				
			||||||
 | 
					      <groupId>com.konghq</groupId>
 | 
				
			||||||
 | 
					      <artifactId>unirest-java</artifactId>
 | 
				
			||||||
 | 
					    </dependency>
 | 
				
			||||||
 | 
					    <dependency>
 | 
				
			||||||
 | 
					      <groupId>org.apache.kafka</groupId>
 | 
				
			||||||
 | 
					      <artifactId>kafka-clients</artifactId>
 | 
				
			||||||
 | 
					    </dependency>
 | 
				
			||||||
 | 
					  </dependencies>
 | 
				
			||||||
 | 
					</project>
 | 
				
			||||||
@@ -0,0 +1,253 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (c) Meta Platforms, Inc. and affiliates.
 | 
				
			||||||
 | 
					 * All rights reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This source code is licensed under the BSD-style license found in the
 | 
				
			||||||
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package com.facebook.openwifi.cloudsdk;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.ArrayList;
 | 
				
			||||||
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					import java.util.Objects;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.facebook.openwifi.cloudsdk.models.ap.State;
 | 
				
			||||||
 | 
					import com.facebook.openwifi.cloudsdk.models.ap.State.Interface.Counters;
 | 
				
			||||||
 | 
					import com.facebook.openwifi.cloudsdk.models.ap.State.Interface.SSID.Association;
 | 
				
			||||||
 | 
					import com.google.gson.JsonObject;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Aggregation model for State aggregation. Only contains info useful for
 | 
				
			||||||
 | 
					 * analysis.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class AggregatedState {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Radio information with channel, channel_width and tx_power.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public static class RadioConfig {
 | 
				
			||||||
 | 
							public int channel;
 | 
				
			||||||
 | 
							public int channelWidth;
 | 
				
			||||||
 | 
							public int txPower;
 | 
				
			||||||
 | 
							public String phy;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/** Default constructor with no args */
 | 
				
			||||||
 | 
							private RadioConfig() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/** Constructor with args */
 | 
				
			||||||
 | 
							public RadioConfig(JsonObject radio) {
 | 
				
			||||||
 | 
								this.channel = radio.get("channel").getAsInt();
 | 
				
			||||||
 | 
								this.channelWidth = radio.get("channel_width").getAsInt();
 | 
				
			||||||
 | 
								this.txPower = radio.get("tx_power").getAsInt();
 | 
				
			||||||
 | 
								this.phy = radio.get("phy").getAsString();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public RadioConfig(int channel, int channelWidth, int txPower) {
 | 
				
			||||||
 | 
								this.channel = channel;
 | 
				
			||||||
 | 
								this.channelWidth = channelWidth;
 | 
				
			||||||
 | 
								this.txPower = txPower;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							@Override
 | 
				
			||||||
 | 
							public int hashCode() {
 | 
				
			||||||
 | 
								return Objects.hash(channel, channelWidth, txPower);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							@Override
 | 
				
			||||||
 | 
							public boolean equals(Object obj) {
 | 
				
			||||||
 | 
								if (this == obj) {
 | 
				
			||||||
 | 
									return true;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (obj == null) {
 | 
				
			||||||
 | 
									return false;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (getClass() != obj.getClass()) {
 | 
				
			||||||
 | 
									return false;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								RadioConfig other = (RadioConfig) obj;
 | 
				
			||||||
 | 
								return channel == other.channel &&
 | 
				
			||||||
 | 
									channelWidth == other.channelWidth && txPower == other.txPower;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Data model to keep raw data from {@link State.Interface.SSID.Association},
 | 
				
			||||||
 | 
						 * {@link State.Radio} and {@link State.Interface.Counters}.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public static class AssociationInfo {
 | 
				
			||||||
 | 
							/** Rate information with aggregated fields. */
 | 
				
			||||||
 | 
							public static class Rate {
 | 
				
			||||||
 | 
								/**
 | 
				
			||||||
 | 
								 * Aggregated fields bitRate
 | 
				
			||||||
 | 
								 */
 | 
				
			||||||
 | 
								public long bitRate;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/**
 | 
				
			||||||
 | 
								 * Aggregated fields chWidth
 | 
				
			||||||
 | 
								 */
 | 
				
			||||||
 | 
								public int chWidth;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/**
 | 
				
			||||||
 | 
								 * Aggregated fields mcs
 | 
				
			||||||
 | 
								 */
 | 
				
			||||||
 | 
								public int mcs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/** Constructor with no args */
 | 
				
			||||||
 | 
								private Rate() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/** Constructor with args */
 | 
				
			||||||
 | 
								private Rate(long bitRate, int chWidth, int mcs) {
 | 
				
			||||||
 | 
									this.bitRate = bitRate;
 | 
				
			||||||
 | 
									this.chWidth = chWidth;
 | 
				
			||||||
 | 
									this.mcs = mcs;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public long connected;
 | 
				
			||||||
 | 
							public long inactive;
 | 
				
			||||||
 | 
							public int rssi;
 | 
				
			||||||
 | 
							public long rxBytes;
 | 
				
			||||||
 | 
							public long rxPackets;
 | 
				
			||||||
 | 
							public Rate rxRate;
 | 
				
			||||||
 | 
							public long txBytes;
 | 
				
			||||||
 | 
							public long txDuration;
 | 
				
			||||||
 | 
							public long txFailed;
 | 
				
			||||||
 | 
							public long txPackets;
 | 
				
			||||||
 | 
							public Rate txRate;
 | 
				
			||||||
 | 
							public long txRetries;
 | 
				
			||||||
 | 
							public int ackSignal;
 | 
				
			||||||
 | 
							public int ackSignalAvg;
 | 
				
			||||||
 | 
							public long txPacketsCounters;
 | 
				
			||||||
 | 
							public long txErrorsCounters;
 | 
				
			||||||
 | 
							public long txDroppedCounters;
 | 
				
			||||||
 | 
							public long activeMsRadio;
 | 
				
			||||||
 | 
							public long busyMsRadio;
 | 
				
			||||||
 | 
							public long noiseRadio;
 | 
				
			||||||
 | 
							public long receiveMsRadio;
 | 
				
			||||||
 | 
							public long transmitMsRadio;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/** unix time in ms */
 | 
				
			||||||
 | 
							public long timestamp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/** Default Constructor. */
 | 
				
			||||||
 | 
							public AssociationInfo() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/** Constructor with only rssi(for test purpose) */
 | 
				
			||||||
 | 
							public AssociationInfo(int rssi) {
 | 
				
			||||||
 | 
								this.rssi = rssi;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/** Constructor with args */
 | 
				
			||||||
 | 
							public AssociationInfo(
 | 
				
			||||||
 | 
								Association association,
 | 
				
			||||||
 | 
								Counters counters,
 | 
				
			||||||
 | 
								JsonObject radio,
 | 
				
			||||||
 | 
								long timestamp
 | 
				
			||||||
 | 
							) {
 | 
				
			||||||
 | 
								// Association info
 | 
				
			||||||
 | 
								connected = association.connected;
 | 
				
			||||||
 | 
								inactive = association.inactive;
 | 
				
			||||||
 | 
								rssi = association.rssi;
 | 
				
			||||||
 | 
								rxBytes = association.rx_bytes;
 | 
				
			||||||
 | 
								rxPackets = association.rx_packets;
 | 
				
			||||||
 | 
								if (association.rx_rate != null) {
 | 
				
			||||||
 | 
									rxRate = new Rate(
 | 
				
			||||||
 | 
										association.rx_rate.bitrate,
 | 
				
			||||||
 | 
										association.rx_rate.chwidth,
 | 
				
			||||||
 | 
										association.rx_rate.mcs
 | 
				
			||||||
 | 
									);
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									rxRate = new Rate();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								txBytes = association.tx_bytes;
 | 
				
			||||||
 | 
								txPackets = association.tx_packets;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (association.tx_rate != null) {
 | 
				
			||||||
 | 
									txRate = new Rate(
 | 
				
			||||||
 | 
										association.tx_rate.bitrate,
 | 
				
			||||||
 | 
										association.tx_rate.chwidth,
 | 
				
			||||||
 | 
										association.tx_rate.mcs
 | 
				
			||||||
 | 
									);
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									txRate = new Rate();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								txRetries = association.tx_retries;
 | 
				
			||||||
 | 
								ackSignal = association.ack_signal;
 | 
				
			||||||
 | 
								ackSignalAvg = association.ack_signal_avg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								//Counters info
 | 
				
			||||||
 | 
								txPacketsCounters = counters.tx_packets;
 | 
				
			||||||
 | 
								txErrorsCounters = counters.tx_errors;
 | 
				
			||||||
 | 
								txDroppedCounters = counters.tx_dropped;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Radio info
 | 
				
			||||||
 | 
								activeMsRadio = radio.get("active_ms").getAsLong();
 | 
				
			||||||
 | 
								busyMsRadio = radio.get("busy_ms").getAsLong();
 | 
				
			||||||
 | 
								transmitMsRadio = radio.get("transmit_ms").getAsLong();
 | 
				
			||||||
 | 
								receiveMsRadio = radio.get("receive_ms").getAsLong();
 | 
				
			||||||
 | 
								noiseRadio = radio.get("noise").getAsLong();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								this.timestamp = timestamp;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Aggregate AssociationInfo over bssid, station and RadioConfig.
 | 
				
			||||||
 | 
						public String bssid;
 | 
				
			||||||
 | 
						public String station;
 | 
				
			||||||
 | 
						public RadioConfig radioConfig;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Store a list of AssociationInfo of the same link and radio configuration. */
 | 
				
			||||||
 | 
						public List<AssociationInfo> associationInfoList;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Constructor with no args. For test purpose. */
 | 
				
			||||||
 | 
						public AggregatedState() {
 | 
				
			||||||
 | 
							this.associationInfoList = new ArrayList<>();
 | 
				
			||||||
 | 
							this.radioConfig = new RadioConfig();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Construct from Association, Counters, Radio and time stamp */
 | 
				
			||||||
 | 
						public AggregatedState(
 | 
				
			||||||
 | 
							Association association,
 | 
				
			||||||
 | 
							Counters counters,
 | 
				
			||||||
 | 
							JsonObject radio,
 | 
				
			||||||
 | 
							long timestamp
 | 
				
			||||||
 | 
						) {
 | 
				
			||||||
 | 
							this.bssid = association.bssid;
 | 
				
			||||||
 | 
							this.station = association.station;
 | 
				
			||||||
 | 
							this.associationInfoList = new ArrayList<>();
 | 
				
			||||||
 | 
							associationInfoList
 | 
				
			||||||
 | 
								.add(new AssociationInfo(association, counters, radio, timestamp));
 | 
				
			||||||
 | 
							this.radioConfig = new RadioConfig(radio);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Check whether the passed-in AggregatedState and this one match for aggregation.
 | 
				
			||||||
 | 
						 * If the two match in bssid, station and radio. Then they could be aggregated.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * @param state the reference AggregatedState with which to check with.
 | 
				
			||||||
 | 
						 * @return boolean return true if the two matches for aggregation.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public boolean matchesForAggregation(AggregatedState state) {
 | 
				
			||||||
 | 
							return bssid == state.bssid && station == state.station &&
 | 
				
			||||||
 | 
								Objects.equals(radioConfig, state.radioConfig);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Add an AggregatedState to this AggregatedState. Succeed only when the two
 | 
				
			||||||
 | 
						 * match for aggregation.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * @param state input AggregatedState
 | 
				
			||||||
 | 
						 * @return boolean true if the two match in bssid, station, channel,
 | 
				
			||||||
 | 
						 *         channel_width and tx_power
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public boolean add(AggregatedState state) {
 | 
				
			||||||
 | 
							if (matchesForAggregation(state)) {
 | 
				
			||||||
 | 
								associationInfoList.addAll(state.associationInfoList);
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,125 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (c) Meta Platforms, Inc. and affiliates.
 | 
				
			||||||
 | 
					 * All rights reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This source code is licensed under the BSD-style license found in the
 | 
				
			||||||
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package com.facebook.openwifi.cloudsdk;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.google.gson.JsonElement;
 | 
				
			||||||
 | 
					import com.google.gson.JsonObject;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Utility functions for dealing with IEs
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public abstract class IEUtils {
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Try to get a json object as a byte
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * @param contents the JSON object to try to parse
 | 
				
			||||||
 | 
						 * @param fieldName the field name
 | 
				
			||||||
 | 
						 * @return the field as a byte or null
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public static Byte parseOptionalByteField(
 | 
				
			||||||
 | 
							JsonObject contents,
 | 
				
			||||||
 | 
							String fieldName
 | 
				
			||||||
 | 
						) {
 | 
				
			||||||
 | 
							JsonElement element = contents.get(fieldName);
 | 
				
			||||||
 | 
							if (element == null) {
 | 
				
			||||||
 | 
								return null;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return element.getAsByte();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Try to get a json object as a short
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * @param contents the JSON object to try to parse
 | 
				
			||||||
 | 
						 * @param fieldName the field name
 | 
				
			||||||
 | 
						 * @return the field as a short or null
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public static Short parseOptionalShortField(
 | 
				
			||||||
 | 
							JsonObject contents,
 | 
				
			||||||
 | 
							String fieldName
 | 
				
			||||||
 | 
						) {
 | 
				
			||||||
 | 
							JsonElement element = contents.get(fieldName);
 | 
				
			||||||
 | 
							if (element == null) {
 | 
				
			||||||
 | 
								return null;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return element.getAsShort();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Try to get a json object as a int
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * @param contents the JSON object to try to parse
 | 
				
			||||||
 | 
						 * @param fieldName the field name
 | 
				
			||||||
 | 
						 * @return the field as a int or null
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public static Integer parseOptionalIntField(
 | 
				
			||||||
 | 
							JsonObject contents,
 | 
				
			||||||
 | 
							String fieldName
 | 
				
			||||||
 | 
						) {
 | 
				
			||||||
 | 
							JsonElement element = contents.get(fieldName);
 | 
				
			||||||
 | 
							if (element == null) {
 | 
				
			||||||
 | 
								return null;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return element.getAsInt();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Try to get a json object as a int
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * @param contents the JSON object to try to parse
 | 
				
			||||||
 | 
						 * @param fieldName the field name
 | 
				
			||||||
 | 
						 * @return the field as a int (0 if key not present)
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public static Integer parseIntField(
 | 
				
			||||||
 | 
							JsonObject contents,
 | 
				
			||||||
 | 
							String fieldName
 | 
				
			||||||
 | 
						) {
 | 
				
			||||||
 | 
							JsonElement element = contents.get(fieldName);
 | 
				
			||||||
 | 
							if (element == null) {
 | 
				
			||||||
 | 
								return 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return element.getAsInt();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Try to get a json object as a string
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * @param contents the JSON object to try to parse
 | 
				
			||||||
 | 
						 * @param fieldName the field name
 | 
				
			||||||
 | 
						 * @return the field as a string or null
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public static String parseOptionalStringField(
 | 
				
			||||||
 | 
							JsonObject contents,
 | 
				
			||||||
 | 
							String fieldName
 | 
				
			||||||
 | 
						) {
 | 
				
			||||||
 | 
							JsonElement element = contents.get(fieldName);
 | 
				
			||||||
 | 
							if (element == null) {
 | 
				
			||||||
 | 
								return null;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return element.getAsString();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Try to get a json object as a boolean when represented as a number (0, 1)
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * @param contents the JSON object to try to parse
 | 
				
			||||||
 | 
						 * @param fieldName the field name
 | 
				
			||||||
 | 
						 * @return the field as a boolean (false if key not present)
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public static boolean parseBooleanNumberField(
 | 
				
			||||||
 | 
							JsonObject contents,
 | 
				
			||||||
 | 
							String fieldName
 | 
				
			||||||
 | 
						) {
 | 
				
			||||||
 | 
							JsonElement element = contents.get(fieldName);
 | 
				
			||||||
 | 
							if (element == null) {
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return element.getAsInt() > 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,54 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (c) Meta Platforms, Inc. and affiliates.
 | 
				
			||||||
 | 
					 * All rights reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This source code is licensed under the BSD-style license found in the
 | 
				
			||||||
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package com.facebook.openwifi.cloudsdk;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.Objects;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.facebook.openwifi.cloudsdk.ies.Country;
 | 
				
			||||||
 | 
					import com.facebook.openwifi.cloudsdk.ies.LocalPowerConstraint;
 | 
				
			||||||
 | 
					import com.facebook.openwifi.cloudsdk.ies.QbssLoad;
 | 
				
			||||||
 | 
					import com.facebook.openwifi.cloudsdk.ies.RMEnabledCapabilities;
 | 
				
			||||||
 | 
					import com.facebook.openwifi.cloudsdk.ies.TxPwrInfo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Wrapper class containing information elements */
 | 
				
			||||||
 | 
					public final class InformationElements {
 | 
				
			||||||
 | 
						public Country country;
 | 
				
			||||||
 | 
						public QbssLoad qbssLoad;
 | 
				
			||||||
 | 
						public LocalPowerConstraint localPowerConstraint;
 | 
				
			||||||
 | 
						public TxPwrInfo txPwrInfo;
 | 
				
			||||||
 | 
						public RMEnabledCapabilities rmEnabledCapabilities;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Override
 | 
				
			||||||
 | 
						public int hashCode() {
 | 
				
			||||||
 | 
							return Objects.hash(
 | 
				
			||||||
 | 
								country,
 | 
				
			||||||
 | 
								localPowerConstraint,
 | 
				
			||||||
 | 
								qbssLoad,
 | 
				
			||||||
 | 
								rmEnabledCapabilities,
 | 
				
			||||||
 | 
								txPwrInfo
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Override
 | 
				
			||||||
 | 
						public boolean equals(Object obj) {
 | 
				
			||||||
 | 
							if (this == obj)
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
							if (obj == null)
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							if (getClass() != obj.getClass())
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							InformationElements other = (InformationElements) obj;
 | 
				
			||||||
 | 
							return Objects.equals(country, other.country) &&
 | 
				
			||||||
 | 
								Objects.equals(localPowerConstraint, other.localPowerConstraint) &&
 | 
				
			||||||
 | 
								Objects.equals(qbssLoad, other.qbssLoad) &&
 | 
				
			||||||
 | 
								Objects
 | 
				
			||||||
 | 
									.equals(rmEnabledCapabilities, other.rmEnabledCapabilities) &&
 | 
				
			||||||
 | 
								Objects.equals(txPwrInfo, other.txPwrInfo);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (c) Meta Platforms, Inc. and affiliates.
 | 
				
			||||||
 | 
					 * All rights reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This source code is licensed under the BSD-style license found in the
 | 
				
			||||||
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package com.facebook.openwifi.cloudsdk;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.facebook.openwifi.cloudsdk.models.ap.State;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class StateInfo extends State {
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Unix time in milliseconds (ms). This is added it because State.unit.localtime is an unknown
 | 
				
			||||||
 | 
						 * time reference.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public long timestamp;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -6,15 +6,20 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral;
 | 
					package com.facebook.openwifi.cloudsdk;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.ArrayList;
 | 
				
			||||||
 | 
					import java.util.Collections;
 | 
				
			||||||
import java.util.HashSet;
 | 
					import java.util.HashSet;
 | 
				
			||||||
 | 
					import java.util.List;
 | 
				
			||||||
import java.util.Set;
 | 
					import java.util.Set;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.facebook.openwifi.cloudsdk.models.ap.UCentralSchema;
 | 
				
			||||||
import com.google.gson.Gson;
 | 
					import com.google.gson.Gson;
 | 
				
			||||||
import com.google.gson.JsonArray;
 | 
					import com.google.gson.JsonArray;
 | 
				
			||||||
import com.google.gson.JsonElement;
 | 
					import com.google.gson.JsonElement;
 | 
				
			||||||
import com.google.gson.JsonObject;
 | 
					import com.google.gson.JsonObject;
 | 
				
			||||||
 | 
					import com.google.gson.reflect.TypeToken;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Wrapper around uCentral AP configuration.
 | 
					 * Wrapper around uCentral AP configuration.
 | 
				
			||||||
@@ -51,33 +56,33 @@ public class UCentralApConfiguration {
 | 
				
			|||||||
		return config.getAsJsonArray("radios").size();
 | 
							return config.getAsJsonArray("radios").size();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/** Return all info in the radio config (or an empty array if none). */
 | 
						/** Return all info in the radio config (or an empty list if none). */
 | 
				
			||||||
	public JsonArray getRadioConfigList() {
 | 
						public List<UCentralSchema.Radio> getRadioConfigList() {
 | 
				
			||||||
		if (!config.has("radios") || !config.get("radios").isJsonArray()) {
 | 
							if (config.has("radios") && config.get("radios").isJsonArray()) {
 | 
				
			||||||
			return new JsonArray();
 | 
								List<UCentralSchema.Radio> radios = new Gson().fromJson(
 | 
				
			||||||
 | 
									config.getAsJsonArray("radios"),
 | 
				
			||||||
 | 
									new TypeToken<ArrayList<UCentralSchema.Radio>>() {}.getType()
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
								if (radios != null) {
 | 
				
			||||||
 | 
									return radios;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		return config.getAsJsonArray("radios");
 | 
							}
 | 
				
			||||||
 | 
							return Collections.emptyList();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/** Return all the operational bands of an AP (from the radio config) */
 | 
						/** Return all the operational bands of an AP (from the radio config) */
 | 
				
			||||||
	public Set<String> getRadioBandsSet(JsonArray radioConfigList) {
 | 
						public Set<String> getRadioBandsSet(
 | 
				
			||||||
 | 
							List<UCentralSchema.Radio> radioConfigList
 | 
				
			||||||
 | 
						) {
 | 
				
			||||||
		Set<String> radioBandsSet = new HashSet<>();
 | 
							Set<String> radioBandsSet = new HashSet<>();
 | 
				
			||||||
		if (radioConfigList == null) {
 | 
							if (radioConfigList == null) {
 | 
				
			||||||
			return radioBandsSet;
 | 
								return radioBandsSet;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		for (
 | 
							for (UCentralSchema.Radio radio : radioConfigList) {
 | 
				
			||||||
			int radioIndex = 0; radioIndex < radioConfigList.size();
 | 
								if (radio == null || radio.band == null) {
 | 
				
			||||||
			radioIndex++
 | 
					 | 
				
			||||||
		) {
 | 
					 | 
				
			||||||
			JsonElement e = radioConfigList.get(radioIndex);
 | 
					 | 
				
			||||||
			if (!e.isJsonObject()) {
 | 
					 | 
				
			||||||
				continue;
 | 
									continue;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			JsonObject radioObject = e.getAsJsonObject();
 | 
								radioBandsSet.add(radio.band);
 | 
				
			||||||
			if (!radioObject.has("band")) {
 | 
					 | 
				
			||||||
				continue;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			radioBandsSet.add(radioObject.get("band").getAsString());
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return radioBandsSet;
 | 
							return radioBandsSet;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral;
 | 
					package com.facebook.openwifi.cloudsdk;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.Collections;
 | 
					import java.util.Collections;
 | 
				
			||||||
import java.util.HashMap;
 | 
					import java.util.HashMap;
 | 
				
			||||||
@@ -20,22 +20,22 @@ import org.json.JSONObject;
 | 
				
			|||||||
import org.slf4j.Logger;
 | 
					import org.slf4j.Logger;
 | 
				
			||||||
import org.slf4j.LoggerFactory;
 | 
					import org.slf4j.LoggerFactory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.facebook.openwifirrm.RRMConfig.UCentralConfig.UCentralSocketParams;
 | 
					import com.facebook.openwifi.cloudsdk.models.gw.CommandInfo;
 | 
				
			||||||
import com.facebook.openwifirrm.ucentral.gw.models.CommandInfo;
 | 
					import com.facebook.openwifi.cloudsdk.models.gw.DeviceCapabilities;
 | 
				
			||||||
import com.facebook.openwifirrm.ucentral.gw.models.DeviceCapabilities;
 | 
					import com.facebook.openwifi.cloudsdk.models.gw.DeviceConfigureRequest;
 | 
				
			||||||
import com.facebook.openwifirrm.ucentral.gw.models.DeviceConfigureRequest;
 | 
					import com.facebook.openwifi.cloudsdk.models.gw.DeviceListWithStatus;
 | 
				
			||||||
import com.facebook.openwifirrm.ucentral.gw.models.DeviceListWithStatus;
 | 
					import com.facebook.openwifi.cloudsdk.models.gw.DeviceWithStatus;
 | 
				
			||||||
import com.facebook.openwifirrm.ucentral.gw.models.DeviceWithStatus;
 | 
					import com.facebook.openwifi.cloudsdk.models.gw.ScriptRequest;
 | 
				
			||||||
import com.facebook.openwifirrm.ucentral.gw.models.ServiceEvent;
 | 
					import com.facebook.openwifi.cloudsdk.models.gw.ServiceEvent;
 | 
				
			||||||
import com.facebook.openwifirrm.ucentral.gw.models.StatisticsRecords;
 | 
					import com.facebook.openwifi.cloudsdk.models.gw.StatisticsRecords;
 | 
				
			||||||
import com.facebook.openwifirrm.ucentral.gw.models.SystemInfoResults;
 | 
					import com.facebook.openwifi.cloudsdk.models.gw.SystemInfoResults;
 | 
				
			||||||
import com.facebook.openwifirrm.ucentral.gw.models.TokenValidationResult;
 | 
					import com.facebook.openwifi.cloudsdk.models.gw.TokenValidationResult;
 | 
				
			||||||
import com.facebook.openwifirrm.ucentral.gw.models.WifiScanRequest;
 | 
					import com.facebook.openwifi.cloudsdk.models.gw.WifiScanRequest;
 | 
				
			||||||
import com.facebook.openwifirrm.ucentral.prov.models.EntityList;
 | 
					import com.facebook.openwifi.cloudsdk.models.prov.EntityList;
 | 
				
			||||||
import com.facebook.openwifirrm.ucentral.prov.models.InventoryTagList;
 | 
					import com.facebook.openwifi.cloudsdk.models.prov.InventoryTagList;
 | 
				
			||||||
import com.facebook.openwifirrm.ucentral.prov.models.RRMDetails;
 | 
					import com.facebook.openwifi.cloudsdk.models.prov.RRMDetails;
 | 
				
			||||||
import com.facebook.openwifirrm.ucentral.prov.models.SerialNumberList;
 | 
					import com.facebook.openwifi.cloudsdk.models.prov.SerialNumberList;
 | 
				
			||||||
import com.facebook.openwifirrm.ucentral.prov.models.VenueList;
 | 
					import com.facebook.openwifi.cloudsdk.models.prov.VenueList;
 | 
				
			||||||
import com.google.gson.Gson;
 | 
					import com.google.gson.Gson;
 | 
				
			||||||
import com.google.gson.JsonSyntaxException;
 | 
					import com.google.gson.JsonSyntaxException;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -127,8 +127,14 @@ public class UCentralClient {
 | 
				
			|||||||
	/** uCentral password */
 | 
						/** uCentral password */
 | 
				
			||||||
	private final String password;
 | 
						private final String password;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/** Socket parameters */
 | 
						/** Connection timeout for all requests, in ms */
 | 
				
			||||||
	private final UCentralSocketParams socketParams;
 | 
						private final int connectTimeoutMs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Socket timeout for all requests, in ms */
 | 
				
			||||||
 | 
						private final int socketTimeoutMs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Socket timeout for wifi scan requests, in ms */
 | 
				
			||||||
 | 
						private final int wifiScanTimeoutMs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/** The learned service endpoints. */
 | 
						/** The learned service endpoints. */
 | 
				
			||||||
	private final Map<String, ServiceEvent> serviceEndpoints = new HashMap<>();
 | 
						private final Map<String, ServiceEvent> serviceEndpoints = new HashMap<>();
 | 
				
			||||||
@@ -147,7 +153,9 @@ public class UCentralClient {
 | 
				
			|||||||
	 *        (if needed)
 | 
						 *        (if needed)
 | 
				
			||||||
	 * @param username uCentral username (for public endpoints only)
 | 
						 * @param username uCentral username (for public endpoints only)
 | 
				
			||||||
	 * @param password uCentral password (for public endpoints only)
 | 
						 * @param password uCentral password (for public endpoints only)
 | 
				
			||||||
	 * @param socketParams Socket parameters
 | 
						 * @param connectTimeoutMs connection timeout for all requests, in ms
 | 
				
			||||||
 | 
						 * @param socketTimeoutMs socket timeout for all requests, in ms
 | 
				
			||||||
 | 
						 * @param wifiScanTimeoutMs socket timeout for wifi scan requests, in ms
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	public UCentralClient(
 | 
						public UCentralClient(
 | 
				
			||||||
		String rrmEndpoint,
 | 
							String rrmEndpoint,
 | 
				
			||||||
@@ -155,13 +163,17 @@ public class UCentralClient {
 | 
				
			|||||||
		String uCentralSecPublicEndpoint,
 | 
							String uCentralSecPublicEndpoint,
 | 
				
			||||||
		String username,
 | 
							String username,
 | 
				
			||||||
		String password,
 | 
							String password,
 | 
				
			||||||
		UCentralSocketParams socketParams
 | 
							int connectTimeoutMs,
 | 
				
			||||||
 | 
							int socketTimeoutMs,
 | 
				
			||||||
 | 
							int wifiScanTimeoutMs
 | 
				
			||||||
	) {
 | 
						) {
 | 
				
			||||||
		this.rrmEndpoint = rrmEndpoint;
 | 
							this.rrmEndpoint = rrmEndpoint;
 | 
				
			||||||
		this.usePublicEndpoints = usePublicEndpoints;
 | 
							this.usePublicEndpoints = usePublicEndpoints;
 | 
				
			||||||
		this.username = username;
 | 
							this.username = username;
 | 
				
			||||||
		this.password = password;
 | 
							this.password = password;
 | 
				
			||||||
		this.socketParams = socketParams;
 | 
							this.connectTimeoutMs = connectTimeoutMs;
 | 
				
			||||||
 | 
							this.socketTimeoutMs = socketTimeoutMs;
 | 
				
			||||||
 | 
							this.wifiScanTimeoutMs = wifiScanTimeoutMs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (usePublicEndpoints) {
 | 
							if (usePublicEndpoints) {
 | 
				
			||||||
			setServicePublicEndpoint(OWSEC_SERVICE, uCentralSecPublicEndpoint);
 | 
								setServicePublicEndpoint(OWSEC_SERVICE, uCentralSecPublicEndpoint);
 | 
				
			||||||
@@ -305,8 +317,8 @@ public class UCentralClient {
 | 
				
			|||||||
			endpoint,
 | 
								endpoint,
 | 
				
			||||||
			service,
 | 
								service,
 | 
				
			||||||
			parameters,
 | 
								parameters,
 | 
				
			||||||
			socketParams.connectTimeoutMs,
 | 
								connectTimeoutMs,
 | 
				
			||||||
			socketParams.socketTimeoutMs
 | 
								socketTimeoutMs
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -349,8 +361,8 @@ public class UCentralClient {
 | 
				
			|||||||
			endpoint,
 | 
								endpoint,
 | 
				
			||||||
			service,
 | 
								service,
 | 
				
			||||||
			body,
 | 
								body,
 | 
				
			||||||
			socketParams.connectTimeoutMs,
 | 
								connectTimeoutMs,
 | 
				
			||||||
			socketParams.socketTimeoutMs
 | 
								socketTimeoutMs
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -454,8 +466,8 @@ public class UCentralClient {
 | 
				
			|||||||
			String.format("device/%s/wifiscan", serialNumber),
 | 
								String.format("device/%s/wifiscan", serialNumber),
 | 
				
			||||||
			OWGW_SERVICE,
 | 
								OWGW_SERVICE,
 | 
				
			||||||
			req,
 | 
								req,
 | 
				
			||||||
			socketParams.connectTimeoutMs,
 | 
								connectTimeoutMs,
 | 
				
			||||||
			socketParams.wifiScanTimeoutMs
 | 
								wifiScanTimeoutMs
 | 
				
			||||||
		);
 | 
							);
 | 
				
			||||||
		if (!response.isSuccess()) {
 | 
							if (!response.isSuccess()) {
 | 
				
			||||||
			logger.error("Error: {}", response.getBody());
 | 
								logger.error("Error: {}", response.getBody());
 | 
				
			||||||
@@ -551,6 +563,71 @@ public class UCentralClient {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Run a shell script on a device and return the result, or null upon error.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * @see #runScript(String, String, int)
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public CommandInfo runScript(String serialNumber, String script) {
 | 
				
			||||||
 | 
							return runScript(serialNumber, script, 30);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Run a shell script on a device and return the result, or null upon error.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * @see #runScript(String, String, int, String)
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public CommandInfo runScript(
 | 
				
			||||||
 | 
							String serialNumber,
 | 
				
			||||||
 | 
							String script,
 | 
				
			||||||
 | 
							int timeoutSec
 | 
				
			||||||
 | 
						) {
 | 
				
			||||||
 | 
							return runScript(serialNumber, script, timeoutSec, "shell");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Run a script on a device and return the result, or null upon error.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * @param serialNumber the device
 | 
				
			||||||
 | 
						 * @param script the script contents
 | 
				
			||||||
 | 
						 * @param timeoutSec the timeout in seconds
 | 
				
			||||||
 | 
						 * @param type the script type (either "shell" or "ucode")
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * @see UCentralUtils#getScriptOutput(CommandInfo)
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public CommandInfo runScript(
 | 
				
			||||||
 | 
							String serialNumber,
 | 
				
			||||||
 | 
							String script,
 | 
				
			||||||
 | 
							int timeoutSec,
 | 
				
			||||||
 | 
							String type
 | 
				
			||||||
 | 
						) {
 | 
				
			||||||
 | 
							ScriptRequest req = new ScriptRequest();
 | 
				
			||||||
 | 
							req.serialNumber = serialNumber;
 | 
				
			||||||
 | 
							req.timeout = timeoutSec;
 | 
				
			||||||
 | 
							req.type = type;
 | 
				
			||||||
 | 
							req.script = script;
 | 
				
			||||||
 | 
							req.scriptId = "1"; // ??
 | 
				
			||||||
 | 
							HttpResponse<String> response = httpPost(
 | 
				
			||||||
 | 
								String.format("device/%s/script", serialNumber),
 | 
				
			||||||
 | 
								OWGW_SERVICE,
 | 
				
			||||||
 | 
								req
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
							if (!response.isSuccess()) {
 | 
				
			||||||
 | 
								logger.error("Error: {}", response.getBody());
 | 
				
			||||||
 | 
								return null;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							try {
 | 
				
			||||||
 | 
								return gson.fromJson(response.getBody(), CommandInfo.class);
 | 
				
			||||||
 | 
							} catch (JsonSyntaxException e) {
 | 
				
			||||||
 | 
								String errMsg = String.format(
 | 
				
			||||||
 | 
									"Failed to deserialize to CommandInfo: %s",
 | 
				
			||||||
 | 
									response.getBody()
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
								logger.error(errMsg, e);
 | 
				
			||||||
 | 
								return null;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/** Retrieve a list of inventory from owprov. */
 | 
						/** Retrieve a list of inventory from owprov. */
 | 
				
			||||||
	public InventoryTagList getProvInventory() {
 | 
						public InventoryTagList getProvInventory() {
 | 
				
			||||||
		HttpResponse<String> response = httpGet("inventory", OWPROV_SERVICE);
 | 
							HttpResponse<String> response = httpGet("inventory", OWPROV_SERVICE);
 | 
				
			||||||
@@ -613,6 +690,19 @@ public class UCentralClient {
 | 
				
			|||||||
		try {
 | 
							try {
 | 
				
			||||||
			return gson.fromJson(response.getBody(), RRMDetails.class);
 | 
								return gson.fromJson(response.getBody(), RRMDetails.class);
 | 
				
			||||||
		} catch (JsonSyntaxException e) {
 | 
							} catch (JsonSyntaxException e) {
 | 
				
			||||||
 | 
								// catch strings like "no", "inherit", "invalid" (???)
 | 
				
			||||||
 | 
								JSONObject respBody;
 | 
				
			||||||
 | 
								try {
 | 
				
			||||||
 | 
									respBody = new JSONObject(response.getBody());
 | 
				
			||||||
 | 
									respBody.getString("rrm");
 | 
				
			||||||
 | 
									logger.error(
 | 
				
			||||||
 | 
										"RRMDetails returned unexpected string body: {}",
 | 
				
			||||||
 | 
										respBody
 | 
				
			||||||
 | 
									);
 | 
				
			||||||
 | 
									return null;
 | 
				
			||||||
 | 
								} catch (JSONException e2) { /* ignore and fall through */}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// otherwise, log as a deserialization error
 | 
				
			||||||
			String errMsg = String.format(
 | 
								String errMsg = String.format(
 | 
				
			||||||
				"Failed to deserialize to RRMDetails: %s",
 | 
									"Failed to deserialize to RRMDetails: %s",
 | 
				
			||||||
				response.getBody()
 | 
									response.getBody()
 | 
				
			||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral;
 | 
					package com.facebook.openwifi.cloudsdk;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.Arrays;
 | 
					import java.util.Arrays;
 | 
				
			||||||
import java.util.Collections;
 | 
					import java.util.Collections;
 | 
				
			||||||
@@ -22,7 +22,7 @@ public final class UCentralConstants {
 | 
				
			|||||||
	public static final String BAND_2G = "2G";
 | 
						public static final String BAND_2G = "2G";
 | 
				
			||||||
	/** String of the 5 GHz band */
 | 
						/** String of the 5 GHz band */
 | 
				
			||||||
	public static final String BAND_5G = "5G";
 | 
						public static final String BAND_5G = "5G";
 | 
				
			||||||
	/** List of all bands */
 | 
						/** List of all bands ordered from lowest to highest */
 | 
				
			||||||
	public static final List<String> BANDS = Collections
 | 
						public static final List<String> BANDS = Collections
 | 
				
			||||||
		.unmodifiableList(Arrays.asList(BAND_2G, BAND_5G));
 | 
							.unmodifiableList(Arrays.asList(BAND_2G, BAND_5G));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -6,29 +6,34 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral;
 | 
					package com.facebook.openwifi.cloudsdk;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.security.MessageDigest;
 | 
					import java.nio.charset.StandardCharsets;
 | 
				
			||||||
import java.security.NoSuchAlgorithmException;
 | 
					 | 
				
			||||||
import java.util.ArrayList;
 | 
					import java.util.ArrayList;
 | 
				
			||||||
 | 
					import java.util.Arrays;
 | 
				
			||||||
 | 
					import java.util.Base64;
 | 
				
			||||||
 | 
					import java.util.Collections;
 | 
				
			||||||
import java.util.HashMap;
 | 
					import java.util.HashMap;
 | 
				
			||||||
import java.util.HashSet;
 | 
					import java.util.HashSet;
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
import java.util.Map;
 | 
					import java.util.Map;
 | 
				
			||||||
import java.util.Map.Entry;
 | 
					import java.util.Map.Entry;
 | 
				
			||||||
import java.util.Set;
 | 
					import java.util.Set;
 | 
				
			||||||
 | 
					import java.util.zip.DataFormatException;
 | 
				
			||||||
 | 
					import java.util.zip.Inflater;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import org.slf4j.Logger;
 | 
					import org.slf4j.Logger;
 | 
				
			||||||
import org.slf4j.LoggerFactory;
 | 
					import org.slf4j.LoggerFactory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.facebook.openwifirrm.RRMConfig;
 | 
					import com.facebook.openwifi.cloudsdk.ies.Country;
 | 
				
			||||||
import com.facebook.openwifirrm.Utils;
 | 
					import com.facebook.openwifi.cloudsdk.ies.LocalPowerConstraint;
 | 
				
			||||||
import com.facebook.openwifirrm.optimizers.channel.ChannelOptimizer;
 | 
					import com.facebook.openwifi.cloudsdk.ies.QbssLoad;
 | 
				
			||||||
import com.facebook.openwifirrm.ucentral.informationelement.Country;
 | 
					import com.facebook.openwifi.cloudsdk.ies.RMEnabledCapabilities;
 | 
				
			||||||
import com.facebook.openwifirrm.ucentral.informationelement.LocalPowerConstraint;
 | 
					import com.facebook.openwifi.cloudsdk.ies.TxPwrInfo;
 | 
				
			||||||
import com.facebook.openwifirrm.ucentral.informationelement.QbssLoad;
 | 
					import com.facebook.openwifi.cloudsdk.models.ap.Capabilities;
 | 
				
			||||||
import com.facebook.openwifirrm.ucentral.informationelement.TxPwrInfo;
 | 
					import com.facebook.openwifi.cloudsdk.models.ap.State;
 | 
				
			||||||
import com.facebook.openwifirrm.ucentral.models.State;
 | 
					import com.facebook.openwifi.cloudsdk.models.ap.UCentralSchema;
 | 
				
			||||||
 | 
					import com.facebook.openwifi.cloudsdk.models.gw.CommandInfo;
 | 
				
			||||||
import com.google.gson.Gson;
 | 
					import com.google.gson.Gson;
 | 
				
			||||||
import com.google.gson.JsonArray;
 | 
					import com.google.gson.JsonArray;
 | 
				
			||||||
import com.google.gson.JsonElement;
 | 
					import com.google.gson.JsonElement;
 | 
				
			||||||
@@ -47,25 +52,47 @@ public class UCentralUtils {
 | 
				
			|||||||
	/** The Gson instance. */
 | 
						/** The Gson instance. */
 | 
				
			||||||
	private static final Gson gson = new Gson();
 | 
						private static final Gson gson = new Gson();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/** Map of band to the band-specific lowest available channel*/
 | 
						/** Map from band to ordered (increasing) list of available channels */
 | 
				
			||||||
	public static final Map<String, Integer> LOWER_CHANNEL_LIMIT =
 | 
						public static final Map<String, List<Integer>> AVAILABLE_CHANNELS_BAND =
 | 
				
			||||||
		new HashMap<>();
 | 
							Collections
 | 
				
			||||||
	static {
 | 
								.unmodifiableMap(buildBandToChannelsMap());
 | 
				
			||||||
		UCentralUtils.LOWER_CHANNEL_LIMIT.put(UCentralConstants.BAND_2G, 1);
 | 
					 | 
				
			||||||
		UCentralUtils.LOWER_CHANNEL_LIMIT.put(UCentralConstants.BAND_5G, 36);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/** Map of band to the band-specific highest available channel*/
 | 
					 | 
				
			||||||
	public static final Map<String, Integer> UPPER_CHANNEL_LIMIT =
 | 
					 | 
				
			||||||
		new HashMap<>();
 | 
					 | 
				
			||||||
	static {
 | 
					 | 
				
			||||||
		UCentralUtils.UPPER_CHANNEL_LIMIT.put(UCentralConstants.BAND_2G, 11);
 | 
					 | 
				
			||||||
		UCentralUtils.UPPER_CHANNEL_LIMIT.put(UCentralConstants.BAND_5G, 165);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// This class should not be instantiated.
 | 
						// This class should not be instantiated.
 | 
				
			||||||
	private UCentralUtils() {}
 | 
						private UCentralUtils() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Builds map from band to ordered (increasing) list of available channels.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						private static Map<String, List<Integer>> buildBandToChannelsMap() {
 | 
				
			||||||
 | 
							Map<String, List<Integer>> bandToChannelsMap = new HashMap<>();
 | 
				
			||||||
 | 
							bandToChannelsMap.put(
 | 
				
			||||||
 | 
								UCentralConstants.BAND_5G,
 | 
				
			||||||
 | 
								Collections.unmodifiableList(
 | 
				
			||||||
 | 
									Arrays.asList(36, 40, 44, 48, 149, 153, 157, 161, 165)
 | 
				
			||||||
 | 
								)
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
							// NOTE: later, we may want to support channels 12, 13, and/or 14, if
 | 
				
			||||||
 | 
							// the AP supports it and OWF vendors will use them
 | 
				
			||||||
 | 
							bandToChannelsMap.put(
 | 
				
			||||||
 | 
								UCentralConstants.BAND_2G,
 | 
				
			||||||
 | 
								Collections.unmodifiableList(
 | 
				
			||||||
 | 
									Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)
 | 
				
			||||||
 | 
								)
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
							return bandToChannelsMap;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Return the lowest available channel for the given band */
 | 
				
			||||||
 | 
						public static int getLowerChannelLimit(String band) {
 | 
				
			||||||
 | 
							return AVAILABLE_CHANNELS_BAND.get(band).get(0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Return the lowest available channel for the given band */
 | 
				
			||||||
 | 
						public static int getUpperChannelLimit(String band) {
 | 
				
			||||||
 | 
							List<Integer> channels = AVAILABLE_CHANNELS_BAND.get(band);
 | 
				
			||||||
 | 
							return channels.get(channels.size() - 1);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Parse a JSON wifi scan result into a list of WifiScanEntry objects.
 | 
						 * Parse a JSON wifi scan result into a list of WifiScanEntry objects.
 | 
				
			||||||
	 *
 | 
						 *
 | 
				
			||||||
@@ -147,9 +174,13 @@ public class UCentralUtils {
 | 
				
			|||||||
				case TxPwrInfo.TYPE:
 | 
									case TxPwrInfo.TYPE:
 | 
				
			||||||
					ieContainer.txPwrInfo = TxPwrInfo.parse(contents);
 | 
										ieContainer.txPwrInfo = TxPwrInfo.parse(contents);
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
 | 
									case RMEnabledCapabilities.TYPE:
 | 
				
			||||||
 | 
										ieContainer.rmEnabledCapabilities =
 | 
				
			||||||
 | 
											RMEnabledCapabilities.parse(contents);
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			} catch (Exception e) {
 | 
								} catch (Exception e) {
 | 
				
			||||||
				logger.debug("Skipping invalid IE {}", ie);
 | 
									logger.error(String.format("Skipping invalid IE %s", ie), e);
 | 
				
			||||||
				continue;
 | 
									continue;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -249,28 +280,20 @@ public class UCentralUtils {
 | 
				
			|||||||
	 * Returns the results map
 | 
						 * Returns the results map
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	public static Map<String, List<String>> getBandsMap(
 | 
						public static Map<String, List<String>> getBandsMap(
 | 
				
			||||||
		Map<String, JsonArray> deviceStatus
 | 
							Map<String, List<UCentralSchema.Radio>> deviceStatus
 | 
				
			||||||
	) {
 | 
						) {
 | 
				
			||||||
		Map<String, List<String>> bandsMap = new HashMap<>();
 | 
							Map<String, List<String>> bandsMap = new HashMap<>();
 | 
				
			||||||
 | 
					 | 
				
			||||||
		for (String serialNumber : deviceStatus.keySet()) {
 | 
					 | 
				
			||||||
			JsonArray radioList =
 | 
					 | 
				
			||||||
				deviceStatus.get(serialNumber).getAsJsonArray();
 | 
					 | 
				
			||||||
		for (
 | 
							for (
 | 
				
			||||||
				int radioIndex = 0; radioIndex < radioList.size(); radioIndex++
 | 
								Map.Entry<String, List<UCentralSchema.Radio>> entry : deviceStatus
 | 
				
			||||||
 | 
									.entrySet()
 | 
				
			||||||
		) {
 | 
							) {
 | 
				
			||||||
				JsonElement e = radioList.get(radioIndex);
 | 
								String serialNumber = entry.getKey();
 | 
				
			||||||
				if (!e.isJsonObject()) {
 | 
								for (UCentralSchema.Radio radio : entry.getValue()) {
 | 
				
			||||||
					return null;
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				JsonObject radioObject = e.getAsJsonObject();
 | 
					 | 
				
			||||||
				String band = radioObject.get("band").getAsString();
 | 
					 | 
				
			||||||
				bandsMap
 | 
									bandsMap
 | 
				
			||||||
					.computeIfAbsent(band, k -> new ArrayList<>())
 | 
										.computeIfAbsent(radio.band, k -> new ArrayList<>())
 | 
				
			||||||
					.add(serialNumber);
 | 
										.add(serialNumber);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					 | 
				
			||||||
		return bandsMap;
 | 
							return bandsMap;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -284,75 +307,61 @@ public class UCentralUtils {
 | 
				
			|||||||
	 * @return the results map of {band, {device, list of available channels}}
 | 
						 * @return the results map of {band, {device, list of available channels}}
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	public static Map<String, Map<String, List<Integer>>> getDeviceAvailableChannels(
 | 
						public static Map<String, Map<String, List<Integer>>> getDeviceAvailableChannels(
 | 
				
			||||||
		Map<String, JsonArray> deviceStatus,
 | 
							Map<String, List<UCentralSchema.Radio>> deviceStatus,
 | 
				
			||||||
		Map<String, JsonObject> deviceCapabilities,
 | 
							Map<String, Map<String, Capabilities.Phy>> deviceCapabilities,
 | 
				
			||||||
		Map<String, List<Integer>> defaultAvailableChannels
 | 
							Map<String, List<Integer>> defaultAvailableChannels
 | 
				
			||||||
	) {
 | 
						) {
 | 
				
			||||||
		Map<String, Map<String, List<Integer>>> deviceAvailableChannels =
 | 
							Map<String, Map<String, List<Integer>>> deviceAvailableChannels =
 | 
				
			||||||
			new HashMap<>();
 | 
								new HashMap<>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for (String serialNumber : deviceStatus.keySet()) {
 | 
					 | 
				
			||||||
			JsonArray radioList =
 | 
					 | 
				
			||||||
				deviceStatus.get(serialNumber).getAsJsonArray();
 | 
					 | 
				
			||||||
		for (
 | 
							for (
 | 
				
			||||||
				int radioIndex = 0; radioIndex < radioList.size(); radioIndex++
 | 
								Map.Entry<String, List<UCentralSchema.Radio>> entry : deviceStatus
 | 
				
			||||||
 | 
									.entrySet()
 | 
				
			||||||
		) {
 | 
							) {
 | 
				
			||||||
				JsonElement e = radioList.get(radioIndex);
 | 
								String serialNumber = entry.getKey();
 | 
				
			||||||
				if (!e.isJsonObject()) {
 | 
								for (UCentralSchema.Radio radio : entry.getValue()) {
 | 
				
			||||||
					return null;
 | 
									Map<String, Capabilities.Phy> capabilitiesPhyMap =
 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				JsonObject radioObject = e.getAsJsonObject();
 | 
					 | 
				
			||||||
				String band = radioObject.get("band").getAsString();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				JsonObject capabilitesObject =
 | 
					 | 
				
			||||||
					deviceCapabilities.get(serialNumber);
 | 
										deviceCapabilities.get(serialNumber);
 | 
				
			||||||
				List<Integer> availableChannels = new ArrayList<>();
 | 
									List<Integer> availableChannels = new ArrayList<>();
 | 
				
			||||||
				if (capabilitesObject == null) {
 | 
									if (capabilitiesPhyMap == null) {
 | 
				
			||||||
					availableChannels
 | 
										availableChannels
 | 
				
			||||||
						.addAll(defaultAvailableChannels.get(band));
 | 
											.addAll(defaultAvailableChannels.get(radio.band));
 | 
				
			||||||
				} else {
 | 
									} else {
 | 
				
			||||||
					Set<Entry<String, JsonElement>> entrySet = capabilitesObject
 | 
										Set<Entry<String, Capabilities.Phy>> entrySet =
 | 
				
			||||||
 | 
											capabilitiesPhyMap
 | 
				
			||||||
							.entrySet();
 | 
												.entrySet();
 | 
				
			||||||
					for (Map.Entry<String, JsonElement> f : entrySet) {
 | 
										for (Map.Entry<String, Capabilities.Phy> f : entrySet) {
 | 
				
			||||||
						String bandInsideObject = f.getValue()
 | 
											Capabilities.Phy phy = f.getValue();
 | 
				
			||||||
							.getAsJsonObject()
 | 
											String bandInsideObject = phy.band.toString();
 | 
				
			||||||
							.get("band")
 | 
											if (bandInsideObject.equals(radio.band)) {
 | 
				
			||||||
							.getAsString();
 | 
					 | 
				
			||||||
						if (bandInsideObject.equals(band)) {
 | 
					 | 
				
			||||||
							// (TODO) Remove the following dfsChannels code block
 | 
												// (TODO) Remove the following dfsChannels code block
 | 
				
			||||||
							// when the DFS channels are available
 | 
												// when the DFS channels are available
 | 
				
			||||||
							Set<Integer> dfsChannels = new HashSet<>();
 | 
												Set<Integer> dfsChannels = new HashSet<>();
 | 
				
			||||||
							try {
 | 
												try {
 | 
				
			||||||
								JsonArray channelInfo = f.getValue()
 | 
													int[] channelInfo = phy.dfs_channels;
 | 
				
			||||||
									.getAsJsonObject()
 | 
													for (int d : channelInfo) {
 | 
				
			||||||
									.get("dfs_channels")
 | 
														dfsChannels.add(d);
 | 
				
			||||||
									.getAsJsonArray();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
								for (JsonElement d : channelInfo) {
 | 
					 | 
				
			||||||
									dfsChannels.add(d.getAsInt());
 | 
					 | 
				
			||||||
								}
 | 
													}
 | 
				
			||||||
							} catch (Exception d) {}
 | 
												} catch (Exception d) {}
 | 
				
			||||||
							try {
 | 
												try {
 | 
				
			||||||
								JsonArray channelInfo = f.getValue()
 | 
													int[] channelInfo = phy.channels;
 | 
				
			||||||
									.getAsJsonObject()
 | 
													for (int channel : channelInfo) {
 | 
				
			||||||
									.get("channels")
 | 
					 | 
				
			||||||
									.getAsJsonArray();
 | 
					 | 
				
			||||||
								for (JsonElement c : channelInfo) {
 | 
					 | 
				
			||||||
									int channel = c.getAsInt();
 | 
					 | 
				
			||||||
									if (!dfsChannels.contains(channel)) {
 | 
														if (!dfsChannels.contains(channel)) {
 | 
				
			||||||
										availableChannels.add(channel);
 | 
															availableChannels.add(channel);
 | 
				
			||||||
									}
 | 
														}
 | 
				
			||||||
								}
 | 
													}
 | 
				
			||||||
							} catch (Exception c) {
 | 
												} catch (Exception c) {
 | 
				
			||||||
								availableChannels
 | 
													availableChannels
 | 
				
			||||||
									.addAll(defaultAvailableChannels.get(band));
 | 
														.addAll(
 | 
				
			||||||
 | 
															defaultAvailableChannels.get(radio.band)
 | 
				
			||||||
 | 
														);
 | 
				
			||||||
							}
 | 
												}
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				deviceAvailableChannels.computeIfAbsent(
 | 
									deviceAvailableChannels.computeIfAbsent(
 | 
				
			||||||
					band,
 | 
										radio.band,
 | 
				
			||||||
					k -> new HashMap<>()
 | 
										k -> new HashMap<>()
 | 
				
			||||||
				)
 | 
									)
 | 
				
			||||||
					.put(
 | 
										.put(
 | 
				
			||||||
@@ -371,10 +380,10 @@ public class UCentralUtils {
 | 
				
			|||||||
	 * Returns the results map
 | 
						 * Returns the results map
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	public static Map<String, String> getBssidsMap(
 | 
						public static Map<String, String> getBssidsMap(
 | 
				
			||||||
		Map<String, State> latestState
 | 
							Map<String, ? extends State> latestState
 | 
				
			||||||
	) {
 | 
						) {
 | 
				
			||||||
		Map<String, String> bssidMap = new HashMap<>();
 | 
							Map<String, String> bssidMap = new HashMap<>();
 | 
				
			||||||
		for (Map.Entry<String, State> e : latestState.entrySet()) {
 | 
							for (Entry<String, ? extends State> e : latestState.entrySet()) {
 | 
				
			||||||
			State state = e.getValue();
 | 
								State state = e.getValue();
 | 
				
			||||||
			for (
 | 
								for (
 | 
				
			||||||
				int interfaceIndex = 0;
 | 
									int interfaceIndex = 0;
 | 
				
			||||||
@@ -399,47 +408,6 @@ public class UCentralUtils {
 | 
				
			|||||||
		return bssidMap;
 | 
							return bssidMap;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/** Generate the RRM service key. */
 | 
					 | 
				
			||||||
	public static String generateServiceKey(
 | 
					 | 
				
			||||||
		RRMConfig.ServiceConfig serviceConfig
 | 
					 | 
				
			||||||
	) {
 | 
					 | 
				
			||||||
		try {
 | 
					 | 
				
			||||||
			MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
 | 
					 | 
				
			||||||
			sha256.update(serviceConfig.publicEndpoint.getBytes());
 | 
					 | 
				
			||||||
			sha256.update(serviceConfig.privateEndpoint.getBytes());
 | 
					 | 
				
			||||||
			return Utils.bytesToHex(sha256.digest());
 | 
					 | 
				
			||||||
		} catch (NoSuchAlgorithmException e) {
 | 
					 | 
				
			||||||
			logger.error("Unable to generate service key", e);
 | 
					 | 
				
			||||||
			return "";
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * Converts channel number to that channel's center frequency in MHz.
 | 
					 | 
				
			||||||
	 *
 | 
					 | 
				
			||||||
	 * @param channel channel number. See
 | 
					 | 
				
			||||||
	 *                {@link ChannelOptimizer#AVAILABLE_CHANNELS_BAND} for channels
 | 
					 | 
				
			||||||
	 *                in each band.
 | 
					 | 
				
			||||||
	 * @return the center frequency of the given channel in MHz
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	public static int channelToFrequencyMHz(int channel) {
 | 
					 | 
				
			||||||
		if (
 | 
					 | 
				
			||||||
			ChannelOptimizer.AVAILABLE_CHANNELS_BAND
 | 
					 | 
				
			||||||
				.get(UCentralConstants.BAND_2G)
 | 
					 | 
				
			||||||
				.contains(channel)
 | 
					 | 
				
			||||||
		) {
 | 
					 | 
				
			||||||
			return 2407 + 5 * channel;
 | 
					 | 
				
			||||||
		} else if (
 | 
					 | 
				
			||||||
			ChannelOptimizer.AVAILABLE_CHANNELS_BAND
 | 
					 | 
				
			||||||
				.get(UCentralConstants.BAND_5G)
 | 
					 | 
				
			||||||
				.contains(channel)
 | 
					 | 
				
			||||||
		) {
 | 
					 | 
				
			||||||
			return 5000 + channel;
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			throw new IllegalArgumentException("Must provide a valid channel.");
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Determines if the given channel is in the given band.
 | 
						 * Determines if the given channel is in the given band.
 | 
				
			||||||
	 *
 | 
						 *
 | 
				
			||||||
@@ -448,25 +416,17 @@ public class UCentralUtils {
 | 
				
			|||||||
	 * @return true if the given channel is in the given band; false otherwise
 | 
						 * @return true if the given channel is in the given band; false otherwise
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	public static boolean isChannelInBand(int channel, String band) {
 | 
						public static boolean isChannelInBand(int channel, String band) {
 | 
				
			||||||
		return LOWER_CHANNEL_LIMIT.get(band) <= channel &&
 | 
							return AVAILABLE_CHANNELS_BAND.get(band).contains(channel);
 | 
				
			||||||
			channel <= UPPER_CHANNEL_LIMIT.get(band);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/** Return which band contains the given frequency (MHz). */
 | 
				
			||||||
	 * Given the channel, gets the band by checking lower bound and upper bound
 | 
						public static String freqToBand(int freqMHz) {
 | 
				
			||||||
	 * of each band
 | 
							if (2412 <= freqMHz && freqMHz <= 2484) {
 | 
				
			||||||
	 *
 | 
								return "2G";
 | 
				
			||||||
	 * @param channel channel number
 | 
							} else {
 | 
				
			||||||
	 * @return band if the channel can be mapped to a valid band; null otherwise
 | 
								return "5G";
 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	public static String getBandFromChannel(int channel) {
 | 
					 | 
				
			||||||
		for (String band : UCentralConstants.BANDS) {
 | 
					 | 
				
			||||||
			if (isChannelInBand(channel, band)) {
 | 
					 | 
				
			||||||
				return band;
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
		return null;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Tries to parse channel width, if it encounters an error it will return null.
 | 
						 * Tries to parse channel width, if it encounters an error it will return null.
 | 
				
			||||||
@@ -515,4 +475,116 @@ public class UCentralUtils {
 | 
				
			|||||||
			return null;
 | 
								return null;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Return a map of Wi-Fi client (STA) MAC addresses to the Client structure
 | 
				
			||||||
 | 
						 * found for that interface. This does NOT support clients connected on
 | 
				
			||||||
 | 
						 * multiple interfaces simultaneously.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public static Map<String, State.Interface.Client> getWifiClientInfo(
 | 
				
			||||||
 | 
							State state
 | 
				
			||||||
 | 
						) {
 | 
				
			||||||
 | 
							Map<String, State.Interface.Client> ret = new HashMap<>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Aggregate over all interfaces
 | 
				
			||||||
 | 
							for (State.Interface iface : state.interfaces) {
 | 
				
			||||||
 | 
								if (iface.ssids == null || iface.clients == null) {
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Convert client array to map (for faster lookups)
 | 
				
			||||||
 | 
								Map<String, State.Interface.Client> ifaceMap = new HashMap<>();
 | 
				
			||||||
 | 
								for (State.Interface.Client client : iface.clients) {
 | 
				
			||||||
 | 
									ifaceMap.put(client.mac, client);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// Loop over all SSIDs and connected clients
 | 
				
			||||||
 | 
								for (State.Interface.SSID ssid : iface.ssids) {
 | 
				
			||||||
 | 
									if (ssid.associations == null) {
 | 
				
			||||||
 | 
										continue;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									for (
 | 
				
			||||||
 | 
										State.Interface.SSID.Association association : ssid.associations
 | 
				
			||||||
 | 
									) {
 | 
				
			||||||
 | 
										State.Interface.Client client =
 | 
				
			||||||
 | 
											ifaceMap.get(association.station);
 | 
				
			||||||
 | 
										if (client != null) {
 | 
				
			||||||
 | 
											ret.put(association.station, client);
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Decompress (inflate) a UTF-8 string using ZLIB.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * @param compressed the compressed string
 | 
				
			||||||
 | 
						 * @param uncompressedSize the uncompressed size (must be known)
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						private static String inflate(String compressed, int uncompressedSize)
 | 
				
			||||||
 | 
							throws DataFormatException {
 | 
				
			||||||
 | 
							if (compressed == null) {
 | 
				
			||||||
 | 
								throw new NullPointerException("Null compressed string");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (uncompressedSize < 0) {
 | 
				
			||||||
 | 
								throw new IllegalArgumentException("Invalid size");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							byte[] input = compressed.getBytes(StandardCharsets.UTF_8);
 | 
				
			||||||
 | 
							byte[] output = new byte[uncompressedSize];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Inflater inflater = new Inflater();
 | 
				
			||||||
 | 
							inflater.setInput(input, 0, input.length);
 | 
				
			||||||
 | 
							inflater.inflate(output);
 | 
				
			||||||
 | 
							inflater.end();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return new String(output, StandardCharsets.UTF_8);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Given the result of the "script" API, return the actual script output
 | 
				
			||||||
 | 
						 * (decoded/decompressed if needed), or null if the script returned an
 | 
				
			||||||
 | 
						 * error.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * @see UCentralClient#runScript(String, String, int, String)
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public static String getScriptOutput(CommandInfo info) {
 | 
				
			||||||
 | 
							if (info == null || info.results == null) {
 | 
				
			||||||
 | 
								return null;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (!info.results.has("status")) {
 | 
				
			||||||
 | 
								return null;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							JsonObject status = info.results.get("status").getAsJsonObject();
 | 
				
			||||||
 | 
							if (!status.has("error")) {
 | 
				
			||||||
 | 
								return null;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							int errorCode = status.get("error").getAsInt();
 | 
				
			||||||
 | 
							if (errorCode != 0) {
 | 
				
			||||||
 | 
								logger.error("Script failed with code {}", errorCode);
 | 
				
			||||||
 | 
								return null;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (status.has("result")) {
 | 
				
			||||||
 | 
								// Raw result
 | 
				
			||||||
 | 
								return status.get("result").getAsString();
 | 
				
			||||||
 | 
							} else if (status.has("result_64") && status.has("result_sz")) {
 | 
				
			||||||
 | 
								// Base64+compressed result
 | 
				
			||||||
 | 
								// NOTE: untested, not actually implemented on ucentral-client?
 | 
				
			||||||
 | 
								try {
 | 
				
			||||||
 | 
									String encoded = status.get("result_64").getAsString();
 | 
				
			||||||
 | 
									int uncompressedSize = status.get("result_sz").getAsInt();
 | 
				
			||||||
 | 
									String decoded = new String(
 | 
				
			||||||
 | 
										Base64.getDecoder().decode(encoded),
 | 
				
			||||||
 | 
										StandardCharsets.UTF_8
 | 
				
			||||||
 | 
									);
 | 
				
			||||||
 | 
									return inflate(decoded, uncompressedSize);
 | 
				
			||||||
 | 
								} catch (Exception e) {
 | 
				
			||||||
 | 
									logger.error("Failed to decode or inflate script result", e);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return null;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -6,11 +6,11 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral;
 | 
					package com.facebook.openwifi.cloudsdk;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.Objects;
 | 
					import java.util.Objects;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.facebook.openwifirrm.ucentral.models.WifiScanEntryResult;
 | 
					import com.facebook.openwifi.cloudsdk.models.ap.WifiScanEntryResult;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Extends {@link WifiScanEntryResult} to track the response time of the entry.
 | 
					 * Extends {@link WifiScanEntryResult} to track the response time of the entry.
 | 
				
			||||||
@@ -0,0 +1,155 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (c) Meta Platforms, Inc. and affiliates.
 | 
				
			||||||
 | 
					 * All rights reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This source code is licensed under the BSD-style license found in the
 | 
				
			||||||
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package com.facebook.openwifi.cloudsdk.ies;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.Objects;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.google.gson.JsonObject;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// NOTE: Not validated (not seen on test devices)
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * This information element (IE) appears in wifiscan entries. It's called "BSS AC Access Delay" in
 | 
				
			||||||
 | 
					 * 802.11 specs (section 9.4.2.43). Refer to the specification for more details.
 | 
				
			||||||
 | 
					 * Language in javadocs is taken from the specification.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class BssAcAccessDelay {
 | 
				
			||||||
 | 
						/** Defined in 802.11 table 9-92 */
 | 
				
			||||||
 | 
						public static final int TYPE = 68;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Subfield that goes into Access Category Access Delay field in BSS AC
 | 
				
			||||||
 | 
						 * Access Delay. For information on what the values mean, check section
 | 
				
			||||||
 | 
						 * 9.4.2.43
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public static class AccessCategoryAccessDelay {
 | 
				
			||||||
 | 
							/**
 | 
				
			||||||
 | 
							 * Unsigned 8 bits that represents a scaled representation of best effort AC
 | 
				
			||||||
 | 
							 * access delay
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							public final short averageAccessDelayForBestEffort;
 | 
				
			||||||
 | 
							/**
 | 
				
			||||||
 | 
							 * Unsigned 8 bits that represents a scaled representation of background AC
 | 
				
			||||||
 | 
							 * access delay
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							public final short averageAccessDelayForBackground;
 | 
				
			||||||
 | 
							/**
 | 
				
			||||||
 | 
							 * Unsigned 8 bits that represents a scaled representation of video AC access
 | 
				
			||||||
 | 
							 * delay
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							public final short averageAccessDelayForVideo;
 | 
				
			||||||
 | 
							/**
 | 
				
			||||||
 | 
							 * Unsigned 8 bits that represents a scaled representation of voice AC access
 | 
				
			||||||
 | 
							 * delay
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							public final short averageAccessDelayForVoice;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/** Constructor */
 | 
				
			||||||
 | 
							public AccessCategoryAccessDelay(
 | 
				
			||||||
 | 
								short averageAccessDelayForBestEffort,
 | 
				
			||||||
 | 
								short averageAccessDelayForBackground,
 | 
				
			||||||
 | 
								short averageAccessDelayForVideo,
 | 
				
			||||||
 | 
								short averageAccessDelayForVoice
 | 
				
			||||||
 | 
							) {
 | 
				
			||||||
 | 
								this.averageAccessDelayForBestEffort =
 | 
				
			||||||
 | 
									averageAccessDelayForBestEffort;
 | 
				
			||||||
 | 
								this.averageAccessDelayForBackground =
 | 
				
			||||||
 | 
									averageAccessDelayForBackground;
 | 
				
			||||||
 | 
								this.averageAccessDelayForVideo = averageAccessDelayForVideo;
 | 
				
			||||||
 | 
								this.averageAccessDelayForVoice = averageAccessDelayForVoice;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/** Parse AccessCategoryAccessDelay from JSON object */
 | 
				
			||||||
 | 
							// TODO rename fields as necessary - we don't know how the data format yet
 | 
				
			||||||
 | 
							public static AccessCategoryAccessDelay parse(JsonObject contents) {
 | 
				
			||||||
 | 
								return new AccessCategoryAccessDelay(
 | 
				
			||||||
 | 
									contents.get("Average Access Delay For Best Effort").getAsShort(),
 | 
				
			||||||
 | 
									contents.get("Average Access Delay For Background").getAsShort(),
 | 
				
			||||||
 | 
									contents.get("Average Access Delay For Video").getAsShort(),
 | 
				
			||||||
 | 
									contents.get("Average Access Delay For Voice").getAsShort()
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							@Override
 | 
				
			||||||
 | 
							public int hashCode() {
 | 
				
			||||||
 | 
								return Objects.hash(
 | 
				
			||||||
 | 
									averageAccessDelayForBestEffort,
 | 
				
			||||||
 | 
									averageAccessDelayForBestEffort,
 | 
				
			||||||
 | 
									averageAccessDelayForVideo,
 | 
				
			||||||
 | 
									averageAccessDelayForVoice
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							@Override
 | 
				
			||||||
 | 
							public boolean equals(Object obj) {
 | 
				
			||||||
 | 
								if (obj == null) {
 | 
				
			||||||
 | 
									return false;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (this == obj) {
 | 
				
			||||||
 | 
									return true;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (getClass() != obj.getClass()) {
 | 
				
			||||||
 | 
									return false;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								AccessCategoryAccessDelay other = (AccessCategoryAccessDelay) obj;
 | 
				
			||||||
 | 
								return averageAccessDelayForBestEffort ==
 | 
				
			||||||
 | 
									other.averageAccessDelayForBestEffort &&
 | 
				
			||||||
 | 
									averageAccessDelayForBackground ==
 | 
				
			||||||
 | 
										other.averageAccessDelayForBackground &&
 | 
				
			||||||
 | 
									averageAccessDelayForVideo ==
 | 
				
			||||||
 | 
										other.averageAccessDelayForVideo &&
 | 
				
			||||||
 | 
									averageAccessDelayForVoice == other.averageAccessDelayForVoice;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** 32 bits - Holds AccessCategoryAccessDelay subfield */
 | 
				
			||||||
 | 
						public final AccessCategoryAccessDelay accessCategoryAccessDelay;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Constructor */
 | 
				
			||||||
 | 
						public BssAcAccessDelay(
 | 
				
			||||||
 | 
							AccessCategoryAccessDelay accessCategoryAccessDelay
 | 
				
			||||||
 | 
						) {
 | 
				
			||||||
 | 
							this.accessCategoryAccessDelay = accessCategoryAccessDelay;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Parse BssAcAccessDelay from JSON object */
 | 
				
			||||||
 | 
						// TODO rename fields as necessary - we don't know how the data format yet
 | 
				
			||||||
 | 
						public static BssAcAccessDelay parse(JsonObject contents) {
 | 
				
			||||||
 | 
							return new BssAcAccessDelay(
 | 
				
			||||||
 | 
								AccessCategoryAccessDelay.parse(
 | 
				
			||||||
 | 
									contents.get("AP Average Access Delay").getAsJsonObject()
 | 
				
			||||||
 | 
								)
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Override
 | 
				
			||||||
 | 
						public int hashCode() {
 | 
				
			||||||
 | 
							return Objects.hash(accessCategoryAccessDelay);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Override
 | 
				
			||||||
 | 
						public boolean equals(Object obj) {
 | 
				
			||||||
 | 
							if (obj == null) {
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (this == obj) {
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (getClass() != obj.getClass()) {
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							BssAcAccessDelay other = (BssAcAccessDelay) obj;
 | 
				
			||||||
 | 
							return accessCategoryAccessDelay == other.accessCategoryAccessDelay;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,68 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (c) Meta Platforms, Inc. and affiliates.
 | 
				
			||||||
 | 
					 * All rights reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This source code is licensed under the BSD-style license found in the
 | 
				
			||||||
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package com.facebook.openwifi.cloudsdk.ies;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.Objects;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.google.gson.JsonObject;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// NOTE: Not validated (not seen on test devices)
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * This information element (IE) appears in wifiscan entries. It's called "BSS Average Access Delay" in
 | 
				
			||||||
 | 
					 * 802.11 specs (section 9.4.2.38). Refer to the specification for more details.
 | 
				
			||||||
 | 
					 * Language in javadocs is taken from the specification.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class BssAvgAccessDelay {
 | 
				
			||||||
 | 
						/** Defined in 802.11 table 9-92 */
 | 
				
			||||||
 | 
						public static final int TYPE = 63;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Unsigned 8 bits representing a scaled average medium access delay for all DCF
 | 
				
			||||||
 | 
						 * and EDCAF frames transmitted, measured from the time it's ready for
 | 
				
			||||||
 | 
						 * transmission to actual transmission start time.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public final short apAvgAccessDelay;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Constructor */
 | 
				
			||||||
 | 
						public BssAvgAccessDelay(short apAvgAccessDelay) {
 | 
				
			||||||
 | 
							this.apAvgAccessDelay = apAvgAccessDelay;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Parse BssAvgAccessDelay from JSON object */
 | 
				
			||||||
 | 
						// TODO modify this method as necessary - since the IE doesn't seem to be
 | 
				
			||||||
 | 
						// present, we have no idea what the format looks like
 | 
				
			||||||
 | 
						public static BssAvgAccessDelay parse(JsonObject contents) {
 | 
				
			||||||
 | 
							return new BssAvgAccessDelay(
 | 
				
			||||||
 | 
								contents.get("AP Average Access Delay").getAsShort()
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Override
 | 
				
			||||||
 | 
						public int hashCode() {
 | 
				
			||||||
 | 
							return Objects.hash(apAvgAccessDelay);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Override
 | 
				
			||||||
 | 
						public boolean equals(Object obj) {
 | 
				
			||||||
 | 
							if (obj == null) {
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (this == obj) {
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (getClass() != obj.getClass()) {
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							BssAvgAccessDelay other = (BssAvgAccessDelay) obj;
 | 
				
			||||||
 | 
							return apAvgAccessDelay == other.apAvgAccessDelay;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,87 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (c) Meta Platforms, Inc. and affiliates.
 | 
				
			||||||
 | 
					 * All rights reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This source code is licensed under the BSD-style license found in the
 | 
				
			||||||
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package com.facebook.openwifi.cloudsdk.ies;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.ArrayList;
 | 
				
			||||||
 | 
					import java.util.Collections;
 | 
				
			||||||
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					import java.util.Objects;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.google.gson.JsonElement;
 | 
				
			||||||
 | 
					import com.google.gson.JsonObject;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// NOTE: Not validated (not seen on test devices)
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * This information element (IE) appears in wifiscan entries. It's called "20/40
 | 
				
			||||||
 | 
					 * BSS Intolerant Channel Report" in 802.11 specs (section 9.4.2.57). Refer to
 | 
				
			||||||
 | 
					 * the specification for more details. Language in javadocs is taken from the
 | 
				
			||||||
 | 
					 * specification.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class BssIntolerantChannelReport {
 | 
				
			||||||
 | 
						/** Defined in 802.11 table 9-92 */
 | 
				
			||||||
 | 
						public static final int TYPE = 73;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Unsigned 8 bits representing the operating class in which the channel list
 | 
				
			||||||
 | 
						 * is valid
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public final short operatingClass;
 | 
				
			||||||
 | 
						/** List of unsigned 8 bits, representing the channel numbers */
 | 
				
			||||||
 | 
						public final List<Short> channelList;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Constructor */
 | 
				
			||||||
 | 
						public BssIntolerantChannelReport(
 | 
				
			||||||
 | 
							short operatingClass,
 | 
				
			||||||
 | 
							List<Short> channelList
 | 
				
			||||||
 | 
						) {
 | 
				
			||||||
 | 
							this.operatingClass = operatingClass;
 | 
				
			||||||
 | 
							this.channelList = Collections.unmodifiableList(channelList);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Parse BssIntolerantChannelReport from JSON object */
 | 
				
			||||||
 | 
						// TODO rename fields as necessary - we don't know how the data format yet
 | 
				
			||||||
 | 
						public static BssIntolerantChannelReport parse(JsonObject contents) {
 | 
				
			||||||
 | 
							List<Short> channelList = new ArrayList<>();
 | 
				
			||||||
 | 
							JsonElement channelListJson = contents.get("Channel List");
 | 
				
			||||||
 | 
							if (channelListJson != null) {
 | 
				
			||||||
 | 
								for (JsonElement elem : channelListJson.getAsJsonArray()) {
 | 
				
			||||||
 | 
									channelList.add(elem.getAsShort());
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return new BssIntolerantChannelReport(
 | 
				
			||||||
 | 
								contents.get("Operating Class").getAsShort(),
 | 
				
			||||||
 | 
								channelList
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Override
 | 
				
			||||||
 | 
						public int hashCode() {
 | 
				
			||||||
 | 
							return Objects.hash(operatingClass, channelList);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Override
 | 
				
			||||||
 | 
						public boolean equals(Object obj) {
 | 
				
			||||||
 | 
							if (obj == null) {
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (this == obj) {
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (getClass() != obj.getClass()) {
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							BssIntolerantChannelReport other = (BssIntolerantChannelReport) obj;
 | 
				
			||||||
 | 
							return operatingClass == other.operatingClass &&
 | 
				
			||||||
 | 
								channelList.equals(other.channelList);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,201 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (c) Meta Platforms, Inc. and affiliates.
 | 
				
			||||||
 | 
					 * All rights reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This source code is licensed under the BSD-style license found in the
 | 
				
			||||||
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package com.facebook.openwifi.cloudsdk.ies;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.Objects;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.google.gson.JsonObject;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// NOTE: Not validated (not seen on test devices)
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * This information element (IE) appears in wifiscan entries. It's called
 | 
				
			||||||
 | 
					 * "Collocated Interference Report" in 802.11 specs (section 9.4.2.84). Refer to
 | 
				
			||||||
 | 
					 * the specification for more details. Language in javadocs is taken from the
 | 
				
			||||||
 | 
					 * specification.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class CollocatedInterferenceReport {
 | 
				
			||||||
 | 
						/** Defined in 802.11 table 9-92 */
 | 
				
			||||||
 | 
						public static final int TYPE = 96;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static class InterferenceAccuracyAndIndex {
 | 
				
			||||||
 | 
							/**
 | 
				
			||||||
 | 
							 * Unsigned int (4 bits) representing expected accuracy of the estimate of
 | 
				
			||||||
 | 
							 * interference in dB with 95% confidence interval
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							public final byte expectedAccuracy;
 | 
				
			||||||
 | 
							/**
 | 
				
			||||||
 | 
							 * Unsigned int (4 bits) indicating the interference index that is unique for
 | 
				
			||||||
 | 
							 * each type of interference source
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							public final byte interferenceIndex;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/** Constructor */
 | 
				
			||||||
 | 
							public InterferenceAccuracyAndIndex(
 | 
				
			||||||
 | 
								byte expectedAccuracy,
 | 
				
			||||||
 | 
								byte interferenceIndex
 | 
				
			||||||
 | 
							) {
 | 
				
			||||||
 | 
								this.expectedAccuracy = expectedAccuracy;
 | 
				
			||||||
 | 
								this.interferenceIndex = interferenceIndex;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/** Parse InterferenceAccuracyAndIndex from JSON object */
 | 
				
			||||||
 | 
							// TODO modify this method as necessary - since the IE doesn't seem to be
 | 
				
			||||||
 | 
							// present, we have no idea what the format looks like
 | 
				
			||||||
 | 
							public static InterferenceAccuracyAndIndex parse(JsonObject contents) {
 | 
				
			||||||
 | 
								return new InterferenceAccuracyAndIndex(
 | 
				
			||||||
 | 
									contents.get("Expected Accuracy").getAsByte(),
 | 
				
			||||||
 | 
									contents.get("Interference Index").getAsByte()
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							@Override
 | 
				
			||||||
 | 
							public int hashCode() {
 | 
				
			||||||
 | 
								return Objects.hash(expectedAccuracy, interferenceIndex);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							@Override
 | 
				
			||||||
 | 
							public boolean equals(Object obj) {
 | 
				
			||||||
 | 
								if (obj == null) {
 | 
				
			||||||
 | 
									return false;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (this == obj) {
 | 
				
			||||||
 | 
									return true;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (getClass() != obj.getClass()) {
 | 
				
			||||||
 | 
									return false;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								InterferenceAccuracyAndIndex other =
 | 
				
			||||||
 | 
									(InterferenceAccuracyAndIndex) obj;
 | 
				
			||||||
 | 
								return expectedAccuracy == other.expectedAccuracy &&
 | 
				
			||||||
 | 
									interferenceIndex == other.interferenceIndex;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Unsigned 8 bits representing when the report is generated */
 | 
				
			||||||
 | 
						public final short reportPeriod;
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * signed 8 bits representing the maximum level of the collocated
 | 
				
			||||||
 | 
						 * interference power in units of dBm over all receive chains averaged over a
 | 
				
			||||||
 | 
						 * 4 microsecond period during an interference period and across interference
 | 
				
			||||||
 | 
						 * bandwidth
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public final byte interferenceLevel;
 | 
				
			||||||
 | 
						/** Subfield for interference level accuracy and index - 8 bits */
 | 
				
			||||||
 | 
						public final InterferenceAccuracyAndIndex interferenceAccuracyAndIndex;
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Unsigned 32 bits representing the interval between two successibe periods
 | 
				
			||||||
 | 
						 * of interference in microseconds
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public final long interferenceInterval;
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Unsigned 32 bits representing the duration of each period of interference in
 | 
				
			||||||
 | 
						 * microseconds
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public final long interferenceBurstLength;
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Unsigned 32 bits contains the least significant 4 octets (i.e., B0–B31) of
 | 
				
			||||||
 | 
						 * the TSF timer at the start of the interference burst. When either the
 | 
				
			||||||
 | 
						 * Interference Interval or the Interference Burst Length fields are set to
 | 
				
			||||||
 | 
						 * 2^32 – 1, this field indicates the average duty cycle
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public final long interferenceStartTimeDutyCycle;
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Unsigned 32 bits representing indicates the center frequency of interference
 | 
				
			||||||
 | 
						 * in units of 5 kHz
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public final long interferenceCenterFrequency;
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Unsigned 16 bits representing the bandwidth in units of 5 kHz at the –3 dB
 | 
				
			||||||
 | 
						 * roll-off point of the interference signal
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public final short interferenceBandwidth;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Constructor */
 | 
				
			||||||
 | 
						public CollocatedInterferenceReport(
 | 
				
			||||||
 | 
							short reportPeriod,
 | 
				
			||||||
 | 
							byte interferenceLevel,
 | 
				
			||||||
 | 
							InterferenceAccuracyAndIndex interferenceAccuracyAndIndex,
 | 
				
			||||||
 | 
							long interferenceInterval,
 | 
				
			||||||
 | 
							long interferenceBurstLength,
 | 
				
			||||||
 | 
							long interferenceStartTimeDutyCycle,
 | 
				
			||||||
 | 
							long interferenceCenterFrequency,
 | 
				
			||||||
 | 
							short interferenceBandwidth
 | 
				
			||||||
 | 
						) {
 | 
				
			||||||
 | 
							this.reportPeriod = reportPeriod;
 | 
				
			||||||
 | 
							this.interferenceLevel = interferenceLevel;
 | 
				
			||||||
 | 
							this.interferenceAccuracyAndIndex = interferenceAccuracyAndIndex;
 | 
				
			||||||
 | 
							this.interferenceInterval = interferenceInterval;
 | 
				
			||||||
 | 
							this.interferenceBurstLength = interferenceBurstLength;
 | 
				
			||||||
 | 
							this.interferenceStartTimeDutyCycle = interferenceStartTimeDutyCycle;
 | 
				
			||||||
 | 
							this.interferenceCenterFrequency = interferenceCenterFrequency;
 | 
				
			||||||
 | 
							this.interferenceBandwidth = interferenceBandwidth;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Parse CollocatedInterferenceReport from JSON object */
 | 
				
			||||||
 | 
						// TODO rename fields as necessary - we don't know how the data format yet
 | 
				
			||||||
 | 
						public static CollocatedInterferenceReport parse(JsonObject contents) {
 | 
				
			||||||
 | 
							return new CollocatedInterferenceReport(
 | 
				
			||||||
 | 
								contents.get("Report Period").getAsShort(),
 | 
				
			||||||
 | 
								contents.get("Intereference Level").getAsByte(),
 | 
				
			||||||
 | 
								InterferenceAccuracyAndIndex
 | 
				
			||||||
 | 
									.parse(
 | 
				
			||||||
 | 
										contents.get("Interference Level Accuracy/Inteference Index").getAsJsonObject()
 | 
				
			||||||
 | 
									),
 | 
				
			||||||
 | 
								contents.get("Interference Interval").getAsLong(),
 | 
				
			||||||
 | 
								contents.get("Interference Burst Length").getAsLong(),
 | 
				
			||||||
 | 
								contents.get("Interference Start Time/Duty Cycle").getAsLong(),
 | 
				
			||||||
 | 
								contents.get("Interference Center Frequency").getAsLong(),
 | 
				
			||||||
 | 
								contents.get("Interference Bandwidth").getAsShort()
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Override
 | 
				
			||||||
 | 
						public int hashCode() {
 | 
				
			||||||
 | 
							return Objects.hash(
 | 
				
			||||||
 | 
								reportPeriod,
 | 
				
			||||||
 | 
								interferenceLevel,
 | 
				
			||||||
 | 
								interferenceAccuracyAndIndex,
 | 
				
			||||||
 | 
								interferenceInterval,
 | 
				
			||||||
 | 
								interferenceBurstLength,
 | 
				
			||||||
 | 
								interferenceStartTimeDutyCycle,
 | 
				
			||||||
 | 
								interferenceCenterFrequency,
 | 
				
			||||||
 | 
								interferenceBandwidth
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Override
 | 
				
			||||||
 | 
						public boolean equals(Object obj) {
 | 
				
			||||||
 | 
							if (obj == null) {
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (this == obj) {
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (getClass() != obj.getClass()) {
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							CollocatedInterferenceReport other = (CollocatedInterferenceReport) obj;
 | 
				
			||||||
 | 
							return reportPeriod == other.reportPeriod &&
 | 
				
			||||||
 | 
								interferenceLevel == other.interferenceLevel &&
 | 
				
			||||||
 | 
								interferenceAccuracyAndIndex
 | 
				
			||||||
 | 
									.equals(other.interferenceAccuracyAndIndex) &&
 | 
				
			||||||
 | 
								interferenceInterval == other.interferenceInterval &&
 | 
				
			||||||
 | 
								interferenceBurstLength == other.interferenceBurstLength &&
 | 
				
			||||||
 | 
								interferenceStartTimeDutyCycle ==
 | 
				
			||||||
 | 
									other.interferenceStartTimeDutyCycle &&
 | 
				
			||||||
 | 
								interferenceCenterFrequency == other.interferenceCenterFrequency &&
 | 
				
			||||||
 | 
								interferenceBandwidth == other.interferenceBandwidth;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -6,52 +6,47 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral.informationelement;
 | 
					package com.facebook.openwifi.cloudsdk.ies;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.ArrayList;
 | 
					import java.util.ArrayList;
 | 
				
			||||||
import java.util.Collections;
 | 
					import java.util.Collections;
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
import java.util.Objects;
 | 
					import java.util.Objects;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import org.slf4j.Logger;
 | 
					 | 
				
			||||||
import org.slf4j.LoggerFactory;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import com.google.gson.JsonElement;
 | 
					import com.google.gson.JsonElement;
 | 
				
			||||||
import com.google.gson.JsonObject;
 | 
					import com.google.gson.JsonObject;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * This information element (IE) appears in wifiscan entries.
 | 
					 * This information element (IE) appears in wifiscan entries.
 | 
				
			||||||
 * Refer to the 802.11 specification for more details. Language in
 | 
					 * Refer to the 802.11 specification (section 9.4.2.8) for more details.
 | 
				
			||||||
 * javadocs is taken from the specification.
 | 
					 * Language in javadocs is taken from the specification.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public class Country {
 | 
					public class Country {
 | 
				
			||||||
	private static final Logger logger = LoggerFactory.getLogger(Country.class);
 | 
						/** Defined in 802.11 table 9-92 */
 | 
				
			||||||
 | 
					 | 
				
			||||||
	/** Defined in 802.11 */
 | 
					 | 
				
			||||||
	public static final int TYPE = 7;
 | 
						public static final int TYPE = 7;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/** Constraints for a subset of channels in the AP's country */
 | 
						/** Constraints for a subset of channels in the AP's country */
 | 
				
			||||||
	public static class CountryInfo {
 | 
						public static class CountryInfo {
 | 
				
			||||||
		/**
 | 
							/**
 | 
				
			||||||
		 * The lowest channel number in the CountryInfo.
 | 
							 * 8 bits unsigned - the lowest channel number in the CountryInfo.
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		public final int firstChannelNumber;
 | 
							public final short firstChannelNumber;
 | 
				
			||||||
		/**
 | 
							/**
 | 
				
			||||||
		 * The maximum power, in dBm, allowed to be transmitted.
 | 
							 * 8 bits unsigned - The maximum power, in dBm, allowed to be transmitted.
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		public final int maximumTransmitPowerLevel;
 | 
							public final short maximumTransmitPowerLevel;
 | 
				
			||||||
		/**
 | 
							/**
 | 
				
			||||||
		 * Number of channels this CountryInfo applies to. E.g., if First
 | 
							 * 8 bits unsigned - Number of channels this CountryInfo applies to. E.g.,
 | 
				
			||||||
		 * Channel Number is 2 and Number of Channels is 4, this CountryInfo
 | 
							 * if First Channel Number is 2 and Number of Channels is 4, this CountryInfo
 | 
				
			||||||
		 * describes channels 2, 3, 4, and 5.
 | 
							 * describes channels 2, 3, 4, and 5.
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		public final int numberOfChannels;
 | 
							public final short numberOfChannels;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/** Constructor. */
 | 
							/** Constructor. */
 | 
				
			||||||
		public CountryInfo(
 | 
							public CountryInfo(
 | 
				
			||||||
			int firstChannelNumber,
 | 
								short firstChannelNumber,
 | 
				
			||||||
			int maximumTransmitPowerLevel,
 | 
								short maximumTransmitPowerLevel,
 | 
				
			||||||
			int numberOfChannels
 | 
								short numberOfChannels
 | 
				
			||||||
		) {
 | 
							) {
 | 
				
			||||||
			this.firstChannelNumber = firstChannelNumber;
 | 
								this.firstChannelNumber = firstChannelNumber;
 | 
				
			||||||
			this.maximumTransmitPowerLevel = maximumTransmitPowerLevel;
 | 
								this.maximumTransmitPowerLevel = maximumTransmitPowerLevel;
 | 
				
			||||||
@@ -60,13 +55,13 @@ public class Country {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		/** Parse CountryInfo from the appropriate Json object. */
 | 
							/** Parse CountryInfo from the appropriate Json object. */
 | 
				
			||||||
		public static CountryInfo parse(JsonObject contents) {
 | 
							public static CountryInfo parse(JsonObject contents) {
 | 
				
			||||||
			final int firstChannelNumber =
 | 
								final short firstChannelNumber =
 | 
				
			||||||
				contents.get("First Channel Number").getAsInt();
 | 
									contents.get("First Channel Number").getAsShort();
 | 
				
			||||||
			final int maximumTransmitPowerLevel = contents
 | 
								final short maximumTransmitPowerLevel = contents
 | 
				
			||||||
				.get("Maximum Transmit Power Level (in dBm)")
 | 
									.get("Maximum Transmit Power Level (in dBm)")
 | 
				
			||||||
				.getAsInt();
 | 
									.getAsShort();
 | 
				
			||||||
			final int numberOfChannels =
 | 
								final short numberOfChannels =
 | 
				
			||||||
				contents.get("Number of Channels").getAsInt();
 | 
									contents.get("Number of Channels").getAsShort();
 | 
				
			||||||
			return new CountryInfo(
 | 
								return new CountryInfo(
 | 
				
			||||||
				firstChannelNumber,
 | 
									firstChannelNumber,
 | 
				
			||||||
				maximumTransmitPowerLevel,
 | 
									maximumTransmitPowerLevel,
 | 
				
			||||||
@@ -99,15 +94,10 @@ public class Country {
 | 
				
			|||||||
				maximumTransmitPowerLevel == other.maximumTransmitPowerLevel &&
 | 
									maximumTransmitPowerLevel == other.maximumTransmitPowerLevel &&
 | 
				
			||||||
				numberOfChannels == other.numberOfChannels;
 | 
									numberOfChannels == other.numberOfChannels;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					 | 
				
			||||||
		@Override
 | 
					 | 
				
			||||||
		public String toString() {
 | 
					 | 
				
			||||||
			return "CountryInfo [firstChannelNumber=" + firstChannelNumber +
 | 
					 | 
				
			||||||
				", maximumTransmitPowerLevel=" + maximumTransmitPowerLevel +
 | 
					 | 
				
			||||||
				", numberOfChannels=" + numberOfChannels + "]";
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Country */
 | 
				
			||||||
 | 
						public final String country;
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Each constraint is a CountryInfo describing tx power constraints on
 | 
						 * Each constraint is a CountryInfo describing tx power constraints on
 | 
				
			||||||
	 * one or more channels, for the current country.
 | 
						 * one or more channels, for the current country.
 | 
				
			||||||
@@ -115,7 +105,11 @@ public class Country {
 | 
				
			|||||||
	public final List<CountryInfo> constraints;
 | 
						public final List<CountryInfo> constraints;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/** Constructor */
 | 
						/** Constructor */
 | 
				
			||||||
	public Country(List<CountryInfo> countryInfos) {
 | 
						public Country(
 | 
				
			||||||
 | 
							String country,
 | 
				
			||||||
 | 
							List<CountryInfo> countryInfos
 | 
				
			||||||
 | 
						) {
 | 
				
			||||||
 | 
							this.country = country;
 | 
				
			||||||
		this.constraints = Collections.unmodifiableList(countryInfos);
 | 
							this.constraints = Collections.unmodifiableList(countryInfos);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -125,12 +119,16 @@ public class Country {
 | 
				
			|||||||
		JsonElement constraintsObject = contents.get("constraints");
 | 
							JsonElement constraintsObject = contents.get("constraints");
 | 
				
			||||||
		if (constraintsObject != null) {
 | 
							if (constraintsObject != null) {
 | 
				
			||||||
			for (JsonElement jsonElement : constraintsObject.getAsJsonArray()) {
 | 
								for (JsonElement jsonElement : constraintsObject.getAsJsonArray()) {
 | 
				
			||||||
 | 
									JsonObject innerElem = jsonElement.getAsJsonObject();
 | 
				
			||||||
				CountryInfo countryInfo =
 | 
									CountryInfo countryInfo =
 | 
				
			||||||
					CountryInfo.parse(jsonElement.getAsJsonObject());
 | 
										CountryInfo.parse(innerElem.get("Country Info").getAsJsonObject());
 | 
				
			||||||
				constraints.add(countryInfo);
 | 
									constraints.add(countryInfo);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return new Country(constraints);
 | 
							return new Country(
 | 
				
			||||||
 | 
								contents.get("Code").getAsString(),
 | 
				
			||||||
 | 
								constraints
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@Override
 | 
						@Override
 | 
				
			||||||
@@ -152,9 +150,4 @@ public class Country {
 | 
				
			|||||||
		Country other = (Country) obj;
 | 
							Country other = (Country) obj;
 | 
				
			||||||
		return Objects.equals(constraints, other.constraints);
 | 
							return Objects.equals(constraints, other.constraints);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					 | 
				
			||||||
	@Override
 | 
					 | 
				
			||||||
	public String toString() {
 | 
					 | 
				
			||||||
		return "Country [constraints=" + constraints + "]";
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral.informationelement;
 | 
					package com.facebook.openwifi.cloudsdk.ies;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.Arrays;
 | 
					import java.util.Arrays;
 | 
				
			||||||
import java.util.Objects;
 | 
					import java.util.Objects;
 | 
				
			||||||
@@ -15,9 +15,12 @@ import org.apache.commons.codec.binary.Base64;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * High Throughput (HT) Operation Element, which is potentially present in
 | 
					 * High Throughput (HT) Operation Element, which is potentially present in
 | 
				
			||||||
 * wifiscan entries. Introduced in 802.11n (2009).
 | 
					 * wifiscan entries. Introduced in 802.11n (2009). Refer to the 802.11
 | 
				
			||||||
 | 
					 * specification (section 9.4.2.56)).
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public class HTOperation {
 | 
					public class HTOperation {
 | 
				
			||||||
 | 
						/** Defined in 802.11 table 9-92 */
 | 
				
			||||||
 | 
						public static final int TYPE = 61;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/** Channel number of the primary channel. */
 | 
						/** Channel number of the primary channel. */
 | 
				
			||||||
	public final byte primaryChannel;
 | 
						public final byte primaryChannel;
 | 
				
			||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral.informationelement;
 | 
					package com.facebook.openwifi.cloudsdk.ies;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.Objects;
 | 
					import java.util.Objects;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -15,32 +15,31 @@ import com.google.gson.JsonObject;
 | 
				
			|||||||
/**
 | 
					/**
 | 
				
			||||||
 * This information element (IE) appears in wifiscan entries. It is called
 | 
					 * This information element (IE) appears in wifiscan entries. It is called
 | 
				
			||||||
 * "Local Power Constraint" in these entries, and just "Power Constraint" in
 | 
					 * "Local Power Constraint" in these entries, and just "Power Constraint" in
 | 
				
			||||||
 * the 802.11 specification. Refer to the specification for more details.
 | 
					 * the 802.11 specification (section 9.4.2.13). Refer to the specification for more details.
 | 
				
			||||||
 * Language in javadocs is taken from the specification.
 | 
					 * Language in javadocs is taken from the specification.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public class LocalPowerConstraint {
 | 
					public class LocalPowerConstraint {
 | 
				
			||||||
 | 
						/** Defined in 802.11 table 9-92 */
 | 
				
			||||||
	/** Defined in 802.11 */
 | 
					 | 
				
			||||||
	public static final int TYPE = 32;
 | 
						public static final int TYPE = 32;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Units are dB.
 | 
						 * Unsigned 8 bits - units are dB.
 | 
				
			||||||
	 * <p>
 | 
						 * <p>
 | 
				
			||||||
	 * The local maximum transmit power for a channel is defined as the maximum
 | 
						 * The local maximum transmit power for a channel is defined as the maximum
 | 
				
			||||||
	 * transmit power level specified for the channel in the Country IE minus
 | 
						 * transmit power level specified for the channel in the Country IE minus
 | 
				
			||||||
	 * this variable for the given channel.
 | 
						 * this variable for the given channel.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	public final int localPowerConstraint;
 | 
						public final short localPowerConstraint;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/** Constructor */
 | 
						/** Constructor */
 | 
				
			||||||
	public LocalPowerConstraint(int localPowerConstraint) {
 | 
						public LocalPowerConstraint(short localPowerConstraint) {
 | 
				
			||||||
		this.localPowerConstraint = localPowerConstraint;
 | 
							this.localPowerConstraint = localPowerConstraint;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/** Parse LocalPowerConstraint IE from appropriate Json object. */
 | 
						/** Parse LocalPowerConstraint IE from appropriate Json object. */
 | 
				
			||||||
	public static LocalPowerConstraint parse(JsonObject contents) {
 | 
						public static LocalPowerConstraint parse(JsonObject contents) {
 | 
				
			||||||
		final int localPowerConstraint =
 | 
							final short localPowerConstraint =
 | 
				
			||||||
			contents.get("Local Power Constraint").getAsInt();
 | 
								contents.get("Local Power Constraint").getAsShort();
 | 
				
			||||||
		return new LocalPowerConstraint(localPowerConstraint);
 | 
							return new LocalPowerConstraint(localPowerConstraint);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -63,10 +62,4 @@ public class LocalPowerConstraint {
 | 
				
			|||||||
		LocalPowerConstraint other = (LocalPowerConstraint) obj;
 | 
							LocalPowerConstraint other = (LocalPowerConstraint) obj;
 | 
				
			||||||
		return localPowerConstraint == other.localPowerConstraint;
 | 
							return localPowerConstraint == other.localPowerConstraint;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					 | 
				
			||||||
	@Override
 | 
					 | 
				
			||||||
	public String toString() {
 | 
					 | 
				
			||||||
		return "LocalPowerConstraint [localPowerConstraint=" +
 | 
					 | 
				
			||||||
			localPowerConstraint + "]";
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,318 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (c) Meta Platforms, Inc. and affiliates.
 | 
				
			||||||
 | 
					 * All rights reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This source code is licensed under the BSD-style license found in the
 | 
				
			||||||
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package com.facebook.openwifi.cloudsdk.ies;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.ArrayList;
 | 
				
			||||||
 | 
					import java.util.Collections;
 | 
				
			||||||
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					import java.util.Objects;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.google.gson.JsonElement;
 | 
				
			||||||
 | 
					import com.google.gson.JsonObject;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// NOTE: Not validated (not seen on test devices)
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * This information element (IE) appears in wifiscan entries. It's called
 | 
				
			||||||
 | 
					 * "Neighbor Report" in 802.11 specs (section 9.4.2.36). Refer to the
 | 
				
			||||||
 | 
					 * specification for more details. Language in javadocs is taken from the
 | 
				
			||||||
 | 
					 * specification.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class NeighborReport {
 | 
				
			||||||
 | 
						/** Defined in 802.11 table 9-92 */
 | 
				
			||||||
 | 
						public static final int TYPE = 52;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * The BSSID Information field can be used to help determine neighbor service
 | 
				
			||||||
 | 
						 * set transition candidates
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public static class BssidInfo {
 | 
				
			||||||
 | 
							/**
 | 
				
			||||||
 | 
							 * The capability subelement containing selected capability information for
 | 
				
			||||||
 | 
							 * the AP indicated by this BSSID.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							public static class Capabilities {
 | 
				
			||||||
 | 
								/** dot11SpectrumManagementRequired */
 | 
				
			||||||
 | 
								public final boolean spectrumManagement;
 | 
				
			||||||
 | 
								/** dot11QosOptionImplemented */
 | 
				
			||||||
 | 
								public final boolean qos;
 | 
				
			||||||
 | 
								/** dot11APSDOptionImplemented */
 | 
				
			||||||
 | 
								public final boolean apsd;
 | 
				
			||||||
 | 
								/** dot11RadioMeasurementActivated */
 | 
				
			||||||
 | 
								public final boolean radioMeasurement;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/** Constructor */
 | 
				
			||||||
 | 
								public Capabilities(
 | 
				
			||||||
 | 
									boolean spectrumManagement,
 | 
				
			||||||
 | 
									boolean qos,
 | 
				
			||||||
 | 
									boolean apsd,
 | 
				
			||||||
 | 
									boolean radioMeasurement
 | 
				
			||||||
 | 
								) {
 | 
				
			||||||
 | 
									this.spectrumManagement = spectrumManagement;
 | 
				
			||||||
 | 
									this.qos = qos;
 | 
				
			||||||
 | 
									this.apsd = apsd;
 | 
				
			||||||
 | 
									this.radioMeasurement = radioMeasurement;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/** Parse Capabilities from JSON object */
 | 
				
			||||||
 | 
								// TODO modify this method as necessary - since the IE doesn't seem to be
 | 
				
			||||||
 | 
								// present, we have no idea what the format looks like
 | 
				
			||||||
 | 
								public static Capabilities parse(JsonObject contents) {
 | 
				
			||||||
 | 
									return new Capabilities(
 | 
				
			||||||
 | 
										contents.get("Spectrum Management").getAsBoolean(),
 | 
				
			||||||
 | 
										contents.get("QoS").getAsBoolean(),
 | 
				
			||||||
 | 
										contents.get("APSD").getAsBoolean(),
 | 
				
			||||||
 | 
										contents.get("Radio Management").getAsBoolean()
 | 
				
			||||||
 | 
									);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								@Override
 | 
				
			||||||
 | 
								public int hashCode() {
 | 
				
			||||||
 | 
									return Objects
 | 
				
			||||||
 | 
										.hash(spectrumManagement, qos, apsd, radioMeasurement);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								@Override
 | 
				
			||||||
 | 
								public boolean equals(Object obj) {
 | 
				
			||||||
 | 
									if (obj == null) {
 | 
				
			||||||
 | 
										return false;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (this == obj) {
 | 
				
			||||||
 | 
										return true;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (getClass() != obj.getClass()) {
 | 
				
			||||||
 | 
										return false;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									Capabilities other = (Capabilities) obj;
 | 
				
			||||||
 | 
									return spectrumManagement == other.spectrumManagement &&
 | 
				
			||||||
 | 
										qos == other.qos && apsd == other.apsd &&
 | 
				
			||||||
 | 
										radioMeasurement == other.radioMeasurement;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/**
 | 
				
			||||||
 | 
							 * 2 unsigned bits - whether the AP identified by this BSSID is reachable by
 | 
				
			||||||
 | 
							 * the STA that requested the neighbor report
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							public final byte apReachability;
 | 
				
			||||||
 | 
							/**
 | 
				
			||||||
 | 
							 * If true, indicates that the AP identified by this BSSID supports the same
 | 
				
			||||||
 | 
							 * security provisioning as used by the STA in its current association. If the
 | 
				
			||||||
 | 
							 * bit is false, it indicates either that the AP does not support the same
 | 
				
			||||||
 | 
							 * security provisioning or that the security information is not available at
 | 
				
			||||||
 | 
							 * this time.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							public final boolean security;
 | 
				
			||||||
 | 
							/**
 | 
				
			||||||
 | 
							 * Indicates the AP indicated by this BSSID has the same authenticator as
 | 
				
			||||||
 | 
							 * the AP sending the report. If this bit is false, it indicates a distinct
 | 
				
			||||||
 | 
							 * authenticator or the information is not available.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							public final boolean keyScope;
 | 
				
			||||||
 | 
							/**
 | 
				
			||||||
 | 
							 * @see Capabilities
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							public final Capabilities capabilities;
 | 
				
			||||||
 | 
							/**
 | 
				
			||||||
 | 
							 * Set to true to indicate that the AP represented by this BSSID is including
 | 
				
			||||||
 | 
							 * an MDE in its Beacon frames and that the contents of that MDE are identical
 | 
				
			||||||
 | 
							 * to the MDE advertised by the AP sending the report
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							public final boolean mobilityDomain;
 | 
				
			||||||
 | 
							/**
 | 
				
			||||||
 | 
							 * High throughput or not, if true the contents of the HT Capabilities in the
 | 
				
			||||||
 | 
							 * Beacon frame should be identical to the HT Capabilities advertised by the
 | 
				
			||||||
 | 
							 * AP sending the report
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							public final boolean highThroughput;
 | 
				
			||||||
 | 
							/**
 | 
				
			||||||
 | 
							 * Very High throughput or not, if true the contents of the VHT Capabilities
 | 
				
			||||||
 | 
							 * in the Beacon frame should be identical to the VHT Capabilities advertised
 | 
				
			||||||
 | 
							 * by the AP sending the report
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							public final boolean veryHighThroughput;
 | 
				
			||||||
 | 
							/**
 | 
				
			||||||
 | 
							 * Indicate that the AP represented by this BSSID is an AP that has set the Fine
 | 
				
			||||||
 | 
							 * Timing Measurement Responder field of the Extended Capabilities element
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							public final boolean ftm;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/** Constructor */
 | 
				
			||||||
 | 
							public BssidInfo(
 | 
				
			||||||
 | 
								byte apReachability,
 | 
				
			||||||
 | 
								boolean security,
 | 
				
			||||||
 | 
								boolean keyScope,
 | 
				
			||||||
 | 
								Capabilities capabilities,
 | 
				
			||||||
 | 
								boolean mobilityDomain,
 | 
				
			||||||
 | 
								boolean highThroughput,
 | 
				
			||||||
 | 
								boolean veryHighThroughput,
 | 
				
			||||||
 | 
								boolean ftm
 | 
				
			||||||
 | 
							) {
 | 
				
			||||||
 | 
								this.apReachability = apReachability;
 | 
				
			||||||
 | 
								this.security = security;
 | 
				
			||||||
 | 
								this.keyScope = keyScope;
 | 
				
			||||||
 | 
								this.capabilities = capabilities;
 | 
				
			||||||
 | 
								this.mobilityDomain = mobilityDomain;
 | 
				
			||||||
 | 
								this.highThroughput = highThroughput;
 | 
				
			||||||
 | 
								this.veryHighThroughput = veryHighThroughput;
 | 
				
			||||||
 | 
								this.ftm = ftm;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/** Parse BssidInfo from JSON object */
 | 
				
			||||||
 | 
							// TODO rename fields as necessary - we don't know how the data format yet
 | 
				
			||||||
 | 
							public static BssidInfo parse(JsonObject contents) {
 | 
				
			||||||
 | 
								JsonElement capabilitiesJson = contents.get("capabilities");
 | 
				
			||||||
 | 
								if (capabilitiesJson == null) {
 | 
				
			||||||
 | 
									return null;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								Capabilities capabilities =
 | 
				
			||||||
 | 
									Capabilities.parse(capabilitiesJson.getAsJsonObject());
 | 
				
			||||||
 | 
								return new BssidInfo(
 | 
				
			||||||
 | 
									contents.get("AP Reachability").getAsByte(),
 | 
				
			||||||
 | 
									contents.get("Security").getAsBoolean(),
 | 
				
			||||||
 | 
									contents.get("Key Scope").getAsBoolean(),
 | 
				
			||||||
 | 
									capabilities,
 | 
				
			||||||
 | 
									contents.get("Mobility Domain").getAsBoolean(),
 | 
				
			||||||
 | 
									contents.get("High Throughput").getAsBoolean(),
 | 
				
			||||||
 | 
									contents.get("Very High Throughput").getAsBoolean(),
 | 
				
			||||||
 | 
									contents.get("FTM").getAsBoolean()
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							@Override
 | 
				
			||||||
 | 
							public int hashCode() {
 | 
				
			||||||
 | 
								return Objects.hash(
 | 
				
			||||||
 | 
									apReachability,
 | 
				
			||||||
 | 
									security,
 | 
				
			||||||
 | 
									keyScope,
 | 
				
			||||||
 | 
									mobilityDomain,
 | 
				
			||||||
 | 
									highThroughput,
 | 
				
			||||||
 | 
									veryHighThroughput,
 | 
				
			||||||
 | 
									ftm
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							@Override
 | 
				
			||||||
 | 
							public boolean equals(Object obj) {
 | 
				
			||||||
 | 
								if (obj == null) {
 | 
				
			||||||
 | 
									return false;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (this == obj) {
 | 
				
			||||||
 | 
									return true;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (getClass() != obj.getClass()) {
 | 
				
			||||||
 | 
									return false;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								BssidInfo other = (BssidInfo) obj;
 | 
				
			||||||
 | 
								return apReachability == other.apReachability &&
 | 
				
			||||||
 | 
									security == other.security && keyScope == other.keyScope &&
 | 
				
			||||||
 | 
									capabilities == other.capabilities &&
 | 
				
			||||||
 | 
									mobilityDomain == other.mobilityDomain &&
 | 
				
			||||||
 | 
									highThroughput == other.highThroughput &&
 | 
				
			||||||
 | 
									veryHighThroughput == other.veryHighThroughput &&
 | 
				
			||||||
 | 
									ftm == other.ftm;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** BSSID */
 | 
				
			||||||
 | 
						public final String bssid;
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * @see BssidInfo
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public final BssidInfo bssidInfo;
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Unsigned 8 bits - indicates the channel set of the AP indicated by this BSSID
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public final short operatingClass;
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Unsigned 8 bits - channel number
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public final short channelNumber;
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Unsigned 8 bits - PHY type
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public final short phyType;
 | 
				
			||||||
 | 
						// TODO do we want to support the subelements?
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Optional subelements
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public final List<JsonObject> subelements;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Constructor */
 | 
				
			||||||
 | 
						public NeighborReport(
 | 
				
			||||||
 | 
							String bssid,
 | 
				
			||||||
 | 
							BssidInfo bssidInfo,
 | 
				
			||||||
 | 
							short operatingClass,
 | 
				
			||||||
 | 
							short channelNumber,
 | 
				
			||||||
 | 
							short phyType,
 | 
				
			||||||
 | 
							List<JsonObject> subelements
 | 
				
			||||||
 | 
						) {
 | 
				
			||||||
 | 
							this.bssid = bssid;
 | 
				
			||||||
 | 
							this.bssidInfo = bssidInfo;
 | 
				
			||||||
 | 
							this.operatingClass = operatingClass;
 | 
				
			||||||
 | 
							this.channelNumber = channelNumber;
 | 
				
			||||||
 | 
							this.phyType = phyType;
 | 
				
			||||||
 | 
							this.subelements = Collections.unmodifiableList(subelements);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Parse NeighborReport from JSON object */
 | 
				
			||||||
 | 
						// TODO modify this method as necessary - since the IE doesn't seem to be
 | 
				
			||||||
 | 
						// present, we have no idea what the format looks like
 | 
				
			||||||
 | 
						public static NeighborReport parse(JsonObject contents) {
 | 
				
			||||||
 | 
							List<JsonObject> subelements = null;
 | 
				
			||||||
 | 
							JsonElement subelementsObj = contents.get("Subelements");
 | 
				
			||||||
 | 
							if (subelementsObj != null) {
 | 
				
			||||||
 | 
								subelements = new ArrayList<JsonObject>();
 | 
				
			||||||
 | 
								for (JsonElement elem : subelementsObj.getAsJsonArray()) {
 | 
				
			||||||
 | 
									subelements.add(elem.getAsJsonObject());
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return new NeighborReport(
 | 
				
			||||||
 | 
								contents.get("BSSID").getAsString(),
 | 
				
			||||||
 | 
								BssidInfo.parse(contents.get("BSSID Info").getAsJsonObject()),
 | 
				
			||||||
 | 
								contents.get("Operating Class").getAsShort(),
 | 
				
			||||||
 | 
								contents.get("Channel Number").getAsShort(),
 | 
				
			||||||
 | 
								contents.get("Phy Type").getAsShort(),
 | 
				
			||||||
 | 
								subelements
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Override
 | 
				
			||||||
 | 
						public int hashCode() {
 | 
				
			||||||
 | 
							return Objects
 | 
				
			||||||
 | 
								.hash(bssid, bssidInfo, operatingClass, channelNumber, phyType);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Override
 | 
				
			||||||
 | 
						public boolean equals(Object obj) {
 | 
				
			||||||
 | 
							if (obj == null) {
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (this == obj) {
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (getClass() != obj.getClass()) {
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							NeighborReport other = (NeighborReport) obj;
 | 
				
			||||||
 | 
							return bssid == other.bssid && bssidInfo == other.bssidInfo &&
 | 
				
			||||||
 | 
								operatingClass == other.operatingClass &&
 | 
				
			||||||
 | 
								channelNumber == other.channelNumber && phyType == other.phyType;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,80 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (c) Meta Platforms, Inc. and affiliates.
 | 
				
			||||||
 | 
					 * All rights reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This source code is licensed under the BSD-style license found in the
 | 
				
			||||||
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package com.facebook.openwifi.cloudsdk.ies;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.Objects;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.google.gson.JsonObject;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// NOTE: Not validated (not seen on test devices)
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * This information element (IE) appears in wifiscan entries. It's called "Power
 | 
				
			||||||
 | 
					 * Capability" in 802.11 specs (section 9.4.2.14). Refer to the specification
 | 
				
			||||||
 | 
					 * for more details. Language in javadocs is taken from the specification.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class PowerCapability {
 | 
				
			||||||
 | 
						/** Defined in 802.11 table 9-92 */
 | 
				
			||||||
 | 
						public static final int TYPE = 33;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Signed 8 bits units of dB relative to 1mW - nominal minimum transmit power
 | 
				
			||||||
 | 
						 * with which the STA is capable of transmitting in the current channel, with a
 | 
				
			||||||
 | 
						 * tolerance ± 5 dB.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public final byte minimumTxPowerCapability;
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Signed 8 bits units of dB relative to 1mW - nominal maximum transmit power
 | 
				
			||||||
 | 
						 * with which the STA is capable of transmitting in the current channel, with a
 | 
				
			||||||
 | 
						 * tolerance ± 5 dB.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public final byte maximumTxPowerCapability;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Constructor */
 | 
				
			||||||
 | 
						public PowerCapability(
 | 
				
			||||||
 | 
							byte minimumTxPowerCapability,
 | 
				
			||||||
 | 
							byte maximumTxPowerCapability
 | 
				
			||||||
 | 
						) {
 | 
				
			||||||
 | 
							this.minimumTxPowerCapability = minimumTxPowerCapability;
 | 
				
			||||||
 | 
							this.maximumTxPowerCapability = maximumTxPowerCapability;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Parse PowerCapability from JSON object */
 | 
				
			||||||
 | 
						// TODO modify this method as necessary - since the IE doesn't seem to be
 | 
				
			||||||
 | 
						// present, we have no idea what the format looks like
 | 
				
			||||||
 | 
						public static PowerCapability parse(JsonObject contents) {
 | 
				
			||||||
 | 
							return new PowerCapability(
 | 
				
			||||||
 | 
								contents.get("Minimum Tx Power Capability").getAsByte(),
 | 
				
			||||||
 | 
								contents.get("Maximum Tx Power Capability").getAsByte()
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Override
 | 
				
			||||||
 | 
						public int hashCode() {
 | 
				
			||||||
 | 
							return Objects.hash(minimumTxPowerCapability, maximumTxPowerCapability);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Override
 | 
				
			||||||
 | 
						public boolean equals(Object obj) {
 | 
				
			||||||
 | 
							if (obj == null) {
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (this == obj) {
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (getClass() != obj.getClass()) {
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							PowerCapability other = (PowerCapability) obj;
 | 
				
			||||||
 | 
							return minimumTxPowerCapability == other.minimumTxPowerCapability &&
 | 
				
			||||||
 | 
								maximumTxPowerCapability == other.maximumTxPowerCapability;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral.informationelement;
 | 
					package com.facebook.openwifi.cloudsdk.ies;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.Objects;
 | 
					import java.util.Objects;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -15,22 +15,21 @@ import com.google.gson.JsonObject;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * This information element (IE) appears in wifiscan entries. It is called
 | 
					 * This information element (IE) appears in wifiscan entries. It is called
 | 
				
			||||||
 * "QBSS Load" in these entries, and just "BSS Load" in the 802.11
 | 
					 * "QBSS Load" in these entries, and just "BSS Load" in the 802.11 specification
 | 
				
			||||||
 * specification. Refer to the specification for more details. Language in
 | 
					 * (section 9.4.2.27). Refer to the specification for more details. Language in
 | 
				
			||||||
 * javadocs is taken from the specification.
 | 
					 * javadocs is taken from the specification.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public class QbssLoad {
 | 
					public class QbssLoad {
 | 
				
			||||||
 | 
						/** Defined in 802.11 table 9-92 */
 | 
				
			||||||
	/** Defined in 802.11 */
 | 
					 | 
				
			||||||
	public static final int TYPE = 11;
 | 
						public static final int TYPE = 11;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * The total number of STAs currently associated with the BSS.
 | 
						 * Unsigned 16 bits - The total number of STAs currently associated with the BSS.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	public final int stationCount;
 | 
						public final short stationCount;
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * The Channel Utilization field is defined as the percentage of time,
 | 
						 * Unsigned 8 bits - The Channel Utilization field is defined as the percentage
 | 
				
			||||||
	 * linearly scaled with 255 representing 100%, that the AP sensed the
 | 
						 * of time, linearly scaled with 255 representing 100%, that the AP sensed the
 | 
				
			||||||
	 * medium was busy, as indicated by either the physical or virtual carrier
 | 
						 * medium was busy, as indicated by either the physical or virtual carrier
 | 
				
			||||||
	 * sense (CS) mechanism. When more than one channel is in use for the BSS,
 | 
						 * sense (CS) mechanism. When more than one channel is in use for the BSS,
 | 
				
			||||||
	 * the Channel Utilization field value is calculated only for the primary
 | 
						 * the Channel Utilization field value is calculated only for the primary
 | 
				
			||||||
@@ -40,22 +39,22 @@ public class QbssLoad {
 | 
				
			|||||||
	 * 		(dot11ChannelUtilizationBeaconIntervals * dot11BeaconPeriod * 1024)
 | 
						 * 		(dot11ChannelUtilizationBeaconIntervals * dot11BeaconPeriod * 1024)
 | 
				
			||||||
	 * )
 | 
						 * )
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	public final int channelUtilization;
 | 
						public final short channelUtilization;
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * The Available Admission Capacity field contains an unsigned integer that
 | 
						 * Unsigned 16 bits - The Available Admission Capacity field contains an
 | 
				
			||||||
	 * specifies the remaining amount of medium time available via explicit
 | 
						 * unsigned integer that specifies the remaining amount of medium time
 | 
				
			||||||
	 * admission control, in units of 32 miscrosecond/second. The field is
 | 
						 * available via explicit admission control, in units of 32
 | 
				
			||||||
	 * helpful for roaming STAs to select an AP that is likely to accept future
 | 
						 * miscrosecond/second. The field is helpful for roaming STAs to select an AP
 | 
				
			||||||
	 * admission control requests, but it does not represent an assurance that
 | 
						 * that is likely to accept future admission control requests, but it does not
 | 
				
			||||||
	 * the HC admits these requests.
 | 
						 * represent an assurance that the HC admits these requests.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	public final int availableAdmissionCapacity;
 | 
						public final short availableAdmissionCapacity;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/** Constructor */
 | 
						/** Constructor */
 | 
				
			||||||
	public QbssLoad(
 | 
						public QbssLoad(
 | 
				
			||||||
		int stationCount,
 | 
							short stationCount,
 | 
				
			||||||
		int channelUtilization,
 | 
							short channelUtilization,
 | 
				
			||||||
		int availableAdmissionCapacity
 | 
							short availableAdmissionCapacity
 | 
				
			||||||
	) {
 | 
						) {
 | 
				
			||||||
		this.stationCount = stationCount;
 | 
							this.stationCount = stationCount;
 | 
				
			||||||
		this.channelUtilization = channelUtilization;
 | 
							this.channelUtilization = channelUtilization;
 | 
				
			||||||
@@ -70,11 +69,11 @@ public class QbssLoad {
 | 
				
			|||||||
			return null;
 | 
								return null;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		contents = ccaContentJsonElement.getAsJsonObject();
 | 
							contents = ccaContentJsonElement.getAsJsonObject();
 | 
				
			||||||
		final int stationCount = contents.get("Station Count").getAsInt();
 | 
							final short stationCount = contents.get("Station Count").getAsShort();
 | 
				
			||||||
		final int channelUtilization =
 | 
							final short channelUtilization =
 | 
				
			||||||
			contents.get("Channel Utilization").getAsInt();
 | 
								contents.get("Channel Utilization").getAsShort();
 | 
				
			||||||
		final int availableAdmissionCapacity =
 | 
							final short availableAdmissionCapacity =
 | 
				
			||||||
			contents.get("Available Admission Capabilities").getAsInt();
 | 
								contents.get("Available Admission Capabilities").getAsShort();
 | 
				
			||||||
		return new QbssLoad(
 | 
							return new QbssLoad(
 | 
				
			||||||
			stationCount,
 | 
								stationCount,
 | 
				
			||||||
			channelUtilization,
 | 
								channelUtilization,
 | 
				
			||||||
@@ -107,11 +106,4 @@ public class QbssLoad {
 | 
				
			|||||||
			channelUtilization == other.channelUtilization &&
 | 
								channelUtilization == other.channelUtilization &&
 | 
				
			||||||
			stationCount == other.stationCount;
 | 
								stationCount == other.stationCount;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					 | 
				
			||||||
	@Override
 | 
					 | 
				
			||||||
	public String toString() {
 | 
					 | 
				
			||||||
		return "QbssLoad [stationCount=" + stationCount +
 | 
					 | 
				
			||||||
			", channelUtilization=" + channelUtilization +
 | 
					 | 
				
			||||||
			", availableAdmissionCapacity=" + availableAdmissionCapacity + "]";
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,67 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (c) Meta Platforms, Inc. and affiliates.
 | 
				
			||||||
 | 
					 * All rights reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This source code is licensed under the BSD-style license found in the
 | 
				
			||||||
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package com.facebook.openwifi.cloudsdk.ies;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.Objects;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.google.gson.JsonObject;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// NOTE: Not validated (not seen on test devices)
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * This information element (IE) appears in wifiscan entries. It's called "RCPI"
 | 
				
			||||||
 | 
					 * in 802.11 specs (section 9.4.2.37). Refer to the specification for more
 | 
				
			||||||
 | 
					 * details. Language in javadocs is taken from the specification.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class RCPI {
 | 
				
			||||||
 | 
						/** Defined in 802.11 table 9-92 */
 | 
				
			||||||
 | 
						public static final int TYPE = 53;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Unsigned 8 bits - indication of the received RF power in the selected
 | 
				
			||||||
 | 
						 * channel for a received frame
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public final short rcpi;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Constructor */
 | 
				
			||||||
 | 
						public RCPI(short rcpi) {
 | 
				
			||||||
 | 
							this.rcpi = rcpi;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Parse RCPI from JSON object */
 | 
				
			||||||
 | 
						// TODO modify this method as necessary - since the IE doesn't seem to be
 | 
				
			||||||
 | 
						// present, we have no idea what the format looks like
 | 
				
			||||||
 | 
						public static RCPI parse(JsonObject contents) {
 | 
				
			||||||
 | 
							return new RCPI(
 | 
				
			||||||
 | 
								contents.get("RCPI").getAsShort()
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Override
 | 
				
			||||||
 | 
						public int hashCode() {
 | 
				
			||||||
 | 
							return Objects.hash(rcpi);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Override
 | 
				
			||||||
 | 
						public boolean equals(Object obj) {
 | 
				
			||||||
 | 
							if (obj == null) {
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (this == obj) {
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (getClass() != obj.getClass()) {
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							RCPI other = (RCPI) obj;
 | 
				
			||||||
 | 
							return rcpi == other.rcpi;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,274 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (c) Meta Platforms, Inc. and affiliates.
 | 
				
			||||||
 | 
					 * All rights reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This source code is licensed under the BSD-style license found in the
 | 
				
			||||||
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package com.facebook.openwifi.cloudsdk.ies;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.Objects;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.facebook.openwifi.cloudsdk.IEUtils;
 | 
				
			||||||
 | 
					import com.google.gson.JsonObject;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * This information element (IE) appears in wifiscan entries. It's called "RM
 | 
				
			||||||
 | 
					 * Enabled Capabilities" in 802.11 specs (section 9.4.2.45). Refer to the
 | 
				
			||||||
 | 
					 * specification for more details. Language in javadocs is taken from the
 | 
				
			||||||
 | 
					 * specification.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class RMEnabledCapabilities {
 | 
				
			||||||
 | 
						/** Defined in 802.11 table 9-92 */
 | 
				
			||||||
 | 
						public static final int TYPE = 70;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Bit fields
 | 
				
			||||||
 | 
						// @formatter:off
 | 
				
			||||||
 | 
						public final boolean linkMeasurementCapabilityEnabled;
 | 
				
			||||||
 | 
						public final boolean neighborReportCapabilityEnabled;
 | 
				
			||||||
 | 
						public final boolean parallelMeasurementsCapabilityEnabled;
 | 
				
			||||||
 | 
						public final boolean repeatedMeasurementsCapabilityEnabled;
 | 
				
			||||||
 | 
						public final boolean beaconPassiveMeasurementCapabilityEnabled;
 | 
				
			||||||
 | 
						public final boolean beaconActiveMeasurementCapabilityEnabled;
 | 
				
			||||||
 | 
						public final boolean beaconTableMeasurementCapabilityEnabled;
 | 
				
			||||||
 | 
						public final boolean beaconMeasurementReportingConditionsCapabilityEnabled;
 | 
				
			||||||
 | 
						public final boolean frameMeasurementCapabilityEnabled;
 | 
				
			||||||
 | 
						public final boolean channelLoadMeasurementCapabilityEnabled;
 | 
				
			||||||
 | 
						public final boolean noiseHistogramMeasurementCapabilityEnabled;
 | 
				
			||||||
 | 
						public final boolean statisticsMeasurementCapabilityEnabled;
 | 
				
			||||||
 | 
						public final boolean lciMeasurementCapabilityEnabled;
 | 
				
			||||||
 | 
						public final boolean lciAzimuthCapabilityEnabled;
 | 
				
			||||||
 | 
						public final boolean transmitStreamCategoryMeasurementCapabilityEnabled;
 | 
				
			||||||
 | 
						public final boolean triggeredTransmitStreamCategoryMeasurementCapabilityEnabled;
 | 
				
			||||||
 | 
						public final boolean apChannelReportCapabilityEnabled;
 | 
				
			||||||
 | 
						public final boolean rmMibCapabilityEnabled;
 | 
				
			||||||
 | 
						public final int operatingChannelMaxMeasurementDuration;
 | 
				
			||||||
 | 
						public final int nonoperatingChannelMaxMeasurementDuration;
 | 
				
			||||||
 | 
						public final int measurementPilotCapability;
 | 
				
			||||||
 | 
						public final boolean measurementPilotTransmissionInformationCapabilityEnabled;
 | 
				
			||||||
 | 
						public final boolean neighborReportTsfOffsetCapabilityEnabled;
 | 
				
			||||||
 | 
						public final boolean rcpiMeasurementCapabilityEnabled;
 | 
				
			||||||
 | 
						public final boolean rsniMeasurementCapabilityEnabled;
 | 
				
			||||||
 | 
						public final boolean bssAverageAccessDelayCapabilityEnabled;
 | 
				
			||||||
 | 
						public final boolean bssAvailableAdmissionCapacityCapabilityEnabled;
 | 
				
			||||||
 | 
						public final boolean antennaCapabilityEnabled;
 | 
				
			||||||
 | 
						public final boolean ftmRangeReportCapabilityEnabled;
 | 
				
			||||||
 | 
						public final boolean civicLocationMeasurementCapabilityEnabled;
 | 
				
			||||||
 | 
						// @formatter:on
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Constructor */
 | 
				
			||||||
 | 
						public RMEnabledCapabilities(
 | 
				
			||||||
 | 
							boolean linkMeasurementCapabilityEnabled,
 | 
				
			||||||
 | 
							boolean neighborReportCapabilityEnabled,
 | 
				
			||||||
 | 
							boolean parallelMeasurementsCapabilityEnabled,
 | 
				
			||||||
 | 
							boolean repeatedMeasurementsCapabilityEnabled,
 | 
				
			||||||
 | 
							boolean beaconPassiveMeasurementCapabilityEnabled,
 | 
				
			||||||
 | 
							boolean beaconActiveMeasurementCapabilityEnabled,
 | 
				
			||||||
 | 
							boolean beaconTableMeasurementCapabilityEnabled,
 | 
				
			||||||
 | 
							boolean beaconMeasurementReportingConditionsCapabilityEnabled,
 | 
				
			||||||
 | 
							boolean frameMeasurementCapabilityEnabled,
 | 
				
			||||||
 | 
							boolean channelLoadMeasurementCapabilityEnabled,
 | 
				
			||||||
 | 
							boolean noiseHistogramMeasurementCapabilityEnabled,
 | 
				
			||||||
 | 
							boolean statisticsMeasurementCapabilityEnabled,
 | 
				
			||||||
 | 
							boolean lciMeasurementCapabilityEnabled,
 | 
				
			||||||
 | 
							boolean lciAzimuthCapabilityEnabled,
 | 
				
			||||||
 | 
							boolean transmitStreamCategoryMeasurementCapabilityEnabled,
 | 
				
			||||||
 | 
							boolean triggeredTransmitStreamCategoryMeasurementCapabilityEnabled,
 | 
				
			||||||
 | 
							boolean apChannelReportCapabilityEnabled,
 | 
				
			||||||
 | 
							boolean rmMibCapabilityEnabled,
 | 
				
			||||||
 | 
							int operatingChannelMaxMeasurementDuration,
 | 
				
			||||||
 | 
							int nonoperatingChannelMaxMeasurementDuration,
 | 
				
			||||||
 | 
							int measurementPilotCapability,
 | 
				
			||||||
 | 
							boolean measurementPilotTransmissionInformationCapabilityEnabled,
 | 
				
			||||||
 | 
							boolean neighborReportTsfOffsetCapabilityEnabled,
 | 
				
			||||||
 | 
							boolean rcpiMeasurementCapabilityEnabled,
 | 
				
			||||||
 | 
							boolean rsniMeasurementCapabilityEnabled,
 | 
				
			||||||
 | 
							boolean bssAverageAccessDelayCapabilityEnabled,
 | 
				
			||||||
 | 
							boolean bssAvailableAdmissionCapacityCapabilityEnabled,
 | 
				
			||||||
 | 
							boolean antennaCapabilityEnabled,
 | 
				
			||||||
 | 
							boolean ftmRangeReportCapabilityEnabled,
 | 
				
			||||||
 | 
							boolean civicLocationMeasurementCapabilityEnabled
 | 
				
			||||||
 | 
						) {
 | 
				
			||||||
 | 
							// @formatter:off
 | 
				
			||||||
 | 
							this.linkMeasurementCapabilityEnabled = linkMeasurementCapabilityEnabled;
 | 
				
			||||||
 | 
							this.neighborReportCapabilityEnabled = neighborReportCapabilityEnabled;
 | 
				
			||||||
 | 
							this.parallelMeasurementsCapabilityEnabled = parallelMeasurementsCapabilityEnabled;
 | 
				
			||||||
 | 
							this.repeatedMeasurementsCapabilityEnabled = repeatedMeasurementsCapabilityEnabled;
 | 
				
			||||||
 | 
							this.beaconPassiveMeasurementCapabilityEnabled = beaconPassiveMeasurementCapabilityEnabled;
 | 
				
			||||||
 | 
							this.beaconActiveMeasurementCapabilityEnabled = beaconActiveMeasurementCapabilityEnabled;
 | 
				
			||||||
 | 
							this.beaconTableMeasurementCapabilityEnabled = beaconTableMeasurementCapabilityEnabled;
 | 
				
			||||||
 | 
							this.beaconMeasurementReportingConditionsCapabilityEnabled = beaconMeasurementReportingConditionsCapabilityEnabled;
 | 
				
			||||||
 | 
							this.frameMeasurementCapabilityEnabled = frameMeasurementCapabilityEnabled;
 | 
				
			||||||
 | 
							this.channelLoadMeasurementCapabilityEnabled = channelLoadMeasurementCapabilityEnabled;
 | 
				
			||||||
 | 
							this.noiseHistogramMeasurementCapabilityEnabled = noiseHistogramMeasurementCapabilityEnabled;
 | 
				
			||||||
 | 
							this.statisticsMeasurementCapabilityEnabled = statisticsMeasurementCapabilityEnabled;
 | 
				
			||||||
 | 
							this.lciMeasurementCapabilityEnabled = lciMeasurementCapabilityEnabled;
 | 
				
			||||||
 | 
							this.lciAzimuthCapabilityEnabled = lciAzimuthCapabilityEnabled;
 | 
				
			||||||
 | 
							this.transmitStreamCategoryMeasurementCapabilityEnabled = transmitStreamCategoryMeasurementCapabilityEnabled;
 | 
				
			||||||
 | 
							this.triggeredTransmitStreamCategoryMeasurementCapabilityEnabled = triggeredTransmitStreamCategoryMeasurementCapabilityEnabled;
 | 
				
			||||||
 | 
							this.apChannelReportCapabilityEnabled = apChannelReportCapabilityEnabled;
 | 
				
			||||||
 | 
							this.rmMibCapabilityEnabled = rmMibCapabilityEnabled;
 | 
				
			||||||
 | 
							this.operatingChannelMaxMeasurementDuration = operatingChannelMaxMeasurementDuration;
 | 
				
			||||||
 | 
							this.nonoperatingChannelMaxMeasurementDuration = nonoperatingChannelMaxMeasurementDuration;
 | 
				
			||||||
 | 
							this.measurementPilotCapability = measurementPilotCapability;
 | 
				
			||||||
 | 
							this.measurementPilotTransmissionInformationCapabilityEnabled = measurementPilotTransmissionInformationCapabilityEnabled;
 | 
				
			||||||
 | 
							this.neighborReportTsfOffsetCapabilityEnabled = neighborReportTsfOffsetCapabilityEnabled;
 | 
				
			||||||
 | 
							this.rcpiMeasurementCapabilityEnabled = rcpiMeasurementCapabilityEnabled;
 | 
				
			||||||
 | 
							this.rsniMeasurementCapabilityEnabled = rsniMeasurementCapabilityEnabled;
 | 
				
			||||||
 | 
							this.bssAverageAccessDelayCapabilityEnabled = bssAverageAccessDelayCapabilityEnabled;
 | 
				
			||||||
 | 
							this.bssAvailableAdmissionCapacityCapabilityEnabled = bssAvailableAdmissionCapacityCapabilityEnabled;
 | 
				
			||||||
 | 
							this.antennaCapabilityEnabled = antennaCapabilityEnabled;
 | 
				
			||||||
 | 
							this.ftmRangeReportCapabilityEnabled = ftmRangeReportCapabilityEnabled;
 | 
				
			||||||
 | 
							this.civicLocationMeasurementCapabilityEnabled = civicLocationMeasurementCapabilityEnabled;
 | 
				
			||||||
 | 
							// @formatter:on
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Parse RMEnabledCapabilities IE from appropriate Json object. */
 | 
				
			||||||
 | 
						public static RMEnabledCapabilities parse(JsonObject contents) {
 | 
				
			||||||
 | 
							JsonObject o = contents.get("RM Capabilities").getAsJsonObject();
 | 
				
			||||||
 | 
							// @formatter:off
 | 
				
			||||||
 | 
							return new RMEnabledCapabilities(
 | 
				
			||||||
 | 
								/* bits 0-17 */
 | 
				
			||||||
 | 
								IEUtils.parseBooleanNumberField(o, "Link Measurement"),
 | 
				
			||||||
 | 
								IEUtils.parseBooleanNumberField(o, "Neighbor Report"),
 | 
				
			||||||
 | 
								IEUtils.parseBooleanNumberField(o, "Parallel Measurements"),
 | 
				
			||||||
 | 
								IEUtils.parseBooleanNumberField(o, "Repeated Measurements"),
 | 
				
			||||||
 | 
								IEUtils.parseBooleanNumberField(o, "Beacon Passive Measurement"),
 | 
				
			||||||
 | 
								IEUtils.parseBooleanNumberField(o, "Beacon Active Measurement"),
 | 
				
			||||||
 | 
								IEUtils.parseBooleanNumberField(o, "Beacon Table Measurement"),
 | 
				
			||||||
 | 
								IEUtils.parseBooleanNumberField(o, "Beacon Measurement Reporting Conditions"),
 | 
				
			||||||
 | 
								IEUtils.parseBooleanNumberField(o, "Frame Measurement"),
 | 
				
			||||||
 | 
								IEUtils.parseBooleanNumberField(o, "Channel Load Measurement"),
 | 
				
			||||||
 | 
								IEUtils.parseBooleanNumberField(o, "Noise Histogram Measurement"),
 | 
				
			||||||
 | 
								IEUtils.parseBooleanNumberField(o, "Statistics Measurement"),
 | 
				
			||||||
 | 
								IEUtils.parseBooleanNumberField(o, "LCI Measurement"),
 | 
				
			||||||
 | 
								IEUtils.parseBooleanNumberField(o, "LCI Azimuth capability"),
 | 
				
			||||||
 | 
								IEUtils.parseBooleanNumberField(o, "Transmit Stream/Category Measurement"),
 | 
				
			||||||
 | 
								IEUtils.parseBooleanNumberField(o, "Triggered Transmit Stream/Category Measurement"),
 | 
				
			||||||
 | 
								IEUtils.parseBooleanNumberField(o, "AP Channel Report capability"),
 | 
				
			||||||
 | 
								IEUtils.parseBooleanNumberField(o, "RM MIB capability"),
 | 
				
			||||||
 | 
								/* bits 18-20 */
 | 
				
			||||||
 | 
								IEUtils.parseIntField(o, "Operating Channel Max Measurement Duration"),
 | 
				
			||||||
 | 
								/* bits 21-23 */
 | 
				
			||||||
 | 
								IEUtils.parseIntField(o, "Nonoperating Channel Max Measurement Duration"),
 | 
				
			||||||
 | 
								/* bits 24-26 */
 | 
				
			||||||
 | 
								IEUtils.parseIntField(o, "Measurement Pilotcapability"),
 | 
				
			||||||
 | 
								/* bits 27-35 */
 | 
				
			||||||
 | 
								false /* TODO "Measurement Pilot Transmission Information Capability" */,
 | 
				
			||||||
 | 
								IEUtils.parseBooleanNumberField(o, "Neighbor Report TSF Offset"),
 | 
				
			||||||
 | 
								IEUtils.parseBooleanNumberField(o, "RCPI Measurement capability"),
 | 
				
			||||||
 | 
								IEUtils.parseBooleanNumberField(o, "RSNI Measurement capability"),
 | 
				
			||||||
 | 
								IEUtils.parseBooleanNumberField(o, "BSS Average Access Delay capability"),
 | 
				
			||||||
 | 
								IEUtils.parseBooleanNumberField(o, "BSS Available Admission Capacity capability"),
 | 
				
			||||||
 | 
								IEUtils.parseBooleanNumberField(o, "Antenna capability"),
 | 
				
			||||||
 | 
								false /* TODO "FTM Range Report Capability" */,
 | 
				
			||||||
 | 
								false /* TODO "Civic Location Measurement Capability" */
 | 
				
			||||||
 | 
								/* bits 36-39 reserved */
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
							// @formatter:on
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Override
 | 
				
			||||||
 | 
						public int hashCode() {
 | 
				
			||||||
 | 
							return Objects.hash(
 | 
				
			||||||
 | 
								antennaCapabilityEnabled,
 | 
				
			||||||
 | 
								apChannelReportCapabilityEnabled,
 | 
				
			||||||
 | 
								beaconActiveMeasurementCapabilityEnabled,
 | 
				
			||||||
 | 
								beaconMeasurementReportingConditionsCapabilityEnabled,
 | 
				
			||||||
 | 
								beaconPassiveMeasurementCapabilityEnabled,
 | 
				
			||||||
 | 
								beaconTableMeasurementCapabilityEnabled,
 | 
				
			||||||
 | 
								bssAvailableAdmissionCapacityCapabilityEnabled,
 | 
				
			||||||
 | 
								bssAverageAccessDelayCapabilityEnabled,
 | 
				
			||||||
 | 
								channelLoadMeasurementCapabilityEnabled,
 | 
				
			||||||
 | 
								civicLocationMeasurementCapabilityEnabled,
 | 
				
			||||||
 | 
								frameMeasurementCapabilityEnabled,
 | 
				
			||||||
 | 
								ftmRangeReportCapabilityEnabled,
 | 
				
			||||||
 | 
								lciAzimuthCapabilityEnabled,
 | 
				
			||||||
 | 
								lciMeasurementCapabilityEnabled,
 | 
				
			||||||
 | 
								linkMeasurementCapabilityEnabled,
 | 
				
			||||||
 | 
								measurementPilotCapability,
 | 
				
			||||||
 | 
								measurementPilotTransmissionInformationCapabilityEnabled,
 | 
				
			||||||
 | 
								neighborReportCapabilityEnabled,
 | 
				
			||||||
 | 
								neighborReportTsfOffsetCapabilityEnabled,
 | 
				
			||||||
 | 
								noiseHistogramMeasurementCapabilityEnabled,
 | 
				
			||||||
 | 
								nonoperatingChannelMaxMeasurementDuration,
 | 
				
			||||||
 | 
								operatingChannelMaxMeasurementDuration,
 | 
				
			||||||
 | 
								parallelMeasurementsCapabilityEnabled,
 | 
				
			||||||
 | 
								rcpiMeasurementCapabilityEnabled,
 | 
				
			||||||
 | 
								repeatedMeasurementsCapabilityEnabled,
 | 
				
			||||||
 | 
								rmMibCapabilityEnabled,
 | 
				
			||||||
 | 
								rsniMeasurementCapabilityEnabled,
 | 
				
			||||||
 | 
								statisticsMeasurementCapabilityEnabled,
 | 
				
			||||||
 | 
								transmitStreamCategoryMeasurementCapabilityEnabled,
 | 
				
			||||||
 | 
								triggeredTransmitStreamCategoryMeasurementCapabilityEnabled
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Override
 | 
				
			||||||
 | 
						public boolean equals(Object obj) {
 | 
				
			||||||
 | 
							if (this == obj)
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
							if (obj == null)
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							if (getClass() != obj.getClass())
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							RMEnabledCapabilities other = (RMEnabledCapabilities) obj;
 | 
				
			||||||
 | 
							return antennaCapabilityEnabled == other.antennaCapabilityEnabled &&
 | 
				
			||||||
 | 
								apChannelReportCapabilityEnabled ==
 | 
				
			||||||
 | 
									other.apChannelReportCapabilityEnabled &&
 | 
				
			||||||
 | 
								beaconActiveMeasurementCapabilityEnabled ==
 | 
				
			||||||
 | 
									other.beaconActiveMeasurementCapabilityEnabled &&
 | 
				
			||||||
 | 
								beaconMeasurementReportingConditionsCapabilityEnabled ==
 | 
				
			||||||
 | 
									other.beaconMeasurementReportingConditionsCapabilityEnabled &&
 | 
				
			||||||
 | 
								beaconPassiveMeasurementCapabilityEnabled ==
 | 
				
			||||||
 | 
									other.beaconPassiveMeasurementCapabilityEnabled &&
 | 
				
			||||||
 | 
								beaconTableMeasurementCapabilityEnabled ==
 | 
				
			||||||
 | 
									other.beaconTableMeasurementCapabilityEnabled &&
 | 
				
			||||||
 | 
								bssAvailableAdmissionCapacityCapabilityEnabled ==
 | 
				
			||||||
 | 
									other.bssAvailableAdmissionCapacityCapabilityEnabled &&
 | 
				
			||||||
 | 
								bssAverageAccessDelayCapabilityEnabled ==
 | 
				
			||||||
 | 
									other.bssAverageAccessDelayCapabilityEnabled &&
 | 
				
			||||||
 | 
								channelLoadMeasurementCapabilityEnabled ==
 | 
				
			||||||
 | 
									other.channelLoadMeasurementCapabilityEnabled &&
 | 
				
			||||||
 | 
								civicLocationMeasurementCapabilityEnabled ==
 | 
				
			||||||
 | 
									other.civicLocationMeasurementCapabilityEnabled &&
 | 
				
			||||||
 | 
								frameMeasurementCapabilityEnabled ==
 | 
				
			||||||
 | 
									other.frameMeasurementCapabilityEnabled &&
 | 
				
			||||||
 | 
								ftmRangeReportCapabilityEnabled ==
 | 
				
			||||||
 | 
									other.ftmRangeReportCapabilityEnabled &&
 | 
				
			||||||
 | 
								lciAzimuthCapabilityEnabled == other.lciAzimuthCapabilityEnabled &&
 | 
				
			||||||
 | 
								lciMeasurementCapabilityEnabled ==
 | 
				
			||||||
 | 
									other.lciMeasurementCapabilityEnabled &&
 | 
				
			||||||
 | 
								linkMeasurementCapabilityEnabled ==
 | 
				
			||||||
 | 
									other.linkMeasurementCapabilityEnabled &&
 | 
				
			||||||
 | 
								measurementPilotCapability == other.measurementPilotCapability &&
 | 
				
			||||||
 | 
								measurementPilotTransmissionInformationCapabilityEnabled ==
 | 
				
			||||||
 | 
									other.measurementPilotTransmissionInformationCapabilityEnabled &&
 | 
				
			||||||
 | 
								neighborReportCapabilityEnabled ==
 | 
				
			||||||
 | 
									other.neighborReportCapabilityEnabled &&
 | 
				
			||||||
 | 
								neighborReportTsfOffsetCapabilityEnabled ==
 | 
				
			||||||
 | 
									other.neighborReportTsfOffsetCapabilityEnabled &&
 | 
				
			||||||
 | 
								noiseHistogramMeasurementCapabilityEnabled ==
 | 
				
			||||||
 | 
									other.noiseHistogramMeasurementCapabilityEnabled &&
 | 
				
			||||||
 | 
								nonoperatingChannelMaxMeasurementDuration ==
 | 
				
			||||||
 | 
									other.nonoperatingChannelMaxMeasurementDuration &&
 | 
				
			||||||
 | 
								operatingChannelMaxMeasurementDuration ==
 | 
				
			||||||
 | 
									other.operatingChannelMaxMeasurementDuration &&
 | 
				
			||||||
 | 
								parallelMeasurementsCapabilityEnabled ==
 | 
				
			||||||
 | 
									other.parallelMeasurementsCapabilityEnabled &&
 | 
				
			||||||
 | 
								rcpiMeasurementCapabilityEnabled ==
 | 
				
			||||||
 | 
									other.rcpiMeasurementCapabilityEnabled &&
 | 
				
			||||||
 | 
								repeatedMeasurementsCapabilityEnabled ==
 | 
				
			||||||
 | 
									other.repeatedMeasurementsCapabilityEnabled &&
 | 
				
			||||||
 | 
								rmMibCapabilityEnabled == other.rmMibCapabilityEnabled &&
 | 
				
			||||||
 | 
								rsniMeasurementCapabilityEnabled ==
 | 
				
			||||||
 | 
									other.rsniMeasurementCapabilityEnabled &&
 | 
				
			||||||
 | 
								statisticsMeasurementCapabilityEnabled ==
 | 
				
			||||||
 | 
									other.statisticsMeasurementCapabilityEnabled &&
 | 
				
			||||||
 | 
								transmitStreamCategoryMeasurementCapabilityEnabled ==
 | 
				
			||||||
 | 
									other.transmitStreamCategoryMeasurementCapabilityEnabled &&
 | 
				
			||||||
 | 
								triggeredTransmitStreamCategoryMeasurementCapabilityEnabled ==
 | 
				
			||||||
 | 
									other.triggeredTransmitStreamCategoryMeasurementCapabilityEnabled;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,313 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (c) Meta Platforms, Inc. and affiliates.
 | 
				
			||||||
 | 
					 * All rights reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This source code is licensed under the BSD-style license found in the
 | 
				
			||||||
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package com.facebook.openwifi.cloudsdk.ies;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.ArrayList;
 | 
				
			||||||
 | 
					import java.util.Collections;
 | 
				
			||||||
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					import java.util.Objects;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.facebook.openwifi.cloudsdk.IEUtils;
 | 
				
			||||||
 | 
					import com.google.gson.JsonElement;
 | 
				
			||||||
 | 
					import com.google.gson.JsonObject;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// NOTE: Not validated (not seen on test devices)
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * This information element (IE) appears in wifiscan entries. It's called
 | 
				
			||||||
 | 
					 * "Reduced Neighbor Report" in 802.11 specs (section 9.4.2.170). Refer to the
 | 
				
			||||||
 | 
					 * specification for more details. Language in javadocs is taken from the
 | 
				
			||||||
 | 
					 * specification.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class ReducedNeighborReport {
 | 
				
			||||||
 | 
						/** Defined in 802.11 table 9-92 */
 | 
				
			||||||
 | 
						public static final int TYPE = 201;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * The Neighbor AP Information field specifies TBTT and other information
 | 
				
			||||||
 | 
						 * related to a group of neighbor APs on one channel.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public static class NeighborApInformation {
 | 
				
			||||||
 | 
							/**
 | 
				
			||||||
 | 
							 * Subfield for TBTT Information header
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							public static class TbttInformationHeader {
 | 
				
			||||||
 | 
								/**
 | 
				
			||||||
 | 
								 * Unsigned 2 bits -  identifies, together with the TBTT Information Length
 | 
				
			||||||
 | 
								 * subfield, the format of the TBTT Information field
 | 
				
			||||||
 | 
								 */
 | 
				
			||||||
 | 
								public final byte tbttInformationType;
 | 
				
			||||||
 | 
								/**
 | 
				
			||||||
 | 
								 * 1 bit - reserved except when the Reduced Neighbor Report element is
 | 
				
			||||||
 | 
								 * carried in a Probe Response frame transmitted by a TVHT AP
 | 
				
			||||||
 | 
								 */
 | 
				
			||||||
 | 
								public final boolean filteredNeighborAp;
 | 
				
			||||||
 | 
								/**
 | 
				
			||||||
 | 
								 * Unsigned 4 bits - number of TBTT Information fields included in the TBTT
 | 
				
			||||||
 | 
								 * Information Set field of the Neighbor AP Information field, minus one
 | 
				
			||||||
 | 
								 */
 | 
				
			||||||
 | 
								public final byte tbttInformationCount;
 | 
				
			||||||
 | 
								/**
 | 
				
			||||||
 | 
								 * Unsigned 8 bits - the length of each TBTT Information field included in
 | 
				
			||||||
 | 
								 * the TBTT Information Set field of the Neighbor AP Information field
 | 
				
			||||||
 | 
								 */
 | 
				
			||||||
 | 
								public final short tbttInformationLength;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/** Constructor */
 | 
				
			||||||
 | 
								public TbttInformationHeader(
 | 
				
			||||||
 | 
									byte tbttInformationType,
 | 
				
			||||||
 | 
									boolean filteredNeighborAp,
 | 
				
			||||||
 | 
									byte tbttInformationCount,
 | 
				
			||||||
 | 
									short tbttInformationLength
 | 
				
			||||||
 | 
								) {
 | 
				
			||||||
 | 
									this.tbttInformationType = tbttInformationType;
 | 
				
			||||||
 | 
									this.filteredNeighborAp = filteredNeighborAp;
 | 
				
			||||||
 | 
									this.tbttInformationCount = tbttInformationCount;
 | 
				
			||||||
 | 
									this.tbttInformationLength = tbttInformationLength;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/** Parse TbttInformationHeader from JSON object */
 | 
				
			||||||
 | 
								// TODO modify this method as necessary - since the IE doesn't seem to be
 | 
				
			||||||
 | 
								// present, we have no idea what the format looks like
 | 
				
			||||||
 | 
								public static TbttInformationHeader parse(JsonObject contents) {
 | 
				
			||||||
 | 
									return new TbttInformationHeader(
 | 
				
			||||||
 | 
										contents.get("TBTT Information Type").getAsByte(),
 | 
				
			||||||
 | 
										contents.get("Filtered Neighbor Map").getAsBoolean(),
 | 
				
			||||||
 | 
										contents.get("TBTT Information Count").getAsByte(),
 | 
				
			||||||
 | 
										contents.get("TBTT Information Length").getAsShort()
 | 
				
			||||||
 | 
									);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								@Override
 | 
				
			||||||
 | 
								public int hashCode() {
 | 
				
			||||||
 | 
									return Objects.hash(
 | 
				
			||||||
 | 
										tbttInformationType,
 | 
				
			||||||
 | 
										filteredNeighborAp,
 | 
				
			||||||
 | 
										tbttInformationCount,
 | 
				
			||||||
 | 
										tbttInformationLength
 | 
				
			||||||
 | 
									);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								@Override
 | 
				
			||||||
 | 
								public boolean equals(Object obj) {
 | 
				
			||||||
 | 
									if (obj == null) {
 | 
				
			||||||
 | 
										return false;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (this == obj) {
 | 
				
			||||||
 | 
										return true;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (getClass() != obj.getClass()) {
 | 
				
			||||||
 | 
										return false;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									TbttInformationHeader other = (TbttInformationHeader) obj;
 | 
				
			||||||
 | 
									return tbttInformationType == other.tbttInformationType &&
 | 
				
			||||||
 | 
										filteredNeighborAp == other.filteredNeighborAp &&
 | 
				
			||||||
 | 
										tbttInformationCount == other.tbttInformationCount &&
 | 
				
			||||||
 | 
										tbttInformationLength == other.tbttInformationLength;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/**
 | 
				
			||||||
 | 
							 * Subfield for TBTT Information
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							public static class TbttInformation {
 | 
				
			||||||
 | 
								/**
 | 
				
			||||||
 | 
								 * Unsigned 8 bits - offset in TUs, rounded down to nearest TU, to the next
 | 
				
			||||||
 | 
								 * TBTT of an AP’s BSS from the immediately prior TBTT of the AP that
 | 
				
			||||||
 | 
								 * transmits this element
 | 
				
			||||||
 | 
								 */
 | 
				
			||||||
 | 
								public final short neighborApTbttOffset;
 | 
				
			||||||
 | 
								/** BSSID of neighbor, optional */
 | 
				
			||||||
 | 
								public final String bssid;
 | 
				
			||||||
 | 
								/** Short SSID of neighbor, optional */
 | 
				
			||||||
 | 
								public final String shortSsid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/** Constructor */
 | 
				
			||||||
 | 
								public TbttInformation(
 | 
				
			||||||
 | 
									short neighborApTbttOffset,
 | 
				
			||||||
 | 
									String bssid,
 | 
				
			||||||
 | 
									String shortSsid
 | 
				
			||||||
 | 
								) {
 | 
				
			||||||
 | 
									this.neighborApTbttOffset = neighborApTbttOffset;
 | 
				
			||||||
 | 
									this.bssid = bssid;
 | 
				
			||||||
 | 
									this.shortSsid = shortSsid;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/** Parse TbttInformation from JSON object */
 | 
				
			||||||
 | 
								// TODO modify this method as necessary - since the IE doesn't seem to be
 | 
				
			||||||
 | 
								// present, we have no idea what the format looks like
 | 
				
			||||||
 | 
								public static TbttInformation parse(JsonObject contents) {
 | 
				
			||||||
 | 
									return new TbttInformation(
 | 
				
			||||||
 | 
										contents.get("Neighbor AP TBTT Offset").getAsShort(),
 | 
				
			||||||
 | 
										IEUtils.parseOptionalStringField(contents, "BSSID"),
 | 
				
			||||||
 | 
										IEUtils.parseOptionalStringField(contents, "Short SSID")
 | 
				
			||||||
 | 
									);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								@Override
 | 
				
			||||||
 | 
								public int hashCode() {
 | 
				
			||||||
 | 
									return Objects.hash(neighborApTbttOffset, bssid, shortSsid);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								@Override
 | 
				
			||||||
 | 
								public boolean equals(Object obj) {
 | 
				
			||||||
 | 
									if (obj == null) {
 | 
				
			||||||
 | 
										return false;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (this == obj) {
 | 
				
			||||||
 | 
										return true;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (getClass() != obj.getClass()) {
 | 
				
			||||||
 | 
										return false;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									TbttInformation other = (TbttInformation) obj;
 | 
				
			||||||
 | 
									return neighborApTbttOffset ==
 | 
				
			||||||
 | 
										other.neighborApTbttOffset && bssid.equals(other.bssid) &&
 | 
				
			||||||
 | 
										Objects.equals(shortSsid, other.shortSsid);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/**
 | 
				
			||||||
 | 
							 * @see TbttInformationHeader
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							public final TbttInformationHeader tbttInformationHeader;
 | 
				
			||||||
 | 
							/**
 | 
				
			||||||
 | 
							 * Unsigned 8 bits - channel starting frequency that, together with the
 | 
				
			||||||
 | 
							 * Channel Number field, indicates the primary channel of the BSSs of the APs
 | 
				
			||||||
 | 
							 * in this Neighbor AP Information field
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							public final short operatingClass;
 | 
				
			||||||
 | 
							/**
 | 
				
			||||||
 | 
							 * Unsigned 8 bits - the last known primary channel of the APs in this
 | 
				
			||||||
 | 
							 * Neighbor AP Information field.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							public final short channelNumber;
 | 
				
			||||||
 | 
							/**
 | 
				
			||||||
 | 
							 * @see TbttInformation
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							public final TbttInformation tbttInformation;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/** Constructor */
 | 
				
			||||||
 | 
							public NeighborApInformation(
 | 
				
			||||||
 | 
								TbttInformationHeader tbttInformationHeader,
 | 
				
			||||||
 | 
								short operatingClass,
 | 
				
			||||||
 | 
								short channelNumber,
 | 
				
			||||||
 | 
								TbttInformation tbttInformation
 | 
				
			||||||
 | 
							) {
 | 
				
			||||||
 | 
								this.tbttInformationHeader = tbttInformationHeader;
 | 
				
			||||||
 | 
								this.operatingClass = operatingClass;
 | 
				
			||||||
 | 
								this.channelNumber = channelNumber;
 | 
				
			||||||
 | 
								this.tbttInformation = tbttInformation;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/** Parse NeighborApInformation from JSON object */
 | 
				
			||||||
 | 
							// TODO modify this method as necessary - since the IE doesn't seem to be
 | 
				
			||||||
 | 
							// present, we have no idea what the format looks like
 | 
				
			||||||
 | 
							public static NeighborApInformation parse(JsonObject contents) {
 | 
				
			||||||
 | 
								return new NeighborApInformation(
 | 
				
			||||||
 | 
									TbttInformationHeader.parse(
 | 
				
			||||||
 | 
										contents.get("TBTT Information Header").getAsJsonObject()
 | 
				
			||||||
 | 
									),
 | 
				
			||||||
 | 
									contents.get("Operating Class").getAsShort(),
 | 
				
			||||||
 | 
									contents.get("Channel Number").getAsShort(),
 | 
				
			||||||
 | 
									TbttInformation.parse(contents.get("TBTT Information").getAsJsonObject())
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							@Override
 | 
				
			||||||
 | 
							public int hashCode() {
 | 
				
			||||||
 | 
								return Objects.hash(
 | 
				
			||||||
 | 
									tbttInformationHeader,
 | 
				
			||||||
 | 
									operatingClass,
 | 
				
			||||||
 | 
									channelNumber,
 | 
				
			||||||
 | 
									tbttInformation
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							@Override
 | 
				
			||||||
 | 
							public boolean equals(Object obj) {
 | 
				
			||||||
 | 
								if (obj == null) {
 | 
				
			||||||
 | 
									return false;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (this == obj) {
 | 
				
			||||||
 | 
									return true;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (getClass() != obj.getClass()) {
 | 
				
			||||||
 | 
									return false;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								NeighborApInformation other = (NeighborApInformation) obj;
 | 
				
			||||||
 | 
								return tbttInformationHeader.equals(other.tbttInformationHeader) &&
 | 
				
			||||||
 | 
									operatingClass == other.operatingClass &&
 | 
				
			||||||
 | 
									channelNumber == other.channelNumber &&
 | 
				
			||||||
 | 
									Objects.equals(tbttInformation, other.tbttInformation);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** number of channels in a subband of supported channels */
 | 
				
			||||||
 | 
						public final List<NeighborApInformation> neighborApInformations;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Constructor */
 | 
				
			||||||
 | 
						public ReducedNeighborReport(
 | 
				
			||||||
 | 
							List<NeighborApInformation> neighborApInformations
 | 
				
			||||||
 | 
						) {
 | 
				
			||||||
 | 
							this.neighborApInformations =
 | 
				
			||||||
 | 
								Collections.unmodifiableList(neighborApInformations);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Parse ReducedNeighborReport from JSON object */
 | 
				
			||||||
 | 
						// TODO modify this method as necessary - since the IE doesn't seem to be
 | 
				
			||||||
 | 
						// present, we have no idea what the format looks like
 | 
				
			||||||
 | 
						public static ReducedNeighborReport parse(JsonObject contents) {
 | 
				
			||||||
 | 
							List<NeighborApInformation> neighborApInformations = new ArrayList<>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							JsonElement neighborApInformationsObject =
 | 
				
			||||||
 | 
								contents.get("Neighbor AP Informations");
 | 
				
			||||||
 | 
							if (neighborApInformationsObject != null) {
 | 
				
			||||||
 | 
								for (
 | 
				
			||||||
 | 
									JsonElement elem : neighborApInformationsObject.getAsJsonArray()
 | 
				
			||||||
 | 
								) {
 | 
				
			||||||
 | 
									neighborApInformations
 | 
				
			||||||
 | 
										.add(NeighborApInformation.parse(elem.getAsJsonObject()));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return new ReducedNeighborReport(neighborApInformations);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Override
 | 
				
			||||||
 | 
						public int hashCode() {
 | 
				
			||||||
 | 
							return Objects.hash(neighborApInformations);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Override
 | 
				
			||||||
 | 
						public boolean equals(Object obj) {
 | 
				
			||||||
 | 
							if (obj == null) {
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (this == obj) {
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (getClass() != obj.getClass()) {
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ReducedNeighborReport other = (ReducedNeighborReport) obj;
 | 
				
			||||||
 | 
							return neighborApInformations.equals(other.neighborApInformations);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,70 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (c) Meta Platforms, Inc. and affiliates.
 | 
				
			||||||
 | 
					 * All rights reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This source code is licensed under the BSD-style license found in the
 | 
				
			||||||
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package com.facebook.openwifi.cloudsdk.ies;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.Objects;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.google.gson.JsonObject;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// NOTE: Not validated (not seen on test devices)
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * This information element (IE) appears in wifiscan entries. It's called
 | 
				
			||||||
 | 
					 * "Supported Channels" in 802.11 specs (section 9.4.2.17). Refer to the
 | 
				
			||||||
 | 
					 * specification for more details. Language in javadocs is taken from the
 | 
				
			||||||
 | 
					 * specification.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class SupportedChannels {
 | 
				
			||||||
 | 
						/** Defined in 802.11 table 9-92 */
 | 
				
			||||||
 | 
						public static final int TYPE = 36;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Unsigned 8 bits - first channel in a subband of supported channels */
 | 
				
			||||||
 | 
						public final short firstChannelNumber;
 | 
				
			||||||
 | 
						/** Unsigned 8 bits - number of channels in a subband of supported channels */
 | 
				
			||||||
 | 
						public final short numberOfChannels;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Constructor */
 | 
				
			||||||
 | 
						public SupportedChannels(short firstChannelNumber, short numberOfChannels) {
 | 
				
			||||||
 | 
							this.firstChannelNumber = firstChannelNumber;
 | 
				
			||||||
 | 
							this.numberOfChannels = numberOfChannels;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Parse SupportedChannels from JSON object */
 | 
				
			||||||
 | 
						// TODO modify this method as necessary - since the IE doesn't seem to be
 | 
				
			||||||
 | 
						// present, we have no idea what the format looks like
 | 
				
			||||||
 | 
						public static SupportedChannels parse(JsonObject contents) {
 | 
				
			||||||
 | 
							return new SupportedChannels(
 | 
				
			||||||
 | 
								contents.get("First Channel Number").getAsShort(),
 | 
				
			||||||
 | 
								contents.get("Number of Channels").getAsShort()
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Override
 | 
				
			||||||
 | 
						public int hashCode() {
 | 
				
			||||||
 | 
							return Objects.hash(firstChannelNumber, numberOfChannels);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Override
 | 
				
			||||||
 | 
						public boolean equals(Object obj) {
 | 
				
			||||||
 | 
							if (obj == null) {
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (this == obj) {
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (getClass() != obj.getClass()) {
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							SupportedChannels other = (SupportedChannels) obj;
 | 
				
			||||||
 | 
							return firstChannelNumber == other.firstChannelNumber &&
 | 
				
			||||||
 | 
								numberOfChannels == other.numberOfChannels;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -6,39 +6,46 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral.informationelement;
 | 
					package com.facebook.openwifi.cloudsdk.ies;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.Objects;
 | 
					import java.util.Objects;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.google.gson.JsonElement;
 | 
					import com.facebook.openwifi.cloudsdk.IEUtils;
 | 
				
			||||||
import com.google.gson.JsonObject;
 | 
					import com.google.gson.JsonObject;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * This information element (IE) appears in wifiscan entries. It is called
 | 
					 * This information element (IE) appears in wifiscan entries. It is called
 | 
				
			||||||
 * "Tx Pwr Info" in these entries, and "Transmit Power Envelope" in the 802.11
 | 
					 * "Tx Pwr Info" in these entries, and "Transmit Power Envelope" in the 802.11
 | 
				
			||||||
 * specification. Refer to the specification for more details. Language in
 | 
					 * specification (section 9.4.2.161). Refer to the specification for more details. Language in
 | 
				
			||||||
 * javadocs is taken from the specification.
 | 
					 * javadocs is taken from the specification.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public class TxPwrInfo {
 | 
					public class TxPwrInfo {
 | 
				
			||||||
 | 
						/** Defined in 802.11 table 9-92 */
 | 
				
			||||||
	/** Defined in 802.11 */
 | 
					 | 
				
			||||||
	public static final int TYPE = 195;
 | 
						public static final int TYPE = 195;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/** Local maximum transmit power for 20 MHz. Required field. */
 | 
						/**
 | 
				
			||||||
	public final Integer localMaxTxPwrConstraint20MHz;
 | 
						 * Unsigned 8 bits - Local maximum transmit power for 20 MHz. Required field.
 | 
				
			||||||
	/** Local maximum transmit power for 40 MHz. Optional field. */
 | 
						 */
 | 
				
			||||||
	public final Integer localMaxTxPwrConstraint40MHz;
 | 
						public final Short localMaxTxPwrConstraint20MHz;
 | 
				
			||||||
	/** Local maximum transmit power for 80 MHz. Optional field. */
 | 
						/**
 | 
				
			||||||
	public final Integer localMaxTxPwrConstraint80MHz;
 | 
						 * Unsigned 8 bits - Local maximum transmit power for 40 MHz. Optional field.
 | 
				
			||||||
	/** Local maximum transmit power for both 160 MHz and 80+80 MHz. Optional field. */
 | 
						 */
 | 
				
			||||||
	public final Integer localMaxTxPwrConstraint160MHz;
 | 
						public final Short localMaxTxPwrConstraint40MHz;
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Unsigned 8 bits - Local maximum transmit power for 80 MHz. Optional field.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public final Short localMaxTxPwrConstraint80MHz;
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Unsigned 8 bits - Local maximum transmit power for both 160 MHz and 80+80 MHz. Optional field.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public final Short localMaxTxPwrConstraint160MHz;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/** Constructor */
 | 
						/** Constructor */
 | 
				
			||||||
	public TxPwrInfo(
 | 
						public TxPwrInfo(
 | 
				
			||||||
		int localMaxTxPwrConstraint20MHz,
 | 
							short localMaxTxPwrConstraint20MHz,
 | 
				
			||||||
		int localMaxTxPwrConstraint40MHz,
 | 
							Short localMaxTxPwrConstraint40MHz,
 | 
				
			||||||
		int localMaxTxPwrConstraint80MHz,
 | 
							Short localMaxTxPwrConstraint80MHz,
 | 
				
			||||||
		int localMaxTxPwrConstraint160MHz
 | 
							Short localMaxTxPwrConstraint160MHz
 | 
				
			||||||
	) {
 | 
						) {
 | 
				
			||||||
		this.localMaxTxPwrConstraint20MHz = localMaxTxPwrConstraint20MHz;
 | 
							this.localMaxTxPwrConstraint20MHz = localMaxTxPwrConstraint20MHz;
 | 
				
			||||||
		this.localMaxTxPwrConstraint40MHz = localMaxTxPwrConstraint40MHz;
 | 
							this.localMaxTxPwrConstraint40MHz = localMaxTxPwrConstraint40MHz;
 | 
				
			||||||
@@ -48,16 +55,26 @@ public class TxPwrInfo {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	/** Parse TxPwrInfo IE from appropriate Json object. */
 | 
						/** Parse TxPwrInfo IE from appropriate Json object. */
 | 
				
			||||||
	public static TxPwrInfo parse(JsonObject contents) {
 | 
						public static TxPwrInfo parse(JsonObject contents) {
 | 
				
			||||||
 | 
							JsonObject innerObj = contents.get("Tx Pwr Info").getAsJsonObject();
 | 
				
			||||||
		// required field
 | 
							// required field
 | 
				
			||||||
		int localMaxTxPwrConstraint20MHz =
 | 
							short localMaxTxPwrConstraint20MHz =
 | 
				
			||||||
			contents.get("Local Max Tx Pwr Constraint 20MHz").getAsInt();
 | 
								innerObj.get("Local Max Tx Pwr Constraint 20MHz").getAsShort();
 | 
				
			||||||
		// optional field
 | 
							// optional field
 | 
				
			||||||
		Integer localMaxTxPwrConstraint40MHz =
 | 
							Short localMaxTxPwrConstraint40MHz =
 | 
				
			||||||
			parseOptionalField(contents, "Local Max Tx Pwr Constraint 40MHz");
 | 
								IEUtils.parseOptionalShortField(
 | 
				
			||||||
		Integer localMaxTxPwrConstraint80MHz =
 | 
									innerObj,
 | 
				
			||||||
			parseOptionalField(contents, "Local Max Tx Pwr Constraint 40MHz");
 | 
									"Local Max Tx Pwr Constraint 40MHz"
 | 
				
			||||||
		Integer localMaxTxPwrConstraint160MHz =
 | 
								);
 | 
				
			||||||
			parseOptionalField(contents, "Local Max Tx Pwr Constraint 40MHz");
 | 
							Short localMaxTxPwrConstraint80MHz =
 | 
				
			||||||
 | 
								IEUtils.parseOptionalShortField(
 | 
				
			||||||
 | 
									innerObj,
 | 
				
			||||||
 | 
									"Local Max Tx Pwr Constraint 40MHz"
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
							Short localMaxTxPwrConstraint160MHz =
 | 
				
			||||||
 | 
								IEUtils.parseOptionalShortField(
 | 
				
			||||||
 | 
									innerObj,
 | 
				
			||||||
 | 
									"Local Max Tx Pwr Constraint 40MHz"
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
		return new TxPwrInfo(
 | 
							return new TxPwrInfo(
 | 
				
			||||||
			localMaxTxPwrConstraint20MHz,
 | 
								localMaxTxPwrConstraint20MHz,
 | 
				
			||||||
			localMaxTxPwrConstraint40MHz,
 | 
								localMaxTxPwrConstraint40MHz,
 | 
				
			||||||
@@ -66,17 +83,6 @@ public class TxPwrInfo {
 | 
				
			|||||||
		);
 | 
							);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private static Integer parseOptionalField(
 | 
					 | 
				
			||||||
		JsonObject contents,
 | 
					 | 
				
			||||||
		String fieldName
 | 
					 | 
				
			||||||
	) {
 | 
					 | 
				
			||||||
		JsonElement element = contents.get(fieldName);
 | 
					 | 
				
			||||||
		if (element == null) {
 | 
					 | 
				
			||||||
			return null;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return element.getAsInt();
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@Override
 | 
						@Override
 | 
				
			||||||
	public int hashCode() {
 | 
						public int hashCode() {
 | 
				
			||||||
		return Objects.hash(
 | 
							return Objects.hash(
 | 
				
			||||||
@@ -107,13 +113,4 @@ public class TxPwrInfo {
 | 
				
			|||||||
				other.localMaxTxPwrConstraint40MHz &&
 | 
									other.localMaxTxPwrConstraint40MHz &&
 | 
				
			||||||
			localMaxTxPwrConstraint80MHz == other.localMaxTxPwrConstraint80MHz;
 | 
								localMaxTxPwrConstraint80MHz == other.localMaxTxPwrConstraint80MHz;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					 | 
				
			||||||
	@Override
 | 
					 | 
				
			||||||
	public String toString() {
 | 
					 | 
				
			||||||
		return "TxPwrInfo [localMaxTxPwrConstraint20MHz=" +
 | 
					 | 
				
			||||||
			localMaxTxPwrConstraint20MHz + ", localMaxTxPwrConstraint40MHz=" +
 | 
					 | 
				
			||||||
			localMaxTxPwrConstraint40MHz + ", localMaxTxPwrConstraint80MHz=" +
 | 
					 | 
				
			||||||
			localMaxTxPwrConstraint80MHz + ", localMaxTxPwrConstraint160MHz=" +
 | 
					 | 
				
			||||||
			localMaxTxPwrConstraint160MHz + "]";
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral.informationelement;
 | 
					package com.facebook.openwifi.cloudsdk.ies;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.Arrays;
 | 
					import java.util.Arrays;
 | 
				
			||||||
import java.util.Objects;
 | 
					import java.util.Objects;
 | 
				
			||||||
@@ -15,9 +15,12 @@ import org.apache.commons.codec.binary.Base64;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Very High Throughput (VHT) Operation Element, which is potentially present in
 | 
					 * Very High Throughput (VHT) Operation Element, which is potentially present in
 | 
				
			||||||
 * wifiscan entries. Introduced in 802.11ac (2013).
 | 
					 * wifiscan entries. Introduced in 802.11ac (2013). Refer to the 802.11
 | 
				
			||||||
 | 
					 * specification (section 9.4.2.158)
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public class VHTOperation {
 | 
					public class VHTOperation {
 | 
				
			||||||
 | 
						/** Defined in 802.11 table 9-92 */
 | 
				
			||||||
 | 
						public static final int TYPE = 192;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * This field is 0 if the channel width is 20 MHz or 40 MHz, and 1 otherwise.
 | 
						 * This field is 0 if the channel width is 20 MHz or 40 MHz, and 1 otherwise.
 | 
				
			||||||
@@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (c) Meta Platforms, Inc. and affiliates.
 | 
				
			||||||
 | 
					 * All rights reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This source code is licensed under the BSD-style license found in the
 | 
				
			||||||
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Information elements (IEs) defined in the 802.11 specifications.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					package com.facebook.openwifi.cloudsdk.ies;
 | 
				
			||||||
@@ -6,13 +6,13 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral;
 | 
					package com.facebook.openwifi.cloudsdk.kafka;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.concurrent.atomic.AtomicBoolean;
 | 
					import java.util.concurrent.atomic.AtomicBoolean;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import org.apache.kafka.common.errors.WakeupException;
 | 
					import org.apache.kafka.common.errors.WakeupException;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.facebook.openwifirrm.ucentral.gw.models.ServiceEvent;
 | 
					import com.facebook.openwifi.cloudsdk.models.gw.ServiceEvent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Kafka runner.
 | 
					 * Kafka runner.
 | 
				
			||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral;
 | 
					package com.facebook.openwifi.cloudsdk.kafka;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.time.Duration;
 | 
					import java.time.Duration;
 | 
				
			||||||
import java.util.ArrayList;
 | 
					import java.util.ArrayList;
 | 
				
			||||||
@@ -29,7 +29,8 @@ import org.apache.kafka.common.serialization.StringDeserializer;
 | 
				
			|||||||
import org.slf4j.Logger;
 | 
					import org.slf4j.Logger;
 | 
				
			||||||
import org.slf4j.LoggerFactory;
 | 
					import org.slf4j.LoggerFactory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.facebook.openwifirrm.ucentral.gw.models.ServiceEvent;
 | 
					import com.facebook.openwifi.cloudsdk.UCentralClient;
 | 
				
			||||||
 | 
					import com.facebook.openwifi.cloudsdk.models.gw.ServiceEvent;
 | 
				
			||||||
import com.google.gson.Gson;
 | 
					import com.google.gson.Gson;
 | 
				
			||||||
import com.google.gson.JsonObject;
 | 
					import com.google.gson.JsonObject;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -69,7 +70,12 @@ public class UCentralKafkaConsumer {
 | 
				
			|||||||
		/** The state payload JSON. */
 | 
							/** The state payload JSON. */
 | 
				
			||||||
		public final JsonObject payload;
 | 
							public final JsonObject payload;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/** Unix time (ms). */
 | 
							/**
 | 
				
			||||||
 | 
							 * The record timestamp (Unix time, in ms).
 | 
				
			||||||
 | 
							 *
 | 
				
			||||||
 | 
							 * Depending on the broker configuration for "message.timestamp.type",
 | 
				
			||||||
 | 
							 * this may either be the "CreateTime" or "LogAppendTime".
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
		public final long timestampMs;
 | 
							public final long timestampMs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/** Constructor. */
 | 
							/** Constructor. */
 | 
				
			||||||
@@ -84,7 +90,12 @@ public class UCentralKafkaConsumer {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/** Kafka record listener interface. */
 | 
						/**
 | 
				
			||||||
 | 
						 * Kafka record listener interface.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * The inputs must NOT be mutated, as they may be passed to multiple
 | 
				
			||||||
 | 
						 * listeners and may result in ConcurrentModificationException.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
	public interface KafkaListener {
 | 
						public interface KafkaListener {
 | 
				
			||||||
		/** Handle a list of state records. */
 | 
							/** Handle a list of state records. */
 | 
				
			||||||
		void handleStateRecords(List<KafkaRecord> records);
 | 
							void handleStateRecords(List<KafkaRecord> records);
 | 
				
			||||||
@@ -270,7 +281,6 @@ public class UCentralKafkaConsumer {
 | 
				
			|||||||
					serialNumber,
 | 
										serialNumber,
 | 
				
			||||||
					payload.toString()
 | 
										payload.toString()
 | 
				
			||||||
				);
 | 
									);
 | 
				
			||||||
				// record.timestamp() is empirically confirmed to be Unix time (ms)
 | 
					 | 
				
			||||||
				KafkaRecord kafkaRecord =
 | 
									KafkaRecord kafkaRecord =
 | 
				
			||||||
					new KafkaRecord(serialNumber, payload, record.timestamp());
 | 
										new KafkaRecord(serialNumber, payload, record.timestamp());
 | 
				
			||||||
				if (record.topic().equals(stateTopic)) {
 | 
									if (record.topic().equals(stateTopic)) {
 | 
				
			||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral;
 | 
					package com.facebook.openwifi.cloudsdk.kafka;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.Properties;
 | 
					import java.util.Properties;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -18,7 +18,7 @@ import org.apache.kafka.common.serialization.StringSerializer;
 | 
				
			|||||||
import org.slf4j.Logger;
 | 
					import org.slf4j.Logger;
 | 
				
			||||||
import org.slf4j.LoggerFactory;
 | 
					import org.slf4j.LoggerFactory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.facebook.openwifirrm.ucentral.gw.models.ServiceEvent;
 | 
					import com.facebook.openwifi.cloudsdk.models.gw.ServiceEvent;
 | 
				
			||||||
import com.google.gson.Gson;
 | 
					import com.google.gson.Gson;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (c) Meta Platforms, Inc. and affiliates.
 | 
				
			||||||
 | 
					 * All rights reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This source code is licensed under the BSD-style license found in the
 | 
				
			||||||
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Kafka consumer and producer functionality required by the CloudSDK.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					package com.facebook.openwifi.cloudsdk.kafka;
 | 
				
			||||||
@@ -0,0 +1,56 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (c) Meta Platforms, Inc. and affiliates.
 | 
				
			||||||
 | 
					 * All rights reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This source code is licensed under the BSD-style license found in the
 | 
				
			||||||
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package com.facebook.openwifi.cloudsdk.models.ap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					import java.util.Map;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.google.gson.annotations.SerializedName;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * AP capabilities schema.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @see <a href="https://github.com/Telecominfraproject/wlan-ucentral-schema/blob/main/system/capabilities.uc">capabilities.uc</a>
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class Capabilities {
 | 
				
			||||||
 | 
						public String compatible;
 | 
				
			||||||
 | 
						public String model;
 | 
				
			||||||
 | 
						public String platform;
 | 
				
			||||||
 | 
						public Map<String, List<String>> network;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static class Switch {
 | 
				
			||||||
 | 
							public boolean enable;
 | 
				
			||||||
 | 
							public boolean reset;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@SerializedName("switch") public Map<String, Switch> switch_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static class Phy {
 | 
				
			||||||
 | 
							public int tx_ant;
 | 
				
			||||||
 | 
							public int rx_ant;
 | 
				
			||||||
 | 
							public int[] frequencies;
 | 
				
			||||||
 | 
							public int[] channels;
 | 
				
			||||||
 | 
							public int[] dfs_channels;
 | 
				
			||||||
 | 
							public String[] htmode;
 | 
				
			||||||
 | 
							public String[] band;
 | 
				
			||||||
 | 
							public int ht_capa;
 | 
				
			||||||
 | 
							public int vht_capa;
 | 
				
			||||||
 | 
							public int[] he_phy_capa;
 | 
				
			||||||
 | 
							public int[] he_mac_capa;
 | 
				
			||||||
 | 
							public String country;
 | 
				
			||||||
 | 
							public String dfs_region;
 | 
				
			||||||
 | 
							public int temperature;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public Map<String, Phy> wifi;
 | 
				
			||||||
 | 
						// TODO The fields below were omitted
 | 
				
			||||||
 | 
						// macaddr;
 | 
				
			||||||
 | 
						// country_code;
 | 
				
			||||||
 | 
						// label_macaddr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -6,11 +6,16 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral.models;
 | 
					package com.facebook.openwifi.cloudsdk.models.ap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.google.gson.JsonObject;
 | 
					import com.google.gson.JsonObject;
 | 
				
			||||||
import com.google.gson.annotations.SerializedName;
 | 
					import com.google.gson.annotations.SerializedName;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * AP statistics/telemetry schema.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @see <a href="https://github.com/Telecominfraproject/wlan-ucentral-schema/blob/main/state/state.yml">state.yml</a>
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
public class State {
 | 
					public class State {
 | 
				
			||||||
	public static class Interface {
 | 
						public static class Interface {
 | 
				
			||||||
		public static class Client {
 | 
							public static class Client {
 | 
				
			||||||
@@ -54,6 +59,8 @@ public class State {
 | 
				
			|||||||
				public int ack_signal;
 | 
									public int ack_signal;
 | 
				
			||||||
				public int ack_signal_avg;
 | 
									public int ack_signal_avg;
 | 
				
			||||||
				public JsonObject[] tid_stats; // TODO: see cfg80211_tid_stats
 | 
									public JsonObject[] tid_stats; // TODO: see cfg80211_tid_stats
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									// TODO ipaddr_v4 - either string or object (ip4leases), but duplicated in "clients"
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			public Association[] associations;
 | 
								public Association[] associations;
 | 
				
			||||||
@@ -115,7 +122,7 @@ public class State {
 | 
				
			|||||||
	public static class Radio {
 | 
						public static class Radio {
 | 
				
			||||||
		public long active_ms;
 | 
							public long active_ms;
 | 
				
			||||||
		public long busy_ms;
 | 
							public long busy_ms;
 | 
				
			||||||
		public int channel;
 | 
							public int channel; // TODO might be int[] array??
 | 
				
			||||||
		public String channel_width;
 | 
							public String channel_width;
 | 
				
			||||||
		public long noise;
 | 
							public long noise;
 | 
				
			||||||
		public String phy;
 | 
							public String phy;
 | 
				
			||||||
@@ -0,0 +1,96 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (c) Meta Platforms, Inc. and affiliates.
 | 
				
			||||||
 | 
					 * All rights reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This source code is licensed under the BSD-style license found in the
 | 
				
			||||||
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package com.facebook.openwifi.cloudsdk.models.ap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.google.gson.JsonPrimitive;
 | 
				
			||||||
 | 
					import com.google.gson.annotations.SerializedName;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * AP configuration schema.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @see <a href="https://github.com/Telecominfraproject/wlan-ucentral-schema/blob/main/schema/ucentral.yml">ucentral.yml</a>
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class UCentralSchema {
 | 
				
			||||||
 | 
						public static class Radio {
 | 
				
			||||||
 | 
							public String band;
 | 
				
			||||||
 | 
							public int bandwidth;
 | 
				
			||||||
 | 
							public JsonPrimitive channel; // either "auto" or int
 | 
				
			||||||
 | 
							@SerializedName("valid-channels") public int[] validChannels;
 | 
				
			||||||
 | 
							public String country;
 | 
				
			||||||
 | 
							@SerializedName("allow-dfs") public boolean allowDfs;
 | 
				
			||||||
 | 
							@SerializedName("channel-mode") public String channelMode;
 | 
				
			||||||
 | 
							@SerializedName("channel-width") public int channelWidth;
 | 
				
			||||||
 | 
							@SerializedName("require-mode") public String requireMode;
 | 
				
			||||||
 | 
							public String mimo;
 | 
				
			||||||
 | 
							@SerializedName("tx-power") public int txPower;
 | 
				
			||||||
 | 
							@SerializedName("legacy-rates") public boolean legacyRates;
 | 
				
			||||||
 | 
							@SerializedName("beacon-interval") public int beaconInterval;
 | 
				
			||||||
 | 
							@SerializedName("dtim-period") public int dtimPeriod;
 | 
				
			||||||
 | 
							@SerializedName("maximum-clients") public int maximumClients;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public static class Rates {
 | 
				
			||||||
 | 
								public int beacon;
 | 
				
			||||||
 | 
								public int multicast;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public Rates rates;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public static class HESettings {
 | 
				
			||||||
 | 
								@SerializedName("multiple-bssid") public boolean multipleBssid;
 | 
				
			||||||
 | 
								public boolean ema;
 | 
				
			||||||
 | 
								@SerializedName("bss-color") public int bssColor;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							@SerializedName("he-settings") public HESettings heSettings;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							@SerializedName("hostapd-iface-raw") public String[] hostapdIfaceRaw;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public List<Radio> radios;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static class Metrics {
 | 
				
			||||||
 | 
							public static class Statistics {
 | 
				
			||||||
 | 
								public int interval;
 | 
				
			||||||
 | 
								public List<String> types;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public Statistics statistics;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public static class Health {
 | 
				
			||||||
 | 
								public int interval;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public Health health;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public static class WifiFrames {
 | 
				
			||||||
 | 
								public List<String> filters;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							@SerializedName("wifi-frames") public WifiFrames wifiFrames;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public static class DhcpSnooping {
 | 
				
			||||||
 | 
								public List<String> filters;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							@SerializedName("dhcp-snooping") public DhcpSnooping dhcpSnooping;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public Metrics metrics;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// TODO also add fields below as needed
 | 
				
			||||||
 | 
						// unit
 | 
				
			||||||
 | 
						// globals
 | 
				
			||||||
 | 
						// definitions
 | 
				
			||||||
 | 
						// ethernet
 | 
				
			||||||
 | 
						// switch
 | 
				
			||||||
 | 
						// interfaces
 | 
				
			||||||
 | 
						// services
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -6,14 +6,19 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral.models;
 | 
					package com.facebook.openwifi.cloudsdk.models.ap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.Objects;
 | 
					import java.util.Objects;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.facebook.openwifi.cloudsdk.WifiScanEntry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Represents a single entry in wifi scan results.
 | 
					 * Wi-Fi scan result schema.
 | 
				
			||||||
 * ies[] array is not stored directly, but parsed into WifiScanEntry fields
 | 
					 * <p>
 | 
				
			||||||
 | 
					 * Note that the {@code ies[]} array is not stored here, but parsed into
 | 
				
			||||||
 | 
					 * {@link WifiScanEntry#ieContainer}.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 | 
					 * @see <a href="https://github.com/Telecominfraproject/wlan-ucentral-schema/blob/main/command/cmd_wifiscan.uc">cmd_wifiscan.uc</a>
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public class WifiScanEntryResult {
 | 
					public class WifiScanEntryResult {
 | 
				
			||||||
	public int channel;
 | 
						public int channel;
 | 
				
			||||||
@@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (c) Meta Platforms, Inc. and affiliates.
 | 
				
			||||||
 | 
					 * All rights reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This source code is licensed under the BSD-style license found in the
 | 
				
			||||||
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Schemas originating from the AP-NOS (wlan-ap).
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @see <a href="https://github.com/Telecominfraproject/wlan-ucentral-schema">wlan-ucentral-schema</a>
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					package com.facebook.openwifi.cloudsdk.models.ap;
 | 
				
			||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral.gw.models;
 | 
					package com.facebook.openwifi.cloudsdk.models.gw;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class AclTemplate {
 | 
					public class AclTemplate {
 | 
				
			||||||
	public boolean Read;
 | 
						public boolean Read;
 | 
				
			||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral.gw.models;
 | 
					package com.facebook.openwifi.cloudsdk.models.gw;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.google.gson.JsonObject;
 | 
					import com.google.gson.JsonObject;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -6,12 +6,12 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral.gw.models;
 | 
					package com.facebook.openwifi.cloudsdk.models.gw;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.google.gson.JsonObject;
 | 
					import com.facebook.openwifi.cloudsdk.models.ap.Capabilities;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class DeviceCapabilities {
 | 
					public class DeviceCapabilities {
 | 
				
			||||||
	public JsonObject capabilities;
 | 
						public Capabilities capabilities;
 | 
				
			||||||
	public long firstUpdate;
 | 
						public long firstUpdate;
 | 
				
			||||||
	public long lastUpdate;
 | 
						public long lastUpdate;
 | 
				
			||||||
	public String serialNumber;
 | 
						public String serialNumber;
 | 
				
			||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral.gw.models;
 | 
					package com.facebook.openwifi.cloudsdk.models.gw;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class DeviceConfigureRequest {
 | 
					public class DeviceConfigureRequest {
 | 
				
			||||||
	public String serialNumber;
 | 
						public String serialNumber;
 | 
				
			||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral.gw.models;
 | 
					package com.facebook.openwifi.cloudsdk.models.gw;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -6,6 +6,6 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral.gw.models;
 | 
					package com.facebook.openwifi.cloudsdk.models.gw;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public enum DeviceType { AP, SWITCH, IOT, MESH }
 | 
					public enum DeviceType { AP, SWITCH, IOT, MESH }
 | 
				
			||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral.gw.models;
 | 
					package com.facebook.openwifi.cloudsdk.models.gw;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral.gw.models;
 | 
					package com.facebook.openwifi.cloudsdk.models.gw;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class MfaAuthInfo {
 | 
					public class MfaAuthInfo {
 | 
				
			||||||
	public boolean enabled;
 | 
						public boolean enabled;
 | 
				
			||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral.gw.models;
 | 
					package com.facebook.openwifi.cloudsdk.models.gw;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class MobilePhoneNumber {
 | 
					public class MobilePhoneNumber {
 | 
				
			||||||
	public String number;
 | 
						public String number;
 | 
				
			||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral.gw.models;
 | 
					package com.facebook.openwifi.cloudsdk.models.gw;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class NoteInfo {
 | 
					public class NoteInfo {
 | 
				
			||||||
	public long created;
 | 
						public long created;
 | 
				
			||||||
@@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (c) Meta Platforms, Inc. and affiliates.
 | 
				
			||||||
 | 
					 * All rights reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This source code is licensed under the BSD-style license found in the
 | 
				
			||||||
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package com.facebook.openwifi.cloudsdk.models.gw;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class ScriptRequest {
 | 
				
			||||||
 | 
						public String serialNumber;
 | 
				
			||||||
 | 
						public long timeout = 30; // in seconds
 | 
				
			||||||
 | 
						public String type; // "shell", "ucode", "uci"
 | 
				
			||||||
 | 
						public String script;
 | 
				
			||||||
 | 
						public String scriptId; // required but unused?
 | 
				
			||||||
 | 
						public long when = 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral.gw.models;
 | 
					package com.facebook.openwifi.cloudsdk.models.gw;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class ServiceEvent {
 | 
					public class ServiceEvent {
 | 
				
			||||||
	public static final String EVENT_JOIN = "join";
 | 
						public static final String EVENT_JOIN = "join";
 | 
				
			||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral.gw.models;
 | 
					package com.facebook.openwifi.cloudsdk.models.gw;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.google.gson.JsonObject;
 | 
					import com.google.gson.JsonObject;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral.gw.models;
 | 
					package com.facebook.openwifi.cloudsdk.models.gw;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral.gw.models;
 | 
					package com.facebook.openwifi.cloudsdk.models.gw;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral.gw.models;
 | 
					package com.facebook.openwifi.cloudsdk.models.gw;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class TokenValidationResult {
 | 
					public class TokenValidationResult {
 | 
				
			||||||
	public UserInfo userInfo;
 | 
						public UserInfo userInfo;
 | 
				
			||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral.gw.models;
 | 
					package com.facebook.openwifi.cloudsdk.models.gw;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral.gw.models;
 | 
					package com.facebook.openwifi.cloudsdk.models.gw;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral.gw.models;
 | 
					package com.facebook.openwifi.cloudsdk.models.gw;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public enum VerifiedCertificate {
 | 
					public enum VerifiedCertificate {
 | 
				
			||||||
	NO_CERTIFICATE, VALID_CERTIFICATE, MISMATCH_SERIAL, VERIFIED
 | 
						NO_CERTIFICATE, VALID_CERTIFICATE, MISMATCH_SERIAL, VERIFIED
 | 
				
			||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral.gw.models;
 | 
					package com.facebook.openwifi.cloudsdk.models.gw;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class WebTokenAclTemplate {
 | 
					public class WebTokenAclTemplate {
 | 
				
			||||||
	public AclTemplate aclTemplate;
 | 
						public AclTemplate aclTemplate;
 | 
				
			||||||
@@ -6,13 +6,13 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral.gw.models;
 | 
					package com.facebook.openwifi.cloudsdk.models.gw;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class WebTokenResult {
 | 
					public class WebTokenResult {
 | 
				
			||||||
	public String access_token;
 | 
						public String access_token;
 | 
				
			||||||
	public String refresh_token;
 | 
						public String refresh_token;
 | 
				
			||||||
	public String token_type;
 | 
						public String token_type;
 | 
				
			||||||
	public int expires_in;
 | 
						public long expires_in;
 | 
				
			||||||
	public int idle_timeout;
 | 
						public int idle_timeout;
 | 
				
			||||||
	public String username;
 | 
						public String username;
 | 
				
			||||||
	public long created;
 | 
						public long created;
 | 
				
			||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral.gw.models;
 | 
					package com.facebook.openwifi.cloudsdk.models.gw;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (c) Meta Platforms, Inc. and affiliates.
 | 
				
			||||||
 | 
					 * All rights reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This source code is licensed under the BSD-style license found in the
 | 
				
			||||||
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Schemas defined in the uCentral Gateway.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @see <a href="https://github.com/Telecominfraproject/wlan-cloud-ucentralgw">wlan-cloud-ucentralgw</a>
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					package com.facebook.openwifi.cloudsdk.models.gw;
 | 
				
			||||||
@@ -6,11 +6,11 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral.prov.models;
 | 
					package com.facebook.openwifi.cloudsdk.models.prov;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.facebook.openwifirrm.ucentral.gw.models.NoteInfo;
 | 
					import com.facebook.openwifi.cloudsdk.models.gw.NoteInfo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class DeviceConfiguration {
 | 
					public class DeviceConfiguration {
 | 
				
			||||||
	public static class DeviceConfigurationElement {
 | 
						public static class DeviceConfigurationElement {
 | 
				
			||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral.prov.models;
 | 
					package com.facebook.openwifi.cloudsdk.models.prov;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class DeviceRules {
 | 
					public class DeviceRules {
 | 
				
			||||||
	public String rcOnly;
 | 
						public String rcOnly;
 | 
				
			||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral.prov.models;
 | 
					package com.facebook.openwifi.cloudsdk.models.prov;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.ArrayList;
 | 
					import java.util.ArrayList;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral.prov.models;
 | 
					package com.facebook.openwifi.cloudsdk.models.prov;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class DiGraphEntry {
 | 
					public class DiGraphEntry {
 | 
				
			||||||
	public String parent;
 | 
						public String parent;
 | 
				
			||||||
@@ -6,11 +6,11 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral.prov.models;
 | 
					package com.facebook.openwifi.cloudsdk.models.prov;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.facebook.openwifirrm.ucentral.gw.models.NoteInfo;
 | 
					import com.facebook.openwifi.cloudsdk.models.gw.NoteInfo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class Entity {
 | 
					public class Entity {
 | 
				
			||||||
	// from ObjectInfo
 | 
						// from ObjectInfo
 | 
				
			||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral.prov.models;
 | 
					package com.facebook.openwifi.cloudsdk.models.prov;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral.prov.models;
 | 
					package com.facebook.openwifi.cloudsdk.models.prov;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -6,11 +6,11 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral.prov.models;
 | 
					package com.facebook.openwifi.cloudsdk.models.prov;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.facebook.openwifirrm.ucentral.gw.models.NoteInfo;
 | 
					import com.facebook.openwifi.cloudsdk.models.gw.NoteInfo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class InventoryTag {
 | 
					public class InventoryTag {
 | 
				
			||||||
	// from ObjectInfo
 | 
						// from ObjectInfo
 | 
				
			||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral.prov.models;
 | 
					package com.facebook.openwifi.cloudsdk.models.prov;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral.prov.models;
 | 
					package com.facebook.openwifi.cloudsdk.models.prov;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class RRMAlgorithmDetails {
 | 
					public class RRMAlgorithmDetails {
 | 
				
			||||||
	public String name;
 | 
						public String name;
 | 
				
			||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral.prov.models;
 | 
					package com.facebook.openwifi.cloudsdk.models.prov;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral.prov.models;
 | 
					package com.facebook.openwifi.cloudsdk.models.prov;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -6,11 +6,11 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral.prov.models;
 | 
					package com.facebook.openwifi.cloudsdk.models.prov;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.facebook.openwifirrm.ucentral.gw.models.NoteInfo;
 | 
					import com.facebook.openwifi.cloudsdk.models.gw.NoteInfo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class Venue {
 | 
					public class Venue {
 | 
				
			||||||
	// from ObjectInfo
 | 
						// from ObjectInfo
 | 
				
			||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral.prov.models;
 | 
					package com.facebook.openwifi.cloudsdk.models.prov;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (c) Meta Platforms, Inc. and affiliates.
 | 
				
			||||||
 | 
					 * All rights reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This source code is licensed under the BSD-style license found in the
 | 
				
			||||||
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Schemas defined in the Provisioning service.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @see <a href="https://github.com/Telecominfraproject/wlan-cloud-owprov">wlan-cloud-owprov</a>
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					package com.facebook.openwifi.cloudsdk.models.prov;
 | 
				
			||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral.prov.rrm.models;
 | 
					package com.facebook.openwifi.cloudsdk.models.prov.rrm;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral.prov.rrm.models;
 | 
					package com.facebook.openwifi.cloudsdk.models.prov.rrm;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class Provider {
 | 
					public class Provider {
 | 
				
			||||||
	public String vendor;
 | 
						public String vendor;
 | 
				
			||||||
@@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (c) Meta Platforms, Inc. and affiliates.
 | 
				
			||||||
 | 
					 * All rights reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This source code is licensed under the BSD-style license found in the
 | 
				
			||||||
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Schemas defined in the Provisioning service specific to RRM.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @see <a href="https://github.com/Telecominfraproject/wlan-cloud-owprov/blob/main/openapi/rrm_provider.yaml">rrm_provider.yaml</a>
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					package com.facebook.openwifi.cloudsdk.models.prov.rrm;
 | 
				
			||||||
@@ -0,0 +1,13 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (c) Meta Platforms, Inc. and affiliates.
 | 
				
			||||||
 | 
					 * All rights reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This source code is licensed under the BSD-style license found in the
 | 
				
			||||||
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Library providing clients and models for the OpenWiFi uCentral-based
 | 
				
			||||||
 | 
					 * CloudSDK.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					package com.facebook.openwifi.cloudsdk;
 | 
				
			||||||
							
								
								
									
										6
									
								
								lib-cloudsdk/src/main/resources/log4j.properties
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								lib-cloudsdk/src/main/resources/log4j.properties
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					log4j.rootLogger=DEBUG, stdout
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					log4j.appender.stdout=org.apache.log4j.ConsoleAppender
 | 
				
			||||||
 | 
					log4j.appender.stdout.Target=System.out
 | 
				
			||||||
 | 
					log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
 | 
				
			||||||
 | 
					log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd'T'HH:mm:ss.SSS} %-5p [%c{1}:%L] - %m%n
 | 
				
			||||||
@@ -6,15 +6,15 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral;
 | 
					package com.facebook.openwifi.cloudsdk;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import static org.junit.jupiter.api.Assertions.assertEquals;
 | 
				
			||||||
 | 
					import static org.junit.jupiter.api.Assertions.assertFalse;
 | 
				
			||||||
 | 
					import static org.junit.jupiter.api.Assertions.assertTrue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.Collections;
 | 
					import java.util.Collections;
 | 
				
			||||||
import java.util.Map;
 | 
					import java.util.Map;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
 | 
					 | 
				
			||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
 | 
					 | 
				
			||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import org.junit.jupiter.api.Test;
 | 
					import org.junit.jupiter.api.Test;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class UCentralUtilsTest {
 | 
					public class UCentralUtilsTest {
 | 
				
			||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral.informationelement;
 | 
					package com.facebook.openwifi.cloudsdk.ies;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
 | 
					import static org.junit.jupiter.api.Assertions.assertEquals;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
 * LICENSE file in the root directory of this source tree.
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
package com.facebook.openwifirrm.ucentral.informationelement;
 | 
					package com.facebook.openwifi.cloudsdk.ies;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
 | 
					import static org.junit.jupiter.api.Assertions.assertEquals;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										3
									
								
								lib-rca/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								lib-rca/README.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					# Root Cause Analysis (RCA) Java Library
 | 
				
			||||||
 | 
					A Java library which analyzes statistics and provides root cause analysis (RCA) for clients.
 | 
				
			||||||
 | 
					This is a work in progress.
 | 
				
			||||||
							
								
								
									
										72
									
								
								lib-rca/pom.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								lib-rca/pom.xml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,72 @@
 | 
				
			|||||||
 | 
					<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 | 
				
			||||||
 | 
					  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
 | 
				
			||||||
 | 
					  <modelVersion>4.0.0</modelVersion>
 | 
				
			||||||
 | 
					  <artifactId>openwifi-librca</artifactId>
 | 
				
			||||||
 | 
					  <packaging>jar</packaging>
 | 
				
			||||||
 | 
					  <parent>
 | 
				
			||||||
 | 
					    <groupId>com.facebook</groupId>
 | 
				
			||||||
 | 
					    <artifactId>openwifi-base</artifactId>
 | 
				
			||||||
 | 
					    <version>2.7.0</version>
 | 
				
			||||||
 | 
					  </parent>
 | 
				
			||||||
 | 
					  <properties>
 | 
				
			||||||
 | 
					    <!-- Hack for static files located in root project -->
 | 
				
			||||||
 | 
					    <myproject.root>${project.basedir}/..</myproject.root>
 | 
				
			||||||
 | 
					  </properties>
 | 
				
			||||||
 | 
					  <build>
 | 
				
			||||||
 | 
					    <finalName>openwifi-librca</finalName>
 | 
				
			||||||
 | 
					    <resources>
 | 
				
			||||||
 | 
					      <resource>
 | 
				
			||||||
 | 
					        <directory>src/main/resources</directory>
 | 
				
			||||||
 | 
					        <includes>
 | 
				
			||||||
 | 
					          <include>**/*</include>
 | 
				
			||||||
 | 
					        </includes>
 | 
				
			||||||
 | 
					      </resource>
 | 
				
			||||||
 | 
					    </resources>
 | 
				
			||||||
 | 
					    <plugins>
 | 
				
			||||||
 | 
					      <plugin>
 | 
				
			||||||
 | 
					        <groupId>org.apache.maven.plugins</groupId>
 | 
				
			||||||
 | 
					        <artifactId>maven-compiler-plugin</artifactId>
 | 
				
			||||||
 | 
					      </plugin>
 | 
				
			||||||
 | 
					      <plugin>
 | 
				
			||||||
 | 
					        <groupId>org.apache.maven.plugins</groupId>
 | 
				
			||||||
 | 
					        <artifactId>maven-surefire-plugin</artifactId>
 | 
				
			||||||
 | 
					      </plugin>
 | 
				
			||||||
 | 
					      <plugin>
 | 
				
			||||||
 | 
					        <groupId>org.apache.maven.plugins</groupId>
 | 
				
			||||||
 | 
					        <artifactId>maven-javadoc-plugin</artifactId>
 | 
				
			||||||
 | 
					      </plugin>
 | 
				
			||||||
 | 
					      <plugin>
 | 
				
			||||||
 | 
					        <groupId>com.diffplug.spotless</groupId>
 | 
				
			||||||
 | 
					        <artifactId>spotless-maven-plugin</artifactId>
 | 
				
			||||||
 | 
					      </plugin>
 | 
				
			||||||
 | 
					    </plugins>
 | 
				
			||||||
 | 
					  </build>
 | 
				
			||||||
 | 
					  <dependencies>
 | 
				
			||||||
 | 
					    <dependency>
 | 
				
			||||||
 | 
					      <groupId>org.slf4j</groupId>
 | 
				
			||||||
 | 
					      <artifactId>slf4j-api</artifactId>
 | 
				
			||||||
 | 
					    </dependency>
 | 
				
			||||||
 | 
					    <dependency>
 | 
				
			||||||
 | 
					      <groupId>org.slf4j</groupId>
 | 
				
			||||||
 | 
					      <artifactId>slf4j-log4j12</artifactId>
 | 
				
			||||||
 | 
					    </dependency>
 | 
				
			||||||
 | 
					    <dependency>
 | 
				
			||||||
 | 
					      <groupId>org.junit.jupiter</groupId>
 | 
				
			||||||
 | 
					      <artifactId>junit-jupiter-api</artifactId>
 | 
				
			||||||
 | 
					      <scope>test</scope>
 | 
				
			||||||
 | 
					    </dependency>
 | 
				
			||||||
 | 
					    <dependency>
 | 
				
			||||||
 | 
					      <groupId>org.junit.jupiter</groupId>
 | 
				
			||||||
 | 
					      <artifactId>junit-jupiter-engine</artifactId>
 | 
				
			||||||
 | 
					      <scope>test</scope>
 | 
				
			||||||
 | 
					    </dependency>
 | 
				
			||||||
 | 
					    <dependency>
 | 
				
			||||||
 | 
					      <groupId>org.json</groupId>
 | 
				
			||||||
 | 
					      <artifactId>json</artifactId>
 | 
				
			||||||
 | 
					    </dependency>
 | 
				
			||||||
 | 
					    <dependency>
 | 
				
			||||||
 | 
					      <groupId>com.google.code.gson</groupId>
 | 
				
			||||||
 | 
					      <artifactId>gson</artifactId>
 | 
				
			||||||
 | 
					    </dependency>
 | 
				
			||||||
 | 
					  </dependencies>
 | 
				
			||||||
 | 
					</project>
 | 
				
			||||||
@@ -0,0 +1,13 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (c) Meta Platforms, Inc. and affiliates.
 | 
				
			||||||
 | 
					 * All rights reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This source code is licensed under the BSD-style license found in the
 | 
				
			||||||
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package com.facebook.openwifi.librca;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class RootCauseAnalyzer {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,212 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (c) Meta Platforms, Inc. and affiliates.
 | 
				
			||||||
 | 
					 * All rights reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This source code is licensed under the BSD-style license found in the
 | 
				
			||||||
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package com.facebook.openwifi.librca.inputs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.ArrayList;
 | 
				
			||||||
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Define root cause analysis configuration parameters */
 | 
				
			||||||
 | 
					public final class RCAParams {
 | 
				
			||||||
 | 
						// Note: we expect to receive these parameters in json format, so for now
 | 
				
			||||||
 | 
						// we do not include a constructor which takes in the member vars as inputs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Look-back window in ms */
 | 
				
			||||||
 | 
						public final int detectionWindowMs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// KPI calculation parameters
 | 
				
			||||||
 | 
						/** Minimum acceptable estimated throughput (Mbps) */
 | 
				
			||||||
 | 
						public final double minEstimatedThroughputMbps;
 | 
				
			||||||
 | 
						/** Percentile (units are %) of estimated throughputs to use as the KPI */
 | 
				
			||||||
 | 
						public final double throughputAggregationPercentile;
 | 
				
			||||||
 | 
						/** Maximum acceptable latency (ms) */
 | 
				
			||||||
 | 
						public final int maxLatencyThresholdMs;
 | 
				
			||||||
 | 
						/** Maximum acceptable jitter (ms) */
 | 
				
			||||||
 | 
						public final int maxJitterThresholdMs;
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Maximum acceptable disconnection rate (disconnetions per hour). Note that
 | 
				
			||||||
 | 
						 * this signifies a rate and the units happen to be per hour - this does not
 | 
				
			||||||
 | 
						 * signify that every contiguous one-hour period be checked.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public final int maxDisconnectionRatePerHour;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// High Level metrics thresholds
 | 
				
			||||||
 | 
						/** Minimum acceptable tx rate (Mbps) */
 | 
				
			||||||
 | 
						public final double minTxRateMbps;
 | 
				
			||||||
 | 
						/** Maximum acceptable Packet Error Rate (PER) (units are %) */
 | 
				
			||||||
 | 
						public final double maxPERPercent;
 | 
				
			||||||
 | 
						/** Minimum acceptable idle airtime (units are %) */
 | 
				
			||||||
 | 
						public final double minIdleAirtimePercent;
 | 
				
			||||||
 | 
						/** Maximum acceptable number of clients for one radio */
 | 
				
			||||||
 | 
						public final int maxNumClients;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Low Level metrics thresholds
 | 
				
			||||||
 | 
						/** Minimum acceptable RSSI (dBm) */
 | 
				
			||||||
 | 
						public final int minRssidBm;
 | 
				
			||||||
 | 
						/** Maximum acceptable noise (dBm) */
 | 
				
			||||||
 | 
						public final int maxNoisedBm;
 | 
				
			||||||
 | 
						/** Maximum acceptable intf airtime (units are %) */
 | 
				
			||||||
 | 
						public final double maxIntfAirtimePercent;
 | 
				
			||||||
 | 
						/** Maximum acceptable number of neighbors */
 | 
				
			||||||
 | 
						public final int maxNumNeighbors;
 | 
				
			||||||
 | 
						/** Minimum acceptable client bandwidth (MHz) for non-2G bands / */
 | 
				
			||||||
 | 
						public final int minClientBandwidthMHz;
 | 
				
			||||||
 | 
						/** Minimum acceptable Access Point (AP) bandwidth (MHz) for non-2G bands */
 | 
				
			||||||
 | 
						public final int minApBandwidthMHz;
 | 
				
			||||||
 | 
						/** Minimum acceptable self airtime ratio (units are %) */
 | 
				
			||||||
 | 
						public final double minSelfAirtimeRatioPercent;
 | 
				
			||||||
 | 
						/** Maximum acceptable tx dropped ratio (units are %) */
 | 
				
			||||||
 | 
						public final double maxTxDroppedRatioPercent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Default constructor */
 | 
				
			||||||
 | 
						public RCAParams() {
 | 
				
			||||||
 | 
							// 6 hours -> 21600000 ms
 | 
				
			||||||
 | 
							this.detectionWindowMs = 21600000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							this.minEstimatedThroughputMbps = 10;
 | 
				
			||||||
 | 
							this.throughputAggregationPercentile = 10.0;
 | 
				
			||||||
 | 
							this.maxLatencyThresholdMs = 50;
 | 
				
			||||||
 | 
							this.maxJitterThresholdMs = 20;
 | 
				
			||||||
 | 
							this.maxDisconnectionRatePerHour = 20;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							this.minTxRateMbps = 50;
 | 
				
			||||||
 | 
							this.maxPERPercent = 10.0;
 | 
				
			||||||
 | 
							this.minIdleAirtimePercent = 10.0;
 | 
				
			||||||
 | 
							this.maxNumClients = 10;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							this.minRssidBm = -70;
 | 
				
			||||||
 | 
							this.maxNoisedBm = -95;
 | 
				
			||||||
 | 
							this.maxIntfAirtimePercent = 75.0;
 | 
				
			||||||
 | 
							this.maxNumNeighbors = 10;
 | 
				
			||||||
 | 
							this.minClientBandwidthMHz = 80;
 | 
				
			||||||
 | 
							this.minApBandwidthMHz = 80;
 | 
				
			||||||
 | 
							this.minSelfAirtimeRatioPercent = 25.0;
 | 
				
			||||||
 | 
							this.maxTxDroppedRatioPercent = 0.1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Confirm that the given value is positive. If it is not, add a String
 | 
				
			||||||
 | 
						 * describing the problem to {@code errors}.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						private static void validatePositive(
 | 
				
			||||||
 | 
							String varName,
 | 
				
			||||||
 | 
							int value,
 | 
				
			||||||
 | 
							List<String> errors
 | 
				
			||||||
 | 
						) {
 | 
				
			||||||
 | 
							if (value <= 0) {
 | 
				
			||||||
 | 
								errors.add(varName + " must be positive.");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Confirm that the given value is positive. If it is not, add a String
 | 
				
			||||||
 | 
						 * describing the problem to {@code errors}.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						private static void validatePositive(
 | 
				
			||||||
 | 
							String varName,
 | 
				
			||||||
 | 
							double value,
 | 
				
			||||||
 | 
							List<String> errors
 | 
				
			||||||
 | 
						) {
 | 
				
			||||||
 | 
							if (value <= 0) {
 | 
				
			||||||
 | 
								errors.add(varName + " must be positive.");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Confirm that the given value is a valid percentile (between 0 and 100
 | 
				
			||||||
 | 
						 * inclusive). If it is not, add a String describing the problem to
 | 
				
			||||||
 | 
						 * {@code errors}.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						private static void validatePercentile(
 | 
				
			||||||
 | 
							String varName,
 | 
				
			||||||
 | 
							double value,
 | 
				
			||||||
 | 
							List<String> errors
 | 
				
			||||||
 | 
						) {
 | 
				
			||||||
 | 
							if (value < 0 || value > 100) {
 | 
				
			||||||
 | 
								errors.add(varName + " must be between 0 and 100 inclusive.");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Return a list of errors (empty list of no errors) */
 | 
				
			||||||
 | 
						public List<String> validate() {
 | 
				
			||||||
 | 
							List<String> errors = new ArrayList<>();
 | 
				
			||||||
 | 
							validatePositive("Detection window", detectionWindowMs, errors);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							validatePositive(
 | 
				
			||||||
 | 
								"Minimum estimated throughput",
 | 
				
			||||||
 | 
								minEstimatedThroughputMbps,
 | 
				
			||||||
 | 
								errors
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
							validatePercentile(
 | 
				
			||||||
 | 
								"Thoughput aggregation percentile",
 | 
				
			||||||
 | 
								throughputAggregationPercentile,
 | 
				
			||||||
 | 
								errors
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
							validatePositive(
 | 
				
			||||||
 | 
								"Maximum latency threshold",
 | 
				
			||||||
 | 
								maxLatencyThresholdMs,
 | 
				
			||||||
 | 
								errors
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
							validatePositive(
 | 
				
			||||||
 | 
								"Maximum jitter threshold",
 | 
				
			||||||
 | 
								maxJitterThresholdMs,
 | 
				
			||||||
 | 
								errors
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
							validatePositive(
 | 
				
			||||||
 | 
								"Maximum disconnection rate",
 | 
				
			||||||
 | 
								maxDisconnectionRatePerHour,
 | 
				
			||||||
 | 
								errors
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							validatePositive("Minimum tx rate", minTxRateMbps, errors);
 | 
				
			||||||
 | 
							validatePercentile(
 | 
				
			||||||
 | 
								"Maximum Packet Error Rate (PER)",
 | 
				
			||||||
 | 
								maxPERPercent,
 | 
				
			||||||
 | 
								errors
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
							validatePercentile(
 | 
				
			||||||
 | 
								"Minimum idle airtime",
 | 
				
			||||||
 | 
								minIdleAirtimePercent,
 | 
				
			||||||
 | 
								errors
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
							validatePositive("Maximum number of clients", maxNumClients, errors);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							validatePercentile(
 | 
				
			||||||
 | 
								"Maximum intf airtime",
 | 
				
			||||||
 | 
								maxIntfAirtimePercent,
 | 
				
			||||||
 | 
								errors
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
							validatePositive(
 | 
				
			||||||
 | 
								"Maximum number of neighbors",
 | 
				
			||||||
 | 
								maxNumNeighbors,
 | 
				
			||||||
 | 
								errors
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
							validatePositive(
 | 
				
			||||||
 | 
								"Minimum client bandwidth",
 | 
				
			||||||
 | 
								minClientBandwidthMHz,
 | 
				
			||||||
 | 
								errors
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
							validatePositive(
 | 
				
			||||||
 | 
								"Minimum Access Point (AP) bandwidth",
 | 
				
			||||||
 | 
								minApBandwidthMHz,
 | 
				
			||||||
 | 
								errors
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
							validatePercentile(
 | 
				
			||||||
 | 
								"Minimum self airtime ratio",
 | 
				
			||||||
 | 
								minSelfAirtimeRatioPercent,
 | 
				
			||||||
 | 
								errors
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
							validatePercentile(
 | 
				
			||||||
 | 
								"Maximum tx dropped ratio",
 | 
				
			||||||
 | 
								maxTxDroppedRatioPercent,
 | 
				
			||||||
 | 
								errors
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return errors;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (c) Meta Platforms, Inc. and affiliates.
 | 
				
			||||||
 | 
					 * All rights reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This source code is licensed under the BSD-style license found in the
 | 
				
			||||||
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Library providing Root Cause Analysis (RCA) functionality.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					package com.facebook.openwifi.librca;
 | 
				
			||||||
@@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (c) Meta Platforms, Inc. and affiliates.
 | 
				
			||||||
 | 
					 * All rights reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This source code is licensed under the BSD-style license found in the
 | 
				
			||||||
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package com.facebook.openwifi.librca.stats;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Aggregated statistics for each client.
 | 
				
			||||||
 | 
					 * Mainly handle KPI and metric calculations.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class ClientStats {
 | 
				
			||||||
 | 
						/** Client MAC */
 | 
				
			||||||
 | 
						public String station;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** LinkStats that are of the same station(client) */
 | 
				
			||||||
 | 
						public List<LinkStats> connections;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,75 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (c) Meta Platforms, Inc. and affiliates.
 | 
				
			||||||
 | 
					 * All rights reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This source code is licensed under the BSD-style license found in the
 | 
				
			||||||
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package com.facebook.openwifi.librca.stats;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Aggregation Statistics Model of InputStats.
 | 
				
			||||||
 | 
					 * Aggregate by bssid, station and RadioConfig.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class LinkStats {
 | 
				
			||||||
 | 
						public static class RadioConfig {
 | 
				
			||||||
 | 
							public int channel;
 | 
				
			||||||
 | 
							public int channelWidth;
 | 
				
			||||||
 | 
							public int txPower;
 | 
				
			||||||
 | 
							public String phy;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static class AssociationInfo {
 | 
				
			||||||
 | 
							/** Rate information for receive/transmit data rate. */
 | 
				
			||||||
 | 
							public static class Rate {
 | 
				
			||||||
 | 
								public long bitRate;
 | 
				
			||||||
 | 
								public int chWidth;
 | 
				
			||||||
 | 
								public int mcs;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public long connected;
 | 
				
			||||||
 | 
							public long inactive;
 | 
				
			||||||
 | 
							public int rssi;
 | 
				
			||||||
 | 
							public long rxBytes;
 | 
				
			||||||
 | 
							public long rxPackets;
 | 
				
			||||||
 | 
							public Rate rxRate;
 | 
				
			||||||
 | 
							public long txBytes;
 | 
				
			||||||
 | 
							public long txDuration;
 | 
				
			||||||
 | 
							public long txFailed;
 | 
				
			||||||
 | 
							public long txPackets;
 | 
				
			||||||
 | 
							public Rate txRate;
 | 
				
			||||||
 | 
							public long txRetries;
 | 
				
			||||||
 | 
							public int ackSignal;
 | 
				
			||||||
 | 
							public int ackSignalAvg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// The metrics below are from Interface the client was connected to.
 | 
				
			||||||
 | 
							public long txPacketsCounters;
 | 
				
			||||||
 | 
							public long txErrorsCounters;
 | 
				
			||||||
 | 
							public long txDroppedCounters;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// The metrics below are from the radio the client was associated to.
 | 
				
			||||||
 | 
							public long activeMsRadio;
 | 
				
			||||||
 | 
							public long busyMsRadio;
 | 
				
			||||||
 | 
							public long noiseRadio;
 | 
				
			||||||
 | 
							public long receiveMsRadio;
 | 
				
			||||||
 | 
							public long transmitMsRadio;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/** Unix time in milliseconds */
 | 
				
			||||||
 | 
							public long timestamp;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** BSSID of the AP radio */
 | 
				
			||||||
 | 
						public String bssid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Client MAC */
 | 
				
			||||||
 | 
						public String station;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Radio configuration parameters */
 | 
				
			||||||
 | 
						public RadioConfig radioConfig;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Association list */
 | 
				
			||||||
 | 
						public List<AssociationInfo> associationInfoList;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,78 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (c) Meta Platforms, Inc. and affiliates.
 | 
				
			||||||
 | 
					 * All rights reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This source code is licensed under the BSD-style license found in the
 | 
				
			||||||
 | 
					 * LICENSE file in the root directory of this source tree.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package com.facebook.openwifi.librca.stats.inputs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Input data model.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * TODO: very incomplete
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					public class InputStats {
 | 
				
			||||||
 | 
						/** Radio parameters */
 | 
				
			||||||
 | 
						public static class Radio {
 | 
				
			||||||
 | 
							public long active_ms;
 | 
				
			||||||
 | 
							public long busy_ms;
 | 
				
			||||||
 | 
							public int channel;
 | 
				
			||||||
 | 
							public String channel_width;
 | 
				
			||||||
 | 
							public long noise;
 | 
				
			||||||
 | 
							public String phy;
 | 
				
			||||||
 | 
							public long receive_ms;
 | 
				
			||||||
 | 
							public long transmit_ms;
 | 
				
			||||||
 | 
							public int tx_power;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static class SSID {
 | 
				
			||||||
 | 
							public static class Association {
 | 
				
			||||||
 | 
								public static class Rate {
 | 
				
			||||||
 | 
									public long bitrate;
 | 
				
			||||||
 | 
									public int chwidth;
 | 
				
			||||||
 | 
									public int mcs;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								public String bssid; // bssid of the AP radio
 | 
				
			||||||
 | 
								public String station; // client MAC
 | 
				
			||||||
 | 
								public long connected;
 | 
				
			||||||
 | 
								public long inactive;
 | 
				
			||||||
 | 
								public int rssi;
 | 
				
			||||||
 | 
								public long rx_bytes;
 | 
				
			||||||
 | 
								public long rx_packets;
 | 
				
			||||||
 | 
								public Rate rx_rate;
 | 
				
			||||||
 | 
								public long tx_bytes;
 | 
				
			||||||
 | 
								public long tx_duration;
 | 
				
			||||||
 | 
								public long tx_failed;
 | 
				
			||||||
 | 
								public long tx_offset;
 | 
				
			||||||
 | 
								public long tx_packets;
 | 
				
			||||||
 | 
								public Rate tx_rate;
 | 
				
			||||||
 | 
								public long tx_retries;
 | 
				
			||||||
 | 
								public int ack_signal;
 | 
				
			||||||
 | 
								public int ack_signal_avg;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public Association[] associations;
 | 
				
			||||||
 | 
							public Radio radio;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Counters are for the wireless interface as a whole */
 | 
				
			||||||
 | 
						public static class Counters {
 | 
				
			||||||
 | 
							public long rx_bytes;
 | 
				
			||||||
 | 
							public long rx_packets;
 | 
				
			||||||
 | 
							public long rx_errors;
 | 
				
			||||||
 | 
							public long rx_dropped;
 | 
				
			||||||
 | 
							public long tx_bytes;
 | 
				
			||||||
 | 
							public long tx_packets;
 | 
				
			||||||
 | 
							public long tx_errors;
 | 
				
			||||||
 | 
							public long tx_dropped;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public SSID[] ssids;
 | 
				
			||||||
 | 
						public Counters counters;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Unix time in milliseconds */
 | 
				
			||||||
 | 
						public long timestamp;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user