mirror of
				https://github.com/Telecominfraproject/wlan-ap.git
				synced 2025-11-04 04:18:07 +00:00 
			
		
		
		
	Compare commits
	
		
			182 Commits
		
	
	
		
			v2.5.0-rc4
			...
			v2.6.0
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					4c21f5c4b6 | ||
| 
						 | 
					cf657dbd94 | ||
| 
						 | 
					33c9876760 | ||
| 
						 | 
					4d6d7405d6 | ||
| 
						 | 
					e249701c34 | ||
| 
						 | 
					0d50975152 | ||
| 
						 | 
					6d87847d15 | ||
| 
						 | 
					eebe021780 | ||
| 
						 | 
					c6e0384f21 | ||
| 
						 | 
					23ae850f72 | ||
| 
						 | 
					708cf2dec6 | ||
| 
						 | 
					a95745d95b | ||
| 
						 | 
					83ccea0abf | ||
| 
						 | 
					bfeaf89238 | ||
| 
						 | 
					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() {
 | 
			
		||||
@@ -61,15 +67,70 @@ add_interface() {
 | 
			
		||||
	add_option boolean ingress
 | 
			
		||||
	add_option boolean egress
 | 
			
		||||
	add_option string mode
 | 
			
		||||
	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 ubus.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
 | 
			
		||||
)
 | 
			
		||||
							
								
								
									
										363
									
								
								feeds/ucentral/radius-gw-proxy/src/main.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										363
									
								
								feeds/ucentral/radius-gw-proxy/src/main.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,363 @@
 | 
			
		||||
/* SPDX-License-Identifier: BSD-3-Clause */
 | 
			
		||||
 | 
			
		||||
#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/ulog.h>
 | 
			
		||||
 | 
			
		||||
#include <libubus.h>
 | 
			
		||||
 | 
			
		||||
#include "ubus.h"
 | 
			
		||||
 | 
			
		||||
#define RAD_PROX_BUFLEN		(4 * 1024)
 | 
			
		||||
 | 
			
		||||
#define TLV_NAS_IP		4
 | 
			
		||||
#define TLV_PROXY_STATE		33
 | 
			
		||||
 | 
			
		||||
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_proxy_state_key {
 | 
			
		||||
	char id[256];
 | 
			
		||||
	enum socket_type type;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct radius_proxy_state {
 | 
			
		||||
	struct avl_node avl;
 | 
			
		||||
	struct radius_proxy_state_key key;
 | 
			
		||||
	int port;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct radius_socket *sock_auth;
 | 
			
		||||
static struct radius_socket *sock_acct;
 | 
			
		||||
static struct radius_socket *sock_dae;
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
avl_memcmp(const void *k1, const void *k2, void *ptr)
 | 
			
		||||
{
 | 
			
		||||
	return memcmp(k1, k2, sizeof(struct radius_proxy_state_key));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static AVL_TREE(radius_proxy_states, avl_memcmp, false, NULL);
 | 
			
		||||
static struct blob_buf b;
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
radius_proxy_state_add(char *id, int port, enum socket_type type)
 | 
			
		||||
{
 | 
			
		||||
	struct radius_proxy_state *station;
 | 
			
		||||
	struct radius_proxy_state_key key = { .type = type };
 | 
			
		||||
 | 
			
		||||
	strcpy(key.id, id);
 | 
			
		||||
	station = avl_find_element(&radius_proxy_states, &key, station, avl);
 | 
			
		||||
 | 
			
		||||
	if (!station) {
 | 
			
		||||
		ULOG_INFO("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_proxy_states, &station->avl);
 | 
			
		||||
	}
 | 
			
		||||
	station->port = port;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static char *
 | 
			
		||||
b64enc(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 char *
 | 
			
		||||
b64dec(char *src, int *ret)
 | 
			
		||||
{
 | 
			
		||||
	int len = strlen(src);
 | 
			
		||||
	char *dst = malloc(len);
 | 
			
		||||
	*ret = b64_decode(src, dst, len);
 | 
			
		||||
	if (*ret < 0)
 | 
			
		||||
		return NULL;
 | 
			
		||||
	return dst;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
radius_forward_gw(char *buf, enum socket_type type)
 | 
			
		||||
{
 | 
			
		||||
	struct radius_header *hdr = (struct radius_header *) buf;
 | 
			
		||||
	struct ubus_request async = { };
 | 
			
		||||
	char *data = b64enc(buf, ntohs(hdr->len));
 | 
			
		||||
 | 
			
		||||
	if (!data || !ucentral)
 | 
			
		||||
		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;
 | 
			
		||||
	case RADIUS_DAS:
 | 
			
		||||
		blobmsg_add_string(&b, "radius", "coa");
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	blobmsg_add_string(&b, "data", data);
 | 
			
		||||
 | 
			
		||||
	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, int tx)
 | 
			
		||||
{
 | 
			
		||||
	struct radius_header *hdr = (struct radius_header *) buf;
 | 
			
		||||
	struct radius_tlv *proxy_state = NULL;
 | 
			
		||||
	char proxy_state_str[256] = {};
 | 
			
		||||
	void *avp = hdr->avp;
 | 
			
		||||
	int len_orig = ntohs(hdr->len);
 | 
			
		||||
	uint8_t localhost[] = { 0x7f, 0, 0, 1 };
 | 
			
		||||
 | 
			
		||||
	if (len_orig != len) {
 | 
			
		||||
		ULOG_ERR("invalid header length, %d %d\n", len_orig, len);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	printf("\tcode:%d, id:%d, len:%d\n", hdr->code, hdr->id, len_orig);
 | 
			
		||||
 | 
			
		||||
	len -= sizeof(*hdr);
 | 
			
		||||
 | 
			
		||||
	while (len > 0) {
 | 
			
		||||
		struct radius_tlv *tlv = (struct radius_tlv *)avp;
 | 
			
		||||
 | 
			
		||||
		if (len < tlv->len) {
 | 
			
		||||
			ULOG_ERR("invalid TLV length\n");
 | 
			
		||||
			return -1;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (tlv->id == TLV_PROXY_STATE)
 | 
			
		||||
			proxy_state = tlv;
 | 
			
		||||
 | 
			
		||||
		if (type == RADIUS_DAS && tlv->id == TLV_NAS_IP && tlv->len == 6)
 | 
			
		||||
			memcpy(tlv->data, &localhost, 4);
 | 
			
		||||
 | 
			
		||||
		printf("\tID:%d, len:%d\n", tlv->id, tlv->len);
 | 
			
		||||
		avp += tlv->len;
 | 
			
		||||
		len -= tlv->len;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (type == RADIUS_DAS) {
 | 
			
		||||
		if (tx) {
 | 
			
		||||
			radius_forward_gw(buf, type);
 | 
			
		||||
		} else {
 | 
			
		||||
			struct sockaddr_in dest;
 | 
			
		||||
 | 
			
		||||
			memset(&dest, 0, sizeof(dest));
 | 
			
		||||
			dest.sin_family = AF_INET;
 | 
			
		||||
			dest.sin_port = htons(3799);
 | 
			
		||||
			inet_pton(AF_INET, "127.0.0.1", &(dest.sin_addr.s_addr));
 | 
			
		||||
 | 
			
		||||
			if (sendto(sock_dae->fd.fd, buf, len_orig,
 | 
			
		||||
				   MSG_DONTWAIT, (struct sockaddr*)&dest, sizeof(dest)) < 0)
 | 
			
		||||
				ULOG_ERR("failed to deliver DAS frame to localhost\n");
 | 
			
		||||
		}
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!proxy_state) {
 | 
			
		||||
		ULOG_ERR("no proxy_state found\n");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	memcpy(proxy_state_str, proxy_state->data, proxy_state->len - 2);
 | 
			
		||||
	printf("\tfowarding to %s, prox_state:%s\n", tx ? "gateway" : "hostapd", proxy_state_str);
 | 
			
		||||
	if (tx) {
 | 
			
		||||
		radius_proxy_state_add(proxy_state_str, port, type);
 | 
			
		||||
		radius_forward_gw(buf, type);
 | 
			
		||||
	} else {
 | 
			
		||||
		struct radius_proxy_state *proxy = avl_find_element(&radius_proxy_states, proxy_state, proxy, avl);
 | 
			
		||||
		struct radius_proxy_state_key key = {};
 | 
			
		||||
		struct sockaddr_in dest;
 | 
			
		||||
		struct radius_socket *sock;
 | 
			
		||||
 | 
			
		||||
		switch(type) {
 | 
			
		||||
		case RADIUS_AUTH:
 | 
			
		||||
			sock = sock_auth;
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case RADIUS_ACCT:
 | 
			
		||||
			sock = sock_acct;
 | 
			
		||||
			break;
 | 
			
		||||
		default:
 | 
			
		||||
			ULOG_ERR("bad socket type\n");
 | 
			
		||||
			return -1;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		strcpy(key.id, proxy_state_str);
 | 
			
		||||
		key.type = type;
 | 
			
		||||
		proxy = avl_find_element(&radius_proxy_states, &key, proxy, avl);
 | 
			
		||||
 | 
			
		||||
		if (!proxy) {
 | 
			
		||||
			ULOG_ERR("unknown proxy_state, dropping frame\n");
 | 
			
		||||
			return -1;
 | 
			
		||||
		}
 | 
			
		||||
		memset(&dest, 0, sizeof(dest));
 | 
			
		||||
		dest.sin_family = AF_INET;
 | 
			
		||||
		dest.sin_port = proxy->port;
 | 
			
		||||
		inet_pton(AF_INET, "127.0.0.1", &(dest.sin_addr.s_addr));
 | 
			
		||||
 | 
			
		||||
		if (sendto(sock->fd.fd, buf, len_orig,
 | 
			
		||||
			   MSG_DONTWAIT, (struct sockaddr*)&dest, sizeof(dest)) < 0)
 | 
			
		||||
			ULOG_ERR("failed to deliver frame to localhost\n");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
gateway_recv(char *data, enum socket_type type)
 | 
			
		||||
{
 | 
			
		||||
	int len = 0;
 | 
			
		||||
	char *frame;
 | 
			
		||||
 | 
			
		||||
	frame = b64dec(data, &len);
 | 
			
		||||
 | 
			
		||||
	if (!frame) {
 | 
			
		||||
		ULOG_ERR("failed to b64_decode frame\n");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	radius_parse(frame, len, 0, type, 0);
 | 
			
		||||
	free(frame);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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 radius_socket *sock = container_of(u, struct radius_socket, fd);
 | 
			
		||||
	int len;
 | 
			
		||||
 | 
			
		||||
	do {
 | 
			
		||||
		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;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		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, 1);
 | 
			
		||||
	} while (1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct radius_socket *
 | 
			
		||||
sock_open(char *port, enum socket_type type)
 | 
			
		||||
{
 | 
			
		||||
	struct radius_socket *sock = malloc(sizeof(*sock));
 | 
			
		||||
 | 
			
		||||
	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;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
	sock->type = type;
 | 
			
		||||
	sock->fd.cb = sock_recv;
 | 
			
		||||
 | 
			
		||||
	uloop_fd_add(&sock->fd, ULOOP_READ);
 | 
			
		||||
 | 
			
		||||
	return sock;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main(int argc, char **argv)
 | 
			
		||||
{
 | 
			
		||||
	ulog_open(ULOG_STDIO | ULOG_SYSLOG, LOG_DAEMON, "radius-gw-proxy");
 | 
			
		||||
 | 
			
		||||
	uloop_init();
 | 
			
		||||
 | 
			
		||||
	ubus_init();
 | 
			
		||||
 | 
			
		||||
	sock_auth = sock_open("1812", RADIUS_AUTH);
 | 
			
		||||
	sock_acct = sock_open("1813", RADIUS_ACCT);
 | 
			
		||||
	sock_dae = sock_open("1814", RADIUS_DAS);
 | 
			
		||||
 | 
			
		||||
	uloop_run();
 | 
			
		||||
	uloop_end();
 | 
			
		||||
	ubus_deinit();
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										124
									
								
								feeds/ucentral/radius-gw-proxy/src/ubus.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								feeds/ucentral/radius-gw-proxy/src/ubus.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,124 @@
 | 
			
		||||
/* SPDX-License-Identifier: BSD-3-Clause */
 | 
			
		||||
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#include <libubox/ulog.h>
 | 
			
		||||
#include <libubus.h>
 | 
			
		||||
#include "ubus.h"
 | 
			
		||||
 | 
			
		||||
struct ubus_auto_conn conn;
 | 
			
		||||
uint32_t ucentral;
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
	RADIUS_TYPE,
 | 
			
		||||
	RADIUS_DATA,
 | 
			
		||||
	__RADIUS_MAX,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct blobmsg_policy frame_policy[__RADIUS_MAX] = {
 | 
			
		||||
	[RADIUS_TYPE] = { .name = "radius", .type = BLOBMSG_TYPE_STRING },
 | 
			
		||||
	[RADIUS_DATA] = { .name = "data", .type = BLOBMSG_TYPE_STRING },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int ubus_frame_cb(struct ubus_context *ctx,
 | 
			
		||||
			 struct ubus_object *obj,
 | 
			
		||||
			 struct ubus_request_data *req,
 | 
			
		||||
			 const char *method, struct blob_attr *msg)
 | 
			
		||||
{
 | 
			
		||||
	struct blob_attr *tb[__RADIUS_MAX] = {};
 | 
			
		||||
	enum socket_type type;
 | 
			
		||||
	char *radius, *data;
 | 
			
		||||
 | 
			
		||||
	blobmsg_parse(frame_policy, __RADIUS_MAX, tb, blobmsg_data(msg), blobmsg_data_len(msg));
 | 
			
		||||
	if (!tb[RADIUS_TYPE] || !tb[RADIUS_DATA])
 | 
			
		||||
		return UBUS_STATUS_INVALID_ARGUMENT;
 | 
			
		||||
 | 
			
		||||
	radius = blobmsg_get_string(tb[RADIUS_TYPE]);
 | 
			
		||||
	data = blobmsg_get_string(tb[RADIUS_DATA]);
 | 
			
		||||
 | 
			
		||||
	if (!strcmp(radius, "auth"))
 | 
			
		||||
		type = RADIUS_AUTH;
 | 
			
		||||
	else if (!strcmp(radius, "acct"))
 | 
			
		||||
		type = RADIUS_ACCT;
 | 
			
		||||
	else if (!strcmp(radius, "coa"))
 | 
			
		||||
		type = RADIUS_DAS;
 | 
			
		||||
	else
 | 
			
		||||
		return UBUS_STATUS_INVALID_ARGUMENT;
 | 
			
		||||
 | 
			
		||||
	gateway_recv(data, type);
 | 
			
		||||
 | 
			
		||||
	return UBUS_STATUS_OK;
 | 
			
		||||
}
 | 
			
		||||
static const struct ubus_method ucentral_methods[] = {
 | 
			
		||||
	UBUS_METHOD("frame", ubus_frame_cb, frame_policy),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct ubus_object_type ubus_object_type =
 | 
			
		||||
	UBUS_OBJECT_TYPE("radius.proxy", ucentral_methods);
 | 
			
		||||
 | 
			
		||||
struct ubus_object ubus_object = {
 | 
			
		||||
	.name = "radius.proxy",
 | 
			
		||||
	.type = &ubus_object_type,
 | 
			
		||||
	.methods = ucentral_methods,
 | 
			
		||||
	.n_methods = ARRAY_SIZE(ucentral_methods),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
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_add_object(ctx, &ubus_object);
 | 
			
		||||
	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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ubus_init(void)
 | 
			
		||||
{
 | 
			
		||||
	memset(&conn, 0, sizeof(conn));
 | 
			
		||||
	ucentral = 0;
 | 
			
		||||
	conn.cb = ubus_connect_handler;
 | 
			
		||||
	ubus_auto_connect(&conn);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ubus_deinit(void)
 | 
			
		||||
{
 | 
			
		||||
	ubus_auto_shutdown(&conn);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										13
									
								
								feeds/ucentral/radius-gw-proxy/src/ubus.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								feeds/ucentral/radius-gw-proxy/src/ubus.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
			
		||||
enum socket_type {
 | 
			
		||||
	RADIUS_AUTH = 0,
 | 
			
		||||
	RADIUS_ACCT,
 | 
			
		||||
	RADIUS_DAS
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
extern struct ubus_auto_conn conn;
 | 
			
		||||
extern uint32_t ucentral;
 | 
			
		||||
 | 
			
		||||
void ubus_init(void);
 | 
			
		||||
void ubus_deinit(void);
 | 
			
		||||
void gateway_recv(char *data, enum socket_type type);
 | 
			
		||||
 | 
			
		||||
@@ -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:=2fc20dd3b5c8a7d93e17a843a2feaa823a6f8e902fdca96df62aa3f12efdfbaa
 | 
			
		||||
PKG_SOURCE_PROTO:=git
 | 
			
		||||
PKG_SOURCE_DATE:=2022-01-10
 | 
			
		||||
PKG_SOURCE_VERSION:=e3b71c61e1a07bb3b5fa34fe835fd8f6f708caa3
 | 
			
		||||
PKG_SOURCE_DATE:=2022-06-22
 | 
			
		||||
PKG_SOURCE_VERSION:=68fe6c21f2c2643de79ecd5558a51ffb84168f75
 | 
			
		||||
 | 
			
		||||
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:=3603ddd26026d3a5b0febe7fbae22fd28fd6d7370793ecf979561d8886be2af4
 | 
			
		||||
PKG_SOURCE_PROTO:=git
 | 
			
		||||
PKG_SOURCE_DATE:=2022-01-17
 | 
			
		||||
PKG_SOURCE_VERSION:=19fcc8d8163e84734d34dc7dd9767c2fa133fa16
 | 
			
		||||
PKG_SOURCE_DATE:=2022-05-29
 | 
			
		||||
PKG_SOURCE_VERSION:=9691cc6860c25ba7d62142846da44bd09c17acc0
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
@@ -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;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user