mirror of
				https://github.com/Telecominfraproject/wlan-ap.git
				synced 2025-10-30 18:07:52 +00:00 
			
		
		
		
	Compare commits
	
		
			168 Commits
		
	
	
		
			v2.5.0-rc4
			...
			v2.6.0-rc3
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 7439217b3c | ||
|   | ae2377f4d2 | ||
|   | b81d0aaf0e | ||
|   | 1546bef93f | ||
|   | 32b1aade42 | ||
|   | 2a92b75fe1 | ||
|   | cb30d9e20a | ||
|   | 588206b93b | ||
|   | 6399649038 | ||
|   | aa3cb95233 | ||
|   | 3ea06dac40 | ||
|   | a70dda4a8e | ||
|   | a01f1add81 | ||
|   | 57849591d7 | ||
|   | b4a09e7167 | ||
|   | 96bb8b1372 | ||
|   | 99ea9da785 | ||
|   | bfe7fadfc5 | ||
|   | ad1dcc4f45 | ||
|   | f371c789d0 | ||
|   | 386eca1f65 | ||
|   | 8b9047952d | ||
|   | 5a105ef06e | ||
|   | c60dc1e045 | ||
|   | 1e1bd19429 | ||
|   | cfe07f6e15 | ||
|   | a64039db20 | ||
|   | 7f81ddb8cc | ||
|   | 3c0d495334 | ||
|   | 38a7c54cce | ||
|   | 1aead07444 | ||
|   | d2f44cbb12 | ||
|   | 43d7ca31d6 | ||
|   | 0985c573b0 | ||
|   | d9ed861c1d | ||
|   | 8ef9989147 | ||
|   | 7d5eab4bf3 | ||
|   | 5e03e04bbd | ||
|   | 6fabaeca53 | ||
|   | be4ca445f5 | ||
|   | e99c8b27e1 | ||
|   | e9055b4f08 | ||
|   | cfcafb676b | ||
|   | 899b4d6bfd | ||
|   | 2003632ddb | ||
|   | d4a14106b7 | ||
|   | 85af9d7e0b | ||
|   | d4442efbfe | ||
|   | 3a26ae2695 | ||
|   | 09af596e85 | ||
|   | 5985187316 | ||
|   | 33ac83a309 | ||
|   | 921c1b553d | ||
|   | d160507230 | ||
|   | 7368620fd2 | ||
|   | a910e297a3 | ||
|   | f819bb8753 | ||
|   | cc0d4bded2 | ||
|   | e3b2b7f232 | ||
|   | c8dde50eba | ||
|   | 3c355f96eb | ||
|   | 93dd24ef6e | ||
|   | 107bc8ef65 | ||
|   | 9a8278afcc | ||
|   | 1c48765913 | ||
|   | c6a45184fd | ||
|   | 18d5b8cba7 | ||
|   | 65c08ade18 | ||
|   | 3f6fee91e9 | ||
|   | d29c4e49b3 | ||
|   | f162000749 | ||
|   | c804333bc0 | ||
|   | 449795db97 | ||
|   | af92a2c7aa | ||
|   | b68affdf6a | ||
|   | 7a95f9ac2d | ||
|   | 8b5d9d84de | ||
|   | 93d93c7708 | ||
|   | b35232ab4a | ||
|   | 770a2bdd36 | ||
|   | 9650f8eaa8 | ||
|   | 63ab76bb30 | ||
|   | fcb21ca0b6 | ||
|   | d6d5422152 | ||
|   | 5b970a3f12 | ||
|   | a4a7c1f9f3 | ||
|   | 5cbac23e3f | ||
|   | 172c0d3690 | ||
|   | 535f41d58b | ||
|   | 2be18091a4 | ||
|   | 73f42e3c6f | ||
|   | cff778d8ca | ||
|   | 94d4498a2d | ||
|   | eb0ab17f58 | ||
|   | 1ab99d50b2 | ||
|   | dfeddc0d89 | ||
|   | efde86be9d | ||
|   | 739e8c12fb | ||
|   | 3fdbbff9f7 | ||
|   | 0a56755bef | ||
|   | c35290772d | ||
|   | cedcbcbc2b | ||
|   | 9de96deca8 | ||
|   | 19dbb1d5e3 | ||
|   | 83b6ccf562 | ||
|   | ea86593835 | ||
|   | 36b5478005 | ||
|   | 1ad19297c1 | ||
|   | f5357f7854 | ||
|   | 8a3140b89b | ||
|   | 16e0724ace | ||
|   | 17ff9eecf5 | ||
|   | 4b870f978c | ||
|   | 8b83365961 | ||
|   | c6ebb5537a | ||
|   | 6ebe189d71 | ||
|   | 98b56551d5 | ||
|   | 606e27e256 | ||
|   | 94fe14b9f9 | ||
|   | 58388f84b6 | ||
|   | 79ea04af49 | ||
|   | 396e2bd06c | ||
|   | 1a484c7f39 | ||
|   | e6b1030991 | ||
|   | 6e32e68302 | ||
|   | 0f13f7f5cd | ||
|   | 2ac4f9ef1d | ||
|   | f1a75c25f9 | ||
|   | ff8d70753d | ||
|   | caea6baecd | ||
|   | 2e914c9b35 | ||
|   | da65d7e06f | ||
|   | d18eef480c | ||
|   | f3532c66e5 | ||
|   | 9678b1d6a5 | ||
|   | 379a4e2382 | ||
|   | edb33cd560 | ||
|   | 2ff425ddeb | ||
|   | 7d016ac27f | ||
|   | 9790377dec | ||
|   | 597c547101 | ||
|   | 73b2645027 | ||
|   | 8d58387d15 | ||
|   | 54dac4d348 | ||
|   | a0880ed0f1 | ||
|   | ed6d683980 | ||
|   | 4c72c6a35a | ||
|   | 125d56866e | ||
|   | a70a767ec0 | ||
|   | b8a6764207 | ||
|   | 98c9fcfd5d | ||
|   | eac5504fec | ||
|   | c2c75b67eb | ||
|   | ef3eacefa7 | ||
|   | ef7481596a | ||
|   | 6f4e00aa46 | ||
|   | be65578a7f | ||
|   | 20d4bd0c7d | ||
|   | 531f4eb811 | ||
|   | 3b0dae7189 | ||
|   | 79395593ba | ||
|   | 61248b98e0 | ||
|   | 72b5abb72a | ||
|   | 673a029a02 | ||
|   | 7efb85180f | ||
|   | f95eadaa8f | ||
|   | 6f6b40a94f | ||
|   | d84982f161 | 
							
								
								
									
										39
									
								
								.github/actions/create-ami-from-image/action.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								.github/actions/create-ami-from-image/action.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| name: Create AMI from firmware image in S3 bucket | ||||
|  | ||||
| inputs: | ||||
|   firmware_image_name: | ||||
|     description: Name of the firmware image | ||||
|     required: true | ||||
|   firmware_image_s3_bucket: | ||||
|     description: Name of the S3 bucket where the image resides | ||||
|     required: true | ||||
|  | ||||
| runs: | ||||
|   using: "composite" | ||||
|   steps: | ||||
|     - name: Import snapshot based on firmware image | ||||
|       id: import_snapshot | ||||
|       shell: bash | ||||
|       run: | | ||||
|         echo ::set-output name=import_task_id::$(aws ec2 import-snapshot --description '${{ inputs.firmware_image_name }}' --disk-container 'Format=raw,UserBucket={S3Bucket=${{ inputs.firmware_image_s3_bucket }},S3Key=${{ inputs.firmware_image_name }}}' | jq -r '.ImportTaskId') | ||||
|  | ||||
|     - name: Wait for import task to complete and get snapshot ID | ||||
|       id: get_snapshot_id | ||||
|       shell: bash | ||||
|       run: | | ||||
|         IMPORT_TASK_STATUS="" | ||||
|         while [[ $IMPORT_TASK_STATUS != 'completed' ]]; do | ||||
|           IMPORT_TASK_STATUS=$(aws ec2 describe-import-snapshot-tasks --import-task-ids ${{ steps.import_snapshot.outputs.import_task_id }} | jq -r '.ImportSnapshotTasks[].SnapshotTaskDetail.Status') | ||||
|           echo "Import task status is $IMPORT_TASK_STATUS, waiting for completion." | ||||
|         done | ||||
|         echo ::set-output name=id::$(aws ec2 describe-import-snapshot-tasks --import-task-ids ${{ steps.import_snapshot.outputs.import_task_id }} | jq -r '.ImportSnapshotTasks[].SnapshotTaskDetail.SnapshotId') | ||||
|  | ||||
|     - name: Tag snapshot with image name | ||||
|       shell: bash | ||||
|       run: | | ||||
|         aws ec2 create-tags --resources ${{ steps.get_snapshot_id.outputs.id }} --tags 'Key=Name,Value=${{ inputs.firmware_image_name }}' | ||||
|  | ||||
|     - name: Register AMI based on snapshot | ||||
|       shell: bash | ||||
|       run: | | ||||
|         aws ec2 register-image --name '${{ inputs.firmware_image_name }}' --root-device-name /dev/xvda --block-device-mappings 'DeviceName=/dev/xvda,Ebs={SnapshotId=${{ steps.get_snapshot_id.outputs.id }}}' | ||||
							
								
								
									
										36
									
								
								.github/workflows/build-dev.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										36
									
								
								.github/workflows/build-dev.yml
									
									
									
									
										vendored
									
									
								
							| @@ -1,5 +1,13 @@ | ||||
| name: Build OpenWrt/uCentral images | ||||
|  | ||||
| env: | ||||
|   AWS_DEFAULT_OUTPUT: json | ||||
|   AWS_DEFAULT_REGION: us-east-1 | ||||
|   AWS_S3_BUCKET_NAME: ucentral-ap-firmware | ||||
|   AWS_ACCOUNT_ID: ${{ secrets.UCENTRAL_S3_ACCOUNT_ID }} | ||||
|   AWS_ACCESS_KEY_ID: ${{ secrets.UCENTRAL_S3_ACCESS_KEY_ID }} | ||||
|   AWS_SECRET_ACCESS_KEY: ${{ secrets.UCENTRAL_S3_ACCESS_KEY_SECRET }} | ||||
|  | ||||
| on: | ||||
|   push: | ||||
|     branches: [ main, next, staging-* ] | ||||
| @@ -8,10 +16,12 @@ on: | ||||
| jobs: | ||||
|   build: | ||||
|     runs-on: ubuntu-latest | ||||
|     outputs: | ||||
|       x64_vm_image_name: ${{ steps.package_and_upload_image.outputs.x64_vm_image_name }} | ||||
|     strategy: | ||||
|       fail-fast: false | ||||
|       matrix: | ||||
|         target: ['actiontec_web7200', 'cig_wf188n', 'cig_wf194c', 'cig_wf194c4', 'cig_wf196', 'cig_wf160d', 'cig_wf808', 'cybertan_eww622-a1', 'edgecore_eap101', 'edgecore_eap102', 'edgecore_eap104', 'edgecore_ecs4100-12ph', 'edgecore_ecw5211', 'edgecore_ecw5410', 'edgecore_oap100', 'edgecore_ssw2ac2600', 'edgecore_spw2ac1200', 'edgecore_spw2ac1200-lan-poe', 'hfcl_ion4', 'hfcl_ion4xe', 'hfcl_ion4xi', 'indio_um-305ac', 'linksys_ea6350-v4', 'linksys_e8450-ubi', 'linksys_ea8300', 'tp-link_ec420-g1', 'tplink_ex227', 'tplink_ex228', 'tplink_ex447', 'wallys_dr40x9', 'wallys_dr6018', 'wallys_dr6018_v4' ] | ||||
|         target: ['actiontec_web7200', 'cig_wf188n', 'cig_wf194c', 'cig_wf194c4', 'cig_wf196', 'cig_wf610d', 'cig_wf808', 'cybertan_eww622-a1', 'edgecore_eap101', 'edgecore_eap102', 'edgecore_eap104', 'edgecore_ecs4100-12ph', 'edgecore_ecw5211', 'edgecore_ecw5410', 'edgecore_oap100', 'edgecore_ssw2ac2600', 'edgecore_spw2ac1200', 'edgecore_spw2ac1200-lan-poe', 'hfcl_ion4', 'hfcl_ion4xe', 'hfcl_ion4xi', 'indio_um-305ac', 'indio_um-305ax', 'indio_um-325ac', 'indio_um-510ac-v3', 'indio_um-550ac', 'linksys_ea6350-v4', 'linksys_e8450-ubi', 'linksys_ea8300', 'tp-link_ec420-g1', 'tplink_ex227', 'tplink_ex228', 'tplink_ex447', 'udaya_a5-id2', 'wallys_dr40x9', 'x64_vm' ] | ||||
|  | ||||
|     steps: | ||||
|     - uses: actions/checkout@v2 | ||||
| @@ -24,17 +34,12 @@ jobs: | ||||
|         make -j TARGET=${{ matrix.target }} | ||||
|  | ||||
|     - name: Package and upload image for ${{ matrix.target }} | ||||
|       id: package_and_upload_image | ||||
|       env: | ||||
|           GH_BUILD_USERNAME: ${{ secrets.GH_BUILD_USERNAME }} | ||||
|           GH_BUILD_PASSWORD: ${{ secrets.GH_BUILD_PASSWORD }} | ||||
|           ARTIFACTORY_USERNAME: cicd-indoor-main | ||||
|           ARTIFACTORY_PASSWORD: ${{ secrets.ARTIFACTORY_PASSWORD }} | ||||
|           AWS_S3_BUCKET_NAME: ucentral-ap-firmware | ||||
|           AWS_DEFAULT_OUTPUT: json | ||||
|           AWS_DEFAULT_REGION: us-east-1 | ||||
|           AWS_ACCOUNT_ID: ${{ secrets.UCENTRAL_S3_ACCOUNT_ID }} | ||||
|           AWS_ACCESS_KEY_ID: ${{ secrets.UCENTRAL_S3_ACCESS_KEY_ID }} | ||||
|           AWS_SECRET_ACCESS_KEY: ${{ secrets.UCENTRAL_S3_ACCESS_KEY_SECRET }} | ||||
|       run: | | ||||
|         LOWERCASE_TARGET=`echo ${{ matrix.target }} | tr '[:upper:]' '[:lower:]'` | ||||
|         HASH=$(git rev-parse --short HEAD) | ||||
| @@ -66,6 +71,10 @@ jobs: | ||||
|         [ -f openwrt/tmp/image-file ] && aws s3 cp --acl public-read --content-type "application/json" "latest-upgrade.json" "s3://$AWS_S3_BUCKET_NAME/$JSON_NAME" | ||||
|         [ -f openwrt/tmp/image-file ] && aws s3api put-object-tagging --bucket "$AWS_S3_BUCKET_NAME" --key "$JSON_NAME" --tagging "{\"TagSet\":[{\"Key\":\"release\",\"Value\":\"$IS_RELEASE\"}]}" | ||||
|  | ||||
|         if [ ${{ matrix.target }} == 'x64_vm' ]; then | ||||
|           echo ::set-output name=x64_vm_image_name::"$(echo $IMG_NAME)" | ||||
|         fi | ||||
|  | ||||
|   trigger-testing: | ||||
|     runs-on: ubuntu-latest | ||||
|     needs: build | ||||
| @@ -78,3 +87,16 @@ jobs: | ||||
|         repository: Telecominfraproject/wlan-testing | ||||
|         event-type: new-ap-release | ||||
|         client-payload: '{"ref": "${GITHUB_REF#refs/tags/}", "sha": "${{ github.sha }}"}' | ||||
|  | ||||
|   create-x64_vm-ami: | ||||
|     runs-on: ubuntu-latest | ||||
|     needs: build | ||||
|     if: startsWith(github.ref, 'refs/tags/v') | ||||
|     steps: | ||||
|     - uses: actions/checkout@v2 | ||||
|  | ||||
|     - name: Use create-ami-from-image composite action | ||||
|       uses: ./.github/actions/create-ami-from-image | ||||
|       with: | ||||
|         firmware_image_name: ${{ needs.build.outputs.x64_vm_image_name }} | ||||
|         firmware_image_s3_bucket: ${{ env.AWS_S3_BUCKET_NAME }} | ||||
|   | ||||
							
								
								
									
										88
									
								
								.github/workflows/x64_vm-build-test.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								.github/workflows/x64_vm-build-test.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,88 @@ | ||||
| name: Test x64_vm build and AMI creation | ||||
|  | ||||
| env: | ||||
|   AWS_DEFAULT_OUTPUT: json | ||||
|   AWS_DEFAULT_REGION: us-east-1 | ||||
|   AWS_S3_BUCKET_NAME: ucentral-ap-firmware | ||||
|   AWS_ACCOUNT_ID: ${{ secrets.UCENTRAL_S3_ACCOUNT_ID }} | ||||
|   AWS_ACCESS_KEY_ID: ${{ secrets.UCENTRAL_S3_ACCESS_KEY_ID }} | ||||
|   AWS_SECRET_ACCESS_KEY: ${{ secrets.UCENTRAL_S3_ACCESS_KEY_SECRET }} | ||||
|  | ||||
| on: | ||||
|   workflow_dispatch: | ||||
|  | ||||
| jobs: | ||||
|   build: | ||||
|     runs-on: ubuntu-latest | ||||
|     outputs: | ||||
|       x64_vm_image_name: ${{ steps.package_and_upload_image.outputs.x64_vm_image_name }} | ||||
|     strategy: | ||||
|       fail-fast: false | ||||
|       matrix: | ||||
|         target: ['x64_vm'] | ||||
|  | ||||
|     steps: | ||||
|     - uses: actions/checkout@v2 | ||||
|  | ||||
|     - name: Build image for ${{ matrix.target }} | ||||
|       id: build | ||||
|       run: | | ||||
|         git config --global user.email "you@example.com" | ||||
|         git config --global user.name "Your Name" | ||||
|         make -j TARGET=${{ matrix.target }} | ||||
|  | ||||
|     - name: Package and upload image for ${{ matrix.target }} | ||||
|       id: package_and_upload_image | ||||
|       env: | ||||
|         GH_BUILD_USERNAME: ${{ secrets.GH_BUILD_USERNAME }} | ||||
|         GH_BUILD_PASSWORD: ${{ secrets.GH_BUILD_PASSWORD }} | ||||
|         ARTIFACTORY_USERNAME: cicd-indoor-main | ||||
|         ARTIFACTORY_PASSWORD: ${{ secrets.ARTIFACTORY_PASSWORD }} | ||||
|       run: | | ||||
|         LOWERCASE_TARGET=`echo ${{ matrix.target }} | tr '[:upper:]' '[:lower:]'` | ||||
|         HASH=$(git rev-parse --short HEAD) | ||||
|  | ||||
|         if [[ ${GITHUB_REF} == "refs/heads/"* ]] | ||||
|         then | ||||
|           REF=$(echo ${GITHUB_REF#refs/heads/} | tr '/' '-') | ||||
|           IS_RELEASE="false" | ||||
|         else | ||||
|           REF=$(echo ${GITHUB_REF#refs/tags/} | tr '/' '-') | ||||
|           IS_RELEASE="true" | ||||
|         fi | ||||
|  | ||||
|         BASENAME="$(date +%Y%m%d)-$LOWERCASE_TARGET-$REF-$HASH" | ||||
|         TAR_NAME="$BASENAME.tar.gz" | ||||
|         IMG_NAME="$BASENAME-upgrade.bin"; | ||||
|         JSON_NAME="$BASENAME.json"; | ||||
|  | ||||
|         tar cfz "$TAR_NAME" -C openwrt/bin/targets/ . | ||||
|         curl -s -u $GH_BUILD_USERNAME:$GH_BUILD_PASSWORD -T "$TAR_NAME" "https://tip.jfrog.io/artifactory/tip-wlan-ap-firmware/uCentral/$LOWERCASE_TARGET/"$TAR_NAME"" | ||||
|         IMG_NAME="$BASENAME-upgrade.bin"; | ||||
|         TIP_VERSION="$(grep DISTRIB_TIP= openwrt/tmp/openwrt_release | cut -d\' -f2)" | ||||
|         echo -e "{\n\t\"image\":\""${IMG_NAME}"\",\n\t\"revision\": \""${TIP_VERSION}"\",\n\t\"timestamp\":\""$(date +%s)"\",\n\t\"compatible\": \""${LOWERCASE_TARGET}"\"\n}" > latest-upgrade.json | ||||
|         [ -f openwrt/tmp/image-file ] && curl -s -u $GH_BUILD_USERNAME:$GH_BUILD_PASSWORD -T "openwrt/$(cat openwrt/tmp/image-file)" "https://tip.jfrog.io/artifactory/tip-wlan-ap-firmware/uCentral/$LOWERCASE_TARGET/"$IMG_NAME"" | ||||
|         [ -f openwrt/tmp/image-file ] && curl -s -u $GH_BUILD_USERNAME:$GH_BUILD_PASSWORD -T "latest-upgrade.json" "https://tip.jfrog.io/artifactory/tip-wlan-ap-firmware/uCentral/$LOWERCASE_TARGET/latest-upgrade.json" | ||||
|  | ||||
|         [ -f openwrt/tmp/image-file ] && aws s3 cp --acl public-read --content-type "application/octet-stream" "openwrt/$(cat openwrt/tmp/image-file)" "s3://$AWS_S3_BUCKET_NAME/$IMG_NAME" | ||||
|         [ -f openwrt/tmp/image-file ] && aws s3api put-object-tagging --bucket "$AWS_S3_BUCKET_NAME" --key "$IMG_NAME" --tagging "{\"TagSet\":[{\"Key\":\"release\",\"Value\":\"$IS_RELEASE\"}]}" | ||||
|         [ -f openwrt/tmp/image-file ] && aws s3 cp --acl public-read --content-type "application/json" "latest-upgrade.json" "s3://$AWS_S3_BUCKET_NAME/$JSON_NAME" | ||||
|         [ -f openwrt/tmp/image-file ] && aws s3api put-object-tagging --bucket "$AWS_S3_BUCKET_NAME" --key "$JSON_NAME" --tagging "{\"TagSet\":[{\"Key\":\"release\",\"Value\":\"$IS_RELEASE\"}]}" | ||||
|  | ||||
|         if [[ ${{ matrix.target }} == 'x64_vm' ]]; then | ||||
|           echo ::set-output name=x64_vm_image_name::"$(echo $IMG_NAME)" | ||||
|         fi | ||||
|  | ||||
|   create-x64_vm-ami: | ||||
|     runs-on: ubuntu-latest | ||||
|     needs: build | ||||
|     steps: | ||||
|     - uses: actions/checkout@v2 | ||||
|       with: | ||||
|         ref: WIFI-7206-add-workflow-to-build-virtual-ap-image | ||||
|  | ||||
|     - name: Use create-ami-from-image composite action | ||||
|       uses: ./.github/actions/create-ami-from-image | ||||
|       with: | ||||
|         firmware_image_name: ${{ needs.build.outputs.x64_vm_image_name }} | ||||
|         firmware_image_s3_bucket: ${{ env.AWS_S3_BUCKET_NAME }} | ||||
| @@ -12,7 +12,7 @@ First we need to clone and setup our tree. This will result in an openwrt/. | ||||
| Next we need to select the profile and base package selection. This setup will install the feeds, packages and generate the .config file. | ||||
| ``` | ||||
| cd openwrt | ||||
| ./scripts/gen_config.py ea8300 | ||||
| ./scripts/gen_config.py linksys_ea8300 | ||||
| ``` | ||||
| Finally we can build the tree. | ||||
| ``` | ||||
|   | ||||
| @@ -39,6 +39,10 @@ hfcl,ion4xe) | ||||
|         ucidef_set_led_wlan "wlan5g" "WLAN5G" "blue:wifi5" "phy0tpt" | ||||
|         ucidef_set_led_wlan "wlan2g" "WLAN2G" "blue:wifi2" "phy1tpt" | ||||
| 	;; | ||||
| glinet,ax1800|\ | ||||
| glinet,axt1800) | ||||
| 	ucidef_set_led_netdev "wan" "WAN" "blue:wan" "eth0" "tx rx link" | ||||
| 	;; | ||||
| esac | ||||
|  | ||||
| board_config_flush | ||||
|   | ||||
| @@ -32,11 +32,14 @@ qcom_setup_interfaces() | ||||
| 	cig,wf194c4|\ | ||||
| 	edgecore,eap106|\ | ||||
| 	qcom,ipq5018-mp03.3|\ | ||||
| 	yuncore,ax840|\ | ||||
| 	motorola,q14|\ | ||||
| 	sercomm,wallaby) | ||||
| 		ucidef_set_interface_lan "eth0" | ||||
| 		ucidef_set_interface_wan "eth1" | ||||
| 		;; | ||||
| 	edgecore,eap101) | ||||
| 	edgecore,eap101|\ | ||||
| 	glinet,axt1800) | ||||
| 		ucidef_set_interface_lan "eth1 eth2" | ||||
| 		ucidef_set_interface_wan "eth0" | ||||
| 		;; | ||||
| @@ -52,7 +55,8 @@ qcom_setup_interfaces() | ||||
| 		ucidef_set_interface_lan "eth0 eth1 eth2 eth3" | ||||
| 		ucidef_set_interface_wan "eth4" | ||||
| 		;; | ||||
| 	wallys,dr6018-v4) | ||||
| 	wallys,dr6018-v4|\ | ||||
| 	glinet,ax1800) | ||||
| 		ucidef_set_interface_lan "eth1 eth2 eth3 eth4" | ||||
| 		ucidef_set_interface_wan "eth0" | ||||
| 		;; | ||||
| @@ -73,7 +77,8 @@ qcom_setup_macs() | ||||
|  | ||||
| 	case $board in | ||||
| 	cig,wf194c|\ | ||||
| 	cig,wf194c4) | ||||
| 	cig,wf194c4|\ | ||||
| 	cig,wf196) | ||||
| 		mac=$(grep BaseMacAddress= /dev/mtd14 | cut -dx -f2) | ||||
| 		wan_mac=$(macaddr_canonicalize $mac) | ||||
| 		lan_mac=$(macaddr_add "$wan_mac" 1) | ||||
| @@ -81,6 +86,15 @@ qcom_setup_macs() | ||||
| 		ucidef_set_network_device_mac eth1 $wan_mac | ||||
| 		ucidef_set_label_macaddr $wan_mac | ||||
| 		;; | ||||
| 	cybertan,eww622-a1) | ||||
| 	        mac=$(grep -i -m 1 mac_addr_base= /dev/`cat /proc/mtd | grep devinfo | cut -d: -f1` | cut -d= -f2) | ||||
| 	        [ -z "$mac"] && mac="00:11:22:33:44:55" | ||||
| 		wan_mac=$(macaddr_canonicalize $mac) | ||||
| 		lan_mac=$(macaddr_add "$wan_mac" 1) | ||||
| 		ucidef_set_network_device_mac eth0 $wan_mac | ||||
| 		ucidef_set_network_device_mac eth1 $lan_mac | ||||
| 		ucidef_set_label_macaddr $wan_mac | ||||
| 		;; | ||||
| 	*) | ||||
| 		wan_mac=$(cat /sys/class/net/eth0/address) | ||||
| 		lan_mac=$(macaddr_add "$wan_mac" 1) | ||||
| @@ -88,6 +102,7 @@ qcom_setup_macs() | ||||
| 	esac | ||||
| 	[ -n "$lan_mac" ] && ucidef_set_interface_macaddr "lan" $lan_mac | ||||
| 	[ -n "$wan_mac" ] && ucidef_set_interface_macaddr "wan" $wan_mac | ||||
| 	[ -n "$wan_mac" ] && ucidef_set_label_macaddr "$wan_mac" | ||||
| } | ||||
|  | ||||
| board_config_update | ||||
|   | ||||
| @@ -81,6 +81,7 @@ case "$FIRMWARE" in | ||||
| 	qcom,ipq807x-hk14|\ | ||||
| 	tplink,ex227|\ | ||||
| 	tplink,ex447|\ | ||||
| 	yuncore,ax840|\ | ||||
| 	sercomm,wallaby) | ||||
|                 caldata_extract "0:ART" 0x1000 0x20000 | ||||
| 		;; | ||||
| @@ -96,7 +97,8 @@ case "$FIRMWARE" in | ||||
| 	wallys,dr6018|\ | ||||
| 	wallys,dr6018-v4|\ | ||||
| 	qcom,ipq6018-cp01|\ | ||||
| 	xiaomi,ax1800) | ||||
| 	xiaomi,ax1800|\ | ||||
| 	glinet,ax1800) | ||||
|                 caldata_extract "0:ART" 0x1000 0x20000   | ||||
| 		;; | ||||
| 	esac | ||||
| @@ -105,13 +107,22 @@ ath11k/IPQ5018/hw1.0/caldata.bin) | ||||
| 	case "$board" in | ||||
| 	cybertan,eww622-a1|\ | ||||
| 	edgecore,eap104|\ | ||||
| 	motorola,q14|\ | ||||
| 	qcom,ipq5018-mp03.1) | ||||
|                 caldata_extract "0:ART" 0x1000 0x20000   | ||||
| 		;; | ||||
| 	esac | ||||
| 	;; | ||||
| ath11k/qcn6122/hw1.0/caldata_1.bin) | ||||
| 	case "$board" in | ||||
| 	motorola,q14) | ||||
|                 caldata_extract "0:ART" 0x26800 0x20000   | ||||
| 		;; | ||||
| 	esac | ||||
| 	;; | ||||
| ath11k/qcn6122/hw1.0/caldata_2.bin) | ||||
| 	case "$board" in | ||||
| 	motorola,q14|\ | ||||
| 	edgecore,eap104) | ||||
|                 caldata_extract "0:ART" 0x4c000 0x20000   | ||||
| 		;; | ||||
|   | ||||
| @@ -19,4 +19,12 @@ boot() { | ||||
| 		ssdk_sh debug phy set 8 0x4004c441 0x8 | ||||
| 		;; | ||||
| 	esac | ||||
|  | ||||
| 	case "$(board_name)" in | ||||
| 	cig,wf196) | ||||
| 		# setup the leds | ||||
| 		ssdk_sh debug phy set 0 0x401ec431 0xc00f | ||||
| 		ssdk_sh debug phy set 0 0x401ec430 0x806f | ||||
| 		;; | ||||
| 	esac | ||||
| } | ||||
|   | ||||
| @@ -4,8 +4,14 @@ START=99 | ||||
|  | ||||
| boot() { | ||||
| 	case "$(board_name)" in | ||||
| 	hfcl,ion4xe|\ | ||||
| 	hfcl,ion4xi) | ||||
| 		fw_setenv boot_count 0 | ||||
| 		;;		 | ||||
| 	edgecore,eap101|\ | ||||
| 	edgecore,eap102) | ||||
| 		avail=$(fw_printenv -n upgrade_available) | ||||
| 		[ "${avail}" -eq 1 ] || fw_setenv upgrade_available 1 | ||||
| 		fw_setenv bootcount 0 | ||||
| 		;; | ||||
| 	esac | ||||
|   | ||||
| @@ -1,5 +1,8 @@ | ||||
| . /lib/functions/system.sh | ||||
|  | ||||
| RAMFS_COPY_BIN='fw_printenv fw_setenv' | ||||
| RAMFS_COPY_DATA='/etc/fw_env.config /var/lock/fw_printenv.lock' | ||||
|  | ||||
| qca_do_upgrade() { | ||||
|         local tar_file="$1" | ||||
|  | ||||
| @@ -16,6 +19,50 @@ qca_do_upgrade() { | ||||
|         fi | ||||
| } | ||||
|  | ||||
| find_mmc_part() { | ||||
| 	local DEVNAME PARTNAME | ||||
|  | ||||
| 	if grep -q "$1" /proc/mtd; then | ||||
| 		echo "" && return 0 | ||||
| 	fi | ||||
|  | ||||
| 	for DEVNAME in /sys/block/mmcblk*/mmcblk*p*; do | ||||
| 		PARTNAME=$(grep PARTNAME ${DEVNAME}/uevent | cut -f2 -d'=') | ||||
| 		[ "$PARTNAME" = "$1" ] && echo "/dev/$(basename $DEVNAME)" && return 0 | ||||
| 	done | ||||
| } | ||||
|  | ||||
| do_flash_emmc() { | ||||
| 	local tar_file=$1 | ||||
| 	local emmcblock=$(find_mmc_part $2) | ||||
| 	local board_dir=$3 | ||||
| 	local part=$4 | ||||
|  | ||||
| 	[ -z "$emmcblock" ] && { | ||||
| 		echo failed to find $2 | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	echo erase $4 | ||||
| 	dd if=/dev/zero of=${emmcblock} 2> /dev/null | ||||
| 	echo flash $4 | ||||
| 	tar Oxf $tar_file ${board_dir}/$part | dd of=${emmcblock} | ||||
| } | ||||
|  | ||||
| emmc_do_upgrade() { | ||||
| 	local tar_file="$1" | ||||
|  | ||||
| 	local board_dir=$(tar tf $tar_file | grep -m 1 '^sysupgrade-.*/$') | ||||
| 	board_dir=${board_dir%/} | ||||
| 	do_flash_emmc $tar_file '0:HLOS' $board_dir kernel | ||||
| 	do_flash_emmc $tar_file 'rootfs' $board_dir root | ||||
|  | ||||
| 	local emmcblock="$(find_mmc_part "rootfs_data")" | ||||
|         if [ -e "$emmcblock" ]; then | ||||
|                 mkfs.ext4 -F "$emmcblock" | ||||
|         fi | ||||
| } | ||||
|  | ||||
| platform_check_image() { | ||||
| 	local magic_long="$(get_magic_long "$1")" | ||||
| 	board=$(board_name) | ||||
| @@ -26,6 +73,8 @@ platform_check_image() { | ||||
| 	cig,wf194c4|\ | ||||
| 	cig,wf196|\ | ||||
| 	cybertan,eww622-a1|\ | ||||
| 	glinet,ax1800|\ | ||||
| 	glinet,axt1800|\ | ||||
| 	wallys,dr6018|\ | ||||
| 	wallys,dr6018-v4|\ | ||||
| 	edgecore,eap101|\ | ||||
| @@ -36,6 +85,8 @@ platform_check_image() { | ||||
| 	hfcl,ion4xe|\ | ||||
| 	tplink,ex227|\ | ||||
| 	tplink,ex447|\ | ||||
| 	yuncore,ax840|\ | ||||
| 	motorola,q14|\ | ||||
| 	qcom,ipq6018-cp01|\ | ||||
| 	qcom,ipq807x-hk01|\ | ||||
| 	qcom,ipq807x-hk14|\ | ||||
| @@ -56,30 +107,58 @@ platform_do_upgrade() { | ||||
| 	cig,wf188) | ||||
| 		qca_do_upgrade $1 | ||||
| 		;; | ||||
| 	motorola,q14) | ||||
| 		emmc_do_upgrade $1 | ||||
| 		;; | ||||
| 	cig,wf188n|\ | ||||
| 	cig,wf194c|\ | ||||
| 	cig,wf194c4|\ | ||||
| 	cig,wf196|\ | ||||
| 	cybertan,eww622-a1|\ | ||||
| 	edgecore,eap104|\ | ||||
| 	hfcl,ion4xi|\ | ||||
| 	hfcl,ion4xe|\ | ||||
| 	glinet,ax1800|\ | ||||
| 	glinet,axt1800|\ | ||||
| 	qcom,ipq6018-cp01|\ | ||||
| 	qcom,ipq807x-hk01|\ | ||||
| 	qcom,ipq807x-hk14|\ | ||||
| 	qcom,ipq5018-mp03.3|\ | ||||
| 	wallys,dr6018|\ | ||||
| 	wallys,dr6018-v4|\ | ||||
| 	yuncore,ax840|\ | ||||
| 	tplink,ex447|\ | ||||
| 	tplink,ex227)	 | ||||
| 		nand_upgrade_tar "$1" | ||||
| 		;; | ||||
| 	edgecore,eap106|\ | ||||
| 	edgecore,eap102|\ | ||||
| 	edgecore,eap101) | ||||
| 	hfcl,ion4xi|\ | ||||
| 	hfcl,ion4xe) | ||||
| 		if grep -q rootfs_1 /proc/cmdline; then | ||||
| 			CI_UBIPART="rootfs" | ||||
| 			fw_setenv primary 0 || exit 1 | ||||
| 		else | ||||
| 			CI_UBIPART="rootfs_1" | ||||
| 			fw_setenv primary 1 || exit 1 | ||||
| 		fi | ||||
| 		nand_upgrade_tar "$1" | ||||
| 		;; | ||||
| 	edgecore,eap106) | ||||
| 		CI_UBIPART="rootfs1" | ||||
| 		[ "$(find_mtd_chardev rootfs)" ] && CI_UBIPART="rootfs" | ||||
| 		nand_upgrade_tar "$1" | ||||
| 		;; | ||||
| 	edgecore,eap101|\ | ||||
| 	edgecore,eap102) | ||||
| 		if [ "$(find_mtd_chardev rootfs)" ]; then | ||||
| 			CI_UBIPART="rootfs" | ||||
| 		else | ||||
| 			if grep -q rootfs1 /proc/cmdline; then | ||||
| 				CI_UBIPART="rootfs2" | ||||
| 				fw_setenv active 2 || exit 1 | ||||
| 			else | ||||
| 				CI_UBIPART="rootfs1" | ||||
| 				fw_setenv active 1 || exit 1 | ||||
| 			fi | ||||
| 		fi | ||||
| 		nand_upgrade_tar "$1" | ||||
| 		;; | ||||
| 	esac | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,23 @@ | ||||
| /* | ||||
|  * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. | ||||
|  * | ||||
|  * Permission to use, copy, modify, and/or distribute this software for any | ||||
|  * purpose with or without fee is hereby granted, provided that the above | ||||
|  * copyright notice and this permission notice appear in all copies. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||||
|  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||||
|  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||||
|  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||||
|  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||||
|  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||||
|  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| #include "../../../arm64/boot/dts/qcom/qcom-ipq5018-q14.dts" | ||||
|  | ||||
| / { | ||||
| 	pmuv8: pmu { | ||||
| 		compatible = "arm,cortex-a7-pmu"; | ||||
| 	}; | ||||
| }; | ||||
| @@ -0,0 +1,18 @@ | ||||
| /* | ||||
|  * Copyright (c) 2019, The Linux Foundation. All rights reserved. | ||||
|  * | ||||
|  * Permission to use, copy, modify, and/or distribute this software for any | ||||
|  * purpose with or without fee is hereby granted, provided that the above | ||||
|  * copyright notice and this permission notice appear in all copies. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||||
|  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||||
|  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||||
|  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||||
|  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||||
|  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||||
|  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| #include "../../../arm64/boot/dts/qcom/qcom-ipq6018-gl-ax1800.dts" | ||||
| #include "qcom-ipq6018.dtsi" | ||||
| @@ -0,0 +1,18 @@ | ||||
| /* | ||||
|  * Copyright (c) 2019, The Linux Foundation. All rights reserved. | ||||
|  * | ||||
|  * Permission to use, copy, modify, and/or distribute this software for any | ||||
|  * purpose with or without fee is hereby granted, provided that the above | ||||
|  * copyright notice and this permission notice appear in all copies. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||||
|  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||||
|  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||||
|  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||||
|  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||||
|  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||||
|  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| #include "../../../arm64/boot/dts/qcom/qcom-ipq6018-gl-axt1800.dts" | ||||
| #include "qcom-ipq6018.dtsi" | ||||
| @@ -0,0 +1,18 @@ | ||||
| /* | ||||
|  * Copyright (c) 2019, The Linux Foundation. All rights reserved. | ||||
|  * | ||||
|  * Permission to use, copy, modify, and/or distribute this software for any | ||||
|  * purpose with or without fee is hereby granted, provided that the above | ||||
|  * copyright notice and this permission notice appear in all copies. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||||
|  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||||
|  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||||
|  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||||
|  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||||
|  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||||
|  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| #include "../../../arm64/boot/dts/qcom/qcom-ipq6018-yuncore-ax840.dts" | ||||
| #include "qcom-ipq6018.dtsi" | ||||
| @@ -32,6 +32,10 @@ | ||||
| 		serial1 = &blsp1_uart2; | ||||
| 		ethernet0 = "/soc/dp1"; | ||||
| 		ethernet1 = "/soc/dp2"; | ||||
| 	        led-boot = &led_sys; | ||||
| 		led-failsafe = &led_sys; | ||||
| 		led-running = &led_sys; | ||||
| 		led-upgrade = &led_sys; | ||||
| 	}; | ||||
|  | ||||
| 	chosen { | ||||
| @@ -708,32 +712,20 @@ | ||||
| 		pinctrl-0 = <&leds_pins>; | ||||
| 		pinctrl-names = "default"; | ||||
|  | ||||
| 		led@1 { | ||||
| 		led_sys: led@1 { | ||||
| 			label = "sys:blue"; | ||||
| 			gpios = <&tlmm 1 GPIO_ACTIVE_HIGH>;  /* GPIO_1 */ | ||||
| 		/*	default-state="on"; */ | ||||
| 			linux,default-trigger = "timer"; | ||||
| 			active-delay = <700>; | ||||
| 			inactive-delay = <700>; | ||||
| 			default-state="on"; | ||||
| 		}; | ||||
| 		led@35 { | ||||
| 			label = "sys:green"; | ||||
| 			gpios = <&tlmm 35 GPIO_ACTIVE_HIGH>;  /* GPIO_35 */ | ||||
| 			default-state="off"; | ||||
| 		/*	linux,default-trigger = "timer"; | ||||
| 			active-delay = <700>; | ||||
| 			inactive-delay = <700>; | ||||
| 			default-state="on";		*/ | ||||
| 		}; | ||||
| 		led@31 { | ||||
| 			label = "sys:red"; | ||||
| 			gpios = <&tlmm 31 GPIO_ACTIVE_HIGH>;  /* GPIO_31 */ | ||||
| 			default-state="off"; | ||||
| 		/*	linux,default-trigger = "timer"; | ||||
| 			active-delay = <700>; | ||||
| 			inactive-delay = <700>; | ||||
| 			default-state="on";		*/ | ||||
| 		}; | ||||
| 	}; | ||||
| }; | ||||
|   | ||||
							
								
								
									
										886
									
								
								feeds/ipq807x/ipq807x/files/arch/arm64/boot/dts/qcom/qcom-ipq5018-q14.dts
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										886
									
								
								feeds/ipq807x/ipq807x/files/arch/arm64/boot/dts/qcom/qcom-ipq5018-q14.dts
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,886 @@ | ||||
| /dts-v1/; | ||||
| /* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. | ||||
|  * | ||||
|  * Permission to use, copy, modify, and/or distribute this software for any | ||||
|  * purpose with or without fee is hereby granted, provided that the above | ||||
|  * copyright notice and this permission notice appear in all copies. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||||
|  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||||
|  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||||
|  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||||
|  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||||
|  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||||
|  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| #include "qcom-ipq5018.dtsi" | ||||
|  | ||||
| / { | ||||
| 	#address-cells = <0x2>; | ||||
| 	#size-cells = <0x2>; | ||||
| 	model = "Motorola Q14"; | ||||
| 	compatible = "motorola,q14", "qcom,ipq5018-mp03.5-c1", "qcom,ipq5018"; | ||||
| 	interrupt-parent = <&intc>; | ||||
|  | ||||
| 	aliases { | ||||
| 		sdhc1 = &sdhc_1; /* SDC1 eMMC slot */ | ||||
| 		serial0 = &blsp1_uart1; | ||||
| 		serial1 = &blsp1_uart2; | ||||
| 		ethernet0 = "/soc/dp1"; | ||||
| 		ethernet1 = "/soc/dp2"; | ||||
| 	}; | ||||
|  | ||||
| 	chosen { | ||||
| 		bootargs = "console=ttyMSM0,115200,n8 rw init=/init"; | ||||
| 	#ifdef __IPQ_MEM_PROFILE_256_MB__ | ||||
| 		bootargs-append = " swiotlb=1"; | ||||
| 	#else | ||||
| 		bootargs-append = " swiotlb=1 coherent_pool=2M"; | ||||
| 	#endif | ||||
| 		stdout-path = "serial0"; | ||||
| 	}; | ||||
|  | ||||
| 	reserved-memory { | ||||
| 	#ifdef __IPQ_MEM_PROFILE_256_MB__ | ||||
| 	/*                   256 MB Profile | ||||
| 	 * +==========+==============+=========================+ | ||||
| 	 * |          |              |                         | | ||||
| 	 * |  Region  | Start Offset |          Size           | | ||||
| 	 * |          |              |                         | | ||||
| 	 * +----------+--------------+-------------------------+ | ||||
| 	 * |    NSS   |  0x40000000  |           8MB           | | ||||
| 	 * +----------+--------------+-------------------------+ | ||||
| 	 * |   Linux  |  0x40800000  | Depends on total memory | | ||||
| 	 * +----------+--------------+-------------------------+ | ||||
| 	 * |   uboot  |  0x4A600000  |           4MB           | | ||||
| 	 * +----------+--------------+-------------------------+ | ||||
| 	 * |    SBL   |  0x4AA00000  |           1MB           | | ||||
| 	 * +----------+--------------+-------------------------+ | ||||
| 	 * |   smem   |  0x4AB00000  |           1MB           | | ||||
| 	 * +----------+--------------+-------------------------+ | ||||
| 	 * |    TZ    |  0x4AC00000  |           4MB           | | ||||
| 	 * +----------+--------------+-------------------------+ | ||||
| 	 * |    Q6    |              |                         | | ||||
| 	 * |   code/  |  0x4B000000  |          20MB           | | ||||
| 	 * |   data   |              |                         | | ||||
| 	 * +----------+--------------+-------------------------+ | ||||
| 	 * |  IPQ5018 |              |                         | | ||||
| 	 * |   data   |  0x4C400000  |          13MB           | | ||||
| 	 * +----------+--------------+-------------------------+ | ||||
| 	 * |  IPQ5018 |              |                         | | ||||
| 	 * |  M3 Dump |  0x4D100000  |           1MB           | | ||||
| 	 * +----------+--------------+-------------------------+ | ||||
| 	 * |  IPQ5018 |              |                         | | ||||
| 	 * |   QDSS   |  0x4D200000  |           1MB           | | ||||
| 	 * +----------+--------------+-------------------------+ | ||||
| 	 * | QCN6122_1|              |                         | | ||||
| 	 * |   data   |  0x4D300000  |          15MB           | | ||||
| 	 * +----------+--------------+-------------------------+ | ||||
| 	 * | QCN6122_1|              |                         | | ||||
| 	 * |  M3 Dump |  0x4E200000  |           1MB           | | ||||
| 	 * +----------+--------------+-------------------------+ | ||||
| 	 * | QCN6122_1|              |                         | | ||||
| 	 * |   QDSS   |  0x4E300000  |           1MB           | | ||||
| 	 * +----------+--------------+-------------------------+ | ||||
| 	 * | QCN6122_2|              |                         | | ||||
| 	 * |   data   |  0x4E400000  |          15MB           | | ||||
| 	 * +----------+--------------+-------------------------+ | ||||
| 	 * | QCN6122_2|              |                         | | ||||
| 	 * |  M3 Dump |  0x4F300000  |           1MB           | | ||||
| 	 * +----------+--------------+-------------------------+ | ||||
| 	 * | QCN6122_2|              |                         | | ||||
| 	 * |   QDSS   |  0x4F400000  |           1MB           | | ||||
| 	 * +----------+--------------+-------------------------+ | ||||
| 	 * |                                                   | | ||||
| 	 * |            Rest of the memory for Linux           | | ||||
| 	 * |                                                   | | ||||
| 	 * +===================================================+ | ||||
| 	 */ | ||||
| 		q6_mem_regions: q6_mem_regions@4B000000 { | ||||
| 			no-map; | ||||
| 			reg = <0x0 0x4B000000 0x0 0x4500000>; | ||||
| 		}; | ||||
|  | ||||
| 		q6_code_data: q6_code_data@4B000000 { | ||||
| 			no-map; | ||||
| 			reg = <0x0 0x4B000000 0x0 0x1400000>; | ||||
| 		}; | ||||
|  | ||||
| 		q6_ipq5018_data: q6_ipq5018_data@4C400000 { | ||||
| 			no-map; | ||||
| 			reg = <0x0 0x4C400000 0x0 0xD00000>; | ||||
| 		}; | ||||
|  | ||||
| 		m3_dump: m3_dump@4D100000 { | ||||
| 			no-map; | ||||
| 			reg = <0x0 0x4D100000 0x0 0x100000>; | ||||
| 		}; | ||||
|  | ||||
| 		q6_etr_region: q6_etr_dump@4D200000 { | ||||
| 			no-map; | ||||
| 			reg = <0x0 0x4D200000 0x0 0x100000>; | ||||
| 		}; | ||||
|  | ||||
| 		q6_qcn6122_data1: q6_qcn6122_data1@4D300000 { | ||||
| 			no-map; | ||||
| 			reg = <0x0 0x4D300000 0x0 0xF00000>; | ||||
| 		}; | ||||
|  | ||||
| 		m3_dump_qcn6122_1: m3_dump_qcn6122_1@4E200000 { | ||||
| 			no-map; | ||||
| 			reg = <0x0 0x4E200000 0x0 0x100000>; | ||||
| 		}; | ||||
|  | ||||
| 		q6_qcn6122_etr_1: q6_qcn6122_etr_1@4E300000 { | ||||
| 			no-map; | ||||
| 			reg = <0x0 0x4E300000 0x0 0x100000>; | ||||
| 		}; | ||||
|  | ||||
| 		q6_qcn6122_data2: q6_qcn6122_data2@4E400000 { | ||||
| 			no-map; | ||||
| 			reg = <0x0 0x4E400000 0x0 0xF00000>; | ||||
| 		}; | ||||
|  | ||||
| 		m3_dump_qcn6122_2: m3_dump_qcn6122_2@4F300000 { | ||||
| 			no-map; | ||||
| 			reg = <0x0 0x4F300000 0x0 0x100000>; | ||||
| 		}; | ||||
|  | ||||
| 		q6_qcn6122_etr_2: q6_qcn6122_etr_2@4F400000 { | ||||
| 			no-map; | ||||
| 			reg = <0x0 0x4F400000 0x0 0x100000>; | ||||
| 		}; | ||||
| 	#else | ||||
| 	/*                 512MB/1GB Profiles | ||||
| 	 * +==========+==============+=========================+ | ||||
| 	 * |          |              |                         | | ||||
| 	 * |  Region  | Start Offset |          Size           | | ||||
| 	 * |          |              |                         | | ||||
| 	 * +----------+--------------+-------------------------+ | ||||
| 	 * |    NSS   |  0x40000000  |          16MB           | | ||||
| 	 * +----------+--------------+-------------------------+ | ||||
| 	 * |   Linux  |  0x41000000  | Depends on total memory | | ||||
| 	 * +----------+--------------+-------------------------+ | ||||
| 	 * |   uboot  |  0x4A600000  |           4MB           | | ||||
| 	 * +----------+--------------+-------------------------+ | ||||
| 	 * |    SBL   |  0x4AA00000  |           1MB           | | ||||
| 	 * +----------+--------------+-------------------------+ | ||||
| 	 * |   smem   |  0x4AB00000  |           1MB           | | ||||
| 	 * +----------+--------------+-------------------------+ | ||||
| 	 * |    TZ    |  0x4AC00000  |           4MB           | | ||||
| 	 * +----------+--------------+-------------------------+ | ||||
| 	 * |    Q6    |              |                         | | ||||
| 	 * |   code/  |  0x4B000000  |          20MB           | | ||||
| 	 * |   data   |              |                         | | ||||
| 	 * +----------+--------------+-------------------------+ | ||||
| 	 * |  IPQ5018 |              |                         | | ||||
| 	 * |   data   |  0x4C400000  |          14MB           | | ||||
| 	 * +----------+--------------+-------------------------+ | ||||
| 	 * |  IPQ5018 |              |                         | | ||||
| 	 * |  M3 Dump |  0x4D200000  |           1MB           | | ||||
| 	 * +----------+--------------+-------------------------+ | ||||
| 	 * |  IPQ5018 |              |                         | | ||||
| 	 * |   QDSS   |  0x4D300000  |           1MB           | | ||||
| 	 * +----------+--------------+-------------------------+ | ||||
| 	 * |  IPQ5018 |              |                         | | ||||
| 	 * |  Caldb   |  0x4D400000  |           2MB           | | ||||
| 	 * +----------+--------------+-------------------------+ | ||||
| 	 * | QCN6122_1|              |                         | | ||||
| 	 * |   data   |  0x4D600000  |          16MB           | | ||||
| 	 * +----------+--------------+-------------------------+ | ||||
| 	 * | QCN6122_1|              |                         | | ||||
| 	 * |  M3 Dump |  0x4E600000  |           1MB           | | ||||
| 	 * +----------+--------------+-------------------------+ | ||||
| 	 * | QCN6122_1|              |                         | | ||||
| 	 * |   QDSS   |  0x4E700000  |           1MB           | | ||||
| 	 * +----------+--------------+-------------------------+ | ||||
| 	 * | QCN6122_1|              |                         | | ||||
| 	 * |  Caldb   |  0x4E800000  |           5MB           | | ||||
| 	 * +----------+--------------+-------------------------+ | ||||
| 	 * | QCN6122_2|              |                         | | ||||
| 	 * |   data   |  0x4ED00000  |          16MB           | | ||||
| 	 * +----------+--------------+-------------------------+ | ||||
| 	 * | QCN6122_2|              |                         | | ||||
| 	 * |  M3 Dump |  0x4FD00000  |           1MB           | | ||||
| 	 * +----------+--------------+-------------------------+ | ||||
| 	 * | QCN6122_2|              |                         | | ||||
| 	 * |   QDSS   |  0x4FE00000  |           1MB           | | ||||
| 	 * +----------+--------------+-------------------------+ | ||||
| 	 * | QCN6122_2|              |                         | | ||||
| 	 * |  Caldb   |  0x4FF00000  |           5MB           | | ||||
| 	 * +----------+--------------+-------------------------+ | ||||
| 	 * |                                                   | | ||||
| 	 * |            Rest of the memory for Linux           | | ||||
| 	 * |                                                   | | ||||
| 	 * +===================================================+ | ||||
| 	 */ | ||||
| 		q6_mem_regions: q6_mem_regions@4B000000 { | ||||
| 			no-map; | ||||
| 			reg = <0x0 0x4B000000 0x0 0x5400000>; | ||||
| 		}; | ||||
|  | ||||
| 		q6_code_data: q6_code_data@4B000000 { | ||||
| 			no-map; | ||||
| 			reg = <0x0 0x4B000000 0x0 01400000>; | ||||
| 		}; | ||||
|  | ||||
| 		q6_ipq5018_data: q6_ipq5018_data@4C400000 { | ||||
| 			no-map; | ||||
| 			reg = <0x0 0x4C400000 0x0 0xE00000>; | ||||
| 		}; | ||||
|  | ||||
| 		m3_dump: m3_dump@4D200000 { | ||||
| 			no-map; | ||||
| 			reg = <0x0 0x4D200000 0x0 0x100000>; | ||||
| 		}; | ||||
|  | ||||
| 		q6_etr_region: q6_etr_dump@4D300000 { | ||||
| 			no-map; | ||||
| 			reg = <0x0 0x4D300000 0x0 0x100000>; | ||||
| 		}; | ||||
|  | ||||
| 		q6_caldb_region: q6_caldb_region@4D400000 { | ||||
| 			no-map; | ||||
| 			reg = <0x0 0x4D400000 0x0 0x200000>; | ||||
| 		}; | ||||
|  | ||||
| 		q6_qcn6122_data1: q6_qcn6122_data1@4D600000 { | ||||
| 			no-map; | ||||
| 			reg = <0x0 0x4D600000 0x0 0x1000000>; | ||||
| 		}; | ||||
|  | ||||
| 		m3_dump_qcn6122_1: m3_dump_qcn6122_1@4E600000 { | ||||
| 			no-map; | ||||
| 			reg = <0x0 0x4E600000 0x0 0x100000>; | ||||
| 		}; | ||||
|  | ||||
| 		q6_qcn6122_etr_1: q6_qcn6122_etr_1@4E700000 { | ||||
| 			no-map; | ||||
| 			reg = <0x0 0x4E700000 0x0 0x100000>; | ||||
| 		}; | ||||
|  | ||||
| 		q6_qcn6122_caldb_1: q6_qcn6122_caldb_1@4E800000 { | ||||
| 			no-map; | ||||
| 			reg = <0x0 0x4E800000 0x0 0x500000>; | ||||
| 		}; | ||||
|  | ||||
| 		q6_qcn6122_data2: q6_qcn6122_data2@4E900000 { | ||||
| 			no-map; | ||||
| 			reg = <0x0 0x4ED00000 0x0 0x1000000>; | ||||
| 		}; | ||||
|  | ||||
| 		m3_dump_qcn6122_2: m3_dump_qcn6122_2@4FD00000 { | ||||
| 			no-map; | ||||
| 			reg = <0x0 0x4FD00000 0x0 0x100000>; | ||||
| 		}; | ||||
|  | ||||
| 		q6_qcn6122_etr_2: q6_qcn6122_etr_2@4FE00000 { | ||||
| 			no-map; | ||||
| 			reg = <0x0 0x4FE00000 0x0 0x100000>; | ||||
| 		}; | ||||
|  | ||||
| 		q6_qcn6122_caldb_2: q6_qcn6122_caldb_2@4FF00000 { | ||||
| 			no-map; | ||||
| 			reg = <0x0 0x4FF00000 0x0 0x500000>; | ||||
| 		}; | ||||
|  | ||||
| 	#endif | ||||
| 	}; | ||||
|  | ||||
| 	soc { | ||||
| 		serial@78af000 { | ||||
| 			status = "ok"; | ||||
| 		}; | ||||
|  | ||||
| 		blsp1_uart2: serial@78b0000 { | ||||
| 			pinctrl-0 = <&blsp1_uart_pins>; | ||||
| 			pinctrl-names = "default"; | ||||
| 		}; | ||||
|  | ||||
| 		qpic_bam: dma@7984000{ | ||||
| 			status = "ok"; | ||||
| 		}; | ||||
|  | ||||
| 		nand: qpic-nand@79b0000 { | ||||
| 			status = "disabled"; | ||||
| 		}; | ||||
|  | ||||
| 		spi_0: spi@78b5000 { /* BLSP1 QUP0 */ | ||||
| 			pinctrl-0 = <&blsp0_spi_pins>; | ||||
| 			pinctrl-names = "default"; | ||||
| 			cs-select = <0>; | ||||
| 			status = "ok"; | ||||
|  | ||||
| 			m25p80@0 { | ||||
| 				#address-cells = <1>; | ||||
| 				#size-cells = <1>; | ||||
| 				reg = <0>; | ||||
| 				compatible = "n25q128a11"; | ||||
| 				linux,modalias = "m25p80", "n25q128a11"; | ||||
| 				spi-max-frequency = <50000000>; | ||||
| 				use-default-sizes; | ||||
| 			}; | ||||
| 		}; | ||||
|  | ||||
| 		mdio0: mdio@88000 { | ||||
| 			status = "ok"; | ||||
|  | ||||
| 			ethernet-phy@0 { | ||||
| 				reg = <7>; | ||||
| 			}; | ||||
| 		}; | ||||
|  | ||||
| 		mdio1: mdio@90000 { | ||||
| 			status = "ok"; | ||||
| 			pinctrl-0 = <&mdio1_pins>; | ||||
| 			pinctrl-names = "default"; | ||||
| 			phy-reset-gpio = <&tlmm 39 0>; | ||||
|  | ||||
| 			ethernet-phy@0 { | ||||
| 				reg = <28>; | ||||
| 			}; | ||||
| 		}; | ||||
|  | ||||
| 		ess-instance { | ||||
| 			num_devices = <0x1>; | ||||
| 			ess-switch@0x39c00000 { | ||||
| 				switch_mac_mode = <0xf>; /* mac mode for uniphy instance*/ | ||||
| 				cmnblk_clk = "internal_96MHz"; /* cmnblk clk*/ | ||||
| 				qcom,port_phyinfo { | ||||
| 					port@0 { | ||||
| 						port_id = <1>; | ||||
| 						phy_address = <7>; | ||||
| 						mdiobus = <&mdio0>; | ||||
| 					}; | ||||
| 					port@1 { | ||||
| 						port_id = <2>; | ||||
| 						phy_address = <0x1c>; | ||||
| 						mdiobus = <&mdio1>; | ||||
| 						port_mac_sel = "QGMAC_PORT"; | ||||
| 					}; | ||||
| 				}; | ||||
| 				led_source@0 { | ||||
| 					source = <0>; | ||||
| 					mode = "normal"; | ||||
| 					speed = "all"; | ||||
| 					blink_en = "enable"; | ||||
| 					active = "high"; | ||||
| 				}; | ||||
| 			}; | ||||
| 		}; | ||||
|  | ||||
| 		dp1 { | ||||
| 			device_type = "network"; | ||||
| 			compatible = "qcom,nss-dp"; | ||||
| 			clocks = <&gcc GCC_SNOC_GMAC0_AXI_CLK>; | ||||
| 			clock-names = "nss-snoc-gmac-axi-clk"; | ||||
| 			qcom,id = <1>; | ||||
| 			reg = <0x39C00000 0x10000>; | ||||
| 			interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>; | ||||
| 			qcom,mactype = <2>; | ||||
| 			qcom,link-poll = <1>; | ||||
| 			qcom,phy-mdio-addr = <7>; | ||||
| 			mdio-bus = <&mdio0>; | ||||
| 			local-mac-address = [000000000000]; | ||||
| 			phy-mode = "sgmii"; | ||||
| 		}; | ||||
|  | ||||
| 		dp2 { | ||||
| 			device_type = "network"; | ||||
| 			compatible = "qcom,nss-dp"; | ||||
| 			clocks = <&gcc GCC_SNOC_GMAC1_AXI_CLK>; | ||||
| 			clock-names = "nss-snoc-gmac-axi-clk"; | ||||
| 			qcom,id = <2>; | ||||
| 			reg = <0x39D00000 0x10000>; | ||||
| 			interrupts = <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>; | ||||
| 			qcom,mactype = <2>; | ||||
| 			qcom,link-poll = <1>; | ||||
| 			qcom,phy-mdio-addr = <28>; | ||||
| 			mdio-bus = <&mdio1>; | ||||
| 			local-mac-address = [000000000000]; | ||||
| 			phy-mode = "sgmii"; | ||||
| 		}; | ||||
|  | ||||
| 		qcom,test@0 { | ||||
| 			status = "ok"; | ||||
| 		}; | ||||
|  | ||||
| 		nss-macsec1 { | ||||
| 			compatible = "qcom,nss-macsec"; | ||||
| 			phy_addr = <0x1c>; | ||||
| 			mdiobus = <&mdio1>; | ||||
| 		}; | ||||
|  | ||||
| 		lpass: lpass@0xA000000{ | ||||
| 			status = "disabled"; | ||||
| 		}; | ||||
|  | ||||
| 		pcm: pcm@0xA3C0000{ | ||||
| 			pinctrl-0 = <&audio_pins>; | ||||
| 			pinctrl-names = "default"; | ||||
| 			status = "disabled"; | ||||
| 		}; | ||||
|  | ||||
| 		pcm_lb: pcm_lb@0 { | ||||
| 			status = "disabled"; | ||||
| 		}; | ||||
| 	}; | ||||
|  | ||||
| 	thermal-zones { | ||||
| 		status = "ok"; | ||||
| 	}; | ||||
| }; | ||||
|  | ||||
| &sdhc_1 { | ||||
| 	pinctrl-0 = <&emmc_pins>; | ||||
| 	pinctrl-names = "default"; | ||||
| 	qcom,clk-rates = <400000 25000000 50000000 100000000 \ | ||||
| 			 192000000 384000000>; | ||||
| 	qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v"; | ||||
| 	qcom,nonremovable; | ||||
| 	status = "ok"; | ||||
| }; | ||||
|  | ||||
| &tlmm { | ||||
| 	pinctrl-0 = <&blsp0_uart_pins &phy_led_pins>; | ||||
| 	pinctrl-names = "default"; | ||||
|  | ||||
| 	blsp0_uart_pins: uart_pins { | ||||
| 		blsp0_uart_rx_tx { | ||||
| 			pins = "gpio20", "gpio21"; | ||||
| 			function = "blsp0_uart0"; | ||||
| 			bias-disable; | ||||
| 		}; | ||||
| 	}; | ||||
|  | ||||
| 	blsp1_uart_pins: blsp1_uart_pins { | ||||
| 		blsp1_uart_rx_tx { | ||||
| 			pins = "gpio23", "gpio25", "gpio24", "gpio26"; | ||||
| 			function = "blsp1_uart2"; | ||||
| 			bias-disable; | ||||
| 		}; | ||||
| 	}; | ||||
|  | ||||
| 	blsp0_spi_pins: blsp0_spi_pins { | ||||
| 		mux { | ||||
| 			pins = "gpio10", "gpio11", "gpio12", "gpio13"; | ||||
| 			function = "blsp0_spi"; | ||||
| 			drive-strength = <2>; | ||||
| 			bias-disable; | ||||
| 		}; | ||||
| 	}; | ||||
|  | ||||
| 	emmc_pins: emmc_pins { | ||||
| 		emmc_clk { | ||||
| 				pins = "gpio9"; | ||||
| 				function = "sdc1_clk"; | ||||
| 				drive-strength = <8>; | ||||
| 				bias-disable; | ||||
| 			}; | ||||
| 		emmc_cmd { | ||||
| 				pins = "gpio8"; | ||||
| 				function = "sdc1_cmd"; | ||||
| 				drive-strength = <8>; | ||||
| 				bias-pull-up; | ||||
| 			}; | ||||
| 		emmc_data_0 { | ||||
| 				pins = "gpio7"; | ||||
| 				function = "sdc10"; | ||||
| 				drive-strength = <8>; | ||||
| 				bias-disable; | ||||
| 			}; | ||||
| 		emmc_data_1 { | ||||
| 				pins = "gpio6"; | ||||
| 				function = "sdc11"; | ||||
| 				drive-strength = <8>; | ||||
| 				bias-disable; | ||||
| 			}; | ||||
| 		emmc_data_2 { | ||||
| 				pins = "gpio5"; | ||||
| 				function = "sdc12"; | ||||
| 				drive-strength = <8>; | ||||
| 				bias-disable; | ||||
| 			}; | ||||
| 		emmc_data_3 { | ||||
| 				pins = "gpio4"; | ||||
| 				function = "sdc13"; | ||||
| 				drive-strength = <8>; | ||||
| 				bias-disable; | ||||
| 			}; | ||||
| 	}; | ||||
|  | ||||
| 	mdio1_pins: mdio_pinmux { | ||||
| 		mux_0 { | ||||
| 			pins = "gpio36"; | ||||
| 			function = "mdc"; | ||||
| 			drive-strength = <8>; | ||||
| 			bias-pull-up; | ||||
| 		}; | ||||
|  | ||||
| 		mux_1 { | ||||
| 			pins = "gpio37"; | ||||
| 			function = "mdio"; | ||||
| 			drive-strength = <8>; | ||||
| 			bias-pull-up; | ||||
| 		}; | ||||
| 	}; | ||||
|  | ||||
| 	phy_led_pins: phy_led_pins { | ||||
| 		gephy_led_pin { | ||||
| 			pins = "gpio46"; | ||||
| 			function = "led0"; | ||||
| 			drive-strength = <8>; | ||||
| 			bias-pull-down; | ||||
| 		}; | ||||
| 	}; | ||||
|  | ||||
| 	i2c_pins: i2c_pins { | ||||
| 		i2c_scl { | ||||
| 			pins = "gpio25"; | ||||
| 			function = "blsp2_i2c1"; | ||||
| 			drive-strength = <8>; | ||||
| 			bias-disable; | ||||
| 		}; | ||||
|  | ||||
| 		i2c_sda { | ||||
| 			pins = "gpio26"; | ||||
| 			function = "blsp2_i2c1"; | ||||
| 			drive-strength = <8>; | ||||
| 			bias-disable; | ||||
| 		}; | ||||
| 	}; | ||||
|  | ||||
| 	button_pins: button_pins { | ||||
| 		wps_button { | ||||
| 			pins = "gpio38"; | ||||
| 			function = "gpio"; | ||||
| 			drive-strength = <8>; | ||||
| 			bias-pull-up; | ||||
| 		}; | ||||
| 		 | ||||
| 		reset_button { | ||||
| 			pins = "gpio31"; | ||||
| 			function = "gpio"; | ||||
| 			drive-strength = <8>; | ||||
| 			bias-pull-up; | ||||
| 		};		 | ||||
| 		 | ||||
| 	}; | ||||
|  | ||||
| 	audio_pins: audio_pinmux { | ||||
| 		mux_1 { | ||||
| 			pins = "gpio24"; | ||||
| 			function = "audio_rxbclk"; | ||||
| 			drive-strength = <8>; | ||||
| 			bias-pull-down; | ||||
| 		}; | ||||
|  | ||||
| 		mux_2 { | ||||
| 			pins = "gpio25"; | ||||
| 			function = "audio_rxfsync"; | ||||
| 			drive-strength = <8>; | ||||
| 			bias-pull-down; | ||||
| 		}; | ||||
|  | ||||
| 		mux_3 { | ||||
| 			pins = "gpio26"; | ||||
| 			function = "audio_rxd"; | ||||
| 			drive-strength = <8>; | ||||
| 			bias-pull-down; | ||||
| 		}; | ||||
|  | ||||
| 		mux_4 { | ||||
| 			pins = "gpio27"; | ||||
| 			function = "audio_txmclk"; | ||||
| 			drive-strength = <8>; | ||||
| 			bias-pull-down; | ||||
| 		}; | ||||
|  | ||||
| 		mux_5 { | ||||
| 			pins = "gpio28"; | ||||
| 			function = "audio_txbclk"; | ||||
| 			drive-strength = <8>; | ||||
| 			bias-pull-down; | ||||
| 		}; | ||||
|  | ||||
| 		mux_6 { | ||||
| 			pins = "gpio29"; | ||||
| 			function = "audio_txfsync"; | ||||
| 			drive-strength = <8>; | ||||
| 			bias-pull-down; | ||||
| 		}; | ||||
|  | ||||
| 		mux_7 { | ||||
| 			pins = "gpio30"; | ||||
| 			function = "audio_txd"; | ||||
| 			drive-strength = <8>; | ||||
| 			bias-pull-down; | ||||
| 		}; | ||||
| 	}; | ||||
|  | ||||
| }; | ||||
|  | ||||
| &soc { | ||||
| 	gpio_keys { | ||||
| 		compatible = "gpio-keys"; | ||||
| 		pinctrl-0 = <&button_pins>; | ||||
| 		pinctrl-names = "default"; | ||||
|  | ||||
| 		button@1 { | ||||
| 			label = "wps"; | ||||
| 			linux,code = <KEY_WPS_BUTTON>; | ||||
| 			gpios = <&tlmm 38 GPIO_ACTIVE_LOW>; | ||||
| 			linux,input-type = <1>; | ||||
| 			debounce-interval = <60>; | ||||
| 		}; | ||||
| 		 | ||||
| 		button@2 { | ||||
| 			label = "reset"; | ||||
| 			linux,code = <KEY_RESTART>; | ||||
| 			gpios = <&tlmm 31 GPIO_ACTIVE_LOW>; | ||||
| 			linux,input-type = <1>; | ||||
| 			debounce-interval = <60>; | ||||
| 		};			 | ||||
| 		 | ||||
| 	}; | ||||
| }; | ||||
|  | ||||
| &usb3 { | ||||
| 	status = "ok"; | ||||
| 	device-power-gpio = <&tlmm 24 1>; | ||||
| }; | ||||
|  | ||||
| &eud { | ||||
| 	status = "ok"; | ||||
| }; | ||||
|  | ||||
| &pcie_x1 { | ||||
| 	status = "ok"; | ||||
| 	perst-gpio = <&tlmm 18 1>; | ||||
| }; | ||||
|  | ||||
| &pcie_x2 { | ||||
| 	status = "ok"; | ||||
| 	perst-gpio = <&tlmm 15 1>; | ||||
| }; | ||||
|  | ||||
| &dwc_0 { | ||||
| 	/delete-property/ #phy-cells; | ||||
| 	/delete-property/ phys; | ||||
| 	/delete-property/ phy-names; | ||||
| }; | ||||
|  | ||||
| &hs_m31phy_0 { | ||||
| 	status = "ok"; | ||||
| }; | ||||
|  | ||||
| &pcie_x1phy { | ||||
| 	status = "ok"; | ||||
| }; | ||||
|  | ||||
| &pcie_x2phy { | ||||
| 	status = "ok"; | ||||
| }; | ||||
|  | ||||
| &pcie_x1_rp { | ||||
|         status = "ok"; | ||||
|  | ||||
| 	mhi_0: qcom,mhi@0 { | ||||
| 		reg = <0 0 0 0 0 >; | ||||
| 	}; | ||||
| }; | ||||
|  | ||||
| &pcie_x2_rp { | ||||
|         status = "ok"; | ||||
|  | ||||
| 	mhi_1: qcom,mhi@1 { | ||||
| 		reg = <0 0 0 0 0 >; | ||||
|  | ||||
| 	}; | ||||
| }; | ||||
|  | ||||
| &qfprom { | ||||
| 	status = "ok"; | ||||
| }; | ||||
|  | ||||
| &tsens { | ||||
| 	status = "ok"; | ||||
| }; | ||||
|  | ||||
| &qcom_q6v5_wcss { | ||||
| 	qcom,multipd_arch; | ||||
| 	memory-region = <&q6_mem_regions>; | ||||
| 	qcom,share_bootargs; | ||||
| 	qcom,bootargs_smem = <507>; | ||||
| boot-args = <0x1 0x4 0x3 0x0F 0x0 0x0>, | ||||
| 			<0x2 0x4 0x2 0x12 0x0 0x0>;	 | ||||
| 			 | ||||
| 	/* IPQ5018 */ | ||||
| 	q6v5_wcss_userpd1 { | ||||
| 		m3_firmware = "IPQ5018/m3_fw.mdt"; | ||||
| 		interrupts-extended = <&wcss_smp2p_in 8 0>, | ||||
| 			<&wcss_smp2p_in 9 0>, | ||||
| 			<&wcss_smp2p_in 12 0>, | ||||
| 			<&wcss_smp2p_in 11 0>; | ||||
| 		interrupt-names ="fatal", | ||||
| 			"ready", | ||||
| 			"spawn_ack", | ||||
| 			"stop-ack"; | ||||
| 		qcom,smem-states = <&wcss_smp2p_out 8>, | ||||
| 			<&wcss_smp2p_out 9>, | ||||
| 			<&wcss_smp2p_out 10>; | ||||
| 		qcom,smem-state-names = "shutdown", | ||||
| 			"stop", | ||||
| 			"spawn"; | ||||
| 		qca,asid = <1>; | ||||
| 		qca,auto-restart; | ||||
| 		qca,int_radio; | ||||
| 		#ifdef __IPQ_MEM_PROFILE_256_MB__ | ||||
| 		memory-region = <&q6_ipq5018_data>, <&m3_dump>, | ||||
| 				<&q6_etr_region>; | ||||
| 		#else | ||||
| 		memory-region = <&q6_ipq5018_data>, <&m3_dump>, | ||||
| 				<&q6_etr_region>, <&q6_caldb_region>; | ||||
| 		#endif | ||||
| 	}; | ||||
|  | ||||
| 	/* QCN6122 6G */ | ||||
| 	q6v5_wcss_userpd2 { | ||||
| 		m3_firmware = "qcn6122/m3_fw.mdt"; | ||||
| 		interrupts-extended = <&wcss_smp2p_in 16 0>, | ||||
| 			<&wcss_smp2p_in 17 0>, | ||||
| 			<&wcss_smp2p_in 20 0>, | ||||
| 			<&wcss_smp2p_in 19 0>; | ||||
| 		interrupt-names ="fatal", | ||||
| 			"ready", | ||||
| 			"spawn_ack", | ||||
| 			"stop-ack"; | ||||
| 		qcom,smem-states = <&wcss_smp2p_out 16>, | ||||
| 			<&wcss_smp2p_out 17>, | ||||
| 			<&wcss_smp2p_out 18>; | ||||
| 		qcom,smem-state-names = "shutdown", | ||||
| 			"stop", | ||||
| 			"spawn"; | ||||
| 		qca,asid = <2>; | ||||
| 		qca,auto-restart; | ||||
| 		#ifdef __IPQ_MEM_PROFILE_256_MB__ | ||||
| 		memory-region = <&q6_qcn6122_data1>, <&m3_dump_qcn6122_1>, | ||||
| 				<&q6_qcn6122_etr_1>; | ||||
| 		#else | ||||
| 		memory-region = <&q6_qcn6122_data1>, <&m3_dump_qcn6122_1>, | ||||
| 				<&q6_qcn6122_etr_1>, <&q6_qcn6122_caldb_1>; | ||||
| 		#endif | ||||
| 	}; | ||||
|  | ||||
| 	/* QCN6122 5G */ | ||||
| 	q6v5_wcss_userpd3 { | ||||
| 		m3_firmware = "qcn6122/m3_fw.mdt"; | ||||
| 		interrupts-extended = <&wcss_smp2p_in 24 0>, | ||||
| 			<&wcss_smp2p_in 25 0>, | ||||
| 			<&wcss_smp2p_in 28 0>, | ||||
| 			<&wcss_smp2p_in 27 0>; | ||||
| 		interrupt-names ="fatal", | ||||
| 			"ready", | ||||
| 			"spawn_ack", | ||||
| 			"stop-ack"; | ||||
| 		qcom,smem-states = <&wcss_smp2p_out 24>, | ||||
| 			<&wcss_smp2p_out 25>, | ||||
| 			<&wcss_smp2p_out 26>; | ||||
| 		qcom,smem-state-names = "shutdown", | ||||
| 			"stop", | ||||
| 			"spawn"; | ||||
| 		qca,asid = <3>; | ||||
| 		qca,auto-restart; | ||||
| 		#ifdef __IPQ_MEM_PROFILE_256_MB__ | ||||
| 		memory-region = <&q6_qcn6122_data2>, <&m3_dump_qcn6122_2>, | ||||
| 				<&q6_qcn6122_etr_2>; | ||||
| 		#else | ||||
| 		memory-region = <&q6_qcn6122_data2>, <&m3_dump_qcn6122_2>, | ||||
| 				<&q6_qcn6122_etr_2>, <&q6_qcn6122_caldb_2>; | ||||
| 		#endif | ||||
| 	}; | ||||
| }; | ||||
|  | ||||
| &i2c_0 { | ||||
| 	pinctrl-0 = <&i2c_pins>; | ||||
| 	pinctrl-names = "default"; | ||||
| 	status = "disabled"; | ||||
| }; | ||||
|  | ||||
| &qgic_msi_0 { | ||||
| 	status = "ok"; | ||||
| }; | ||||
|  | ||||
| &qgic_msi_1 { | ||||
| 	status = "ok"; | ||||
| }; | ||||
|  | ||||
| &wifi0 { | ||||
| 	/* IPQ5018 */ | ||||
| 	qcom,multipd_arch; | ||||
| 	qcom,userpd-subsys-name = "q6v5_wcss_userpd1"; | ||||
| #ifdef __IPQ_MEM_PROFILE_256_MB__ | ||||
| 	qcom,tgt-mem-mode = <2>; | ||||
| #else | ||||
| 	qcom,tgt-mem-mode = <1>; | ||||
| #endif | ||||
| 	qcom,board_id = <0x24>; | ||||
| 	qcom,bdf-addr = <0x4C400000 0x4C400000 0x4C400000 0x0 0x0>; | ||||
| #ifdef __CNSS2__ | ||||
| 	qcom,caldb-addr = <0x4D400000 0x4D400000 0 0 0>; | ||||
| #else | ||||
| 	qcom,caldb-addr = <0x4D400000>; | ||||
| 	m3-dump-addr = <0x4D200000>; | ||||
| 	nss-radio-priority = <0>; | ||||
| #endif | ||||
| 	mem-region = <&q6_ipq5018_data>; | ||||
| 	qcom,caldb-size = <0x200000>; | ||||
| 	status = "ok"; | ||||
| }; | ||||
|  | ||||
| &wifi1 { | ||||
| 	/* QCN6122 5G */ | ||||
| 	qcom,multipd_arch; | ||||
| 	qcom,userpd-subsys-name = "q6v5_wcss_userpd2"; | ||||
| #ifdef __IPQ_MEM_PROFILE_256_MB__ | ||||
| 	qcom,tgt-mem-mode = <2>; | ||||
| #else | ||||
| 	qcom,tgt-mem-mode = <1>; | ||||
| #endif | ||||
| 	qcom,board_id = <0x60>; | ||||
| 	qcom,bdf-addr = <0x4D600000 0x4D600000 0x4D300000 0x0 0x0>; | ||||
| #ifdef __CNSS2__ | ||||
| 	qcom,caldb-addr = <0x4E800000 0x4E800000 0 0 0>; | ||||
| #else | ||||
| 	qcom,caldb-addr = <0x4E800000>; | ||||
| 	m3-dump-addr = <0x4E600000>; | ||||
| 	nss-radio-priority = <1>; | ||||
| #endif | ||||
| 	mem-region = <&q6_qcn6122_data1>; | ||||
| 	qcom,caldb-size = <0x500000>; | ||||
| 	status = "ok"; | ||||
| }; | ||||
|  | ||||
| &wifi2 { | ||||
| 	/* QCN6122 6G */ | ||||
| 	qcom,multipd_arch; | ||||
| 	qcom,userpd-subsys-name = "q6v5_wcss_userpd3"; | ||||
| #ifdef __IPQ_MEM_PROFILE_256_MB__ | ||||
| 	qcom,tgt-mem-mode = <2>; | ||||
| #else | ||||
| 	qcom,tgt-mem-mode = <1>; | ||||
| #endif | ||||
| 	qcom,board_id = <0xb0>; | ||||
| 	qcom,bdf-addr = <0x4ED00000 0x4ED00000 0x4E400000 0x0 0x0>; | ||||
| #ifdef __CNSS2__ | ||||
| 	qcom,caldb-addr = <0x4FF00000 0x4FF00000 0 0 0>; | ||||
| #else | ||||
| 	qcom,caldb-addr = <0x4FF00000>; | ||||
| 	m3-dump-addr = <0x4FD00000>; | ||||
| 	nss-radio-priority = <1>; | ||||
| #endif | ||||
| 	mem-region = <&q6_qcn6122_data2>; | ||||
| 	qcom,caldb-size = <0x500000>; | ||||
| 	status = "ok"; | ||||
| }; | ||||
| @@ -0,0 +1,78 @@ | ||||
| /dts-v1/; | ||||
| /* | ||||
|  * Copyright (c) 2019, The Linux Foundation. All rights reserved. | ||||
|  * | ||||
|  * Permission to use, copy, modify, and/or distribute this software for any | ||||
|  * purpose with or without fee is hereby granted, provided that the above | ||||
|  * copyright notice and this permission notice appear in all copies. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||||
|  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||||
|  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||||
|  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||||
|  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||||
|  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||||
|  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| #include "qcom-ipq6018-gl-ax1800.dtsi" | ||||
|  | ||||
| / { | ||||
| 	model = "GL Technologies, Inc. AX1800"; | ||||
| 	compatible = "glinet,ax1800", "qcom,ipq6018-cp03", "qcom,ipq6018"; | ||||
|  | ||||
| 	aliases { | ||||
| 		ethernet3 = "/soc/dp4"; | ||||
| 		ethernet4 = "/soc/dp5"; | ||||
| 	}; | ||||
| }; | ||||
|  | ||||
| &mdio0 { | ||||
| 	phy3: ethernet-phy@3 { | ||||
| 		reg = <3>; | ||||
| 	}; | ||||
| 	phy4: ethernet-phy@4 { | ||||
| 		reg = <4>; | ||||
| 	}; | ||||
| }; | ||||
|  | ||||
| &ess0 { | ||||
| 	switch_lan_bmp = <0x3c>; /* lan port bitmap */ | ||||
|  | ||||
| 	qcom,port_phyinfo { | ||||
| 		port@3 { | ||||
| 			port_id = <4>; | ||||
| 			phy_address = <3>; | ||||
| 		}; | ||||
| 		port@4 { | ||||
| 			port_id = <5>; | ||||
| 			phy_address = <4>; | ||||
| 		}; | ||||
| 	}; | ||||
| }; | ||||
|  | ||||
| &soc { | ||||
| 	dp4 { | ||||
| 		device_type = "network"; | ||||
| 		compatible = "qcom,nss-dp"; | ||||
| 		qcom,id = <4>; | ||||
| 		reg = <0x3a001600 0x200>; | ||||
| 		qcom,mactype = <0>; | ||||
| 		local-mac-address = [000000000000]; | ||||
| 		qcom,link-poll = <1>; | ||||
| 		qcom,phy-mdio-addr = <3>; | ||||
| 		phy-mode = "sgmii"; | ||||
| 	}; | ||||
|  | ||||
| 	dp5 { | ||||
| 		device_type = "network"; | ||||
| 		compatible = "qcom,nss-dp"; | ||||
| 		qcom,id = <5>; | ||||
| 		reg = <0x3a001800 0x200>; | ||||
| 		qcom,mactype = <0>; | ||||
| 		local-mac-address = [000000000000]; | ||||
| 		qcom,link-poll = <1>; | ||||
| 		qcom,phy-mdio-addr = <4>; | ||||
| 		phy-mode = "sgmii"; | ||||
| 	}; | ||||
| }; | ||||
| @@ -0,0 +1,364 @@ | ||||
| /* | ||||
|  * Copyright (c) 2019, The Linux Foundation. All rights reserved. | ||||
|  * | ||||
|  * Permission to use, copy, modify, and/or distribute this software for any | ||||
|  * purpose with or without fee is hereby granted, provided that the above | ||||
|  * copyright notice and this permission notice appear in all copies. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||||
|  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||||
|  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||||
|  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||||
|  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||||
|  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||||
|  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| #include "qcom-ipq6018.dtsi" | ||||
| #include <dt-bindings/input/input.h> | ||||
|  | ||||
| / { | ||||
| 	#address-cells = <0x2>; | ||||
| 	#size-cells = <0x2>; | ||||
| 	interrupt-parent = <&intc>; | ||||
| 	qcom,msm-id = <0x1A5 0x0>; | ||||
|  | ||||
| 	aliases { | ||||
| 		ethernet0 = "/soc/dp1"; | ||||
| 		ethernet1 = "/soc/dp2"; | ||||
| 		ethernet2 = "/soc/dp3"; | ||||
|  | ||||
| 		led-boot = &led_run; | ||||
| 		led-failsafe = &led_run; | ||||
| 		led-running = &led_run; | ||||
| 		led-upgrade = &led_run; | ||||
| 	}; | ||||
|  | ||||
| 	chosen { | ||||
| 		bootargs = "console=ttyMSM0,115200,n8 rw init=/init"; | ||||
| 		bootargs-append = " swiotlb=1 coherent_pool=2M"; | ||||
| 	}; | ||||
| }; | ||||
|  | ||||
| &tlmm { | ||||
| 	uart_pins: uart_pins { | ||||
| 		mux { | ||||
| 			pins = "gpio44", "gpio45"; | ||||
| 			function = "blsp2_uart"; | ||||
| 			drive-strength = <8>; | ||||
| 			bias-pull-down; | ||||
| 		}; | ||||
| 	}; | ||||
|  | ||||
| 	qpic_pins: qpic_pins { | ||||
| 		data_0 { | ||||
| 			pins = "gpio15"; | ||||
| 			function = "qpic_pad0"; | ||||
| 			drive-strength = <8>; | ||||
| 			bias-pull-down; | ||||
| 		}; | ||||
| 		data_1 { | ||||
| 			pins = "gpio12"; | ||||
| 			function = "qpic_pad1"; | ||||
| 			drive-strength = <8>; | ||||
| 			bias-pull-down; | ||||
| 		}; | ||||
| 		data_2 { | ||||
| 			pins = "gpio13"; | ||||
| 			function = "qpic_pad2"; | ||||
| 			drive-strength = <8>; | ||||
| 			bias-pull-down; | ||||
| 		}; | ||||
| 		data_3 { | ||||
| 			pins = "gpio14"; | ||||
| 			function = "qpic_pad3"; | ||||
| 			drive-strength = <8>; | ||||
| 			bias-pull-down; | ||||
| 		}; | ||||
| 		data_4 { | ||||
| 			pins = "gpio5"; | ||||
| 			function = "qpic_pad4"; | ||||
| 			drive-strength = <8>; | ||||
| 			bias-pull-down; | ||||
| 		}; | ||||
| 		data_5 { | ||||
| 			pins = "gpio6"; | ||||
| 			function = "qpic_pad5"; | ||||
| 			drive-strength = <8>; | ||||
| 			bias-pull-down; | ||||
| 		}; | ||||
| 		data_6 { | ||||
| 			pins = "gpio7"; | ||||
| 			function = "qpic_pad6"; | ||||
| 			drive-strength = <8>; | ||||
| 			bias-pull-down; | ||||
| 		}; | ||||
| 		data_7 { | ||||
| 			pins = "gpio8"; | ||||
| 			function = "qpic_pad7"; | ||||
| 			drive-strength = <8>; | ||||
| 			bias-pull-down; | ||||
| 		}; | ||||
| 		qpic_pad { | ||||
| 			pins = "gpio1", "gpio3", "gpio4", | ||||
| 			       "gpio10", "gpio11", "gpio17"; | ||||
| 			function = "qpic_pad"; | ||||
| 			drive-strength = <8>; | ||||
| 			bias-pull-down; | ||||
| 		}; | ||||
| 	}; | ||||
|  | ||||
| 	button_pins: button_pins { | ||||
| 		switch_button { | ||||
| 			pins = "gpio9"; | ||||
| 			function = "gpio"; | ||||
| 			drive-strength = <8>; | ||||
| 			bias-pull-up; | ||||
| 		}; | ||||
| 		reset_button { | ||||
| 			pins = "gpio18"; | ||||
| 			function = "gpio"; | ||||
| 			drive-strength = <8>; | ||||
| 			bias-pull-up; | ||||
| 		}; | ||||
| 	}; | ||||
|  | ||||
| 	mdio_pins: mdio_pinmux { | ||||
| 		mux_0 { | ||||
| 			pins = "gpio64"; | ||||
| 			function = "mdc"; | ||||
| 			drive-strength = <8>; | ||||
| 			bias-pull-up; | ||||
| 		}; | ||||
| 		mux_1 { | ||||
| 			pins = "gpio65"; | ||||
| 			function = "mdio"; | ||||
| 			drive-strength = <8>; | ||||
| 			bias-pull-up; | ||||
| 		}; | ||||
| 		mux_2 { | ||||
| 			pins = "gpio74"; | ||||
| 			function = "gpio"; | ||||
| 			bias-pull-up; | ||||
| 		}; | ||||
| 	}; | ||||
|  | ||||
| 	leds_pins: leds_pins { | ||||
| 		white { | ||||
| 			pins = "gpio35"; | ||||
| 			function = "gpio"; | ||||
| 			drive-strength = <8>; | ||||
| 			bias-pull-down; | ||||
| 		}; | ||||
| 		blue { | ||||
| 			pins = "gpio37"; | ||||
| 			function = "gpio"; | ||||
| 			drive-strength = <8>; | ||||
| 			bias-pull-down; | ||||
| 		}; | ||||
| 	}; | ||||
|  | ||||
| 	usb_pins: usb_pins { | ||||
| 		usb_pwr { | ||||
| 			pins = "gpio0"; | ||||
| 			function = "gpio"; | ||||
| 			bias-pull-up; | ||||
| 			output-high; | ||||
| 		}; | ||||
| 	}; | ||||
| }; | ||||
|  | ||||
| &soc { | ||||
| 	mdio0: mdio@90000 { | ||||
| 		pinctrl-0 = <&mdio_pins>; | ||||
| 		pinctrl-names = "default"; | ||||
| 		phy-reset-gpio = <&tlmm 74 GPIO_ACTIVE_HIGH>; | ||||
| 		status = "ok"; | ||||
| 		phy0: ethernet-phy@0 { | ||||
| 			reg = <0>; | ||||
| 		}; | ||||
| 		phy1: ethernet-phy@1 { | ||||
| 			reg = <1>; | ||||
| 		}; | ||||
| 		phy2: ethernet-phy@2 { | ||||
| 			reg = <2>; | ||||
| 		}; | ||||
| 	}; | ||||
|  | ||||
| 	ess0: ess-switch@3a000000 { | ||||
| 		switch_cpu_bmp = <0x1>;  /* cpu port bitmap */ | ||||
| 		switch_lan_bmp = <0x0c>; /* lan port bitmap */ | ||||
| 		switch_wan_bmp = <0x02>; /* wan port bitmap */ | ||||
| 		switch_inner_bmp = <0xc0>; /*inner port bitmap*/ | ||||
| 		switch_mac_mode = <0x0>; /* mac mode for uniphy instance0*/ | ||||
| 		switch_mac_mode1 = <0xff>; /* mac mode for uniphy instance1*/ | ||||
| 		switch_mac_mode2 = <0xff>; /* mac mode for uniphy instance2*/ | ||||
| 		qcom,port_phyinfo { | ||||
| 			port@0 { | ||||
| 				port_id = <1>; | ||||
| 				phy_address = <0>; | ||||
| 			}; | ||||
| 			port@1 { | ||||
| 				port_id = <2>; | ||||
| 				phy_address = <1>; | ||||
| 			}; | ||||
| 			port@2 { | ||||
| 				port_id = <3>; | ||||
| 				phy_address = <2>; | ||||
| 			}; | ||||
| 		}; | ||||
| 	}; | ||||
|  | ||||
| 	dp1 { | ||||
| 		device_type = "network"; | ||||
| 		compatible = "qcom,nss-dp"; | ||||
| 		qcom,id = <1>; | ||||
| 		reg = <0x3a001000 0x200>; | ||||
| 		qcom,mactype = <0>; | ||||
| 		local-mac-address = [000000000000]; | ||||
| 		qcom,link-poll = <1>; | ||||
| 		qcom,phy-mdio-addr = <0>; | ||||
| 		phy-mode = "sgmii"; | ||||
| 	}; | ||||
|  | ||||
| 	dp2 { | ||||
| 		device_type = "network"; | ||||
| 		compatible = "qcom,nss-dp"; | ||||
| 		qcom,id = <2>; | ||||
| 		reg = <0x3a001200 0x200>; | ||||
| 		qcom,mactype = <0>; | ||||
| 		local-mac-address = [000000000000]; | ||||
| 		qcom,link-poll = <1>; | ||||
| 		qcom,phy-mdio-addr = <1>; | ||||
| 		phy-mode = "sgmii"; | ||||
| 	}; | ||||
|  | ||||
| 	dp3 { | ||||
| 		device_type = "network"; | ||||
| 		compatible = "qcom,nss-dp"; | ||||
| 		qcom,id = <3>; | ||||
| 		reg = <0x3a001400 0x200>; | ||||
| 		qcom,mactype = <0>; | ||||
| 		local-mac-address = [000000000000]; | ||||
| 		qcom,link-poll = <1>; | ||||
| 		qcom,phy-mdio-addr = <2>; | ||||
| 		phy-mode = "sgmii"; | ||||
| 	}; | ||||
|  | ||||
| 	leds { | ||||
| 		compatible = "gpio-leds"; | ||||
| 		pinctrl-0 = <&leds_pins>; | ||||
| 		pinctrl-names = "default"; | ||||
|  | ||||
| 		led_run: led@35 { | ||||
| 			label = "white:sys"; | ||||
| 			gpios = <&tlmm 35 GPIO_ACTIVE_HIGH>; | ||||
| 			default-state = "on"; | ||||
| 		}; | ||||
|  | ||||
| 		led@37 { | ||||
| 			label = "blue:wan"; | ||||
| 			gpios = <&tlmm 37 GPIO_ACTIVE_HIGH>; | ||||
| 			default-state = "on"; | ||||
| 		}; | ||||
| 	}; | ||||
|  | ||||
| 	gpio_keys { | ||||
| 		compatible = "gpio-keys"; | ||||
| 		pinctrl-0 = <&button_pins>; | ||||
| 		pinctrl-names = "default"; | ||||
|  | ||||
| 		switch { | ||||
| 			label = "switch"; | ||||
| 			linux,code = <KEY_WPS_BUTTON>; | ||||
| 			gpios = <&tlmm 9 GPIO_ACTIVE_LOW>; | ||||
| 			linux,input-type = <1>; | ||||
| 			debounce-interval = <60>; | ||||
| 		}; | ||||
| 		reset { | ||||
| 			label = "reset"; | ||||
| 			linux,code = <KEY_RESTART>; | ||||
| 			gpios = <&tlmm 18 GPIO_ACTIVE_LOW>; | ||||
| 			linux,input-type = <1>; | ||||
| 			debounce-interval = <60>; | ||||
| 		}; | ||||
| 	}; | ||||
| }; | ||||
|  | ||||
| &blsp1_uart3 { | ||||
| 	pinctrl-0 = <&uart_pins>; | ||||
| 	pinctrl-names = "default"; | ||||
| 	status = "ok"; | ||||
| }; | ||||
|  | ||||
| &qpic_bam { | ||||
| 	status = "ok"; | ||||
| }; | ||||
|  | ||||
| &nand { | ||||
| 	pinctrl-0 = <&qpic_pins>; | ||||
| 	pinctrl-names = "default"; | ||||
| 	status = "ok"; | ||||
| }; | ||||
|  | ||||
| &ssphy_0 { | ||||
| 	status = "ok"; | ||||
| }; | ||||
|  | ||||
| &qusb_phy_0 { | ||||
| 	status = "ok"; | ||||
| }; | ||||
|  | ||||
| &usb3 { | ||||
| 	pinctrl-0 = <&usb_pins>; | ||||
| 	pinctrl-names = "default"; | ||||
| 	status = "ok"; | ||||
| }; | ||||
|  | ||||
| &nss_crypto { | ||||
| 	status = "ok"; | ||||
| }; | ||||
|  | ||||
| &q6_region { | ||||
| 	reg = <0x0 0x4ab00000 0x0 0x05500000>; | ||||
| }; | ||||
|  | ||||
| &CPU0 { | ||||
| 	operating-points = < | ||||
| 		/* kHz   uV (fixed) */ | ||||
| 		864000   1100000 | ||||
| 		1056000  1100000 | ||||
| 		1200000  1100000 | ||||
| 	>; | ||||
| 	clock-latency = <200000>; | ||||
| }; | ||||
|  | ||||
| &CPU1 { | ||||
| 	operating-points = < | ||||
| 		/* kHz   uV (fixed) */ | ||||
| 		864000   1100000 | ||||
| 		1056000  1100000 | ||||
| 		1200000  1100000 | ||||
| 	>; | ||||
| 	clock-latency = <200000>; | ||||
| }; | ||||
|  | ||||
| &CPU2 { | ||||
| 	operating-points = < | ||||
| 		/* kHz   uV (fixed) */ | ||||
| 		864000   1100000 | ||||
| 		1056000  1100000 | ||||
| 		1200000  1100000 | ||||
| 	>; | ||||
| 	clock-latency = <200000>; | ||||
| }; | ||||
|  | ||||
| &CPU3 { | ||||
| 	operating-points = < | ||||
| 		/* kHz   uV (fixed) */ | ||||
| 		864000   1100000 | ||||
| 		1056000  1100000 | ||||
| 		1200000  1100000 | ||||
| 	>; | ||||
| 	clock-latency = <200000>; | ||||
| }; | ||||
| @@ -0,0 +1,94 @@ | ||||
| /dts-v1/; | ||||
| /* | ||||
|  * Copyright (c) 2019, The Linux Foundation. All rights reserved. | ||||
|  * | ||||
|  * Permission to use, copy, modify, and/or distribute this software for any | ||||
|  * purpose with or without fee is hereby granted, provided that the above | ||||
|  * copyright notice and this permission notice appear in all copies. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||||
|  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||||
|  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||||
|  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||||
|  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||||
|  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||||
|  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| #include "qcom-ipq6018-gl-ax1800.dtsi" | ||||
|  | ||||
| / { | ||||
| 	model = "GL Technologies, Inc. AXT1800"; | ||||
| 	compatible = "glinet,axt1800", "qcom,ipq6018-cp03", "qcom,ipq6018"; | ||||
|  | ||||
| 	aliases { | ||||
| 		sdhc0 = &sdhc_2; | ||||
| 	}; | ||||
| }; | ||||
|  | ||||
| &tlmm { | ||||
| 	sd_pins: sd_pins { | ||||
| 		sd { | ||||
| 			pins = "gpio62"; | ||||
| 			function = "sd_card"; | ||||
| 			bias-pull-up; | ||||
| 		}; | ||||
| 		ldo { | ||||
| 			pins = "gpio66"; | ||||
| 			function = "gpio"; | ||||
| 			bias-pull-up; | ||||
| 		}; | ||||
| 	}; | ||||
|  | ||||
| 	pwm_pins: pwm_pinmux { | ||||
| 		pwm { | ||||
| 			pins = "gpio30"; | ||||
| 			function = "pwm13"; | ||||
| 			drive-strength = <8>; | ||||
| 		}; | ||||
| 	}; | ||||
|  | ||||
| 	fan_pins: fan_pins { | ||||
| 		pwr { | ||||
| 			pins = "gpio29"; | ||||
| 			function = "gpio"; | ||||
| 			bias-pull-up; | ||||
| 			output-high; | ||||
| 		}; | ||||
| 		speed { | ||||
| 			pins = "gpio31"; | ||||
| 			function = "gpio"; | ||||
| 			drive-strength = <8>; | ||||
| 			bias-pull-down; | ||||
| 		}; | ||||
| 	}; | ||||
| }; | ||||
|  | ||||
| &soc { | ||||
| 	pwm:pwm { | ||||
| 		#pwm-cells = <2>; | ||||
| 		pinctrl-0 = <&pwm_pins>; | ||||
| 		pinctrl-names = "default"; | ||||
| 		used-pwm-indices = <0>, <1>, <0>, <0>; | ||||
| 		status = "ok"; | ||||
| 	}; | ||||
|  | ||||
| 	pwm-fan { | ||||
| 		compatible = "pwm-fan"; | ||||
| 		pinctrl-0 = <&fan_pins>; | ||||
| 		pinctrl-names = "default"; | ||||
| 		cooling-min-state = <0>; | ||||
| 		cooling-max-state = <3>; | ||||
| 		#cooling-cells = <2>; | ||||
| 		pwms = <&pwm 1 255>; | ||||
| 		cooling-levels = <0 150 200 255>; | ||||
| 	}; | ||||
| }; | ||||
|  | ||||
| &sdhc_2 { | ||||
| 	pinctrl-0 = <&sd_pins>; | ||||
| 	pinctrl-names = "default"; | ||||
| 	cd-gpios = <&tlmm 62 1>; | ||||
| 	sd-ldo-gpios = <&tlmm 66 1>; | ||||
| 	status = "ok"; | ||||
| }; | ||||
| @@ -0,0 +1,343 @@ | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later OR MIT | ||||
| /dts-v1/; | ||||
|  | ||||
| #include "qcom-ipq6018.dtsi" | ||||
| #include "qcom-ipq6018-rpm-regulator.dtsi" | ||||
| #include "qcom-ipq6018-cpr-regulator.dtsi" | ||||
| #include "qcom-ipq6018-cp-cpu.dtsi" | ||||
| #include <dt-bindings/input/input.h> | ||||
| #include <dt-bindings/gpio/gpio.h> | ||||
|  | ||||
| / { | ||||
| 	model = "YunCore AX840"; | ||||
| 	compatible = "yuncore,ax840", "qcom,ipq6018-cp03", "qcom,ipq6018"; | ||||
|  | ||||
| 	#address-cells = <0x2>; | ||||
| 	#size-cells = <0x2>; | ||||
| 	interrupt-parent = <&intc>; | ||||
|  | ||||
| 	aliases { | ||||
| 		/* Aliases as required by u-boot to patch MAC addresses */ | ||||
| 		ethernet0 = "/soc/dp2"; | ||||
| 		ethernet1 = "/soc/dp1"; | ||||
|  | ||||
| 		serial0 = &blsp1_uart3; | ||||
| 		serial1 = &blsp1_uart2; | ||||
|  | ||||
| 		led-boot = &led_system; | ||||
| 		led-failsafe = &led_system; | ||||
| 		led-running = &led_system; | ||||
| 		led-upgrade = &led_system; | ||||
| 	}; | ||||
|  | ||||
| 	chosen { | ||||
| 		bootargs = "console=ttyMSM0,115200,n8 rw init=/init"; | ||||
| 		bootargs-append = " swiotlb=1 coherent_pool=2M"; | ||||
| 	}; | ||||
|  | ||||
| 	reserved-memory { | ||||
| 		tzapp:tzapp@49B00000 {	/* TZAPPS */ | ||||
| 			no-map; | ||||
| 			reg = <0x0 0x49B00000 0x0 0x00600000>; | ||||
| 		}; | ||||
| 	}; | ||||
| }; | ||||
|  | ||||
| &tlmm { | ||||
| 	uart_pins: uart_pins { | ||||
| 		mux { | ||||
| 			pins = "gpio44", "gpio45"; | ||||
| 			function = "blsp2_uart"; | ||||
| 			drive-strength = <8>; | ||||
| 			bias-pull-down; | ||||
| 		}; | ||||
| 	}; | ||||
|  | ||||
| 	spi_0_pins: spi_0_pins { | ||||
| 		mux { | ||||
| 			pins = "gpio38", "gpio39", "gpio40", "gpio41"; | ||||
| 			function = "blsp0_spi"; | ||||
| 			drive-strength = <8>; | ||||
| 			bias-pull-down; | ||||
| 		}; | ||||
| 	}; | ||||
|  | ||||
| 	qpic_pins: qpic_pins { | ||||
| 		data_0 { | ||||
| 			pins = "gpio15"; | ||||
| 			function = "qpic_pad0"; | ||||
| 			drive-strength = <8>; | ||||
| 			bias-pull-down; | ||||
| 		}; | ||||
|  | ||||
| 		data_1 { | ||||
| 			pins = "gpio12"; | ||||
| 			function = "qpic_pad1"; | ||||
| 			drive-strength = <8>; | ||||
| 			bias-pull-down; | ||||
| 		}; | ||||
|  | ||||
| 		data_2 { | ||||
| 			pins = "gpio13"; | ||||
| 			function = "qpic_pad2"; | ||||
| 			drive-strength = <8>; | ||||
| 			bias-pull-down; | ||||
| 		}; | ||||
|  | ||||
| 		data_3 { | ||||
| 			pins = "gpio14"; | ||||
| 			function = "qpic_pad3"; | ||||
| 			drive-strength = <8>; | ||||
| 			bias-pull-down; | ||||
| 		}; | ||||
|  | ||||
| 		data_4 { | ||||
| 			pins = "gpio5"; | ||||
| 			function = "qpic_pad4"; | ||||
| 			drive-strength = <8>; | ||||
| 			bias-pull-down; | ||||
| 		}; | ||||
|  | ||||
| 		data_5 { | ||||
| 			pins = "gpio6"; | ||||
| 			function = "qpic_pad5"; | ||||
| 			drive-strength = <8>; | ||||
| 			bias-pull-down; | ||||
| 		}; | ||||
|  | ||||
| 		data_6 { | ||||
| 			pins = "gpio7"; | ||||
| 			function = "qpic_pad6"; | ||||
| 			drive-strength = <8>; | ||||
| 			bias-pull-down; | ||||
| 		}; | ||||
|  | ||||
| 		data_7 { | ||||
| 			pins = "gpio8"; | ||||
| 			function = "qpic_pad7"; | ||||
| 			drive-strength = <8>; | ||||
| 			bias-pull-down; | ||||
| 		}; | ||||
|  | ||||
| 		qpic_pad { | ||||
| 			pins = "gpio1",  "gpio3",  "gpio4", | ||||
| 			       "gpio10", "gpio11", "gpio17"; | ||||
| 			function = "qpic_pad"; | ||||
| 			drive-strength = <8>; | ||||
| 			bias-pull-down; | ||||
| 		}; | ||||
| 	}; | ||||
|  | ||||
| 	button_pins: button_pins { | ||||
| 		rst_button { | ||||
| 			pins = "gpio19"; | ||||
| 			function = "gpio"; | ||||
| 			drive-strength = <8>; | ||||
| 			bias-pull-up; | ||||
| 		}; | ||||
| 	}; | ||||
|  | ||||
| 	mdio_pins: mdio_pinmux { | ||||
| 		mux_0 { | ||||
| 			pins = "gpio64"; | ||||
| 			function = "mdc"; | ||||
| 			drive-strength = <8>; | ||||
| 			bias-pull-up; | ||||
| 		}; | ||||
|  | ||||
| 		mux_1 { | ||||
| 			pins = "gpio65"; | ||||
| 			function = "mdio"; | ||||
| 			drive-strength = <8>; | ||||
| 			bias-pull-up; | ||||
| 		}; | ||||
|  | ||||
| 		mux_2 { | ||||
| 			pins = "gpio75"; | ||||
| 			function = "gpio"; | ||||
| 			bias-pull-up; | ||||
| 		}; | ||||
| 	}; | ||||
|  | ||||
| 	leds_pins: leds_pins { | ||||
| 		led_blue { | ||||
| 			pins = "gpio35"; | ||||
| 			function = "gpio"; | ||||
| 			drive-strength = <2>; | ||||
| 			bias-pull-down; | ||||
| 		}; | ||||
|  | ||||
| 		led_green { | ||||
| 			pins = "gpio37"; | ||||
| 			function = "gpio"; | ||||
| 			drive-strength = <2>; | ||||
| 			bias-pull-down; | ||||
| 		}; | ||||
|  | ||||
| 		led_red { | ||||
| 			pins = "gpio32"; | ||||
| 			function = "gpio"; | ||||
| 			drive-strength = <2>; | ||||
| 			bias-pull-down; | ||||
| 		}; | ||||
| 	}; | ||||
| }; | ||||
|  | ||||
| &soc { | ||||
| 	mdio: mdio@90000 { | ||||
| 		status = "ok"; | ||||
|  | ||||
| 		pinctrl-0 = <&mdio_pins>; | ||||
| 		pinctrl-names = "default"; | ||||
| 		phy-reset-gpio = <&tlmm 75 0>; | ||||
|  | ||||
| 		ethernet-phy@0 { | ||||
| 			reg = <0x03>; | ||||
| 		}; | ||||
|  | ||||
| 		ethernet-phy@1 { | ||||
| 			reg = <0x04>; | ||||
| 		}; | ||||
| 	}; | ||||
|  | ||||
| 	ess-switch@3a000000 { | ||||
| 		switch_cpu_bmp =   <0x01>; /* cpu port bitmap */ | ||||
| 		switch_lan_bmp =   <0x10>; /* lan port bitmap */ | ||||
| 		switch_wan_bmp =   <0x20>; /* wan port bitmap */ | ||||
| 		switch_inner_bmp = <0x80>; /*inner port bitmap*/ | ||||
| 		switch_mac_mode =  <0x00>; /* mac mode for uniphy instance0*/ | ||||
| 		switch_mac_mode1 = <0xff>; /* mac mode for uniphy instance1*/ | ||||
| 		switch_mac_mode2 = <0xff>; /* mac mode for uniphy instance2*/ | ||||
|  | ||||
| 		qcom,port_phyinfo { | ||||
| 			port@3 { | ||||
| 				port_id = <0x04>; | ||||
| 				phy_address = <0x03>; | ||||
| 			}; | ||||
|  | ||||
| 			port@4 { | ||||
| 				port_id = <0x05>; | ||||
| 				phy_address = <0x04>; | ||||
| 			}; | ||||
| 		}; | ||||
| 	}; | ||||
|  | ||||
| 	dp1 { | ||||
| 		device_type = "network"; | ||||
| 		compatible = "qcom,nss-dp"; | ||||
| 		qcom,id = <0x05>; | ||||
| 		reg = <0x3a001800 0x200>; | ||||
| 		qcom,mactype = <0x00>; | ||||
| 		local-mac-address = [00 00 00 00 00 00]; | ||||
| 		qcom,link-poll = <0x01>; | ||||
| 		qcom,phy-mdio-addr = <0x04>; | ||||
| 		phy-mode = "sgmii"; | ||||
| 	}; | ||||
|  | ||||
| 	dp2 { | ||||
| 		device_type = "network"; | ||||
| 		compatible = "qcom,nss-dp"; | ||||
| 		qcom,id = <0x04>; | ||||
| 		reg = <0x3a001600 0x200>; | ||||
| 		qcom,mactype = <0x00>; | ||||
| 		local-mac-address = [00 00 00 00 00 00]; | ||||
| 		qcom,link-poll = <0x01>; | ||||
| 		qcom,phy-mdio-addr = <0x03>; | ||||
| 		phy-mode = "sgmii"; | ||||
| 	}; | ||||
|  | ||||
| 	gpio_keys { | ||||
| 		compatible = "gpio-keys"; | ||||
|  | ||||
| 		pinctrl-0 = <&button_pins>; | ||||
| 		pinctrl-names = "default"; | ||||
|  | ||||
| 		reset { | ||||
| 			label = "reset"; | ||||
| 			linux,code = <KEY_RESTART>; | ||||
| 			gpios = <&tlmm 19 GPIO_ACTIVE_LOW>; | ||||
| 			linux,input-type = <1>; | ||||
| 			debounce-interval = <60>; | ||||
| 		}; | ||||
| 	}; | ||||
|  | ||||
| 	leds { | ||||
| 		compatible = "gpio-leds"; | ||||
|  | ||||
| 		pinctrl-0 = <&leds_pins>; | ||||
| 		pinctrl-names = "default"; | ||||
|  | ||||
| 		led_system: system { | ||||
| 			label = "ax860:green:system"; | ||||
| 			gpio = <&tlmm 37 GPIO_ACTIVE_HIGH>; | ||||
| 		}; | ||||
|  | ||||
| 		wlan2g { | ||||
| 			label = "ax860:blue:wlan2g"; | ||||
| 			gpio = <&tlmm 35 GPIO_ACTIVE_HIGH>; | ||||
| 		}; | ||||
|  | ||||
| 		wlan5g { | ||||
| 			label = "ax860:red:wlan5g"; | ||||
| 			gpio = <&tlmm 32 GPIO_ACTIVE_HIGH>; | ||||
| 		}; | ||||
| 	}; | ||||
| }; | ||||
|  | ||||
| &blsp1_uart3 { | ||||
| 	pinctrl-0 = <&uart_pins>; | ||||
| 	pinctrl-names = "default"; | ||||
| 	status = "ok"; | ||||
| }; | ||||
|  | ||||
| &spi_0 { | ||||
| 	pinctrl-0 = <&spi_0_pins>; | ||||
| 	pinctrl-names = "default"; | ||||
| 	cs-select = <0>; | ||||
| 	status = "ok"; | ||||
|  | ||||
| 	m25p80@0 { | ||||
| 		#address-cells = <1>; | ||||
| 		#size-cells = <1>; | ||||
| 		reg = <0>; | ||||
| 		compatible = "n25q128a11"; | ||||
| 		linux,modalias = "m25p80", "n25q128a11"; | ||||
| 		spi-max-frequency = <50000000>; | ||||
| 		use-default-sizes; | ||||
| 	}; | ||||
| }; | ||||
|  | ||||
| &qpic_bam { | ||||
| 	status = "ok"; | ||||
| }; | ||||
|  | ||||
| &nand { | ||||
| 	pinctrl-0 = <&qpic_pins>; | ||||
| 	pinctrl-names = "default"; | ||||
| 	status = "ok"; | ||||
| }; | ||||
|  | ||||
| &nss_crypto { | ||||
| 	status = "ok"; | ||||
| }; | ||||
|  | ||||
| &cpu0_opp_table { | ||||
| 	compatible = "operating-points-v2"; | ||||
| 	opp-shared; | ||||
|  | ||||
| 	opp03 { | ||||
| 		opp-hz = /bits/ 64 <1200000000>; | ||||
| 		opp-microvolt = <3>; | ||||
| 		clock-latency-ns = <200000>; | ||||
| 	}; | ||||
|  | ||||
| 	/delete-node/ opp04; | ||||
| 	/delete-node/ opp05; | ||||
| 	/delete-node/ opp06; | ||||
| }; | ||||
|  | ||||
| &qseecom { | ||||
| 	mem-start = <0x49B00000>; | ||||
| 	mem-size = <0x600000>; | ||||
| 	status = "ok"; | ||||
| }; | ||||
| @@ -51,7 +51,7 @@ | ||||
| 		#ifdef __IPQ_MEM_PROFILE_256_MB__ | ||||
| 			bootargs-append = " swiotlb=1"; | ||||
| 		#else | ||||
| 			bootargs-append = " swiotlb=1 coherent_pool=2M"; | ||||
| 			bootargs-append = " swiotlb=1 coherent_pool=2M vmalloc=600M"; | ||||
| 		#endif | ||||
| 	}; | ||||
|  | ||||
|   | ||||
| @@ -18,6 +18,17 @@ define Device/edgecore_eap104 | ||||
| endef | ||||
| TARGET_DEVICES += edgecore_eap104 | ||||
|  | ||||
| define Device/motorola_q14 | ||||
|   DEVICE_TITLE := Motorola Q14 | ||||
|   DEVICE_DTS := qcom-ipq5018-q14 | ||||
|   SUPPORTED_DEVICES := motorola,q14 | ||||
|   DEVICE_PACKAGES := ath11k-wifi-motorola-q14 ath11k-firmware-ipq50xx-spruce ath11k-firmware-qcn6122 | ||||
|   DEVICE_DTS_CONFIG := config@mp03.5-c1 | ||||
|   IMAGES := sysupgrade.tar mmc-factory.bin | ||||
|   IMAGE/mmc-factory.bin := append-ubi | qsdk-ipq-factory-mmc | ||||
| endef | ||||
| TARGET_DEVICES += motorola_q14 | ||||
|  | ||||
| define Device/qcom_mp03_1 | ||||
|   DEVICE_TITLE := Qualcomm Maple 03.1 | ||||
|   DEVICE_DTS := qcom-ipq5018-mp03.1 | ||||
|   | ||||
| @@ -1,16 +1,5 @@ | ||||
| KERNEL_LOADADDR := 0x41008000 | ||||
|  | ||||
| define Device/cig_wf188 | ||||
|   DEVICE_TITLE := Cigtech WF-188 | ||||
|   DEVICE_DTS := qcom-ipq6018-cig-wf188 | ||||
|   DEVICE_DTS_CONFIG := config@cp03-c1 | ||||
|   SUPPORTED_DEVICES := cig,wf188 | ||||
|   IMAGES := sysupgrade.tar | ||||
|   IMAGE/sysupgrade.tar/squashfs := append-rootfs | pad-rootfs | sysupgrade-tar rootfs=$$$$@ | append-metadata | ||||
|   DEVICE_PACKAGES := ath11k-wifi-cig-wf188 uboot-env | ||||
| endef | ||||
| TARGET_DEVICES += cig_wf188 | ||||
|  | ||||
| define Device/cig_wf188n | ||||
|   DEVICE_TITLE := Cigtech WF-188n | ||||
|   DEVICE_DTS := qcom-ipq6018-cig-wf188n | ||||
| @@ -43,7 +32,7 @@ define Device/edgecore_eap101 | ||||
|   DEVICE_DTS := qcom-ipq6018-edgecore-eap101 | ||||
|   DEVICE_DTS_CONFIG := config@cp01-c1 | ||||
|   SUPPORTED_DEVICES := edgecore,eap101 | ||||
|   DEVICE_PACKAGES := ath11k-wifi-edgecore-eap101 uboot-envtools | ||||
|   DEVICE_PACKAGES := ath11k-wifi-edgecore-eap101 uboot-envtools -kmod-usb-dwc3-of-simple kmod-usb-dwc3-qcom kmod-usb3 kmod-usb2 | ||||
| endef | ||||
| TARGET_DEVICES += edgecore_eap101 | ||||
|  | ||||
| @@ -52,7 +41,7 @@ define Device/wallys_dr6018 | ||||
|   DEVICE_DTS := qcom-ipq6018-wallys-dr6018 | ||||
|   DEVICE_DTS_CONFIG := config@cp01-c4 | ||||
|   SUPPORTED_DEVICES := wallys,dr6018 | ||||
|   DEVICE_PACKAGES := ath11k-wifi-wallys-dr6018 uboot-envtools | ||||
|   DEVICE_PACKAGES := ath11k-wifi-wallys-dr6018 uboot-envtools -kmod-usb-dwc3-of-simple kmod-usb-dwc3-qcom kmod-usb3 kmod-usb2 | ||||
| endef | ||||
| TARGET_DEVICES += wallys_dr6018 | ||||
|  | ||||
| @@ -72,3 +61,30 @@ define Device/qcom_cp01_c1 | ||||
|   DEVICE_PACKAGES := ath11k-wifi-qcom-ipq6018 | ||||
| endef | ||||
| TARGET_DEVICES += qcom_cp01_c1 | ||||
|  | ||||
| define Device/glinet_ax1800 | ||||
|   DEVICE_TITLE := GL-iNet AX1800 | ||||
|   DEVICE_DTS := qcom-ipq6018-gl-ax1800 | ||||
|   SUPPORTED_DEVICES := glinet,ax1800 | ||||
|   DEVICE_DTS_CONFIG := config@cp03-c1 | ||||
|   DEVICE_PACKAGES := ath11k-wifi-gl-ax1800 -kmod-usb-dwc3-of-simple kmod-usb-dwc3-qcom kmod-usb3 | ||||
| endef | ||||
| TARGET_DEVICES += glinet_ax1800 | ||||
|  | ||||
| define Device/glinet_axt1800 | ||||
|   DEVICE_TITLE := GL-iNet AXT1800 | ||||
|   DEVICE_DTS := qcom-ipq6018-gl-axt1800 | ||||
|   SUPPORTED_DEVICES := glinet,axt1800 | ||||
|   DEVICE_DTS_CONFIG := config@cp03-c1 | ||||
|   DEVICE_PACKAGES := ath11k-wifi-gl-axt1800 -kmod-usb-dwc3-of-simple kmod-usb-dwc3-qcom kmod-usb3 | ||||
| endef | ||||
| TARGET_DEVICES += glinet_axt1800 | ||||
|  | ||||
| define Device/yuncore_ax840 | ||||
|   DEVICE_TITLE := YunCore AX840 | ||||
|   DEVICE_DTS := qcom-ipq6018-yuncore-ax840 | ||||
|   DEVICE_DTS_CONFIG := config@cp03-c1 | ||||
|   SUPPORTED_DEVICES := yuncore,ax840 | ||||
|   DEVICE_PACKAGES := ath11k-wifi-yuncore-ax840 uboot-env | ||||
| endef | ||||
| TARGET_DEVICES += yuncore_ax840 | ||||
|   | ||||
| @@ -41,6 +41,8 @@ define Device/cig_wf196 | ||||
|   DEVICE_DTS := qcom-ipq807x-wf196 | ||||
|   DEVICE_DTS_CONFIG=config@hk14 | ||||
|   SUPPORTED_DEVICES := cig,wf196 | ||||
|   BLOCKSIZE := 256k | ||||
|   PAGESIZE := 4096 | ||||
|   DEVICE_PACKAGES := ath11k-wifi-cig-wf196 aq-fw-download uboot-envtools kmod-usb3 kmod-usb2 \ | ||||
|   	ath11k-firmware-qcn9000 ath11k-wifi-cig-wf196_6g | ||||
| endef | ||||
|   | ||||
| @@ -111,3 +111,22 @@ define KernelPackage/diag-char/description | ||||
| endef | ||||
|  | ||||
| $(eval $(call KernelPackage,diag-char)) | ||||
|  | ||||
| define KernelPackage/usb-dwc3-qcom | ||||
|   TITLE:=DWC3 Qualcomm USB driver | ||||
|   DEPENDS:=@(!LINUX_4_14) @TARGET_ipq807x +kmod-usb-dwc3 | ||||
|   KCONFIG:= CONFIG_USB_DWC3_QCOM | ||||
|   FILES:= $(LINUX_DIR)/drivers/usb/dwc3/dwc3-qcom.ko \ | ||||
|         $(LINUX_DIR)/drivers/usb/dwc3/dbm.ko | ||||
|   AUTOLOAD:=$(call AutoLoad,53,dwc3-qcom dbm,1) | ||||
|   $(call AddDepends/usb) | ||||
| endef | ||||
|  | ||||
| define KernelPackage/usb-dwc3-qcom/description | ||||
|  Some Qualcomm SoCs use DesignWare Core IP for USB2/3 functionality. | ||||
|  This driver also handles Qscratch wrapper which is needed for | ||||
|  peripheral mode support. | ||||
| endef | ||||
|  | ||||
|  | ||||
| $(eval $(call KernelPackage,usb-dwc3-qcom)) | ||||
|   | ||||
							
								
								
									
										25
									
								
								feeds/ipq807x/ipq807x/patches/001-backport_kbuild_fix.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								feeds/ipq807x/ipq807x/patches/001-backport_kbuild_fix.patch
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| --- a/scripts/Makefile.lib | ||||
| +++ b/scripts/Makefile.lib | ||||
| @@ -96,10 +96,10 @@ obj-dirs	:= $(addprefix $(obj)/,$(obj-di | ||||
|  # Note: Files that end up in two or more modules are compiled without the | ||||
|  #       KBUILD_MODNAME definition. The reason is that any made-up name would | ||||
|  #       differ in different configs. | ||||
| -name-fix = $(subst $(comma),_,$(subst -,_,$1)) | ||||
| -basename_flags = -D"KBUILD_BASENAME=KBUILD_STR($(call name-fix,$(basetarget)))" | ||||
| +name-fix = $(squote)$(quote)$(subst $(comma),_,$(subst -,_,$1))$(quote)$(squote) | ||||
| +basename_flags = -DKBUILD_BASENAME=$(call name-fix,$(basetarget)) | ||||
|  modname_flags  = $(if $(filter 1,$(words $(modname))),\ | ||||
| -                 -D"KBUILD_MODNAME=KBUILD_STR($(call name-fix,$(modname)))") | ||||
| +                 -DKBUILD_MODNAME=$(call name-fix,$(modname))) | ||||
|   | ||||
|  orig_c_flags   = $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(KBUILD_SUBDIR_CCFLAGS) \ | ||||
|                   $(ccflags-y) $(CFLAGS_$(basetarget).o) | ||||
| @@ -155,7 +155,7 @@ endif | ||||
|   | ||||
|  c_flags        = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE)     \ | ||||
|  		 $(__c_flags) $(modkern_cflags)                           \ | ||||
| -		 -D"KBUILD_STR(s)=\#s" $(basename_flags) $(modname_flags) | ||||
| +		 $(basename_flags) $(modname_flags) | ||||
|   | ||||
|  a_flags        = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE)     \ | ||||
|  		 $(__a_flags) $(modkern_aflags) | ||||
| @@ -0,0 +1,36 @@ | ||||
| From fd65e5a95d08389444e8591a20538b3edece0e15 Mon Sep 17 00:00:00 2001 | ||||
| From: Nikolay Aleksandrov <nikolay@cumulusnetworks.com> | ||||
| Date: Fri, 31 Jul 2020 19:26:16 +0300 | ||||
| Subject: [PATCH] net: bridge: clear bridge's private skb space on xmit | ||||
|  | ||||
| We need to clear all of the bridge private skb variables as they can be | ||||
| stale due to the packet being recirculated through the stack and then | ||||
| transmitted through the bridge device. Similar memset is already done on | ||||
| bridge's input. We've seen cases where proxyarp_replied was 1 on routed | ||||
| multicast packets transmitted through the bridge to ports with neigh | ||||
| suppress which were getting dropped. Same thing can in theory happen with | ||||
| the port isolation bit as well. | ||||
|  | ||||
| Fixes: 821f1b21cabb ("bridge: add new BR_NEIGH_SUPPRESS port flag to suppress arp and nd flood") | ||||
| Signed-off-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com> | ||||
| Signed-off-by: David S. Miller <davem@davemloft.net> | ||||
| --- | ||||
|  net/bridge/br_device.c | 2 ++ | ||||
|  1 file changed, 2 insertions(+) | ||||
|  | ||||
| diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c | ||||
| index 8c7b78f8bc23..9a2fb4aa1a10 100644 | ||||
| --- a/net/bridge/br_device.c | ||||
| +++ b/net/bridge/br_device.c | ||||
| @@ -36,6 +36,8 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev) | ||||
|  	const unsigned char *dest; | ||||
|  	u16 vid = 0; | ||||
|   | ||||
| +	memset(skb->cb, 0, sizeof(struct br_input_skb_cb)); | ||||
| + | ||||
|  	rcu_read_lock(); | ||||
|  	nf_ops = rcu_dereference(nf_br_ops); | ||||
|  	if (nf_ops && nf_ops->br_dev_xmit_hook(skb)) { | ||||
| --  | ||||
| 2.25.1 | ||||
|  | ||||
| @@ -0,0 +1,88 @@ | ||||
| From: Felix Fietkau <nbd@nbd.name> | ||||
| Date: Mon, 8 Feb 2021 11:34:08 -0800 | ||||
| Subject: [PATCH] net: extract napi poll functionality to __napi_poll() | ||||
|  | ||||
| This commit introduces a new function __napi_poll() which does the main | ||||
| logic of the existing napi_poll() function, and will be called by other | ||||
| functions in later commits. | ||||
| This idea and implementation is done by Felix Fietkau <nbd@nbd.name> and | ||||
| is proposed as part of the patch to move napi work to work_queue | ||||
| context. | ||||
| This commit by itself is a code restructure. | ||||
|  | ||||
| Signed-off-by: Felix Fietkau <nbd@nbd.name> | ||||
| Signed-off-by: Wei Wang <weiwan@google.com> | ||||
| Reviewed-by: Alexander Duyck <alexanderduyck@fb.com> | ||||
| Signed-off-by: David S. Miller <davem@davemloft.net> | ||||
| --- | ||||
|  | ||||
| --- a/net/core/dev.c | ||||
| +++ b/net/core/dev.c | ||||
| @@ -6322,15 +6322,10 @@ void netif_napi_del(struct napi_struct * | ||||
|  } | ||||
|  EXPORT_SYMBOL(netif_napi_del); | ||||
|   | ||||
| -static int napi_poll(struct napi_struct *n, struct list_head *repoll) | ||||
| +static int __napi_poll(struct napi_struct *n, bool *repoll) | ||||
|  { | ||||
| -	void *have; | ||||
|  	int work, weight; | ||||
|   | ||||
| -	list_del_init(&n->poll_list); | ||||
| - | ||||
| -	have = netpoll_poll_lock(n); | ||||
| - | ||||
|  	weight = n->weight; | ||||
|   | ||||
|  	/* This NAPI_STATE_SCHED test is for avoiding a race | ||||
| @@ -6348,7 +6343,7 @@ static int napi_poll(struct napi_struct | ||||
|  	WARN_ON_ONCE(work > weight); | ||||
|   | ||||
|  	if (likely(work < weight)) | ||||
| -		goto out_unlock; | ||||
| +		return work; | ||||
|   | ||||
|  	/* Drivers must not modify the NAPI state if they | ||||
|  	 * consume the entire weight.  In such cases this code | ||||
| @@ -6357,7 +6352,7 @@ static int napi_poll(struct napi_struct | ||||
|  	 */ | ||||
|  	if (unlikely(napi_disable_pending(n))) { | ||||
|  		napi_complete(n); | ||||
| -		goto out_unlock; | ||||
| +		return work; | ||||
|  	} | ||||
|   | ||||
|  	if (n->gro_bitmask) { | ||||
| @@ -6375,12 +6370,29 @@ static int napi_poll(struct napi_struct | ||||
|  	if (unlikely(!list_empty(&n->poll_list))) { | ||||
|  		pr_warn_once("%s: Budget exhausted after napi rescheduled\n", | ||||
|  			     n->dev ? n->dev->name : "backlog"); | ||||
| -		goto out_unlock; | ||||
| +		return work; | ||||
|  	} | ||||
|   | ||||
| -	list_add_tail(&n->poll_list, repoll); | ||||
| +	*repoll = true; | ||||
| + | ||||
| +	return work; | ||||
| +} | ||||
| + | ||||
| +static int napi_poll(struct napi_struct *n, struct list_head *repoll) | ||||
| +{ | ||||
| +	bool do_repoll = false; | ||||
| +	void *have; | ||||
| +	int work; | ||||
| + | ||||
| +	list_del_init(&n->poll_list); | ||||
| + | ||||
| +	have = netpoll_poll_lock(n); | ||||
| + | ||||
| +	work = __napi_poll(n, &do_repoll); | ||||
| + | ||||
| +	if (do_repoll) | ||||
| +		list_add_tail(&n->poll_list, repoll); | ||||
|   | ||||
| -out_unlock: | ||||
|  	netpoll_poll_unlock(have); | ||||
|   | ||||
|  	return work; | ||||
| @@ -0,0 +1,245 @@ | ||||
| From: Wei Wang <weiwan@google.com> | ||||
| Date: Mon, 8 Feb 2021 11:34:09 -0800 | ||||
| Subject: [PATCH] net: implement threaded-able napi poll loop support | ||||
|  | ||||
| This patch allows running each napi poll loop inside its own | ||||
| kernel thread. | ||||
| The kthread is created during netif_napi_add() if dev->threaded | ||||
| is set. And threaded mode is enabled in napi_enable(). We will | ||||
| provide a way to set dev->threaded and enable threaded mode | ||||
| without a device up/down in the following patch. | ||||
|  | ||||
| Once that threaded mode is enabled and the kthread is | ||||
| started, napi_schedule() will wake-up such thread instead | ||||
| of scheduling the softirq. | ||||
|  | ||||
| The threaded poll loop behaves quite likely the net_rx_action, | ||||
| but it does not have to manipulate local irqs and uses | ||||
| an explicit scheduling point based on netdev_budget. | ||||
|  | ||||
| Co-developed-by: Paolo Abeni <pabeni@redhat.com> | ||||
| Signed-off-by: Paolo Abeni <pabeni@redhat.com> | ||||
| Co-developed-by: Hannes Frederic Sowa <hannes@stressinduktion.org> | ||||
| Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org> | ||||
| Co-developed-by: Jakub Kicinski <kuba@kernel.org> | ||||
| Signed-off-by: Jakub Kicinski <kuba@kernel.org> | ||||
| Signed-off-by: Wei Wang <weiwan@google.com> | ||||
| Reviewed-by: Alexander Duyck <alexanderduyck@fb.com> | ||||
| Signed-off-by: David S. Miller <davem@davemloft.net> | ||||
| --- | ||||
|  | ||||
| --- a/include/linux/netdevice.h | ||||
| +++ b/include/linux/netdevice.h | ||||
| @@ -319,6 +319,7 @@ struct napi_struct { | ||||
|  	struct list_head	dev_list; | ||||
|  	struct hlist_node	napi_hash_node; | ||||
|  	unsigned int		napi_id; | ||||
| +	struct task_struct	*thread; | ||||
|  }; | ||||
|   | ||||
|  enum { | ||||
| @@ -326,6 +327,7 @@ enum { | ||||
|  	NAPI_STATE_DISABLE,	/* Disable pending */ | ||||
|  	NAPI_STATE_NPSVC,	/* Netpoll - don't dequeue from poll_list */ | ||||
|  	NAPI_STATE_HASHED,	/* In NAPI hash */ | ||||
| +	NAPI_STATE_THREADED,	/* The poll is performed inside its own thread*/ | ||||
|  }; | ||||
|   | ||||
|  enum gro_result { | ||||
| @@ -501,13 +503,7 @@ void napi_disable(struct napi_struct *n) | ||||
|   * Resume NAPI from being scheduled on this context. | ||||
|   * Must be paired with napi_disable. | ||||
|   */ | ||||
| -static inline void napi_enable(struct napi_struct *n) | ||||
| -{ | ||||
| -	BUG_ON(!test_bit(NAPI_STATE_SCHED, &n->state)); | ||||
| -	smp_mb__before_atomic(); | ||||
| -	clear_bit(NAPI_STATE_SCHED, &n->state); | ||||
| -	clear_bit(NAPI_STATE_NPSVC, &n->state); | ||||
| -} | ||||
| +void napi_enable(struct napi_struct *n); | ||||
|   | ||||
|  /** | ||||
|   *	napi_synchronize - wait until NAPI is not running | ||||
| @@ -1573,6 +1569,8 @@ enum netdev_priv_flags_ext { | ||||
|   *			switch driver and used to set the phys state of the | ||||
|   *			switch port. | ||||
|   * | ||||
| + *	@threaded:	napi threaded mode is enabled | ||||
| + * | ||||
|   *	FIXME: cleanup struct net_device such that network protocol info | ||||
|   *	moves out. | ||||
|   */ | ||||
| @@ -1852,6 +1850,7 @@ struct net_device { | ||||
|  	struct phy_device *phydev; | ||||
|  	struct lock_class_key *qdisc_tx_busylock; | ||||
|  	bool proto_down; | ||||
| +	unsigned		threaded:1; | ||||
|  }; | ||||
|  #define to_net_dev(d) container_of(d, struct net_device, dev) | ||||
|   | ||||
| --- a/net/core/dev.c | ||||
| +++ b/net/core/dev.c | ||||
| @@ -94,6 +94,7 @@ | ||||
|  #include <linux/ethtool.h> | ||||
|  #include <linux/notifier.h> | ||||
|  #include <linux/skbuff.h> | ||||
| +#include <linux/kthread.h> | ||||
|  #include <net/net_namespace.h> | ||||
|  #include <net/sock.h> | ||||
|  #include <linux/rtnetlink.h> | ||||
| @@ -1304,6 +1305,27 @@ void netdev_notify_peers(struct net_devi | ||||
|  } | ||||
|  EXPORT_SYMBOL(netdev_notify_peers); | ||||
|   | ||||
| +static int napi_threaded_poll(void *data); | ||||
| + | ||||
| +static int napi_kthread_create(struct napi_struct *n) | ||||
| +{ | ||||
| +	int err = 0; | ||||
| + | ||||
| +	/* Create and wake up the kthread once to put it in | ||||
| +	 * TASK_INTERRUPTIBLE mode to avoid the blocked task | ||||
| +	 * warning and work with loadavg. | ||||
| +	 */ | ||||
| +	n->thread = kthread_run(napi_threaded_poll, n, "napi/%s-%d", | ||||
| +				n->dev->name, n->napi_id); | ||||
| +	if (IS_ERR(n->thread)) { | ||||
| +		err = PTR_ERR(n->thread); | ||||
| +		pr_err("kthread_run failed with err %d\n", err); | ||||
| +		n->thread = NULL; | ||||
| +	} | ||||
| + | ||||
| +	return err; | ||||
| +} | ||||
| + | ||||
|  static int __dev_open(struct net_device *dev) | ||||
|  { | ||||
|  	const struct net_device_ops *ops = dev->netdev_ops; | ||||
| @@ -3248,6 +3270,21 @@ int weight_p __read_mostly = 64; | ||||
|  static inline void ____napi_schedule(struct softnet_data *sd, | ||||
|  				     struct napi_struct *napi) | ||||
|  { | ||||
| +	struct task_struct *thread; | ||||
| + | ||||
| +	if (test_bit(NAPI_STATE_THREADED, &napi->state)) { | ||||
| +		/* Paired with smp_mb__before_atomic() in | ||||
| +		 * napi_enable(). Use READ_ONCE() to guarantee | ||||
| +		 * a complete read on napi->thread. Only call | ||||
| +		 * wake_up_process() when it's not NULL. | ||||
| +		 */ | ||||
| +		thread = READ_ONCE(napi->thread); | ||||
| +		if (thread) { | ||||
| +			wake_up_process(thread); | ||||
| +			return; | ||||
| +		} | ||||
| +	} | ||||
| + | ||||
|  	list_add_tail(&napi->poll_list, &sd->poll_list); | ||||
|  	__raise_softirq_irqoff(NET_RX_SOFTIRQ); | ||||
|  } | ||||
| @@ -4828,9 +4865,33 @@ void netif_napi_add(struct net_device *d | ||||
|  	napi->poll_owner = -1; | ||||
|  #endif | ||||
|  	set_bit(NAPI_STATE_SCHED, &napi->state); | ||||
| +	/* Create kthread for this napi if dev->threaded is set. | ||||
| +	 * Clear dev->threaded if kthread creation failed so that | ||||
| +	 * threaded mode will not be enabled in napi_enable(). | ||||
| +	 */ | ||||
| +	if (dev->threaded && napi_kthread_create(napi)) | ||||
| +		dev->threaded = 0; | ||||
|  } | ||||
|  EXPORT_SYMBOL(netif_napi_add); | ||||
|   | ||||
| +/** | ||||
| + *	napi_enable - enable NAPI scheduling | ||||
| + *	@n: NAPI context | ||||
| + * | ||||
| + * Resume NAPI from being scheduled on this context. | ||||
| + * Must be paired with napi_disable. | ||||
| + */ | ||||
| +void napi_enable(struct napi_struct *n) | ||||
| +{ | ||||
| +	BUG_ON(!test_bit(NAPI_STATE_SCHED, &n->state)); | ||||
| +	smp_mb__before_atomic(); | ||||
| +	clear_bit(NAPI_STATE_SCHED, &n->state); | ||||
| +	clear_bit(NAPI_STATE_NPSVC, &n->state); | ||||
| +	if (n->dev->threaded && n->thread) | ||||
| +		set_bit(NAPI_STATE_THREADED, &n->state); | ||||
| +} | ||||
| +EXPORT_SYMBOL(napi_enable); | ||||
| + | ||||
|  void napi_disable(struct napi_struct *n) | ||||
|  { | ||||
|  	might_sleep(); | ||||
| @@ -4844,6 +4905,7 @@ void napi_disable(struct napi_struct *n) | ||||
|  	hrtimer_cancel(&n->timer); | ||||
|   | ||||
|  	clear_bit(NAPI_STATE_DISABLE, &n->state); | ||||
| +	clear_bit(NAPI_STATE_THREADED, &n->state); | ||||
|  } | ||||
|  EXPORT_SYMBOL(napi_disable); | ||||
|   | ||||
| @@ -4855,6 +4917,11 @@ void netif_napi_del(struct napi_struct * | ||||
|  	kfree_skb_list(napi->gro_list); | ||||
|  	napi->gro_list = NULL; | ||||
|  	napi->gro_count = 0; | ||||
| + | ||||
| +	if (napi->thread) { | ||||
| +		kthread_stop(napi->thread); | ||||
| +		napi->thread = NULL; | ||||
| +	} | ||||
|  } | ||||
|  EXPORT_SYMBOL(netif_napi_del); | ||||
|   | ||||
| @@ -4940,6 +5007,50 @@ static int napi_poll(struct napi_struct | ||||
|  	return work; | ||||
|  } | ||||
|   | ||||
| +static int napi_thread_wait(struct napi_struct *napi) | ||||
| +{ | ||||
| +	set_current_state(TASK_INTERRUPTIBLE); | ||||
| + | ||||
| +	while (!kthread_should_stop() && !napi_disable_pending(napi)) { | ||||
| +		if (test_bit(NAPI_STATE_SCHED, &napi->state)) { | ||||
| +			WARN_ON(!list_empty(&napi->poll_list)); | ||||
| +			__set_current_state(TASK_RUNNING); | ||||
| +			return 0; | ||||
| +		} | ||||
| + | ||||
| +		schedule(); | ||||
| +		set_current_state(TASK_INTERRUPTIBLE); | ||||
| +	} | ||||
| +	__set_current_state(TASK_RUNNING); | ||||
| +	return -1; | ||||
| +} | ||||
| + | ||||
| +static int napi_threaded_poll(void *data) | ||||
| +{ | ||||
| +	struct napi_struct *napi = data; | ||||
| +	void *have; | ||||
| + | ||||
| +	while (!napi_thread_wait(napi)) { | ||||
| +		for (;;) { | ||||
| +			bool repoll = false; | ||||
| + | ||||
| +			local_bh_disable(); | ||||
| + | ||||
| +			have = netpoll_poll_lock(napi); | ||||
| +			__napi_poll(napi, &repoll); | ||||
| +			netpoll_poll_unlock(have); | ||||
| + | ||||
| +			local_bh_enable(); | ||||
| + | ||||
| +			if (!repoll) | ||||
| +				break; | ||||
| + | ||||
| +			cond_resched(); | ||||
| +		} | ||||
| +	} | ||||
| +	return 0; | ||||
| +} | ||||
| + | ||||
|  static void net_rx_action(struct softirq_action *h) | ||||
|  { | ||||
|  	struct softnet_data *sd = this_cpu_ptr(&softnet_data); | ||||
| @@ -0,0 +1,156 @@ | ||||
| From: Wei Wang <weiwan@google.com> | ||||
| Date: Mon, 8 Feb 2021 11:34:10 -0800 | ||||
| Subject: [PATCH] net: add sysfs attribute to control napi threaded mode | ||||
|  | ||||
| This patch adds a new sysfs attribute to the network device class. | ||||
| Said attribute provides a per-device control to enable/disable the | ||||
| threaded mode for all the napi instances of the given network device, | ||||
| without the need for a device up/down. | ||||
| User sets it to 1 or 0 to enable or disable threaded mode. | ||||
| Note: when switching between threaded and the current softirq based mode | ||||
| for a napi instance, it will not immediately take effect if the napi is | ||||
| currently being polled. The mode switch will happen for the next time | ||||
| napi_schedule() is called. | ||||
|  | ||||
| Co-developed-by: Paolo Abeni <pabeni@redhat.com> | ||||
| Signed-off-by: Paolo Abeni <pabeni@redhat.com> | ||||
| Co-developed-by: Hannes Frederic Sowa <hannes@stressinduktion.org> | ||||
| Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org> | ||||
| Co-developed-by: Felix Fietkau <nbd@nbd.name> | ||||
| Signed-off-by: Felix Fietkau <nbd@nbd.name> | ||||
| Signed-off-by: Wei Wang <weiwan@google.com> | ||||
| Reviewed-by: Alexander Duyck <alexanderduyck@fb.com> | ||||
| Signed-off-by: David S. Miller <davem@davemloft.net> | ||||
| --- | ||||
|  | ||||
| --- a/include/linux/netdevice.h | ||||
| +++ b/include/linux/netdevice.h | ||||
| @@ -496,6 +496,8 @@ void napi_hash_del(struct napi_struct *n | ||||
|   */ | ||||
|  void napi_disable(struct napi_struct *n); | ||||
|   | ||||
| +int dev_set_threaded(struct net_device *dev, bool threaded); | ||||
| + | ||||
|  /** | ||||
|   *	napi_enable - enable NAPI scheduling | ||||
|   *	@n: napi context | ||||
| --- a/net/core/dev.c | ||||
| +++ b/net/core/dev.c | ||||
| @@ -3274,8 +3274,9 @@ static inline void ____napi_schedule(str | ||||
|   | ||||
|  	if (test_bit(NAPI_STATE_THREADED, &napi->state)) { | ||||
|  		/* Paired with smp_mb__before_atomic() in | ||||
| -		 * napi_enable(). Use READ_ONCE() to guarantee | ||||
| -		 * a complete read on napi->thread. Only call | ||||
| +		 * napi_enable()/dev_set_threaded(). | ||||
| +		 * Use READ_ONCE() to guarantee a complete | ||||
| +		 * read on napi->thread. Only call | ||||
|  		 * wake_up_process() when it's not NULL. | ||||
|  		 */ | ||||
|  		thread = READ_ONCE(napi->thread); | ||||
| @@ -4844,6 +4845,49 @@ static enum hrtimer_restart napi_watchdo | ||||
|  	return HRTIMER_NORESTART; | ||||
|  } | ||||
|   | ||||
| +int dev_set_threaded(struct net_device *dev, bool threaded) | ||||
| +{ | ||||
| +	struct napi_struct *napi; | ||||
| +	int err = 0; | ||||
| + | ||||
| +	if (dev->threaded == threaded) | ||||
| +		return 0; | ||||
| + | ||||
| +	if (threaded) { | ||||
| +		list_for_each_entry(napi, &dev->napi_list, dev_list) { | ||||
| +			if (!napi->thread) { | ||||
| +				err = napi_kthread_create(napi); | ||||
| +				if (err) { | ||||
| +					threaded = false; | ||||
| +					break; | ||||
| +				} | ||||
| +			} | ||||
| +		} | ||||
| +	} | ||||
| + | ||||
| +	dev->threaded = threaded; | ||||
| + | ||||
| +	/* Make sure kthread is created before THREADED bit | ||||
| +	 * is set. | ||||
| +	 */ | ||||
| +	smp_mb__before_atomic(); | ||||
| + | ||||
| +	/* Setting/unsetting threaded mode on a napi might not immediately | ||||
| +	 * take effect, if the current napi instance is actively being | ||||
| +	 * polled. In this case, the switch between threaded mode and | ||||
| +	 * softirq mode will happen in the next round of napi_schedule(). | ||||
| +	 * This should not cause hiccups/stalls to the live traffic. | ||||
| +	 */ | ||||
| +	list_for_each_entry(napi, &dev->napi_list, dev_list) { | ||||
| +		if (threaded) | ||||
| +			set_bit(NAPI_STATE_THREADED, &napi->state); | ||||
| +		else | ||||
| +			clear_bit(NAPI_STATE_THREADED, &napi->state); | ||||
| +	} | ||||
| + | ||||
| +	return err; | ||||
| +} | ||||
| + | ||||
|  void netif_napi_add(struct net_device *dev, struct napi_struct *napi, | ||||
|  		    int (*poll)(struct napi_struct *, int), int weight) | ||||
|  { | ||||
| --- a/net/core/net-sysfs.c | ||||
| +++ b/net/core/net-sysfs.c | ||||
| @@ -486,6 +486,45 @@ static ssize_t phys_switch_id_show(struc | ||||
|  } | ||||
|  static DEVICE_ATTR_RO(phys_switch_id); | ||||
|   | ||||
| +static ssize_t threaded_show(struct device *dev, | ||||
| +			     struct device_attribute *attr, char *buf) | ||||
| +{ | ||||
| +	struct net_device *netdev = to_net_dev(dev); | ||||
| +	ssize_t ret = -EINVAL; | ||||
| + | ||||
| +	if (!rtnl_trylock()) | ||||
| +		return restart_syscall(); | ||||
| + | ||||
| +	if (dev_isalive(netdev)) | ||||
| +		ret = sprintf(buf, fmt_dec, netdev->threaded); | ||||
| + | ||||
| +	rtnl_unlock(); | ||||
| +	return ret; | ||||
| +} | ||||
| + | ||||
| +static int modify_napi_threaded(struct net_device *dev, unsigned long val) | ||||
| +{ | ||||
| +	int ret; | ||||
| + | ||||
| +	if (list_empty(&dev->napi_list)) | ||||
| +		return -EOPNOTSUPP; | ||||
| + | ||||
| +	if (val != 0 && val != 1) | ||||
| +		return -EOPNOTSUPP; | ||||
| + | ||||
| +	ret = dev_set_threaded(dev, val); | ||||
| + | ||||
| +	return ret; | ||||
| +} | ||||
| + | ||||
| +static ssize_t threaded_store(struct device *dev, | ||||
| +			      struct device_attribute *attr, | ||||
| +			      const char *buf, size_t len) | ||||
| +{ | ||||
| +	return netdev_store(dev, attr, buf, len, modify_napi_threaded); | ||||
| +} | ||||
| +static DEVICE_ATTR_RW(threaded); | ||||
| + | ||||
|  static struct attribute *net_class_attrs[] = { | ||||
|  	&dev_attr_netdev_group.attr, | ||||
|  	&dev_attr_type.attr, | ||||
| @@ -514,6 +553,7 @@ static struct attribute *net_class_attrs | ||||
|  	&dev_attr_phys_port_name.attr, | ||||
|  	&dev_attr_phys_switch_id.attr, | ||||
|  	&dev_attr_proto_down.attr, | ||||
| +	&dev_attr_threaded.attr, | ||||
|  	NULL, | ||||
|  }; | ||||
|  ATTRIBUTE_GROUPS(net_class); | ||||
| @@ -0,0 +1,118 @@ | ||||
| From: Wei Wang <weiwan@google.com> | ||||
| Date: Mon, 1 Mar 2021 17:21:13 -0800 | ||||
| Subject: [PATCH] net: fix race between napi kthread mode and busy poll | ||||
|  | ||||
| Currently, napi_thread_wait() checks for NAPI_STATE_SCHED bit to | ||||
| determine if the kthread owns this napi and could call napi->poll() on | ||||
| it. However, if socket busy poll is enabled, it is possible that the | ||||
| busy poll thread grabs this SCHED bit (after the previous napi->poll() | ||||
| invokes napi_complete_done() and clears SCHED bit) and tries to poll | ||||
| on the same napi. napi_disable() could grab the SCHED bit as well. | ||||
| This patch tries to fix this race by adding a new bit | ||||
| NAPI_STATE_SCHED_THREADED in napi->state. This bit gets set in | ||||
| ____napi_schedule() if the threaded mode is enabled, and gets cleared | ||||
| in napi_complete_done(), and we only poll the napi in kthread if this | ||||
| bit is set. This helps distinguish the ownership of the napi between | ||||
| kthread and other scenarios and fixes the race issue. | ||||
|  | ||||
| Fixes: 29863d41bb6e ("net: implement threaded-able napi poll loop support") | ||||
| Reported-by: Martin Zaharinov <micron10@gmail.com> | ||||
| Suggested-by: Jakub Kicinski <kuba@kernel.org> | ||||
| Signed-off-by: Wei Wang <weiwan@google.com> | ||||
| Cc: Alexander Duyck <alexanderduyck@fb.com> | ||||
| Cc: Eric Dumazet <edumazet@google.com> | ||||
| Cc: Paolo Abeni <pabeni@redhat.com> | ||||
| Cc: Hannes Frederic Sowa <hannes@stressinduktion.org> | ||||
| --- | ||||
|  | ||||
| --- a/include/linux/netdevice.h | ||||
| +++ b/include/linux/netdevice.h | ||||
| @@ -328,6 +328,7 @@ enum { | ||||
|  	NAPI_STATE_NPSVC,	/* Netpoll - don't dequeue from poll_list */ | ||||
|  	NAPI_STATE_HASHED,	/* In NAPI hash */ | ||||
|  	NAPI_STATE_THREADED,	/* The poll is performed inside its own thread*/ | ||||
| +	NAPI_STATE_SCHED_THREADED,	/* Napi is currently scheduled in threaded mode */ | ||||
|  }; | ||||
|   | ||||
|  enum gro_result { | ||||
| --- a/net/core/dev.c | ||||
| +++ b/net/core/dev.c | ||||
| @@ -3281,6 +3281,8 @@ static inline void ____napi_schedule(str | ||||
|  		 */ | ||||
|  		thread = READ_ONCE(napi->thread); | ||||
|  		if (thread) { | ||||
| +			if (thread->state != TASK_INTERRUPTIBLE) | ||||
| +				set_bit(NAPI_STATE_SCHED_THREADED, &napi->state); | ||||
|  			wake_up_process(thread); | ||||
|  			return; | ||||
|  		} | ||||
| @@ -4745,12 +4747,14 @@ void __napi_complete(struct napi_struct | ||||
|  	list_del_init(&n->poll_list); | ||||
|  	smp_mb__before_atomic(); | ||||
|  	clear_bit(NAPI_STATE_SCHED, &n->state); | ||||
| +	clear_bit(NAPI_STATE_SCHED_THREADED, &n->state); | ||||
|  } | ||||
|  EXPORT_SYMBOL(__napi_complete); | ||||
|   | ||||
|  void napi_complete_done(struct napi_struct *n, int work_done) | ||||
|  { | ||||
|  	unsigned long flags; | ||||
| +	unsigned long val, new; | ||||
|   | ||||
|  	/* | ||||
|  	 * don't let napi dequeue from the cpu poll list | ||||
| @@ -4771,14 +4775,19 @@ void napi_complete_done(struct napi_stru | ||||
|  		else | ||||
|  			napi_gro_flush(n, false); | ||||
|  	} | ||||
| -	if (likely(list_empty(&n->poll_list))) { | ||||
| -		WARN_ON_ONCE(!test_and_clear_bit(NAPI_STATE_SCHED, &n->state)); | ||||
| -	} else { | ||||
| -		/* If n->poll_list is not empty, we need to mask irqs */ | ||||
| -		local_irq_save(flags); | ||||
| -		__napi_complete(n); | ||||
| -		local_irq_restore(flags); | ||||
| -	} | ||||
| + | ||||
| +	/* If n->poll_list is not empty, we need to mask irqs */ | ||||
| +	local_irq_save(flags); | ||||
| +	list_del_init(&n->poll_list); | ||||
| +	local_irq_restore(flags); | ||||
| + | ||||
| +	do { | ||||
| +		val = READ_ONCE(n->state); | ||||
| + | ||||
| +		WARN_ON_ONCE(!(val & BIT(NAPI_STATE_SCHED))); | ||||
| +		new = val & ~(BIT(NAPI_STATE_SCHED) | | ||||
| +			      BIT(NAPI_STATE_SCHED_THREADED)); | ||||
| +	} while (cmpxchg(&n->state, val, new) != val); | ||||
|  } | ||||
|  EXPORT_SYMBOL(napi_complete_done); | ||||
|   | ||||
| @@ -5053,16 +5062,25 @@ static int napi_poll(struct napi_struct | ||||
|   | ||||
|  static int napi_thread_wait(struct napi_struct *napi) | ||||
|  { | ||||
| +	bool woken = false; | ||||
| + | ||||
|  	set_current_state(TASK_INTERRUPTIBLE); | ||||
|   | ||||
|  	while (!kthread_should_stop() && !napi_disable_pending(napi)) { | ||||
| -		if (test_bit(NAPI_STATE_SCHED, &napi->state)) { | ||||
| +		/* Testing SCHED_THREADED bit here to make sure the current | ||||
| +		 * kthread owns this napi and could poll on this napi. | ||||
| +		 * Testing SCHED bit is not enough because SCHED bit might be | ||||
| +		 * set by some other busy poll thread or by napi_disable(). | ||||
| +		 */ | ||||
| +		if (test_bit(NAPI_STATE_SCHED_THREADED, &napi->state) || woken) { | ||||
|  			WARN_ON(!list_empty(&napi->poll_list)); | ||||
|  			__set_current_state(TASK_RUNNING); | ||||
|  			return 0; | ||||
|  		} | ||||
|   | ||||
|  		schedule(); | ||||
| +		/* woken being true indicates this thread owns this napi. */ | ||||
| +		woken = true; | ||||
|  		set_current_state(TASK_INTERRUPTIBLE); | ||||
|  	} | ||||
|  	__set_current_state(TASK_RUNNING); | ||||
| @@ -0,0 +1,53 @@ | ||||
| From: Paolo Abeni <pabeni@redhat.com> | ||||
| Date: Fri, 9 Apr 2021 17:24:17 +0200 | ||||
| Subject: [PATCH] net: fix hangup on napi_disable for threaded napi | ||||
|  | ||||
| napi_disable() is subject to an hangup, when the threaded | ||||
| mode is enabled and the napi is under heavy traffic. | ||||
|  | ||||
| If the relevant napi has been scheduled and the napi_disable() | ||||
| kicks in before the next napi_threaded_wait() completes - so | ||||
| that the latter quits due to the napi_disable_pending() condition, | ||||
| the existing code leaves the NAPI_STATE_SCHED bit set and the | ||||
| napi_disable() loop waiting for such bit will hang. | ||||
|  | ||||
| This patch addresses the issue by dropping the NAPI_STATE_DISABLE | ||||
| bit test in napi_thread_wait(). The later napi_threaded_poll() | ||||
| iteration will take care of clearing the NAPI_STATE_SCHED. | ||||
|  | ||||
| This also addresses a related problem reported by Jakub: | ||||
| before this patch a napi_disable()/napi_enable() pair killed | ||||
| the napi thread, effectively disabling the threaded mode. | ||||
| On the patched kernel napi_disable() simply stops scheduling | ||||
| the relevant thread. | ||||
|  | ||||
| v1 -> v2: | ||||
|   - let the main napi_thread_poll() loop clear the SCHED bit | ||||
|  | ||||
| Reported-by: Jakub Kicinski <kuba@kernel.org> | ||||
| Fixes: 29863d41bb6e ("net: implement threaded-able napi poll loop support") | ||||
| Signed-off-by: Paolo Abeni <pabeni@redhat.com> | ||||
| Reviewed-by: Eric Dumazet <edumazet@google.com> | ||||
| Link: https://lore.kernel.org/r/883923fa22745a9589e8610962b7dc59df09fb1f.1617981844.git.pabeni@redhat.com | ||||
| Signed-off-by: Jakub Kicinski <kuba@kernel.org> | ||||
| --- | ||||
|  | ||||
| --- a/net/core/dev.c | ||||
| +++ b/net/core/dev.c | ||||
| @@ -5066,7 +5066,7 @@ static int napi_thread_wait(struct napi_ | ||||
|   | ||||
|  	set_current_state(TASK_INTERRUPTIBLE); | ||||
|   | ||||
| -	while (!kthread_should_stop() && !napi_disable_pending(napi)) { | ||||
| +	while (!kthread_should_stop()) { | ||||
|  		/* Testing SCHED_THREADED bit here to make sure the current | ||||
|  		 * kthread owns this napi and could poll on this napi. | ||||
|  		 * Testing SCHED bit is not enough because SCHED bit might be | ||||
| @@ -5084,6 +5084,7 @@ static int napi_thread_wait(struct napi_ | ||||
|  		set_current_state(TASK_INTERRUPTIBLE); | ||||
|  	} | ||||
|  	__set_current_state(TASK_RUNNING); | ||||
| + | ||||
|  	return -1; | ||||
|  } | ||||
|   | ||||
| @@ -0,0 +1,439 @@ | ||||
| From: Daniel Borkmann <daniel@iogearbox.net> | ||||
| Date: Thu, 7 Jan 2016 22:29:47 +0100 | ||||
| Subject: [PATCH] net, sched: add clsact qdisc | ||||
|  | ||||
| This work adds a generalization of the ingress qdisc as a qdisc holding | ||||
| only classifiers. The clsact qdisc works on ingress, but also on egress. | ||||
| In both cases, it's execution happens without taking the qdisc lock, and | ||||
| the main difference for the egress part compared to prior version of [1] | ||||
| is that this can be applied with _any_ underlying real egress qdisc (also | ||||
| classless ones). | ||||
|  | ||||
| Besides solving the use-case of [1], that is, allowing for more programmability | ||||
| on assigning skb->priority for the mqprio case that is supported by most | ||||
| popular 10G+ NICs, it also opens up a lot more flexibility for other tc | ||||
| applications. The main work on classification can already be done at clsact | ||||
| egress time if the use-case allows and state stored for later retrieval | ||||
| f.e. again in skb->priority with major/minors (which is checked by most | ||||
| classful qdiscs before consulting tc_classify()) and/or in other skb fields | ||||
| like skb->tc_index for some light-weight post-processing to get to the | ||||
| eventual classid in case of a classful qdisc. Another use case is that | ||||
| the clsact egress part allows to have a central egress counterpart to | ||||
| the ingress classifiers, so that classifiers can easily share state (e.g. | ||||
| in cls_bpf via eBPF maps) for ingress and egress. | ||||
|  | ||||
| Currently, default setups like mq + pfifo_fast would require for this to | ||||
| use, for example, prio qdisc instead (to get a tc_classify() run) and to | ||||
| duplicate the egress classifier for each queue. With clsact, it allows | ||||
| for leaving the setup as is, it can additionally assign skb->priority to | ||||
| put the skb in one of pfifo_fast's bands and it can share state with maps. | ||||
| Moreover, we can access the skb's dst entry (f.e. to retrieve tclassid) | ||||
| w/o the need to perform a skb_dst_force() to hold on to it any longer. In | ||||
| lwt case, we can also use this facility to setup dst metadata via cls_bpf | ||||
| (bpf_skb_set_tunnel_key()) without needing a real egress qdisc just for | ||||
| that (case of IFF_NO_QUEUE devices, for example). | ||||
|  | ||||
| The realization can be done without any changes to the scheduler core | ||||
| framework. All it takes is that we have two a-priori defined minors/child | ||||
| classes, where we can mux between ingress and egress classifier list | ||||
| (dev->ingress_cl_list and dev->egress_cl_list, latter stored close to | ||||
| dev->_tx to avoid extra cacheline miss for moderate loads). The egress | ||||
| part is a bit similar modelled to handle_ing() and patched to a noop in | ||||
| case the functionality is not used. Both handlers are now called | ||||
| sch_handle_ingress() and sch_handle_egress(), code sharing among the two | ||||
| doesn't seem practical as there are various minor differences in both | ||||
| paths, so that making them conditional in a single handler would rather | ||||
| slow things down. | ||||
|  | ||||
| Full compatibility to ingress qdisc is provided as well. Since both | ||||
| piggyback on TC_H_CLSACT, only one of them (ingress/clsact) can exist | ||||
| per netdevice, and thus ingress qdisc specific behaviour can be retained | ||||
| for user space. This means, either a user does 'tc qdisc add dev foo ingress' | ||||
| and configures ingress qdisc as usual, or the 'tc qdisc add dev foo clsact' | ||||
| alternative, where both, ingress and egress classifier can be configured | ||||
| as in the below example. ingress qdisc supports attaching classifier to any | ||||
| minor number whereas clsact has two fixed minors for muxing between the | ||||
| lists, therefore to not break user space setups, they are better done as | ||||
| two separate qdiscs. | ||||
|  | ||||
| I decided to extend the sch_ingress module with clsact functionality so | ||||
| that commonly used code can be reused, the module is being aliased with | ||||
| sch_clsact so that it can be auto-loaded properly. Alternative would have been | ||||
| to add a flag when initializing ingress to alter its behaviour plus aliasing | ||||
| to a different name (as it's more than just ingress). However, the first would | ||||
| end up, based on the flag, choosing the new/old behaviour by calling different | ||||
| function implementations to handle each anyway, the latter would require to | ||||
| register ingress qdisc once again under different alias. So, this really begs | ||||
| to provide a minimal, cleaner approach to have Qdisc_ops and Qdisc_class_ops | ||||
| by its own that share callbacks used by both. | ||||
|  | ||||
| Example, adding qdisc: | ||||
|  | ||||
|    # tc qdisc add dev foo clsact | ||||
|    # tc qdisc show dev foo | ||||
|    qdisc mq 0: root | ||||
|    qdisc pfifo_fast 0: parent :1 bands 3 priomap  1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1 | ||||
|    qdisc pfifo_fast 0: parent :2 bands 3 priomap  1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1 | ||||
|    qdisc pfifo_fast 0: parent :3 bands 3 priomap  1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1 | ||||
|    qdisc pfifo_fast 0: parent :4 bands 3 priomap  1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1 | ||||
|    qdisc clsact ffff: parent ffff:fff1 | ||||
|  | ||||
| Adding filters (deleting, etc works analogous by specifying ingress/egress): | ||||
|  | ||||
|    # tc filter add dev foo ingress bpf da obj bar.o sec ingress | ||||
|    # tc filter add dev foo egress  bpf da obj bar.o sec egress | ||||
|    # tc filter show dev foo ingress | ||||
|    filter protocol all pref 49152 bpf | ||||
|    filter protocol all pref 49152 bpf handle 0x1 bar.o:[ingress] direct-action | ||||
|    # tc filter show dev foo egress | ||||
|    filter protocol all pref 49152 bpf | ||||
|    filter protocol all pref 49152 bpf handle 0x1 bar.o:[egress] direct-action | ||||
|  | ||||
| A 'tc filter show dev foo' or 'tc filter show dev foo parent ffff:' will | ||||
| show an empty list for clsact. Either using the parent names (ingress/egress) | ||||
| or specifying the full major/minor will then show the related filter lists. | ||||
|  | ||||
| Prior work on a mqprio prequeue() facility [1] was done mainly by John Fastabend. | ||||
|  | ||||
|   [1] http://patchwork.ozlabs.org/patch/512949/ | ||||
|  | ||||
| Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> | ||||
| Acked-by: John Fastabend <john.r.fastabend@intel.com> | ||||
| Signed-off-by: David S. Miller <davem@davemloft.net> | ||||
| --- | ||||
|  | ||||
| --- a/include/linux/netdevice.h | ||||
| +++ b/include/linux/netdevice.h | ||||
| @@ -1770,7 +1770,9 @@ struct net_device { | ||||
|  #ifdef CONFIG_XPS | ||||
|  	struct xps_dev_maps __rcu *xps_maps; | ||||
|  #endif | ||||
| - | ||||
| +#ifdef CONFIG_NET_CLS_ACT | ||||
| +	struct tcf_proto __rcu  *egress_cl_list; | ||||
| +#endif | ||||
|  #ifdef CONFIG_NET_SWITCHDEV | ||||
|  	u32			offload_fwd_mark; | ||||
|  #endif | ||||
| --- a/include/linux/rtnetlink.h | ||||
| +++ b/include/linux/rtnetlink.h | ||||
| @@ -84,6 +84,11 @@ void net_inc_ingress_queue(void); | ||||
|  void net_dec_ingress_queue(void); | ||||
|  #endif | ||||
|   | ||||
| +#ifdef CONFIG_NET_EGRESS | ||||
| +void net_inc_egress_queue(void); | ||||
| +void net_dec_egress_queue(void); | ||||
| +#endif | ||||
| + | ||||
|  extern void rtnetlink_init(void); | ||||
|  extern void __rtnl_unlock(void); | ||||
|   | ||||
| --- a/include/uapi/linux/pkt_sched.h | ||||
| +++ b/include/uapi/linux/pkt_sched.h | ||||
| @@ -72,6 +72,10 @@ struct tc_estimator { | ||||
|  #define TC_H_UNSPEC	(0U) | ||||
|  #define TC_H_ROOT	(0xFFFFFFFFU) | ||||
|  #define TC_H_INGRESS    (0xFFFFFFF1U) | ||||
| +#define TC_H_CLSACT	TC_H_INGRESS | ||||
| + | ||||
| +#define TC_H_MIN_INGRESS	0xFFF2U | ||||
| +#define TC_H_MIN_EGRESS		0xFFF3U | ||||
|   | ||||
|  /* Need to corrospond to iproute2 tc/tc_core.h "enum link_layer" */ | ||||
|  enum tc_link_layer { | ||||
| --- a/net/core/dev.c | ||||
| +++ b/net/core/dev.c | ||||
| @@ -1697,6 +1697,22 @@ void net_dec_ingress_queue(void) | ||||
|  EXPORT_SYMBOL_GPL(net_dec_ingress_queue); | ||||
|  #endif | ||||
|   | ||||
| +#ifdef CONFIG_NET_EGRESS | ||||
| +static struct static_key egress_needed __read_mostly; | ||||
| + | ||||
| +void net_inc_egress_queue(void) | ||||
| +{ | ||||
| +	static_key_slow_inc(&egress_needed); | ||||
| +} | ||||
| +EXPORT_SYMBOL_GPL(net_inc_egress_queue); | ||||
| + | ||||
| +void net_dec_egress_queue(void) | ||||
| +{ | ||||
| +	static_key_slow_dec(&egress_needed); | ||||
| +} | ||||
| +EXPORT_SYMBOL_GPL(net_dec_egress_queue); | ||||
| +#endif | ||||
| + | ||||
|  static struct static_key netstamp_needed __read_mostly; | ||||
|  #ifdef HAVE_JUMP_LABEL | ||||
|  static atomic_t netstamp_needed_deferred; | ||||
| @@ -2936,7 +2952,6 @@ static inline int __dev_xmit_skb(struct | ||||
|  	bool contended; | ||||
|  	int rc; | ||||
|   | ||||
| -	qdisc_pkt_len_init(skb); | ||||
|  	qdisc_calculate_pkt_len(skb, q); | ||||
|  	/* | ||||
|  	 * Heuristic to force contended enqueues to serialize on a | ||||
| @@ -3028,6 +3043,49 @@ int dev_loopback_xmit(struct net *net, s | ||||
|  } | ||||
|  EXPORT_SYMBOL(dev_loopback_xmit); | ||||
|   | ||||
| +#ifdef CONFIG_NET_EGRESS | ||||
| +static struct sk_buff * | ||||
| +sch_handle_egress(struct sk_buff *skb, int *ret, struct net_device *dev) | ||||
| +{ | ||||
| +	struct tcf_proto *cl = rcu_dereference_bh(dev->egress_cl_list); | ||||
| +	struct tcf_result cl_res; | ||||
| + | ||||
| +	if (!cl) | ||||
| +		return skb; | ||||
| + | ||||
| +	/* skb->tc_verd and qdisc_skb_cb(skb)->pkt_len were already set | ||||
| +	 * earlier by the caller. | ||||
| +	 */ | ||||
| +	qdisc_bstats_cpu_update(cl->q, skb); | ||||
| + | ||||
| +	switch (tc_classify(skb, cl, &cl_res, false)) { | ||||
| +	case TC_ACT_OK: | ||||
| +	case TC_ACT_RECLASSIFY: | ||||
| +		skb->tc_index = TC_H_MIN(cl_res.classid); | ||||
| +		break; | ||||
| +	case TC_ACT_SHOT: | ||||
| +		qdisc_qstats_cpu_drop(cl->q); | ||||
| +		*ret = NET_XMIT_DROP; | ||||
| +		goto drop; | ||||
| +	case TC_ACT_STOLEN: | ||||
| +	case TC_ACT_QUEUED: | ||||
| +		*ret = NET_XMIT_SUCCESS; | ||||
| +drop: | ||||
| +		kfree_skb(skb); | ||||
| +		return NULL; | ||||
| +	case TC_ACT_REDIRECT: | ||||
| +		/* No need to push/pop skb's mac_header here on egress! */ | ||||
| +		skb_do_redirect(skb); | ||||
| +		*ret = NET_XMIT_SUCCESS; | ||||
| +		return NULL; | ||||
| +	default: | ||||
| +		break; | ||||
| +	} | ||||
| + | ||||
| +	return skb; | ||||
| +} | ||||
| +#endif /* CONFIG_NET_EGRESS */ | ||||
| + | ||||
|  static inline int get_xps_queue(struct net_device *dev, struct sk_buff *skb) | ||||
|  { | ||||
|  #ifdef CONFIG_XPS | ||||
| @@ -3152,6 +3210,17 @@ static int __dev_queue_xmit(struct sk_bu | ||||
|   | ||||
|  	skb_update_prio(skb); | ||||
|   | ||||
| +	qdisc_pkt_len_init(skb); | ||||
| +#ifdef CONFIG_NET_CLS_ACT | ||||
| +	skb->tc_verd = SET_TC_AT(skb->tc_verd, AT_EGRESS); | ||||
| +# ifdef CONFIG_NET_EGRESS | ||||
| +	if (static_key_false(&egress_needed)) { | ||||
| +		skb = sch_handle_egress(skb, &rc, dev); | ||||
| +		if (!skb) | ||||
| +			goto out; | ||||
| +	} | ||||
| +# endif | ||||
| +#endif | ||||
|  	/* If device/qdisc don't need skb->dst, release it right now while | ||||
|  	 * its hot in this cpu cache. | ||||
|  	 */ | ||||
| @@ -3173,9 +3242,6 @@ static int __dev_queue_xmit(struct sk_bu | ||||
|  	txq = netdev_pick_tx(dev, skb, accel_priv); | ||||
|  	q = rcu_dereference_bh(txq->qdisc); | ||||
|   | ||||
| -#ifdef CONFIG_NET_CLS_ACT | ||||
| -	skb->tc_verd = SET_TC_AT(skb->tc_verd, AT_EGRESS); | ||||
| -#endif | ||||
|  	trace_net_dev_queue(skb); | ||||
|  	if (q->enqueue) { | ||||
|  		rc = __dev_xmit_skb(skb, q, dev, txq); | ||||
| @@ -3750,9 +3816,9 @@ int (*br_fdb_test_addr_hook)(struct net_ | ||||
|  EXPORT_SYMBOL_GPL(br_fdb_test_addr_hook); | ||||
|  #endif | ||||
|   | ||||
| -static inline struct sk_buff *handle_ing(struct sk_buff *skb, | ||||
| -					 struct packet_type **pt_prev, | ||||
| -					 int *ret, struct net_device *orig_dev) | ||||
| +static inline struct sk_buff * | ||||
| +sch_handle_ingress(struct sk_buff *skb, struct packet_type **pt_prev, int *ret, | ||||
| +		   struct net_device *orig_dev) | ||||
|  { | ||||
|  #ifdef CONFIG_NET_CLS_ACT | ||||
|  	struct tcf_proto *cl = rcu_dereference_bh(skb->dev->ingress_cl_list); | ||||
| @@ -3974,7 +4040,7 @@ another_round: | ||||
|  skip_taps: | ||||
|  #ifdef CONFIG_NET_INGRESS | ||||
|  	if (static_key_false(&ingress_needed)) { | ||||
| -		skb = handle_ing(skb, &pt_prev, &ret, orig_dev); | ||||
| +		skb = sch_handle_ingress(skb, &pt_prev, &ret, orig_dev); | ||||
|  		if (!skb) | ||||
|  			goto out; | ||||
|   | ||||
| --- a/net/Kconfig | ||||
| +++ b/net/Kconfig | ||||
| @@ -54,6 +54,9 @@ config COMPAT_NETLINK_MESSAGES | ||||
|  config NET_INGRESS | ||||
|  	bool | ||||
|   | ||||
| +config NET_EGRESS | ||||
| +	bool | ||||
| + | ||||
|  menu "Networking options" | ||||
|   | ||||
|  source "net/packet/Kconfig" | ||||
| --- a/net/sched/cls_bpf.c | ||||
| +++ b/net/sched/cls_bpf.c | ||||
| @@ -291,7 +291,7 @@ static int cls_bpf_prog_from_efd(struct | ||||
|  	prog->bpf_name = name; | ||||
|  	prog->filter = fp; | ||||
|   | ||||
| -	if (fp->dst_needed) | ||||
| +	if (fp->dst_needed && !(tp->q->flags & TCQ_F_INGRESS)) | ||||
|  		netif_keep_dst(qdisc_dev(tp->q)); | ||||
|   | ||||
|  	return 0; | ||||
| --- a/net/sched/Kconfig | ||||
| +++ b/net/sched/Kconfig | ||||
| @@ -342,15 +342,21 @@ config NET_SCH_PIE | ||||
|  	  If unsure, say N. | ||||
|   | ||||
|  config NET_SCH_INGRESS | ||||
| -	tristate "Ingress Qdisc" | ||||
| +	tristate "Ingress/classifier-action Qdisc" | ||||
|  	depends on NET_CLS_ACT | ||||
|  	select NET_INGRESS | ||||
| +	select NET_EGRESS | ||||
|  	---help--- | ||||
| -	  Say Y here if you want to use classifiers for incoming packets. | ||||
| +	  Say Y here if you want to use classifiers for incoming and/or outgoing | ||||
| +	  packets. This qdisc doesn't do anything else besides running classifiers, | ||||
| +	  which can also have actions attached to them. In case of outgoing packets, | ||||
| +	  classifiers that this qdisc holds are executed in the transmit path | ||||
| +	  before real enqueuing to an egress qdisc happens. | ||||
| + | ||||
|  	  If unsure, say Y. | ||||
|   | ||||
| -	  To compile this code as a module, choose M here: the | ||||
| -	  module will be called sch_ingress. | ||||
| +	  To compile this code as a module, choose M here: the module will be | ||||
| +	  called sch_ingress with alias of sch_clsact. | ||||
|   | ||||
|  config NET_SCH_PLUG | ||||
|  	tristate "Plug network traffic until release (PLUG)" | ||||
| --- a/net/sched/sch_ingress.c | ||||
| +++ b/net/sched/sch_ingress.c | ||||
| @@ -1,4 +1,5 @@ | ||||
| -/* net/sched/sch_ingress.c - Ingress qdisc | ||||
| +/* net/sched/sch_ingress.c - Ingress and clsact qdisc | ||||
| + * | ||||
|   *              This program is free software; you can redistribute it and/or | ||||
|   *              modify it under the terms of the GNU General Public License | ||||
|   *              as published by the Free Software Foundation; either version | ||||
| @@ -98,17 +99,100 @@ static struct Qdisc_ops ingress_qdisc_op | ||||
|  	.owner		=	THIS_MODULE, | ||||
|  }; | ||||
|   | ||||
| +static unsigned long clsact_get(struct Qdisc *sch, u32 classid) | ||||
| +{ | ||||
| +	switch (TC_H_MIN(classid)) { | ||||
| +	case TC_H_MIN(TC_H_MIN_INGRESS): | ||||
| +	case TC_H_MIN(TC_H_MIN_EGRESS): | ||||
| +		return TC_H_MIN(classid); | ||||
| +	default: | ||||
| +		return 0; | ||||
| +	} | ||||
| +} | ||||
| + | ||||
| +static unsigned long clsact_bind_filter(struct Qdisc *sch, | ||||
| +					unsigned long parent, u32 classid) | ||||
| +{ | ||||
| +	return clsact_get(sch, classid); | ||||
| +} | ||||
| + | ||||
| +static struct tcf_proto __rcu **clsact_find_tcf(struct Qdisc *sch, | ||||
| +						unsigned long cl) | ||||
| +{ | ||||
| +	struct net_device *dev = qdisc_dev(sch); | ||||
| + | ||||
| +	switch (cl) { | ||||
| +	case TC_H_MIN(TC_H_MIN_INGRESS): | ||||
| +		return &dev->ingress_cl_list; | ||||
| +	case TC_H_MIN(TC_H_MIN_EGRESS): | ||||
| +		return &dev->egress_cl_list; | ||||
| +	default: | ||||
| +		return NULL; | ||||
| +	} | ||||
| +} | ||||
| + | ||||
| +static int clsact_init(struct Qdisc *sch, struct nlattr *opt) | ||||
| +{ | ||||
| +	net_inc_ingress_queue(); | ||||
| +	net_inc_egress_queue(); | ||||
| + | ||||
| +	sch->flags |= TCQ_F_CPUSTATS; | ||||
| + | ||||
| +	return 0; | ||||
| +} | ||||
| + | ||||
| +static void clsact_destroy(struct Qdisc *sch) | ||||
| +{ | ||||
| +	struct net_device *dev = qdisc_dev(sch); | ||||
| + | ||||
| +	tcf_destroy_chain(&dev->ingress_cl_list); | ||||
| +	tcf_destroy_chain(&dev->egress_cl_list); | ||||
| + | ||||
| +	net_dec_ingress_queue(); | ||||
| +	net_dec_egress_queue(); | ||||
| +} | ||||
| + | ||||
| +static const struct Qdisc_class_ops clsact_class_ops = { | ||||
| +	.leaf		=	ingress_leaf, | ||||
| +	.get		=	clsact_get, | ||||
| +	.put		=	ingress_put, | ||||
| +	.walk		=	ingress_walk, | ||||
| +	.tcf_chain	=	clsact_find_tcf, | ||||
| +	.bind_tcf	=	clsact_bind_filter, | ||||
| +	.unbind_tcf	=	ingress_put, | ||||
| +}; | ||||
| + | ||||
| +static struct Qdisc_ops clsact_qdisc_ops __read_mostly = { | ||||
| +	.cl_ops		=	&clsact_class_ops, | ||||
| +	.id		=	"clsact", | ||||
| +	.init		=	clsact_init, | ||||
| +	.destroy	=	clsact_destroy, | ||||
| +	.dump		=	ingress_dump, | ||||
| +	.owner		=	THIS_MODULE, | ||||
| +}; | ||||
| + | ||||
|  static int __init ingress_module_init(void) | ||||
|  { | ||||
| -	return register_qdisc(&ingress_qdisc_ops); | ||||
| +	int ret; | ||||
| + | ||||
| +	ret = register_qdisc(&ingress_qdisc_ops); | ||||
| +	if (!ret) { | ||||
| +		ret = register_qdisc(&clsact_qdisc_ops); | ||||
| +		if (ret) | ||||
| +			unregister_qdisc(&ingress_qdisc_ops); | ||||
| +	} | ||||
| + | ||||
| +	return ret; | ||||
|  } | ||||
|   | ||||
|  static void __exit ingress_module_exit(void) | ||||
|  { | ||||
|  	unregister_qdisc(&ingress_qdisc_ops); | ||||
| +	unregister_qdisc(&clsact_qdisc_ops); | ||||
|  } | ||||
|   | ||||
|  module_init(ingress_module_init); | ||||
|  module_exit(ingress_module_exit); | ||||
|   | ||||
| +MODULE_ALIAS("sch_clsact"); | ||||
|  MODULE_LICENSE("GPL"); | ||||
| @@ -0,0 +1,75 @@ | ||||
| From: Shmulik Ladkani <shmulik.ladkani@gmail.com> | ||||
| Date: Thu, 13 Oct 2016 09:06:41 +0300 | ||||
| Subject: [PATCH] net/sched: act_mirred: Rename tcfm_ok_push to | ||||
|  tcfm_mac_header_xmit and make it a bool | ||||
|  | ||||
| 'tcfm_ok_push' specifies whether a mac_len sized push is needed upon | ||||
| egress to the target device (if action is performed at ingress). | ||||
|  | ||||
| Rename it to 'tcfm_mac_header_xmit' as this is actually an attribute of | ||||
| the target device (and use a bool instead of int). | ||||
|  | ||||
| This allows to decouple the attribute from the action to be taken. | ||||
|  | ||||
| Signed-off-by: Shmulik Ladkani <shmulik.ladkani@gmail.com> | ||||
| Acked-by: Jamal Hadi Salim <jhs@mojatatu.com> | ||||
| Signed-off-by: David S. Miller <davem@davemloft.net> | ||||
| --- | ||||
|  | ||||
| --- a/include/net/tc_act/tc_mirred.h | ||||
| +++ b/include/net/tc_act/tc_mirred.h | ||||
| @@ -7,7 +7,7 @@ struct tcf_mirred { | ||||
|  	struct tcf_common	common; | ||||
|  	int			tcfm_eaction; | ||||
|  	int			tcfm_ifindex; | ||||
| -	int			tcfm_ok_push; | ||||
| +	bool			tcfm_mac_header_xmit; | ||||
|  	struct net_device __rcu	*tcfm_dev; | ||||
|  	struct list_head	tcfm_list; | ||||
|  }; | ||||
| --- a/net/sched/act_mirred.c | ||||
| +++ b/net/sched/act_mirred.c | ||||
| @@ -55,10 +55,11 @@ static int tcf_mirred_init(struct net *n | ||||
|  			   int bind) | ||||
|  { | ||||
|  	struct nlattr *tb[TCA_MIRRED_MAX + 1]; | ||||
| +	bool mac_header_xmit = false; | ||||
|  	struct tc_mirred *parm; | ||||
|  	struct tcf_mirred *m; | ||||
|  	struct net_device *dev; | ||||
| -	int ret, ok_push = 0; | ||||
| +	int ret; | ||||
|   | ||||
|  	if (nla == NULL) | ||||
|  		return -EINVAL; | ||||
| @@ -86,10 +87,10 @@ static int tcf_mirred_init(struct net *n | ||||
|  		case ARPHRD_IPGRE: | ||||
|  		case ARPHRD_VOID: | ||||
|  		case ARPHRD_NONE: | ||||
| -			ok_push = 0; | ||||
| +			mac_header_xmit = false; | ||||
|  			break; | ||||
|  		default: | ||||
| -			ok_push = 1; | ||||
| +			mac_header_xmit = true; | ||||
|  			break; | ||||
|  		} | ||||
|  	} else { | ||||
| @@ -123,7 +124,7 @@ static int tcf_mirred_init(struct net *n | ||||
|  			dev_put(rcu_dereference_protected(m->tcfm_dev, 1)); | ||||
|  		dev_hold(dev); | ||||
|  		rcu_assign_pointer(m->tcfm_dev, dev); | ||||
| -		m->tcfm_ok_push = ok_push; | ||||
| +		m->tcfm_mac_header_xmit = mac_header_xmit; | ||||
|  	} | ||||
|   | ||||
|  	if (ret == ACT_P_CREATED) { | ||||
| @@ -169,7 +170,7 @@ static int tcf_mirred(struct sk_buff *sk | ||||
|  		goto out; | ||||
|   | ||||
|  	if (!(at & AT_EGRESS)) { | ||||
| -		if (m->tcfm_ok_push) | ||||
| +		if (m->tcfm_mac_header_xmit) | ||||
|  			skb_push_rcsum(skb2, skb->mac_len); | ||||
|  	} | ||||
|   | ||||
| @@ -0,0 +1,36 @@ | ||||
| From: Shmulik Ladkani <shmulik.ladkani@gmail.com> | ||||
| Date: Thu, 13 Oct 2016 09:06:42 +0300 | ||||
| Subject: [PATCH] net/sched: act_mirred: Refactor detection whether dev needs | ||||
|  xmit at mac header | ||||
|  | ||||
| Move detection logic that tests whether device expects skb data to point | ||||
| at mac_header upon xmit into a function. | ||||
|  | ||||
| Signed-off-by: Shmulik Ladkani <shmulik.ladkani@gmail.com> | ||||
| Acked-by: Jamal Hadi Salim <jhs@mojatatu.com> | ||||
| Signed-off-by: David S. Miller <davem@davemloft.net> | ||||
| --- | ||||
|  | ||||
| --- a/net/sched/act_mirred.c | ||||
| +++ b/net/sched/act_mirred.c | ||||
| @@ -80,19 +80,7 @@ static int tcf_mirred_init(struct net *n | ||||
|  		dev = __dev_get_by_index(net, parm->ifindex); | ||||
|  		if (dev == NULL) | ||||
|  			return -ENODEV; | ||||
| -		switch (dev->type) { | ||||
| -		case ARPHRD_TUNNEL: | ||||
| -		case ARPHRD_TUNNEL6: | ||||
| -		case ARPHRD_SIT: | ||||
| -		case ARPHRD_IPGRE: | ||||
| -		case ARPHRD_VOID: | ||||
| -		case ARPHRD_NONE: | ||||
| -			mac_header_xmit = false; | ||||
| -			break; | ||||
| -		default: | ||||
| -			mac_header_xmit = true; | ||||
| -			break; | ||||
| -		} | ||||
| +		mac_header_xmit = dev_is_mac_header_xmit(dev); | ||||
|  	} else { | ||||
|  		dev = NULL; | ||||
|  	} | ||||
| @@ -0,0 +1,125 @@ | ||||
| From: Shmulik Ladkani <shmulik.ladkani@gmail.com> | ||||
| Date: Thu, 13 Oct 2016 09:06:44 +0300 | ||||
| Subject: [PATCH] net/sched: act_mirred: Implement ingress actions | ||||
|  | ||||
| Up until now, 'action mirred' supported only egress actions (either | ||||
| TCA_EGRESS_REDIR or TCA_EGRESS_MIRROR). | ||||
|  | ||||
| This patch implements the corresponding ingress actions | ||||
| TCA_INGRESS_REDIR and TCA_INGRESS_MIRROR. | ||||
|  | ||||
| This allows attaching filters whose target is to hand matching skbs into | ||||
| the rx processing of a specified device. | ||||
|  | ||||
| Signed-off-by: Shmulik Ladkani <shmulik.ladkani@gmail.com> | ||||
| Cc: Jamal Hadi Salim <jhs@mojatatu.com> | ||||
| Cc: Eric Dumazet <eric.dumazet@gmail.com> | ||||
| Cc: Cong Wang <xiyou.wangcong@gmail.com> | ||||
| Tested-by: Jamal Hadi Salim <jhs@mojatatu.com> | ||||
| Acked-by: Jamal Hadi Salim <jhs@mojatatu.com> | ||||
| Signed-off-by: David S. Miller <davem@davemloft.net> | ||||
| --- | ||||
|  | ||||
| --- a/net/sched/act_mirred.c | ||||
| +++ b/net/sched/act_mirred.c | ||||
| @@ -33,6 +33,25 @@ | ||||
|  static LIST_HEAD(mirred_list); | ||||
|  static DEFINE_SPINLOCK(mirred_list_lock); | ||||
|   | ||||
| +static bool tcf_mirred_is_act_redirect(int action) | ||||
| +{ | ||||
| +	return action == TCA_EGRESS_REDIR || action == TCA_INGRESS_REDIR; | ||||
| +} | ||||
| + | ||||
| +static u32 tcf_mirred_act_direction(int action) | ||||
| +{ | ||||
| +	switch (action) { | ||||
| +	case TCA_EGRESS_REDIR: | ||||
| +	case TCA_EGRESS_MIRROR: | ||||
| +		return AT_EGRESS; | ||||
| +	case TCA_INGRESS_REDIR: | ||||
| +	case TCA_INGRESS_MIRROR: | ||||
| +		return AT_INGRESS; | ||||
| +	default: | ||||
| +		BUG(); | ||||
| +	} | ||||
| +} | ||||
| + | ||||
|  static void tcf_mirred_release(struct tc_action *a, int bind) | ||||
|  { | ||||
|  	struct tcf_mirred *m = to_mirred(a); | ||||
| @@ -72,6 +91,8 @@ static int tcf_mirred_init(struct net *n | ||||
|  	switch (parm->eaction) { | ||||
|  	case TCA_EGRESS_MIRROR: | ||||
|  	case TCA_EGRESS_REDIR: | ||||
| +	case TCA_INGRESS_REDIR: | ||||
| +	case TCA_INGRESS_MIRROR: | ||||
|  		break; | ||||
|  	default: | ||||
|  		return -EINVAL; | ||||
| @@ -129,9 +150,12 @@ static int tcf_mirred(struct sk_buff *sk | ||||
|  		      struct tcf_result *res) | ||||
|  { | ||||
|  	struct tcf_mirred *m = a->priv; | ||||
| +	bool m_mac_header_xmit; | ||||
|  	struct net_device *dev; | ||||
|  	struct sk_buff *skb2; | ||||
| -	int retval, err; | ||||
| +	int retval, err = 0; | ||||
| +	int m_eaction; | ||||
| +	int mac_len; | ||||
|  	u32 at; | ||||
|   | ||||
|  	tcf_lastuse_update(&m->tcf_tm); | ||||
| @@ -139,6 +163,8 @@ static int tcf_mirred(struct sk_buff *sk | ||||
|  	bstats_cpu_update(this_cpu_ptr(m->common.cpu_bstats), skb); | ||||
|   | ||||
|  	rcu_read_lock(); | ||||
| +	m_mac_header_xmit = READ_ONCE(m->tcfm_mac_header_xmit); | ||||
| +	m_eaction = READ_ONCE(m->tcfm_eaction); | ||||
|  	retval = READ_ONCE(m->tcf_action); | ||||
|  	dev = rcu_dereference(m->tcfm_dev); | ||||
|  	if (unlikely(!dev)) { | ||||
| @@ -157,24 +183,37 @@ static int tcf_mirred(struct sk_buff *sk | ||||
|  	if (!skb2) | ||||
|  		goto out; | ||||
|   | ||||
| -	if (!(at & AT_EGRESS)) { | ||||
| -		if (m->tcfm_mac_header_xmit) | ||||
| +	/* If action's target direction differs than filter's direction, | ||||
| +	 * and devices expect a mac header on xmit, then mac push/pull is | ||||
| +	 * needed. | ||||
| +	 */ | ||||
| +	if (at != tcf_mirred_act_direction(m_eaction) && m_mac_header_xmit) { | ||||
| +		if (at & AT_EGRESS) { | ||||
| +			/* caught at egress, act ingress: pull mac */ | ||||
| +			mac_len = skb_network_header(skb) - skb_mac_header(skb); | ||||
| +			skb_pull_rcsum(skb2, mac_len); | ||||
| +		} else { | ||||
| +			/* caught at ingress, act egress: push mac */ | ||||
|  			skb_push_rcsum(skb2, skb->mac_len); | ||||
| +		} | ||||
|  	} | ||||
|   | ||||
|  	/* mirror is always swallowed */ | ||||
| -	if (m->tcfm_eaction != TCA_EGRESS_MIRROR) | ||||
| +	if (tcf_mirred_is_act_redirect(m_eaction)) | ||||
|  		skb2->tc_verd = SET_TC_FROM(skb2->tc_verd, at); | ||||
|   | ||||
|  	skb2->skb_iif = skb->dev->ifindex; | ||||
|  	skb2->dev = dev; | ||||
|  	skb_sender_cpu_clear(skb2); | ||||
| -	err = dev_queue_xmit(skb2); | ||||
| +	if (tcf_mirred_act_direction(m_eaction) & AT_EGRESS) | ||||
| +		err = dev_queue_xmit(skb2); | ||||
| +	else | ||||
| +		err = netif_receive_skb(skb2); | ||||
|   | ||||
|  	if (err) { | ||||
|  out: | ||||
|  		qstats_overlimit_inc(this_cpu_ptr(m->common.cpu_qstats)); | ||||
| -		if (m->tcfm_eaction != TCA_EGRESS_MIRROR) | ||||
| +		if (tcf_mirred_is_act_redirect(m_eaction)) | ||||
|  			retval = TC_ACT_SHOT; | ||||
|  	} | ||||
|  	rcu_read_unlock(); | ||||
| @@ -1,67 +0,0 @@ | ||||
| # | ||||
| # Copyright (C) 2011 OpenWrt.org | ||||
| # | ||||
| # This is free software, licensed under the GNU General Public License v2. | ||||
| # See /LICENSE for more information. | ||||
| # | ||||
|  | ||||
| include $(TOPDIR)/rules.mk | ||||
|  | ||||
| PKG_NAME:=libprotobuf-c | ||||
| PKG_VERSION:=1.3.1 | ||||
| PKG_RELEASE:=2 | ||||
|  | ||||
| PKG_SOURCE:=protobuf-c-$(PKG_VERSION).tar.gz | ||||
| PKG_SOURCE_URL:=https://github.com/protobuf-c/protobuf-c/releases/download/v$(PKG_VERSION) | ||||
| PKG_HASH:=51472d3a191d6d7b425e32b612e477c06f73fe23e07f6a6a839b11808e9d2267 | ||||
| PKG_BUILD_DIR:=$(BUILD_DIR)/protobuf-c-$(PKG_VERSION) | ||||
| HOST_BUILD_DIR:=$(BUILD_DIR_HOST)/protobuf-c-$(PKG_VERSION) | ||||
|  | ||||
| PKG_MAINTAINER:=Rosen Penev <rosenp@gmail.com> | ||||
| PKG_LICENSE:=BSD-2c | ||||
|  | ||||
| PKG_BUILD_DEPENDS:=protobuf-c/host | ||||
| HOST_BUILD_DEPENDS:=protobuf/host | ||||
|  | ||||
| PKG_INSTALL:=1 | ||||
| PKG_BUILD_PARALLEL:=1 | ||||
|  | ||||
| include $(INCLUDE_DIR)/package.mk | ||||
| include $(INCLUDE_DIR)/host-build.mk | ||||
|  | ||||
| define Package/libprotobuf-c | ||||
|   TITLE:=Protocol Buffers library | ||||
|   SECTION:=libs | ||||
|   CATEGORY:=Libraries | ||||
|   URL:=https://github.com/protobuf-c/protobuf-c | ||||
| endef | ||||
|  | ||||
| define Package/libprotobuf-c/description | ||||
|   Runtime library to use Google Protocol Buffers from C applications. | ||||
|   Protocol Buffers are a way of encoding structured data in an efficient yet | ||||
|   extensible format. Google uses Protocol Buffers for almost all of its | ||||
|   internal RPC protocols and file formats. | ||||
| endef | ||||
|  | ||||
| CONFIGURE_ARGS += \ | ||||
| 	--enable-shared \ | ||||
| 	--enable-static \ | ||||
| 	--disable-protoc | ||||
|  | ||||
| define Build/InstallDev | ||||
| 	$(INSTALL_DIR) $(1)/usr/include/ | ||||
| 	$(CP) $(PKG_INSTALL_DIR)/usr/include/* $(1)/usr/include/ | ||||
| 	$(INSTALL_DIR) $(1)/usr/lib | ||||
| 	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libprotobuf-c.{a,la,so*} $(1)/usr/lib/ | ||||
| 	$(INSTALL_DIR) $(1)/usr/lib/pkgconfig | ||||
| 	$(CP) $(PKG_INSTALL_DIR)/usr/lib/pkgconfig/* $(1)/usr/lib/pkgconfig/ | ||||
| endef | ||||
|  | ||||
| define Package/libprotobuf-c/install | ||||
| 	$(INSTALL_DIR) $(1)/usr/lib | ||||
| 	$(CP) $(PKG_INSTALL_DIR)/usr/lib/libprotobuf-c.so.* $(1)/usr/lib/ | ||||
| endef | ||||
|  | ||||
| $(eval $(call BuildPackage,libprotobuf-c)) | ||||
| $(eval $(call HostBuild)) | ||||
|  | ||||
| @@ -1,13 +0,0 @@ | ||||
| Index: protobuf-c-1.3.1/t/generated-code2/cxx-generate-packed-data.cc | ||||
| =================================================================== | ||||
| --- protobuf-c-1.3.1.orig/t/generated-code2/cxx-generate-packed-data.cc | ||||
| +++ protobuf-c-1.3.1/t/generated-code2/cxx-generate-packed-data.cc | ||||
| @@ -998,7 +998,7 @@ static void dump_test_packed_repeated_en | ||||
|  static void dump_test_unknown_fields (void) | ||||
|  { | ||||
|    EmptyMess mess; | ||||
| -  const google::protobuf::Message::Reflection *reflection = mess.GetReflection(); | ||||
| +  const google::protobuf::Reflection *reflection = mess.GetReflection(); | ||||
|    google::protobuf::UnknownFieldSet *fs = reflection->MutableUnknownFields(&mess); | ||||
|   | ||||
|  #if GOOGLE_PROTOBUF_VERSION >= 2001000 | ||||
| @@ -1,110 +0,0 @@ | ||||
| # | ||||
| # Copyright (C) 2007-2015 OpenWrt.org | ||||
| # | ||||
| # This is free software, licensed under the GNU General Public License v2. | ||||
| # See /LICENSE for more information. | ||||
| # | ||||
|  | ||||
| include $(TOPDIR)/rules.mk | ||||
|  | ||||
| PKG_NAME:=protobuf | ||||
| PKG_VERSION:=3.7.1 | ||||
| PKG_RELEASE:=1 | ||||
|  | ||||
| PKG_SOURCE:=$(PKG_NAME)-cpp-$(PKG_VERSION).tar.gz | ||||
| PKG_SOURCE_URL:=https://github.com/google/protobuf/releases/download/v$(PKG_VERSION) | ||||
| PKG_HASH:=97f6cdaa0724d5a8cd3375d5f5cf4bd253d5ad5291154f533ed0d94a9d501ef3 | ||||
|  | ||||
| PKG_LICENSE:=BSD-3-Clause | ||||
| PKG_LICENSE_FILES:=LICENSE | ||||
| PKG_CPE_ID:=cpe:/a:google:protobuf | ||||
|  | ||||
| PKG_BUILD_DEPENDS:=protobuf/host | ||||
|  | ||||
| PKG_BUILD_PARALLEL:=1 | ||||
| PKG_INSTALL:=1 | ||||
|  | ||||
| include $(INCLUDE_DIR)/package.mk | ||||
| include $(INCLUDE_DIR)/host-build.mk | ||||
|  | ||||
| define Package/protobuf/Default | ||||
|   SECTION:=libs | ||||
|   CATEGORY:=Libraries | ||||
|   TITLE:=A structured data encoding library | ||||
|   URL:=https://github.com/google/protobuf | ||||
|   DEPENDS:=+zlib +libpthread +libatomic +libstdcpp | ||||
|   MAINTAINER:=Ken Keys <kkeys@caida.org> | ||||
| endef | ||||
|  | ||||
| define Package/protobuf | ||||
|   $(call Package/protobuf/Default) | ||||
|   DEPENDS+=+protobuf-lite | ||||
| endef | ||||
|  | ||||
| define Package/protobuf-lite | ||||
|   $(call Package/protobuf/Default) | ||||
| endef | ||||
|  | ||||
| define Package/protobuf/description/Default | ||||
| Protocol Buffers are a way of encoding structured data in an efficient | ||||
| yet extensible format. Google uses Protocol Buffers for almost all | ||||
| of its internal RPC protocols and file formats. | ||||
| endef | ||||
|  | ||||
| define Package/protobuf/description | ||||
| $(call Package/protobuf/description/Default) | ||||
|  | ||||
| This package provides the libprotoc, libprotobuf, and libprotobuf-lite | ||||
| libraries.  For a much smaller protobuf package, see "protobuf-lite". | ||||
|  | ||||
| endef | ||||
|  | ||||
| define Package/protobuf-lite/description | ||||
| $(call Package/protobuf/description/Default) | ||||
|  | ||||
| This package provides the libprotobuf-lite library. | ||||
|  | ||||
| endef | ||||
|  | ||||
| EXTRA_CPPFLAGS+=-std=c++11 | ||||
| CONFIGURE_ARGS += --with-protoc=$(STAGING_DIR_HOSTPKG)/bin/protoc | ||||
|  | ||||
| define Build/InstallDev | ||||
| 	$(INSTALL_DIR) \ | ||||
| 		$(1)/usr/lib \ | ||||
| 		$(1)/usr/include | ||||
|  | ||||
| 	$(CP) \ | ||||
| 		$(PKG_INSTALL_DIR)/usr/include/* \ | ||||
| 		$(1)/usr/include/ | ||||
|  | ||||
| 	$(CP) \ | ||||
| 		$(PKG_INSTALL_DIR)/usr/lib/* \ | ||||
| 		$(1)/usr/lib/ | ||||
| endef | ||||
|  | ||||
| define Package/protobuf-lite/install | ||||
| 	$(INSTALL_DIR) \ | ||||
| 		$(1)/usr/lib | ||||
|  | ||||
| 	$(CP) \ | ||||
| 		$(PKG_INSTALL_DIR)/usr/lib/libprotobuf-lite.so* \ | ||||
| 		$(1)/usr/lib/ | ||||
| endef | ||||
|  | ||||
| define Package/protobuf/install | ||||
| 	$(INSTALL_DIR) \ | ||||
| 		$(1)/usr/lib | ||||
|  | ||||
| 	$(CP) \ | ||||
| 		$(PKG_INSTALL_DIR)/usr/lib/libprotoc.so*  \ | ||||
| 		$(1)/usr/lib/ | ||||
|  | ||||
| 	$(CP) \ | ||||
| 		$(PKG_INSTALL_DIR)/usr/lib/libprotobuf.so* \ | ||||
| 		$(1)/usr/lib/ | ||||
| endef | ||||
|  | ||||
| $(eval $(call BuildPackage,protobuf)) | ||||
| $(eval $(call BuildPackage,protobuf-lite)) | ||||
| $(eval $(call HostBuild)) | ||||
							
								
								
									
										11
									
								
								feeds/ipq807x/qca-nss-drv/patches/200-napi_threaded.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								feeds/ipq807x/qca-nss-drv/patches/200-napi_threaded.patch
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| --- a/nss_hal/nss_hal.c | ||||
| +++ b/nss_hal/nss_hal.c | ||||
| @@ -306,6 +306,8 @@ int nss_hal_probe(struct platform_device | ||||
|  	 * Initialize the dummy netdevice. | ||||
|  	 */ | ||||
|  	init_dummy_netdev(&nss_ctx->napi_ndev); | ||||
| +	strcpy(nss_ctx->napi_ndev.name, "nss"); | ||||
| +	nss_ctx->napi_ndev.threaded = 1; | ||||
|   | ||||
|  	for (i = 0; i < npd->num_irq; i++) { | ||||
|  		err = nss_hal_register_irq(nss_ctx, npd, &nss_ctx->napi_ndev, i); | ||||
							
								
								
									
										55
									
								
								feeds/ipq807x/wireguard/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								feeds/ipq807x/wireguard/Makefile
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,55 @@ | ||||
| # | ||||
| # Copyright (C) 2016-2019 Jason A. Donenfeld <Jason@zx2c4.com> | ||||
| # Copyright (C) 2016 Baptiste Jonglez <openwrt@bitsofnetworks.org> | ||||
| # Copyright (C) 2016-2017 Dan Luedtke <mail@danrl.com> | ||||
| # | ||||
| # This is free software, licensed under the GNU General Public License v2. | ||||
| # See /LICENSE for more information. | ||||
|  | ||||
| include $(TOPDIR)/rules.mk | ||||
| include $(INCLUDE_DIR)/kernel.mk | ||||
|  | ||||
| PKG_NAME:=wireguard-backport | ||||
|  | ||||
| PKG_VERSION:=1.0.20211208 | ||||
| PKG_RELEASE:=1 | ||||
|  | ||||
| PKG_SOURCE:=wireguard-linux-compat-$(PKG_VERSION).tar.xz | ||||
| PKG_SOURCE_URL:=https://git.zx2c4.com/wireguard-linux-compat/snapshot/ | ||||
| PKG_HASH:=c0e607138a17daac656f508d8e63ea3737b5221fa5d9288191ddeb099f5a3b92 | ||||
|  | ||||
| PKG_LICENSE:=GPL-2.0 | ||||
| PKG_LICENSE_FILES:=COPYING | ||||
|  | ||||
| PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/wireguard-linux-compat-$(PKG_VERSION) | ||||
| PKG_BUILD_PARALLEL:=1 | ||||
| PKG_USE_MIPS16:=0 | ||||
|  | ||||
| # WireGuard's makefile needs this to know where to build the kernel module | ||||
| export KERNELDIR:=$(LINUX_DIR) | ||||
|  | ||||
| include $(INCLUDE_DIR)/package.mk | ||||
| include $(INCLUDE_DIR)/kernel-defaults.mk | ||||
| include $(INCLUDE_DIR)/package-defaults.mk | ||||
|  | ||||
| define Build/Compile | ||||
| 	$(MAKE) $(KERNEL_MAKEOPTS) M="$(PKG_BUILD_DIR)/src" modules | ||||
| endef | ||||
|  | ||||
| define KernelPackage/wireguard-backport | ||||
|   SECTION:=kernel | ||||
|   CATEGORY:=Kernel modules | ||||
|   SUBMENU:=Network Support | ||||
|   TITLE:=WireGuard kernel module | ||||
|   DEPENDS:=+IPV6:kmod-udptunnel6 +kmod-udptunnel4 | ||||
|   FILES:= $(PKG_BUILD_DIR)/src/wireguard.$(LINUX_KMOD_SUFFIX) | ||||
|   AUTOLOAD:=$(call AutoProbe,wireguard) | ||||
| endef | ||||
|  | ||||
| define KernelPackage/wireguard-backport/description | ||||
|   $(call Package/wireguard/Default/description) | ||||
|  | ||||
|   This package provides the kernel module for WireGuard. | ||||
| endef | ||||
|  | ||||
| $(eval $(call KernelPackage,wireguard-backport)) | ||||
							
								
								
									
										29
									
								
								feeds/ipq807x/wireguard/patches/100-compat.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								feeds/ipq807x/wireguard/patches/100-compat.patch
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| Index: wireguard-linux-compat-1.0.20211208/src/compat/compat.h | ||||
| =================================================================== | ||||
| --- wireguard-linux-compat-1.0.20211208.orig/src/compat/compat.h | ||||
| +++ wireguard-linux-compat-1.0.20211208/src/compat/compat.h | ||||
| @@ -11,6 +11,8 @@ | ||||
|  #include <linux/types.h> | ||||
|  #include <generated/utsrelease.h> | ||||
|   | ||||
| +#define fallthrough | ||||
| + | ||||
|  #ifdef RHEL_MAJOR | ||||
|  #if RHEL_MAJOR == 7 | ||||
|  #define ISRHEL7 | ||||
| @@ -686,15 +688,6 @@ struct __compat_dummy_container { char d | ||||
|  #define genl_dump_check_consistent(a, b) genl_dump_check_consistent(a, b, &genl_family) | ||||
|  #endif | ||||
|   | ||||
| -#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0) && !defined(ISRHEL7) | ||||
| -static inline void *skb_put_data(struct sk_buff *skb, const void *data, unsigned int len) | ||||
| -{ | ||||
| -	void *tmp = skb_put(skb, len); | ||||
| -	memcpy(tmp, data, len); | ||||
| -	return tmp; | ||||
| -} | ||||
| -#endif | ||||
| - | ||||
|  #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0) && !defined(ISRHEL7) | ||||
|  #define napi_complete_done(n, work_done) napi_complete(n) | ||||
|  #endif | ||||
| @@ -2,6 +2,17 @@ | ||||
|  | ||||
| START=80 | ||||
|  | ||||
| copy_certificates() { | ||||
| 	[ -f /certificates/dev-id ] || return | ||||
|  | ||||
| 	cp /certificates/*.pem /etc/ucentral/ | ||||
| 	cp /certificates/dev-id /etc/ucentral/ | ||||
| 	chown root.network /etc/ucentral/*.pem | ||||
| 	chmod 0440 root.network /etc/ucentral/*.pem | ||||
| 	chmod 0400 /etc/ucentral/dev-id | ||||
| 	exit 0 | ||||
| } | ||||
|  | ||||
| boot() { | ||||
| 	[ -f /etc/ucentral/dev-id ] && return | ||||
| 	. /lib/functions.sh | ||||
| @@ -17,11 +28,49 @@ boot() { | ||||
| 			[ -e /dev/ubi1 ] && mount -t ubifs ubi1:certificates /certificates | ||||
| 		fi | ||||
| 	fi | ||||
| 	[ -f /certificates/dev-id ] && { | ||||
| 		cp /certificates/*.pem /etc/ucentral/ | ||||
| 		cp /certificates/dev-id /etc/ucentral/ | ||||
| 		chown root.network /etc/ucentral/*.pem  | ||||
| 		chmod 0440 root.network /etc/ucentral/*.pem | ||||
| 		chmod 0400 /etc/ucentral/dev-id | ||||
| 	} | ||||
| 	copy_certificates | ||||
|  | ||||
| 	# if we get here no valid certificates were found | ||||
|  | ||||
| 	. /lib/functions.sh | ||||
|  | ||||
| 	local PART_NAME | ||||
|  | ||||
| 	case "$(board_name)" in | ||||
| 	actiontec,web7200) | ||||
| 		if grep -q bootselect=0 /proc/cmdline; then | ||||
| 			PART_NAME=firmware2 | ||||
| 		else | ||||
| 			PART_NAME=firmware1 | ||||
| 		fi | ||||
| 		;; | ||||
| 	edgecore,ecw5211|\ | ||||
| 	edgecore,eap101|\ | ||||
| 	edgecore,eap102) | ||||
| 		if grep -q rootfs1 /proc/cmdline; then | ||||
| 			PART_NAME=rootfs2 | ||||
| 		else | ||||
| 			PART_NAME=rootfs1 | ||||
| 		fi	 | ||||
| 		;; | ||||
| 	hfcl,ion4xi|\ | ||||
| 	hfcl,ion4xe) | ||||
| 		if grep -q rootfs_1 /proc/cmdline; then | ||||
| 			PART_NAME=rootfs | ||||
| 		else | ||||
| 			PART_NAME=rootfs_1 | ||||
| 		fi	 | ||||
| 		;; | ||||
| 	*) | ||||
| 		return 1 | ||||
| 		;; | ||||
| 	esac | ||||
|  | ||||
| 	local MTD=$(find_mtd_index $PART_NAME) | ||||
|  | ||||
| 	[ -z "$MTD" ] && return 1 | ||||
|  | ||||
| 	ubiattach -m $MTD -d 3 | ||||
| 	[ -e /dev/ubi3 ] && mount -t ubifs ubi3:certificates /certificates | ||||
| 	copy_certificates | ||||
| } | ||||
|   | ||||
| @@ -8,7 +8,7 @@ generate_certificate_volume() { | ||||
| 	ubinfo /dev/ubi0 -N certificates > /dev/null | ||||
| 	[ $? -eq 0 ] || { | ||||
| 		ubirsvol /dev/ubi0 -N rootfs_data -s 20MiB | ||||
| 		ubimkvol /dev/ubi0 -N certificates -s 2MiB | ||||
| 		ubimkvol /dev/ubi0 -N certificates -S 20 | ||||
| 	} | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -8,13 +8,13 @@ PROG=/usr/bin/ucode | ||||
| start_service() { | ||||
| 	[ -f /etc/ucentral/capabilities.json ] || { | ||||
| 		mkdir -p /etc/ucentral/ | ||||
| 		ucode -m ubus -E board=/etc/board.json /usr/share/ucentral/capabilities.uc > /etc/ucentral/capabilities.json  | ||||
| 		/usr/share/ucentral/capabilities.uc | ||||
| 	} | ||||
|  | ||||
| 	/usr/share/ucentral/ucentral.uc /etc/ucentral/ucentral.cfg.0000000001 > /dev/null | ||||
|  | ||||
| 	procd_open_instance | ||||
| 	procd_set_param command "$PROG" -m uci -m fs -i /usr/share/ucentral/firstcontact.uc | ||||
| 	procd_set_param command "$PROG" -l uci -l fs /usr/share/ucentral/firstcontact.uc | ||||
| 	procd_set_param respawn 1 10 0 | ||||
| 	procd_close_instance | ||||
| } | ||||
|   | ||||
| @@ -1,4 +1,3 @@ | ||||
| {% | ||||
| let devid; | ||||
| let fd = fs.open("/etc/ucentral/dev-id", "r"); | ||||
| if (!fd) { | ||||
| @@ -62,4 +61,3 @@ system("/etc/init.d/firstcontact disable"); | ||||
| system("reload_config"); | ||||
| system("/etc/init.d/ucentral start"); | ||||
| system("/etc/init.d/firstcontact stop"); | ||||
| %} | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| # | ||||
| # Copyright (C) 2008-2012 OpenWrt.org | ||||
| # Copyright (C) 2021 OpenWrt.org | ||||
| # | ||||
| # This is free software, licensed under the GNU General Public License v2. | ||||
| # See /LICENSE for more information. | ||||
| @@ -9,26 +9,31 @@ include $(TOPDIR)/rules.mk | ||||
| include $(INCLUDE_DIR)/kernel.mk | ||||
|  | ||||
| PKG_NAME:=qosify | ||||
| PKG_RELEASE:=1 | ||||
| PKG_SOURCE_URL=$(PROJECT_GIT)/project/qosify.git | ||||
| PKG_SOURCE_PROTO:=git | ||||
| PKG_SOURCE_DATE:=2022-03-06 | ||||
| PKG_SOURCE_VERSION:=f13b67c9a786567df240a8f3f608e2724ddaadba | ||||
| PKG_MIRROR_HASH:=3d8629e711e46a6be79a46a6394165fd1761687f24b8ed954dc4f16f177cd90f | ||||
| PKG_RELEASE:=$(AUTORELEASE) | ||||
|  | ||||
| PKG_LICENSE:=GPL-2.0 | ||||
| PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name> | ||||
|  | ||||
| PKG_BUILD_DEPENDS:=bpf-headers | ||||
| PKG_FLAGS:=nonshared | ||||
|  | ||||
| include $(INCLUDE_DIR)/package.mk | ||||
| include $(INCLUDE_DIR)/cmake.mk | ||||
| include $(INCLUDE_DIR)/bpf.mk | ||||
| include $(INCLUDE_DIR)/nls.mk | ||||
|  | ||||
| define Package/qosify | ||||
|   SECTION:=kernel | ||||
|   CATEGORY:=Kernel modules | ||||
|   SUBMENU:=Network Support | ||||
|   TITLE:=QoS classifier eBPF module | ||||
|   DEPENDS:=+libbpf +libubox +libubus +kmod-sched-cake +tc-full | ||||
|   PKGFLAGS+=nonshared | ||||
|   SECTION:=utils | ||||
|   CATEGORY:=Base system | ||||
|   TITLE:=A simple QoS solution based eBPF + CAKE | ||||
|   DEPENDS:=+libbpf +libubox +libubus +kmod-sched-cake +kmod-sched-bpf +kmod-ifb +tc-full $(BPF_DEPENDS) | ||||
| endef | ||||
|  | ||||
| BPF_DOC = $(wildcard $(patsubst %,$(BPF_HEADERS_DIR)/scripts/%.py,bpf_doc bpf_helpers_doc)) | ||||
|  | ||||
| define Build/Compile | ||||
| 	$(call CompileBPF,$(PKG_BUILD_DIR)/qosify-bpf.c) | ||||
| 	$(Build/Compile/Default) | ||||
| @@ -36,17 +41,28 @@ endef | ||||
|  | ||||
| define Package/qosify/conffiles | ||||
| /etc/config/qosify | ||||
| /etc/qosify-defaults.conf | ||||
| /etc/qosify/00-defaults.conf | ||||
| endef | ||||
|  | ||||
| define Package/qosify/install | ||||
| 	$(INSTALL_DIR) $(1)/lib/bpf $(1)/usr/sbin $(1)/etc/init.d $(1)/etc/config $(1)/etc/hotplug.d/net | ||||
| 	$(INSTALL_DIR) \ | ||||
| 		$(1)/lib/bpf \ | ||||
| 		$(1)/usr/sbin \ | ||||
| 		$(1)/etc/init.d \ | ||||
| 		$(1)/etc/config \ | ||||
| 		$(1)/etc/qosify \ | ||||
| 		$(1)/etc/hotplug.d/net \ | ||||
| 		$(1)/etc/hotplug.d/iface | ||||
| 	$(INSTALL_DATA) $(PKG_BUILD_DIR)/qosify-bpf.o $(1)/lib/bpf | ||||
| 	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/qosify $(1)/usr/sbin/ | ||||
| 	$(INSTALL_BIN) \ | ||||
| 		$(PKG_INSTALL_DIR)/usr/bin/qosify \ | ||||
| 		./files/qosify-status \ | ||||
| 		$(1)/usr/sbin/ | ||||
| 	$(INSTALL_BIN) ./files/qosify.init $(1)/etc/init.d/qosify | ||||
| 	$(INSTALL_DATA) ./files/qosify-defaults.conf $(1)/etc/qosify-defaults.conf | ||||
| 	$(INSTALL_DATA) ./files/qosify-defaults.conf $(1)/etc/qosify/00-defaults.conf | ||||
| 	$(INSTALL_DATA) ./files/qosify.conf $(1)/etc/config/qosify | ||||
| 	$(INSTALL_DATA) ./files/qosify.hotplug $(1)/etc/hotplug.d/net/10-qosify | ||||
| 	$(INSTALL_DATA) ./files/qosify.hotplug $(1)/etc/hotplug.d/iface/10-qosify | ||||
| endef | ||||
|  | ||||
| $(eval $(call BuildPackage,qosify)) | ||||
|   | ||||
										
											Binary file not shown.
										
									
								
							| @@ -1,17 +1,17 @@ | ||||
| # DNS | ||||
| tcp:53		CS5 | ||||
| tcp:5353	CS5 | ||||
| udp:53		CS5 | ||||
| udp:5353	CS5 | ||||
| tcp:53		voice | ||||
| tcp:5353	voice | ||||
| udp:53		voice | ||||
| udp:5353	voice | ||||
|  | ||||
| # NTP | ||||
| udp:123		CS6 | ||||
| udp:123		voice | ||||
|  | ||||
| # SSH | ||||
| tcp:22		+CS4 | ||||
| tcp:22		+video | ||||
|  | ||||
| # HTTP/QUIC | ||||
| tcp:80		+CS3 | ||||
| tcp:443		+CS3 | ||||
| udp:80		+CS3 | ||||
| udp:443		+CS3 | ||||
| tcp:80		+besteffort | ||||
| tcp:443		+besteffort | ||||
| udp:80		+besteffort | ||||
| udp:443		+besteffort | ||||
|   | ||||
							
								
								
									
										70
									
								
								feeds/ucentral/qosify/files/qosify-status
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								feeds/ucentral/qosify/files/qosify-status
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,70 @@ | ||||
| #!/bin/sh | ||||
| . /usr/share/libubox/jshn.sh | ||||
|  | ||||
| dev_status() { | ||||
| 	tc -s qdisc sh dev "$1" root | ||||
| 	echo | ||||
| } | ||||
|  | ||||
| common_status() { | ||||
| 	json_get_vars ifname ingress egress | ||||
|  | ||||
| 	[ -n "$ifname" ] || return | ||||
|  | ||||
| 	[ "$egress" -gt 0 ] && { | ||||
| 		echo "egress status:" | ||||
| 		dev_status "$ifname" | ||||
| 	} | ||||
| 	[ "$ingress" -gt 0 ] && { | ||||
| 		echo "ingress status:" | ||||
| 		dev_status "$(printf %.16s "ifb-$ifname")" | ||||
| 	} | ||||
| } | ||||
|  | ||||
| is_active() { | ||||
| 	json_get_vars active | ||||
|  | ||||
| 	[ "${active:-0}" -gt 0 ] | ||||
| } | ||||
|  | ||||
| device_status() { | ||||
| 	local name="$2" | ||||
|  | ||||
| 	json_select "$name" | ||||
|  | ||||
| 	if is_active; then | ||||
| 		status="active" | ||||
| 	else | ||||
| 		status="not found" | ||||
| 	fi | ||||
|  | ||||
| 	echo "===== device $name: $status =====" | ||||
|  | ||||
| 	is_active && common_status | ||||
|  | ||||
| 	json_select .. | ||||
| } | ||||
|  | ||||
| interface_status() { | ||||
| 	local name="$2" | ||||
|  | ||||
| 	json_select "$name" | ||||
|  | ||||
| 	if is_active; then | ||||
| 		status="active" | ||||
| 	elif ubus -S -t 0 wait_for "network.interface.$name"; then | ||||
| 		status="down" | ||||
| 	else | ||||
| 		status="not found" | ||||
| 	fi | ||||
|  | ||||
| 	echo "===== interface $name: $status =====" | ||||
|  | ||||
| 	is_active && common_status | ||||
|  | ||||
| 	json_select .. | ||||
| } | ||||
|  | ||||
| json_load "$(ubus call qosify status)" | ||||
| json_for_each_item device_status devices | ||||
| json_for_each_item interface_status interfaces | ||||
| @@ -1,24 +1,42 @@ | ||||
| config defaults | ||||
| 	list defaults /etc/qosify-defaults.conf | ||||
| 	option dscp_prio CS5 | ||||
| 	option dscp_icmp CS6 | ||||
| 	option dscp_bulk CS0 | ||||
| 	option dscp_default_udp	CS4 | ||||
| 	option bulk_trigger_timeout 5 | ||||
| 	option bulk_trigger_pps	100 | ||||
| 	list defaults /etc/qosify/*.conf | ||||
| 	option dscp_prio video | ||||
| 	option dscp_icmp +besteffort | ||||
| 	option dscp_default_udp besteffort | ||||
| 	option prio_max_avg_pkt_len 500 | ||||
|  | ||||
| config class besteffort | ||||
| 	option ingress CS0 | ||||
| 	option egress CS0 | ||||
|  | ||||
| config class bulk | ||||
| 	option ingress LE | ||||
| 	option egress LE | ||||
|  | ||||
| config class video | ||||
| 	option ingress AF41 | ||||
| 	option egress AF41 | ||||
|  | ||||
| config class voice | ||||
| 	option ingress CS6 | ||||
| 	option egress CS6 | ||||
| 	option bulk_trigger_pps 100 | ||||
| 	option bulk_trigger_timeout 5 | ||||
| 	option dscp_bulk CS0 | ||||
|  | ||||
| config interface wan | ||||
| 	option name wan | ||||
| 	option disabled 1 | ||||
| 	option bandwidth_up 100mbit | ||||
| 	option bandwidth_down 100mbit | ||||
| 	option overhead_type none | ||||
| 	# defaults: | ||||
| 	option ingress 1 | ||||
| 	option egress 1 | ||||
| 	option mode diffserv4 | ||||
| 	option nat 1 | ||||
| 	option host_isolate 1 | ||||
| 	option autorate_ingress 1 | ||||
| 	option autorate_ingress 0 | ||||
| 	option ingress_options "" | ||||
| 	option egress_options "" | ||||
| 	option options "" | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| #!/bin/sh /etc/rc.common | ||||
| # Copyright (c) 2014 OpenWrt.org | ||||
| # Copyright (c) 2021 OpenWrt.org | ||||
|  | ||||
| START=19 | ||||
|  | ||||
| @@ -15,6 +15,16 @@ add_option() { | ||||
| 	[ -n "$val" ] && json_add_$type "$name" "$val" | ||||
| } | ||||
|  | ||||
| add_flow_config() { | ||||
| 	local cfg="$1" | ||||
|  | ||||
| 	add_option string dscp_prio | ||||
| 	add_option string dscp_bulk | ||||
| 	add_option int bulk_trigger_timeout | ||||
| 	add_option int bulk_trigger_pps | ||||
| 	add_option int prio_max_avg_pkt_len | ||||
| } | ||||
|  | ||||
| add_defaults() { | ||||
| 	cfg="$1" | ||||
|  | ||||
| @@ -27,15 +37,11 @@ add_defaults() { | ||||
| 	done | ||||
| 	json_close_array | ||||
|  | ||||
| 	add_flow_config "$cfg" | ||||
| 	add_option int timeout | ||||
| 	add_option string dscp_prio | ||||
| 	add_option string dscp_bulk | ||||
| 	add_option string dscp_icmp | ||||
| 	add_option string dscp_default_udp | ||||
| 	add_option string dscp_default_tcp | ||||
| 	add_option int bulk_trigger_timeout  | ||||
| 	add_option int bulk_trigger_pps | ||||
| 	add_option int prio_max_avg_pkt_len | ||||
| } | ||||
|  | ||||
| add_interface() { | ||||
| @@ -57,19 +63,74 @@ add_interface() { | ||||
| 	bw_down="${bw_down:-$bw}" | ||||
| 	[ -n "$bw_down" ] && json_add_string bandwidth_down "$bw_down" | ||||
|  | ||||
| 	add_option string bandwidth  | ||||
| 	add_option string bandwidth | ||||
| 	add_option boolean ingress | ||||
| 	add_option boolean egress | ||||
| 	add_option string mode | ||||
| 	add_option boolean host_isolate  | ||||
| 	add_option boolean nat | ||||
| 	add_option boolean host_isolate | ||||
| 	add_option boolean autorate_ingress | ||||
| 	add_option string ingress_options | ||||
| 	add_option string egress_options | ||||
| 	add_option string options | ||||
|  | ||||
| 	config_get user_options "$cfg" options | ||||
|  | ||||
| 	config_get otype "$cfg" overhead_type | ||||
| 	options= | ||||
| 	case "$otype" in | ||||
| 		none);; | ||||
| 		manual) | ||||
| 			config_get overhead "$cfg" overhead | ||||
| 			[ -n "$overhead" ] && append options "overhead $overhead" | ||||
|  | ||||
| 			config_get encap "$cfg" overhead_encap | ||||
| 			[ -n "$encap" ] && append options "$encap" | ||||
| 		;; | ||||
| 		conservative|\ | ||||
| 		pppoa-vcmux|\ | ||||
| 		pppoa-llc|\ | ||||
| 		pppoe-vcmux|\ | ||||
| 		pppoe-llcsnap|\ | ||||
| 		bridged-vcmux|\ | ||||
| 		bridged-llcsnap|\ | ||||
| 		ipoa-vcmux|\ | ||||
| 		ipoa-llcsnap|\ | ||||
| 		pppoe-ptm|\ | ||||
| 		bridged-ptm|\ | ||||
| 		docsis|\ | ||||
| 		ethernet) | ||||
| 			append options "$otype" | ||||
| 		;; | ||||
| 	esac | ||||
|  | ||||
| 	config_get mpu "$cfg" overhead_mpu | ||||
| 	[ -n "$mpu" ] && append options "mpu $mpu" | ||||
|  | ||||
| 	config_get ovlan "$cfg" overhead_vlan | ||||
| 	[ "${ovlan:-0}" -ge 2 ] && append options "ether-vlan" | ||||
| 	[ "${ovlan:-0}" -ge 1 ] && append options "ether-vlan" | ||||
|  | ||||
| 	[ -n "$user_options" ] && append options "$user_options" | ||||
| 	[ -n "$options" ] && json_add_string options "$options" | ||||
|  | ||||
| 	json_close_object | ||||
| } | ||||
|  | ||||
| add_class() { | ||||
| 	local cfg="$1" | ||||
|  | ||||
| 	config_get value "$cfg" value | ||||
| 	config_get ingress "$cfg" ingress | ||||
| 	config_get egress "$cfg" egress | ||||
|  | ||||
| 	json_add_object "$cfg" | ||||
| 	json_add_string ingress "${ingress:-$value}" | ||||
| 	json_add_string egress "${egress:-$value}" | ||||
| 	add_flow_config "$cfg" | ||||
| 	json_close_object | ||||
| } | ||||
|  | ||||
|  | ||||
| reload_service() { | ||||
| 	json_init | ||||
|  | ||||
| @@ -81,6 +142,11 @@ reload_service() { | ||||
| 	config_foreach add_interface interface | ||||
| 	json_close_object | ||||
|  | ||||
| 	json_add_object classes | ||||
| 	config_foreach add_class class | ||||
| 	config_foreach add_class alias | ||||
| 	json_close_object | ||||
|  | ||||
| 	json_add_object devices | ||||
| 	config_foreach add_interface device | ||||
| 	json_close_object | ||||
|   | ||||
| @@ -1,15 +0,0 @@ | ||||
| cmake_minimum_required(VERSION 3.10) | ||||
|  | ||||
| PROJECT(qosify C) | ||||
|  | ||||
| ADD_DEFINITIONS(-Os -Wall -Wno-unknown-warning-option -Wno-array-bounds -Wno-format-truncation -Werror --std=gnu99) | ||||
|  | ||||
| SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") | ||||
|  | ||||
| find_library(bpf NAMES bpf) | ||||
| ADD_EXECUTABLE(qosify main.c loader.c map.c ubus.c interface.c) | ||||
| TARGET_LINK_LIBRARIES(qosify ${bpf} ubox ubus) | ||||
|  | ||||
| INSTALL(TARGETS qosify | ||||
| 	RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR} | ||||
| ) | ||||
| @@ -1,112 +0,0 @@ | ||||
| QoSify is simple daemon for setting up and managing CAKE along with a custom | ||||
| eBPF based classifier that sets DSCP fields of packets. | ||||
|  | ||||
| It supports the following features: | ||||
| - simple TCP/UDP port based mapping | ||||
| - IP address based mapping | ||||
| - priority boosting based on average packet size | ||||
| - bulk flow detection based on number of packets per second | ||||
| - dynamically add IP entries with timeout | ||||
| - dns regex entries and ubus api for providing dns lookup results | ||||
|  | ||||
| It can be configured via ubus call qosify config. | ||||
|  | ||||
| This call supports the following parameters: | ||||
| - "reset": BOOL | ||||
| 	Reset the config to defaults instead of only updating supplied values | ||||
|  | ||||
| - "files": ARRAY of STRING | ||||
| 	List of files with port/IP/host mappings | ||||
|  | ||||
| - "timeout": INT32 | ||||
| 	Default timeout for dynamically added entries | ||||
|  | ||||
| - "dscp_default_udp": STRING | ||||
| 	Default DSCP value for UDP packets | ||||
|  | ||||
| - "dscp_default_tcp": STRING | ||||
| 	Default DSCP value for TCP packets | ||||
|  | ||||
| - "dscp_prio": STRING | ||||
| 	DSCP value for priority-marked packets | ||||
|  | ||||
| - "dscp_bulk": STRING | ||||
| 	DSCP value for bulk-marked packets | ||||
|  | ||||
| - "dscp_icmp": STRING | ||||
| 	DSCP value for ICMP packets | ||||
|  | ||||
| - "bulk_trigger_pps": INT32 | ||||
| 	Number of packets per second to trigger bulk flow detection | ||||
|  | ||||
| - "bulk_trigger_timeout": INT32 | ||||
| 	Time below bulk_trigger_pps threshold until a bulk flow mark is removed | ||||
|  | ||||
| - "prio_max_avg_pkt_len": INT32 | ||||
| 	Maximum average packet length for marking a flow as priority | ||||
|  | ||||
| - "interfaces": TABLE of TABLE | ||||
| 	netifd interfaces to enable QoS on | ||||
|  | ||||
| - "devices": TABLE of TABLE | ||||
| 	netdevs to enable QoS on | ||||
|  | ||||
|  | ||||
| interface/device properties: | ||||
| - "bandwidth_up": STRING | ||||
| 	Uplink bandwidth (same format as tc) | ||||
|  | ||||
| - "bandwidth_down": STRING | ||||
| 	Downlink bandwidth (same format as tc) | ||||
|  | ||||
| - "ingress": BOOL | ||||
| 	Enable ingress shaping | ||||
|  | ||||
| - "egress": BOOL | ||||
| 	Enable egress shaping | ||||
|  | ||||
| - "mode": STRING | ||||
| 	CAKE diffserv mode | ||||
|  | ||||
| - "nat": BOOL | ||||
| 	Enable CAKE NAT host detection via conntrack | ||||
|  | ||||
| - "host_isolate": BOOL | ||||
| 	Enable CAKE host isolation | ||||
|  | ||||
| - "autorate_ingress": BOOL | ||||
| 	Enable CAKE automatic rate estimation for ingress | ||||
|  | ||||
| - "ingress_options": STRING | ||||
| 	CAKE ingress options | ||||
|  | ||||
| - "egress_options": STRING | ||||
| 	CAKE egress options | ||||
|  | ||||
| - "options": STRING | ||||
| 	CAKE options for ingress + egress | ||||
|  | ||||
|  | ||||
| Mapping file syntax: | ||||
|  | ||||
| Each line has two whitespace separated fields, match and dscp | ||||
| match is one of: | ||||
| - tcp:<port>[-<endport>] | ||||
| 	TCP single port, or range from <port> to <endport> | ||||
| - udp:<port>[-<endport>] | ||||
| 	UDP single port, or range from <port> to <endport> | ||||
| - <ipaddr> | ||||
| 	IPv4 address, e.g. 1.1.1.1 | ||||
| - <ipv6addr> | ||||
| 	IPv6 address, e.g. ff01::1 | ||||
| - dns:<regex> | ||||
| 	POSIX.2 extended regular expression for matching hostnames | ||||
| 	Only works, if dns lookups are passed to qosify via the add_dns_host ubus call. | ||||
|  | ||||
| dscp can be a raw value, or a codepoint like CS0 | ||||
| Adding a + in front of the value tells qosify to only override the DSCP value if it is zero | ||||
|  | ||||
|  | ||||
| Planned features: | ||||
| - Integration with dnsmasq to support hostname pattern based DSCP marking | ||||
| - Support for LAN host based priority | ||||
| @@ -1,563 +0,0 @@ | ||||
| // SPDX-License-Identifier: GPL-2.0+ | ||||
| /* | ||||
|  * Copyright (C) 2021 Felix Fietkau <nbd@nbd.name> | ||||
|  */ | ||||
| #include <sys/types.h> | ||||
| #include <sys/socket.h> | ||||
| #include <sys/wait.h> | ||||
| #include <sys/ioctl.h> | ||||
| #include <net/if_arp.h> | ||||
| #include <net/if.h> | ||||
|  | ||||
| #include <unistd.h> | ||||
| #include <errno.h> | ||||
|  | ||||
| #include <libubox/vlist.h> | ||||
| #include <libubox/avl-cmp.h> | ||||
| #include <libubox/uloop.h> | ||||
|  | ||||
| #include "qosify.h" | ||||
|  | ||||
| static void interface_update_cb(struct vlist_tree *tree, | ||||
| 				struct vlist_node *node_new, | ||||
| 				struct vlist_node *node_old); | ||||
|  | ||||
| static VLIST_TREE(devices, avl_strcmp, interface_update_cb, true, false); | ||||
| static VLIST_TREE(interfaces, avl_strcmp, interface_update_cb, true, false); | ||||
| static int socket_fd; | ||||
|  | ||||
| #define APPEND(_buf, _ofs, _format, ...) _ofs += snprintf(_buf + _ofs, sizeof(_buf) - _ofs, _format, ##__VA_ARGS__) | ||||
|  | ||||
| struct qosify_iface_config { | ||||
| 	struct blob_attr *data; | ||||
|  | ||||
| 	bool ingress; | ||||
| 	bool egress; | ||||
| 	bool nat; | ||||
| 	bool host_isolate; | ||||
| 	bool autorate_ingress; | ||||
|  | ||||
| 	const char *bandwidth_up; | ||||
| 	const char *bandwidth_down; | ||||
| 	const char *mode; | ||||
| 	const char *common_opts; | ||||
| 	const char *ingress_opts; | ||||
| 	const char *egress_opts; | ||||
| }; | ||||
|  | ||||
|  | ||||
| struct qosify_iface { | ||||
| 	struct vlist_node node; | ||||
|  | ||||
| 	char ifname[IFNAMSIZ]; | ||||
| 	bool active; | ||||
|  | ||||
| 	bool device; | ||||
| 	struct blob_attr *config_data; | ||||
| 	struct qosify_iface_config config; | ||||
| }; | ||||
|  | ||||
| enum { | ||||
| 	IFACE_ATTR_BW_UP, | ||||
| 	IFACE_ATTR_BW_DOWN, | ||||
| 	IFACE_ATTR_INGRESS, | ||||
| 	IFACE_ATTR_EGRESS, | ||||
| 	IFACE_ATTR_MODE, | ||||
| 	IFACE_ATTR_NAT, | ||||
| 	IFACE_ATTR_HOST_ISOLATE, | ||||
| 	IFACE_ATTR_AUTORATE_IN, | ||||
| 	IFACE_ATTR_INGRESS_OPTS, | ||||
| 	IFACE_ATTR_EGRESS_OPTS, | ||||
| 	IFACE_ATTR_OPTS, | ||||
| 	__IFACE_ATTR_MAX | ||||
| }; | ||||
|  | ||||
| static inline const char *qosify_iface_name(struct qosify_iface *iface) | ||||
| { | ||||
| 	return iface->node.avl.key; | ||||
| } | ||||
|  | ||||
| static void | ||||
| iface_config_parse(struct blob_attr *attr, struct blob_attr **tb) | ||||
| { | ||||
| 	static const struct blobmsg_policy policy[__IFACE_ATTR_MAX] = { | ||||
| 		[IFACE_ATTR_BW_UP] = { "bandwidth_up", BLOBMSG_TYPE_STRING }, | ||||
| 		[IFACE_ATTR_BW_DOWN] = { "bandwidth_down", BLOBMSG_TYPE_STRING }, | ||||
| 		[IFACE_ATTR_INGRESS] = { "ingress", BLOBMSG_TYPE_BOOL }, | ||||
| 		[IFACE_ATTR_EGRESS] = { "egress", BLOBMSG_TYPE_BOOL }, | ||||
| 		[IFACE_ATTR_MODE] = { "mode", BLOBMSG_TYPE_STRING }, | ||||
| 		[IFACE_ATTR_NAT] = { "nat", BLOBMSG_TYPE_BOOL }, | ||||
| 		[IFACE_ATTR_HOST_ISOLATE] = { "host_isolate", BLOBMSG_TYPE_BOOL }, | ||||
| 		[IFACE_ATTR_AUTORATE_IN] = { "autorate_ingress", BLOBMSG_TYPE_BOOL }, | ||||
| 		[IFACE_ATTR_INGRESS_OPTS] = { "ingress_options", BLOBMSG_TYPE_STRING }, | ||||
| 		[IFACE_ATTR_EGRESS_OPTS] = { "egress_options", BLOBMSG_TYPE_STRING }, | ||||
| 		[IFACE_ATTR_OPTS] = { "options", BLOBMSG_TYPE_STRING }, | ||||
| 	}; | ||||
|  | ||||
| 	blobmsg_parse(policy, __IFACE_ATTR_MAX, tb, blobmsg_data(attr), blobmsg_len(attr)); | ||||
| } | ||||
|  | ||||
| static bool | ||||
| iface_config_equal(struct qosify_iface *if1, struct qosify_iface *if2) | ||||
| { | ||||
| 	struct blob_attr *tb1[__IFACE_ATTR_MAX], *tb2[__IFACE_ATTR_MAX]; | ||||
| 	int i; | ||||
|  | ||||
| 	iface_config_parse(if1->config_data, tb1); | ||||
| 	iface_config_parse(if2->config_data, tb2); | ||||
|  | ||||
| 	for (i = 0; i < __IFACE_ATTR_MAX; i++) { | ||||
| 		if (!!tb1[i] != !!tb2[i]) | ||||
| 			return false; | ||||
|  | ||||
| 		if (!tb1[i]) | ||||
| 			continue; | ||||
|  | ||||
| 		if (blob_raw_len(tb1[i]) != blob_raw_len(tb2[i])) | ||||
| 			return false; | ||||
|  | ||||
| 		if (memcmp(tb1[i], tb2[i], blob_raw_len(tb1[i])) != 0) | ||||
| 			return false; | ||||
| 	} | ||||
|  | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| static const char *check_str(struct blob_attr *attr) | ||||
| { | ||||
| 	const char *str = blobmsg_get_string(attr); | ||||
|  | ||||
| 	if (strchr(str, '\'')) | ||||
| 		return NULL; | ||||
|  | ||||
| 	return str; | ||||
| } | ||||
|  | ||||
| static void | ||||
| iface_config_set(struct qosify_iface *iface, struct blob_attr *attr) | ||||
| { | ||||
| 	struct qosify_iface_config *cfg = &iface->config; | ||||
| 	struct blob_attr *tb[__IFACE_ATTR_MAX]; | ||||
| 	struct blob_attr *cur; | ||||
|  | ||||
| 	iface_config_parse(attr, tb); | ||||
|  | ||||
| 	memset(cfg, 0, sizeof(*cfg)); | ||||
|  | ||||
| 	/* defaults */ | ||||
| 	cfg->mode = "diffserv4"; | ||||
| 	cfg->ingress = true; | ||||
| 	cfg->egress = true; | ||||
| 	cfg->host_isolate = true; | ||||
| 	cfg->autorate_ingress = true; | ||||
| 	cfg->nat = !iface->device; | ||||
|  | ||||
| 	if ((cur = tb[IFACE_ATTR_BW_UP]) != NULL) | ||||
| 		cfg->bandwidth_up = check_str(cur); | ||||
| 	if ((cur = tb[IFACE_ATTR_BW_DOWN]) != NULL) | ||||
| 		cfg->bandwidth_down = check_str(cur); | ||||
| 	if ((cur = tb[IFACE_ATTR_MODE]) != NULL) | ||||
| 		cfg->mode = check_str(cur); | ||||
| 	if ((cur = tb[IFACE_ATTR_OPTS]) != NULL) | ||||
| 		cfg->common_opts = check_str(cur); | ||||
| 	if ((cur = tb[IFACE_ATTR_EGRESS_OPTS]) != NULL) | ||||
| 		cfg->egress_opts = check_str(cur); | ||||
| 	if ((cur = tb[IFACE_ATTR_INGRESS_OPTS]) != NULL) | ||||
| 		cfg->ingress_opts = check_str(cur); | ||||
| 	if ((cur = tb[IFACE_ATTR_INGRESS]) != NULL) | ||||
| 		cfg->ingress = blobmsg_get_bool(cur); | ||||
| 	if ((cur = tb[IFACE_ATTR_EGRESS]) != NULL) | ||||
| 		cfg->egress = blobmsg_get_bool(cur); | ||||
| 	if ((cur = tb[IFACE_ATTR_NAT]) != NULL) | ||||
| 		cfg->nat = blobmsg_get_bool(cur); | ||||
| 	if ((cur = tb[IFACE_ATTR_HOST_ISOLATE]) != NULL) | ||||
| 		cfg->host_isolate = blobmsg_get_bool(cur); | ||||
| 	if ((cur = tb[IFACE_ATTR_AUTORATE_IN]) != NULL) | ||||
| 		cfg->autorate_ingress = blobmsg_get_bool(cur); | ||||
| } | ||||
|  | ||||
| static const char * | ||||
| interface_ifb_name(struct qosify_iface *iface) | ||||
| { | ||||
| 	static char ifname[IFNAMSIZ + 1] = "ifb-"; | ||||
| 	int len = strlen(iface->ifname); | ||||
|  | ||||
| 	if (len + 4 < IFNAMSIZ) { | ||||
| 		snprintf(ifname + 4, IFNAMSIZ - 4, "%s", iface->ifname); | ||||
|  | ||||
| 		return ifname; | ||||
| 	} | ||||
|  | ||||
| 	ifname[4] = iface->ifname[0]; | ||||
| 	ifname[5] = iface->ifname[1]; | ||||
| 	snprintf(ifname + 6, IFNAMSIZ - 6, "%s", iface->ifname + len - (IFNAMSIZ + 6) - 1); | ||||
|  | ||||
| 	return ifname; | ||||
| } | ||||
|  | ||||
| static int run_cmd(char *cmd, bool ignore) | ||||
| { | ||||
| 	char *argv[] = { "sh", "-c", cmd, NULL }; | ||||
| 	bool first = true; | ||||
| 	int status = -1; | ||||
| 	char buf[512]; | ||||
| 	int fds[2]; | ||||
| 	FILE *f; | ||||
| 	int pid; | ||||
|  | ||||
| 	if (pipe(fds)) | ||||
| 		return -1; | ||||
|  | ||||
| 	pid = fork(); | ||||
| 	if (!pid) { | ||||
| 		close(fds[0]); | ||||
| 		if (fds[1] != STDOUT_FILENO) | ||||
| 			dup2(fds[1], STDOUT_FILENO); | ||||
| 		if (fds[1] != STDERR_FILENO) | ||||
| 			dup2(fds[1], STDERR_FILENO); | ||||
| 		if (fds[1] > STDERR_FILENO) | ||||
| 			close(fds[1]); | ||||
| 		execv("/bin/sh", argv); | ||||
| 		exit(1); | ||||
| 	} | ||||
|  | ||||
| 	if (pid < 0) | ||||
| 		return -1; | ||||
|  | ||||
| 	close(fds[1]); | ||||
| 	f = fdopen(fds[0], "r"); | ||||
| 	if (!f) { | ||||
| 		close(fds[0]); | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| 	while (fgets(buf, sizeof(buf), f) != NULL) { | ||||
| 		if (!strlen(buf)) | ||||
| 			break; | ||||
| 		if (ignore) | ||||
| 			continue; | ||||
| 		if (first) { | ||||
| 			ULOG_WARN("Command: %s\n", cmd); | ||||
| 			first = false; | ||||
| 		} | ||||
| 		ULOG_WARN("%s%s", buf, strchr(buf, '\n') ? "" : "\n"); | ||||
| 	} | ||||
|  | ||||
| 	fclose(f); | ||||
|  | ||||
| out: | ||||
| 	while (waitpid(pid, &status, 0) < 0) | ||||
| 		if (errno != EINTR) | ||||
| 			break; | ||||
|  | ||||
| 	return status; | ||||
| } | ||||
|  | ||||
| static int | ||||
| prepare_tc_cmd(char *buf, int len, const char *type, const char *cmd, | ||||
| 	       const char *dev, const char *extra) | ||||
| { | ||||
| 	return snprintf(buf, len, "tc %s %s dev '%s' %s", type, cmd, dev, extra); | ||||
| } | ||||
|  | ||||
| static int | ||||
| cmd_del_qdisc(const char *ifname, const char *type) | ||||
| { | ||||
| 	char buf[64]; | ||||
|  | ||||
| 	prepare_tc_cmd(buf, sizeof(buf), "qdisc", "del", ifname, type); | ||||
|  | ||||
| 	return run_cmd(buf, true); | ||||
| } | ||||
|  | ||||
| static int | ||||
| cmd_add_qdisc(struct qosify_iface *iface, const char *ifname, bool egress, bool eth) | ||||
| { | ||||
| 	struct qosify_iface_config *cfg = &iface->config; | ||||
| 	const char *bw = egress ? cfg->bandwidth_up : cfg->bandwidth_down; | ||||
| 	const char *dir_opts = egress ? cfg->egress_opts : cfg->ingress_opts; | ||||
| 	char buf[512]; | ||||
| 	int ofs; | ||||
|  | ||||
| 	cmd_del_qdisc(ifname, "root"); | ||||
|  | ||||
| 	ofs = prepare_tc_cmd(buf, sizeof(buf), "qdisc", "add", ifname, "root handle 1: cake"); | ||||
| 	if (bw) | ||||
| 		APPEND(buf, ofs, " bandwidth %s", bw); | ||||
|  | ||||
| 	APPEND(buf, ofs, " %s %sgress", cfg->mode, egress ? "e" : "in"); | ||||
|  | ||||
| 	if (cfg->host_isolate) | ||||
| 		APPEND(buf, ofs, " %snat dual-%shost", | ||||
| 			cfg->nat ? "" : "no", | ||||
| 			egress ? "src" : "dst"); | ||||
| 	else | ||||
| 		APPEND(buf, ofs, " flows"); | ||||
|  | ||||
| 	APPEND(buf, ofs, " %s %s", | ||||
| 	       cfg->common_opts ? cfg->common_opts : "", | ||||
| 	       dir_opts ? dir_opts : ""); | ||||
|  | ||||
| 	run_cmd(buf, false); | ||||
|  | ||||
| 	ofs = prepare_tc_cmd(buf, sizeof(buf), "filter", "add", ifname, "parent 1: bpf"); | ||||
| 	APPEND(buf, ofs, " object-pinned /sys/fs/bpf/qosify_%sgress_%s verbose direct-action", | ||||
| 	       egress ? "e" : "in", | ||||
| 		   eth ? "eth" : "ip"); | ||||
|  | ||||
| 	return run_cmd(buf, false); | ||||
| } | ||||
|  | ||||
| static int | ||||
| cmd_del_ingress(struct qosify_iface *iface) | ||||
| { | ||||
| 	char buf[256]; | ||||
|  | ||||
| 	cmd_del_qdisc(iface->ifname, "handle ffff: ingress"); | ||||
| 	snprintf(buf, sizeof(buf), "ip link del '%s'", interface_ifb_name(iface)); | ||||
|  | ||||
| 	return run_cmd(buf, true); | ||||
| } | ||||
|  | ||||
|  | ||||
| static int | ||||
| cmd_add_ingress(struct qosify_iface *iface, bool eth) | ||||
| { | ||||
| 	const char *ifbdev = interface_ifb_name(iface); | ||||
| 	char buf[256]; | ||||
| 	int ofs; | ||||
|  | ||||
| 	cmd_del_ingress(iface); | ||||
|  | ||||
| 	ofs = prepare_tc_cmd(buf, sizeof(buf), "qdisc", "add", iface->ifname, " handle ffff: ingress"); | ||||
| 	run_cmd(buf, false); | ||||
|  | ||||
| 	snprintf(buf, sizeof(buf), "ip link add '%s' type ifb", ifbdev); | ||||
| 	run_cmd(buf, false); | ||||
|  | ||||
| 	cmd_add_qdisc(iface, ifbdev, false, eth); | ||||
|  | ||||
| 	snprintf(buf, sizeof(buf), "ip link set dev '%s' up", ifbdev); | ||||
| 	run_cmd(buf, false); | ||||
|  | ||||
| 	ofs = prepare_tc_cmd(buf, sizeof(buf), "filter", "add", iface->ifname, " parent ffff:"); | ||||
| 	APPEND(buf, ofs, " protocol all prio 10 u32 match u32 0 0 " | ||||
| 			 "flowid 1:1 action mirred egress redirect dev '%s'", ifbdev); | ||||
| 	return run_cmd(buf, false); | ||||
| } | ||||
|  | ||||
| static void | ||||
| interface_start(struct qosify_iface *iface) | ||||
| { | ||||
| 	struct ifreq ifr = {}; | ||||
| 	bool eth; | ||||
|  | ||||
| 	if (!iface->ifname[0] || iface->active) | ||||
| 		return; | ||||
|  | ||||
| 	ULOG_INFO("start interface %s\n", iface->ifname); | ||||
|  | ||||
| 	strncpy(ifr.ifr_name, iface->ifname, sizeof(ifr.ifr_name)); | ||||
| 	if (ioctl(socket_fd, SIOCGIFHWADDR, &ifr) < 0) { | ||||
| 		ULOG_ERR("ioctl(SIOCGIFHWADDR, %s) failed: %s\n", iface->ifname, strerror(errno)); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	eth = ifr.ifr_hwaddr.sa_family == ARPHRD_ETHER; | ||||
|  | ||||
| 	if (iface->config.egress) | ||||
| 		cmd_add_qdisc(iface, iface->ifname, true, eth); | ||||
| 	if (iface->config.ingress) | ||||
| 		cmd_add_ingress(iface, eth); | ||||
|  | ||||
| 	iface->active = true; | ||||
| } | ||||
|  | ||||
| static void | ||||
| interface_stop(struct qosify_iface *iface) | ||||
| { | ||||
| 	if (!iface->ifname[0] || !iface->active) | ||||
| 		return; | ||||
|  | ||||
| 	ULOG_INFO("stop interface %s\n", iface->ifname); | ||||
| 	iface->active = false; | ||||
|  | ||||
| 	if (iface->config.egress) | ||||
| 		cmd_del_qdisc(iface->ifname, "root"); | ||||
| 	if (iface->config.ingress) | ||||
| 		cmd_del_ingress(iface); | ||||
| } | ||||
|  | ||||
| static void | ||||
| interface_set_config(struct qosify_iface *iface, struct blob_attr *config) | ||||
| { | ||||
| 	iface->config_data = blob_memdup(config); | ||||
| 	iface_config_set(iface, iface->config_data); | ||||
| 	interface_start(iface); | ||||
| } | ||||
|  | ||||
| static void | ||||
| interface_update_cb(struct vlist_tree *tree, | ||||
| 		    struct vlist_node *node_new, struct vlist_node *node_old) | ||||
| { | ||||
| 	struct qosify_iface *if_new = NULL, *if_old = NULL; | ||||
|  | ||||
| 	if (node_new) | ||||
| 		if_new = container_of(node_new, struct qosify_iface, node); | ||||
| 	if (node_old) | ||||
| 		if_old = container_of(node_old, struct qosify_iface, node); | ||||
|  | ||||
| 	if (if_new && if_old) { | ||||
| 		if (!iface_config_equal(if_old, if_new)) { | ||||
| 			interface_stop(if_old); | ||||
| 			free(if_old->config_data); | ||||
| 			interface_set_config(if_old, if_new->config_data); | ||||
| 		} | ||||
|  | ||||
| 		free(if_new); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	if (if_old) { | ||||
| 		interface_stop(if_old); | ||||
| 		free(if_old->config_data); | ||||
| 		free(if_old); | ||||
| 	} | ||||
|  | ||||
| 	if (if_new) | ||||
| 		interface_set_config(if_new, if_new->config_data); | ||||
| } | ||||
|  | ||||
| static void | ||||
| interface_create(struct blob_attr *attr, bool device) | ||||
| { | ||||
| 	struct qosify_iface *iface; | ||||
| 	const char *name = blobmsg_name(attr); | ||||
| 	int name_len = strlen(name); | ||||
| 	char *name_buf; | ||||
|  | ||||
| 	if (strchr(name, '\'')) | ||||
| 		return; | ||||
|  | ||||
| 	if (name_len >= IFNAMSIZ) | ||||
| 		return; | ||||
|  | ||||
| 	if (blobmsg_type(attr) != BLOBMSG_TYPE_TABLE) | ||||
| 		return; | ||||
|  | ||||
| 	iface = calloc_a(sizeof(*iface), &name_buf, name_len + 1); | ||||
| 	strcpy(name_buf, blobmsg_name(attr)); | ||||
| 	iface->config_data = attr; | ||||
| 	iface->device = device; | ||||
| 	vlist_add(device ? &devices : &interfaces, &iface->node, name_buf); | ||||
| } | ||||
|  | ||||
| void qosify_iface_config_update(struct blob_attr *ifaces, struct blob_attr *devs) | ||||
| { | ||||
| 	struct blob_attr *cur; | ||||
| 	int rem; | ||||
|  | ||||
| 	vlist_update(&devices); | ||||
| 	blobmsg_for_each_attr(cur, devs, rem) | ||||
| 		interface_create(cur, true); | ||||
| 	vlist_flush(&devices); | ||||
|  | ||||
| 	vlist_update(&interfaces); | ||||
| 	blobmsg_for_each_attr(cur, ifaces, rem) | ||||
| 		interface_create(cur, false); | ||||
| 	vlist_flush(&interfaces); | ||||
| } | ||||
|  | ||||
| static void | ||||
| qosify_iface_check_device(struct qosify_iface *iface) | ||||
| { | ||||
| 	const char *name = qosify_iface_name(iface); | ||||
| 	int ifindex; | ||||
|  | ||||
| 	ifindex = if_nametoindex(name); | ||||
| 	if (!ifindex) { | ||||
| 		interface_stop(iface); | ||||
| 		iface->ifname[0] = 0; | ||||
| 	} else { | ||||
| 		snprintf(iface->ifname, sizeof(iface->ifname), "%s", name); | ||||
| 		interface_start(iface); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static void | ||||
| qosify_iface_check_interface(struct qosify_iface *iface) | ||||
| { | ||||
| 	const char *name = qosify_iface_name(iface); | ||||
| 	char ifname[IFNAMSIZ]; | ||||
|  | ||||
| 	if (qosify_ubus_check_interface(name, ifname, sizeof(ifname)) == 0) { | ||||
| 		snprintf(iface->ifname, sizeof(iface->ifname), "%s", ifname); | ||||
| 		interface_start(iface); | ||||
| 	} else { | ||||
| 		interface_stop(iface); | ||||
| 		iface->ifname[0] = 0; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static void qos_iface_check_cb(struct uloop_timeout *t) | ||||
| { | ||||
| 	struct qosify_iface *iface; | ||||
|  | ||||
| 	vlist_for_each_element(&devices, iface, node) | ||||
| 		qosify_iface_check_device(iface); | ||||
| 	vlist_for_each_element(&interfaces, iface, node) | ||||
| 		qosify_iface_check_interface(iface); | ||||
| } | ||||
|  | ||||
| void qosify_iface_check(void) | ||||
| { | ||||
| 	static struct uloop_timeout timer = { | ||||
| 		.cb = qos_iface_check_cb, | ||||
| 	}; | ||||
|  | ||||
| 	uloop_timeout_set(&timer, 10); | ||||
| } | ||||
|  | ||||
| void qosify_iface_status(struct blob_buf *b) | ||||
| { | ||||
| 	struct qosify_iface *iface; | ||||
| 	void *c, *i; | ||||
|  | ||||
| 	c = blobmsg_open_table(b, "devices"); | ||||
| 	vlist_for_each_element(&devices, iface, node) { | ||||
| 		i = blobmsg_open_table(b, qosify_iface_name(iface)); | ||||
| 		blobmsg_add_u8(b, "active", iface->active); | ||||
| 		blobmsg_close_table(b, i); | ||||
| 	} | ||||
| 	blobmsg_close_table(b, c); | ||||
|  | ||||
| 	c = blobmsg_open_table(b, "interfaces"); | ||||
| 	vlist_for_each_element(&interfaces, iface, node) { | ||||
| 		i = blobmsg_open_table(b, qosify_iface_name(iface)); | ||||
| 		blobmsg_add_u8(b, "active", iface->active); | ||||
| 		if (iface->ifname) | ||||
| 			blobmsg_add_string(b, "ifname", iface->ifname); | ||||
| 		blobmsg_close_table(b, i); | ||||
| 	} | ||||
| 	blobmsg_close_table(b, c); | ||||
| } | ||||
|  | ||||
| int qosify_iface_init(void) | ||||
| { | ||||
| 	socket_fd = socket(AF_UNIX, SOCK_DGRAM, 0); | ||||
| 	if (socket < 0) | ||||
| 		return -1; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| void qosify_iface_stop(void) | ||||
| { | ||||
| 	struct qosify_iface *iface; | ||||
|  | ||||
| 	vlist_for_each_element(&interfaces, iface, node) | ||||
| 		interface_stop(iface); | ||||
| 	vlist_for_each_element(&devices, iface, node) | ||||
| 		interface_stop(iface); | ||||
| } | ||||
|  | ||||
| @@ -1,121 +0,0 @@ | ||||
| // SPDX-License-Identifier: GPL-2.0+ | ||||
| /* | ||||
|  * Copyright (C) 2021 Felix Fietkau <nbd@nbd.name> | ||||
|  */ | ||||
| #include <sys/resource.h> | ||||
| #include <sys/stat.h> | ||||
| #include <arpa/inet.h> | ||||
| #include <glob.h> | ||||
| #include <unistd.h> | ||||
|  | ||||
| #include "qosify.h" | ||||
|  | ||||
| static int qosify_bpf_pr(enum libbpf_print_level level, const char *format, | ||||
| 		     va_list args) | ||||
| { | ||||
| 	return vfprintf(stderr, format, args); | ||||
| } | ||||
|  | ||||
| static void qosify_init_env(void) | ||||
| { | ||||
| 	struct rlimit limit = { | ||||
| 		.rlim_cur = RLIM_INFINITY, | ||||
| 		.rlim_max = RLIM_INFINITY, | ||||
| 	}; | ||||
|  | ||||
| 	setrlimit(RLIMIT_MEMLOCK, &limit); | ||||
| } | ||||
|  | ||||
| static void qosify_fill_rodata(struct bpf_object *obj, uint32_t flags) | ||||
| { | ||||
| 	struct bpf_map *map = NULL; | ||||
|  | ||||
| 	while ((map = bpf_map__next(map, obj)) != NULL) { | ||||
| 		if (!strstr(bpf_map__name(map), ".rodata")) | ||||
| 			continue; | ||||
|  | ||||
| 		bpf_map__set_initial_value(map, &flags, sizeof(flags)); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static int | ||||
| qosify_create_program(const char *suffix, uint32_t flags) | ||||
| { | ||||
| 	DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts, | ||||
| 		.pin_root_path = CLASSIFY_DATA_PATH, | ||||
| 	); | ||||
| 	struct bpf_program *prog; | ||||
| 	struct bpf_object *obj; | ||||
| 	char path[256]; | ||||
| 	int err; | ||||
|  | ||||
| 	snprintf(path, sizeof(path), CLASSIFY_PIN_PATH "_" "%s", suffix); | ||||
|  | ||||
| 	obj = bpf_object__open_file(CLASSIFY_PROG_PATH, &opts); | ||||
| 	err = libbpf_get_error(obj); | ||||
| 	if (err) { | ||||
| 		perror("bpf_object__open_file"); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	prog = bpf_object__find_program_by_title(obj, "classifier"); | ||||
| 	if (!prog) { | ||||
| 		fprintf(stderr, "Can't find classifier prog\n"); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	bpf_program__set_type(prog, BPF_PROG_TYPE_SCHED_CLS); | ||||
|  | ||||
| 	qosify_fill_rodata(obj, flags); | ||||
|  | ||||
| 	err = bpf_object__load(obj); | ||||
| 	if (err) { | ||||
| 		perror("bpf_object__load"); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	libbpf_set_print(NULL); | ||||
|  | ||||
| 	unlink(path); | ||||
| 	err = bpf_program__pin(prog, path); | ||||
| 	if (err) { | ||||
| 		fprintf(stderr, "Failed to pin program to %s: %s\n", | ||||
| 			path, strerror(-err)); | ||||
| 	} | ||||
|  | ||||
| 	bpf_object__close(obj); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int qosify_loader_init(void) | ||||
| { | ||||
| 	static const struct { | ||||
| 		const char *suffix; | ||||
| 		uint32_t flags; | ||||
| 	} progs[] = { | ||||
| 		{ "egress_eth", 0 }, | ||||
| 		{ "egress_ip", QOSIFY_IP_ONLY }, | ||||
| 		{ "ingress_eth", QOSIFY_INGRESS }, | ||||
| 		{ "ingress_ip", QOSIFY_INGRESS | QOSIFY_IP_ONLY }, | ||||
| 	}; | ||||
| 	glob_t g; | ||||
| 	int i; | ||||
|  | ||||
| 	if (glob(CLASSIFY_DATA_PATH "/*", 0, NULL, &g) == 0) { | ||||
| 		for (i = 0; i < g.gl_pathc; i++) | ||||
| 			unlink(g.gl_pathv[i]); | ||||
| 	} | ||||
|  | ||||
|  | ||||
| 	libbpf_set_print(qosify_bpf_pr); | ||||
|  | ||||
| 	qosify_init_env(); | ||||
|  | ||||
| 	for (i = 0; i < ARRAY_SIZE(progs); i++) { | ||||
| 		if (qosify_create_program(progs[i].suffix, progs[i].flags)) | ||||
| 			return -1; | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
| @@ -1,72 +0,0 @@ | ||||
| // SPDX-License-Identifier: GPL-2.0+ | ||||
| /* | ||||
|  * Copyright (C) 2021 Felix Fietkau <nbd@nbd.name> | ||||
|  */ | ||||
| #include <stdio.h> | ||||
| #include <unistd.h> | ||||
| #include <stdint.h> | ||||
|  | ||||
| #include <libubox/uloop.h> | ||||
|  | ||||
| #include "qosify.h" | ||||
|  | ||||
| static int usage(const char *progname) | ||||
| { | ||||
| 	fprintf(stderr, "Usage: %s [options]\n" | ||||
| 		"Options:\n" | ||||
| 		"	-l <file>	Load defaults from <file>\n" | ||||
| 		"	-o		only load program/maps without running as daemon\n" | ||||
| 		"\n", progname); | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| int main(int argc, char **argv) | ||||
| { | ||||
| 	const char *load_file = NULL; | ||||
| 	bool oneshot = false; | ||||
| 	int ch; | ||||
|  | ||||
| 	while ((ch = getopt(argc, argv, "fl:o")) != -1) { | ||||
| 		switch (ch) { | ||||
| 		case 'f': | ||||
| 			break; | ||||
| 		case 'l': | ||||
| 			load_file = optarg; | ||||
| 			break; | ||||
| 		case 'o': | ||||
| 			oneshot = true; | ||||
| 			break; | ||||
| 		default: | ||||
| 			return usage(argv[0]); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (qosify_loader_init()) | ||||
| 		return 2; | ||||
|  | ||||
| 	if (qosify_map_init()) | ||||
| 		return 2; | ||||
|  | ||||
| 	if (qosify_map_load_file(load_file)) | ||||
| 		return 2; | ||||
|  | ||||
| 	if (oneshot) | ||||
| 		return 0; | ||||
|  | ||||
| 	ulog_open(ULOG_SYSLOG, LOG_DAEMON, "qosify"); | ||||
| 	uloop_init(); | ||||
|  | ||||
| 	if (qosify_ubus_init() || | ||||
| 	    qosify_iface_init()) | ||||
| 		return 2; | ||||
|  | ||||
| 	uloop_run(); | ||||
|  | ||||
| 	qosify_ubus_stop(); | ||||
| 	qosify_iface_stop(); | ||||
|  | ||||
| 	uloop_done(); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
| @@ -1,735 +0,0 @@ | ||||
| // SPDX-License-Identifier: GPL-2.0+ | ||||
| /* | ||||
|  * Copyright (C) 2021 Felix Fietkau <nbd@nbd.name> | ||||
|  */ | ||||
| #include <arpa/inet.h> | ||||
|  | ||||
| #include <errno.h> | ||||
| #include <stdio.h> | ||||
| #include <ctype.h> | ||||
| #include <stdlib.h> | ||||
| #include <time.h> | ||||
|  | ||||
| #include <libubox/uloop.h> | ||||
|  | ||||
| #include "qosify.h" | ||||
|  | ||||
| static int qosify_map_entry_cmp(const void *k1, const void *k2, void *ptr); | ||||
|  | ||||
| static int qosify_map_fds[__CL_MAP_MAX]; | ||||
| static AVL_TREE(map_data, qosify_map_entry_cmp, false, NULL); | ||||
| static LIST_HEAD(map_files); | ||||
| static uint32_t next_timeout; | ||||
| static uint8_t qosify_dscp_default[2] = { 0xff, 0xff }; | ||||
| int qosify_map_timeout; | ||||
| int qosify_active_timeout; | ||||
| struct qosify_config config; | ||||
|  | ||||
| struct qosify_map_file { | ||||
| 	struct list_head list; | ||||
| 	char filename[]; | ||||
| }; | ||||
|  | ||||
| static const struct { | ||||
| 	const char *name; | ||||
| 	const char *type_name; | ||||
| } qosify_map_info[] = { | ||||
| 	[CL_MAP_TCP_PORTS] = { "tcp_ports", "tcp_port" }, | ||||
| 	[CL_MAP_UDP_PORTS] = { "udp_ports", "udp_port" }, | ||||
| 	[CL_MAP_IPV4_ADDR] = { "ipv4_map", "ipv4_addr" }, | ||||
| 	[CL_MAP_IPV6_ADDR] = { "ipv6_map", "ipv6_addr" }, | ||||
| 	[CL_MAP_CONFIG] = { "config", "config" }, | ||||
| 	[CL_MAP_DNS] = { "dns", "dns" }, | ||||
| }; | ||||
|  | ||||
| static const struct { | ||||
| 	const char name[5]; | ||||
| 	uint8_t val; | ||||
| } codepoints[] = { | ||||
| 	{ "CS0", 0 }, | ||||
| 	{ "CS1", 8 }, | ||||
| 	{ "CS2", 16 }, | ||||
| 	{ "CS3", 24 }, | ||||
| 	{ "CS4", 32 }, | ||||
| 	{ "CS5", 40 }, | ||||
| 	{ "CS6", 48 }, | ||||
| 	{ "CS7", 56 }, | ||||
| 	{ "AF11", 10 }, | ||||
| 	{ "AF12", 12 }, | ||||
| 	{ "AF13", 14 }, | ||||
| 	{ "AF21", 18 }, | ||||
| 	{ "AF22", 20 }, | ||||
| 	{ "AF22", 22 }, | ||||
| 	{ "AF31", 26 }, | ||||
| 	{ "AF32", 28 }, | ||||
| 	{ "AF33", 30 }, | ||||
| 	{ "AF41", 34 }, | ||||
| 	{ "AF42", 36 }, | ||||
| 	{ "AF43", 38 }, | ||||
| 	{ "EF", 46 }, | ||||
| 	{ "VA", 44 }, | ||||
| 	{ "LE", 1 }, | ||||
| 	{ "DF", 0 }, | ||||
| }; | ||||
|  | ||||
| static void qosify_map_timer_cb(struct uloop_timeout *t) | ||||
| { | ||||
| 	qosify_map_gc(); | ||||
| } | ||||
|  | ||||
| static struct uloop_timeout qosify_map_timer = { | ||||
| 	.cb = qosify_map_timer_cb, | ||||
| }; | ||||
|  | ||||
| static uint32_t qosify_gettime(void) | ||||
| { | ||||
| 	struct timespec ts; | ||||
|  | ||||
| 	clock_gettime(CLOCK_MONOTONIC, &ts); | ||||
|  | ||||
| 	return ts.tv_sec; | ||||
| } | ||||
|  | ||||
| static const char * | ||||
| qosify_map_path(enum qosify_map_id id) | ||||
| { | ||||
| 	static char path[128]; | ||||
| 	const char *name; | ||||
|  | ||||
| 	if (id >= ARRAY_SIZE(qosify_map_info)) | ||||
| 		return NULL; | ||||
|  | ||||
| 	name = qosify_map_info[id].name; | ||||
| 	if (!name) | ||||
| 		return NULL; | ||||
|  | ||||
| 	snprintf(path, sizeof(path), "%s/%s", CLASSIFY_DATA_PATH, name); | ||||
|  | ||||
| 	return path; | ||||
| } | ||||
|  | ||||
| static int qosify_map_get_fd(enum qosify_map_id id) | ||||
| { | ||||
| 	const char *path = qosify_map_path(id); | ||||
| 	int fd; | ||||
|  | ||||
| 	if (!path) | ||||
| 		return -1; | ||||
|  | ||||
| 	fd = bpf_obj_get(path); | ||||
| 	if (fd < 0) | ||||
| 		fprintf(stderr, "Failed to open map %s: %s\n", path, strerror(errno)); | ||||
|  | ||||
| 	return fd; | ||||
| } | ||||
|  | ||||
| static void qosify_map_clear_list(enum qosify_map_id id) | ||||
| { | ||||
| 	int fd = qosify_map_fds[id]; | ||||
| 	__u32 key[4] = {}; | ||||
|  | ||||
| 	while (bpf_map_get_next_key(fd, &key, &key) != -1) | ||||
| 		bpf_map_delete_elem(fd, &key); | ||||
| } | ||||
|  | ||||
| static void __qosify_map_set_dscp_default(enum qosify_map_id id, uint8_t val) | ||||
| { | ||||
| 	struct qosify_map_data data = { | ||||
| 		.id = id, | ||||
| 	}; | ||||
| 	int fd = qosify_map_fds[id]; | ||||
| 	int i; | ||||
|  | ||||
| 	val |= QOSIFY_DSCP_DEFAULT_FLAG; | ||||
|  | ||||
| 	for (i = 0; i < (1 << 16); i++) { | ||||
| 		data.addr.port = htons(i); | ||||
| 		if (avl_find(&map_data, &data)) | ||||
| 			continue; | ||||
|  | ||||
| 		bpf_map_update_elem(fd, &data.addr, &val, BPF_ANY); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void qosify_map_set_dscp_default(enum qosify_map_id id, uint8_t val) | ||||
| { | ||||
| 	bool udp; | ||||
|  | ||||
| 	if (id == CL_MAP_TCP_PORTS) | ||||
| 		udp = false; | ||||
| 	else if (id == CL_MAP_UDP_PORTS) | ||||
| 		udp = true; | ||||
| 	else | ||||
| 		return; | ||||
|  | ||||
| 	if (qosify_dscp_default[udp] == val) | ||||
| 		return; | ||||
|  | ||||
| 	qosify_dscp_default[udp] = val; | ||||
| 	__qosify_map_set_dscp_default(id, val); | ||||
| } | ||||
|  | ||||
| int qosify_map_init(void) | ||||
| { | ||||
| 	int i; | ||||
|  | ||||
| 	for (i = 0; i < CL_MAP_DNS; i++) { | ||||
| 		qosify_map_fds[i] = qosify_map_get_fd(i); | ||||
| 		if (qosify_map_fds[i] < 0) | ||||
| 			return -1; | ||||
| 	} | ||||
|  | ||||
| 	qosify_map_clear_list(CL_MAP_IPV4_ADDR); | ||||
| 	qosify_map_clear_list(CL_MAP_IPV6_ADDR); | ||||
| 	qosify_map_reset_config(); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static char *str_skip(char *str, bool space) | ||||
| { | ||||
| 	while (*str && isspace(*str) == space) | ||||
| 		str++; | ||||
|  | ||||
| 	return str; | ||||
| } | ||||
|  | ||||
| static int | ||||
| qosify_map_codepoint(const char *val) | ||||
| { | ||||
| 	int i; | ||||
|  | ||||
| 	for (i = 0; i < ARRAY_SIZE(codepoints); i++) | ||||
| 		if (!strcmp(codepoints[i].name, val)) | ||||
| 			return codepoints[i].val; | ||||
|  | ||||
| 	return 0xff; | ||||
| } | ||||
|  | ||||
| static int qosify_map_entry_cmp(const void *k1, const void *k2, void *ptr) | ||||
| { | ||||
| 	const struct qosify_map_data *d1 = k1; | ||||
| 	const struct qosify_map_data *d2 = k2; | ||||
|  | ||||
| 	if (d1->id != d2->id) | ||||
| 		return d2->id - d1->id; | ||||
|  | ||||
| 	if (d1->id == CL_MAP_DNS) | ||||
| 		return strcmp(d1->addr.dns.pattern, d2->addr.dns.pattern); | ||||
|  | ||||
| 	return memcmp(&d1->addr, &d2->addr, sizeof(d1->addr)); | ||||
| } | ||||
|  | ||||
| static struct qosify_map_entry * | ||||
| __qosify_map_alloc_entry(struct qosify_map_data *data) | ||||
| { | ||||
| 	struct qosify_map_entry *e; | ||||
| 	char *pattern; | ||||
|  | ||||
| 	if (data->id < CL_MAP_DNS) { | ||||
| 		e = calloc(1, sizeof(*e)); | ||||
| 		memcpy(&e->data.addr, &data->addr, sizeof(e->data.addr)); | ||||
|  | ||||
| 		return e; | ||||
| 	} | ||||
|  | ||||
| 	e = calloc_a(sizeof(*e), &pattern, strlen(data->addr.dns.pattern) + 1); | ||||
| 	strcpy(pattern, data->addr.dns.pattern); | ||||
| 	e->data.addr.dns.pattern = pattern; | ||||
| 	if (regcomp(&e->data.addr.dns.regex, pattern, | ||||
| 		    REG_EXTENDED | REG_ICASE | REG_NOSUB)) { | ||||
| 		free(e); | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	return e; | ||||
| } | ||||
|  | ||||
| static void __qosify_map_set_entry(struct qosify_map_data *data) | ||||
| { | ||||
| 	int fd = qosify_map_fds[data->id]; | ||||
| 	struct qosify_map_entry *e; | ||||
| 	bool file = data->file; | ||||
| 	int32_t delta = 0; | ||||
| 	bool add = data->dscp != 0xff; | ||||
| 	uint8_t prev_dscp = 0xff; | ||||
|  | ||||
| 	e = avl_find_element(&map_data, data, e, avl); | ||||
| 	if (!e) { | ||||
| 		if (!add) | ||||
| 			return; | ||||
|  | ||||
| 		e = __qosify_map_alloc_entry(data); | ||||
| 		if (!e) | ||||
| 			return; | ||||
|  | ||||
| 		e->avl.key = &e->data; | ||||
| 		e->data.id = data->id; | ||||
| 		avl_insert(&map_data, &e->avl); | ||||
| 	} else { | ||||
| 		prev_dscp = e->data.dscp; | ||||
| 	} | ||||
|  | ||||
| 	if (file) | ||||
| 		e->data.file = add; | ||||
| 	else | ||||
| 		e->data.user = add; | ||||
|  | ||||
| 	if (add) { | ||||
| 		if (file) | ||||
| 			e->data.file_dscp = data->dscp; | ||||
| 		if (!e->data.user || !file) | ||||
| 			e->data.dscp = data->dscp; | ||||
| 	} else if (e->data.file && !file) { | ||||
| 		e->data.dscp = e->data.file_dscp; | ||||
| 	} | ||||
|  | ||||
| 	if (e->data.dscp != prev_dscp && data->id < CL_MAP_DNS) { | ||||
| 		struct qosify_ip_map_val val = { | ||||
| 			.dscp = e->data.dscp, | ||||
| 			.seen = 1, | ||||
| 		}; | ||||
|  | ||||
| 		bpf_map_update_elem(fd, &data->addr, &val, BPF_ANY); | ||||
| 	} | ||||
|  | ||||
| 	if (add) { | ||||
| 		if (qosify_map_timeout == ~0 || file) { | ||||
| 			e->timeout = ~0; | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
| 		e->timeout = qosify_gettime() + qosify_map_timeout; | ||||
| 		delta = e->timeout - next_timeout; | ||||
| 		if (next_timeout && delta >= 0) | ||||
| 			return; | ||||
| 	} | ||||
|  | ||||
| 	uloop_timeout_set(&qosify_map_timer, 1); | ||||
| } | ||||
|  | ||||
| static int | ||||
| qosify_map_set_port(struct qosify_map_data *data, const char *str) | ||||
| { | ||||
| 	unsigned long start_port, end_port; | ||||
| 	char *err; | ||||
| 	int i; | ||||
|  | ||||
| 	start_port = end_port = strtoul(str, &err, 0); | ||||
| 	if (err && *err) { | ||||
| 		if (*err == '-') | ||||
| 			end_port = strtoul(err + 1, &err, 0); | ||||
| 		if (*err) | ||||
| 			return -1; | ||||
| 	} | ||||
|  | ||||
| 	if (!start_port || end_port < start_port || | ||||
| 	    end_port >= 65535) | ||||
| 		return -1; | ||||
|  | ||||
| 	for (i = start_port; i <= end_port; i++) { | ||||
| 		data->addr.port = htons(i); | ||||
| 		__qosify_map_set_entry(data); | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int | ||||
| qosify_map_fill_ip(struct qosify_map_data *data, const char *str) | ||||
| { | ||||
| 	int af; | ||||
|  | ||||
| 	if (data->id == CL_MAP_IPV6_ADDR) | ||||
| 		af = AF_INET6; | ||||
| 	else | ||||
| 		af = AF_INET; | ||||
|  | ||||
| 	if (inet_pton(af, str, &data->addr) != 1) | ||||
| 		return -1; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int qosify_map_set_entry(enum qosify_map_id id, bool file, const char *str, uint8_t dscp) | ||||
| { | ||||
| 	struct qosify_map_data data = { | ||||
| 		.id = id, | ||||
| 		.file = file, | ||||
| 		.dscp = dscp, | ||||
| 	}; | ||||
|  | ||||
| 	switch (id) { | ||||
| 	case CL_MAP_DNS: | ||||
| 		data.addr.dns.pattern = str; | ||||
| 		break; | ||||
| 	case CL_MAP_TCP_PORTS: | ||||
| 	case CL_MAP_UDP_PORTS: | ||||
| 		return qosify_map_set_port(&data, str); | ||||
| 	case CL_MAP_IPV4_ADDR: | ||||
| 	case CL_MAP_IPV6_ADDR: | ||||
| 		if (qosify_map_fill_ip(&data, str)) | ||||
| 			return -1; | ||||
| 		break; | ||||
| 	default: | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	__qosify_map_set_entry(&data); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int qosify_map_dscp_value(const char *val) | ||||
| { | ||||
| 	unsigned long dscp; | ||||
| 	char *err; | ||||
| 	bool fallback = false; | ||||
|  | ||||
| 	if (*val == '+') { | ||||
| 		fallback = true; | ||||
| 		val++; | ||||
| 	} | ||||
|  | ||||
| 	dscp = strtoul(val, &err, 0); | ||||
| 	if (err && *err) | ||||
| 		dscp = qosify_map_codepoint(val); | ||||
|  | ||||
| 	if (dscp >= 64) | ||||
| 		return -1; | ||||
|  | ||||
| 	return dscp + (fallback << 6); | ||||
| } | ||||
|  | ||||
| static void | ||||
| qosify_map_dscp_codepoint_str(char *dest, int len, uint8_t dscp) | ||||
| { | ||||
| 	int i; | ||||
|  | ||||
| 	if (dscp & QOSIFY_DSCP_FALLBACK_FLAG) { | ||||
| 		*(dest++) = '+'; | ||||
| 		len--; | ||||
| 		dscp &= ~QOSIFY_DSCP_FALLBACK_FLAG; | ||||
| 	} | ||||
|  | ||||
| 	for (i = 0; i < ARRAY_SIZE(codepoints); i++) { | ||||
| 		if (codepoints[i].val != dscp) | ||||
| 			continue; | ||||
|  | ||||
| 		snprintf(dest, len, "%s", codepoints[i].name); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	snprintf(dest, len, "0x%x", dscp); | ||||
| } | ||||
|  | ||||
| static void | ||||
| qosify_map_parse_line(char *str) | ||||
| { | ||||
| 	const char *key, *value; | ||||
| 	int dscp; | ||||
|  | ||||
| 	str = str_skip(str, true); | ||||
| 	key = str; | ||||
|  | ||||
| 	str = str_skip(str, false); | ||||
| 	if (!*str) | ||||
| 		return; | ||||
|  | ||||
| 	*(str++) = 0; | ||||
| 	str = str_skip(str, true); | ||||
| 	value = str; | ||||
|  | ||||
| 	dscp = qosify_map_dscp_value(value); | ||||
| 	if (dscp < 0) | ||||
| 		return; | ||||
|  | ||||
| 	if (!strncmp(key, "dns:", 4)) | ||||
| 		qosify_map_set_entry(CL_MAP_DNS, true, key + 4, dscp); | ||||
| 	if (!strncmp(key, "tcp:", 4)) | ||||
| 		qosify_map_set_entry(CL_MAP_TCP_PORTS, true, key + 4, dscp); | ||||
| 	else if (!strncmp(key, "udp:", 4)) | ||||
| 		qosify_map_set_entry(CL_MAP_UDP_PORTS, true, key + 4, dscp); | ||||
| 	else if (strchr(key, ':')) | ||||
| 		qosify_map_set_entry(CL_MAP_IPV6_ADDR, true, key, dscp); | ||||
| 	else if (strchr(key, '.')) | ||||
| 		qosify_map_set_entry(CL_MAP_IPV4_ADDR, true, key, dscp); | ||||
| } | ||||
|  | ||||
| static int __qosify_map_load_file(const char *file) | ||||
| { | ||||
| 	char line[1024]; | ||||
| 	char *cur; | ||||
| 	FILE *f; | ||||
|  | ||||
| 	if (!file) | ||||
| 		return 0; | ||||
|  | ||||
| 	f = fopen(file, "r"); | ||||
| 	if (!f) { | ||||
| 		fprintf(stderr, "Can't open data file %s\n", file); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	while (fgets(line, sizeof(line), f)) { | ||||
| 		cur = strchr(line, '#'); | ||||
| 		if (cur) | ||||
| 			*cur = 0; | ||||
|  | ||||
| 		cur = line + strlen(line); | ||||
| 		if (cur == line) | ||||
| 			continue; | ||||
|  | ||||
| 		while (cur > line && isspace(cur[-1])) | ||||
| 			cur--; | ||||
|  | ||||
| 		*cur = 0; | ||||
| 		qosify_map_parse_line(line); | ||||
| 	} | ||||
|  | ||||
| 	fclose(f); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int qosify_map_load_file(const char *file) | ||||
| { | ||||
| 	struct qosify_map_file *f; | ||||
|  | ||||
| 	if (!file) | ||||
| 		return 0; | ||||
|  | ||||
| 	f = calloc(1, sizeof(*f) + strlen(file) + 1); | ||||
| 	strcpy(f->filename, file); | ||||
| 	list_add_tail(&f->list, &map_files); | ||||
|  | ||||
| 	return __qosify_map_load_file(file); | ||||
| } | ||||
|  | ||||
| static void qosify_map_reset_file_entries(void) | ||||
| { | ||||
| 	struct qosify_map_entry *e; | ||||
|  | ||||
| 	avl_for_each_element(&map_data, e, avl) | ||||
| 		e->data.file = false; | ||||
| } | ||||
|  | ||||
| void qosify_map_clear_files(void) | ||||
| { | ||||
| 	struct qosify_map_file *f, *tmp; | ||||
|  | ||||
| 	qosify_map_reset_file_entries(); | ||||
|  | ||||
| 	list_for_each_entry_safe(f, tmp, &map_files, list) { | ||||
| 		list_del(&f->list); | ||||
| 		free(f); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void qosify_map_reset_config(void) | ||||
| { | ||||
| 	qosify_map_clear_files(); | ||||
| 	qosify_map_set_dscp_default(CL_MAP_TCP_PORTS, 0); | ||||
| 	qosify_map_set_dscp_default(CL_MAP_UDP_PORTS, 0); | ||||
| 	qosify_map_timeout = 3600; | ||||
| 	qosify_active_timeout = 300; | ||||
|  | ||||
| 	memset(&config, 0, sizeof(config)); | ||||
| 	config.dscp_prio = 0xff; | ||||
| 	config.dscp_bulk = 0xff; | ||||
| 	config.dscp_icmp = 0xff; | ||||
| } | ||||
|  | ||||
| void qosify_map_reload(void) | ||||
| { | ||||
| 	struct qosify_map_file *f; | ||||
|  | ||||
| 	qosify_map_reset_file_entries(); | ||||
|  | ||||
| 	list_for_each_entry(f, &map_files, list) | ||||
| 		__qosify_map_load_file(f->filename); | ||||
|  | ||||
| 	qosify_map_gc(); | ||||
| } | ||||
|  | ||||
| static void qosify_map_free_entry(struct qosify_map_entry *e) | ||||
| { | ||||
| 	int fd = qosify_map_fds[e->data.id]; | ||||
|  | ||||
| 	avl_delete(&map_data, &e->avl); | ||||
| 	if (e->data.id < CL_MAP_DNS) | ||||
| 		bpf_map_delete_elem(fd, &e->data.addr); | ||||
| 	free(e); | ||||
| } | ||||
|  | ||||
| static bool | ||||
| qosify_map_entry_refresh_timeout(struct qosify_map_entry *e) | ||||
| { | ||||
| 	struct qosify_ip_map_val val; | ||||
| 	int fd = qosify_map_fds[e->data.id]; | ||||
|  | ||||
| 	if (e->data.id != CL_MAP_IPV4_ADDR && | ||||
| 	    e->data.id != CL_MAP_IPV6_ADDR) | ||||
| 		return false; | ||||
|  | ||||
| 	if (bpf_map_lookup_elem(fd, &e->data.addr, &val)) | ||||
| 		return false; | ||||
|  | ||||
| 	if (!val.seen) | ||||
| 		return false; | ||||
|  | ||||
| 	e->timeout = qosify_gettime() + qosify_active_timeout; | ||||
| 	val.seen = 0; | ||||
| 	bpf_map_update_elem(fd, &e->data.addr, &val, BPF_ANY); | ||||
|  | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| void qosify_map_gc(void) | ||||
| { | ||||
| 	struct qosify_map_entry *e, *tmp; | ||||
| 	int32_t timeout = 0; | ||||
| 	uint32_t cur_time = qosify_gettime(); | ||||
|  | ||||
| 	next_timeout = 0; | ||||
| 	avl_for_each_element_safe(&map_data, e, avl, tmp) { | ||||
| 		int32_t cur_timeout; | ||||
|  | ||||
| 		if (e->data.user && e->timeout != ~0) { | ||||
| 			cur_timeout = e->timeout - cur_time; | ||||
| 			if (cur_timeout <= 0 && | ||||
| 			    qosify_map_entry_refresh_timeout(e)) | ||||
| 				cur_timeout = e->timeout - cur_time; | ||||
| 			if (cur_timeout <= 0) { | ||||
| 				e->data.user = false; | ||||
| 				e->data.dscp = e->data.file_dscp; | ||||
| 			} else if (!timeout || cur_timeout < timeout) { | ||||
| 				timeout = cur_timeout; | ||||
| 				next_timeout = e->timeout; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if (e->data.file || e->data.user) | ||||
| 			continue; | ||||
|  | ||||
| 		qosify_map_free_entry(e); | ||||
| 	} | ||||
|  | ||||
| 	if (!timeout) | ||||
| 		return; | ||||
|  | ||||
| 	uloop_timeout_set(&qosify_map_timer, timeout * 1000); | ||||
| } | ||||
|  | ||||
|  | ||||
| int qosify_map_add_dns_host(const char *host, const char *addr, const char *type, int ttl) | ||||
| { | ||||
| 	struct qosify_map_data data = { | ||||
| 		.id = CL_MAP_DNS, | ||||
| 		.addr.dns.pattern = "", | ||||
| 	}; | ||||
| 	struct qosify_map_entry *e; | ||||
| 	int prev_timeout = qosify_map_timeout; | ||||
|  | ||||
| 	e = avl_find_ge_element(&map_data, &data, e, avl); | ||||
| 	if (!e) | ||||
| 		return 0; | ||||
|  | ||||
| 	memset(&data, 0, sizeof(data)); | ||||
| 	data.user = true; | ||||
| 	if (!strcmp(type, "A")) | ||||
| 		data.id = CL_MAP_IPV4_ADDR; | ||||
| 	else if (!strcmp(type, "AAAA")) | ||||
| 		data.id = CL_MAP_IPV6_ADDR; | ||||
| 	else | ||||
| 		return 0; | ||||
|  | ||||
| 	if (qosify_map_fill_ip(&data, addr)) | ||||
| 		return -1; | ||||
|  | ||||
| 	avl_for_element_to_last(&map_data, e, e, avl) { | ||||
| 		regex_t *regex = &e->data.addr.dns.regex; | ||||
|  | ||||
| 		if (e->data.id != CL_MAP_DNS) | ||||
| 			return 0; | ||||
|  | ||||
| 		if (regexec(regex, host, 0, NULL, 0) != 0) | ||||
| 			continue; | ||||
|  | ||||
| 		if (ttl) | ||||
| 			qosify_map_timeout = ttl; | ||||
| 		data.dscp = e->data.dscp; | ||||
| 		__qosify_map_set_entry(&data); | ||||
| 		qosify_map_timeout = prev_timeout; | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| void qosify_map_dump(struct blob_buf *b) | ||||
| { | ||||
| 	struct qosify_map_entry *e; | ||||
| 	uint32_t cur_time = qosify_gettime(); | ||||
| 	int buf_len = INET6_ADDRSTRLEN + 1; | ||||
| 	char *buf; | ||||
| 	void *a; | ||||
| 	int af; | ||||
|  | ||||
| 	a = blobmsg_open_array(b, "entries"); | ||||
| 	avl_for_each_element(&map_data, e, avl) { | ||||
| 		void *c; | ||||
|  | ||||
| 		if (!e->data.file && !e->data.user) | ||||
| 			continue; | ||||
|  | ||||
| 		c = blobmsg_open_table(b, NULL); | ||||
| 		if (e->data.user && e->timeout != ~0) { | ||||
| 			int32_t cur_timeout = e->timeout - cur_time; | ||||
|  | ||||
| 			if (cur_timeout < 0) | ||||
| 				cur_timeout = 0; | ||||
|  | ||||
| 			blobmsg_add_u32(b, "timeout", cur_timeout); | ||||
| 		} | ||||
|  | ||||
| 		blobmsg_add_u8(b, "file", e->data.file); | ||||
| 		blobmsg_add_u8(b, "user", e->data.user); | ||||
|  | ||||
| 		buf = blobmsg_alloc_string_buffer(b, "dscp", buf_len); | ||||
| 		qosify_map_dscp_codepoint_str(buf, buf_len, e->data.dscp); | ||||
| 		blobmsg_add_string_buffer(b); | ||||
|  | ||||
| 		blobmsg_add_string(b, "type", qosify_map_info[e->data.id].type_name); | ||||
|  | ||||
| 		switch (e->data.id) { | ||||
| 		case CL_MAP_TCP_PORTS: | ||||
| 		case CL_MAP_UDP_PORTS: | ||||
| 			blobmsg_printf(b, "addr", "%d", ntohs(e->data.addr.port)); | ||||
| 			break; | ||||
| 		case CL_MAP_IPV4_ADDR: | ||||
| 		case CL_MAP_IPV6_ADDR: | ||||
| 			buf = blobmsg_alloc_string_buffer(b, "addr", buf_len); | ||||
| 			af = e->data.id == CL_MAP_IPV6_ADDR ? AF_INET6 : AF_INET; | ||||
| 			inet_ntop(af, &e->data.addr, buf, buf_len); | ||||
| 			blobmsg_add_string_buffer(b); | ||||
| 			break; | ||||
| 		case CL_MAP_DNS: | ||||
| 			blobmsg_add_string(b, "addr", e->data.addr.dns.pattern); | ||||
| 			break; | ||||
| 		default: | ||||
| 			*buf = 0; | ||||
| 			break; | ||||
| 		} | ||||
| 		blobmsg_close_table(b, c); | ||||
| 	} | ||||
| 	blobmsg_close_array(b, a); | ||||
| } | ||||
|  | ||||
| void qosify_map_update_config(void) | ||||
| { | ||||
| 	int fd = qosify_map_fds[CL_MAP_CONFIG]; | ||||
| 	uint32_t key = 0; | ||||
|  | ||||
| 	bpf_map_update_elem(fd, &key, &config, BPF_ANY); | ||||
| } | ||||
| @@ -1,464 +0,0 @@ | ||||
| // SPDX-License-Identifier: GPL-2.0+ | ||||
| /* | ||||
|  * Copyright (C) 2021 Felix Fietkau <nbd@nbd.name> | ||||
|  */ | ||||
| #define KBUILD_MODNAME "foo" | ||||
| #include <uapi/linux/bpf.h> | ||||
| #include <uapi/linux/if_ether.h> | ||||
| #include <uapi/linux/if_packet.h> | ||||
| #include <uapi/linux/ip.h> | ||||
| #include <uapi/linux/ipv6.h> | ||||
| #include <uapi/linux/in.h> | ||||
| #include <uapi/linux/tcp.h> | ||||
| #include <uapi/linux/udp.h> | ||||
| #include <uapi/linux/filter.h> | ||||
| #include <uapi/linux/pkt_cls.h> | ||||
| #include <linux/ip.h> | ||||
| #include <net/ipv6.h> | ||||
| #include <bpf/bpf_helpers.h> | ||||
| #include <bpf/bpf_endian.h> | ||||
| #include "qosify-bpf.h" | ||||
|  | ||||
| #define INET_ECN_MASK 3 | ||||
|  | ||||
| #define FLOW_CHECK_INTERVAL	((u32)((1000000000ULL) >> 24)) | ||||
| #define FLOW_TIMEOUT		((u32)((30ULL * 1000000000ULL) >> 24)) | ||||
| #define FLOW_BULK_TIMEOUT	5 | ||||
|  | ||||
| #define EWMA_SHIFT		12 | ||||
|  | ||||
| const volatile static uint32_t module_flags = 0; | ||||
|  | ||||
| struct flow_bucket { | ||||
| 	__u32 last_update; | ||||
| 	__u32 pkt_len_avg; | ||||
| 	__u16 pkt_count; | ||||
| 	__u8 dscp; | ||||
| 	__u8 bulk_timeout; | ||||
| }; | ||||
|  | ||||
| struct { | ||||
| 	__uint(type, BPF_MAP_TYPE_ARRAY); | ||||
| 	__uint(pinning, 1); | ||||
| 	__type(key, __u32); | ||||
| 	__type(value, struct qosify_config); | ||||
| 	__uint(max_entries, 1); | ||||
| } config SEC(".maps"); | ||||
|  | ||||
| typedef struct { | ||||
| 	__uint(type, BPF_MAP_TYPE_ARRAY); | ||||
| 	__uint(pinning, 1); | ||||
| 	__type(key, __u32); | ||||
| 	__type(value, __u8); | ||||
| 	__uint(max_entries, 1 << 16); | ||||
| } port_array_t; | ||||
|  | ||||
| struct { | ||||
| 	__uint(type, BPF_MAP_TYPE_LRU_HASH); | ||||
| 	__uint(pinning, 1); | ||||
| 	__type(key, __u32); | ||||
| 	__uint(value_size, sizeof(struct flow_bucket)); | ||||
| 	__uint(max_entries, QOSIFY_FLOW_BUCKETS); | ||||
| } flow_map SEC(".maps"); | ||||
|  | ||||
| port_array_t tcp_ports SEC(".maps"); | ||||
| port_array_t udp_ports SEC(".maps"); | ||||
|  | ||||
| struct { | ||||
| 	__uint(type, BPF_MAP_TYPE_HASH); | ||||
| 	__uint(pinning, 1); | ||||
| 	__uint(key_size, sizeof(struct in_addr)); | ||||
| 	__type(value, struct qosify_ip_map_val); | ||||
| 	__uint(max_entries, 100000); | ||||
| 	__uint(map_flags, BPF_F_NO_PREALLOC); | ||||
| } ipv4_map SEC(".maps"); | ||||
|  | ||||
| struct { | ||||
| 	__uint(type, BPF_MAP_TYPE_HASH); | ||||
| 	__uint(pinning, 1); | ||||
| 	__uint(key_size, sizeof(struct in6_addr)); | ||||
| 	__type(value, struct qosify_ip_map_val); | ||||
| 	__uint(max_entries, 100000); | ||||
| 	__uint(map_flags, BPF_F_NO_PREALLOC); | ||||
| } ipv6_map SEC(".maps"); | ||||
|  | ||||
| static struct qosify_config *get_config(void) | ||||
| { | ||||
| 	__u32 key = 0; | ||||
|  | ||||
| 	return bpf_map_lookup_elem(&config, &key); | ||||
| } | ||||
|  | ||||
| static __always_inline int proto_is_vlan(__u16 h_proto) | ||||
| { | ||||
| 	return !!(h_proto == bpf_htons(ETH_P_8021Q) || | ||||
| 		  h_proto == bpf_htons(ETH_P_8021AD)); | ||||
| } | ||||
|  | ||||
| static __always_inline int proto_is_ip(__u16 h_proto) | ||||
| { | ||||
| 	return !!(h_proto == bpf_htons(ETH_P_IP) || | ||||
| 		  h_proto == bpf_htons(ETH_P_IPV6)); | ||||
| } | ||||
|  | ||||
| static __always_inline void *skb_ptr(struct __sk_buff *skb, __u32 offset) | ||||
| { | ||||
| 	void *start = (void *)(unsigned long long)skb->data; | ||||
|  | ||||
| 	return start + offset; | ||||
| } | ||||
|  | ||||
| static __always_inline void *skb_end_ptr(struct __sk_buff *skb) | ||||
| { | ||||
| 	return (void *)(unsigned long long)skb->data_end; | ||||
| } | ||||
|  | ||||
| static __always_inline int skb_check(struct __sk_buff *skb, void *ptr) | ||||
| { | ||||
| 	if (ptr > skb_end_ptr(skb)) | ||||
| 		return -1; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static __always_inline __u32 cur_time(void) | ||||
| { | ||||
| 	__u32 val = bpf_ktime_get_ns() >> 24; | ||||
|  | ||||
| 	if (!val) | ||||
| 		val = 1; | ||||
|  | ||||
| 	return val; | ||||
| } | ||||
|  | ||||
| static __always_inline __u32 ewma(__u32 *avg, __u32 val) | ||||
| { | ||||
| 	if (*avg) | ||||
| 		*avg = (*avg * 3) / 4 + (val << EWMA_SHIFT) / 4; | ||||
| 	else | ||||
| 		*avg = val << EWMA_SHIFT; | ||||
|  | ||||
| 	return *avg >> EWMA_SHIFT; | ||||
| } | ||||
|  | ||||
| static __always_inline void | ||||
| ipv4_change_dsfield(struct iphdr *iph, __u8 mask, __u8 value, bool force) | ||||
| { | ||||
| 	__u32 check = bpf_ntohs(iph->check); | ||||
| 	__u8 dsfield; | ||||
|  | ||||
| 	if ((iph->tos & mask) && !force) | ||||
| 		return; | ||||
|  | ||||
| 	dsfield = (iph->tos & mask) | value; | ||||
| 	if (iph->tos == dsfield) | ||||
| 		return; | ||||
|  | ||||
| 	check += iph->tos; | ||||
| 	if ((check + 1) >> 16) | ||||
| 		check = (check + 1) & 0xffff; | ||||
| 	check -= dsfield; | ||||
| 	check += check >> 16; | ||||
| 	iph->check = bpf_htons(check); | ||||
| 	iph->tos = dsfield; | ||||
| } | ||||
|  | ||||
| static __always_inline void | ||||
| ipv6_change_dsfield(struct ipv6hdr *ipv6h, __u8 mask, __u8 value, bool force) | ||||
| { | ||||
| 	__u16 *p = (__u16 *)ipv6h; | ||||
| 	__u16 val; | ||||
|  | ||||
| 	if (((*p >> 4) & mask) && !force) | ||||
| 		return; | ||||
|  | ||||
| 	val = (*p & bpf_htons((((__u16)mask << 4) | 0xf00f))) | bpf_htons((__u16)value << 4); | ||||
| 	if (val == *p) | ||||
| 		return; | ||||
|  | ||||
| 	*p = val; | ||||
| } | ||||
|  | ||||
| static __always_inline int | ||||
| parse_ethernet(struct __sk_buff *skb, __u32 *offset) | ||||
| { | ||||
| 	struct ethhdr *eth; | ||||
| 	__u16 h_proto; | ||||
| 	int i; | ||||
|  | ||||
| 	eth = skb_ptr(skb, *offset); | ||||
| 	if (skb_check(skb, eth + 1)) | ||||
| 		return -1; | ||||
|  | ||||
| 	h_proto = eth->h_proto; | ||||
| 	*offset += sizeof(*eth); | ||||
|  | ||||
| #pragma unroll | ||||
| 	for (i = 0; i < 2; i++) { | ||||
| 		struct vlan_hdr *vlh = skb_ptr(skb, *offset); | ||||
|  | ||||
| 		if (!proto_is_vlan(h_proto)) | ||||
| 			break; | ||||
|  | ||||
| 		if (skb_check(skb, vlh + 1)) | ||||
| 			return -1; | ||||
|  | ||||
| 		h_proto = vlh->h_vlan_encapsulated_proto; | ||||
| 		*offset += sizeof(*vlh); | ||||
| 	} | ||||
|  | ||||
| 	return h_proto; | ||||
| } | ||||
|  | ||||
| static void | ||||
| parse_l4proto(struct qosify_config *config, struct __sk_buff *skb, | ||||
| 	      __u32 offset, __u8 proto, __u8 *dscp_out) | ||||
| { | ||||
| 	struct udphdr *udp; | ||||
| 	__u32 src, dest, key; | ||||
| 	__u8 *value; | ||||
|  | ||||
| 	udp = skb_ptr(skb, offset); | ||||
| 	if (skb_check(skb, &udp->len)) | ||||
| 		return; | ||||
|  | ||||
| 	if (config && (proto == IPPROTO_ICMP || proto == IPPROTO_ICMPV6)) { | ||||
| 		*dscp_out = config->dscp_icmp; | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	src = udp->source; | ||||
| 	dest = udp->dest; | ||||
|  | ||||
| 	if (module_flags & QOSIFY_INGRESS) | ||||
| 		key = src; | ||||
| 	else | ||||
| 		key = dest; | ||||
|  | ||||
| 	if (proto == IPPROTO_TCP) { | ||||
| 		value = bpf_map_lookup_elem(&tcp_ports, &key); | ||||
| 	} else { | ||||
| 		if (proto != IPPROTO_UDP) | ||||
| 			key = 0; | ||||
|  | ||||
| 		value = bpf_map_lookup_elem(&udp_ports, &key); | ||||
| 	} | ||||
|  | ||||
| 	if (!value) | ||||
| 		return; | ||||
|  | ||||
| 	*dscp_out = *value; | ||||
| } | ||||
|  | ||||
| static void | ||||
| check_flow(struct qosify_config *config, struct __sk_buff *skb, | ||||
| 	   uint8_t *dscp) | ||||
| { | ||||
| 	struct flow_bucket flow_data; | ||||
| 	struct flow_bucket *flow; | ||||
| 	__s32 delta; | ||||
| 	__u32 hash; | ||||
| 	__u32 time; | ||||
|  | ||||
| 	if (!(*dscp & QOSIFY_DSCP_DEFAULT_FLAG)) | ||||
| 		return; | ||||
|  | ||||
| 	if (!config) | ||||
| 		return; | ||||
|  | ||||
| 	if (!config->bulk_trigger_pps && | ||||
| 	    !config->prio_max_avg_pkt_len) | ||||
| 		return; | ||||
|  | ||||
| 	time = cur_time(); | ||||
| 	hash = bpf_get_hash_recalc(skb); | ||||
| 	flow = bpf_map_lookup_elem(&flow_map, &hash); | ||||
| 	if (!flow) { | ||||
| 		memset(&flow_data, 0, sizeof(flow_data)); | ||||
| 		bpf_map_update_elem(&flow_map, &hash, &flow_data, BPF_ANY); | ||||
| 		flow = bpf_map_lookup_elem(&flow_map, &hash); | ||||
| 		if (!flow) | ||||
| 			return; | ||||
| 	} | ||||
|  | ||||
| 	if (!flow->last_update) | ||||
| 		goto reset; | ||||
|  | ||||
| 	delta = time - flow->last_update; | ||||
| 	if ((u32)delta > FLOW_TIMEOUT) | ||||
| 		goto reset; | ||||
|  | ||||
| 	if (delta >= FLOW_CHECK_INTERVAL) { | ||||
| 		if (flow->bulk_timeout) { | ||||
| 			flow->bulk_timeout--; | ||||
| 			if (!flow->bulk_timeout) | ||||
| 				flow->dscp = 0xff; | ||||
| 		} | ||||
|  | ||||
| 		goto clear; | ||||
| 	} | ||||
|  | ||||
| 	if (flow->pkt_count < 0xffff) | ||||
| 		flow->pkt_count++; | ||||
|  | ||||
| 	if (config->bulk_trigger_pps && | ||||
| 	    flow->pkt_count > config->bulk_trigger_pps) { | ||||
| 		flow->dscp = config->dscp_bulk; | ||||
| 		flow->bulk_timeout = config->bulk_trigger_timeout; | ||||
| 	} | ||||
|  | ||||
| out: | ||||
| 	if (config->prio_max_avg_pkt_len && | ||||
| 	    flow->dscp != config->dscp_bulk) { | ||||
| 		if (ewma(&flow->pkt_len_avg, skb->len) < | ||||
| 		    config->prio_max_avg_pkt_len) | ||||
| 			flow->dscp = config->dscp_prio; | ||||
| 		else | ||||
| 			flow->dscp = 0xff; | ||||
| 	} | ||||
|  | ||||
| 	if (flow->dscp != 0xff) | ||||
| 		*dscp = flow->dscp; | ||||
|  | ||||
| 	return; | ||||
|  | ||||
| reset: | ||||
| 	flow->dscp = 0xff; | ||||
| 	flow->pkt_len_avg = 0; | ||||
| clear: | ||||
| 	flow->pkt_count = 1; | ||||
| 	flow->last_update = time; | ||||
|  | ||||
| 	goto out; | ||||
| } | ||||
|  | ||||
| static __always_inline void | ||||
| parse_ipv4(struct __sk_buff *skb, __u32 *offset) | ||||
| { | ||||
| 	struct qosify_config *config; | ||||
| 	struct qosify_ip_map_val *ip_val; | ||||
| 	const __u32 zero_port = 0; | ||||
| 	struct iphdr *iph; | ||||
| 	__u8 dscp = 0xff; | ||||
| 	__u8 *value; | ||||
| 	__u8 ipproto; | ||||
| 	int hdr_len; | ||||
| 	void *key; | ||||
| 	bool force; | ||||
|  | ||||
| 	config = get_config(); | ||||
|  | ||||
| 	iph = skb_ptr(skb, *offset); | ||||
| 	if (skb_check(skb, iph + 1)) | ||||
| 		return; | ||||
|  | ||||
| 	hdr_len = iph->ihl * 4; | ||||
| 	if (bpf_skb_pull_data(skb, *offset + hdr_len + sizeof(struct udphdr))) | ||||
| 		return; | ||||
|  | ||||
| 	iph = skb_ptr(skb, *offset); | ||||
| 	*offset += hdr_len; | ||||
|  | ||||
| 	if (skb_check(skb, (void *)(iph + 1))) | ||||
| 		return; | ||||
|  | ||||
| 	ipproto = iph->protocol; | ||||
| 	parse_l4proto(config, skb, *offset, ipproto, &dscp); | ||||
|  | ||||
| 	if (module_flags & QOSIFY_INGRESS) | ||||
| 		key = &iph->saddr; | ||||
| 	else | ||||
| 		key = &iph->daddr; | ||||
|  | ||||
| 	ip_val = bpf_map_lookup_elem(&ipv4_map, key); | ||||
| 	if (ip_val) { | ||||
| 		if (!ip_val->seen) | ||||
| 			ip_val->seen = 1; | ||||
| 		dscp = ip_val->dscp; | ||||
| 	} else if (dscp == 0xff) { | ||||
| 		/* use udp port 0 entry as fallback for non-tcp/udp */ | ||||
| 		value = bpf_map_lookup_elem(&udp_ports, &zero_port); | ||||
| 		if (value) | ||||
| 			dscp = *value; | ||||
| 	} | ||||
|  | ||||
| 	check_flow(config, skb, &dscp); | ||||
|  | ||||
| 	force = !(dscp & QOSIFY_DSCP_FALLBACK_FLAG); | ||||
| 	dscp &= GENMASK(5, 0); | ||||
|  | ||||
| 	ipv4_change_dsfield(iph, INET_ECN_MASK, dscp << 2, force); | ||||
| } | ||||
|  | ||||
| static __always_inline void | ||||
| parse_ipv6(struct __sk_buff *skb, __u32 *offset) | ||||
| { | ||||
| 	struct qosify_config *config; | ||||
| 	struct qosify_ip_map_val *ip_val; | ||||
| 	const __u32 zero_port = 0; | ||||
| 	struct ipv6hdr *iph; | ||||
| 	__u8 dscp = 0; | ||||
| 	__u8 *value; | ||||
| 	__u8 ipproto; | ||||
| 	void *key; | ||||
| 	bool force; | ||||
|  | ||||
| 	config = get_config(); | ||||
|  | ||||
| 	if (bpf_skb_pull_data(skb, *offset + sizeof(*iph) + sizeof(struct udphdr))) | ||||
| 		return; | ||||
|  | ||||
| 	iph = skb_ptr(skb, *offset); | ||||
| 	*offset += sizeof(*iph); | ||||
|  | ||||
| 	if (skb_check(skb, (void *)(iph + 1))) | ||||
| 		return; | ||||
|  | ||||
| 	ipproto = iph->nexthdr; | ||||
| 	if (module_flags & QOSIFY_INGRESS) | ||||
| 		key = &iph->saddr; | ||||
| 	else | ||||
| 		key = &iph->daddr; | ||||
|  | ||||
| 	parse_l4proto(config, skb, *offset, ipproto, &dscp); | ||||
|  | ||||
| 	ip_val = bpf_map_lookup_elem(&ipv6_map, key); | ||||
| 	if (ip_val) { | ||||
| 		if (!ip_val->seen) | ||||
| 			ip_val->seen = 1; | ||||
| 		dscp = ip_val->dscp; | ||||
| 	} else if (dscp == 0xff) { | ||||
| 		/* use udp port 0 entry as fallback for non-tcp/udp */ | ||||
| 		value = bpf_map_lookup_elem(&udp_ports, &zero_port); | ||||
| 		if (value) | ||||
| 			dscp = *value; | ||||
| 	} | ||||
|  | ||||
| 	check_flow(config, skb, &dscp); | ||||
|  | ||||
| 	force = !(dscp & QOSIFY_DSCP_FALLBACK_FLAG); | ||||
| 	dscp &= GENMASK(5, 0); | ||||
|  | ||||
| 	ipv6_change_dsfield(iph, INET_ECN_MASK, dscp << 2, force); | ||||
| } | ||||
|  | ||||
| SEC("classifier") | ||||
| int classify(struct __sk_buff *skb) | ||||
| { | ||||
| 	__u32 offset = 0; | ||||
| 	int type; | ||||
|  | ||||
| 	if (module_flags & QOSIFY_IP_ONLY) | ||||
| 		type = skb->protocol; | ||||
| 	else | ||||
| 		type = parse_ethernet(skb, &offset); | ||||
|  | ||||
| 	if (type == bpf_htons(ETH_P_IP)) | ||||
| 		parse_ipv4(skb, &offset); | ||||
| 	else if (type == bpf_htons(ETH_P_IPV6)) | ||||
| 		parse_ipv6(skb, &offset); | ||||
|  | ||||
| 	return TC_ACT_OK; | ||||
| } | ||||
|  | ||||
| char _license[] SEC("license") = "GPL"; | ||||
| @@ -1,39 +0,0 @@ | ||||
| // SPDX-License-Identifier: GPL-2.0+ | ||||
| /* | ||||
|  * Copyright (C) 2021 Felix Fietkau <nbd@nbd.name> | ||||
|  */ | ||||
| #ifndef __BPF_QOSIFY_H | ||||
| #define __BPF_QOSIFY_H | ||||
|  | ||||
| #ifndef QOSIFY_FLOW_BUCKET_SHIFT | ||||
| #define QOSIFY_FLOW_BUCKET_SHIFT	13 | ||||
| #endif | ||||
|  | ||||
| #define QOSIFY_FLOW_BUCKETS		(1 << QOSIFY_FLOW_BUCKET_SHIFT) | ||||
|  | ||||
| /* rodata per-instance flags */ | ||||
| #define QOSIFY_INGRESS			(1 << 0) | ||||
| #define QOSIFY_IP_ONLY			(1 << 1) | ||||
|  | ||||
|  | ||||
| #define QOSIFY_DSCP_FALLBACK_FLAG	(1 << 6) | ||||
| #define QOSIFY_DSCP_DEFAULT_FLAG	(1 << 7) | ||||
|  | ||||
| /* global config data */ | ||||
| struct qosify_config { | ||||
| 	uint8_t dscp_prio; | ||||
| 	uint8_t dscp_bulk; | ||||
| 	uint8_t dscp_icmp; | ||||
|  | ||||
| 	uint8_t bulk_trigger_timeout; | ||||
| 	uint16_t bulk_trigger_pps; | ||||
|  | ||||
| 	uint16_t prio_max_avg_pkt_len; | ||||
| }; | ||||
|  | ||||
| struct qosify_ip_map_val { | ||||
| 	uint8_t dscp; /* must be first */ | ||||
| 	uint8_t seen; | ||||
| }; | ||||
|  | ||||
| #endif | ||||
| @@ -1,95 +0,0 @@ | ||||
| // SPDX-License-Identifier: GPL-2.0+ | ||||
| /* | ||||
|  * Copyright (C) 2021 Felix Fietkau <nbd@nbd.name> | ||||
|  */ | ||||
| #ifndef __QOS_CLASSIFY_H | ||||
| #define __QOS_CLASSIFY_H | ||||
|  | ||||
| #include <stdbool.h> | ||||
| #include <regex.h> | ||||
|  | ||||
| #include <bpf/bpf.h> | ||||
| #include <bpf/libbpf.h> | ||||
|  | ||||
| #include "qosify-bpf.h" | ||||
|  | ||||
| #include <libubox/utils.h> | ||||
| #include <libubox/avl.h> | ||||
| #include <libubox/blobmsg.h> | ||||
| #include <libubox/ulog.h> | ||||
|  | ||||
| #include <netinet/in.h> | ||||
|  | ||||
| #define CLASSIFY_PROG_PATH	"/lib/bpf/qosify-bpf.o" | ||||
| #define CLASSIFY_PIN_PATH	"/sys/fs/bpf/qosify" | ||||
| #define CLASSIFY_DATA_PATH	"/sys/fs/bpf/qosify_data" | ||||
|  | ||||
| enum qosify_map_id { | ||||
| 	CL_MAP_TCP_PORTS, | ||||
| 	CL_MAP_UDP_PORTS, | ||||
| 	CL_MAP_IPV4_ADDR, | ||||
| 	CL_MAP_IPV6_ADDR, | ||||
| 	CL_MAP_CONFIG, | ||||
| 	CL_MAP_DNS, | ||||
| 	__CL_MAP_MAX, | ||||
| }; | ||||
|  | ||||
| struct qosify_map_data { | ||||
| 	enum qosify_map_id id; | ||||
|  | ||||
| 	bool file : 1; | ||||
| 	bool user : 1; | ||||
|  | ||||
| 	uint8_t dscp; | ||||
| 	uint8_t file_dscp; | ||||
|  | ||||
| 	union { | ||||
| 		uint32_t port; | ||||
| 		struct in_addr ip; | ||||
| 		struct in6_addr ip6; | ||||
| 		struct { | ||||
| 			const char *pattern; | ||||
| 			regex_t regex; | ||||
| 		} dns; | ||||
| 	} addr; | ||||
| }; | ||||
|  | ||||
| struct qosify_map_entry { | ||||
| 	struct avl_node avl; | ||||
|  | ||||
| 	uint32_t timeout; | ||||
|  | ||||
| 	struct qosify_map_data data; | ||||
| }; | ||||
|  | ||||
|  | ||||
| extern int qosify_map_timeout; | ||||
| extern int qosify_active_timeout; | ||||
| extern struct qosify_config config; | ||||
|  | ||||
| int qosify_loader_init(void); | ||||
|  | ||||
| int qosify_map_init(void); | ||||
| int qosify_map_dscp_value(const char *val); | ||||
| int qosify_map_load_file(const char *file); | ||||
| int qosify_map_set_entry(enum qosify_map_id id, bool file, const char *str, uint8_t dscp); | ||||
| void qosify_map_reload(void); | ||||
| void qosify_map_clear_files(void); | ||||
| void qosify_map_gc(void); | ||||
| void qosify_map_dump(struct blob_buf *b); | ||||
| void qosify_map_set_dscp_default(enum qosify_map_id id, uint8_t val); | ||||
| void qosify_map_reset_config(void); | ||||
| void qosify_map_update_config(void); | ||||
| int qosify_map_add_dns_host(const char *host, const char *addr, const char *type, int ttl); | ||||
|  | ||||
| int qosify_iface_init(void); | ||||
| void qosify_iface_config_update(struct blob_attr *ifaces, struct blob_attr *devs); | ||||
| void qosify_iface_check(void); | ||||
| void qosify_iface_status(struct blob_buf *b); | ||||
| void qosify_iface_stop(void); | ||||
|  | ||||
| int qosify_ubus_init(void); | ||||
| void qosify_ubus_stop(void); | ||||
| int qosify_ubus_check_interface(const char *name, char *ifname, int ifname_len); | ||||
|  | ||||
| #endif | ||||
| @@ -1,416 +0,0 @@ | ||||
| // SPDX-License-Identifier: GPL-2.0+ | ||||
| /* | ||||
|  * Copyright (C) 2021 Felix Fietkau <nbd@nbd.name> | ||||
|  */ | ||||
| #include <libubus.h> | ||||
|  | ||||
| #include "qosify.h" | ||||
|  | ||||
| static struct blob_buf b; | ||||
|  | ||||
| static int | ||||
| qosify_ubus_add_array(struct blob_attr *attr, uint8_t val, enum qosify_map_id id) | ||||
| { | ||||
| 	struct blob_attr *cur; | ||||
| 	int rem; | ||||
|  | ||||
| 	if (blobmsg_check_array(attr, BLOBMSG_TYPE_STRING) < 0) | ||||
| 		return UBUS_STATUS_INVALID_ARGUMENT; | ||||
|  | ||||
| 	blobmsg_for_each_attr(cur, attr, rem) | ||||
| 		qosify_map_set_entry(id, false, blobmsg_get_string(cur), val); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int | ||||
| qosify_ubus_set_files(struct blob_attr *attr) | ||||
| { | ||||
| 	struct blob_attr *cur; | ||||
| 	int rem; | ||||
|  | ||||
| 	if (blobmsg_check_array(attr, BLOBMSG_TYPE_STRING) < 0) | ||||
| 		return UBUS_STATUS_INVALID_ARGUMENT; | ||||
|  | ||||
| 	qosify_map_clear_files(); | ||||
|  | ||||
| 	blobmsg_for_each_attr(cur, attr, rem) | ||||
| 		qosify_map_load_file(blobmsg_get_string(cur)); | ||||
|  | ||||
| 	qosify_map_gc(); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| enum { | ||||
| 	CL_ADD_DSCP, | ||||
| 	CL_ADD_TIMEOUT, | ||||
| 	CL_ADD_IPV4, | ||||
| 	CL_ADD_IPV6, | ||||
| 	CL_ADD_TCP_PORT, | ||||
| 	CL_ADD_UDP_PORT, | ||||
| 	CL_ADD_DNS, | ||||
| 	__CL_ADD_MAX | ||||
| }; | ||||
|  | ||||
| static const struct blobmsg_policy qosify_add_policy[__CL_ADD_MAX] = { | ||||
| 	[CL_ADD_DSCP] = { "dscp", BLOBMSG_TYPE_STRING }, | ||||
| 	[CL_ADD_TIMEOUT] = { "timeout", BLOBMSG_TYPE_INT32 }, | ||||
| 	[CL_ADD_IPV4] = { "ipv4", BLOBMSG_TYPE_ARRAY }, | ||||
| 	[CL_ADD_IPV6] = { "ipv6", BLOBMSG_TYPE_ARRAY }, | ||||
| 	[CL_ADD_TCP_PORT] = { "tcp_port", BLOBMSG_TYPE_ARRAY }, | ||||
| 	[CL_ADD_UDP_PORT] = { "udp_port", BLOBMSG_TYPE_ARRAY }, | ||||
| 	[CL_ADD_DNS] = { "dns", BLOBMSG_TYPE_ARRAY }, | ||||
| }; | ||||
|  | ||||
|  | ||||
| static int | ||||
| qosify_ubus_reload(struct ubus_context *ctx, struct ubus_object *obj, | ||||
| 		   struct ubus_request_data *req, const char *method, | ||||
| 		   struct blob_attr *msg) | ||||
| { | ||||
| 	qosify_map_reload(); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int | ||||
| qosify_ubus_add(struct ubus_context *ctx, struct ubus_object *obj, | ||||
| 		struct ubus_request_data *req, const char *method, | ||||
| 		struct blob_attr *msg) | ||||
| { | ||||
| 	int prev_timemout = qosify_map_timeout; | ||||
| 	struct blob_attr *tb[__CL_ADD_MAX]; | ||||
| 	struct blob_attr *cur; | ||||
| 	int dscp = -1; | ||||
| 	int ret; | ||||
|  | ||||
| 	blobmsg_parse(qosify_add_policy, __CL_ADD_MAX, tb, | ||||
| 		      blobmsg_data(msg), blobmsg_len(msg)); | ||||
|  | ||||
| 	if (!strcmp(method, "add")) { | ||||
| 		if ((cur = tb[CL_ADD_DSCP]) != NULL) | ||||
| 			dscp = qosify_map_dscp_value(blobmsg_get_string(cur)); | ||||
| 		else | ||||
| 			return UBUS_STATUS_INVALID_ARGUMENT; | ||||
| 		if (dscp < 0) | ||||
| 			return UBUS_STATUS_INVALID_ARGUMENT; | ||||
|  | ||||
| 		if ((cur = tb[CL_ADD_TIMEOUT]) != NULL) | ||||
| 			qosify_map_timeout = blobmsg_get_u32(cur); | ||||
| 	} else { | ||||
| 		dscp = 0xff; | ||||
| 	} | ||||
|  | ||||
| 	if ((cur = tb[CL_ADD_IPV4]) != NULL && | ||||
| 	    (ret = qosify_ubus_add_array(cur, dscp, CL_MAP_IPV4_ADDR) != 0)) | ||||
| 		return ret; | ||||
|  | ||||
| 	if ((cur = tb[CL_ADD_IPV6]) != NULL && | ||||
| 	    (ret = qosify_ubus_add_array(cur, dscp, CL_MAP_IPV6_ADDR) != 0)) | ||||
| 		return ret; | ||||
|  | ||||
| 	if ((cur = tb[CL_ADD_TCP_PORT]) != NULL && | ||||
| 	    (ret = qosify_ubus_add_array(cur, dscp, CL_MAP_TCP_PORTS) != 0)) | ||||
| 		return ret; | ||||
|  | ||||
| 	if ((cur = tb[CL_ADD_UDP_PORT]) != NULL && | ||||
| 	    (ret = qosify_ubus_add_array(cur, dscp, CL_MAP_UDP_PORTS) != 0)) | ||||
| 		return ret; | ||||
|  | ||||
| 	if ((cur = tb[CL_ADD_DNS]) != NULL && | ||||
| 	    (ret = qosify_ubus_add_array(cur, dscp, CL_MAP_DNS) != 0)) | ||||
| 		return ret; | ||||
|  | ||||
| 	qosify_map_timeout = prev_timemout; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| enum { | ||||
| 	CL_CONFIG_RESET, | ||||
| 	CL_CONFIG_FILES, | ||||
| 	CL_CONFIG_TIMEOUT, | ||||
| 	CL_CONFIG_DSCP_UDP, | ||||
| 	CL_CONFIG_DSCP_TCP, | ||||
| 	CL_CONFIG_DSCP_PRIO, | ||||
| 	CL_CONFIG_DSCP_BULK, | ||||
| 	CL_CONFIG_DSCP_ICMP, | ||||
| 	CL_CONFIG_BULK_TIMEOUT, | ||||
| 	CL_CONFIG_BULK_PPS, | ||||
| 	CL_CONFIG_PRIO_PKT_LEN, | ||||
| 	CL_CONFIG_INTERFACES, | ||||
| 	CL_CONFIG_DEVICES, | ||||
| 	__CL_CONFIG_MAX | ||||
| }; | ||||
|  | ||||
| static const struct blobmsg_policy qosify_config_policy[__CL_CONFIG_MAX] = { | ||||
| 	[CL_CONFIG_RESET] = { "reset", BLOBMSG_TYPE_BOOL }, | ||||
| 	[CL_CONFIG_FILES] = { "files", BLOBMSG_TYPE_ARRAY }, | ||||
| 	[CL_CONFIG_TIMEOUT] = { "timeout", BLOBMSG_TYPE_INT32 }, | ||||
| 	[CL_CONFIG_DSCP_UDP] = { "dscp_default_udp", BLOBMSG_TYPE_STRING }, | ||||
| 	[CL_CONFIG_DSCP_TCP] = { "dscp_default_tcp", BLOBMSG_TYPE_STRING }, | ||||
| 	[CL_CONFIG_DSCP_PRIO] = { "dscp_prio", BLOBMSG_TYPE_STRING }, | ||||
| 	[CL_CONFIG_DSCP_BULK] = { "dscp_bulk", BLOBMSG_TYPE_STRING }, | ||||
| 	[CL_CONFIG_DSCP_ICMP] = { "dscp_icmp", BLOBMSG_TYPE_STRING }, | ||||
| 	[CL_CONFIG_BULK_TIMEOUT] = { "bulk_trigger_timeout", BLOBMSG_TYPE_INT32 }, | ||||
| 	[CL_CONFIG_BULK_PPS] = { "bulk_trigger_pps", BLOBMSG_TYPE_INT32 }, | ||||
| 	[CL_CONFIG_PRIO_PKT_LEN] = { "prio_max_avg_pkt_len", BLOBMSG_TYPE_INT32 }, | ||||
| 	[CL_CONFIG_INTERFACES] = { "interfaces", BLOBMSG_TYPE_TABLE }, | ||||
| 	[CL_CONFIG_DEVICES] = { "devices", BLOBMSG_TYPE_TABLE }, | ||||
| }; | ||||
|  | ||||
| static int __set_dscp(uint8_t *dest, struct blob_attr *attr, bool reset) | ||||
| { | ||||
| 	int dscp; | ||||
|  | ||||
| 	if (reset) | ||||
| 		*dest = 0xff; | ||||
|  | ||||
| 	if (!attr) | ||||
| 		return 0; | ||||
|  | ||||
| 	dscp = qosify_map_dscp_value(blobmsg_get_string(attr)); | ||||
| 	if (dscp < 0) | ||||
| 		return -1; | ||||
|  | ||||
| 	*dest = dscp; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int | ||||
| qosify_ubus_config(struct ubus_context *ctx, struct ubus_object *obj, | ||||
| 		   struct ubus_request_data *req, const char *method, | ||||
| 		   struct blob_attr *msg) | ||||
| { | ||||
| 	struct blob_attr *tb[__CL_CONFIG_MAX]; | ||||
| 	struct blob_attr *cur; | ||||
| 	uint8_t dscp; | ||||
| 	bool reset = false; | ||||
| 	int ret; | ||||
|  | ||||
| 	blobmsg_parse(qosify_config_policy, __CL_CONFIG_MAX, tb, | ||||
| 		      blobmsg_data(msg), blobmsg_len(msg)); | ||||
|  | ||||
| 	if ((cur = tb[CL_CONFIG_RESET]) != NULL) | ||||
| 		reset = blobmsg_get_bool(cur); | ||||
|  | ||||
| 	if (reset) | ||||
| 		qosify_map_reset_config(); | ||||
|  | ||||
| 	if ((cur = tb[CL_CONFIG_TIMEOUT]) != NULL) | ||||
| 		qosify_map_timeout = blobmsg_get_u32(cur); | ||||
|  | ||||
| 	if ((cur = tb[CL_CONFIG_FILES]) != NULL && | ||||
| 	    (ret = qosify_ubus_set_files(cur) != 0)) | ||||
| 		return ret; | ||||
|  | ||||
| 	__set_dscp(&dscp, tb[CL_CONFIG_DSCP_UDP], true); | ||||
| 	if (dscp != 0xff) | ||||
| 		qosify_map_set_dscp_default(CL_MAP_UDP_PORTS, dscp); | ||||
|  | ||||
| 	__set_dscp(&dscp, tb[CL_CONFIG_DSCP_TCP], true); | ||||
| 	if (dscp != 0xff) | ||||
| 		qosify_map_set_dscp_default(CL_MAP_TCP_PORTS, dscp); | ||||
|  | ||||
| 	__set_dscp(&config.dscp_prio, tb[CL_CONFIG_DSCP_PRIO], reset); | ||||
| 	__set_dscp(&config.dscp_bulk, tb[CL_CONFIG_DSCP_BULK], reset); | ||||
| 	__set_dscp(&config.dscp_icmp, tb[CL_CONFIG_DSCP_ICMP], reset); | ||||
|  | ||||
| 	if ((cur = tb[CL_CONFIG_BULK_TIMEOUT]) != NULL) | ||||
| 		config.bulk_trigger_timeout = blobmsg_get_u32(cur); | ||||
|  | ||||
| 	if ((cur = tb[CL_CONFIG_BULK_PPS]) != NULL) | ||||
| 		config.bulk_trigger_pps = blobmsg_get_u32(cur); | ||||
|  | ||||
| 	if ((cur = tb[CL_CONFIG_PRIO_PKT_LEN]) != NULL) | ||||
| 		config.prio_max_avg_pkt_len = blobmsg_get_u32(cur); | ||||
|  | ||||
| 	qosify_map_update_config(); | ||||
|  | ||||
| 	qosify_iface_config_update(tb[CL_CONFIG_INTERFACES], tb[CL_CONFIG_DEVICES]); | ||||
|  | ||||
| 	qosify_iface_check(); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int | ||||
| qosify_ubus_dump(struct ubus_context *ctx, struct ubus_object *obj, | ||||
| 		 struct ubus_request_data *req, const char *method, | ||||
| 		 struct blob_attr *msg) | ||||
| { | ||||
| 	blob_buf_init(&b, 0); | ||||
| 	qosify_map_dump(&b); | ||||
| 	ubus_send_reply(ctx, req, b.head); | ||||
| 	blob_buf_free(&b); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int | ||||
| qosify_ubus_status(struct ubus_context *ctx, struct ubus_object *obj, | ||||
| 		 struct ubus_request_data *req, const char *method, | ||||
| 		 struct blob_attr *msg) | ||||
| { | ||||
| 	blob_buf_init(&b, 0); | ||||
| 	qosify_iface_status(&b); | ||||
| 	ubus_send_reply(ctx, req, b.head); | ||||
| 	blob_buf_free(&b); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int | ||||
| qosify_ubus_check_devices(struct ubus_context *ctx, struct ubus_object *obj, | ||||
| 			  struct ubus_request_data *req, const char *method, | ||||
| 			  struct blob_attr *msg) | ||||
| { | ||||
| 	qosify_iface_check(); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| enum { | ||||
| 	CL_DNS_HOST_NAME, | ||||
| 	CL_DNS_HOST_TYPE, | ||||
| 	CL_DNS_HOST_ADDR, | ||||
| 	CL_DNS_HOST_TTL, | ||||
| 	__CL_DNS_HOST_MAX | ||||
| }; | ||||
|  | ||||
| static const struct blobmsg_policy qosify_dns_policy[__CL_DNS_HOST_MAX] = { | ||||
| 	[CL_DNS_HOST_NAME] = { "name", BLOBMSG_TYPE_STRING }, | ||||
| 	[CL_DNS_HOST_TYPE] = { "type", BLOBMSG_TYPE_STRING }, | ||||
| 	[CL_DNS_HOST_ADDR] = { "address", BLOBMSG_TYPE_STRING }, | ||||
| 	[CL_DNS_HOST_TTL] = { "ttl", BLOBMSG_TYPE_INT32 }, | ||||
| }; | ||||
|  | ||||
| static int | ||||
| qosify_ubus_add_dns_host(struct ubus_context *ctx, struct ubus_object *obj, | ||||
| 			 struct ubus_request_data *req, const char *method, | ||||
| 			 struct blob_attr *msg) | ||||
| { | ||||
| 	struct blob_attr *tb[__CL_DNS_HOST_MAX]; | ||||
| 	struct blob_attr *cur; | ||||
| 	uint32_t ttl = 0; | ||||
|  | ||||
| 	blobmsg_parse(qosify_dns_policy, __CL_DNS_HOST_MAX, tb, | ||||
| 		      blobmsg_data(msg), blobmsg_len(msg)); | ||||
|  | ||||
| 	if (!tb[CL_DNS_HOST_NAME] || !tb[CL_DNS_HOST_TYPE] || | ||||
| 	    !tb[CL_DNS_HOST_ADDR]) | ||||
| 		return UBUS_STATUS_INVALID_ARGUMENT; | ||||
|  | ||||
| 	if ((cur = tb[CL_DNS_HOST_TTL]) != NULL) | ||||
| 		ttl = blobmsg_get_u32(cur); | ||||
|  | ||||
| 	if (qosify_map_add_dns_host(blobmsg_get_string(tb[CL_DNS_HOST_NAME]), | ||||
| 				    blobmsg_get_string(tb[CL_DNS_HOST_ADDR]), | ||||
| 				    blobmsg_get_string(tb[CL_DNS_HOST_TYPE]), | ||||
| 				    ttl)) | ||||
| 		return UBUS_STATUS_INVALID_ARGUMENT; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static const struct ubus_method qosify_methods[] = { | ||||
| 	UBUS_METHOD_NOARG("reload", qosify_ubus_reload), | ||||
| 	UBUS_METHOD("add", qosify_ubus_add, qosify_add_policy), | ||||
| 	UBUS_METHOD_MASK("remove", qosify_ubus_add, qosify_add_policy, | ||||
| 			 ((1 << __CL_ADD_MAX) - 1) & ~(1 << CL_ADD_DSCP)), | ||||
| 	UBUS_METHOD("config", qosify_ubus_config, qosify_config_policy), | ||||
| 	UBUS_METHOD_NOARG("dump", qosify_ubus_dump), | ||||
| 	UBUS_METHOD_NOARG("status", qosify_ubus_status), | ||||
| 	UBUS_METHOD("add_dns_host", qosify_ubus_add_dns_host, qosify_dns_policy), | ||||
| 	UBUS_METHOD_NOARG("check_devices", qosify_ubus_check_devices), | ||||
| }; | ||||
|  | ||||
| static struct ubus_object_type qosify_object_type = | ||||
| 	UBUS_OBJECT_TYPE("qosify", qosify_methods); | ||||
|  | ||||
| static struct ubus_object qosify_object = { | ||||
| 	.name = "qosify", | ||||
| 	.type = &qosify_object_type, | ||||
| 	.methods = qosify_methods, | ||||
| 	.n_methods = ARRAY_SIZE(qosify_methods), | ||||
| }; | ||||
|  | ||||
| static void | ||||
| ubus_connect_handler(struct ubus_context *ctx) | ||||
| { | ||||
| 	ubus_add_object(ctx, &qosify_object); | ||||
| } | ||||
|  | ||||
| static struct ubus_auto_conn conn; | ||||
|  | ||||
| int qosify_ubus_init(void) | ||||
| { | ||||
| 	conn.cb = ubus_connect_handler; | ||||
| 	ubus_auto_connect(&conn); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| void qosify_ubus_stop(void) | ||||
| { | ||||
| 	ubus_auto_shutdown(&conn); | ||||
| } | ||||
|  | ||||
| struct iface_req { | ||||
| 	char *name; | ||||
| 	int len; | ||||
| }; | ||||
|  | ||||
| static void | ||||
| netifd_if_cb(struct ubus_request *req, int type, struct blob_attr *msg) | ||||
| { | ||||
| 	struct iface_req *ifr = req->priv; | ||||
| 	enum { | ||||
| 		IFS_ATTR_UP, | ||||
| 		IFS_ATTR_DEV, | ||||
| 		__IFS_ATTR_MAX | ||||
| 	}; | ||||
| 	static const struct blobmsg_policy policy[__IFS_ATTR_MAX] = { | ||||
| 		[IFS_ATTR_UP] = { "up", BLOBMSG_TYPE_BOOL }, | ||||
| 		[IFS_ATTR_DEV] = { "l3_device", BLOBMSG_TYPE_STRING }, | ||||
| 	}; | ||||
| 	struct blob_attr *tb[__IFS_ATTR_MAX]; | ||||
|  | ||||
| 	blobmsg_parse(policy, __IFS_ATTR_MAX, tb, blobmsg_data(msg), blobmsg_len(msg)); | ||||
|  | ||||
| 	if (!tb[IFS_ATTR_UP] || !tb[IFS_ATTR_DEV]) | ||||
| 		return; | ||||
|  | ||||
| 	if (!blobmsg_get_bool(tb[IFS_ATTR_UP])) | ||||
| 		return; | ||||
|  | ||||
| 	snprintf(ifr->name, ifr->len, "%s", blobmsg_get_string(tb[IFS_ATTR_DEV])); | ||||
| } | ||||
|  | ||||
| int qosify_ubus_check_interface(const char *name, char *ifname, int ifname_len) | ||||
| { | ||||
| 	struct iface_req req = { ifname, ifname_len }; | ||||
| 	char *obj_name = "network.interface."; | ||||
| 	uint32_t id; | ||||
|  | ||||
| #define PREFIX "network.interface." | ||||
| 	obj_name = alloca(sizeof(PREFIX) + strlen(name) + 1); | ||||
| 	sprintf(obj_name, PREFIX "%s", name); | ||||
| #undef PREFIX | ||||
|  | ||||
| 	ifname[0] = 0; | ||||
|  | ||||
| 	if (ubus_lookup_id(&conn.ctx, obj_name, &id)) | ||||
| 		return -1; | ||||
|  | ||||
| 	ubus_invoke(&conn.ctx, id, "status", b.head, netifd_if_cb, &req, 1000); | ||||
|  | ||||
| 	if (!ifname[0]) | ||||
| 		return -1; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
							
								
								
									
										25
									
								
								feeds/ucentral/radius-gw-proxy/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								feeds/ucentral/radius-gw-proxy/Makefile
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| include $(TOPDIR)/rules.mk | ||||
|  | ||||
| PKG_NAME:=radius-gw-proxy | ||||
| PKG_RELEASE:=1 | ||||
|  | ||||
| PKG_LICENSE:=BSD-3-Clause | ||||
| PKG_MAINTAINER:=John Crispin <john@phrozen.org> | ||||
|  | ||||
| include $(INCLUDE_DIR)/package.mk | ||||
| include $(INCLUDE_DIR)/cmake.mk | ||||
|  | ||||
| define Package/radius-gw-proxy | ||||
|   SECTION:=ucentral | ||||
|   CATEGORY:=uCentral | ||||
|   TITLE:=uCentral Gateway radius-gw-proxy | ||||
|   DEPENDS:=+libubox +libubus | ||||
| endef | ||||
|  | ||||
| define Package/radius-gw-proxy/install | ||||
| 	$(INSTALL_DIR) $(1)/usr/sbin | ||||
| 	$(INSTALL_BIN) $(PKG_BUILD_DIR)/radius-gw-proxy $(1)/usr/sbin/ | ||||
| 	$(CP) ./files/* $(1) | ||||
| endef | ||||
|  | ||||
| $(eval $(call BuildPackage,radius-gw-proxy)) | ||||
							
								
								
									
										11
									
								
								feeds/ucentral/radius-gw-proxy/files/etc/init.d/radius-gw-proxy
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										11
									
								
								feeds/ucentral/radius-gw-proxy/files/etc/init.d/radius-gw-proxy
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| #!/bin/sh /etc/rc.common | ||||
|  | ||||
| START=99 | ||||
|  | ||||
| USE_PROCD=1 | ||||
|  | ||||
| start_service() { | ||||
| 	procd_open_instance | ||||
| 	procd_set_param command "/usr/sbin/radius-gw-proxy" | ||||
| 	procd_close_instance | ||||
| } | ||||
							
								
								
									
										30
									
								
								feeds/ucentral/radius-gw-proxy/src/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								feeds/ucentral/radius-gw-proxy/src/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | ||||
| cmake_minimum_required(VERSION 2.6) | ||||
|  | ||||
| PROJECT(radius-gw-proxy C) | ||||
|  | ||||
| ADD_DEFINITIONS(-Wall -Werror) | ||||
| IF(CMAKE_C_COMPILER_VERSION VERSION_GREATER 6) | ||||
| 	ADD_DEFINITIONS(-Wextra -Werror=implicit-function-declaration) | ||||
| 	ADD_DEFINITIONS(-Wformat -Werror=format-security -Werror=format-nonliteral) | ||||
| ENDIF() | ||||
| ADD_DEFINITIONS(-Os -std=gnu99 -g3 -Wmissing-declarations -Wno-unused-parameter -Wno-strict-aliasing) | ||||
|  | ||||
| SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") | ||||
|  | ||||
| SET(SOURCES main.c) | ||||
|  | ||||
| FIND_LIBRARY(ubus NAMES ubus) | ||||
| FIND_LIBRARY(ubox NAMES ubox) | ||||
|  | ||||
| FIND_PATH(ubox_include_dir libubox/uloop.h) | ||||
| FIND_PATH(ubus_include_dir NAMES libubus.h) | ||||
|  | ||||
| INCLUDE_DIRECTORIES(${ubox_include_dir} ${ubus_include_dir}) | ||||
|  | ||||
| ADD_EXECUTABLE(radius-gw-proxy ${SOURCES}) | ||||
|  | ||||
| TARGET_LINK_LIBRARIES(radius-gw-proxy ${ubox} ${ubus}) | ||||
|  | ||||
| INSTALL(TARGETS radius-gw-proxy | ||||
| 	RUNTIME DESTINATION sbin | ||||
| ) | ||||
							
								
								
									
										356
									
								
								feeds/ucentral/radius-gw-proxy/src/main.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										356
									
								
								feeds/ucentral/radius-gw-proxy/src/main.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,356 @@ | ||||
| #define _GNU_SOURCE | ||||
|  | ||||
| #include <sys/types.h> | ||||
| #include <sys/socket.h> | ||||
| #include <netinet/in.h> | ||||
| #include <net/if.h> | ||||
| #include <arpa/inet.h> | ||||
| #include <errno.h> | ||||
| #include <unistd.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
|  | ||||
| #include <libubox/uloop.h> | ||||
| #include <libubox/usock.h> | ||||
|  | ||||
| #include <libubox/avl.h> | ||||
| #include <libubox/avl-cmp.h> | ||||
|  | ||||
| #include <libubus.h> | ||||
|  | ||||
| #define RAD_PROX_BUFLEN		(4 * 1024) | ||||
|  | ||||
| #define TLV_STATION_ID		30 | ||||
| #define TLV_VENDOR		26 | ||||
| #define TLV_TIP_SERVER_V4	2 | ||||
|  | ||||
| #define TIP_VENDOR		58888 | ||||
|  | ||||
| enum socket_type { | ||||
| 	RADIUS_AUTH = 0, | ||||
| 	RADIUS_ACCT, | ||||
| 	RADIUS_DAS | ||||
| }; | ||||
|  | ||||
| struct radius_socket { | ||||
| 	struct uloop_fd fd; | ||||
| 	enum socket_type type; | ||||
| }; | ||||
|  | ||||
| struct radius_header { | ||||
| 	uint8_t code; | ||||
| 	uint8_t id; | ||||
| 	uint16_t len; | ||||
| 	char auth[16]; | ||||
| 	char avp[]; | ||||
| }; | ||||
|  | ||||
| struct radius_tlv { | ||||
| 	uint8_t id; | ||||
| 	uint8_t len; | ||||
| 	char data[]; | ||||
| }; | ||||
|  | ||||
| struct radius_station_id { | ||||
| 	char id[256]; | ||||
| 	enum socket_type type; | ||||
| }; | ||||
|  | ||||
| struct radius_station { | ||||
| 	struct avl_node avl; | ||||
| 	struct radius_station_id key; | ||||
| 	int port; | ||||
| }; | ||||
|  | ||||
| static struct ubus_auto_conn conn; | ||||
| static uint32_t ucentral; | ||||
| static struct blob_buf b; | ||||
|  | ||||
| static int | ||||
| avl_memcmp(const void *k1, const void *k2, void *ptr) | ||||
| { | ||||
| 	return memcmp(k1, k2, sizeof(struct radius_station_id)); | ||||
| } | ||||
|  | ||||
| static AVL_TREE(radius_stations, avl_memcmp, false, NULL); | ||||
|  | ||||
| static void | ||||
| radius_station_add(char *id, int port, enum socket_type type) | ||||
| { | ||||
| 	struct radius_station *station; | ||||
| 	struct radius_station_id key = { .type = type }; | ||||
|  | ||||
| 	strcpy(key.id, id); | ||||
| 	station = avl_find_element(&radius_stations, &key, station, avl); | ||||
|  | ||||
| 	if (!station) { | ||||
| 		printf("new station/port, adding to avl tree\n"); | ||||
| 		station = malloc(sizeof(*station)); | ||||
| 		memset(station, 0, sizeof(*station)); | ||||
| 		strcpy(station->key.id, id); | ||||
| 		station->key.type = type; | ||||
| 		station->avl.key = &station->key; | ||||
| 		avl_insert(&radius_stations, &station->avl); | ||||
| 	} | ||||
| 	station->port = port; | ||||
| } | ||||
|  | ||||
|  | ||||
| static char * | ||||
| b64(char *src, int len) | ||||
| { | ||||
| 	char *dst; | ||||
| 	int ret; | ||||
|  | ||||
| 	if (!src) | ||||
| 		return NULL; | ||||
| 	dst = malloc(len * 4); | ||||
| 	ret = b64_encode(src, len, dst, len * 4); | ||||
| 	if (ret < 1) { | ||||
| 		free(dst); | ||||
| 		return NULL; | ||||
| 	} | ||||
| 	return dst; | ||||
| } | ||||
|  | ||||
| static void | ||||
| radius_forward(char *buf, char *server, enum socket_type type) | ||||
| { | ||||
| 	struct radius_header *hdr = (struct radius_header *) buf; | ||||
| 	struct ubus_request async = { }; | ||||
| 	char *data = b64(buf, hdr->len); | ||||
|  | ||||
| 	if (!data) | ||||
| 		return; | ||||
|  | ||||
| 	blob_buf_init(&b, 0); | ||||
| 	switch (type) { | ||||
| 	case RADIUS_AUTH: | ||||
| 		blobmsg_add_string(&b, "radius", "auth"); | ||||
| 		break; | ||||
| 	case RADIUS_ACCT: | ||||
| 		blobmsg_add_string(&b, "radius", "acct"); | ||||
| 		break; | ||||
| 	default: | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	blobmsg_add_string(&b, "data", data); | ||||
| 	blobmsg_add_string(&b, "dst", server); | ||||
|  | ||||
| 	ubus_invoke_async(&conn.ctx, ucentral, "radius", b.head, &async); | ||||
| 	ubus_abort_request(&conn.ctx, &async); | ||||
|  | ||||
| 	free(data); | ||||
| } | ||||
|  | ||||
| static int | ||||
| radius_parse(char *buf, int len, int port, enum socket_type type) | ||||
| { | ||||
| 	struct radius_header *hdr = (struct radius_header *) buf; | ||||
| 	struct radius_tlv *station_id = NULL; | ||||
| 	char station_id_str[256] = {}; | ||||
| 	char server_ip_str[256] = {}; | ||||
| 	void *avp = hdr->avp; | ||||
|  | ||||
| 	hdr->len = ntohs(hdr->len); | ||||
|  | ||||
| 	if (hdr->len != len) { | ||||
| 		printf("invalid header length\n"); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	printf("\tcode:%d, id:%d, len:%d\n", hdr->code, hdr->id, hdr->len); | ||||
|  | ||||
| 	len -= sizeof(*hdr); | ||||
|  | ||||
| 	while (len > 0) { | ||||
| 		struct radius_tlv *tlv = (struct radius_tlv *)avp; | ||||
|  | ||||
| 		if (len < tlv->len) { | ||||
| 			printf("invalid TLV length\n"); | ||||
| 			return -1; | ||||
| 		} | ||||
|  | ||||
| 		if (tlv->id == TLV_STATION_ID) | ||||
| 			station_id = tlv; | ||||
| 		if (tlv->id == TLV_VENDOR && ntohl(*(uint32_t *) tlv->data) == TIP_VENDOR) { | ||||
| 			struct radius_tlv *vendor = (struct radius_tlv *) &tlv->data[6]; | ||||
|  | ||||
| 			if (vendor->id == TLV_TIP_SERVER_V4) | ||||
| 				strncpy(server_ip_str, vendor->data, vendor->len - 2); | ||||
| 		} | ||||
|  | ||||
| 		printf("\tID:%d, len:%d\n", tlv->id, tlv->len); | ||||
| 		avp += tlv->len; | ||||
| 		len -= tlv->len; | ||||
| 	} | ||||
|  | ||||
| 	if (!station_id) { | ||||
| 		printf("no station ID found\n"); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	if (!*server_ip_str) { | ||||
| 		printf("no server ip found\n"); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	memcpy(station_id_str, station_id->data, station_id->len - 2); | ||||
| 	printf("\tcalling station id:%s, server ip:%s\n", station_id_str, server_ip_str); | ||||
| 	radius_station_add(station_id_str, port, type); | ||||
|  | ||||
| 	radius_forward(buf, server_ip_str, type); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static void | ||||
| sock_recv(struct uloop_fd *u, unsigned int events) | ||||
| { | ||||
| 	static char buf[RAD_PROX_BUFLEN]; | ||||
| 	static char cmsg_buf[( CMSG_SPACE(sizeof(struct in_pktinfo)) + sizeof(int)) + 1]; | ||||
| 	static struct sockaddr_in sin; | ||||
| 	char addr_str[INET_ADDRSTRLEN]; | ||||
| 	static struct iovec iov = { | ||||
| 		.iov_base = buf, | ||||
| 		.iov_len = sizeof(buf) | ||||
| 	}; | ||||
| 	static struct msghdr msg = { | ||||
| 		.msg_name = &sin, | ||||
| 		.msg_namelen = sizeof(sin), | ||||
| 		.msg_iov = &iov, | ||||
| 		.msg_iovlen = 1, | ||||
| 		.msg_control = cmsg_buf, | ||||
| 		.msg_controllen = sizeof(cmsg_buf), | ||||
| 	}; | ||||
| 	struct cmsghdr *cmsg; | ||||
| 	struct radius_socket *sock = container_of(u, struct radius_socket, fd); | ||||
| 	int len; | ||||
|  | ||||
| 	do { | ||||
| 		struct in_pktinfo *pkti = NULL; | ||||
|  | ||||
| 		len = recvmsg(u->fd, &msg, 0); | ||||
| 		if (len < 0) { | ||||
| 			switch (errno) { | ||||
| 			case EAGAIN: | ||||
| 				return; | ||||
| 			case EINTR: | ||||
| 				continue; | ||||
| 			default: | ||||
| 				perror("recvmsg"); | ||||
| 				uloop_fd_delete(u); | ||||
| 				return; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { | ||||
| 			if (cmsg->cmsg_type != IP_PKTINFO) | ||||
| 				continue; | ||||
|  | ||||
| 			pkti = (struct in_pktinfo *) CMSG_DATA(cmsg); | ||||
| 		} | ||||
|  | ||||
| 		if (!pkti) { | ||||
| 			printf("Received packet without ifindex\n"); | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		inet_ntop(AF_INET, &sin.sin_addr, addr_str, sizeof(addr_str)); | ||||
| 		printf("RX: src:%s:%d, len=%d\n", addr_str, sin.sin_port, len); | ||||
| 		radius_parse(buf, len, sin.sin_port, sock->type); | ||||
| 	} while (1); | ||||
| } | ||||
|  | ||||
| static struct radius_socket * | ||||
| sock_open(char *port, enum socket_type type) | ||||
| { | ||||
| 	struct radius_socket *sock = malloc(sizeof(*sock)); | ||||
| 	int yes = 1; | ||||
|  | ||||
| 	if (!sock) | ||||
| 		return NULL; | ||||
|  | ||||
| 	memset(sock, 0, sizeof(*sock)); | ||||
|  | ||||
| 	sock->fd.fd = usock(USOCK_UDP | USOCK_SERVER | USOCK_NONBLOCK | | ||||
| 			    USOCK_NUMERIC | USOCK_IPV4ONLY, | ||||
| 			    "127.0.0.1", port); | ||||
| 	if (sock->fd.fd < 0) { | ||||
|                 perror("usock"); | ||||
| 		free(sock); | ||||
|                 return NULL; | ||||
|         } | ||||
|         if (setsockopt(sock->fd.fd, IPPROTO_IP, IP_PKTINFO, &yes, sizeof(yes)) < 0) | ||||
| 		perror("setsockopt(IP_PKTINFO)"); | ||||
|  | ||||
| 	sock->type = type; | ||||
| 	sock->fd.cb = sock_recv; | ||||
|  | ||||
| 	uloop_fd_add(&sock->fd, ULOOP_READ); | ||||
|  | ||||
| 	return sock; | ||||
| } | ||||
|  | ||||
| static void | ||||
| ubus_event_handler_cb(struct ubus_context *ctx,  struct ubus_event_handler *ev, | ||||
| 		      const char *type, struct blob_attr *msg) | ||||
| { | ||||
| 	enum { | ||||
| 		EVENT_ID, | ||||
| 		EVENT_PATH, | ||||
| 		__EVENT_MAX | ||||
| 	}; | ||||
|  | ||||
| 	static const struct blobmsg_policy status_policy[__EVENT_MAX] = { | ||||
| 		[EVENT_ID] = { .name = "id", .type = BLOBMSG_TYPE_INT32 }, | ||||
| 		[EVENT_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING }, | ||||
| 	}; | ||||
|  | ||||
| 	struct blob_attr *tb[__EVENT_MAX]; | ||||
| 	char *path; | ||||
| 	uint32_t id; | ||||
|  | ||||
| 	blobmsg_parse(status_policy, __EVENT_MAX, tb, blob_data(msg), blob_len(msg)); | ||||
|  | ||||
| 	if (!tb[EVENT_ID] || !tb[EVENT_PATH]) | ||||
| 		return; | ||||
|  | ||||
| 	path = blobmsg_get_string(tb[EVENT_PATH]); | ||||
| 	id = blobmsg_get_u32(tb[EVENT_ID]); | ||||
|  | ||||
| 	if (strcmp(path, "ucentral")) | ||||
| 		return; | ||||
| 	if (!strcmp("ubus.object.remove", type)) | ||||
| 		ucentral = 0; | ||||
| 	else | ||||
| 		ucentral = id; | ||||
| } | ||||
|  | ||||
| static struct ubus_event_handler ubus_event_handler = { .cb = ubus_event_handler_cb }; | ||||
|  | ||||
| static void | ||||
| ubus_connect_handler(struct ubus_context *ctx) | ||||
| { | ||||
| 	ubus_register_event_handler(ctx, &ubus_event_handler, "ubus.object.add"); | ||||
| 	ubus_register_event_handler(ctx, &ubus_event_handler, "ubus.object.remove"); | ||||
|  | ||||
| 	ubus_lookup_id(ctx, "ucentral", &ucentral); | ||||
| } | ||||
|  | ||||
| int main(int argc, char **argv) | ||||
| { | ||||
|  | ||||
| 	uloop_init(); | ||||
|  | ||||
| 	conn.cb = ubus_connect_handler; | ||||
| 	ubus_auto_connect(&conn); | ||||
|  | ||||
| 	sock_open("1812", RADIUS_AUTH); | ||||
| 	sock_open("1813", RADIUS_ACCT); | ||||
|  | ||||
| 	uloop_run(); | ||||
| 	uloop_end(); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
| @@ -101,6 +101,7 @@ deliface() { | ||||
|  | ||||
| found=0 | ||||
| find_ssid() { | ||||
| 	local ssid | ||||
| 	config_get ssid $1 ssid | ||||
| 	[ "$ssid" == "$2" ] || return | ||||
| 	found=1 | ||||
| @@ -119,7 +120,7 @@ addiface() { | ||||
| 	echo -n startup > /tmp/ratelimit.$iface | ||||
|  | ||||
| 	sleep 2 | ||||
| 	ssid=$(ubus call network.wireless status | jsonfilter -e '@[*].interfaces[@.ifname="'"$iface"'"].config.ssid') | ||||
| 	ssid=$(ubus call hostapd.$iface get_status | jsonfilter -e '@.ssid') | ||||
| 	[ -z "$ssid" ] && { | ||||
| 		rm /tmp/ratelimit.$iface | ||||
| 		logger "ratelimit: failed to lookup ssid" | ||||
|   | ||||
| @@ -3,11 +3,11 @@ include $(TOPDIR)/rules.mk | ||||
| PKG_NAME:=ucentral-client | ||||
| PKG_RELEASE:=1 | ||||
|  | ||||
| PKG_SOURCE_URL=https://github.com/blogic/ucentral-client.git | ||||
| PKG_MIRROR_HASH:=f00e800d97335d088281670aa1b459da1fdd5e4a2927ce280b7d9cb369ebc21a | ||||
| PKG_SOURCE_URL=https://github.com/Telecominfraproject/wlan-ucentral-client.git | ||||
| PKG_MIRROR_HASH:=afcdce6a4ea24405b98147bac342a24c21ad6ba91e57a2a966018949ece9a294 | ||||
| PKG_SOURCE_PROTO:=git | ||||
| PKG_SOURCE_DATE:=2022-01-10 | ||||
| PKG_SOURCE_VERSION:=e3b71c61e1a07bb3b5fa34fe835fd8f6f708caa3 | ||||
| PKG_SOURCE_DATE:=2022-05-29 | ||||
| PKG_SOURCE_VERSION:=a4671bbe7d30b1286b718e08573d73dae4df344a | ||||
|  | ||||
| PKG_LICENSE:=BSD-3-Clause | ||||
| PKG_MAINTAINER:=John Crispin <john@phrozen.org> | ||||
| @@ -19,7 +19,7 @@ define Package/ucentral-client | ||||
|   SECTION:=ucentral | ||||
|   CATEGORY:=uCentral | ||||
|   TITLE:=OpenWrt uCentral websocket client | ||||
|   DEPENDS:=+ucode +ucode-mod-fs +ucode-mod-ubus +ucode-mod-uci +ucode-mod-math +ucode-mod-resolv \ | ||||
|   DEPENDS:=+ucode +ucode-mod-fs +ucode-mod-ubus +ucode-mod-uci +ucode-mod-math +ucode-mod-resolv +ucode-mod-uloop \ | ||||
| 	   +libubox +libwebsockets-openssl +libblobmsg-json +libubus | ||||
| endef | ||||
|  | ||||
|   | ||||
| @@ -21,7 +21,7 @@ start_service() { | ||||
|  | ||||
| 	mkdir -p /tmp/ucentral/ | ||||
|  | ||||
| 	ucode -m fs -i /usr/share/ucentral/crashlog.uc | ||||
| 	ucode -l fs /usr/share/ucentral/crashlog.uc | ||||
| 	 | ||||
| 	. /lib/functions.sh | ||||
| 	cp /etc/config-shadow/ucentral /etc/config/ | ||||
| @@ -32,8 +32,6 @@ start_service() { | ||||
| 	config_get debug 'config' 'debug' 0 | ||||
| 	config_get insecure 'config' 'insecure' 0 | ||||
|  | ||||
| 	interval=$(uci get ustats.health.interval) | ||||
|  | ||||
| 	procd_open_instance | ||||
| 	procd_set_param command "$PROG" | ||||
| 	[ -n "$serial" ] && procd_append_param command -S $serial | ||||
| @@ -41,7 +39,6 @@ start_service() { | ||||
| 	[ -n "$port" ] && procd_append_param command -P $port | ||||
| 	[ "$debug" -eq 0 ] || procd_append_param command -d | ||||
| 	[ "$insecure" -eq 0 ] || procd_append_param command -i | ||||
| 	[ -z "$interval" ] || procd_append_param command -H $interval | ||||
| 	[ -z "$(mount | grep 'tmpfs on / type tmpfs')" ] || procd_append_param command -r | ||||
| 	procd_append_param command -f "$(cat /tmp/ucentral.version)" | ||||
| 	procd_set_param respawn 3600 5 0 | ||||
|   | ||||
							
								
								
									
										29
									
								
								feeds/ucentral/ucentral-client/files/etc/init.d/uhealth
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										29
									
								
								feeds/ucentral/ucentral-client/files/etc/init.d/uhealth
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| #!/bin/sh /etc/rc.common | ||||
|  | ||||
| START=99 | ||||
|  | ||||
| USE_PROCD=1 | ||||
| PROG=/usr/share/ucentral/health.uc | ||||
|  | ||||
| boot() { | ||||
| 	# dummy stub to make sure health does not start before | ||||
| 	# a config is applied | ||||
| 	true | ||||
| } | ||||
|  | ||||
| service_triggers() { | ||||
| 	procd_add_reload_trigger ustats | ||||
| } | ||||
|  | ||||
| start_service() { | ||||
| 	. /lib/functions.sh | ||||
| 	config_load 'ustats' | ||||
| 	config_get interval 'health' 'interval' 120 | ||||
|  | ||||
| 	[ "$interval" -eq 0 ] || { | ||||
| 		procd_open_instance | ||||
| 		procd_set_param command "$PROG" | ||||
| 		procd_set_param respawn 1 $interval 0 | ||||
| 		procd_close_instance | ||||
| 	} | ||||
| } | ||||
| @@ -20,9 +20,4 @@ start_service() { | ||||
| 		procd_set_param respawn 1 $interval 0 | ||||
| 		procd_close_instance | ||||
| 	} | ||||
|  | ||||
|         config_get interval 'health' 'interval' 0 | ||||
| 	[ "$interval" -eq 0 ] || { | ||||
| 		ubus call ucentral config '{"health": '$interval' }' | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -4,10 +4,10 @@ PKG_NAME:=ucentral-event | ||||
| PKG_RELEASE:=1 | ||||
|  | ||||
| PKG_SOURCE_URL=https://github.com/blogic/ucentral-event.git | ||||
| PKG_MIRROR_HASH:=615563b31f55b18b8900f8614c6c8add0d6a812da57d220a7632109b06795036 | ||||
| PKG_MIRROR_HASH:=8cb470d7cc6c458fe748ee6f54e4bf79bec5500735d7b992d83c1aa10f700c6b | ||||
| PKG_SOURCE_PROTO:=git | ||||
| PKG_SOURCE_DATE:=2021-04-13 | ||||
| PKG_SOURCE_VERSION:=7b0d136e8556bb099d7032823139d275448714cb | ||||
| PKG_SOURCE_VERSION:=24b7fb36e456d99b470c212674b3bf50bac64c74 | ||||
|  | ||||
| PKG_MAINTAINER:=John Crispin <john@phrozen.org> | ||||
| PKG_LICENSE:=BSD-3-Clause | ||||
|   | ||||
| @@ -3,10 +3,11 @@ include $(TOPDIR)/rules.mk | ||||
| PKG_NAME:=ucentral-schema | ||||
| PKG_RELEASE:=1 | ||||
|  | ||||
| PKG_SOURCE_URL=https://github.com/blogic/ucentral-schema.git | ||||
| PKG_SOURCE_URL=https://github.com/Telecominfraproject/wlan-ucentral-schema.git | ||||
| PKG_MIRROR_HASH:=e2b3842b59c778cd902845ac2c1196859ad19d79bb0f9611044416ecbe1a502f | ||||
| PKG_SOURCE_PROTO:=git | ||||
| PKG_SOURCE_DATE:=2022-01-17 | ||||
| PKG_SOURCE_VERSION:=19fcc8d8163e84734d34dc7dd9767c2fa133fa16 | ||||
| PKG_SOURCE_DATE:=2022-05-29 | ||||
| PKG_SOURCE_VERSION:=4df03737d616e9d6672504e12877b4b7945769f0 | ||||
|  | ||||
| PKG_MAINTAINER:=John Crispin <john@phrozen.org> | ||||
| PKG_LICENSE:=BSD-3-Clause | ||||
|   | ||||
| @@ -6,9 +6,9 @@ USE_PROCD=1 | ||||
| PROG=/usr/bin/ucode | ||||
|  | ||||
| start_service() { | ||||
| 	local interval=$(uci get onlinecheck.@config.check_interval) | ||||
| 	local interval=$(uci get onlinecheck.@config[-1].check_interval) | ||||
| 	procd_open_instance | ||||
| 	procd_set_param command "$PROG" -m uci -m fs -i /usr/share/ucentral/onlinecheck.uc | ||||
| 	procd_set_param command "$PROG" -l uci -l fs /usr/share/ucentral/onlinecheck.uc | ||||
| 	procd_set_param respawn 1 $interval 0 | ||||
| 	procd_close_instance | ||||
| } | ||||
|   | ||||
| @@ -1,23 +1,12 @@ | ||||
| { | ||||
| 	"uuid": 2, | ||||
| 	"radios": [ | ||||
| 		{ | ||||
| 			"band": "6G", | ||||
| 			"country": "CA", | ||||
| 			"channel-mode": "HE", | ||||
| 			"channel-width": 80 | ||||
| 		}, | ||||
| 		{ | ||||
| 			"band": "5G", | ||||
| 			"country": "CA", | ||||
| 			"channel-mode": "HE", | ||||
| 			"channel-width": 80 | ||||
| 		}, | ||||
| 		{ | ||||
| 			"band": "2G", | ||||
| 			"country": "CA", | ||||
| 			"channel-mode": "HE", | ||||
| 			"channel-width": 80 | ||||
| 			"channel-width": 20, | ||||
| 			"channel": 1 | ||||
| 		} | ||||
| 	], | ||||
|  | ||||
| @@ -44,8 +33,27 @@ | ||||
| 			}, | ||||
| 			"tunnel": { | ||||
| 				"proto": "gre", | ||||
| 				"peer-address": "50.210.104.108" | ||||
| 			} | ||||
| 				"peer-address": "192.168.178.59" | ||||
| 			}, | ||||
| 			"ipv4": { | ||||
| 				"addressing": "static", | ||||
| 				"subnet": "192.168.2.2/24", | ||||
| 				"gateway": "192.168.2.1" | ||||
| 			}, | ||||
| 			"ssids": [ | ||||
| 				{ | ||||
| 					"name": "OpenWifi-GRE", | ||||
| 					"wifi-bands": [ | ||||
| 						"2G" | ||||
| 					], | ||||
| 					"bss-mode": "ap", | ||||
| 					"encryption": { | ||||
| 						"proto": "psk2", | ||||
| 						"key": "OpenWifi", | ||||
| 						"ieee80211w": "optional" | ||||
| 					} | ||||
| 				} | ||||
| 			] | ||||
| 		}, | ||||
| 		{ | ||||
| 			"name": "LAN", | ||||
| @@ -69,19 +77,15 @@ | ||||
| 			}, | ||||
| 			"ssids": [ | ||||
| 				{ | ||||
| 					"name": "Maverick", | ||||
| 					"name": "OpenWifi-GRE-NAT", | ||||
| 					"wifi-bands": [ | ||||
| 						"5G", | ||||
| 						"2G" | ||||
| 					], | ||||
| 					"bss-mode": "ap", | ||||
| 					"encryption": { | ||||
| 						"proto": "none", | ||||
| 						"proto": "psk2", | ||||
| 						"key": "OpenWifi", | ||||
| 						"ieee80211w": "optional" | ||||
| 					}, | ||||
| 					"roaming": { | ||||
| 						"message-exchange": "ds", | ||||
| 						"generate-psk": true | ||||
| 					} | ||||
| 				} | ||||
| 			] | ||||
|   | ||||
| @@ -97,7 +97,7 @@ | ||||
| 		"online-check": { | ||||
| 			"ping-hosts": [ | ||||
| 				"192.168.178.1", | ||||
| 				"uecntral.io" | ||||
| 				"ucentral.io" | ||||
| 			], | ||||
| 			"download-hosts": [ | ||||
| 				"ucentral.io" | ||||
|   | ||||
| @@ -0,0 +1,91 @@ | ||||
| { | ||||
| 	"uuid": 2, | ||||
| 	"radios": [ | ||||
| 		{ | ||||
| 			"band": "2G", | ||||
| 			"country": "CA", | ||||
| 			"channel-mode": "HE", | ||||
| 			"channel-width": 20, | ||||
| 			"channel": 6 | ||||
| 		} | ||||
| 	], | ||||
|  | ||||
| 	"interfaces": [ | ||||
| 		{ | ||||
| 			"name": "WAN", | ||||
| 			"role": "upstream", | ||||
| 			"services": [ "ssh" ], | ||||
| 			"ethernet": [ | ||||
| 				{ | ||||
| 					"select-ports": [ | ||||
| 						"WAN*" | ||||
| 					] | ||||
| 				} | ||||
| 			], | ||||
| 			"ipv4": { | ||||
| 				"addressing": "dynamic" | ||||
| 			}, | ||||
| 			"ssids": [ | ||||
| 				{ | ||||
| 					"name": "OpenWifi", | ||||
| 					"wifi-bands": [ | ||||
| 						"2G" | ||||
| 					], | ||||
| 					"bss-mode": "ap", | ||||
| 					"encryption": { | ||||
| 						"proto": "psk2-radius", | ||||
| 						"ieee80211w": "optional" | ||||
| 					}, | ||||
| 					"radius": { | ||||
| 						"authentication": { | ||||
| 							"host": "192.168.50.30", | ||||
| 							"port": 1812, | ||||
| 							"secret": "secret" | ||||
| 						}, | ||||
| 						"accounting": { | ||||
| 							"host": "192.168.50.30", | ||||
| 							"port": 1813, | ||||
| 							"secret": "secret" | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 			] | ||||
| 		}, | ||||
| 		{ | ||||
| 			"name": "LAN", | ||||
| 			"role": "downstream", | ||||
| 			"services": [ "ssh" ], | ||||
| 			"ethernet": [ | ||||
| 				{ | ||||
| 					"select-ports": [ | ||||
| 						"LAN*" | ||||
| 					] | ||||
| 				} | ||||
| 			], | ||||
| 			"ipv4": { | ||||
| 				"addressing": "static", | ||||
| 				"subnet": "192.168.1.1/24", | ||||
| 				"dhcp": { | ||||
| 					"lease-first": 10, | ||||
| 					"lease-count": 100, | ||||
| 					"lease-time": "6h" | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 		} | ||||
| 	], | ||||
| 	"metrics": { | ||||
| 		"statistics": { | ||||
| 			"interval": 120, | ||||
| 			"types": [ "ssids", "lldp", "clients" ] | ||||
| 		}, | ||||
| 		"health": { | ||||
| 			"interval": 120 | ||||
| 		} | ||||
| 	}, | ||||
| 	"services": { | ||||
| 		"ssh": { | ||||
| 			"port": 22 | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @@ -0,0 +1,91 @@ | ||||
| { | ||||
| 	"uuid": 2, | ||||
| 	"radios": [ | ||||
| 		{ | ||||
| 			"band": "5G", | ||||
| 			"country": "CA", | ||||
| 			"channel-mode": "HE", | ||||
| 			"channel-width": 80, | ||||
| 			"channel": 36 | ||||
| 		} | ||||
| 	], | ||||
|  | ||||
| 	"interfaces": [ | ||||
| 		{ | ||||
| 			"name": "WAN", | ||||
| 			"role": "upstream", | ||||
| 			"ethernet": [ | ||||
| 				{ | ||||
| 					"select-ports": [ | ||||
| 						"WAN*" | ||||
| 					] | ||||
| 				} | ||||
| 			], | ||||
| 			"ipv4": { | ||||
| 				"addressing": "dynamic" | ||||
| 			}, | ||||
| 			"ssids": [ | ||||
| 				{ | ||||
| 					"name": "OpenWifi", | ||||
| 					"wifi-bands": [ | ||||
| 						"2G", "5G" | ||||
| 					], | ||||
| 					"bss-mode": "ap", | ||||
| 					"encryption": { | ||||
| 						"proto": "wpa2", | ||||
| 						"ieee80211w": "optional" | ||||
| 					}, | ||||
| 					"radius": { | ||||
| 						"authentication": { | ||||
| 							"host": "192.168.178.192", | ||||
| 							"port": 1812, | ||||
| 							"secret": "secret" | ||||
| 						}, | ||||
| 						"accounting": { | ||||
| 							"host": "192.168.178.192", | ||||
| 							"port": 1813, | ||||
| 							"secret": "secret" | ||||
| 						} | ||||
| 					}, | ||||
| 					"services": [ "radius-gw-proxy" ] | ||||
| 				} | ||||
| 			] | ||||
| 		}, | ||||
| 		{ | ||||
| 			"name": "LAN", | ||||
| 			"role": "downstream", | ||||
| 			"services": [ "ssh" ], | ||||
| 			"ethernet": [ | ||||
| 				{ | ||||
| 					"select-ports": [ | ||||
| 						"LAN*" | ||||
| 					] | ||||
| 				} | ||||
| 			], | ||||
| 			"ipv4": { | ||||
| 				"addressing": "static", | ||||
| 				"subnet": "192.168.1.1/24", | ||||
| 				"dhcp": { | ||||
| 					"lease-first": 10, | ||||
| 					"lease-count": 100, | ||||
| 					"lease-time": "6h" | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 		} | ||||
| 	], | ||||
| 	"metrics": { | ||||
| 		"statistics": { | ||||
| 			"interval": 120, | ||||
| 			"types": [ "ssids", "lldp", "clients" ] | ||||
| 		}, | ||||
| 		"health": { | ||||
| 			"interval": 120 | ||||
| 		} | ||||
| 	}, | ||||
| 	"services": { | ||||
| 		"ssh": { | ||||
| 			"port": 22 | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @@ -103,14 +103,29 @@ | ||||
| 		"radius-proxy": { | ||||
| 			"realms": [ | ||||
| 				{ | ||||
| 					"realm": "test", | ||||
| 					"protocol": "radsec", | ||||
| 					"realm": [ "radsec1", "radsec2" ], | ||||
| 					"host": "192.168.1.10", | ||||
| 					"secret": "secret", | ||||
| 					"ca-certificate": "Zm9vbwo=", | ||||
| 					"certificate": "Zm9vbwo=", | ||||
| 					"private-key": "Zm9vbwo=" | ||||
| 				}, { | ||||
| 					"realm": "*", | ||||
| 					"protocol": "radius", | ||||
| 					"realm": [ "radius1", "radius2" ], | ||||
| 					"auth-server": "192.168.1.11", | ||||
| 					"auth-port": 1812, | ||||
| 					"auth-secret": "secret", | ||||
| 					"acct-server": "192.168.1.11", | ||||
| 					"acct-port": 1813, | ||||
| 					"acct-secret": "secret" | ||||
| 				}, { | ||||
| 					"protocol": "block", | ||||
| 					"realm": [ "block1", "block2" ], | ||||
| 					"message": "Access Denied" | ||||
| 				}, { | ||||
| 					"protocol": "radsec", | ||||
| 					"realm": [ "*" ], | ||||
| 					"auto-discover": true, | ||||
| 					"use-local-certificates": true | ||||
| 				} | ||||
|   | ||||
| @@ -1,23 +1,11 @@ | ||||
| { | ||||
| 	"uuid": 2, | ||||
| 	"radios": [ | ||||
| 		{ | ||||
| 			"band": "6G", | ||||
| 			"country": "CA", | ||||
| 			"channel-mode": "HE", | ||||
| 			"channel-width": 80 | ||||
| 		}, | ||||
| 		{ | ||||
| 			"band": "5G", | ||||
| 			"country": "CA", | ||||
| 			"channel-mode": "HE", | ||||
| 			"channel-width": 80 | ||||
| 		}, | ||||
| 		{ | ||||
| 			"band": "2G", | ||||
| 			"country": "CA", | ||||
| 			"channel-mode": "HE", | ||||
| 			"channel-width": 80 | ||||
| 			"channel": 1 | ||||
| 		} | ||||
| 	], | ||||
|  | ||||
| @@ -49,13 +37,31 @@ | ||||
| 			}, | ||||
| 			"ipv4": { | ||||
| 				"addressing": "static", | ||||
| 				"subnet": "10.0.0.1/24" | ||||
| 			} | ||||
| 				"subnet": "10.0.0.2/24", | ||||
| 				"gateway": "10.0.0.1" | ||||
| 			}, | ||||
| 			"ssids": [ | ||||
| 				{ | ||||
| 					"name": "OpenWifi-VXLAN", | ||||
| 					"wifi-bands": [ | ||||
| 						"2G" | ||||
| 					], | ||||
| 					"bss-mode": "ap", | ||||
| 					"encryption": { | ||||
| 						"proto": "psk2", | ||||
| 						"key": "OpenWifi", | ||||
| 						"ieee80211w": "optional" | ||||
| 					} | ||||
| 				} | ||||
| 			] | ||||
| 		}, | ||||
| 		{ | ||||
| 			"name": "LAN", | ||||
| 			"role": "downstream", | ||||
| 			"services": [ "ssh" ], | ||||
| 			"vlan": { | ||||
| 				"id": 100 | ||||
| 			}, | ||||
| 			"ethernet": [ | ||||
| 				{ | ||||
| 					"select-ports": [ | ||||
| @@ -74,19 +80,15 @@ | ||||
| 			}, | ||||
| 			"ssids": [ | ||||
| 				{ | ||||
| 					"name": "Maverick", | ||||
| 					"name": "OpenWifi-VXLAN", | ||||
| 					"wifi-bands": [ | ||||
| 						"5G", | ||||
| 						"2G" | ||||
| 					], | ||||
| 					"bss-mode": "ap", | ||||
| 					"encryption": { | ||||
| 						"proto": "none", | ||||
| 						"proto": "psk2", | ||||
| 						"key": "OpenWifi", | ||||
| 						"ieee80211w": "optional" | ||||
| 					}, | ||||
| 					"roaming": { | ||||
| 						"message-exchange": "ds", | ||||
| 						"generate-psk": true | ||||
| 					} | ||||
| 				} | ||||
| 			] | ||||
|   | ||||
| @@ -0,0 +1,123 @@ | ||||
| { | ||||
| 	"uuid": 2, | ||||
| 	"radios": [ | ||||
| 		{ | ||||
| 			"band": "2G", | ||||
| 			"country": "US", | ||||
| 			"channel-mode": "HE", | ||||
| 			"channel-width": 20, | ||||
| 			"channel": "auto" | ||||
| 		}, { | ||||
| 			"band": "5G", | ||||
| 			"country": "US", | ||||
| 			"channel-mode": "HE", | ||||
| 			"channel-width": 80, | ||||
| 			"channel": 36 | ||||
| 		}, { | ||||
| 			"band": "6G", | ||||
| 			"country": "US", | ||||
| 			"channel-mode": "HE", | ||||
| 			"channel-width": 80, | ||||
| 			"channel": 33 | ||||
| 		} | ||||
| 	], | ||||
|  | ||||
| 	"interfaces": [ | ||||
| 		{ | ||||
| 			"name": "WAN", | ||||
| 			"role": "upstream", | ||||
| 			"services": [ "lldp" ], | ||||
| 			"ethernet": [ | ||||
| 				{ | ||||
| 					"select-ports": [ | ||||
| 						"WAN*" | ||||
| 					] | ||||
| 				} | ||||
| 			], | ||||
| 			"ipv4": { | ||||
| 				"addressing": "dynamic" | ||||
| 			}, | ||||
| 			"ssids": [ | ||||
| 				{ | ||||
| 					"name": "OpenWifi2", | ||||
| 					"wifi-bands": [ | ||||
| 						"2G" | ||||
| 					], | ||||
| 					"bss-mode": "ap", | ||||
| 					"encryption": { | ||||
| 						"proto": "psk2", | ||||
| 						"key": "OpenWifi", | ||||
| 						"ieee80211w": "optional" | ||||
| 					}, | ||||
| 					"rrm": { | ||||
| 						"reduced-neighbor-reporting": true | ||||
| 					} | ||||
| 				}, { | ||||
| 					"name": "OpenWifi5", | ||||
| 					"wifi-bands": [ | ||||
| 						"5G" | ||||
| 					], | ||||
| 					"bss-mode": "ap", | ||||
| 					"encryption": { | ||||
| 						"proto": "psk2", | ||||
| 						"key": "OpenWifi", | ||||
| 						"ieee80211w": "optional" | ||||
| 					}, | ||||
| 					"rrm": { | ||||
| 						"reduced-neighbor-reporting": true | ||||
| 					} | ||||
| 				}, { | ||||
| 					"name": "OpenWifi6", | ||||
| 					"wifi-bands": [ | ||||
| 						"6G" | ||||
| 					], | ||||
| 					"bss-mode": "ap", | ||||
| 					"encryption": { | ||||
| 						"proto": "sae", | ||||
| 						"key": "OpenWifi", | ||||
| 						"ieee80211w": "required" | ||||
| 					} | ||||
| 				} | ||||
| 			] | ||||
| 		}, | ||||
| 		{ | ||||
| 			"name": "LAN", | ||||
| 			"role": "downstream", | ||||
| 			"services": [ "ssh", "lldp" ], | ||||
| 			"ethernet": [ | ||||
| 				{ | ||||
| 					"select-ports": [ | ||||
| 						"LAN*" | ||||
| 					] | ||||
| 				} | ||||
| 			], | ||||
| 			"ipv4": { | ||||
| 				"addressing": "static", | ||||
| 				"subnet": "192.168.1.1/24", | ||||
| 				"dhcp": { | ||||
| 					"lease-first": 10, | ||||
| 					"lease-count": 100, | ||||
| 					"lease-time": "6h" | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	], | ||||
| 	"metrics": { | ||||
| 		"statistics": { | ||||
| 			"interval": 120, | ||||
| 			"types": [ "ssids", "lldp", "clients" ] | ||||
| 		}, | ||||
| 		"health": { | ||||
| 			"interval": 120 | ||||
| 		} | ||||
| 	}, | ||||
| 	"services": { | ||||
| 		"lldp": { | ||||
| 			"describe": "uCentral", | ||||
| 			"location": "universe" | ||||
| 		}, | ||||
| 		"ssh": { | ||||
| 			"port": 22 | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										2
									
								
								feeds/ucentral/ucentral-schema/files/usr/share/ucentral/wifi_max_user.uc
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										2
									
								
								feeds/ucentral/ucentral-schema/files/usr/share/ucentral/wifi_max_user.uc
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @@ -1,4 +1,4 @@ | ||||
| #!/usr/bin/ucode -R | ||||
| #!/usr/bin/ucode  | ||||
|  | ||||
| let nl = require("nl80211"); | ||||
| let def = nl.const; | ||||
|   | ||||
| @@ -1,4 +1 @@ | ||||
| [ ifup = "$ACTION" ] && { | ||||
| 	ip-collide | ||||
| 	[ $? -eq 0 ] || ubus call ucentral send '{"msg": "ip/domain collision detected", "severity": 3}' | ||||
| } | ||||
| [ ifup = "$ACTION" ] && /usr/share/ucentral/ip-collide.uc | ||||
|   | ||||
| @@ -4,10 +4,11 @@ PKG_NAME:=ucentral-wifi | ||||
| PKG_RELEASE:=1 | ||||
|  | ||||
| PKG_SOURCE_URL=https://github.com/blogic/ucentral-wifi.git | ||||
| PKG_MIRROR_HASH:=b6a3bfbd0823c54bb6fb3899e583db8580474a24c1b238d97be152ea8eccf6e5 | ||||
| PKG_MIRROR_HASH:=8e730a37026a37f113038ae27489bb92104d0a091403b7cc1f379188dddd2699 | ||||
| #PKG_MIRROR_HASH:=b6a3bfbd0823c54bb6fb3899e583db8580474a24c1b238d97be152ea8eccf6e5 | ||||
| PKG_SOURCE_PROTO:=git | ||||
| PKG_SOURCE_DATE:=2022-01-10 | ||||
| PKG_SOURCE_VERSION:=40d0eb9d6f36f558d14d6a1783711c3cf07638c5 | ||||
| PKG_SOURCE_VERSION:=aa9c3ee716929d75852a11640362a09bb32c5262 | ||||
|  | ||||
| PKG_MAINTAINER:=John Crispin <john@phrozen.org> | ||||
| PKG_LICENSE:=BSD-3-Clause | ||||
|   | ||||
| @@ -12,13 +12,13 @@ PKG_RELEASE:=1 | ||||
|  | ||||
| PKG_SOURCE_PROTO:=git | ||||
| PKG_SOURCE_URL=https://github.com/jow-/ucode.git | ||||
| PKG_SOURCE_DATE:=2021-07-30 | ||||
| PKG_SOURCE_VERSION:=03b6a8efc1834a4114f0d11e1a7cecff3242b305 | ||||
| PKG_MIRROR_HASH:=6af37293d6d7023f30728c76a02b4e48d323262a45058410760a30256e0dbe2b | ||||
| PKG_SOURCE_DATE:=2022-04-07 | ||||
| PKG_SOURCE_VERSION:=33f1e0b0926e973fb5ae445e9a995848762143bb | ||||
| PKG_MIRROR_HASH:=e419678244c5402c739e3a200d6d1d7cd6989a711c73744bc68b2d5b76bae33a | ||||
| PKG_MAINTAINER:=Jo-Philipp Wich <jo@mein.io> | ||||
| PKG_LICENSE:=ISC | ||||
|  | ||||
| PKG_ABI_VERSION:=20210730 | ||||
| PKG_ABI_VERSION:=20220322 | ||||
|  | ||||
| include $(INCLUDE_DIR)/package.mk | ||||
| include $(INCLUDE_DIR)/cmake.mk | ||||
| @@ -33,7 +33,7 @@ endef | ||||
|  | ||||
| define Package/ucode | ||||
|   $(Package/ucode/default) | ||||
|   DEPENDS:=+libucode  | ||||
|   DEPENDS:=+libucode | ||||
| endef | ||||
|  | ||||
| define Package/ucode/description | ||||
| @@ -65,17 +65,6 @@ define Package/ucode-mod-fs/description | ||||
| endef | ||||
|  | ||||
|  | ||||
| define Package/ucode-mod-resolv | ||||
|   $(Package/ucode/default) | ||||
|   TITLE+= (resolv module) | ||||
|   DEPENDS:=ucode | ||||
| endef | ||||
|  | ||||
| define Package/ucode-mod-resolv/description | ||||
|  The resolv plugin module allows making DNS resolves. | ||||
| endef | ||||
|  | ||||
|  | ||||
| define Package/ucode-mod-math | ||||
|   $(Package/ucode/default) | ||||
|   TITLE+= (math module) | ||||
| @@ -87,6 +76,50 @@ define Package/ucode-mod-math/description | ||||
| endef | ||||
|  | ||||
|  | ||||
| define Package/ucode-mod-nl80211 | ||||
|   $(Package/ucode/default) | ||||
|   TITLE+= (nl80211 module) | ||||
|   DEPENDS:=ucode +libnl-tiny +kmod-mac80211 | ||||
| endef | ||||
|  | ||||
| define Package/ucode-mod-nl80211/description | ||||
|  The nl80211 plugin provides access to the Linux wireless 802.11 netlink API. | ||||
| endef | ||||
|  | ||||
|  | ||||
| define Package/ucode-mod-resolv | ||||
|   $(Package/ucode/default) | ||||
|   TITLE+= (resolv module) | ||||
|   DEPENDS:=ucode | ||||
| endef | ||||
|  | ||||
| define Package/ucode-mod-resolv/description | ||||
|  The resolv plugin implements simple DNS resolving. | ||||
| endef | ||||
|  | ||||
|  | ||||
| define Package/ucode-mod-rtnl | ||||
|   $(Package/ucode/default) | ||||
|   TITLE+= (rtnl module) | ||||
|   DEPENDS:=ucode +libnl-tiny | ||||
| endef | ||||
|  | ||||
| define Package/ucode-mod-rtnl/description | ||||
|  The rtnl plugin provides access to the Linux routing netlink API. | ||||
| endef | ||||
|  | ||||
|  | ||||
| define Package/ucode-mod-struct | ||||
|   $(Package/ucode/default) | ||||
|   TITLE+= (struct module) | ||||
|   DEPENDS:=ucode | ||||
| endef | ||||
|  | ||||
| define Package/ucode-mod-struct/description | ||||
|  The struct plugin implemnts Python 3 compatible struct.pack/unpack functionality. | ||||
| endef | ||||
|  | ||||
|  | ||||
| define Package/ucode-mod-ubus | ||||
|   $(Package/ucode/default) | ||||
|   TITLE+= (ubus module) | ||||
| @@ -109,40 +142,16 @@ define Package/ucode-mod-uci/description | ||||
|  The uci module allows templates to read and modify uci configuration. | ||||
| endef | ||||
|  | ||||
|  | ||||
| define Package/ucode-mod-nl80211 | ||||
| define Package/ucode-mod-uloop | ||||
|   $(Package/ucode/default) | ||||
|   TITLE+= (nl80211 module) | ||||
|   DEPENDS:=ucode +libnl-tiny +kmod-mac80211 | ||||
|   TITLE+= (uloop module) | ||||
|   DEPENDS:=ucode +libubox | ||||
| endef | ||||
|  | ||||
| define Package/ucode-mod-nl80211/description | ||||
|  The nl80211 module allows templates to send and receive nl80211 messages.. | ||||
| define Package/ucode-mod-uloop/description | ||||
|  The uloop module allows templates to run a main loop. | ||||
| endef | ||||
|  | ||||
|  | ||||
| define Package/ucode-mod-struct | ||||
|   $(Package/ucode/default) | ||||
|   TITLE+= (struct module) | ||||
|   DEPENDS:=ucode | ||||
| endef | ||||
|  | ||||
| define Package/ucode-mod-struct/description | ||||
|  The struct module allows templates to unpack binary buffers. | ||||
| endef | ||||
|  | ||||
|  | ||||
| define Package/ucode-mod-rtnl | ||||
|   $(Package/ucode/default) | ||||
|   TITLE+= (rtnl module) | ||||
|   DEPENDS:=ucode +libnl-tiny | ||||
| endef | ||||
|  | ||||
| define Package/ucode-mod-struct/description | ||||
|  The rtnl module allows templates to send and receive rtnl messages.. | ||||
| endef | ||||
|  | ||||
|  | ||||
| define Build/Prepare | ||||
| 	$(Build/Prepare/Default) | ||||
| 	$(CP) $(STAGING_DIR)/usr/include/mac80211/uapi/linux/nl80211.h $(PKG_BUILD_DIR)/nl80211_copy.h | ||||
| @@ -157,7 +166,7 @@ endef | ||||
|  | ||||
| define Package/ucode/install | ||||
| 	$(INSTALL_DIR) $(1)/usr/bin | ||||
| 	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/ucode $(1)/usr/bin/ucode | ||||
| 	$(CP) $(PKG_INSTALL_DIR)/usr/bin/u* $(1)/usr/bin/ | ||||
| endef | ||||
|  | ||||
| define Package/libucode/install | ||||
| @@ -170,14 +179,29 @@ define Package/ucode-mod-fs/install | ||||
| 	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/lib/ucode/fs.so $(1)/usr/lib/ucode/ | ||||
| endef | ||||
|  | ||||
| define Package/ucode-mod-math/install | ||||
| 	$(INSTALL_DIR) $(1)/usr/lib/ucode | ||||
| 	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/lib/ucode/math.so $(1)/usr/lib/ucode/ | ||||
| endef | ||||
|  | ||||
| define Package/ucode-mod-nl80211/install | ||||
| 	$(INSTALL_DIR) $(1)/usr/lib/ucode | ||||
| 	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/lib/ucode/nl80211.so $(1)/usr/lib/ucode/ | ||||
| endef | ||||
|  | ||||
| define Package/ucode-mod-resolv/install | ||||
| 	$(INSTALL_DIR) $(1)/usr/lib/ucode | ||||
| 	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/lib/ucode/resolv.so $(1)/usr/lib/ucode/ | ||||
| endef | ||||
|  | ||||
| define Package/ucode-mod-math/install | ||||
| define Package/ucode-mod-rtnl/install | ||||
| 	$(INSTALL_DIR) $(1)/usr/lib/ucode | ||||
| 	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/lib/ucode/math.so $(1)/usr/lib/ucode/ | ||||
| 	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/lib/ucode/rtnl.so $(1)/usr/lib/ucode/ | ||||
| endef | ||||
|  | ||||
| define Package/ucode-mod-struct/install | ||||
| 	$(INSTALL_DIR) $(1)/usr/lib/ucode | ||||
| 	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/lib/ucode/struct.so $(1)/usr/lib/ucode/ | ||||
| endef | ||||
|  | ||||
| define Package/ucode-mod-ubus/install | ||||
| @@ -190,29 +214,20 @@ define Package/ucode-mod-uci/install | ||||
| 	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/lib/ucode/uci.so $(1)/usr/lib/ucode/ | ||||
| endef | ||||
|  | ||||
| define Package/ucode-mod-nl80211/install | ||||
| define Package/ucode-mod-uloop/install | ||||
| 	$(INSTALL_DIR) $(1)/usr/lib/ucode | ||||
| 	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/lib/ucode/nl80211.so $(1)/usr/lib/ucode/ | ||||
| endef | ||||
|  | ||||
| define Package/ucode-mod-struct/install | ||||
| 	$(INSTALL_DIR) $(1)/usr/lib/ucode | ||||
| 	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/lib/ucode/struct.so $(1)/usr/lib/ucode/ | ||||
| endef | ||||
|  | ||||
| define Package/ucode-mod-rtnl/install | ||||
| 	$(INSTALL_DIR) $(1)/usr/lib/ucode | ||||
| 	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/lib/ucode/rtnl.so $(1)/usr/lib/ucode/ | ||||
| 	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/lib/ucode/uloop.so $(1)/usr/lib/ucode/ | ||||
| endef | ||||
|  | ||||
|  | ||||
| $(eval $(call BuildPackage,ucode)) | ||||
| $(eval $(call BuildPackage,libucode)) | ||||
| $(eval $(call BuildPackage,ucode-mod-fs)) | ||||
| $(eval $(call BuildPackage,ucode-mod-resolv)) | ||||
| $(eval $(call BuildPackage,ucode-mod-math)) | ||||
| $(eval $(call BuildPackage,ucode-mod-nl80211)) | ||||
| $(eval $(call BuildPackage,ucode-mod-resolv)) | ||||
| $(eval $(call BuildPackage,ucode-mod-rtnl)) | ||||
| $(eval $(call BuildPackage,ucode-mod-struct)) | ||||
| $(eval $(call BuildPackage,ucode-mod-ubus)) | ||||
| $(eval $(call BuildPackage,ucode-mod-uci)) | ||||
| $(eval $(call BuildPackage,ucode-mod-nl80211)) | ||||
| $(eval $(call BuildPackage,ucode-mod-struct)) | ||||
| $(eval $(call BuildPackage,ucode-mod-rtnl)) | ||||
| $(eval $(call BuildPackage,ucode-mod-uloop)) | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| Index: ucode-2021-07-30-03b6a8ef/lib/nl80211.c | ||||
| Index: ucode-2022-04-07-33f1e0b0/lib/nl80211.c | ||||
| =================================================================== | ||||
| --- ucode-2021-07-30-03b6a8ef.orig/lib/nl80211.c | ||||
| +++ ucode-2021-07-30-03b6a8ef/lib/nl80211.c | ||||
| --- ucode-2022-04-07-33f1e0b0.orig/lib/nl80211.c | ||||
| +++ ucode-2022-04-07-33f1e0b0/lib/nl80211.c | ||||
| @@ -38,7 +38,7 @@ limitations under the License. | ||||
|  #include <netlink/genl/family.h> | ||||
|  #include <netlink/genl/ctrl.h> | ||||
|   | ||||
| @@ -1,27 +1,27 @@ | ||||
| From eac420899717e2d23f6d13304bd67278a7e91730 Mon Sep 17 00:00:00 2001 | ||||
| From 25df1c3e41f274f70e4fbf5fdc10e4290ba019f5 Mon Sep 17 00:00:00 2001 | ||||
| From: John Crispin <john@phrozen.org> | ||||
| Date: Thu, 20 Jan 2022 10:48:35 +0100 | ||||
| Subject: [PATCH 1/2] fixes | ||||
| Subject: [PATCH] fixes | ||||
|  | ||||
| --- | ||||
|  lib/nl80211.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++---- | ||||
|  lib/nl80211.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++---- | ||||
|  lib/rtnl.c    |  1 + | ||||
|  2 files changed, 71 insertions(+), 6 deletions(-) | ||||
|  2 files changed, 87 insertions(+), 6 deletions(-) | ||||
|  | ||||
| diff --git a/lib/nl80211.c b/lib/nl80211.c | ||||
| index fc24fb8..1d0871a 100644 | ||||
| --- a/lib/nl80211.c | ||||
| +++ b/lib/nl80211.c | ||||
| @@ -45,6 +45,8 @@ limitations under the License. | ||||
| Index: ucode-2022-04-07-33f1e0b0/lib/nl80211.c | ||||
| =================================================================== | ||||
| --- ucode-2022-04-07-33f1e0b0.orig/lib/nl80211.c | ||||
| +++ ucode-2022-04-07-33f1e0b0/lib/nl80211.c | ||||
| @@ -51,6 +51,8 @@ limitations under the License. | ||||
|   | ||||
|  #define err_return(code, ...) do { set_error(code, __VA_ARGS__); return NULL; } while(0) | ||||
|  #define NL80211_ATTR_NOT_IMPLEMENTED 0x10000 | ||||
|   | ||||
| +#define NL80211_ATTR_NOT_IMPLEMENTED 0x10000 | ||||
| + | ||||
|  static struct { | ||||
|  	int code; | ||||
|  	char *msg; | ||||
| @@ -257,6 +259,14 @@ static const uc_nl_nested_spec_t nl80211_keys_nla = { | ||||
| @@ -263,6 +265,14 @@ static const uc_nl_nested_spec_t nl80211 | ||||
|  	} | ||||
|  }; | ||||
|   | ||||
| @@ -36,7 +36,7 @@ index fc24fb8..1d0871a 100644 | ||||
|  static const uc_nl_nested_spec_t nl80211_mesh_params_nla = { | ||||
|  	.headsize = 0, | ||||
|  	.nattrs = 29, | ||||
| @@ -348,6 +358,14 @@ static const uc_nl_nested_spec_t nl80211_nan_func_nla = { | ||||
| @@ -354,6 +364,14 @@ static const uc_nl_nested_spec_t nl80211 | ||||
|  	} | ||||
|  }; | ||||
|   | ||||
| @@ -51,7 +51,7 @@ index fc24fb8..1d0871a 100644 | ||||
|  static const uc_nl_nested_spec_t nl80211_peer_measurements_peers_req_data_ftm_nla = { | ||||
|  	.headsize = 0, | ||||
|  	.nattrs = 13, | ||||
| @@ -497,6 +515,26 @@ static const uc_nl_nested_spec_t nl80211_wiphy_bands_freqs_wmm_nla = { | ||||
| @@ -503,6 +521,26 @@ static const uc_nl_nested_spec_t nl80211 | ||||
|  	} | ||||
|  }; | ||||
|   | ||||
| @@ -78,7 +78,7 @@ index fc24fb8..1d0871a 100644 | ||||
|  static const uc_nl_nested_spec_t nl80211_wiphy_bands_freqs_nla = { | ||||
|  	.headsize = 0, | ||||
|  	.nattrs = 25, | ||||
| @@ -538,6 +576,10 @@ static const uc_nl_nested_spec_t nl80211_wiphy_bands_rates_nla = { | ||||
| @@ -544,6 +582,10 @@ static const uc_nl_nested_spec_t nl80211 | ||||
|  	} | ||||
|  }; | ||||
|   | ||||
| @@ -89,35 +89,7 @@ index fc24fb8..1d0871a 100644 | ||||
|  static const uc_nl_nested_spec_t nl80211_wiphy_bands_iftype_data_nla = { | ||||
|  	.headsize = 0, | ||||
|  	.nattrs = 7, | ||||
| @@ -645,13 +687,26 @@ static const uc_nl_nested_spec_t nl80211_bss_nla = { | ||||
|   | ||||
|  static const uc_nl_nested_spec_t nl80211_sta_info_bitrate_nla = { | ||||
|  	.headsize = 0, | ||||
| -	.nattrs = 5, | ||||
| +	.nattrs = 18, | ||||
|  	.attrs = { | ||||
|  		{ NL80211_RATE_INFO_BITRATE, "bitrate", DT_U16, 0, NULL }, | ||||
|  		{ NL80211_RATE_INFO_BITRATE32, "bitrate32", DT_U32, 0, NULL }, | ||||
|  		{ NL80211_RATE_INFO_MCS, "mcs", DT_U8, 0, NULL }, | ||||
|  		{ NL80211_RATE_INFO_40_MHZ_WIDTH, "40_mhz_width", DT_FLAG, 0, NULL }, | ||||
|  		{ NL80211_RATE_INFO_SHORT_GI, "short_gi", DT_FLAG, 0, NULL }, | ||||
| +		{ NL80211_RATE_INFO_VHT_MCS, "vht_mcs", DT_U8, 0, NULL }, | ||||
| +		{ NL80211_RATE_INFO_VHT_NSS, "vht_nss", DT_U8, 0, NULL }, | ||||
| +		{ NL80211_RATE_INFO_HE_MCS, "he_mcs", DT_U8, 0, NULL }, | ||||
| +		{ NL80211_RATE_INFO_HE_NSS, "he_nss", DT_U8, 0, NULL }, | ||||
| +		{ NL80211_RATE_INFO_HE_GI, "he_gi", DT_U8, 0, NULL }, | ||||
| +		{ NL80211_RATE_INFO_HE_DCM, "he_dcm", DT_U8, 0, NULL }, | ||||
| +		{ NL80211_RATE_INFO_HE_RU_ALLOC, "he_ru_alloc", DT_U8, 0, NULL }, | ||||
| +		{ NL80211_RATE_INFO_40_MHZ_WIDTH, "width_40", DT_FLAG, 0, NULL }, | ||||
| +		{ NL80211_RATE_INFO_80_MHZ_WIDTH, "width_80", DT_FLAG, 0, NULL }, | ||||
| +		{ NL80211_RATE_INFO_80P80_MHZ_WIDTH, "width_80p80", DT_FLAG, 0, NULL }, | ||||
| +		{ NL80211_RATE_INFO_160_MHZ_WIDTH, "width_160", DT_FLAG, 0, NULL }, | ||||
| +		{ NL80211_RATE_INFO_10_MHZ_WIDTH, "width_10", DT_FLAG, 0, NULL }, | ||||
| +		{ NL80211_RATE_INFO_5_MHZ_WIDTH, "width_5", DT_FLAG, 0, NULL }, | ||||
|  	} | ||||
|  }; | ||||
|   | ||||
| @@ -695,9 +750,13 @@ static const uc_nl_nested_spec_t nl80211_bss_param_nla = { | ||||
| @@ -714,6 +756,10 @@ static const uc_nl_nested_spec_t nl80211 | ||||
|  	} | ||||
|  }; | ||||
|   | ||||
| @@ -127,61 +99,12 @@ index fc24fb8..1d0871a 100644 | ||||
| + | ||||
|  static const uc_nl_nested_spec_t nl80211_sta_info_nla = { | ||||
|  	.headsize = 0, | ||||
| -	.nattrs = 34, | ||||
| +	.nattrs = 35, | ||||
|  	.attrs = { | ||||
|  		{ NL80211_STA_INFO_INACTIVE_TIME, "inactive_time", DT_U32, 0, NULL }, | ||||
|  		{ NL80211_STA_INFO_RX_BYTES, "rx_bytes", DT_U32, 0, NULL }, | ||||
| @@ -724,21 +783,22 @@ static const uc_nl_nested_spec_t nl80211_sta_info_nla = { | ||||
|  		{ NL80211_STA_INFO_NONPEER_PM, "nonpeer_pm", DT_U32, 0, NULL }, | ||||
|  		{ NL80211_STA_INFO_CHAIN_SIGNAL, "chain_signal", DT_S8, DF_MULTIPLE|DF_AUTOIDX, NULL }, | ||||
|  		{ NL80211_STA_INFO_CHAIN_SIGNAL_AVG, "chain_signal_avg", DT_S8, DF_MULTIPLE|DF_AUTOIDX, NULL }, | ||||
| -		{ NL80211_STA_INFO_TID_STATS, "tid_stats", DT_NESTED, 0, &nl80211_tid_stats_nla }, | ||||
| +		{ NL80211_STA_INFO_TID_STATS, "tid_stats", DT_NESTED, DF_MULTIPLE|DF_AUTOIDX, &nl80211_tid_stats_nla }, | ||||
|  		{ NL80211_STA_INFO_BSS_PARAM, "bss_param", DT_NESTED, 0, &nl80211_bss_param_nla }, | ||||
|  		{ NL80211_STA_INFO_RX_DURATION, "rx_duration", DT_U64, 0, NULL }, | ||||
|  		{ NL80211_STA_INFO_TX_DURATION, "tx_duration", DT_U64, 0, NULL }, | ||||
| -		{ NL80211_STA_INFO_ACK_SIGNAL, "ack_signal", DT_U8, 0, NULL }, | ||||
| -		{ NL80211_STA_INFO_ACK_SIGNAL_AVG, "ack_signal_avg", DT_U8, 0, NULL }, | ||||
| +		{ NL80211_STA_INFO_ACK_SIGNAL, "ack_signal", DT_S8, 0, NULL }, | ||||
| +		{ NL80211_STA_INFO_ACK_SIGNAL_AVG, "ack_signal_avg", DT_S8, 0, NULL }, | ||||
|  		{ NL80211_STA_INFO_AIRTIME_LINK_METRIC, "airtime_link_metric", DT_U32, 0, NULL }, | ||||
|  		{ NL80211_STA_INFO_CONNECTED_TO_AS, "connected_to_as", DT_BOOL, 0, NULL }, | ||||
|  		{ NL80211_STA_INFO_CONNECTED_TO_GATE, "connected_to_gate", DT_BOOL, 0, NULL }, | ||||
| +		{ NL80211_STA_INFO_CONNECTED_TIME, "connected_time", DT_U32, 0, NULL }, | ||||
|  	} | ||||
|  }; | ||||
|   | ||||
|  static const uc_nl_nested_spec_t nl80211_msg = { | ||||
|  	.headsize = 0, | ||||
| -	.nattrs = 124, | ||||
| +	.nattrs = 125, | ||||
|  	.attrs = { | ||||
|  		{ NL80211_ATTR_4ADDR, "4addr", DT_U8, 0, NULL }, | ||||
|  		{ NL80211_ATTR_AIRTIME_WEIGHT, "airtime_weight", DT_U16, 0, NULL }, | ||||
| @@ -864,6 +924,7 @@ static const uc_nl_nested_spec_t nl80211_msg = { | ||||
|  		{ NL80211_ATTR_WPA_VERSIONS, "wpa_versions", DT_U32, 0, NULL }, | ||||
|  		{ NL80211_ATTR_SUPPORTED_IFTYPES, "supported_iftypes", DT_NESTED, 0, &nl80211_ifcomb_limit_types_nla }, | ||||
|  		{ NL80211_ATTR_SOFTWARE_IFTYPES, "software_iftypes", DT_NESTED, 0, &nl80211_ifcomb_limit_types_nla }, | ||||
| +		{ NL80211_ATTR_MAX_AP_ASSOC_STA, "max_ap_assoc", DT_U16, 0, NULL }, | ||||
|  	} | ||||
|  }; | ||||
|   | ||||
| @@ -1044,6 +1105,9 @@ uc_nl_parse_attrs(struct nl_msg *msg, char *base, const uc_nl_attr_spec_t *attrs | ||||
|  	bool exists; | ||||
|   | ||||
|  	for (i = 0; i < nattrs; i++) { | ||||
| +		if (attrs[i].attr == NL80211_ATTR_NOT_IMPLEMENTED) | ||||
| +			continue; | ||||
| + | ||||
|  		v = ucv_object_get(obj, attrs[i].key, &exists); | ||||
|   | ||||
|  		if (!exists) | ||||
| diff --git a/lib/rtnl.c b/lib/rtnl.c | ||||
| index b6a3e38..c1d2088 100644 | ||||
| --- a/lib/rtnl.c | ||||
| +++ b/lib/rtnl.c | ||||
| @@ -682,6 +682,7 @@ static const uc_nl_nested_spec_t link_msg = { | ||||
|  	.nattrs = 35, | ||||
| Index: ucode-2022-04-07-33f1e0b0/lib/rtnl.c | ||||
| =================================================================== | ||||
| --- ucode-2022-04-07-33f1e0b0.orig/lib/rtnl.c | ||||
| +++ ucode-2022-04-07-33f1e0b0/lib/rtnl.c | ||||
| @@ -682,6 +682,7 @@ static const uc_nl_nested_spec_t link_ms | ||||
|  		{ IFLA_UNSPEC, "type", DT_U16, 0, MEMBER(ifinfomsg, ifi_type) }, | ||||
|  		{ IFLA_UNSPEC, "dev", DT_NETDEV, 0, MEMBER(ifinfomsg, ifi_index) }, | ||||
|  		{ IFLA_UNSPEC, "flags", DT_FLAGS, 0, MEMBER(ifinfomsg, ifi_flags) }, | ||||
| @@ -189,6 +112,3 @@ index b6a3e38..c1d2088 100644 | ||||
|  		{ IFLA_ADDRESS, "address", DT_LLADDR, 0, NULL }, | ||||
|  		{ IFLA_BROADCAST, "broadcast", DT_LLADDR, 0, NULL }, | ||||
|  		{ IFLA_TXQLEN, "txqlen", DT_U32, 0, NULL }, | ||||
| --  | ||||
| 2.25.1 | ||||
|  | ||||
|   | ||||
| @@ -1,213 +0,0 @@ | ||||
| From 9c77d85f8e121bf0994eb4bc572eea5cf093f0c6 Mon Sep 17 00:00:00 2001 | ||||
| From: John Crispin <john@phrozen.org> | ||||
| Date: Tue, 25 Jan 2022 16:54:48 +0100 | ||||
| Subject: [PATCH] add os library | ||||
|  | ||||
| Signed-off-by: John Crispin <john@phrozen.org> | ||||
| --- | ||||
|  CMakeLists.txt |   7 +++ | ||||
|  lib/os.c       | 167 +++++++++++++++++++++++++++++++++++++++++++++++++ | ||||
|  2 files changed, 174 insertions(+) | ||||
|  create mode 100644 lib/os.c | ||||
|  | ||||
| diff --git a/CMakeLists.txt b/CMakeLists.txt | ||||
| index 7c84fc3..f7d4f83 100644 | ||||
| --- a/CMakeLists.txt | ||||
| +++ b/CMakeLists.txt | ||||
| @@ -27,6 +27,7 @@ OPTION(RTNL_SUPPORT "Route Netlink plugin support" ON) | ||||
|  OPTION(NL80211_SUPPORT "Wireless Netlink plugin support" ON) | ||||
|  OPTION(RESOLV_SUPPORT "NS resolve plugin support" ON) | ||||
|  OPTION(STRUCT_SUPPORT "Struct plugin support" ON) | ||||
| +OPTION(OS_SUPPORT "OS plugin support" ON) | ||||
|   | ||||
|  SET(LIB_SEARCH_PATH "${CMAKE_INSTALL_PREFIX}/lib/ucode/*.so:${CMAKE_INSTALL_PREFIX}/share/ucode/*.uc:./*.so:./*.uc" CACHE STRING "Default library search path") | ||||
|  STRING(REPLACE ":" "\", \"" LIB_SEARCH_DEFINE "${LIB_SEARCH_PATH}") | ||||
| @@ -143,6 +144,12 @@ IF(NL80211_SUPPORT) | ||||
|    TARGET_LINK_LIBRARIES(nl80211_lib ${nl}) | ||||
|  ENDIF() | ||||
|   | ||||
| +IF(OS_SUPPORT) | ||||
| +  SET(LIBRARIES ${LIBRARIES} os_lib) | ||||
| +  ADD_LIBRARY(os_lib MODULE lib/os.c) | ||||
| +  SET_TARGET_PROPERTIES(os_lib PROPERTIES OUTPUT_NAME os PREFIX "") | ||||
| +ENDIF() | ||||
| + | ||||
|  IF(RESOLV_SUPPORT) | ||||
|    SET(LIBRARIES ${LIBRARIES} resolv_lib) | ||||
|    ADD_LIBRARY(resolv_lib MODULE lib/resolv.c) | ||||
| diff --git a/lib/os.c b/lib/os.c | ||||
| new file mode 100644 | ||||
| index 0000000..cebad15 | ||||
| --- /dev/null | ||||
| +++ b/lib/os.c | ||||
| @@ -0,0 +1,167 @@ | ||||
| +#include <glob.h> | ||||
| +#include <stdio.h> | ||||
| +#include <stdint.h> | ||||
| +#include <stdlib.h> | ||||
| +#include <string.h> | ||||
| +#include <unistd.h> | ||||
| +#include <ctype.h> | ||||
| +#include <libgen.h> | ||||
| +#include <fcntl.h> | ||||
| +#include <sys/types.h> | ||||
| +#include <regex.h> | ||||
| + | ||||
| +#include <sys/sysinfo.h> | ||||
| + | ||||
| +#include "ucode/module.h" | ||||
| + | ||||
| +static regex_t pat_vmdata, pat_vmstk; | ||||
| +static struct sysinfo info; | ||||
| +static long systick; | ||||
| + | ||||
| +static void __attribute__((constructor)) | ||||
| +measure_init() | ||||
| +{ | ||||
| +	regcomp(&pat_vmdata, "VmData:[ \t]*([0-9]*) kB", REG_EXTENDED); | ||||
| +	regcomp(&pat_vmstk, "VmStk:[ \t]*([0-9]*) kB", REG_EXTENDED); | ||||
| +	sysinfo(&info); | ||||
| +	systick = sysconf(_SC_CLK_TCK); | ||||
| +} | ||||
| + | ||||
| +static void __attribute__((destructor)) | ||||
| +measure_fini() | ||||
| +{ | ||||
| +	regfree(&pat_vmdata); | ||||
| +	regfree(&pat_vmstk); | ||||
| +} | ||||
| + | ||||
| +static char * | ||||
| +strnchr(char *buf, int c, int i) | ||||
| +{ | ||||
| +	while (*buf && i) { | ||||
| +		buf = strchr(buf, c); | ||||
| +		buf++; | ||||
| +		i--; | ||||
| +	} | ||||
| +	return buf; | ||||
| +} | ||||
| + | ||||
| +static int | ||||
| +measure_process(uc_value_t *obj, pid_t pid) | ||||
| +{ | ||||
| +	int fd; | ||||
| +	char buffer[512] = ""; | ||||
| +	ssize_t rxed; | ||||
| +	regmatch_t matches[2]; | ||||
| +	glob_t gl; | ||||
| +	size_t i; | ||||
| +	char *ch; | ||||
| + | ||||
| +	uint32_t fdcount = 0; | ||||
| +	uint32_t mem = 0; | ||||
| + | ||||
| +	snprintf(buffer, sizeof(buffer), "/proc/%i/fd/*", (int)pid); | ||||
| + | ||||
| +	if (glob(buffer, GLOB_NOESCAPE | GLOB_MARK, NULL, &gl)) | ||||
| +		return -1; | ||||
| + | ||||
| +	for (i = 0; i < gl.gl_pathc; i++) | ||||
| +		if (isdigit(basename(gl.gl_pathv[i])[0])) | ||||
| +			fdcount = fdcount + 1; | ||||
| +	globfree(&gl); | ||||
| +	ucv_object_add(obj, "fd", ucv_int64_new(fdcount)); | ||||
| + | ||||
| +	snprintf(buffer, sizeof(buffer), "/proc/%i/stat", (int)pid); | ||||
| +	fd = open(buffer, O_RDONLY); | ||||
| +	if (fd == -1) | ||||
| +		return -1; | ||||
| + | ||||
| +	rxed = read(fd, buffer, sizeof(buffer) - 1); | ||||
| +	close(fd); | ||||
| +	if (rxed == -1) | ||||
| +		return -1; | ||||
| + | ||||
| +	buffer[rxed] = 0; | ||||
| + | ||||
| +	ch = strnchr(buffer, ' ', 14); | ||||
| +	if (ch) | ||||
| +		ucv_object_add(obj, "load", ucv_int64_new(atoll(ch))); | ||||
| + | ||||
| +	ch = strnchr(buffer, ' ', 21); | ||||
| +	if (ch) | ||||
| +		ucv_object_add(obj, "age", ucv_int64_new(info.uptime - atol(ch) / systick)); | ||||
| + | ||||
| +	snprintf(buffer, sizeof(buffer), "/proc/%i/status", (int)pid); | ||||
| +	fd = open(buffer, O_RDONLY); | ||||
| +	if (fd == -1) | ||||
| +		return -1; | ||||
| + | ||||
| +	rxed = read(fd, buffer, sizeof(buffer) - 1); | ||||
| +	close(fd); | ||||
| +	if (rxed == -1) | ||||
| +		return -1; | ||||
| + | ||||
| +	buffer[rxed] = 0; | ||||
| + | ||||
| +	if (!regexec(&pat_vmdata, buffer, 2, matches, 0)) | ||||
| +		mem += atoi(buffer + matches[1].rm_so) * 1024; | ||||
| + | ||||
| +	if (!regexec(&pat_vmstk, buffer, 2, matches, 0)) | ||||
| +		mem += atoi(buffer + matches[1].rm_so) * 1024; | ||||
| + | ||||
| +	ucv_object_add(obj, "memory", ucv_int64_new(mem)); | ||||
| + | ||||
| +	return 0; | ||||
| +} | ||||
| + | ||||
| +static uc_value_t * | ||||
| +uc_system_hostname(uc_vm_t *vm, size_t nargs) | ||||
| +{ | ||||
| +	char buf[255] = {}; | ||||
| + | ||||
| +	if (gethostname(buf, sizeof(buf)) < 0) | ||||
| +		return NULL; | ||||
| + | ||||
| +	return ucv_string_new(buf); | ||||
| +} | ||||
| + | ||||
| +static uc_value_t * | ||||
| +uc_system_loadavg(uc_vm_t *vm, size_t nargs) | ||||
| +{ | ||||
| +	uc_value_t *res_obj = NULL; | ||||
| +	int i; | ||||
| + | ||||
| +	sysinfo(&info); | ||||
| + | ||||
| +	res_obj = ucv_array_new(vm); | ||||
| +	for (i = 0; i < 3; i++) | ||||
| +		ucv_array_push(res_obj, ucv_double_new(((double) info.loads[i]) / 65535.0f)); | ||||
| + | ||||
| +	return res_obj; | ||||
| +} | ||||
| + | ||||
| +static uc_value_t * | ||||
| +uc_system_process(uc_vm_t *vm, size_t nargs) | ||||
| +{ | ||||
| +	uc_value_t *pid = uc_fn_arg(0); | ||||
| +	uc_value_t *res_obj = NULL; | ||||
| + | ||||
| +	if (ucv_type(pid) != UC_INTEGER) | ||||
| +		return NULL; | ||||
| + | ||||
| +	res_obj = ucv_object_new(vm); | ||||
| + | ||||
| +	measure_process(res_obj, ucv_uint64_get(pid)); | ||||
| + | ||||
| +	return res_obj; | ||||
| +} | ||||
| + | ||||
| +static const uc_function_list_t system_fns[] = { | ||||
| +	{ "hostname",	uc_system_hostname }, | ||||
| +	{ "loadavg",	uc_system_loadavg }, | ||||
| +	{ "process",	uc_system_process }, | ||||
| +}; | ||||
| + | ||||
| +void uc_module_init(uc_vm_t *vm, uc_value_t *scope) | ||||
| +{ | ||||
| +	uc_function_list_register(scope, system_fns); | ||||
| +} | ||||
| --  | ||||
| 2.25.1 | ||||
|  | ||||
| @@ -6,12 +6,6 @@ PKG_RELEASE:=1 | ||||
| PKG_LICENSE:=GPL-2.0 | ||||
| PKG_MAINTAINER:=John Crispin <john@phrozen.org> | ||||
|  | ||||
| PKG_SOURCE_URL=https://github.com/blogic/udhcpsnoop.git | ||||
| PKG_MIRROR_HASH:=721f005e51c46b9381f3e5a6576b8a31afd3903ddb0e7b569d7337a57ca33dd2 | ||||
| PKG_SOURCE_PROTO:=git | ||||
| PKG_SOURCE_DATE:=2021-04-12 | ||||
| PKG_SOURCE_VERSION:=b86639904147a40be32ac43cd89c21109ffc3543 | ||||
|  | ||||
| include $(INCLUDE_DIR)/package.mk | ||||
| include $(INCLUDE_DIR)/cmake.mk | ||||
|  | ||||
| @@ -19,13 +13,20 @@ define Package/udhcpsnoop | ||||
|   SECTION:=net | ||||
|   CATEGORY:=Network | ||||
|   TITLE:=DHCP Snooping Daemon | ||||
|   DEPENDS:=+libubox +libubus +libuci | ||||
|   DEPENDS:=+libubox +libubus +kmod-ifb +tc | ||||
| endef | ||||
|  | ||||
| define Package/udhcpsnoop/install | ||||
| 	$(INSTALL_DIR) \ | ||||
| 		$(1)/usr/sbin \ | ||||
| 		$(1)/etc/init.d \ | ||||
| 		$(1)/etc/config \ | ||||
| 		$(1)/etc/hotplug.d/net | ||||
| 	$(INSTALL_DIR) $(1)/usr/sbin | ||||
| 	$(INSTALL_BIN) $(PKG_BUILD_DIR)/udhcpsnoop $(1)/usr/sbin/ | ||||
| 	$(CP) ./files/* $(1) | ||||
| 	$(INSTALL_BIN) ./files/dhcpsnoop.init $(1)/etc/init.d/dhcpsnoop | ||||
| 	$(INSTALL_DATA) ./files/dhcpsnoop.conf $(1)/etc/config/dhcpsnoop | ||||
| 	$(INSTALL_DATA) ./files/dhcpsnoop.hotplug $(1)/etc/hotplug.d/net/10-dhcpsnoop | ||||
| endef | ||||
|  | ||||
| $(eval $(call BuildPackage,udhcpsnoop)) | ||||
|   | ||||
							
								
								
									
										6
									
								
								feeds/ucentral/udhcpsnoop/files/dhcpsnoop.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								feeds/ucentral/udhcpsnoop/files/dhcpsnoop.conf
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| #config device | ||||
| #	option disabled 1 | ||||
| #	option name eth0 | ||||
| #	option ingress 1 | ||||
| #	option egress 1 | ||||
|  | ||||
							
								
								
									
										2
									
								
								feeds/ucentral/udhcpsnoop/files/dhcpsnoop.hotplug
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								feeds/ucentral/udhcpsnoop/files/dhcpsnoop.hotplug
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| #!/bin/sh | ||||
| ubus call dhcpsnoop check_devices | ||||
							
								
								
									
										60
									
								
								feeds/ucentral/udhcpsnoop/files/dhcpsnoop.init
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								feeds/ucentral/udhcpsnoop/files/dhcpsnoop.init
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,60 @@ | ||||
| #!/bin/sh /etc/rc.common | ||||
| # Copyright (c) 2021 OpenWrt.org | ||||
|  | ||||
| START=40 | ||||
|  | ||||
| USE_PROCD=1 | ||||
| PROG=/usr/sbin/udhcpsnoop | ||||
|  | ||||
| add_option() { | ||||
| 	local type="$1" | ||||
| 	local name="$2" | ||||
| 	local default="$3" | ||||
|  | ||||
| 	config_get val "$cfg" "$name" | ||||
|  | ||||
| 	[ -n "$val" ] && json_add_$type "$name" "${val:-$default}" | ||||
| } | ||||
|  | ||||
| add_device() { | ||||
| 	local cfg="$1" | ||||
|  | ||||
| 	config_get_bool disabled "$cfg" disabled 0 | ||||
| 	[ "$disabled" -gt 0 ] && return | ||||
|  | ||||
| 	config_get name "$cfg" name | ||||
| 	json_add_object "$name" | ||||
|  | ||||
| 	add_option boolean ingress 1 | ||||
| 	add_option boolean egress 1 | ||||
|  | ||||
| 	json_close_object | ||||
| } | ||||
|  | ||||
| reload_service() { | ||||
| 	json_init | ||||
|  | ||||
| 	config_load dhcpsnoop | ||||
|  | ||||
| 	json_add_object devices | ||||
| 	config_foreach add_device device  | ||||
| 	json_close_object | ||||
|  | ||||
| 	ubus call dhcpsnoop config "$(json_dump)" | ||||
| } | ||||
|  | ||||
| service_triggers() { | ||||
| 	procd_add_reload_trigger dhcpsnoop | ||||
| } | ||||
|  | ||||
| start_service() { | ||||
| 	procd_open_instance | ||||
| 	procd_set_param command "$PROG" | ||||
| 	procd_set_param respawn | ||||
| 	procd_close_instance | ||||
| } | ||||
|  | ||||
| service_started() { | ||||
| 	ubus -t 10 wait_for dhcpsnoop | ||||
| 	[ $? = 0 ] && reload_service | ||||
| } | ||||
| @@ -1,4 +0,0 @@ | ||||
| config snooping | ||||
| 	option enable 0 | ||||
| 	#list network lan | ||||
| 	#list network wan | ||||
| @@ -1,22 +0,0 @@ | ||||
| #!/bin/sh /etc/rc.common | ||||
|  | ||||
| START=80 | ||||
|  | ||||
| USE_PROCD=1 | ||||
| PROG=/usr/sbin/udhcpsnoop | ||||
|  | ||||
| service_triggers() { | ||||
| 	procd_add_reload_trigger dhcpsnoop | ||||
| } | ||||
|  | ||||
| start_service() { | ||||
| 	[ "$(uci get dhcpsnoop.@snooping[-1].enable)" -eq 1 ] || return | ||||
| 	procd_open_instance | ||||
| 	procd_set_param command "$PROG" | ||||
| 	procd_set_param respawn | ||||
| 	procd_close_instance | ||||
| } | ||||
|  | ||||
| reload_service() { | ||||
| 	restart | ||||
| } | ||||
							
								
								
									
										16
									
								
								feeds/ucentral/udhcpsnoop/src/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								feeds/ucentral/udhcpsnoop/src/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| cmake_minimum_required(VERSION 3.10) | ||||
|  | ||||
| PROJECT(udhcpsnoop C) | ||||
| INCLUDE(GNUInstallDirs) | ||||
| ADD_DEFINITIONS(-Os -ggdb -Wall -Werror --std=gnu99 -Wmissing-declarations) | ||||
|  | ||||
| SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") | ||||
|  | ||||
| SET(SOURCES main.c ubus.c dev.c dhcp.c cache.c) | ||||
| SET(LIBS ubox ubus) | ||||
|  | ||||
| ADD_EXECUTABLE(udhcpsnoop ${SOURCES}) | ||||
| TARGET_LINK_LIBRARIES(udhcpsnoop ${LIBS}) | ||||
| INSTALL(TARGETS udhcpsnoop | ||||
| 	RUNTIME DESTINATION ${CMAKE_INSTALL_SBINDIR} | ||||
| ) | ||||
							
								
								
									
										77
									
								
								feeds/ucentral/udhcpsnoop/src/cache.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								feeds/ucentral/udhcpsnoop/src/cache.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,77 @@ | ||||
| // SPDX-License-Identifier: GPL-2.0+ | ||||
| /* | ||||
|  * Copyright (C) 2022 Felix Fietkau <nbd@nbd.name> | ||||
|  */ | ||||
|  | ||||
| #include <libubox/avl.h> | ||||
|  | ||||
| #include "dhcpsnoop.h" | ||||
| #include "msg.h" | ||||
|  | ||||
| #define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x" | ||||
| #define MAC_VAR(x) x[0], x[1], x[2], x[3], x[4], x[5] | ||||
|  | ||||
| #define IP_FMT  "%d.%d.%d.%d" | ||||
| #define IP_VAR(x) x[0], x[1], x[2], x[3] | ||||
|  | ||||
| struct mac { | ||||
|         struct avl_node avl; | ||||
| 	uint8_t mac[6]; | ||||
| 	uint8_t ip[4]; | ||||
| 	struct uloop_timeout rebind; | ||||
| }; | ||||
|  | ||||
| static int | ||||
| avl_mac_cmp(const void *k1, const void *k2, void *ptr) | ||||
| { | ||||
| 	return memcmp(k1, k2, 6); | ||||
| } | ||||
|  | ||||
| static struct avl_tree mac_tree = AVL_TREE_INIT(mac_tree, avl_mac_cmp, false, NULL); | ||||
|  | ||||
| static void | ||||
| cache_expire(struct uloop_timeout *t) | ||||
| { | ||||
| 	struct mac *mac = container_of(t, struct mac, rebind); | ||||
|  | ||||
| 	avl_delete(&mac_tree, &mac->avl); | ||||
| 	free(mac); | ||||
| } | ||||
|  | ||||
| void | ||||
| cache_entry(void *_msg, uint32_t rebind) | ||||
| { | ||||
| 	struct dhcpv4_message *msg = (struct dhcpv4_message *) _msg; | ||||
| 	struct mac *mac; | ||||
|  | ||||
| 	mac = avl_find_element(&mac_tree, msg->chaddr, mac, avl); | ||||
|  | ||||
| 	if (!mac) { | ||||
| 		mac = malloc(sizeof(*mac)); | ||||
| 		if (!mac) | ||||
| 			return; | ||||
| 		memset(mac, 0, sizeof(*mac)); | ||||
| 		memcpy(mac->mac, msg->chaddr, 6); | ||||
| 		mac->avl.key = mac->mac; | ||||
| 		mac->rebind.cb = cache_expire; | ||||
| 		avl_insert(&mac_tree, &mac->avl); | ||||
| 	} | ||||
| 	memcpy(mac->ip, &msg->yiaddr.s_addr, 4); | ||||
| 	uloop_timeout_set(&mac->rebind, rebind * 1000); | ||||
| } | ||||
|  | ||||
| void | ||||
| cache_dump(struct blob_buf *b) | ||||
| { | ||||
| 	struct mac *mac; | ||||
|  | ||||
| 	avl_for_each_element(&mac_tree, mac, avl) { | ||||
| 		char addr[18]; | ||||
| 		char ip[16]; | ||||
|  | ||||
| 		snprintf(addr, sizeof(addr), MAC_FMT, MAC_VAR(mac->mac)); | ||||
| 		snprintf(ip, sizeof(ip), IP_FMT, IP_VAR(mac->ip)); | ||||
|  | ||||
| 		blobmsg_add_string(b, addr, ip); | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										425
									
								
								feeds/ucentral/udhcpsnoop/src/dev.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										425
									
								
								feeds/ucentral/udhcpsnoop/src/dev.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,425 @@ | ||||
| // SPDX-License-Identifier: GPL-2.0+ | ||||
| /* | ||||
|  * Copyright (C) 2022 Felix Fietkau <nbd@nbd.name> | ||||
|  */ | ||||
| #include <netinet/if_ether.h> | ||||
| #include <netinet/in.h> | ||||
| #include <netinet/ip.h> | ||||
| #include <netinet/ip6.h> | ||||
| #include <netinet/udp.h> | ||||
| #include <netpacket/packet.h> | ||||
| #include <net/if.h> | ||||
| #include <sys/socket.h> | ||||
| #include <sys/types.h> | ||||
| #include <stdio.h> | ||||
| #include <unistd.h> | ||||
| #include <fcntl.h> | ||||
|  | ||||
| #include <libubox/vlist.h> | ||||
| #include <libubox/avl-cmp.h> | ||||
|  | ||||
| #include "dhcpsnoop.h" | ||||
|  | ||||
| #define APPEND(_buf, _ofs, _format, ...) _ofs += snprintf(_buf + _ofs, sizeof(_buf) - _ofs, _format, ##__VA_ARGS__) | ||||
|  | ||||
| struct vlan_hdr { | ||||
| 	uint16_t tci; | ||||
| 	uint16_t proto; | ||||
| }; | ||||
|  | ||||
| struct packet { | ||||
| 	void *buffer; | ||||
| 	unsigned int len; | ||||
| }; | ||||
|  | ||||
|  | ||||
| struct device { | ||||
| 	struct vlist_node node; | ||||
| 	char ifname[IFNAMSIZ + 1]; | ||||
|  | ||||
| 	int ifindex; | ||||
| 	bool ingress; | ||||
| 	bool egress; | ||||
|  | ||||
| 	bool changed; | ||||
| 	bool active; | ||||
| }; | ||||
|  | ||||
| static void dev_update_cb(struct vlist_tree *tree, struct vlist_node *node_new, | ||||
| 			  struct vlist_node *node_old); | ||||
|  | ||||
| static struct uloop_fd ufd; | ||||
| static VLIST_TREE(devices, avl_strcmp, dev_update_cb, true, false); | ||||
|  | ||||
| static void *pkt_peek(struct packet *pkt, unsigned int len) | ||||
| { | ||||
| 	if (len > pkt->len) | ||||
| 		return NULL; | ||||
|  | ||||
| 	return pkt->buffer; | ||||
| } | ||||
|  | ||||
|  | ||||
| static void *pkt_pull(struct packet *pkt, unsigned int len) | ||||
| { | ||||
| 	void *ret = pkt_peek(pkt, len); | ||||
|  | ||||
| 	if (!ret) | ||||
| 		return NULL; | ||||
|  | ||||
| 	pkt->buffer += len; | ||||
| 	pkt->len -= len; | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| static bool | ||||
| proto_is_vlan(uint16_t proto) | ||||
| { | ||||
| 	return proto == ETH_P_8021Q || proto == ETH_P_8021AD; | ||||
| } | ||||
|  | ||||
| static void | ||||
| dhcpsnoop_packet_cb(struct packet *pkt) | ||||
| { | ||||
| 	struct ethhdr *eth; | ||||
| 	struct ip6_hdr *ip6; | ||||
| 	struct ip *ip; | ||||
| 	struct udphdr *udp; | ||||
| 	uint16_t proto, port; | ||||
| 	const char *type; | ||||
| 	bool ipv6 = false; | ||||
| 	uint32_t rebind = 0; | ||||
|  | ||||
| 	eth = pkt_pull(pkt, sizeof(*eth)); | ||||
| 	if (!eth) | ||||
| 		return; | ||||
|  | ||||
| 	proto = be16_to_cpu(eth->h_proto); | ||||
| 	if (proto_is_vlan(proto)) { | ||||
| 		struct vlan_hdr *vlan; | ||||
|  | ||||
| 		vlan = pkt_pull(pkt, sizeof(*vlan)); | ||||
| 		if (!vlan) | ||||
| 			return; | ||||
|  | ||||
| 		proto = be16_to_cpu(vlan->proto); | ||||
| 	} | ||||
|  | ||||
| 	switch (proto) { | ||||
| 	case ETH_P_IP: | ||||
| 		ip = pkt_peek(pkt, sizeof(struct ip)); | ||||
| 		if (!ip) | ||||
| 			return; | ||||
|  | ||||
| 		if (!pkt_pull(pkt, ip->ip_hl * 4)) | ||||
| 			return; | ||||
|  | ||||
| 		proto = ip->ip_p; | ||||
| 		break; | ||||
| 	case ETH_P_IPV6: | ||||
| 		ip6 = pkt_pull(pkt, sizeof(*ip6)); | ||||
| 		if (!ip6) | ||||
| 			return; | ||||
|  | ||||
| 		proto = ip6->ip6_nxt; | ||||
| 		ipv6 = true; | ||||
| 		break; | ||||
| 	default: | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	if (proto != IPPROTO_UDP) | ||||
| 		return; | ||||
|  | ||||
| 	udp = pkt_pull(pkt, sizeof(struct udphdr)); | ||||
| 	if (!udp) | ||||
| 		return; | ||||
|  | ||||
| 	port = ntohs(udp->uh_sport); | ||||
|  | ||||
| 	if (!ipv6) | ||||
| 		type = dhcpsnoop_parse_ipv4(pkt->buffer, pkt->len, port, &rebind); | ||||
| 	else | ||||
| 		type = dhcpsnoop_parse_ipv6(pkt->buffer, pkt->len, port); | ||||
|  | ||||
| 	if (!type) | ||||
| 		return; | ||||
|  | ||||
| 	dhcpsnoop_ubus_notify(type, pkt->buffer, pkt->len); | ||||
| 	if (!ipv6 && !strcmp(type, "ack") && rebind) | ||||
| 		cache_entry(pkt->buffer, rebind); | ||||
| } | ||||
|  | ||||
| static void | ||||
| dhcpsnoop_socket_cb(struct uloop_fd *fd, unsigned int events) | ||||
| { | ||||
| 	static uint8_t buf[8192]; | ||||
| 	struct packet pkt = { | ||||
| 		.buffer = buf, | ||||
| 	}; | ||||
| 	int len; | ||||
|  | ||||
| retry: | ||||
| 	len = recvfrom(fd->fd, buf, sizeof(buf), MSG_DONTWAIT, NULL, NULL); | ||||
| 	if (len < 0) { | ||||
| 		if (errno == EINTR) | ||||
| 			goto retry; | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	if (!len) | ||||
| 		return; | ||||
|  | ||||
| 	pkt.len = len; | ||||
| 	dhcpsnoop_packet_cb(&pkt); | ||||
| } | ||||
|  | ||||
| static int | ||||
| dhcpsnoop_open_socket(void) | ||||
| { | ||||
| 	struct sockaddr_ll sll = { | ||||
| 		.sll_family = AF_PACKET, | ||||
| 		.sll_protocol = htons(ETH_P_ALL), | ||||
| 	}; | ||||
| 	int sock; | ||||
|  | ||||
| 	sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); | ||||
| 	if (sock == -1) { | ||||
| 		ULOG_ERR("failed to create raw socket: %s\n", strerror(errno)); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	sll.sll_ifindex = if_nametoindex(DHCPSNOOP_IFB_NAME); | ||||
| 	if (bind(sock, (struct sockaddr *)&sll, sizeof(sll))) { | ||||
| 		ULOG_ERR("failed to bind socket to "DHCPSNOOP_IFB_NAME": %s\n", | ||||
| 			 strerror(errno)); | ||||
| 		goto error; | ||||
| 	} | ||||
|  | ||||
| 	fcntl(sock, F_SETFL, fcntl(sock, F_GETFL) | O_NONBLOCK); | ||||
|  | ||||
| 	ufd.fd = sock; | ||||
| 	ufd.cb = dhcpsnoop_socket_cb; | ||||
| 	uloop_fd_add(&ufd, ULOOP_READ); | ||||
|  | ||||
| 	return 0; | ||||
|  | ||||
| error: | ||||
| 	close(sock); | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| static int | ||||
| prepare_filter_cmd(char *buf, int len, const char *dev, int prio, bool add, bool egress) | ||||
| { | ||||
| 	return snprintf(buf, len, "tc filter %s dev '%s' %sgress prio %d", | ||||
| 			add ? "add" : "del", dev, egress ? "e" : "in", prio); | ||||
| } | ||||
|  | ||||
| static void | ||||
| dhcpsnoop_dev_attach_filters(struct device *dev, bool egress) | ||||
| { | ||||
| 	int prio = DHCPSNOOP_PRIO_BASE; | ||||
| 	char buf[256]; | ||||
| 	int ofs; | ||||
|  | ||||
| 	ofs = prepare_filter_cmd(buf, sizeof(buf), dev->ifname, prio++, true, egress); | ||||
| 	APPEND(buf, ofs, " protocol ip u32 match ip sport 67 0xffff" | ||||
| 			 " flowid 1:1 action mirred ingress mirror dev " DHCPSNOOP_IFB_NAME); | ||||
| 	dhcpsnoop_run_cmd(buf, false); | ||||
|  | ||||
| 	ofs = prepare_filter_cmd(buf, sizeof(buf), dev->ifname, prio++, true, egress); | ||||
| 	APPEND(buf, ofs, " protocol 802.1Q u32 offset plus 4 match ip sport 67 0xffff" | ||||
| 			 " flowid 1:1 action mirred ingress mirror dev " DHCPSNOOP_IFB_NAME); | ||||
| 	dhcpsnoop_run_cmd(buf, false); | ||||
|  | ||||
| 	ofs = prepare_filter_cmd(buf, sizeof(buf), dev->ifname, prio++, true, egress); | ||||
| 	APPEND(buf, ofs, " protocol ip u32 match ip sport 68 0xffff" | ||||
| 			 " flowid 1:1 action mirred ingress mirror dev " DHCPSNOOP_IFB_NAME); | ||||
| 	dhcpsnoop_run_cmd(buf, false); | ||||
|  | ||||
| 	ofs = prepare_filter_cmd(buf, sizeof(buf), dev->ifname, prio++, true, egress); | ||||
| 	APPEND(buf, ofs, " protocol 802.1Q u32 offset plus 4 match ip sport 68 0xffff" | ||||
| 			 " flowid 1:1 action mirred ingress mirror dev " DHCPSNOOP_IFB_NAME); | ||||
| 	dhcpsnoop_run_cmd(buf, false); | ||||
|  | ||||
| 	ofs = prepare_filter_cmd(buf, sizeof(buf), dev->ifname, prio++, true, egress); | ||||
| 	APPEND(buf, ofs, " protocol ipv6 u32 match ip6 sport 546 0xfffe" | ||||
| 			 " flowid 1:1 action mirred ingress mirror dev " DHCPSNOOP_IFB_NAME); | ||||
| 	dhcpsnoop_run_cmd(buf, false); | ||||
|  | ||||
| 	ofs = prepare_filter_cmd(buf, sizeof(buf), dev->ifname, prio++, true, egress); | ||||
| 	APPEND(buf, ofs, " protocol 802.1Q u32 offset plus 4 match ip6 sport 546 0xfffe" | ||||
| 			 " flowid 1:1 action mirred ingress mirror dev " DHCPSNOOP_IFB_NAME); | ||||
| 	dhcpsnoop_run_cmd(buf, false); | ||||
| } | ||||
|  | ||||
| static void | ||||
| dhcpsnoop_dev_cleanup_filters(struct device *dev, bool egress) | ||||
| { | ||||
| 	char buf[128]; | ||||
| 	int i; | ||||
|  | ||||
| 	for (i = DHCPSNOOP_PRIO_BASE; i < DHCPSNOOP_PRIO_BASE + 6; i++) { | ||||
| 		prepare_filter_cmd(buf, sizeof(buf), dev->ifname, i, false, egress); | ||||
| 		dhcpsnoop_run_cmd(buf, true); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static void | ||||
| dhcpsnoop_dev_attach(struct device *dev) | ||||
| { | ||||
| 	char buf[64]; | ||||
|  | ||||
| 	dev->active = true; | ||||
| 	snprintf(buf, sizeof(buf), "tc qdisc add dev '%s' clsact", dev->ifname); | ||||
| 	dhcpsnoop_run_cmd(buf, true); | ||||
|  | ||||
| 	if (dev->ingress) | ||||
| 		dhcpsnoop_dev_attach_filters(dev, false); | ||||
| 	if (dev->egress) | ||||
| 		dhcpsnoop_dev_attach_filters(dev, true); | ||||
| } | ||||
|  | ||||
| static void | ||||
| dhcpsnoop_dev_cleanup(struct device *dev) | ||||
| { | ||||
| 	dev->active = false; | ||||
| 	dhcpsnoop_dev_cleanup_filters(dev, true); | ||||
| 	dhcpsnoop_dev_cleanup_filters(dev, false); | ||||
| } | ||||
|  | ||||
| static void | ||||
| __dhcpsnoop_dev_check(struct device *dev) | ||||
| { | ||||
| 	int ifindex; | ||||
|  | ||||
| 	ifindex = if_nametoindex(dev->ifname); | ||||
| 	if (ifindex != dev->ifindex) { | ||||
| 		dev->ifindex = ifindex; | ||||
| 		dev->changed = true; | ||||
| 	} | ||||
|  | ||||
| 	if (!dev->changed) | ||||
| 		return; | ||||
|  | ||||
| 	dev->changed = false; | ||||
| 	dhcpsnoop_dev_cleanup(dev); | ||||
| 	if (ifindex) | ||||
| 		dhcpsnoop_dev_attach(dev); | ||||
| } | ||||
|  | ||||
| static void dev_update_cb(struct vlist_tree *tree, struct vlist_node *node_new, | ||||
| 			  struct vlist_node *node_old) | ||||
| { | ||||
| 	struct device *dev = NULL, *dev_free = NULL; | ||||
|  | ||||
| 	if (node_old && node_new) { | ||||
| 		dev = container_of(node_old, struct device, node); | ||||
| 		dev_free = container_of(node_new, struct device, node); | ||||
|  | ||||
| 		if (dev->ingress != dev_free->ingress || | ||||
| 			dev->egress != dev_free->egress) | ||||
| 			dev->changed = true; | ||||
|  | ||||
| 		dev->ingress = dev_free->ingress; | ||||
| 		dev->egress = dev_free->egress; | ||||
| 	} else if (node_old) { | ||||
| 		dev_free = container_of(node_old, struct device, node); | ||||
| 		if (dev_free->active) | ||||
| 			dhcpsnoop_dev_cleanup(dev_free); | ||||
| 	} else if (node_new) { | ||||
| 		dev = container_of(node_new, struct device, node); | ||||
| 	} | ||||
|  | ||||
| 	if (dev) | ||||
| 		__dhcpsnoop_dev_check(dev); | ||||
| 	if (dev_free) | ||||
| 		free(dev_free); | ||||
| } | ||||
|  | ||||
| static void | ||||
| dhcpsnoop_dev_config_add(struct blob_attr *data) | ||||
| { | ||||
| 	enum { | ||||
| 		DEV_ATTR_INGRESS, | ||||
| 		DEV_ATTR_EGRESS, | ||||
| 		__DEV_ATTR_MAX | ||||
| 	}; | ||||
| 	static const struct blobmsg_policy policy[__DEV_ATTR_MAX] = { | ||||
| 		[DEV_ATTR_INGRESS] = { "ingress", BLOBMSG_TYPE_BOOL }, | ||||
| 		[DEV_ATTR_EGRESS] = { "egress", BLOBMSG_TYPE_BOOL }, | ||||
| 	}; | ||||
| 	struct blob_attr *tb[__DEV_ATTR_MAX]; | ||||
| 	struct blob_attr *cur; | ||||
| 	struct device *dev; | ||||
| 	int len; | ||||
|  | ||||
| 	if (blobmsg_type(data) != BLOBMSG_TYPE_TABLE) | ||||
| 		return; | ||||
|  | ||||
| 	dev = calloc(1, sizeof(*dev)); | ||||
| 	len = snprintf(dev->ifname, sizeof(dev->ifname), "%s", blobmsg_name(data)); | ||||
| 	if (!len || len > IFNAMSIZ) | ||||
| 		goto free; | ||||
|  | ||||
| 	blobmsg_parse(policy, ARRAY_SIZE(tb), tb, blobmsg_data(data), blobmsg_len(data)); | ||||
|  | ||||
| 	if ((cur = tb[DEV_ATTR_INGRESS]) != NULL) | ||||
| 		dev->ingress = blobmsg_get_bool(cur); | ||||
| 	if ((cur = tb[DEV_ATTR_EGRESS]) != NULL) | ||||
| 		dev->egress = blobmsg_get_bool(cur); | ||||
|  | ||||
| 	if (!dev->ingress && !dev->egress) | ||||
| 		goto free; | ||||
|  | ||||
| 	vlist_add(&devices, &dev->node, dev->ifname); | ||||
| 	return; | ||||
|  | ||||
| free: | ||||
| 	free(dev); | ||||
| 	return; | ||||
| } | ||||
|  | ||||
| void dhcpsnoop_dev_config_update(struct blob_attr *data) | ||||
| { | ||||
| 	struct blob_attr *cur; | ||||
| 	int rem; | ||||
|  | ||||
| 	vlist_update(&devices); | ||||
| 	blobmsg_for_each_attr(cur, data, rem) | ||||
| 		dhcpsnoop_dev_config_add(cur); | ||||
| 	vlist_flush(&devices); | ||||
| } | ||||
|  | ||||
| void dhcpsnoop_dev_check(void) | ||||
| { | ||||
| 	struct device *dev; | ||||
|  | ||||
| 	vlist_for_each_element(&devices, dev, node) | ||||
| 		__dhcpsnoop_dev_check(dev); | ||||
| } | ||||
|  | ||||
| int dhcpsnoop_dev_init(void) | ||||
| { | ||||
| 	dhcpsnoop_dev_done(); | ||||
|  | ||||
| 	if (dhcpsnoop_run_cmd("ip link add "DHCPSNOOP_IFB_NAME" type ifb", false) || | ||||
| 	    dhcpsnoop_run_cmd("ip link set dev "DHCPSNOOP_IFB_NAME" up", false) || | ||||
| 	    dhcpsnoop_open_socket()) | ||||
| 		return -1; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| void dhcpsnoop_dev_done(void) | ||||
| { | ||||
| 	if (ufd.registered) { | ||||
| 		uloop_fd_delete(&ufd); | ||||
| 		close(ufd.fd); | ||||
| 	} | ||||
|  | ||||
| 	dhcpsnoop_run_cmd("ip link del "DHCPSNOOP_IFB_NAME, true); | ||||
| 	vlist_flush_all(&devices); | ||||
| } | ||||
							
								
								
									
										90
									
								
								feeds/ucentral/udhcpsnoop/src/dhcp.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								feeds/ucentral/udhcpsnoop/src/dhcp.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,90 @@ | ||||
| // SPDX-License-Identifier: GPL-2.0+ | ||||
| /* | ||||
|  * Copyright (C) 2022 Felix Fietkau <nbd@nbd.name> | ||||
|  */ | ||||
|  | ||||
| #include "dhcpsnoop.h" | ||||
| #include "msg.h" | ||||
|  | ||||
| const char *dhcpsnoop_parse_ipv4(const void *buf, size_t len, uint16_t port, uint32_t *rebind) | ||||
| { | ||||
| 	const struct dhcpv4_message *msg = buf; | ||||
| 	const uint8_t *pos, *end; | ||||
| 	char type = 0; | ||||
|  | ||||
| 	if (port != 67 && port != 68) | ||||
| 		return NULL; | ||||
|  | ||||
| 	if (len < sizeof(*msg)) | ||||
| 		return NULL; | ||||
|  | ||||
| 	if (ntohl(msg->magic) != DHCPV4_MAGIC) | ||||
| 		return NULL; | ||||
|  | ||||
| 	pos = msg->options; | ||||
| 	end = buf + len; | ||||
|  | ||||
| 	while (pos < end) { | ||||
| 		const uint8_t *opt = pos++; | ||||
|  | ||||
| 		if (*opt == DHCPV4_OPT_END) | ||||
| 			break; | ||||
|  | ||||
| 		if (*opt == DHCPV4_OPT_PAD) | ||||
| 			continue; | ||||
|  | ||||
| 		if (pos >= end || 1 + *pos > end - pos) | ||||
| 			break; | ||||
|  | ||||
| 		pos += *pos + 1; | ||||
| 		if (pos >= end) | ||||
| 			break; | ||||
|  | ||||
| 		switch (*opt) { | ||||
| 		case DHCPV4_OPT_MSG_TYPE: | ||||
| 			if (!opt[1]) | ||||
| 				continue; | ||||
| 			type = opt[2]; | ||||
| 			break; | ||||
| 		case DHCPV4_OPT_REBIND: | ||||
| 			if (!rebind || opt[1] != 4) | ||||
| 				continue; | ||||
| 			*rebind = *((uint32_t *) &opt[2]); | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	switch(type) { | ||||
| 	case DHCPV4_MSG_ACK: | ||||
| 		return "ack"; | ||||
| 	case DHCPV4_MSG_DISCOVER: | ||||
| 		return "discover"; | ||||
| 	case DHCPV4_MSG_OFFER: | ||||
| 		return "offer"; | ||||
| 	case DHCPV4_MSG_REQUEST: | ||||
| 		return "request"; | ||||
| 	} | ||||
|  | ||||
| 	return NULL; | ||||
| } | ||||
|  | ||||
| const char *dhcpsnoop_parse_ipv6(const void *buf, size_t len, uint16_t port) | ||||
| { | ||||
| 	const struct dhcpv6_message *msg = buf; | ||||
|  | ||||
| 	if (port != 546 && port != 547) | ||||
| 		return NULL; | ||||
|  | ||||
| 	switch(msg->msg_type) { | ||||
| 	case DHCPV6_MSG_SOLICIT: | ||||
| 		return "solicit"; | ||||
| 	case DHCPV6_MSG_REPLY: | ||||
| 		return "reply"; | ||||
| 	case DHCPV6_MSG_RENEW: | ||||
| 		return "renew"; | ||||
| 	default: | ||||
| 		return NULL; | ||||
| 	} | ||||
| } | ||||
|  | ||||
|  | ||||
							
								
								
									
										32
									
								
								feeds/ucentral/udhcpsnoop/src/dhcpsnoop.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								feeds/ucentral/udhcpsnoop/src/dhcpsnoop.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | ||||
| // SPDX-License-Identifier: GPL-2.0+ | ||||
| /* | ||||
|  * Copyright (C) 2022 Felix Fietkau <nbd@nbd.name> | ||||
|  */ | ||||
| #ifndef __DHCPSNOOP_H | ||||
| #define __DHCPSNOOP_H | ||||
|  | ||||
| #include <libubox/blobmsg.h> | ||||
| #include <libubox/ulog.h> | ||||
| #include <libubox/uloop.h> | ||||
|  | ||||
| #define DHCPSNOOP_IFB_NAME "ifb-dhcp" | ||||
| #define DHCPSNOOP_PRIO_BASE	0x100 | ||||
|  | ||||
| int dhcpsnoop_run_cmd(char *cmd, bool ignore_error); | ||||
|  | ||||
| int dhcpsnoop_dev_init(void); | ||||
| void dhcpsnoop_dev_done(void); | ||||
| void dhcpsnoop_dev_config_update(struct blob_attr *data); | ||||
| void dhcpsnoop_dev_check(void); | ||||
|  | ||||
| void dhcpsnoop_ubus_init(void); | ||||
| void dhcpsnoop_ubus_done(void); | ||||
| void dhcpsnoop_ubus_notify(const char *type, const uint8_t *msg, size_t len); | ||||
|  | ||||
| const char *dhcpsnoop_parse_ipv4(const void *buf, size_t len, uint16_t port, uint32_t *rebind); | ||||
| const char *dhcpsnoop_parse_ipv6(const void *buf, size_t len, uint16_t port); | ||||
|  | ||||
| void cache_entry(void *msg, uint32_t rebind); | ||||
| void cache_dump(struct blob_buf *b); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										84
									
								
								feeds/ucentral/udhcpsnoop/src/main.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								feeds/ucentral/udhcpsnoop/src/main.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,84 @@ | ||||
| // SPDX-License-Identifier: GPL-2.0+ | ||||
| /* | ||||
|  * Copyright (C) 2022 Felix Fietkau <nbd@nbd.name> | ||||
|  */ | ||||
| #include <sys/wait.h> | ||||
| #include <unistd.h> | ||||
| #include <stdio.h> | ||||
| #include "dhcpsnoop.h" | ||||
|  | ||||
| int dhcpsnoop_run_cmd(char *cmd, bool ignore_error) | ||||
| { | ||||
| 	char *argv[] = { "sh", "-c", cmd, NULL }; | ||||
| 	bool first = true; | ||||
| 	int status = -1; | ||||
| 	char buf[512]; | ||||
| 	int fds[2]; | ||||
| 	FILE *f; | ||||
| 	int pid; | ||||
|  | ||||
| 	if (pipe(fds)) | ||||
| 		return -1; | ||||
|  | ||||
| 	pid = fork(); | ||||
| 	if (!pid) { | ||||
| 		close(fds[0]); | ||||
| 		if (fds[1] != STDOUT_FILENO) | ||||
| 			dup2(fds[1], STDOUT_FILENO); | ||||
| 		if (fds[1] != STDERR_FILENO) | ||||
| 			dup2(fds[1], STDERR_FILENO); | ||||
| 		if (fds[1] > STDERR_FILENO) | ||||
| 			close(fds[1]); | ||||
| 		execv("/bin/sh", argv); | ||||
| 		exit(1); | ||||
| 	} | ||||
|  | ||||
| 	if (pid < 0) | ||||
| 		return -1; | ||||
|  | ||||
| 	close(fds[1]); | ||||
| 	f = fdopen(fds[0], "r"); | ||||
| 	if (!f) { | ||||
| 		close(fds[0]); | ||||
| 		goto out; | ||||
| 	} | ||||
|  | ||||
| 	while (fgets(buf, sizeof(buf), f) != NULL) { | ||||
| 		if (!strlen(buf)) | ||||
| 			break; | ||||
| 		if (ignore_error) | ||||
| 			continue; | ||||
| 		if (first) { | ||||
| 			ULOG_WARN("Command: %s\n", cmd); | ||||
| 			first = false; | ||||
| 		} | ||||
| 		ULOG_WARN("%s%s", buf, strchr(buf, '\n') ? "" : "\n"); | ||||
| 	} | ||||
|  | ||||
| 	fclose(f); | ||||
|  | ||||
| out: | ||||
| 	while (waitpid(pid, &status, 0) < 0) | ||||
| 		if (errno != EINTR) | ||||
| 			break; | ||||
|  | ||||
| 	return status; | ||||
| } | ||||
|  | ||||
| int main(int argc, char **argv) | ||||
| { | ||||
| 	ulog_open(ULOG_STDIO | ULOG_SYSLOG, LOG_DAEMON, "udhcpsnoop"); | ||||
|  | ||||
| 	uloop_init(); | ||||
| 	dhcpsnoop_ubus_init(); | ||||
| 	dhcpsnoop_dev_init(); | ||||
|  | ||||
| 	uloop_run(); | ||||
|  | ||||
| 	dhcpsnoop_ubus_done(); | ||||
| 	dhcpsnoop_dev_done(); | ||||
| 	uloop_done(); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user