Merge 4.19.239 into android-4.19-stable
Linux 4.19.239
i2c: pasemi: Wait for write xfers to finish
* smp: Fix offline cpu check in flush_smp_call_function_queue()
kernel/smp.c
ARM: davinci: da850-evm: Avoid NULL pointer dereference
* ipv6: fix panic when forwarding a pkt with no in6 dev
net/ipv6/ip6_output.c
* ALSA: pcm: Test for "silence" field in struct "pcm_format_data"
sound/core/pcm_misc.c
ALSA: hda/realtek: Add quirk for Clevo PD50PNT
gcc-plugins: latent_entropy: use /dev/urandom
mm: kmemleak: take a full lowmem check in kmemleak_*_phys()
* mm, page_alloc: fix build_zonerefs_node()
mm/page_alloc.c
drivers: net: slip: fix NPD bug in sl_tx_timeout()
scsi: mvsas: Add PCI ID of RocketRaid 2640
drm/amd/display: Fix allocate_mst_payload assert on resume
* arm64: alternatives: mark patch_alternative() as `noinstr`
arch/arm64/kernel/alternative.c
gpu: ipu-v3: Fix dev_dbg frequency output
ata: libata-core: Disable READ LOG DMA EXT for Samsung 840 EVOs
* net: micrel: fix KS8851_MLL Kconfig
drivers/net/ethernet/micrel/Kconfig
scsi: ibmvscsis: Increase INITIAL_SRP_LIMIT to 1024
scsi: target: tcmu: Fix possible page UAF
Drivers: hv: vmbus: Prevent load re-ordering when reading ring buffer
drm/amdkfd: Check for potential null return of kmalloc_array()
drm/amd: Add USBC connector ID
cifs: potential buffer overflow in handling symlinks
nfc: nci: add flush_workqueue to prevent uaf
testing/selftests/mqueue: Fix mq_perf_tests to free the allocated cpu set
* sctp: Initialize daddr on peeled off socket
net/sctp/socket.c
net: ethernet: stmmac: fix altr_tse_pcs function when using a fixed-link
mlxsw: i2c: Fix initialization error flow
gpiolib: acpi: use correct format characters
* veth: Ensure eth header is in skb's linear part
drivers/net/veth.c
* net/sched: flower: fix parsing of ethertype following VLAN header
include/net/flow_dissector.h
net/core/flow_dissector.c
memory: atmel-ebi: Fix missing of_node_put in atmel_ebi_probe
* ANDROID: GKI: fix crc issue with commit 6281beee5b ("block: don't merge across cgroup boundaries if blkcg is enabled")
block/blk-merge.c
include/linux/blk-cgroup.h
* Revert "PCI: Reduce warnings on possible RW1C corruption"
drivers/pci/access.c
include/linux/pci.h
Merge 4.19.238 into android-4.19-stable
Linux 4.19.238
drm/amdkfd: Use drm_priv to pass VM from KFD to amdgpu
drm/amdgpu: Check if fd really is an amdgpu fd.
* xfrm: policy: match with both mark and mask on user interfaces
include/net/xfrm.h
net/key/af_key.c
net/xfrm/xfrm_policy.c
net/xfrm/xfrm_user.c
selftests: cgroup: Test open-time cgroup namespace usage for migration checks
selftests: cgroup: Test open-time credential usage for migration checks
selftests: cgroup: Make cg_create() use 0755 for permission instead of 0644
* cgroup: Use open-time cgroup namespace for process migration perm checks
kernel/cgroup/cgroup-internal.h
kernel/cgroup/cgroup.c
* cgroup: Allocate cgroup_file_ctx for kernfs_open_file->priv
kernel/cgroup/cgroup-internal.h
kernel/cgroup/cgroup-v1.c
kernel/cgroup/cgroup.c
* cgroup: Use open-time credentials for process migraton perm checks
kernel/cgroup/cgroup-v1.c
kernel/cgroup/cgroup.c
* mm/sparsemem: fix 'mem_section' will never be NULL gcc 12 warning
include/linux/mmzone.h
* arm64: module: remove (NOLOAD) from linker script
arch/arm64/kernel/module.lds
* mm: don't skip swap entry even if zap_details specified
mm/memory.c
dmaengine: Revert "dmaengine: shdma: Fix runtime PM imbalance on error"
tools build: Use $(shell ) instead of `` to get embedded libperl's ccopts
tools build: Filter out options and warnings not supported by clang
* irqchip/gic-v3: Fix GICR_CTLR.RWP polling
drivers/irqchip/irq-gic-v3.c
perf: qcom_l2_pmu: fix an incorrect NULL check on list iterator
ata: sata_dwc_460ex: Fix crash due to OOB write
* arm64: patch_text: Fixup last cpu should be master
arch/arm64/kernel/insn.c
btrfs: fix qgroup reserve overflow the qgroup limit
x86/speculation: Restore speculation related MSRs during S3 resume
x86/pm: Save the MSR validity status at context setup
mm/mempolicy: fix mpol_new leak in shared_policy_replace
* mmmremap.c: avoid pointless invalidate_range_start/end on mremap(old_size=0)
mm/mremap.c
mmc: renesas_sdhi: don't overwrite TAP settings when HS400 tuning is complete
Revert "mmc: sdhci-xenon: fix annoying 1.8V regulator warning"
drbd: Fix five use after free bugs in get_initial_state
spi: bcm-qspi: fix MSPI only access with bcm_qspi_exec_mem_op()
qede: confirm skb is allocated before using
rxrpc: fix a race in rxrpc_exit_net()
net: openvswitch: don't send internal clone attribute to the userspace.
drm/imx: Fix memory leak in imx_pd_connector_get_modes
net: stmmac: Fix unset max_speed difference between DT and non-DT platforms
scsi: zorro7xx: Fix a resource leak in zorro7xx_remove_one()
Drivers: hv: vmbus: Fix potential crash on module unload
drm/amdgpu: fix off by one in amdgpu_gfx_kiq_acquire()
* KVM: arm64: Check arm64_get_bp_hardening_data() didn't return NULL
arch/arm64/include/asm/kvm_mmu.h
* mm: fix race between MADV_FREE reclaim and blkdev direct IO read
mm/rmap.c
* net: add missing SOF_TIMESTAMPING_OPT_ID support
include/net/sock.h
net/ipv4/raw.c
net/ipv6/raw.c
net/packet/af_packet.c
parisc: Fix CPU affinity for Lasi, WAX and Dino chips
jfs: prevent NULL deref in diFree
virtio_console: eliminate anonymous module_init & module_exit
serial: samsung_tty: do not unlock port->lock for uart_write_wakeup()
NFS: swap-out must always use STABLE writes.
* NFS: swap IO handling is slightly different for O_DIRECT IO
include/linux/nfs_fs.h
SUNRPC/call_alloc: async tasks mustn't block waiting for memory
* clk: Enforce that disjoints limits are invalid
drivers/clk/clk.c
xen: delay xen_hvm_init_time_ops() if kdump is boot on vcpu>=32
NFSv4: Protect the state recovery thread against direct reclaim
w1: w1_therm: fixes w1_seq for ds28ea00 sensors
minix: fix bug when opening a file with O_DIRECT
* init/main.c: return 1 from handled __setup() functions
init/main.c
* Bluetooth: Fix use after free in hci_send_acl
net/bluetooth/hci_event.c
xtensa: fix DTC warning unit_address_format
usb: dwc3: omap: fix "unbalanced disables for smps10_out1" on omap5evm
scsi: libfc: Fix use after free in fc_exch_abts_resp()
MIPS: fix fortify panic when copying asm exception handlers
bnxt_en: Eliminate unintended link toggle during FW reset
macvtap: advertise link netns via netlink
net/smc: correct settings of RMB window update limit
scsi: aha152x: Fix aha152x_setup() __setup handler return value
scsi: pm8001: Fix pm8001_mpi_task_abort_resp()
drm/amdkfd: make CRAT table missing message informational only
* dm ioctl: prevent potential spectre v1 gadget
drivers/md/dm-ioctl.c
* ipv4: Invalidate neighbour for broadcast address upon address addition
include/net/arp.h
net/ipv4/arp.c
net/ipv4/fib_frontend.c
PCI: pciehp: Add Qualcomm quirk for Command Completed erratum
* usb: ehci: add pci device support for Aspeed platforms
drivers/usb/host/ehci-pci.c
iommu/arm-smmu-v3: fix event handling soft lockup
PCI: aardvark: Fix support for MSI interrupts
powerpc: Set crashkernel offset to mid of RMA region
power: supply: axp20x_battery: properly report current when discharging
scsi: bfa: Replace snprintf() with sysfs_emit()
scsi: mvsas: Replace snprintf() with sysfs_emit()
powerpc: dts: t104xrdb: fix phy type for FMAN 4/5
* ptp: replace snprintf with sysfs_emit
drivers/ptp/ptp_sysfs.c
drm/amd/amdgpu/amdgpu_cs: fix refcount leak of a dma_fence obj
ath5k: fix OOB in ath5k_eeprom_read_pcal_info_5111
* drm: Add orientation quirk for GPD Win Max
drivers/gpu/drm/drm_panel_orientation_quirks.c
KVM: x86/svm: Clear reserved bits written to PerfEvtSeln MSRs
ARM: 9187/1: JIVE: fix return value of __setup handler
riscv module: remove (NOLOAD)
rtc: wm8350: Handle error for wm8350_register_irq
ubifs: Rectify space amount budget for mkdir/tmpfile operations
KVM: x86: Forbid VMM to set SYNIC/STIMER MSRs when SynIC wasn't activated
openvswitch: Fixed nd target mask field in the flow dump.
um: Fix uml_mconsole stop/go
ARM: dts: spear13xx: Update SPI dma properties
ARM: dts: spear1340: Update serial node properties
ASoC: topology: Allow TLV control to be either read or write
ubi: fastmap: Return error code if memory allocation fails in add_aeb()
* bpf: Fix comment for helper bpf_current_task_under_cgroup()
include/uapi/linux/bpf.h
* mm/usercopy: return 1 from hardened_usercopy __setup() handler
mm/usercopy.c
* mm/memcontrol: return 1 from cgroup.memory __setup() handler
mm/memcontrol.c
* mm/mmap: return 1 from stack_guard_gap __setup() handler
mm/mmap.c
ACPI: CPPC: Avoid out of bounds access when parsing _CPC data
ubi: Fix race condition between ctrl_cdev_ioctl and ubi_cdev_ioctl
* pinctrl: pinconf-generic: Print arguments for bias-pull-*
drivers/pinctrl/pinconf-generic.c
gfs2: Make sure FITRIM minlen is rounded up to fs block size
can: mcba_usb: properly check endpoint type
can: mcba_usb: mcba_usb_start_xmit(): fix double dev_kfree_skb in error path
ubifs: rename_whiteout: correct old_dir size computing
ubifs: Fix read out-of-bounds in ubifs_wbuf_write_nolock()
ubifs: setflags: Make dirtied_ino_d 8 bytes aligned
ubifs: Add missing iput if do_tmpfile() failed in rename whiteout
ubifs: Fix deadlock in concurrent rename whiteout and inode writeback
ubifs: rename_whiteout: Fix double free for whiteout_ui->data
KVM: x86: fix sending PV IPI
KVM: Prevent module exit until all VMs are freed
scsi: qla2xxx: Use correct feature type field during RFF_ID processing
scsi: qla2xxx: Reduce false trigger to login
scsi: qla2xxx: Fix hang due to session stuck
scsi: qla2xxx: Fix incorrect reporting of task management failure
scsi: qla2xxx: Suppress a kernel complaint in qla_create_qpair()
scsi: qla2xxx: Check for firmware dump already collected
scsi: qla2xxx: Fix warning for missing error code
scsi: qla2xxx: Fix stuck session in gpdb
powerpc: Fix build errors with newer binutils
powerpc/lib/sstep: Fix build errors with newer binutils
powerpc/lib/sstep: Fix 'sthcx' instruction
mmc: host: Return an error when ->enable_sdio_irq() ops is missing
media: hdpvr: initialize dev->worker at hdpvr_register_videodev
media: Revert "media: em28xx: add missing em28xx_close_extension"
video: fbdev: sm712fb: Fix crash in smtcfb_write()
ARM: mmp: Fix failure to remove sram device
ARM: tegra: tamonten: Fix I2C3 pad setting
media: cx88-mpeg: clear interrupt status register before streaming video
* ASoC: soc-core: skip zero num_dai component in searching dai name
sound/soc/soc-core.c
video: fbdev: udlfb: replace snprintf in show functions with sysfs_emit
video: fbdev: omapfb: panel-tpo-td043mtea1: Use sysfs_emit() instead of snprintf()
video: fbdev: omapfb: panel-dsi-cm: Use sysfs_emit() instead of snprintf()
ARM: dts: bcm2837: Add the missing L1/L2 cache information
ARM: dts: qcom: fix gic_irq_domain_translate warnings for msm8960
video: fbdev: omapfb: acx565akm: replace snprintf with sysfs_emit
video: fbdev: cirrusfb: check pixclock to avoid divide by zero
video: fbdev: w100fb: Reset global state
video: fbdev: nvidiafb: Use strscpy() to prevent buffer overflow
ntfs: add sanity check on allocation size
* ext4: don't BUG if someone dirty pages without asking ext4 first
fs/ext4/inode.c
spi: tegra20: Use of_device_get_match_data()
* PM: core: keep irq flags in device_pm_check_callbacks()
drivers/base/power/main.c
ACPI/APEI: Limit printable size of BERT table data
Revert "Revert "block, bfq: honor already-setup queue merges""
lib/raid6/test/Makefile: Use $(pound) instead of \# for Make 4.3
ACPICA: Avoid walking the ACPI Namespace if it is not there
bfq: fix use-after-free in bfq_dispatch_request
irqchip/nvic: Release nvic_base upon failure
* irqchip/qcom-pdc: Fix broken locking
drivers/irqchip/qcom-pdc.c
Fix incorrect type in assignment of ipv6 port for audit
* loop: use sysfs_emit() in the sysfs xxx show()
drivers/block/loop.c
selinux: use correct type for context length
lib/test: use after free in register_test_dev_kmod()
NFSv4/pNFS: Fix another issue with a list iterator pointing to the head
net/x25: Fix null-ptr-deref caused by x25_disconnect
qlcnic: dcb: default to returning -EOPNOTSUPP
net: phy: broadcom: Fix brcm_fet_config_init()
xen: fix is_xen_pmu()
clk: qcom: gcc-msm8994: Fix gpll4 width
* netfilter: nf_conntrack_tcp: preserve liberal flag in tcp options
net/netfilter/nf_conntrack_proto_tcp.c
jfs: fix divide error in dbNextAG
kgdbts: fix return value of __setup handler
kgdboc: fix return value of __setup handler
tty: hvc: fix return value of __setup handler
pinctrl/rockchip: Add missing of_node_put() in rockchip_pinctrl_probe
pinctrl: nomadik: Add missing of_node_put() in nmk_pinctrl_probe
pinctrl: mediatek: Fix missing of_node_put() in mtk_pctrl_init
NFS: remove unneeded check in decode_devicenotify_args()
clk: tegra: tegra124-emc: Fix missing put_device() call in emc_ensure_emc_driver
clk: clps711x: Terminate clk_div_table with sentinel element
clk: loongson1: Terminate clk_div_table with sentinel element
clk: actions: Terminate clk_div_table with sentinel element
remoteproc: qcom_wcnss: Add missing of_node_put() in wcnss_alloc_memory_region
* clk: qcom: clk-rcg2: Update the frac table for pixel clock
drivers/clk/qcom/clk-rcg2.c
dma-debug: fix return value of __setup handlers
iio: adc: Add check for devm_request_threaded_irq
serial: 8250: Fix race condition in RTS-after-send handling
serial: 8250_mid: Balance reference count for PCI DMA device
clk: qcom: ipq8074: Use floor ops for SDCC1 clock
staging:iio:adc:ad7280a: Fix handing of device address bit reversing.
pwm: lpc18xx-sct: Initialize driver data and hardware before pwmchip_add()
mxser: fix xmit_buf leak in activate when LSR == 0xff
mfd: asic3: Add missing iounmap() on error asic3_mfd_probe
* tcp: ensure PMTU updates are processed during fastopen
net/ipv4/tcp_output.c
selftests/bpf/test_lirc_mode2.sh: Exit with proper code
i2c: mux: demux-pinctrl: do not deactivate a master that is not active
* af_netlink: Fix shift out of bounds in group mask calculation
net/netlink/af_netlink.c
USB: storage: ums-realtek: fix error code in rts51x_read_mem()
mtd: rawnand: atmel: fix refcount issue in atmel_nand_controller_init
MIPS: RB532: fix return value of __setup handler
vxcan: enable local echo for sent CAN frames
mfd: mc13xxx: Add check for mc13xxx_irq_request
powerpc/sysdev: fix incorrect use to determine if list is empty
* PCI: Reduce warnings on possible RW1C corruption
drivers/pci/access.c
include/linux/pci.h
power: supply: wm8350-power: Add missing free in free_charger_irq
power: supply: wm8350-power: Handle error for wm8350_register_irq
i2c: xiic: Make bus names unique
hv_balloon: rate-limit "Unhandled message" warning
KVM: x86/emulator: Defer not-present segment check in __load_segment_descriptor()
KVM: x86: Fix emulation in writing cr8
powerpc/Makefile: Don't pass -mcpu=powerpc64 when building 32-bit
drm/bridge: cdns-dsi: Make sure to to create proper aliases for dt
power: supply: bq24190_charger: Fix bq24190_vbus_is_enabled() wrong false return
drm/tegra: Fix reference leak in tegra_dsi_ganged_probe
ext2: correct max file size computing
TOMOYO: fix __setup handlers return values
scsi: pm8001: Fix abort all task initialization
scsi: pm8001: Fix payload initialization in pm80xx_set_thermal_config()
scsi: pm8001: Fix command initialization in pm8001_chip_ssp_tm_req()
scsi: pm8001: Fix command initialization in pm80XX_send_read_log()
dm crypt: fix get_key_size compiler warning if !CONFIG_KEYS
iwlwifi: Fix -EIO error code that is never returned
HID: i2c-hid: fix GET/SET_REPORT for unnumbered reports
power: supply: ab8500: Fix memory leak in ab8500_fg_sysfs_init
ray_cs: Check ioremap return value
power: reset: gemini-poweroff: Fix IRQ check in gemini_poweroff_probe
KVM: PPC: Fix vmx/vsx mixup in mmio emulation
ath9k_htc: fix uninit value bugs
drm/amd/display: Fix a NULL pointer dereference in amdgpu_dm_connector_add_common_modes()
* drm/edid: Don't clear formats if using deep color
drivers/gpu/drm/drm_edid.c
mtd: onenand: Check for error irq
Bluetooth: hci_serdev: call init_rwsem() before p->open()
ath10k: fix memory overwrite of the WoWLAN wakeup packet pattern
drm/bridge: Fix free wrong object in sii8620_init_rcp_input_dev
mmc: davinci_mmc: Handle error for clk_enable
ASoC: msm8916-wcd-digital: Fix missing clk_disable_unprepare() in msm8916_wcd_digital_probe
ASoC: imx-es8328: Fix error return code in imx_es8328_probe()
ASoC: mxs: Fix error handling in mxs_sgtl5000_probe
ASoC: dmaengine: do not use a NULL prepare_slave_config() callback
video: fbdev: omapfb: Add missing of_node_put() in dvic_probe_of
ASoC: fsi: Add check for clk_enable
ASoC: wm8350: Handle error for wm8350_register_irq
ASoC: atmel: Add missing of_node_put() in at91sam9g20ek_audio_probe
media: stk1160: If start stream fails, return buffers with VB2_BUF_STATE_QUEUED
ALSA: firewire-lib: fix uninitialized flag for AV/C deferred transaction
memory: emif: check the pointer temp in get_device_details()
memory: emif: Add check for setup_interrupts
ASoC: atmel_ssc_dai: Handle errors for clk_enable
ASoC: mxs-saif: Handle errors for clk_enable
* printk: fix return value of printk.devkmsg __setup handler
kernel/printk/printk.c
arm64: dts: broadcom: Fix sata nodename
arm64: dts: ns2: Fix spi-cpol and spi-cpha property
ALSA: spi: Add check for clk_enable()
ASoC: ti: davinci-i2s: Add check for clk_enable()
ASoC: rt5663: check the return value of devm_kzalloc() in rt5663_parse_dp()
media: usb: go7007: s2250-board: fix leak in probe()
media: em28xx: initialize refcount before kref_get
soc: ti: wkup_m3_ipc: Fix IRQ check in wkup_m3_ipc_probe
ARM: dts: qcom: ipq4019: fix sleep clock
video: fbdev: fbcvt.c: fix printing in fb_cvt_print_name()
video: fbdev: smscufx: Fix null-ptr-deref in ufx_usb_probe()
media: coda: Fix missing put_device() call in coda_get_vdoa_data
perf/x86/intel/pt: Fix address filter config for 32-bit kernel
* perf/core: Fix address filter parser for multiple filters
kernel/events/core.c
* sched/debug: Remove mpol_get/put and task_lock/unlock from sched_show_numa
kernel/sched/debug.c
clocksource: acpi_pm: fix return value of __setup handler
hwmon: (pmbus) Add Vin unit off handling
crypto: ccp - ccp_dmaengine_unregister release dma channels
ACPI: APEI: fix return value of __setup handlers
* clocksource/drivers/timer-of: Check return value of of_iomap in timer_of_base_init()
drivers/clocksource/timer-of.c
* crypto: vmx - add missing dependencies
drivers/crypto/vmx/Kconfig
hwrng: atmel - disable trng on failure path
PM: suspend: fix return value of __setup handler
PM: hibernate: fix __setup handler error handling
* block: don't delete queue kobject before its children
block/blk-sysfs.c
hwmon: (sch56xx-common) Replace WDOG_ACTIVE with WDOG_HW_RUNNING
hwmon: (pmbus) Add mutex to regulator ops
spi: pxa2xx-pci: Balance reference count for PCI DMA device
selftests/x86: Add validity check and allow field splitting
spi: tegra114: Add missing IRQ check in tegra_spi_probe
crypto: mxs-dcp - Fix scatterlist processing
* crypto: authenc - Fix sleep in atomic context in decrypt_tail
crypto/authenc.c
regulator: qcom_smd: fix for_each_child.cocci warnings
PCI: pciehp: Clear cmd_busy bit in polling mode
brcmfmac: pcie: Replace brcmf_pcie_copy_mem_todev with memcpy_toio
brcmfmac: firmware: Allocate space for default boardrev in nvram
media: davinci: vpif: fix unbalanced runtime PM get
DEC: Limit PMAX memory probing to R3k systems
lib/raid6/test: fix multiple definition linking error
thermal: int340x: Increase bitmap size
carl9170: fix missing bit-wise or operator for tx_params
ARM: dts: exynos: add missing HDMI supplies on SMDK5420
ARM: dts: exynos: add missing HDMI supplies on SMDK5250
ARM: dts: exynos: fix UART3 pins configuration in Exynos5250
ARM: dts: at91: sama5d2: Fix PMERRLOC resource size
video: fbdev: atari: Atari 2 bpp (STe) palette bugfix
video: fbdev: sm712fb: Fix crash in smtcfb_read()
* drm/edid: check basic audio support on CEA extension block
drivers/gpu/drm/drm_edid.c
* block: don't merge across cgroup boundaries if blkcg is enabled
block/blk-merge.c
include/linux/blk-cgroup.h
drivers: hamradio: 6pack: fix UAF bug caused by mod_timer()
ACPI: properties: Consistently return -ENOENT if there are no more references
powerpc/kvm: Fix kvm_use_magic_page
drbd: fix potential silent data corruption
* mm,hwpoison: unmap poisoned page before invalidation
mm/memory.c
ALSA: hda/realtek: Fix audio regression on Mi Notebook Pro 2020
ALSA: cs4236: fix an incorrect NULL check on list iterator
* Revert "Input: clear BTN_RIGHT/MIDDLE on buttonpads"
drivers/input/input.c
qed: validate and restrict untrusted VFs vlan promisc mode
qed: display VF trust config
scsi: libsas: Fix sas_ata_qc_issue() handling of NCQ NON DATA commands
mempolicy: mbind_range() set_policy() after vma_merge()
* mm: invalidate hwpoison page cache page in fault path
mm/memory.c
* mm/pages_alloc.c: don't create ZONE_MOVABLE beyond the end of a node
mm/page_alloc.c
jffs2: fix memory leak in jffs2_scan_medium
jffs2: fix memory leak in jffs2_do_mount_fs
jffs2: fix use-after-free in jffs2_clear_xattr_subsystem
can: ems_usb: ems_usb_start_xmit(): fix double dev_kfree_skb() in error path
pinctrl: samsung: drop pin banks references on error paths
* f2fs: fix to unlock page correctly in error path of is_alive()
fs/f2fs/gc.c
* NFSD: prevent integer overflow on 32 bit systems
include/linux/sunrpc/xdr.h
NFSD: prevent underflow in nfssvc_decode_writeargs()
SUNRPC: avoid race between mod_timer() and del_timer_sync()
Documentation: update stable tree link
Documentation: add link to stable release candidate tree
* ptrace: Check PTRACE_O_SUSPEND_SECCOMP permission on PTRACE_SEIZE
kernel/ptrace.c
clk: uniphier: Fix fixed-rate initialization
* iio: inkern: make a best effort on offset calculation
drivers/iio/inkern.c
* iio: inkern: apply consumer scale when no channel scale is available
drivers/iio/inkern.c
* iio: inkern: apply consumer scale on IIO_VAL_INT cases
drivers/iio/inkern.c
iio: afe: rescale: use s64 for temporary scale calculations
* coresight: Fix TRCCONFIGR.QE sysfs interface
drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
* xhci: make xhci_handshake timeout for xhci_reset() adjustable
drivers/usb/host/xhci-hub.c
drivers/usb/host/xhci-mem.c
drivers/usb/host/xhci.c
drivers/usb/host/xhci.h
USB: usb-storage: Fix use of bitfields for hardware data in ene_ub6250.c
virtio-blk: Use blk_validate_block_size() to validate block size
* block: Add a helper to validate the block size
include/linux/blkdev.h
tpm: fix reference counting for struct tpm_chip
* fuse: fix pipe buffer lifetime for direct_io
fs/fuse/dev.c
fs/fuse/file.c
fs/fuse/fuse_i.h
* af_key: add __GFP_ZERO flag for compose_sadb_supported in function pfkey_register
net/key/af_key.c
* spi: Fix erroneous sgs value with min_t()
drivers/spi/spi.c
net:mcf8390: Use platform_get_irq() to get the interrupt
* spi: Fix invalid sgs value
drivers/spi/spi.c
ethernet: sun: Free the coherent when failing in probing
virtio_console: break out of buf poll on remove
* xfrm: fix tunnel model fragmentation behavior
net/ipv6/xfrm6_output.c
net/xfrm/xfrm_interface.c
* netdevice: add the case if dev is NULL
include/linux/netdevice.h
* USB: serial: simple: add Nokia phone driver
drivers/usb/serial/Kconfig
USB: serial: pl2303: add IBM device IDs
* ANDROID: incremental-fs: limit mount stack depth
fs/incfs/data_mgmt.h
fs/incfs/vfs.c
* UPSTREAM: binderfs: use __u32 for device numbers
include/uapi/linux/android/binderfs.h
Revert "ANDROID: dm-bow: Protect Ranges fetched and erased from the RB tree"
Merge 4.19.237 into android-4.19-stable
Linux 4.19.237
llc: only change llc->dev when bind() succeeds
nds32: fix access_ok() checks in get/put_user
mac80211: fix potential double free on mesh join
crypto: qat - disable registration of algorithms
ACPI: video: Force backlight native for Clevo NL5xRU and NL5xNU
ACPI: battery: Add device HID and quirk for Microsoft Surface Go 3
ACPI / x86: Work around broken XSDT on Advantech DAC-BJ01 board
netfilter: nf_tables: initialize registers in nft_do_chain()
drivers: net: xgene: Fix regression in CRC stripping
ALSA: pci: fix reading of swapped values from pcmreg in AC97 codec
ALSA: cmipci: Restore aux vol on suspend/resume
* ALSA: usb-audio: Add mute TLV for playback volumes on RODE NT-USB
sound/usb/mixer_quirks.c
* ALSA: pcm: Add stream lock during PCM reset ioctl operations
sound/core/pcm_native.c
ALSA: oss: Fix PCM OSS buffer allocation overflow
ASoC: sti: Fix deadlock via snd_pcm_stop_xrun() call
llc: fix netdevice reference leaks in llc_ui_bind()
thermal: int340x: fix memory leak in int3400_notify()
staging: fbtft: fb_st7789v: reset display before initialization
* esp: Fix possible buffer overflow in ESP transformation
include/net/esp.h
include/net/sock.h
net/core/sock.c
net/ipv4/esp4.c
net/ipv6/esp6.c
* net: ipv6: fix skb_over_panic in __ip6_append_data
net/ipv6/ip6_output.c
nfc: st21nfca: Fix potential buffer overflows in EVT_TRANSACTION
Merge 4.19.236 into android-4.19-stable
Linux 4.19.236
perf symbols: Fix symbol size calculation condition
* Input: aiptek - properly check endpoint type
drivers/input/tablet/aiptek.c
* usb: gadget: Fix use-after-free bug by not setting udc->dev.driver
drivers/usb/gadget/udc/core.c
* usb: gadget: rndis: prevent integer overflow in rndis_set_response()
drivers/usb/gadget/function/rndis.c
net: dsa: Add missing of_node_put() in dsa_port_parse_of
* net: handle ARPHRD_PIMREG in dev_is_mac_header_xmit()
include/linux/if_arp.h
drm/panel: simple: Fix Innolux G070Y2-L01 BPP settings
hv_netvsc: Add check for kvmalloc_array
atm: eni: Add check for dma_map_single
* net/packet: fix slab-out-of-bounds access in packet_recvmsg()
net/packet/af_packet.c
efi: fix return value of __setup handlers
ocfs2: fix crash when initialize filecheck kobj fails
crypto: qcom-rng - ensure buffer for generate is completely filled
* arm64: Use the clearbhb instruction in mitigations
arch/arm64/include/asm/assembler.h
arch/arm64/include/asm/cpufeature.h
arch/arm64/include/asm/sysreg.h
arch/arm64/include/asm/vectors.h
arch/arm64/kernel/cpu_errata.c
arch/arm64/kernel/cpufeature.c
arch/arm64/kernel/entry.S
* arm64: add ID_AA64ISAR2_EL1 sys register
arch/arm64/include/asm/cpu.h
arch/arm64/include/asm/sysreg.h
arch/arm64/kernel/cpufeature.c
arch/arm64/kernel/cpuinfo.c
* KVM: arm64: Allow SMCCC_ARCH_WORKAROUND_3 to be discovered and migrated
arch/arm64/include/asm/kvm_host.h
* arm64: Mitigate spectre style branch history side channels
arch/arm64/Kconfig
arch/arm64/include/asm/assembler.h
arch/arm64/include/asm/cpufeature.h
arch/arm64/include/asm/cputype.h
arch/arm64/include/asm/sysreg.h
arch/arm64/include/asm/vectors.h
arch/arm64/kernel/cpu_errata.c
* KVM: arm64: Add templates for BHB mitigation sequences
arch/arm64/include/asm/cpucaps.h
arch/arm64/include/asm/kvm_mmu.h
arch/arm64/include/asm/mmu.h
arch/arm64/kernel/cpu_errata.c
* arm64: proton-pack: Report Spectre-BHB vulnerabilities as part of Spectre-v2
arch/arm64/include/asm/cpufeature.h
arch/arm64/kernel/cpu_errata.c
* arm64: Add percpu vectors for EL1
arch/arm64/include/asm/mmu.h
arch/arm64/include/asm/vectors.h
arch/arm64/kernel/cpufeature.c
arch/arm64/kernel/entry.S
* arm64: entry: Add macro for reading symbol addresses from the trampoline
arch/arm64/kernel/entry.S
* arm64: entry: Add vectors that have the bhb mitigation sequences
arch/arm64/include/asm/assembler.h
arch/arm64/include/asm/vectors.h
arch/arm64/kernel/entry.S
include/linux/arm-smccc.h
* arm64: entry: Add non-kpti __bp_harden_el1_vectors for mitigations
arch/arm64/kernel/entry.S
* arm64: entry: Allow the trampoline text to occupy multiple pages
arch/arm64/include/asm/fixmap.h
arch/arm64/include/asm/sections.h
arch/arm64/kernel/entry.S
arch/arm64/kernel/vmlinux.lds.S
arch/arm64/mm/mmu.c
* arm64: entry: Make the kpti trampoline's kpti sequence optional
arch/arm64/kernel/entry.S
* arm64: entry: Move trampoline macros out of ifdef'd section
arch/arm64/kernel/entry.S
* arm64: entry: Don't assume tramp_vectors is the start of the vectors
arch/arm64/kernel/entry.S
* arm64: entry: Allow tramp_alias to access symbols after the 4K boundary
arch/arm64/kernel/entry.S
* arm64: entry: Move the trampoline data page before the text page
arch/arm64/include/asm/fixmap.h
arch/arm64/kernel/entry.S
* arm64: entry: Free up another register on kpti's tramp_exit path
arch/arm64/kernel/entry.S
* arm64: entry: Make the trampoline cleanup optional
arch/arm64/kernel/entry.S
* arm64: entry.S: Add ventry overflow sanity checks
arch/arm64/kernel/entry.S
* arm64: Add Cortex-X2 CPU part definition
arch/arm64/include/asm/cputype.h
* arm64: Add Neoverse-N2, Cortex-A710 CPU part definition
arch/arm64/include/asm/cputype.h
* arm64: Add part number for Arm Cortex-A77
arch/arm64/include/asm/cputype.h
* fs: sysfs_emit: Remove PAGE_SIZE alignment check
fs/sysfs/file.c
* mm: fix dereference a null pointer in migrate[_huge]_page_move_mapping()
mm/migrate.c
* cpuset: Fix unsafe lock order between cpuset lock and cpuslock
kernel/cgroup/cpuset.c
ia64: ensure proper NUMA distance and possible map initialization
* sched/topology: Fix sched_domain_topology_level alloc in sched_init_numa()
kernel/sched/topology.c
* sched/topology: Make sched_init_numa() use a set for the deduplicating sort
include/linux/topology.h
kernel/sched/topology.c
kselftest/vm: fix tests build with old libc
sfc: extend the locking on mcdi->seqno
* tcp: make tcp_read_sock() more robust
net/ipv4/tcp.c
* nl80211: Update bss channel on channel switch for P2P_CLIENT
net/wireless/nl80211.c
atm: firestream: check the return value of ioremap() in fs_init()
can: rcar_canfd: rcar_canfd_channel_probe(): register the CAN device when fully ready
* ARM: 9178/1: fix unmet dependency on BITREVERSE for HAVE_ARCH_BITREVERSE
lib/Kconfig
MIPS: smp: fill in sibling and core maps earlier
ARM: dts: rockchip: fix a typo on rk3288 crypto-controller
arm64: dts: rockchip: reorder rk3399 hdmi clocks
arm64: dts: rockchip: fix rk3399-puma eMMC HS400 signal integrity
* xfrm: Fix xfrm migrate issues when address family changes
net/xfrm/xfrm_state.c
* xfrm: Check if_id in xfrm_migrate
include/net/xfrm.h
net/key/af_key.c
net/xfrm/xfrm_policy.c
net/xfrm/xfrm_state.c
net/xfrm/xfrm_user.c
* sctp: fix the processing for INIT_ACK chunk
net/sctp/sm_statefuns.c
* sctp: fix the processing for INIT chunk
net/sctp/sm_statefuns.c
* Revert "xfrm: state and policy should fail if XFRMA_IF_ID 0"
net/xfrm/xfrm_user.c
Merge 4.19.235 into android-4.19-stable
Linux 4.19.235
btrfs: unlock newly allocated extent buffer after error
* ext4: add check to prevent attempting to resize an fs with sparse_super2
fs/ext4/resize.c
ARM: fix Thumb2 regression with Spectre BHB
* virtio: acknowledge all features before access
include/linux/virtio_config.h
* virtio: unexport virtio_finalize_features
include/linux/virtio.h
riscv: Fix auipc+jalr relocation range checks
net: macb: Fix lost RX packet wakeup race in NAPI receive
staging: gdm724x: fix use after free in gdm_lte_rx()
ARM: Spectre-BHB: provide empty stub for non-config
selftests/memfd: clean up mapping in mfd_fail_write
* tracing: Ensure trace buffer is at least 4096 bytes large
kernel/trace/trace.c
Revert "xen-netback: Check for hotplug-status existence before watching"
Revert "xen-netback: remove 'hotplug-status' once it has served its purpose"
* net-sysfs: add check for netdevice being present to speed_show
net/core/net-sysfs.c
* sctp: fix kernel-infoleak for SCTP sockets
net/sctp/diag.c
net: phy: DP83822: clear MISR2 register to disable interrupts
gianfar: ethtool: Fix refcount leak in gfar_get_ts_info
gpio: ts4900: Do not set DAT and OE together
NFC: port100: fix use-after-free in port100_send_complete
* net/mlx5: Fix size field in bufferx_reg struct
include/linux/mlx5/mlx5_ifc.h
ax25: Fix NULL pointer dereference in ax25_kill_by_device
net: ethernet: lpc_eth: Handle error for clk_enable
net: ethernet: ti: cpts: Handle error for clk_enable
ethernet: Fix error handling in xemaclite_of_probe
qed: return status of qed_iov_get_link
net: qlogic: check the return value of dma_alloc_coherent() in qed_vf_hw_prepare()
ANDROID: dm-bow: Protect Ranges fetched and erased from the RB tree
Bug: 229982346
Change-Id: I590f3a34c3672086a50ac0fba0b8514a4cc2016a
Signed-off-by: Lucas Wei <lucaswei@google.com>
1325 lines
33 KiB
C
1325 lines
33 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* RNDIS MSG parser
|
|
*
|
|
* Authors: Benedikt Spranger, Pengutronix
|
|
* Robert Schwebel, Pengutronix
|
|
*
|
|
* This software was originally developed in conformance with
|
|
* Microsoft's Remote NDIS Specification License Agreement.
|
|
*
|
|
* 03/12/2004 Kai-Uwe Bloem <linux-development@auerswald.de>
|
|
* Fixed message length bug in init_response
|
|
*
|
|
* 03/25/2004 Kai-Uwe Bloem <linux-development@auerswald.de>
|
|
* Fixed rndis_rm_hdr length bug.
|
|
*
|
|
* Copyright (C) 2004 by David Brownell
|
|
* updates to merge with Linux 2.6, better match RNDIS spec
|
|
*/
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/moduleparam.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/errno.h>
|
|
#include <linux/idr.h>
|
|
#include <linux/list.h>
|
|
#include <linux/proc_fs.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/seq_file.h>
|
|
#include <linux/netdevice.h>
|
|
|
|
#include <asm/io.h>
|
|
#include <asm/byteorder.h>
|
|
#include <asm/unaligned.h>
|
|
|
|
#include "u_rndis.h"
|
|
|
|
#undef VERBOSE_DEBUG
|
|
|
|
#include "rndis.h"
|
|
|
|
/* The driver for your USB chip needs to support ep0 OUT to work with
|
|
* RNDIS, plus all three CDC Ethernet endpoints (interrupt not optional).
|
|
*
|
|
* Windows hosts need an INF file like Documentation/usb/linux.inf
|
|
* and will be happier if you provide the host_addr module parameter.
|
|
*/
|
|
|
|
#if 0
|
|
static int rndis_debug = 0;
|
|
module_param (rndis_debug, int, 0);
|
|
MODULE_PARM_DESC (rndis_debug, "enable debugging");
|
|
#else
|
|
#define rndis_debug 0
|
|
#endif
|
|
|
|
#ifdef CONFIG_USB_GADGET_DEBUG_FILES
|
|
|
|
#define NAME_TEMPLATE "driver/rndis-%03d"
|
|
|
|
#endif /* CONFIG_USB_GADGET_DEBUG_FILES */
|
|
|
|
static DEFINE_IDA(rndis_ida);
|
|
|
|
/* Driver Version */
|
|
static const __le32 rndis_driver_version = cpu_to_le32(1);
|
|
|
|
/* Function Prototypes */
|
|
static rndis_resp_t *rndis_add_response(struct rndis_params *params,
|
|
u32 length);
|
|
|
|
#ifdef CONFIG_USB_GADGET_DEBUG_FILES
|
|
|
|
static const struct file_operations rndis_proc_fops;
|
|
|
|
#endif /* CONFIG_USB_GADGET_DEBUG_FILES */
|
|
|
|
/* supported OIDs */
|
|
static const u32 oid_supported_list[] = {
|
|
/* the general stuff */
|
|
RNDIS_OID_GEN_SUPPORTED_LIST,
|
|
RNDIS_OID_GEN_HARDWARE_STATUS,
|
|
RNDIS_OID_GEN_MEDIA_SUPPORTED,
|
|
RNDIS_OID_GEN_MEDIA_IN_USE,
|
|
RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE,
|
|
RNDIS_OID_GEN_LINK_SPEED,
|
|
RNDIS_OID_GEN_TRANSMIT_BLOCK_SIZE,
|
|
RNDIS_OID_GEN_RECEIVE_BLOCK_SIZE,
|
|
RNDIS_OID_GEN_VENDOR_ID,
|
|
RNDIS_OID_GEN_VENDOR_DESCRIPTION,
|
|
RNDIS_OID_GEN_VENDOR_DRIVER_VERSION,
|
|
RNDIS_OID_GEN_CURRENT_PACKET_FILTER,
|
|
RNDIS_OID_GEN_MAXIMUM_TOTAL_SIZE,
|
|
RNDIS_OID_GEN_MEDIA_CONNECT_STATUS,
|
|
RNDIS_OID_GEN_PHYSICAL_MEDIUM,
|
|
|
|
/* the statistical stuff */
|
|
RNDIS_OID_GEN_XMIT_OK,
|
|
RNDIS_OID_GEN_RCV_OK,
|
|
RNDIS_OID_GEN_XMIT_ERROR,
|
|
RNDIS_OID_GEN_RCV_ERROR,
|
|
RNDIS_OID_GEN_RCV_NO_BUFFER,
|
|
#ifdef RNDIS_OPTIONAL_STATS
|
|
RNDIS_OID_GEN_DIRECTED_BYTES_XMIT,
|
|
RNDIS_OID_GEN_DIRECTED_FRAMES_XMIT,
|
|
RNDIS_OID_GEN_MULTICAST_BYTES_XMIT,
|
|
RNDIS_OID_GEN_MULTICAST_FRAMES_XMIT,
|
|
RNDIS_OID_GEN_BROADCAST_BYTES_XMIT,
|
|
RNDIS_OID_GEN_BROADCAST_FRAMES_XMIT,
|
|
RNDIS_OID_GEN_DIRECTED_BYTES_RCV,
|
|
RNDIS_OID_GEN_DIRECTED_FRAMES_RCV,
|
|
RNDIS_OID_GEN_MULTICAST_BYTES_RCV,
|
|
RNDIS_OID_GEN_MULTICAST_FRAMES_RCV,
|
|
RNDIS_OID_GEN_BROADCAST_BYTES_RCV,
|
|
RNDIS_OID_GEN_BROADCAST_FRAMES_RCV,
|
|
RNDIS_OID_GEN_RCV_CRC_ERROR,
|
|
RNDIS_OID_GEN_TRANSMIT_QUEUE_LENGTH,
|
|
#endif /* RNDIS_OPTIONAL_STATS */
|
|
|
|
/* mandatory 802.3 */
|
|
/* the general stuff */
|
|
RNDIS_OID_802_3_PERMANENT_ADDRESS,
|
|
RNDIS_OID_802_3_CURRENT_ADDRESS,
|
|
RNDIS_OID_802_3_MULTICAST_LIST,
|
|
RNDIS_OID_802_3_MAC_OPTIONS,
|
|
RNDIS_OID_802_3_MAXIMUM_LIST_SIZE,
|
|
|
|
/* the statistical stuff */
|
|
RNDIS_OID_802_3_RCV_ERROR_ALIGNMENT,
|
|
RNDIS_OID_802_3_XMIT_ONE_COLLISION,
|
|
RNDIS_OID_802_3_XMIT_MORE_COLLISIONS,
|
|
#ifdef RNDIS_OPTIONAL_STATS
|
|
RNDIS_OID_802_3_XMIT_DEFERRED,
|
|
RNDIS_OID_802_3_XMIT_MAX_COLLISIONS,
|
|
RNDIS_OID_802_3_RCV_OVERRUN,
|
|
RNDIS_OID_802_3_XMIT_UNDERRUN,
|
|
RNDIS_OID_802_3_XMIT_HEARTBEAT_FAILURE,
|
|
RNDIS_OID_802_3_XMIT_TIMES_CRS_LOST,
|
|
RNDIS_OID_802_3_XMIT_LATE_COLLISIONS,
|
|
#endif /* RNDIS_OPTIONAL_STATS */
|
|
|
|
#ifdef RNDIS_PM
|
|
/* PM and wakeup are "mandatory" for USB, but the RNDIS specs
|
|
* don't say what they mean ... and the NDIS specs are often
|
|
* confusing and/or ambiguous in this context. (That is, more
|
|
* so than their specs for the other OIDs.)
|
|
*
|
|
* FIXME someone who knows what these should do, please
|
|
* implement them!
|
|
*/
|
|
|
|
/* power management */
|
|
OID_PNP_CAPABILITIES,
|
|
OID_PNP_QUERY_POWER,
|
|
OID_PNP_SET_POWER,
|
|
|
|
#ifdef RNDIS_WAKEUP
|
|
/* wake up host */
|
|
OID_PNP_ENABLE_WAKE_UP,
|
|
OID_PNP_ADD_WAKE_UP_PATTERN,
|
|
OID_PNP_REMOVE_WAKE_UP_PATTERN,
|
|
#endif /* RNDIS_WAKEUP */
|
|
#endif /* RNDIS_PM */
|
|
};
|
|
|
|
|
|
/* NDIS Functions */
|
|
static int gen_ndis_query_resp(struct rndis_params *params, u32 OID, u8 *buf,
|
|
unsigned buf_len, rndis_resp_t *r)
|
|
{
|
|
int retval = -ENOTSUPP;
|
|
u32 length = 4; /* usually */
|
|
__le32 *outbuf;
|
|
int i, count;
|
|
rndis_query_cmplt_type *resp;
|
|
struct net_device *net;
|
|
struct rtnl_link_stats64 temp;
|
|
const struct rtnl_link_stats64 *stats;
|
|
|
|
if (!r) return -ENOMEM;
|
|
resp = (rndis_query_cmplt_type *)r->buf;
|
|
|
|
if (!resp) return -ENOMEM;
|
|
|
|
if (buf_len && rndis_debug > 1) {
|
|
pr_debug("query OID %08x value, len %d:\n", OID, buf_len);
|
|
for (i = 0; i < buf_len; i += 16) {
|
|
pr_debug("%03d: %08x %08x %08x %08x\n", i,
|
|
get_unaligned_le32(&buf[i]),
|
|
get_unaligned_le32(&buf[i + 4]),
|
|
get_unaligned_le32(&buf[i + 8]),
|
|
get_unaligned_le32(&buf[i + 12]));
|
|
}
|
|
}
|
|
|
|
/* response goes here, right after the header */
|
|
outbuf = (__le32 *)&resp[1];
|
|
resp->InformationBufferOffset = cpu_to_le32(16);
|
|
|
|
net = params->dev;
|
|
stats = dev_get_stats(net, &temp);
|
|
|
|
switch (OID) {
|
|
|
|
/* general oids (table 4-1) */
|
|
|
|
/* mandatory */
|
|
case RNDIS_OID_GEN_SUPPORTED_LIST:
|
|
pr_debug("%s: RNDIS_OID_GEN_SUPPORTED_LIST\n", __func__);
|
|
length = sizeof(oid_supported_list);
|
|
count = length / sizeof(u32);
|
|
for (i = 0; i < count; i++)
|
|
outbuf[i] = cpu_to_le32(oid_supported_list[i]);
|
|
retval = 0;
|
|
break;
|
|
|
|
/* mandatory */
|
|
case RNDIS_OID_GEN_HARDWARE_STATUS:
|
|
pr_debug("%s: RNDIS_OID_GEN_HARDWARE_STATUS\n", __func__);
|
|
/* Bogus question!
|
|
* Hardware must be ready to receive high level protocols.
|
|
* BTW:
|
|
* reddite ergo quae sunt Caesaris Caesari
|
|
* et quae sunt Dei Deo!
|
|
*/
|
|
*outbuf = cpu_to_le32(0);
|
|
retval = 0;
|
|
break;
|
|
|
|
/* mandatory */
|
|
case RNDIS_OID_GEN_MEDIA_SUPPORTED:
|
|
pr_debug("%s: RNDIS_OID_GEN_MEDIA_SUPPORTED\n", __func__);
|
|
*outbuf = cpu_to_le32(params->medium);
|
|
retval = 0;
|
|
break;
|
|
|
|
/* mandatory */
|
|
case RNDIS_OID_GEN_MEDIA_IN_USE:
|
|
pr_debug("%s: RNDIS_OID_GEN_MEDIA_IN_USE\n", __func__);
|
|
/* one medium, one transport... (maybe you do it better) */
|
|
*outbuf = cpu_to_le32(params->medium);
|
|
retval = 0;
|
|
break;
|
|
|
|
/* mandatory */
|
|
case RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE:
|
|
pr_debug("%s: RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE\n", __func__);
|
|
if (params->dev) {
|
|
*outbuf = cpu_to_le32(params->dev->mtu);
|
|
retval = 0;
|
|
}
|
|
break;
|
|
|
|
/* mandatory */
|
|
case RNDIS_OID_GEN_LINK_SPEED:
|
|
if (rndis_debug > 1)
|
|
pr_debug("%s: RNDIS_OID_GEN_LINK_SPEED\n", __func__);
|
|
if (params->media_state == RNDIS_MEDIA_STATE_DISCONNECTED)
|
|
*outbuf = cpu_to_le32(0);
|
|
else
|
|
*outbuf = cpu_to_le32(params->speed);
|
|
retval = 0;
|
|
break;
|
|
|
|
/* mandatory */
|
|
case RNDIS_OID_GEN_TRANSMIT_BLOCK_SIZE:
|
|
pr_debug("%s: RNDIS_OID_GEN_TRANSMIT_BLOCK_SIZE\n", __func__);
|
|
if (params->dev) {
|
|
*outbuf = cpu_to_le32(params->dev->mtu);
|
|
retval = 0;
|
|
}
|
|
break;
|
|
|
|
/* mandatory */
|
|
case RNDIS_OID_GEN_RECEIVE_BLOCK_SIZE:
|
|
pr_debug("%s: RNDIS_OID_GEN_RECEIVE_BLOCK_SIZE\n", __func__);
|
|
if (params->dev) {
|
|
*outbuf = cpu_to_le32(params->dev->mtu);
|
|
retval = 0;
|
|
}
|
|
break;
|
|
|
|
/* mandatory */
|
|
case RNDIS_OID_GEN_VENDOR_ID:
|
|
pr_debug("%s: RNDIS_OID_GEN_VENDOR_ID\n", __func__);
|
|
*outbuf = cpu_to_le32(params->vendorID);
|
|
retval = 0;
|
|
break;
|
|
|
|
/* mandatory */
|
|
case RNDIS_OID_GEN_VENDOR_DESCRIPTION:
|
|
pr_debug("%s: RNDIS_OID_GEN_VENDOR_DESCRIPTION\n", __func__);
|
|
if (params->vendorDescr) {
|
|
length = strlen(params->vendorDescr);
|
|
memcpy(outbuf, params->vendorDescr, length);
|
|
} else {
|
|
outbuf[0] = 0;
|
|
}
|
|
retval = 0;
|
|
break;
|
|
|
|
case RNDIS_OID_GEN_VENDOR_DRIVER_VERSION:
|
|
pr_debug("%s: RNDIS_OID_GEN_VENDOR_DRIVER_VERSION\n", __func__);
|
|
/* Created as LE */
|
|
*outbuf = rndis_driver_version;
|
|
retval = 0;
|
|
break;
|
|
|
|
/* mandatory */
|
|
case RNDIS_OID_GEN_CURRENT_PACKET_FILTER:
|
|
pr_debug("%s: RNDIS_OID_GEN_CURRENT_PACKET_FILTER\n", __func__);
|
|
*outbuf = cpu_to_le32(*params->filter);
|
|
retval = 0;
|
|
break;
|
|
|
|
/* mandatory */
|
|
case RNDIS_OID_GEN_MAXIMUM_TOTAL_SIZE:
|
|
pr_debug("%s: RNDIS_OID_GEN_MAXIMUM_TOTAL_SIZE\n", __func__);
|
|
*outbuf = cpu_to_le32(RNDIS_MAX_TOTAL_SIZE);
|
|
retval = 0;
|
|
break;
|
|
|
|
/* mandatory */
|
|
case RNDIS_OID_GEN_MEDIA_CONNECT_STATUS:
|
|
if (rndis_debug > 1)
|
|
pr_debug("%s: RNDIS_OID_GEN_MEDIA_CONNECT_STATUS\n", __func__);
|
|
*outbuf = cpu_to_le32(params->media_state);
|
|
retval = 0;
|
|
break;
|
|
|
|
case RNDIS_OID_GEN_PHYSICAL_MEDIUM:
|
|
pr_debug("%s: RNDIS_OID_GEN_PHYSICAL_MEDIUM\n", __func__);
|
|
*outbuf = cpu_to_le32(0);
|
|
retval = 0;
|
|
break;
|
|
|
|
/* The RNDIS specification is incomplete/wrong. Some versions
|
|
* of MS-Windows expect OIDs that aren't specified there. Other
|
|
* versions emit undefined RNDIS messages. DOCUMENT ALL THESE!
|
|
*/
|
|
case RNDIS_OID_GEN_MAC_OPTIONS: /* from WinME */
|
|
pr_debug("%s: RNDIS_OID_GEN_MAC_OPTIONS\n", __func__);
|
|
*outbuf = cpu_to_le32(
|
|
RNDIS_MAC_OPTION_RECEIVE_SERIALIZED
|
|
| RNDIS_MAC_OPTION_FULL_DUPLEX);
|
|
retval = 0;
|
|
break;
|
|
|
|
/* statistics OIDs (table 4-2) */
|
|
|
|
/* mandatory */
|
|
case RNDIS_OID_GEN_XMIT_OK:
|
|
if (rndis_debug > 1)
|
|
pr_debug("%s: RNDIS_OID_GEN_XMIT_OK\n", __func__);
|
|
if (stats) {
|
|
*outbuf = cpu_to_le32(stats->tx_packets
|
|
- stats->tx_errors - stats->tx_dropped);
|
|
retval = 0;
|
|
}
|
|
break;
|
|
|
|
/* mandatory */
|
|
case RNDIS_OID_GEN_RCV_OK:
|
|
if (rndis_debug > 1)
|
|
pr_debug("%s: RNDIS_OID_GEN_RCV_OK\n", __func__);
|
|
if (stats) {
|
|
*outbuf = cpu_to_le32(stats->rx_packets
|
|
- stats->rx_errors - stats->rx_dropped);
|
|
retval = 0;
|
|
}
|
|
break;
|
|
|
|
/* mandatory */
|
|
case RNDIS_OID_GEN_XMIT_ERROR:
|
|
if (rndis_debug > 1)
|
|
pr_debug("%s: RNDIS_OID_GEN_XMIT_ERROR\n", __func__);
|
|
if (stats) {
|
|
*outbuf = cpu_to_le32(stats->tx_errors);
|
|
retval = 0;
|
|
}
|
|
break;
|
|
|
|
/* mandatory */
|
|
case RNDIS_OID_GEN_RCV_ERROR:
|
|
if (rndis_debug > 1)
|
|
pr_debug("%s: RNDIS_OID_GEN_RCV_ERROR\n", __func__);
|
|
if (stats) {
|
|
*outbuf = cpu_to_le32(stats->rx_errors);
|
|
retval = 0;
|
|
}
|
|
break;
|
|
|
|
/* mandatory */
|
|
case RNDIS_OID_GEN_RCV_NO_BUFFER:
|
|
pr_debug("%s: RNDIS_OID_GEN_RCV_NO_BUFFER\n", __func__);
|
|
if (stats) {
|
|
*outbuf = cpu_to_le32(stats->rx_dropped);
|
|
retval = 0;
|
|
}
|
|
break;
|
|
|
|
/* ieee802.3 OIDs (table 4-3) */
|
|
|
|
/* mandatory */
|
|
case RNDIS_OID_802_3_PERMANENT_ADDRESS:
|
|
pr_debug("%s: RNDIS_OID_802_3_PERMANENT_ADDRESS\n", __func__);
|
|
if (params->dev) {
|
|
length = ETH_ALEN;
|
|
memcpy(outbuf, params->host_mac, length);
|
|
retval = 0;
|
|
}
|
|
break;
|
|
|
|
/* mandatory */
|
|
case RNDIS_OID_802_3_CURRENT_ADDRESS:
|
|
pr_debug("%s: RNDIS_OID_802_3_CURRENT_ADDRESS\n", __func__);
|
|
if (params->dev) {
|
|
length = ETH_ALEN;
|
|
memcpy(outbuf, params->host_mac, length);
|
|
retval = 0;
|
|
}
|
|
break;
|
|
|
|
/* mandatory */
|
|
case RNDIS_OID_802_3_MULTICAST_LIST:
|
|
pr_debug("%s: RNDIS_OID_802_3_MULTICAST_LIST\n", __func__);
|
|
/* Multicast base address only */
|
|
*outbuf = cpu_to_le32(0xE0000000);
|
|
retval = 0;
|
|
break;
|
|
|
|
/* mandatory */
|
|
case RNDIS_OID_802_3_MAXIMUM_LIST_SIZE:
|
|
pr_debug("%s: RNDIS_OID_802_3_MAXIMUM_LIST_SIZE\n", __func__);
|
|
/* Multicast base address only */
|
|
*outbuf = cpu_to_le32(1);
|
|
retval = 0;
|
|
break;
|
|
|
|
case RNDIS_OID_802_3_MAC_OPTIONS:
|
|
pr_debug("%s: RNDIS_OID_802_3_MAC_OPTIONS\n", __func__);
|
|
*outbuf = cpu_to_le32(0);
|
|
retval = 0;
|
|
break;
|
|
|
|
/* ieee802.3 statistics OIDs (table 4-4) */
|
|
|
|
/* mandatory */
|
|
case RNDIS_OID_802_3_RCV_ERROR_ALIGNMENT:
|
|
pr_debug("%s: RNDIS_OID_802_3_RCV_ERROR_ALIGNMENT\n", __func__);
|
|
if (stats) {
|
|
*outbuf = cpu_to_le32(stats->rx_frame_errors);
|
|
retval = 0;
|
|
}
|
|
break;
|
|
|
|
/* mandatory */
|
|
case RNDIS_OID_802_3_XMIT_ONE_COLLISION:
|
|
pr_debug("%s: RNDIS_OID_802_3_XMIT_ONE_COLLISION\n", __func__);
|
|
*outbuf = cpu_to_le32(0);
|
|
retval = 0;
|
|
break;
|
|
|
|
/* mandatory */
|
|
case RNDIS_OID_802_3_XMIT_MORE_COLLISIONS:
|
|
pr_debug("%s: RNDIS_OID_802_3_XMIT_MORE_COLLISIONS\n", __func__);
|
|
*outbuf = cpu_to_le32(0);
|
|
retval = 0;
|
|
break;
|
|
|
|
default:
|
|
pr_warn("%s: query unknown OID 0x%08X\n", __func__, OID);
|
|
}
|
|
if (retval < 0)
|
|
length = 0;
|
|
|
|
resp->InformationBufferLength = cpu_to_le32(length);
|
|
r->length = length + sizeof(*resp);
|
|
resp->MessageLength = cpu_to_le32(r->length);
|
|
return retval;
|
|
}
|
|
|
|
static int gen_ndis_set_resp(struct rndis_params *params, u32 OID,
|
|
u8 *buf, u32 buf_len, rndis_resp_t *r)
|
|
{
|
|
rndis_set_cmplt_type *resp;
|
|
int i, retval = -ENOTSUPP;
|
|
|
|
if (!r)
|
|
return -ENOMEM;
|
|
resp = (rndis_set_cmplt_type *)r->buf;
|
|
if (!resp)
|
|
return -ENOMEM;
|
|
|
|
if (buf_len && rndis_debug > 1) {
|
|
pr_debug("set OID %08x value, len %d:\n", OID, buf_len);
|
|
for (i = 0; i < buf_len; i += 16) {
|
|
pr_debug("%03d: %08x %08x %08x %08x\n", i,
|
|
get_unaligned_le32(&buf[i]),
|
|
get_unaligned_le32(&buf[i + 4]),
|
|
get_unaligned_le32(&buf[i + 8]),
|
|
get_unaligned_le32(&buf[i + 12]));
|
|
}
|
|
}
|
|
|
|
switch (OID) {
|
|
case RNDIS_OID_GEN_CURRENT_PACKET_FILTER:
|
|
|
|
/* these NDIS_PACKET_TYPE_* bitflags are shared with
|
|
* cdc_filter; it's not RNDIS-specific
|
|
* NDIS_PACKET_TYPE_x == USB_CDC_PACKET_TYPE_x for x in:
|
|
* PROMISCUOUS, DIRECTED,
|
|
* MULTICAST, ALL_MULTICAST, BROADCAST
|
|
*/
|
|
*params->filter = (u16)get_unaligned_le32(buf);
|
|
pr_debug("%s: RNDIS_OID_GEN_CURRENT_PACKET_FILTER %08x\n",
|
|
__func__, *params->filter);
|
|
|
|
/* this call has a significant side effect: it's
|
|
* what makes the packet flow start and stop, like
|
|
* activating the CDC Ethernet altsetting.
|
|
*/
|
|
retval = 0;
|
|
if (*params->filter) {
|
|
pr_debug("%s(): disable flow control\n", __func__);
|
|
rndis_flow_control(params, false);
|
|
} else {
|
|
pr_err("%s(): enable flow control\n", __func__);
|
|
rndis_flow_control(params, true);
|
|
}
|
|
break;
|
|
|
|
case RNDIS_OID_802_3_MULTICAST_LIST:
|
|
/* I think we can ignore this */
|
|
pr_debug("%s: RNDIS_OID_802_3_MULTICAST_LIST\n", __func__);
|
|
retval = 0;
|
|
break;
|
|
|
|
default:
|
|
pr_warn("%s: set unknown OID 0x%08X, size %d\n",
|
|
__func__, OID, buf_len);
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
/*
|
|
* Response Functions
|
|
*/
|
|
|
|
static int rndis_init_response(struct rndis_params *params,
|
|
rndis_init_msg_type *buf)
|
|
{
|
|
rndis_init_cmplt_type *resp;
|
|
rndis_resp_t *r;
|
|
|
|
if (!params->dev)
|
|
return -ENOTSUPP;
|
|
|
|
r = rndis_add_response(params, sizeof(rndis_init_cmplt_type));
|
|
if (!r)
|
|
return -ENOMEM;
|
|
resp = (rndis_init_cmplt_type *)r->buf;
|
|
|
|
resp->MessageType = cpu_to_le32(RNDIS_MSG_INIT_C);
|
|
resp->MessageLength = cpu_to_le32(52);
|
|
resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
|
|
resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
|
|
resp->MajorVersion = cpu_to_le32(RNDIS_MAJOR_VERSION);
|
|
resp->MinorVersion = cpu_to_le32(RNDIS_MINOR_VERSION);
|
|
resp->DeviceFlags = cpu_to_le32(RNDIS_DF_CONNECTIONLESS);
|
|
resp->Medium = cpu_to_le32(RNDIS_MEDIUM_802_3);
|
|
resp->MaxPacketsPerTransfer = cpu_to_le32(params->max_pkt_per_xfer);
|
|
resp->MaxTransferSize = cpu_to_le32(params->max_pkt_per_xfer *
|
|
(params->dev->mtu
|
|
+ sizeof(struct ethhdr)
|
|
+ sizeof(struct rndis_packet_msg_type)
|
|
+ 22));
|
|
resp->PacketAlignmentFactor = cpu_to_le32(params->pkt_alignment_factor);
|
|
resp->AFListOffset = cpu_to_le32(0);
|
|
resp->AFListSize = cpu_to_le32(0);
|
|
|
|
params->resp_avail(params->v);
|
|
return 0;
|
|
}
|
|
|
|
static int rndis_query_response(struct rndis_params *params,
|
|
rndis_query_msg_type *buf)
|
|
{
|
|
rndis_query_cmplt_type *resp;
|
|
rndis_resp_t *r;
|
|
|
|
/* pr_debug("%s: OID = %08X\n", __func__, cpu_to_le32(buf->OID)); */
|
|
if (!params->dev)
|
|
return -ENOTSUPP;
|
|
|
|
/*
|
|
* we need more memory:
|
|
* gen_ndis_query_resp expects enough space for
|
|
* rndis_query_cmplt_type followed by data.
|
|
* oid_supported_list is the largest data reply
|
|
*/
|
|
r = rndis_add_response(params,
|
|
sizeof(oid_supported_list) + sizeof(rndis_query_cmplt_type));
|
|
if (!r)
|
|
return -ENOMEM;
|
|
resp = (rndis_query_cmplt_type *)r->buf;
|
|
|
|
resp->MessageType = cpu_to_le32(RNDIS_MSG_QUERY_C);
|
|
resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
|
|
|
|
if (gen_ndis_query_resp(params, le32_to_cpu(buf->OID),
|
|
le32_to_cpu(buf->InformationBufferOffset)
|
|
+ 8 + (u8 *)buf,
|
|
le32_to_cpu(buf->InformationBufferLength),
|
|
r)) {
|
|
/* OID not supported */
|
|
resp->Status = cpu_to_le32(RNDIS_STATUS_NOT_SUPPORTED);
|
|
resp->MessageLength = cpu_to_le32(sizeof *resp);
|
|
resp->InformationBufferLength = cpu_to_le32(0);
|
|
resp->InformationBufferOffset = cpu_to_le32(0);
|
|
} else
|
|
resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
|
|
|
|
params->resp_avail(params->v);
|
|
return 0;
|
|
}
|
|
|
|
static int rndis_set_response(struct rndis_params *params,
|
|
rndis_set_msg_type *buf)
|
|
{
|
|
u32 BufLength, BufOffset;
|
|
rndis_set_cmplt_type *resp;
|
|
rndis_resp_t *r;
|
|
|
|
BufLength = le32_to_cpu(buf->InformationBufferLength);
|
|
BufOffset = le32_to_cpu(buf->InformationBufferOffset);
|
|
if ((BufLength > RNDIS_MAX_TOTAL_SIZE) ||
|
|
(BufOffset > RNDIS_MAX_TOTAL_SIZE) ||
|
|
(BufOffset + 8 >= RNDIS_MAX_TOTAL_SIZE))
|
|
return -EINVAL;
|
|
|
|
r = rndis_add_response(params, sizeof(rndis_set_cmplt_type));
|
|
if (!r)
|
|
return -ENOMEM;
|
|
resp = (rndis_set_cmplt_type *)r->buf;
|
|
|
|
#ifdef VERBOSE_DEBUG
|
|
pr_debug("%s: Length: %d\n", __func__, BufLength);
|
|
pr_debug("%s: Offset: %d\n", __func__, BufOffset);
|
|
pr_debug("%s: InfoBuffer: ", __func__);
|
|
|
|
for (i = 0; i < BufLength; i++) {
|
|
pr_debug("%02x ", *(((u8 *) buf) + i + 8 + BufOffset));
|
|
}
|
|
|
|
pr_debug("\n");
|
|
#endif
|
|
|
|
resp->MessageType = cpu_to_le32(RNDIS_MSG_SET_C);
|
|
resp->MessageLength = cpu_to_le32(16);
|
|
resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
|
|
if (gen_ndis_set_resp(params, le32_to_cpu(buf->OID),
|
|
((u8 *)buf) + 8 + BufOffset, BufLength, r))
|
|
resp->Status = cpu_to_le32(RNDIS_STATUS_NOT_SUPPORTED);
|
|
else
|
|
resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
|
|
|
|
params->resp_avail(params->v);
|
|
return 0;
|
|
}
|
|
|
|
static int rndis_reset_response(struct rndis_params *params,
|
|
rndis_reset_msg_type *buf)
|
|
{
|
|
rndis_reset_cmplt_type *resp;
|
|
rndis_resp_t *r;
|
|
u8 *xbuf;
|
|
u32 length;
|
|
|
|
/* drain the response queue */
|
|
while ((xbuf = rndis_get_next_response(params, &length)))
|
|
rndis_free_response(params, xbuf);
|
|
|
|
r = rndis_add_response(params, sizeof(rndis_reset_cmplt_type));
|
|
if (!r)
|
|
return -ENOMEM;
|
|
resp = (rndis_reset_cmplt_type *)r->buf;
|
|
|
|
resp->MessageType = cpu_to_le32(RNDIS_MSG_RESET_C);
|
|
resp->MessageLength = cpu_to_le32(16);
|
|
resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
|
|
/* resent information */
|
|
resp->AddressingReset = cpu_to_le32(1);
|
|
|
|
params->resp_avail(params->v);
|
|
return 0;
|
|
}
|
|
|
|
static int rndis_keepalive_response(struct rndis_params *params,
|
|
rndis_keepalive_msg_type *buf)
|
|
{
|
|
rndis_keepalive_cmplt_type *resp;
|
|
rndis_resp_t *r;
|
|
|
|
/* host "should" check only in RNDIS_DATA_INITIALIZED state */
|
|
|
|
r = rndis_add_response(params, sizeof(rndis_keepalive_cmplt_type));
|
|
if (!r)
|
|
return -ENOMEM;
|
|
resp = (rndis_keepalive_cmplt_type *)r->buf;
|
|
|
|
resp->MessageType = cpu_to_le32(RNDIS_MSG_KEEPALIVE_C);
|
|
resp->MessageLength = cpu_to_le32(16);
|
|
resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
|
|
resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
|
|
|
|
params->resp_avail(params->v);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* Device to Host Comunication
|
|
*/
|
|
static int rndis_indicate_status_msg(struct rndis_params *params, u32 status)
|
|
{
|
|
rndis_indicate_status_msg_type *resp;
|
|
rndis_resp_t *r;
|
|
|
|
if (params->state == RNDIS_UNINITIALIZED)
|
|
return -ENOTSUPP;
|
|
|
|
r = rndis_add_response(params, sizeof(rndis_indicate_status_msg_type));
|
|
if (!r)
|
|
return -ENOMEM;
|
|
resp = (rndis_indicate_status_msg_type *)r->buf;
|
|
|
|
resp->MessageType = cpu_to_le32(RNDIS_MSG_INDICATE);
|
|
resp->MessageLength = cpu_to_le32(20);
|
|
resp->Status = cpu_to_le32(status);
|
|
resp->StatusBufferLength = cpu_to_le32(0);
|
|
resp->StatusBufferOffset = cpu_to_le32(0);
|
|
|
|
params->resp_avail(params->v);
|
|
return 0;
|
|
}
|
|
|
|
int rndis_signal_connect(struct rndis_params *params)
|
|
{
|
|
params->media_state = RNDIS_MEDIA_STATE_CONNECTED;
|
|
return rndis_indicate_status_msg(params, RNDIS_STATUS_MEDIA_CONNECT);
|
|
}
|
|
EXPORT_SYMBOL_GPL(rndis_signal_connect);
|
|
|
|
int rndis_signal_disconnect(struct rndis_params *params)
|
|
{
|
|
params->media_state = RNDIS_MEDIA_STATE_DISCONNECTED;
|
|
return rndis_indicate_status_msg(params, RNDIS_STATUS_MEDIA_DISCONNECT);
|
|
}
|
|
EXPORT_SYMBOL_GPL(rndis_signal_disconnect);
|
|
|
|
void rndis_uninit(struct rndis_params *params)
|
|
{
|
|
u8 *buf;
|
|
u32 length;
|
|
|
|
if (!params)
|
|
return;
|
|
params->state = RNDIS_UNINITIALIZED;
|
|
|
|
/* drain the response queue */
|
|
while ((buf = rndis_get_next_response(params, &length)))
|
|
rndis_free_response(params, buf);
|
|
}
|
|
EXPORT_SYMBOL_GPL(rndis_uninit);
|
|
|
|
void rndis_set_host_mac(struct rndis_params *params, const u8 *addr)
|
|
{
|
|
params->host_mac = addr;
|
|
}
|
|
EXPORT_SYMBOL_GPL(rndis_set_host_mac);
|
|
|
|
/*
|
|
* Message Parser
|
|
*/
|
|
int rndis_msg_parser(struct rndis_params *params, u8 *buf)
|
|
{
|
|
u32 MsgType, MsgLength;
|
|
__le32 *tmp;
|
|
|
|
if (!buf)
|
|
return -ENOMEM;
|
|
|
|
tmp = (__le32 *)buf;
|
|
MsgType = get_unaligned_le32(tmp++);
|
|
MsgLength = get_unaligned_le32(tmp++);
|
|
|
|
if (!params)
|
|
return -ENOTSUPP;
|
|
|
|
/* NOTE: RNDIS is *EXTREMELY* chatty ... Windows constantly polls for
|
|
* rx/tx statistics and link status, in addition to KEEPALIVE traffic
|
|
* and normal HC level polling to see if there's any IN traffic.
|
|
*/
|
|
|
|
/* For USB: responses may take up to 10 seconds */
|
|
switch (MsgType) {
|
|
case RNDIS_MSG_INIT:
|
|
pr_debug("%s: RNDIS_MSG_INIT\n", __func__);
|
|
tmp++; /* to get RequestID */
|
|
params->host_rndis_major_ver = get_unaligned_le32(tmp++);
|
|
params->host_rndis_minor_ver = get_unaligned_le32(tmp++);
|
|
params->dl_max_xfer_size = get_unaligned_le32(tmp++);
|
|
|
|
pr_debug("%s(): RNDIS Host Major:%d Minor:%d version\n",
|
|
__func__, params->host_rndis_major_ver,
|
|
params->host_rndis_minor_ver);
|
|
pr_debug("%s(): DL Max Transfer size:%x\n",
|
|
__func__, params->dl_max_xfer_size);
|
|
params->state = RNDIS_INITIALIZED;
|
|
return rndis_init_response(params, (rndis_init_msg_type *)buf);
|
|
|
|
case RNDIS_MSG_HALT:
|
|
pr_debug("%s: RNDIS_MSG_HALT\n",
|
|
__func__);
|
|
if (params->state == RNDIS_DATA_INITIALIZED) {
|
|
if (params->flow_ctrl_enable) {
|
|
params->flow_ctrl_enable(true, params);
|
|
} else {
|
|
if (params->dev) {
|
|
netif_carrier_off(params->dev);
|
|
netif_stop_queue(params->dev);
|
|
}
|
|
}
|
|
params->state = RNDIS_UNINITIALIZED;
|
|
}
|
|
return 0;
|
|
|
|
case RNDIS_MSG_QUERY:
|
|
return rndis_query_response(params,
|
|
(rndis_query_msg_type *)buf);
|
|
|
|
case RNDIS_MSG_SET:
|
|
return rndis_set_response(params, (rndis_set_msg_type *)buf);
|
|
|
|
case RNDIS_MSG_RESET:
|
|
pr_debug("%s: RNDIS_MSG_RESET\n",
|
|
__func__);
|
|
return rndis_reset_response(params,
|
|
(rndis_reset_msg_type *)buf);
|
|
|
|
case RNDIS_MSG_KEEPALIVE:
|
|
/* For USB: host does this every 5 seconds */
|
|
if (rndis_debug > 1)
|
|
pr_debug("%s: RNDIS_MSG_KEEPALIVE\n",
|
|
__func__);
|
|
return rndis_keepalive_response(params,
|
|
(rndis_keepalive_msg_type *)
|
|
buf);
|
|
|
|
default:
|
|
/* At least Windows XP emits some undefined RNDIS messages.
|
|
* In one case those messages seemed to relate to the host
|
|
* suspending itself.
|
|
*/
|
|
pr_warn("%s: unknown RNDIS message 0x%08X len %d\n",
|
|
__func__, MsgType, MsgLength);
|
|
/* Garbled message can be huge, so limit what we display */
|
|
if (MsgLength > 16)
|
|
MsgLength = 16;
|
|
print_hex_dump_bytes(__func__, DUMP_PREFIX_OFFSET,
|
|
buf, MsgLength);
|
|
break;
|
|
}
|
|
|
|
return -ENOTSUPP;
|
|
}
|
|
EXPORT_SYMBOL_GPL(rndis_msg_parser);
|
|
|
|
static inline int rndis_get_nr(void)
|
|
{
|
|
return ida_simple_get(&rndis_ida, 0, 0, GFP_KERNEL);
|
|
}
|
|
|
|
static inline void rndis_put_nr(int nr)
|
|
{
|
|
ida_simple_remove(&rndis_ida, nr);
|
|
}
|
|
|
|
struct rndis_params *rndis_register(void (*resp_avail)(void *v), void *v,
|
|
void (*flow_ctrl_enable)(bool enable, struct rndis_params *params))
|
|
{
|
|
struct rndis_params *params;
|
|
int i;
|
|
|
|
if (!resp_avail)
|
|
return ERR_PTR(-EINVAL);
|
|
|
|
i = rndis_get_nr();
|
|
if (i < 0) {
|
|
pr_debug("failed\n");
|
|
|
|
return ERR_PTR(-ENODEV);
|
|
}
|
|
|
|
params = kzalloc(sizeof(*params), GFP_KERNEL);
|
|
if (!params) {
|
|
rndis_put_nr(i);
|
|
|
|
return ERR_PTR(-ENOMEM);
|
|
}
|
|
|
|
#ifdef CONFIG_USB_GADGET_DEBUG_FILES
|
|
{
|
|
struct proc_dir_entry *proc_entry;
|
|
char name[20];
|
|
|
|
sprintf(name, NAME_TEMPLATE, i);
|
|
proc_entry = proc_create_data(name, 0660, NULL,
|
|
&rndis_proc_fops, params);
|
|
if (!proc_entry) {
|
|
kfree(params);
|
|
rndis_put_nr(i);
|
|
|
|
return ERR_PTR(-EIO);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
params->confignr = i;
|
|
params->used = 1;
|
|
params->state = RNDIS_UNINITIALIZED;
|
|
params->media_state = RNDIS_MEDIA_STATE_DISCONNECTED;
|
|
params->resp_avail = resp_avail;
|
|
params->flow_ctrl_enable = flow_ctrl_enable;
|
|
params->v = v;
|
|
INIT_LIST_HEAD(¶ms->resp_queue);
|
|
spin_lock_init(¶ms->resp_lock);
|
|
pr_debug("%s: configNr = %d\n", __func__, i);
|
|
|
|
return params;
|
|
}
|
|
EXPORT_SYMBOL_GPL(rndis_register);
|
|
|
|
void rndis_deregister(struct rndis_params *params)
|
|
{
|
|
int i;
|
|
|
|
pr_debug("%s:\n", __func__);
|
|
|
|
if (!params)
|
|
return;
|
|
|
|
i = params->confignr;
|
|
|
|
#ifdef CONFIG_USB_GADGET_DEBUG_FILES
|
|
{
|
|
char name[20];
|
|
|
|
sprintf(name, NAME_TEMPLATE, i);
|
|
remove_proc_entry(name, NULL);
|
|
}
|
|
#endif
|
|
|
|
kfree(params);
|
|
rndis_put_nr(i);
|
|
}
|
|
EXPORT_SYMBOL_GPL(rndis_deregister);
|
|
int rndis_set_param_dev(struct rndis_params *params, struct net_device *dev,
|
|
u16 *cdc_filter)
|
|
{
|
|
pr_debug("%s:\n", __func__);
|
|
if (!dev)
|
|
return -EINVAL;
|
|
if (!params)
|
|
return -1;
|
|
|
|
params->dev = dev;
|
|
params->filter = cdc_filter;
|
|
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL_GPL(rndis_set_param_dev);
|
|
|
|
int rndis_set_param_vendor(struct rndis_params *params, u32 vendorID,
|
|
const char *vendorDescr)
|
|
{
|
|
pr_debug("%s:\n", __func__);
|
|
if (!vendorDescr) return -1;
|
|
if (!params)
|
|
return -1;
|
|
|
|
params->vendorID = vendorID;
|
|
params->vendorDescr = vendorDescr;
|
|
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL_GPL(rndis_set_param_vendor);
|
|
|
|
int rndis_set_param_medium(struct rndis_params *params, u32 medium, u32 speed)
|
|
{
|
|
pr_debug("%s: %u %u\n", __func__, medium, speed);
|
|
if (!params)
|
|
return -1;
|
|
|
|
params->medium = medium;
|
|
params->speed = speed;
|
|
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL_GPL(rndis_set_param_medium);
|
|
|
|
u32 rndis_get_dl_max_xfer_size(struct rndis_params *params)
|
|
{
|
|
pr_debug("%s:\n", __func__);
|
|
return params->dl_max_xfer_size;
|
|
}
|
|
|
|
u32 rndis_get_ul_max_xfer_size(struct rndis_params *params)
|
|
{
|
|
pr_debug("%s:\n", __func__);
|
|
return params->ul_max_xfer_size;
|
|
}
|
|
|
|
void rndis_set_max_pkt_xfer(struct rndis_params *params, u8 max_pkt_per_xfer)
|
|
{
|
|
pr_debug("%s:\n", __func__);
|
|
|
|
params->max_pkt_per_xfer = max_pkt_per_xfer;
|
|
}
|
|
EXPORT_SYMBOL_GPL(rndis_set_max_pkt_xfer);
|
|
|
|
/**
|
|
* rndis_flow_control: enable/disable flow control with USB RNDIS interface
|
|
* params - RNDIS network parameter
|
|
* enable_flow_control - true: perform flow control, false: disable flow control
|
|
*
|
|
* In hw accelerated mode, this function triggers functionality to start/stop
|
|
* endless transfers, otherwise it enables/disables RNDIS network interface.
|
|
*/
|
|
void rndis_flow_control(struct rndis_params *params, bool enable_flow_control)
|
|
{
|
|
if (!params) {
|
|
pr_err("%s: failed, params NULL\n", __func__);
|
|
return;
|
|
}
|
|
|
|
pr_debug("%s(): params->state:%x\n", __func__, params->state);
|
|
|
|
if (enable_flow_control) {
|
|
if (params->state == RNDIS_DATA_INITIALIZED) {
|
|
if (params->flow_ctrl_enable) {
|
|
params->flow_ctrl_enable(enable_flow_control,
|
|
params);
|
|
} else {
|
|
netif_carrier_off(params->dev);
|
|
netif_stop_queue(params->dev);
|
|
}
|
|
}
|
|
params->state = RNDIS_INITIALIZED;
|
|
} else {
|
|
if (params->state != RNDIS_DATA_INITIALIZED) {
|
|
if (params->flow_ctrl_enable) {
|
|
params->flow_ctrl_enable(enable_flow_control,
|
|
params);
|
|
} else {
|
|
netif_carrier_on(params->dev);
|
|
if (netif_running(params->dev))
|
|
netif_wake_queue(params->dev);
|
|
}
|
|
}
|
|
params->state = RNDIS_DATA_INITIALIZED;
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(rndis_flow_control);
|
|
|
|
void rndis_add_hdr(struct sk_buff *skb)
|
|
{
|
|
struct rndis_packet_msg_type *header;
|
|
|
|
if (!skb)
|
|
return;
|
|
header = skb_push(skb, sizeof(*header));
|
|
memset(header, 0, sizeof *header);
|
|
header->MessageType = cpu_to_le32(RNDIS_MSG_PACKET);
|
|
header->MessageLength = cpu_to_le32(skb->len);
|
|
header->DataOffset = cpu_to_le32(36);
|
|
header->DataLength = cpu_to_le32(skb->len - sizeof(*header));
|
|
}
|
|
EXPORT_SYMBOL_GPL(rndis_add_hdr);
|
|
|
|
void rndis_free_response(struct rndis_params *params, u8 *buf)
|
|
{
|
|
rndis_resp_t *r, *n;
|
|
|
|
spin_lock(¶ms->resp_lock);
|
|
list_for_each_entry_safe(r, n, ¶ms->resp_queue, list) {
|
|
if (r->buf == buf) {
|
|
list_del(&r->list);
|
|
kfree(r);
|
|
}
|
|
}
|
|
spin_unlock(¶ms->resp_lock);
|
|
}
|
|
EXPORT_SYMBOL_GPL(rndis_free_response);
|
|
|
|
u8 *rndis_get_next_response(struct rndis_params *params, u32 *length)
|
|
{
|
|
rndis_resp_t *r, *n;
|
|
|
|
if (!length) return NULL;
|
|
|
|
spin_lock(¶ms->resp_lock);
|
|
list_for_each_entry_safe(r, n, ¶ms->resp_queue, list) {
|
|
if (!r->send) {
|
|
r->send = 1;
|
|
*length = r->length;
|
|
spin_unlock(¶ms->resp_lock);
|
|
return r->buf;
|
|
}
|
|
}
|
|
|
|
spin_unlock(¶ms->resp_lock);
|
|
return NULL;
|
|
}
|
|
EXPORT_SYMBOL_GPL(rndis_get_next_response);
|
|
|
|
static rndis_resp_t *rndis_add_response(struct rndis_params *params, u32 length)
|
|
{
|
|
rndis_resp_t *r;
|
|
|
|
/* NOTE: this gets copied into ether.c USB_BUFSIZ bytes ... */
|
|
r = kmalloc(sizeof(rndis_resp_t) + length, GFP_ATOMIC);
|
|
if (!r) return NULL;
|
|
|
|
r->buf = (u8 *)(r + 1);
|
|
r->length = length;
|
|
r->send = 0;
|
|
|
|
spin_lock(¶ms->resp_lock);
|
|
list_add_tail(&r->list, ¶ms->resp_queue);
|
|
spin_unlock(¶ms->resp_lock);
|
|
return r;
|
|
}
|
|
|
|
int rndis_rm_hdr(struct gether *port,
|
|
struct sk_buff *skb,
|
|
struct sk_buff_head *list)
|
|
{
|
|
while (skb->len) {
|
|
struct rndis_packet_msg_type *hdr;
|
|
struct sk_buff *skb2;
|
|
u32 msg_len, data_offset, data_len;
|
|
|
|
/* some rndis hosts send extra byte to avoid zlp, ignore it */
|
|
if (skb->len == 1) {
|
|
dev_kfree_skb_any(skb);
|
|
return 0;
|
|
}
|
|
|
|
if (skb->len < sizeof(*hdr)) {
|
|
pr_err("invalid rndis pkt: skblen:%u hdr_len:%lu\n",
|
|
skb->len, sizeof(*hdr));
|
|
dev_kfree_skb_any(skb);
|
|
return -EINVAL;
|
|
}
|
|
|
|
hdr = (void *)skb->data;
|
|
msg_len = le32_to_cpu(hdr->MessageLength);
|
|
data_offset = le32_to_cpu(hdr->DataOffset);
|
|
data_len = le32_to_cpu(hdr->DataLength);
|
|
|
|
if (skb->len < msg_len ||
|
|
((data_offset + data_len + 8) > msg_len)) {
|
|
pr_err("invalid rndis message: %d/%d/%d/%d, len:%d\n",
|
|
le32_to_cpu(hdr->MessageType), msg_len,
|
|
data_offset, data_len, skb->len);
|
|
dev_kfree_skb_any(skb);
|
|
return -EOVERFLOW;
|
|
}
|
|
if (le32_to_cpu(hdr->MessageType) != RNDIS_MSG_PACKET) {
|
|
pr_err("invalid rndis message: %d/%d/%d/%d, len:%d\n",
|
|
le32_to_cpu(hdr->MessageType), msg_len,
|
|
data_offset, data_len, skb->len);
|
|
dev_kfree_skb_any(skb);
|
|
return -EINVAL;
|
|
}
|
|
|
|
skb_pull(skb, data_offset + 8);
|
|
|
|
if (msg_len == skb->len) {
|
|
skb_trim(skb, data_len);
|
|
break;
|
|
}
|
|
|
|
skb2 = skb_clone(skb, GFP_ATOMIC);
|
|
if (!skb2) {
|
|
pr_err("%s:skb clone failed\n", __func__);
|
|
dev_kfree_skb_any(skb);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
skb_pull(skb, msg_len - sizeof(*hdr));
|
|
skb_trim(skb2, data_len);
|
|
skb_queue_tail(list, skb2);
|
|
}
|
|
|
|
skb_queue_tail(list, skb);
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL_GPL(rndis_rm_hdr);
|
|
|
|
void rndis_set_pkt_alignment_factor(struct rndis_params *params,
|
|
u8 pkt_alignment_factor)
|
|
{
|
|
pr_debug("%s:\n", __func__);
|
|
|
|
if (!params) {
|
|
pr_err("%s: failed, params NULL\n", __func__);
|
|
return;
|
|
}
|
|
|
|
params->pkt_alignment_factor = pkt_alignment_factor;
|
|
}
|
|
EXPORT_SYMBOL_GPL(rndis_set_pkt_alignment_factor);
|
|
|
|
#ifdef CONFIG_USB_GADGET_DEBUG_FILES
|
|
|
|
static int rndis_proc_show(struct seq_file *m, void *v)
|
|
{
|
|
rndis_params *param = m->private;
|
|
|
|
seq_printf(m,
|
|
"Config Nr. %d\n"
|
|
"used : %s\n"
|
|
"state : %s\n"
|
|
"medium : 0x%08X\n"
|
|
"speed : %d\n"
|
|
"cable : %s\n"
|
|
"vendor ID : 0x%08X\n"
|
|
"vendor : %s\n",
|
|
param->confignr, (param->used) ? "y" : "n",
|
|
({ char *s = "?";
|
|
switch (param->state) {
|
|
case RNDIS_UNINITIALIZED:
|
|
s = "RNDIS_UNINITIALIZED"; break;
|
|
case RNDIS_INITIALIZED:
|
|
s = "RNDIS_INITIALIZED"; break;
|
|
case RNDIS_DATA_INITIALIZED:
|
|
s = "RNDIS_DATA_INITIALIZED"; break;
|
|
} s; }),
|
|
param->medium,
|
|
(param->media_state) ? 0 : param->speed*100,
|
|
(param->media_state) ? "disconnected" : "connected",
|
|
param->vendorID, param->vendorDescr);
|
|
return 0;
|
|
}
|
|
|
|
static ssize_t rndis_proc_write(struct file *file, const char __user *buffer,
|
|
size_t count, loff_t *ppos)
|
|
{
|
|
rndis_params *p = PDE_DATA(file_inode(file));
|
|
u32 speed = 0;
|
|
int i, fl_speed = 0;
|
|
|
|
for (i = 0; i < count; i++) {
|
|
char c;
|
|
if (get_user(c, buffer))
|
|
return -EFAULT;
|
|
switch (c) {
|
|
case '0':
|
|
case '1':
|
|
case '2':
|
|
case '3':
|
|
case '4':
|
|
case '5':
|
|
case '6':
|
|
case '7':
|
|
case '8':
|
|
case '9':
|
|
fl_speed = 1;
|
|
speed = speed * 10 + c - '0';
|
|
break;
|
|
case 'C':
|
|
case 'c':
|
|
rndis_signal_connect(p);
|
|
break;
|
|
case 'D':
|
|
case 'd':
|
|
rndis_signal_disconnect(p);
|
|
break;
|
|
default:
|
|
if (fl_speed) p->speed = speed;
|
|
else pr_debug("%c is not valid\n", c);
|
|
break;
|
|
}
|
|
|
|
buffer++;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
static int rndis_proc_open(struct inode *inode, struct file *file)
|
|
{
|
|
return single_open(file, rndis_proc_show, PDE_DATA(inode));
|
|
}
|
|
|
|
static const struct file_operations rndis_proc_fops = {
|
|
.owner = THIS_MODULE,
|
|
.open = rndis_proc_open,
|
|
.read = seq_read,
|
|
.llseek = seq_lseek,
|
|
.release = single_release,
|
|
.write = rndis_proc_write,
|
|
};
|
|
|
|
#define NAME_TEMPLATE "driver/rndis-%03d"
|
|
|
|
#endif /* CONFIG_USB_GADGET_DEBUG_FILES */
|
|
|
|
MODULE_DESCRIPTION("Remote NDIS USB Gadget driver");
|
|
MODULE_LICENSE("GPL v2");
|