diff options
Diffstat (limited to 'sys/compat')
37 files changed, 1509 insertions, 510 deletions
diff --git a/sys/compat/freebsd32/freebsd32_syscall.h b/sys/compat/freebsd32/freebsd32_syscall.h index 90cd21a80923..54063150eef9 100644 --- a/sys/compat/freebsd32/freebsd32_syscall.h +++ b/sys/compat/freebsd32/freebsd32_syscall.h @@ -515,4 +515,6 @@ #define FREEBSD32_SYS_inotify_rm_watch 594 #define FREEBSD32_SYS_getgroups 595 #define FREEBSD32_SYS_setgroups 596 -#define FREEBSD32_SYS_MAXSYSCALL 597 +#define FREEBSD32_SYS_jail_attach_jd 597 +#define FREEBSD32_SYS_jail_remove_jd 598 +#define FREEBSD32_SYS_MAXSYSCALL 599 diff --git a/sys/compat/freebsd32/freebsd32_syscalls.c b/sys/compat/freebsd32/freebsd32_syscalls.c index f0f8d26554b5..f7cc4c284e4d 100644 --- a/sys/compat/freebsd32/freebsd32_syscalls.c +++ b/sys/compat/freebsd32/freebsd32_syscalls.c @@ -602,4 +602,6 @@ const char *freebsd32_syscallnames[] = { "inotify_rm_watch", /* 594 = inotify_rm_watch */ "getgroups", /* 595 = getgroups */ "setgroups", /* 596 = setgroups */ + "jail_attach_jd", /* 597 = jail_attach_jd */ + "jail_remove_jd", /* 598 = jail_remove_jd */ }; diff --git a/sys/compat/freebsd32/freebsd32_sysent.c b/sys/compat/freebsd32/freebsd32_sysent.c index 12f1a346c3e9..18f809ef04e3 100644 --- a/sys/compat/freebsd32/freebsd32_sysent.c +++ b/sys/compat/freebsd32/freebsd32_sysent.c @@ -664,4 +664,6 @@ struct sysent freebsd32_sysent[] = { { .sy_narg = AS(inotify_rm_watch_args), .sy_call = (sy_call_t *)sys_inotify_rm_watch, .sy_auevent = AUE_INOTIFY, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 594 = inotify_rm_watch */ { .sy_narg = AS(getgroups_args), .sy_call = (sy_call_t *)sys_getgroups, .sy_auevent = AUE_GETGROUPS, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 595 = getgroups */ { .sy_narg = AS(setgroups_args), .sy_call = (sy_call_t *)sys_setgroups, .sy_auevent = AUE_SETGROUPS, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 596 = setgroups */ + { .sy_narg = AS(jail_attach_jd_args), .sy_call = (sy_call_t *)sys_jail_attach_jd, .sy_auevent = AUE_JAIL_ATTACH, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 597 = jail_attach_jd */ + { .sy_narg = AS(jail_remove_jd_args), .sy_call = (sy_call_t *)sys_jail_remove_jd, .sy_auevent = AUE_JAIL_REMOVE, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 598 = jail_remove_jd */ }; diff --git a/sys/compat/freebsd32/freebsd32_systrace_args.c b/sys/compat/freebsd32/freebsd32_systrace_args.c index e471c5148021..29a5497e9efa 100644 --- a/sys/compat/freebsd32/freebsd32_systrace_args.c +++ b/sys/compat/freebsd32/freebsd32_systrace_args.c @@ -3413,6 +3413,20 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) *n_args = 2; break; } + /* jail_attach_jd */ + case 597: { + struct jail_attach_jd_args *p = params; + iarg[a++] = p->fd; /* int */ + *n_args = 1; + break; + } + /* jail_remove_jd */ + case 598: { + struct jail_remove_jd_args *p = params; + iarg[a++] = p->fd; /* int */ + *n_args = 1; + break; + } default: *n_args = 0; break; @@ -9222,6 +9236,26 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) break; }; break; + /* jail_attach_jd */ + case 597: + switch (ndx) { + case 0: + p = "int"; + break; + default: + break; + }; + break; + /* jail_remove_jd */ + case 598: + switch (ndx) { + case 0: + p = "int"; + break; + default: + break; + }; + break; default: break; }; @@ -11130,6 +11164,16 @@ systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) if (ndx == 0 || ndx == 1) p = "int"; break; + /* jail_attach_jd */ + case 597: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* jail_remove_jd */ + case 598: + if (ndx == 0 || ndx == 1) + p = "int"; + break; default: break; }; diff --git a/sys/compat/lindebugfs/lindebugfs.c b/sys/compat/lindebugfs/lindebugfs.c index 50f9377ffec3..8cddc6f390bc 100644 --- a/sys/compat/lindebugfs/lindebugfs.c +++ b/sys/compat/lindebugfs/lindebugfs.c @@ -206,7 +206,7 @@ debugfs_create_file(const char *name, umode_t mode, pnode = debugfs_root; flags = fops->write ? PFS_RDWR : PFS_RD; - dnode->d_pfs_node = pfs_create_file(pnode, name, debugfs_fill, + pfs_create_file(pnode, &dnode->d_pfs_node, name, debugfs_fill, debugfs_attr, NULL, debugfs_destroy, flags | PFS_NOWAIT); if (dnode->d_pfs_node == NULL) { free(dm, M_DFSINT); @@ -283,7 +283,8 @@ debugfs_create_dir(const char *name, struct dentry *parent) else pnode = debugfs_root; - dnode->d_pfs_node = pfs_create_dir(pnode, name, debugfs_attr, NULL, debugfs_destroy, PFS_RD | PFS_NOWAIT); + pfs_create_dir(pnode, &dnode->d_pfs_node, name, debugfs_attr, NULL, + debugfs_destroy, PFS_RD | PFS_NOWAIT); if (dnode->d_pfs_node == NULL) { free(dm, M_DFSINT); return (NULL); @@ -316,7 +317,8 @@ debugfs_create_symlink(const char *name, struct dentry *parent, else pnode = debugfs_root; - dnode->d_pfs_node = pfs_create_link(pnode, name, &debugfs_fill_data, NULL, NULL, NULL, PFS_NOWAIT); + pfs_create_link(pnode, &dnode->d_pfs_node, name, &debugfs_fill_data, + NULL, NULL, NULL, PFS_NOWAIT); if (dnode->d_pfs_node == NULL) goto fail; dnode->d_pfs_node->pn_data = dm; diff --git a/sys/compat/linprocfs/linprocfs.c b/sys/compat/linprocfs/linprocfs.c index 1c6d64d6b8bc..95b212be1306 100644 --- a/sys/compat/linprocfs/linprocfs.c +++ b/sys/compat/linprocfs/linprocfs.c @@ -2320,165 +2320,165 @@ linprocfs_init(PFS_INIT_ARGS) root = pi->pi_root; /* /proc/... */ - pfs_create_file(root, "cmdline", &linprocfs_docmdline, - NULL, NULL, NULL, PFS_RD); - pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo, - NULL, NULL, NULL, PFS_RD); - pfs_create_file(root, "devices", &linprocfs_dodevices, - NULL, NULL, NULL, PFS_RD); - pfs_create_file(root, "filesystems", &linprocfs_dofilesystems, - NULL, NULL, NULL, PFS_RD); - pfs_create_file(root, "loadavg", &linprocfs_doloadavg, - NULL, NULL, NULL, PFS_RD); - pfs_create_file(root, "meminfo", &linprocfs_domeminfo, - NULL, NULL, NULL, PFS_RD); - pfs_create_file(root, "modules", &linprocfs_domodules, - NULL, NULL, NULL, PFS_RD); - pfs_create_file(root, "mounts", &linprocfs_domtab, - NULL, NULL, NULL, PFS_RD); - pfs_create_file(root, "mtab", &linprocfs_domtab, - NULL, NULL, NULL, PFS_RD); - pfs_create_file(root, "partitions", &linprocfs_dopartitions, - NULL, NULL, NULL, PFS_RD); - pfs_create_link(root, "self", &procfs_docurproc, - NULL, NULL, NULL, 0); - pfs_create_file(root, "stat", &linprocfs_dostat, - NULL, NULL, NULL, PFS_RD); - pfs_create_file(root, "swaps", &linprocfs_doswaps, - NULL, NULL, NULL, PFS_RD); - pfs_create_file(root, "uptime", &linprocfs_douptime, - NULL, NULL, NULL, PFS_RD); - pfs_create_file(root, "version", &linprocfs_doversion, + pfs_create_file(root, NULL, "cmdline", &linprocfs_docmdline, NULL, NULL, + NULL, PFS_RD); + pfs_create_file(root, NULL, "cpuinfo", &linprocfs_docpuinfo, NULL, NULL, + NULL, PFS_RD); + pfs_create_file(root, NULL, "devices", &linprocfs_dodevices, NULL, NULL, + NULL, PFS_RD); + pfs_create_file(root, NULL, "filesystems", &linprocfs_dofilesystems, NULL, NULL, NULL, PFS_RD); + pfs_create_file(root, NULL, "loadavg", &linprocfs_doloadavg, NULL, NULL, + NULL, PFS_RD); + pfs_create_file(root, NULL, "meminfo", &linprocfs_domeminfo, NULL, NULL, + NULL, PFS_RD); + pfs_create_file(root, NULL, "modules", &linprocfs_domodules, NULL, NULL, + NULL, PFS_RD); + pfs_create_file(root, NULL, "mounts", &linprocfs_domtab, NULL, NULL, + NULL, PFS_RD); + pfs_create_file(root, NULL, "mtab", &linprocfs_domtab, NULL, NULL, NULL, + PFS_RD); + pfs_create_file(root, NULL, "partitions", &linprocfs_dopartitions, NULL, + NULL, NULL, PFS_RD); + pfs_create_link(root, NULL, "self", &procfs_docurproc, NULL, NULL, NULL, + 0); + pfs_create_file(root, NULL, "stat", &linprocfs_dostat, NULL, NULL, NULL, + PFS_RD); + pfs_create_file(root, NULL, "swaps", &linprocfs_doswaps, NULL, NULL, + NULL, PFS_RD); + pfs_create_file(root, NULL, "uptime", &linprocfs_douptime, NULL, NULL, + NULL, PFS_RD); + pfs_create_file(root, NULL, "version", &linprocfs_doversion, NULL, NULL, + NULL, PFS_RD); /* /proc/bus/... */ - dir = pfs_create_dir(root, "bus", NULL, NULL, NULL, 0); - dir = pfs_create_dir(dir, "pci", NULL, NULL, NULL, 0); - dir = pfs_create_dir(dir, "devices", NULL, NULL, NULL, 0); + pfs_create_dir(root, &dir, "bus", NULL, NULL, NULL, 0); + pfs_create_dir(dir, &dir, "pci", NULL, NULL, NULL, 0); + pfs_create_dir(dir, &dir, "devices", NULL, NULL, NULL, 0); /* /proc/net/... */ - dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0); - pfs_create_file(dir, "dev", &linprocfs_donetdev, - NULL, NULL, NULL, PFS_RD); - pfs_create_file(dir, "route", &linprocfs_donetroute, - NULL, NULL, NULL, PFS_RD); + pfs_create_dir(root, &dir, "net", NULL, NULL, NULL, 0); + pfs_create_file(dir, NULL, "dev", &linprocfs_donetdev, NULL, NULL, NULL, + PFS_RD); + pfs_create_file(dir, NULL, "route", &linprocfs_donetroute, NULL, NULL, + NULL, PFS_RD); /* /proc/<pid>/... */ - dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP); - pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline, - NULL, NULL, NULL, PFS_RD); - pfs_create_link(dir, "cwd", &linprocfs_doproccwd, - NULL, NULL, NULL, 0); - pfs_create_file(dir, "environ", &linprocfs_doprocenviron, - NULL, &procfs_candebug, NULL, PFS_RD); - pfs_create_link(dir, "exe", &procfs_doprocfile, - NULL, &procfs_notsystem, NULL, 0); - pfs_create_file(dir, "maps", &linprocfs_doprocmaps, - NULL, NULL, NULL, PFS_RD | PFS_AUTODRAIN); - pfs_create_file(dir, "mem", &linprocfs_doprocmem, - procfs_attr_rw, &procfs_candebug, NULL, PFS_RDWR | PFS_RAW); - pfs_create_file(dir, "mountinfo", &linprocfs_doprocmountinfo, - NULL, NULL, NULL, PFS_RD); - pfs_create_file(dir, "mounts", &linprocfs_domtab, + pfs_create_dir(root, &dir, "pid", NULL, NULL, NULL, PFS_PROCDEP); + pfs_create_file(dir, NULL, "cmdline", &linprocfs_doproccmdline, NULL, + NULL, NULL, PFS_RD); + pfs_create_link(dir, NULL, "cwd", &linprocfs_doproccwd, NULL, NULL, + NULL, 0); + pfs_create_file(dir, NULL, "environ", &linprocfs_doprocenviron, NULL, + &procfs_candebug, NULL, PFS_RD); + pfs_create_link(dir, NULL, "exe", &procfs_doprocfile, NULL, + &procfs_notsystem, NULL, 0); + pfs_create_file(dir, NULL, "maps", &linprocfs_doprocmaps, NULL, NULL, + NULL, PFS_RD | PFS_AUTODRAIN); + pfs_create_file(dir, NULL, "mem", &linprocfs_doprocmem, procfs_attr_rw, + &procfs_candebug, NULL, PFS_RDWR | PFS_RAW); + pfs_create_file(dir, NULL, "mountinfo", &linprocfs_doprocmountinfo, NULL, NULL, NULL, PFS_RD); - pfs_create_link(dir, "root", &linprocfs_doprocroot, - NULL, NULL, NULL, 0); - pfs_create_file(dir, "stat", &linprocfs_doprocstat, - NULL, NULL, NULL, PFS_RD); - pfs_create_file(dir, "statm", &linprocfs_doprocstatm, - NULL, NULL, NULL, PFS_RD); - pfs_create_file(dir, "status", &linprocfs_doprocstatus, - NULL, NULL, NULL, PFS_RD); - pfs_create_link(dir, "fd", &linprocfs_dofdescfs, - NULL, NULL, NULL, 0); - pfs_create_file(dir, "auxv", &linprocfs_doauxv, - NULL, &procfs_candebug, NULL, PFS_RD|PFS_RAWRD); - pfs_create_file(dir, "limits", &linprocfs_doproclimits, - NULL, NULL, NULL, PFS_RD); - pfs_create_file(dir, "oom_score_adj", &linprocfs_do_oom_score_adj, + pfs_create_file(dir, NULL, "mounts", &linprocfs_domtab, NULL, NULL, + NULL, PFS_RD); + pfs_create_link(dir, NULL, "root", &linprocfs_doprocroot, NULL, NULL, + NULL, 0); + pfs_create_file(dir, NULL, "stat", &linprocfs_doprocstat, NULL, NULL, + NULL, PFS_RD); + pfs_create_file(dir, NULL, "statm", &linprocfs_doprocstatm, NULL, NULL, + NULL, PFS_RD); + pfs_create_file(dir, NULL, "status", &linprocfs_doprocstatus, NULL, + NULL, NULL, PFS_RD); + pfs_create_link(dir, NULL, "fd", &linprocfs_dofdescfs, NULL, NULL, NULL, + 0); + pfs_create_file(dir, NULL, "auxv", &linprocfs_doauxv, NULL, + &procfs_candebug, NULL, PFS_RD | PFS_RAWRD); + pfs_create_file(dir, NULL, "limits", &linprocfs_doproclimits, NULL, + NULL, NULL, PFS_RD); + pfs_create_file(dir, NULL, "oom_score_adj", &linprocfs_do_oom_score_adj, procfs_attr_rw, &procfs_candebug, NULL, PFS_RDWR); /* /proc/<pid>/task/... */ - dir = pfs_create_dir(dir, "task", linprocfs_dotaskattr, NULL, NULL, 0); - pfs_create_file(dir, ".dummy", &linprocfs_dotaskdummy, - NULL, NULL, NULL, PFS_RD); + pfs_create_dir(dir, &dir, "task", linprocfs_dotaskattr, NULL, NULL, 0); + pfs_create_file(dir, NULL, ".dummy", &linprocfs_dotaskdummy, NULL, NULL, + NULL, PFS_RD); /* /proc/scsi/... */ - dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0); - pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo, - NULL, NULL, NULL, PFS_RD); - pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi, + pfs_create_dir(root, &dir, "scsi", NULL, NULL, NULL, 0); + pfs_create_file(dir, NULL, "device_info", &linprocfs_doscsidevinfo, NULL, NULL, NULL, PFS_RD); + pfs_create_file(dir, NULL, "scsi", &linprocfs_doscsiscsi, NULL, NULL, + NULL, PFS_RD); /* /proc/sys/... */ - sys = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0); + pfs_create_dir(root, &sys, "sys", NULL, NULL, NULL, 0); /* /proc/sys/kernel/... */ - dir = pfs_create_dir(sys, "kernel", NULL, NULL, NULL, 0); - pfs_create_file(dir, "osrelease", &linprocfs_doosrelease, - NULL, NULL, NULL, PFS_RD); - pfs_create_file(dir, "ostype", &linprocfs_doostype, - NULL, NULL, NULL, PFS_RD); - pfs_create_file(dir, "version", &linprocfs_doosbuild, - NULL, NULL, NULL, PFS_RD); - pfs_create_file(dir, "msgmax", &linprocfs_domsgmax, - NULL, NULL, NULL, PFS_RD); - pfs_create_file(dir, "msgmni", &linprocfs_domsgmni, - NULL, NULL, NULL, PFS_RD); - pfs_create_file(dir, "msgmnb", &linprocfs_domsgmnb, - NULL, NULL, NULL, PFS_RD); - pfs_create_file(dir, "ngroups_max", &linprocfs_dongroups_max, - NULL, NULL, NULL, PFS_RD); - pfs_create_file(dir, "pid_max", &linprocfs_dopid_max, - NULL, NULL, NULL, PFS_RD); - pfs_create_file(dir, "sem", &linprocfs_dosem, - NULL, NULL, NULL, PFS_RD); - pfs_create_file(dir, "shmall", &linprocfs_doshmall, - NULL, NULL, NULL, PFS_RD); - pfs_create_file(dir, "shmmax", &linprocfs_doshmmax, - NULL, NULL, NULL, PFS_RD); - pfs_create_file(dir, "shmmni", &linprocfs_doshmmni, - NULL, NULL, NULL, PFS_RD); - pfs_create_file(dir, "tainted", &linprocfs_dotainted, + pfs_create_dir(sys, &dir, "kernel", NULL, NULL, NULL, 0); + pfs_create_file(dir, NULL, "osrelease", &linprocfs_doosrelease, NULL, + NULL, NULL, PFS_RD); + pfs_create_file(dir, NULL, "ostype", &linprocfs_doostype, NULL, NULL, + NULL, PFS_RD); + pfs_create_file(dir, NULL, "version", &linprocfs_doosbuild, NULL, NULL, + NULL, PFS_RD); + pfs_create_file(dir, NULL, "msgmax", &linprocfs_domsgmax, NULL, NULL, + NULL, PFS_RD); + pfs_create_file(dir, NULL, "msgmni", &linprocfs_domsgmni, NULL, NULL, + NULL, PFS_RD); + pfs_create_file(dir, NULL, "msgmnb", &linprocfs_domsgmnb, NULL, NULL, + NULL, PFS_RD); + pfs_create_file(dir, NULL, "ngroups_max", &linprocfs_dongroups_max, NULL, NULL, NULL, PFS_RD); + pfs_create_file(dir, NULL, "pid_max", &linprocfs_dopid_max, NULL, NULL, + NULL, PFS_RD); + pfs_create_file(dir, NULL, "sem", &linprocfs_dosem, NULL, NULL, NULL, + PFS_RD); + pfs_create_file(dir, NULL, "shmall", &linprocfs_doshmall, NULL, NULL, + NULL, PFS_RD); + pfs_create_file(dir, NULL, "shmmax", &linprocfs_doshmmax, NULL, NULL, + NULL, PFS_RD); + pfs_create_file(dir, NULL, "shmmni", &linprocfs_doshmmni, NULL, NULL, + NULL, PFS_RD); + pfs_create_file(dir, NULL, "tainted", &linprocfs_dotainted, NULL, NULL, + NULL, PFS_RD); /* /proc/sys/kernel/random/... */ - dir = pfs_create_dir(dir, "random", NULL, NULL, NULL, 0); - pfs_create_file(dir, "uuid", &linprocfs_douuid, - NULL, NULL, NULL, PFS_RD); - pfs_create_file(dir, "boot_id", &linprocfs_doboot_id, - NULL, NULL, NULL, PFS_RD); + pfs_create_dir(dir, &dir, "random", NULL, NULL, NULL, 0); + pfs_create_file(dir, NULL, "uuid", &linprocfs_douuid, NULL, NULL, NULL, + PFS_RD); + pfs_create_file(dir, NULL, "boot_id", &linprocfs_doboot_id, NULL, NULL, + NULL, PFS_RD); /* /proc/sys/vm/.... */ - dir = pfs_create_dir(sys, "vm", NULL, NULL, NULL, 0); - pfs_create_file(dir, "min_free_kbytes", &linprocfs_dominfree, + pfs_create_dir(sys, &dir, "vm", NULL, NULL, NULL, 0); + pfs_create_file(dir, NULL, "min_free_kbytes", &linprocfs_dominfree, NULL, NULL, NULL, PFS_RD); - pfs_create_file(dir, "max_map_count", &linprocfs_domax_map_cnt, + pfs_create_file(dir, NULL, "max_map_count", &linprocfs_domax_map_cnt, NULL, NULL, NULL, PFS_RD); /* /proc/sysvipc/... */ - dir = pfs_create_dir(root, "sysvipc", NULL, NULL, NULL, 0); - pfs_create_file(dir, "msg", &linprocfs_dosysvipc_msg, - NULL, NULL, NULL, PFS_RD); - pfs_create_file(dir, "sem", &linprocfs_dosysvipc_sem, - NULL, NULL, NULL, PFS_RD); - pfs_create_file(dir, "shm", &linprocfs_dosysvipc_shm, - NULL, NULL, NULL, PFS_RD); + pfs_create_dir(root, &dir, "sysvipc", NULL, NULL, NULL, 0); + pfs_create_file(dir, NULL, "msg", &linprocfs_dosysvipc_msg, NULL, NULL, + NULL, PFS_RD); + pfs_create_file(dir, NULL, "sem", &linprocfs_dosysvipc_sem, NULL, NULL, + NULL, PFS_RD); + pfs_create_file(dir, NULL, "shm", &linprocfs_dosysvipc_shm, NULL, NULL, + NULL, PFS_RD); /* /proc/sys/fs/... */ - dir = pfs_create_dir(sys, "fs", NULL, NULL, NULL, 0); + pfs_create_dir(sys, &dir, "fs", NULL, NULL, NULL, 0); /* /proc/sys/fs/mqueue/... */ - dir = pfs_create_dir(dir, "mqueue", NULL, NULL, NULL, 0); - pfs_create_file(dir, "msg_default", &linprocfs_domqueue_msg_default, - NULL, NULL, NULL, PFS_RD); - pfs_create_file(dir, "msgsize_default", &linprocfs_domqueue_msgsize_default, - NULL, NULL, NULL, PFS_RD); - pfs_create_file(dir, "msg_max", &linprocfs_domqueue_msg_max, - NULL, NULL, NULL, PFS_RD); - pfs_create_file(dir, "msgsize_max", &linprocfs_domqueue_msgsize_max, - NULL, NULL, NULL, PFS_RD); - pfs_create_file(dir, "queues_max", &linprocfs_domqueue_queues_max, + pfs_create_dir(dir, &dir, "mqueue", NULL, NULL, NULL, 0); + pfs_create_file(dir, NULL, "msg_default", + &linprocfs_domqueue_msg_default, NULL, NULL, NULL, PFS_RD); + pfs_create_file(dir, NULL, "msgsize_default", + &linprocfs_domqueue_msgsize_default, NULL, NULL, NULL, PFS_RD); + pfs_create_file(dir, NULL, "msg_max", &linprocfs_domqueue_msg_max, NULL, + NULL, NULL, PFS_RD); + pfs_create_file(dir, NULL, "msgsize_max", + &linprocfs_domqueue_msgsize_max, NULL, NULL, NULL, PFS_RD); + pfs_create_file(dir, NULL, "queues_max", &linprocfs_domqueue_queues_max, NULL, NULL, NULL, PFS_RD); return (0); diff --git a/sys/compat/linsysfs/linsysfs.c b/sys/compat/linsysfs/linsysfs.c index 7f70221b420d..5a41c5193415 100644 --- a/sys/compat/linsysfs/linsysfs.c +++ b/sys/compat/linsysfs/linsysfs.c @@ -267,6 +267,8 @@ linsysfs_run_bus(device_t dev, struct pfs_node *dir, struct pfs_node *scsi, struct pci_devinfo *dinfo; char *device, *host, *new_path, *devname; + children = NULL; + device = host = NULL; new_path = path; devname = malloc(16, M_TEMP, M_WAITOK); @@ -292,39 +294,43 @@ linsysfs_run_bus(device_t dev, struct pfs_node *dir, struct pfs_node *scsi, dinfo->cfg.func); strcat(new_path, "/"); strcat(new_path, device); - dir = pfs_create_dir(dir, device, + error = pfs_create_dir(dir, &dir, device, NULL, NULL, NULL, 0); - cur_file = pfs_create_file(dir, "vendor", + if (error != 0) + goto out; + pfs_create_dir(dir, &dir, device, NULL, NULL, + NULL, 0); + pfs_create_file(dir, &cur_file, "vendor", &linsysfs_fill_vendor, NULL, NULL, NULL, PFS_RD); cur_file->pn_data = (void*)dev; - cur_file = pfs_create_file(dir, "device", + pfs_create_file(dir, &cur_file, "device", &linsysfs_fill_device, NULL, NULL, NULL, PFS_RD); cur_file->pn_data = (void*)dev; - cur_file = pfs_create_file(dir, + pfs_create_file(dir, &cur_file, "subsystem_vendor", &linsysfs_fill_subvendor, NULL, NULL, NULL, PFS_RD); cur_file->pn_data = (void*)dev; - cur_file = pfs_create_file(dir, + pfs_create_file(dir, &cur_file, "subsystem_device", &linsysfs_fill_subdevice, NULL, NULL, NULL, PFS_RD); cur_file->pn_data = (void*)dev; - cur_file = pfs_create_file(dir, "revision", + pfs_create_file(dir, &cur_file, "revision", &linsysfs_fill_revid, NULL, NULL, NULL, PFS_RD); cur_file->pn_data = (void*)dev; - cur_file = pfs_create_file(dir, "config", + pfs_create_file(dir, &cur_file, "config", &linsysfs_fill_config, NULL, NULL, NULL, PFS_RD); cur_file->pn_data = (void*)dev; - cur_file = pfs_create_file(dir, "uevent", - &linsysfs_fill_uevent_pci, NULL, NULL, - NULL, PFS_RD); + pfs_create_file(dir, &cur_file, "uevent", + &linsysfs_fill_uevent_pci, NULL, NULL, NULL, + PFS_RD); cur_file->pn_data = (void*)dev; - cur_file = pfs_create_link(dir, "subsystem", + pfs_create_link(dir, &cur_file, "subsystem", &linsysfs_fill_data, NULL, NULL, NULL, 0); /* libdrm just checks that the link ends in "/pci" */ cur_file->pn_data = "/sys/bus/pci"; @@ -334,34 +340,32 @@ linsysfs_run_bus(device_t dev, struct pfs_node *dir, struct pfs_node *scsi, sprintf(host, "host%d", host_number++); strcat(new_path, "/"); strcat(new_path, host); - pfs_create_dir(dir, host, - NULL, NULL, NULL, 0); + pfs_create_dir(dir, NULL, host, NULL, + NULL, NULL, 0); scsi_host = malloc(sizeof( struct scsi_host_queue), - M_DEVBUF, M_NOWAIT); + M_DEVBUF, M_WAITOK); scsi_host->path = malloc( strlen(new_path) + 1, - M_DEVBUF, M_NOWAIT); + M_DEVBUF, M_WAITOK); scsi_host->path[0] = '\000'; bcopy(new_path, scsi_host->path, strlen(new_path) + 1); scsi_host->name = "unknown"; - sub_dir = pfs_create_dir(scsi, host, + pfs_create_dir(scsi, &sub_dir, host, NULL, NULL, NULL, 0); - pfs_create_link(sub_dir, "device", - &linsysfs_link_scsi_host, - NULL, NULL, NULL, 0); - pfs_create_file(sub_dir, "proc_name", - &linsysfs_scsiname, + pfs_create_link(sub_dir, NULL, "device", + &linsysfs_link_scsi_host, NULL, + NULL, NULL, 0); + pfs_create_file(sub_dir, NULL, + "proc_name", &linsysfs_scsiname, NULL, NULL, NULL, PFS_RD); scsi_host->name = linux_driver_get_name_dev(dev); TAILQ_INSERT_TAIL(&scsi_host_q, scsi_host, scsi_host_next); } - free(device, M_TEMP); - free(host, M_TEMP); } } @@ -374,26 +378,27 @@ linsysfs_run_bus(device_t dev, struct pfs_node *dir, struct pfs_node *scsi, device_get_unit(dev) >= 0) { dinfo = device_get_ivars(parent); if (dinfo != NULL && dinfo->cfg.baseclass == PCIC_DISPLAY) { - pfs_create_dir(dir, "drm", NULL, NULL, NULL, 0); + pfs_create_dir(dir, NULL, "drm", NULL, NULL, + NULL, 0); sprintf(devname, "226:%d", device_get_unit(dev)); - sub_dir = pfs_create_dir(chardev, - devname, NULL, NULL, NULL, 0); - cur_file = pfs_create_link(sub_dir, - "device", &linsysfs_fill_vgapci, NULL, - NULL, NULL, PFS_RD); + pfs_create_dir(chardev, &sub_dir, devname, NULL, + NULL, NULL, 0); + pfs_create_link(sub_dir, &cur_file, "device", + &linsysfs_fill_vgapci, NULL, NULL, NULL, + PFS_RD); cur_file->pn_data = (void*)dir; - cur_file = pfs_create_file(sub_dir, - "uevent", &linsysfs_fill_uevent_drm, NULL, - NULL, NULL, PFS_RD); + pfs_create_file(sub_dir, &cur_file, "uevent", + &linsysfs_fill_uevent_drm, NULL, NULL, NULL, + PFS_RD); cur_file->pn_data = (void*)dev; sprintf(devname, "card%d", device_get_unit(dev)); - sub_dir = pfs_create_dir(drm, - devname, NULL, NULL, NULL, 0); - cur_file = pfs_create_link(sub_dir, - "device", &linsysfs_fill_vgapci, NULL, - NULL, NULL, PFS_RD); + pfs_create_dir(drm, &sub_dir, devname, NULL, + NULL, NULL, 0); + pfs_create_link(sub_dir, &cur_file, "device", + &linsysfs_fill_vgapci, NULL, NULL, NULL, + PFS_RD); cur_file->pn_data = (void*)dir; } } @@ -401,17 +406,37 @@ linsysfs_run_bus(device_t dev, struct pfs_node *dir, struct pfs_node *scsi, error = device_get_children(dev, &children, &nchildren); if (error == 0) { - for (i = 0; i < nchildren; i++) - if (children[i]) - linsysfs_run_bus(children[i], dir, scsi, + for (i = 0; i < nchildren; i++) { + if (children[i]) { + error = linsysfs_run_bus(children[i], dir, scsi, chardev, drm, new_path, prefix); - free(children, M_TEMP); + if (error != 0) { + printf( + "linsysfs_run_bus: %s omitted from sysfs tree, error %d\n", + device_get_nameunit(children[i]), + error); + } + } + } + + /* + * We override the error to avoid cascading failures; the + * innermost device that failed in a tree is probably the most + * significant one for diagnostics, its parents would be noise. + */ + error = 0; } + +out: + free(host, M_TEMP); + free(device, M_TEMP); + if (children != NULL) + free(children, M_TEMP); if (new_path != path) free(new_path, M_TEMP); free(devname, M_TEMP); - return (1); + return (error); } /* @@ -455,10 +480,10 @@ linsysfs_listcpus(struct pfs_node *dir) for (i = 0; i < mp_ncpus; ++i) { /* /sys/devices/system/cpu/cpuX */ sprintf(name, "cpu%d", i); - cpu = pfs_create_dir(dir, name, NULL, NULL, NULL, 0); + pfs_create_dir(dir, &cpu, name, NULL, NULL, NULL, 0); - pfs_create_file(cpu, "online", &linsysfs_cpuxonline, - NULL, NULL, NULL, PFS_RD); + pfs_create_file(cpu, NULL, "online", &linsysfs_cpuxonline, NULL, + NULL, NULL, PFS_RD); } free(name, M_TEMP); } @@ -485,52 +510,56 @@ linsysfs_init(PFS_INIT_ARGS) root = pi->pi_root; /* /sys/bus/... */ - dir = pfs_create_dir(root, "bus", NULL, NULL, NULL, 0); + pfs_create_dir(root, &dir, "bus", NULL, NULL, NULL, 0); /* /sys/class/... */ - class = pfs_create_dir(root, "class", NULL, NULL, NULL, 0); - scsi = pfs_create_dir(class, "scsi_host", NULL, NULL, NULL, 0); - drm = pfs_create_dir(class, "drm", NULL, NULL, NULL, 0); - pfs_create_dir(class, "power_supply", NULL, NULL, NULL, 0); + pfs_create_dir(root, &class, "class", NULL, NULL, NULL, 0); + pfs_create_dir(class, &scsi, "scsi_host", NULL, NULL, NULL, 0); + pfs_create_dir(class, &drm, "drm", NULL, NULL, NULL, 0); + pfs_create_dir(class, NULL, "power_supply", NULL, NULL, NULL, 0); /* /sys/class/net/.. */ - net = pfs_create_dir(class, "net", NULL, NULL, NULL, 0); + pfs_create_dir(class, &net, "net", NULL, NULL, NULL, 0); /* /sys/dev/... */ - devdir = pfs_create_dir(root, "dev", NULL, NULL, NULL, 0); - chardev = pfs_create_dir(devdir, "char", NULL, NULL, NULL, 0); + pfs_create_dir(root, &devdir, "dev", NULL, NULL, NULL, 0); + pfs_create_dir(devdir, &chardev, "char", NULL, NULL, NULL, 0); /* /sys/devices/... */ - dir = pfs_create_dir(root, "devices", NULL, NULL, NULL, 0); - pci = pfs_create_dir(dir, "pci0000:00", NULL, NULL, NULL, 0); + pfs_create_dir(root, &dir, "devices", NULL, NULL, NULL, 0); + pfs_create_dir(dir, &pci, "pci0000:00", NULL, NULL, NULL, 0); devclass = devclass_find("root"); if (devclass == NULL) { return (0); } + /* + * This assumes that the root node is unlikely to error out in + * linsysfs_run_bus, which may or may not be true. + */ dev = devclass_get_device(devclass, 0); linsysfs_run_bus(dev, pci, scsi, chardev, drm, "/pci0000:00", "0000"); /* /sys/devices/system */ - sys = pfs_create_dir(dir, "system", NULL, NULL, NULL, 0); + pfs_create_dir(dir, &sys, "system", NULL, NULL, NULL, 0); /* /sys/devices/system/cpu */ - cpu = pfs_create_dir(sys, "cpu", NULL, NULL, NULL, 0); + pfs_create_dir(sys, &cpu, "cpu", NULL, NULL, NULL, 0); - pfs_create_file(cpu, "online", &linsysfs_cpuonline, - NULL, NULL, NULL, PFS_RD); - pfs_create_file(cpu, "possible", &linsysfs_cpuonline, - NULL, NULL, NULL, PFS_RD); - pfs_create_file(cpu, "present", &linsysfs_cpuonline, - NULL, NULL, NULL, PFS_RD); + pfs_create_file(cpu, NULL, "online", &linsysfs_cpuonline, NULL, NULL, + NULL, PFS_RD); + pfs_create_file(cpu, NULL, "possible", &linsysfs_cpuonline, NULL, NULL, + NULL, PFS_RD); + pfs_create_file(cpu, NULL, "present", &linsysfs_cpuonline, NULL, NULL, + NULL, PFS_RD); linsysfs_listcpus(cpu); /* /sys/kernel */ - kernel = pfs_create_dir(root, "kernel", NULL, NULL, NULL, 0); + pfs_create_dir(root, &kernel, "kernel", NULL, NULL, NULL, 0); /* /sys/kernel/debug, mountpoint for lindebugfs. */ - pfs_create_dir(kernel, "debug", NULL, NULL, NULL, 0); + pfs_create_dir(kernel, NULL, "debug", NULL, NULL, NULL, 0); linsysfs_net_init(); diff --git a/sys/compat/linsysfs/linsysfs_net.c b/sys/compat/linsysfs/linsysfs_net.c index 73602b0132a4..751dbb5b3713 100644 --- a/sys/compat/linsysfs/linsysfs_net.c +++ b/sys/compat/linsysfs/linsysfs_net.c @@ -237,22 +237,22 @@ linsysfs_net_addif(if_t ifp, void *arg) nic = pfs_find_node(dir, ifname); if (nic == NULL) { - nic = pfs_create_dir(dir, ifname, NULL, linsysfs_if_visible, + pfs_create_dir(dir, &nic, ifname, NULL, linsysfs_if_visible, NULL, 0); - pfs_create_file(nic, "address", &linsysfs_if_addr, + pfs_create_file(nic, NULL, "address", &linsysfs_if_addr, NULL, + NULL, NULL, PFS_RD); + pfs_create_file(nic, NULL, "addr_len", &linsysfs_if_addrlen, NULL, NULL, NULL, PFS_RD); - pfs_create_file(nic, "addr_len", &linsysfs_if_addrlen, + pfs_create_file(nic, NULL, "flags", &linsysfs_if_flags, NULL, + NULL, NULL, PFS_RD); + pfs_create_file(nic, NULL, "ifindex", &linsysfs_if_ifindex, NULL, NULL, NULL, PFS_RD); - pfs_create_file(nic, "flags", &linsysfs_if_flags, + pfs_create_file(nic, NULL, "mtu", &linsysfs_if_mtu, NULL, NULL, + NULL, PFS_RD); + pfs_create_file(nic, NULL, "tx_queue_len", &linsysfs_if_txq_len, NULL, NULL, NULL, PFS_RD); - pfs_create_file(nic, "ifindex", &linsysfs_if_ifindex, - NULL, NULL, NULL, PFS_RD); - pfs_create_file(nic, "mtu", &linsysfs_if_mtu, - NULL, NULL, NULL, PFS_RD); - pfs_create_file(nic, "tx_queue_len", &linsysfs_if_txq_len, - NULL, NULL, NULL, PFS_RD); - pfs_create_file(nic, "type", &linsysfs_if_type, - NULL, NULL, NULL, PFS_RD); + pfs_create_file(nic, NULL, "type", &linsysfs_if_type, NULL, + NULL, NULL, PFS_RD); } /* * There is a small window between registering the if_arrival diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c index 5e32353c6b8e..0925ffb64480 100644 --- a/sys/compat/linux/linux_misc.c +++ b/sys/compat/linux/linux_misc.c @@ -1028,24 +1028,24 @@ linux_nice(struct thread *td, struct linux_nice_args *args) int linux_setgroups(struct thread *td, struct linux_setgroups_args *args) { + const int ngrp = args->gidsetsize; struct ucred *newcred, *oldcred; l_gid_t *linux_gidset; - int ngrp, error; + int error; struct proc *p; - ngrp = args->gidsetsize; - if (ngrp < 0 || ngrp >= ngroups_max) + if (ngrp < 0 || ngrp > ngroups_max) return (EINVAL); linux_gidset = malloc(ngrp * sizeof(*linux_gidset), M_LINUX, M_WAITOK); error = copyin(args->grouplist, linux_gidset, ngrp * sizeof(l_gid_t)); if (error) goto out; + newcred = crget(); crextend(newcred, ngrp); p = td->td_proc; PROC_LOCK(p); - oldcred = p->p_ucred; - crcopy(newcred, oldcred); + oldcred = crcopysafe(p, newcred); if ((error = priv_check_cred(oldcred, PRIV_CRED_SETGROUPS)) != 0) { PROC_UNLOCK(p); @@ -1071,34 +1071,29 @@ out: int linux_getgroups(struct thread *td, struct linux_getgroups_args *args) { - struct ucred *cred; + const struct ucred *const cred = td->td_ucred; l_gid_t *linux_gidset; - gid_t *bsd_gidset; - int bsd_gidsetsz, ngrp, error; + int ngrp, error; - cred = td->td_ucred; - bsd_gidset = cred->cr_groups; - bsd_gidsetsz = cred->cr_ngroups; + ngrp = args->gidsetsize; - if ((ngrp = args->gidsetsize) == 0) { - td->td_retval[0] = bsd_gidsetsz; + if (ngrp == 0) { + td->td_retval[0] = cred->cr_ngroups; return (0); } - - if (ngrp < bsd_gidsetsz) + if (ngrp < cred->cr_ngroups) return (EINVAL); - ngrp = 0; - linux_gidset = malloc(bsd_gidsetsz * sizeof(*linux_gidset), - M_LINUX, M_WAITOK); - while (ngrp < bsd_gidsetsz) { - linux_gidset[ngrp] = bsd_gidset[ngrp]; - ngrp++; - } + ngrp = cred->cr_ngroups; + + linux_gidset = malloc(ngrp * sizeof(*linux_gidset), M_LINUX, M_WAITOK); + for (int i = 0; i < ngrp; ++i) + linux_gidset[i] = cred->cr_groups[i]; error = copyout(linux_gidset, args->grouplist, ngrp * sizeof(l_gid_t)); free(linux_gidset, M_LINUX); - if (error) + + if (error != 0) return (error); td->td_retval[0] = ngrp; diff --git a/sys/compat/linux/linux_netlink.c b/sys/compat/linux/linux_netlink.c index 927f3689e2b6..6aeafe84adc6 100644 --- a/sys/compat/linux/linux_netlink.c +++ b/sys/compat/linux/linux_netlink.c @@ -242,9 +242,24 @@ nlmsg_copy_nla(const struct nlattr *nla_orig, struct nl_writer *nw) } /* + * Translate a FreeBSD interface name to a Linux interface name. + */ +static bool +nlmsg_translate_ifname_nla(struct nlattr *nla, struct nl_writer *nw) +{ + char ifname[LINUX_IFNAMSIZ]; + + if (ifname_bsd_to_linux_name((char *)(nla + 1), ifname, + sizeof(ifname)) <= 0) + return (false); + return (nlattr_add_string(nw, IFLA_IFNAME, ifname)); +} + +#define LINUX_NLA_UNHANDLED -1 +/* * Translate a FreeBSD attribute to a Linux attribute. - * Returns false when the attribute is not processed and the caller must take - * care of it. + * Returns LINUX_NLA_UNHANDLED when the attribute is not processed + * and the caller must take care of it, otherwise the result is returned. */ static int nlmsg_translate_all_nla(struct nlmsghdr *hdr, struct nlattr *nla, @@ -256,27 +271,22 @@ nlmsg_translate_all_nla(struct nlmsghdr *hdr, struct nlattr *nla, case NL_RTM_DELLINK: case NL_RTM_GETLINK: switch (nla->nla_type) { - case IFLA_IFNAME: { - char ifname[LINUX_IFNAMSIZ]; - - if (ifname_bsd_to_linux_name((char *)(nla + 1), ifname, - sizeof(ifname)) > 0) - return (true); - break; - } + case IFLA_IFNAME: + return (nlmsg_translate_ifname_nla(nla, nw)); default: break; } default: break; } - return (false); + return (LINUX_NLA_UNHANDLED); } static bool nlmsg_copy_all_nla(struct nlmsghdr *hdr, int raw_hdrlen, struct nl_writer *nw) { struct nlattr *nla; + int ret; int hdrlen = NETLINK_ALIGN(raw_hdrlen); int attrs_len = hdr->nlmsg_len - sizeof(struct nlmsghdr) - hdrlen; @@ -287,12 +297,15 @@ nlmsg_copy_all_nla(struct nlmsghdr *hdr, int raw_hdrlen, struct nl_writer *nw) if (nla->nla_len < sizeof(struct nlattr)) { return (false); } - if (!nlmsg_translate_all_nla(hdr, nla, nw) && - !nlmsg_copy_nla(nla, nw)) + ret = nlmsg_translate_all_nla(hdr, nla, nw); + if (ret == LINUX_NLA_UNHANDLED) + ret = nlmsg_copy_nla(nla, nw); + if (!ret) return (false); } return (true); } +#undef LINUX_NLA_UNHANDLED static unsigned int rtnl_if_flags_to_linux(unsigned int if_flags) diff --git a/sys/compat/linux/linux_socket.c b/sys/compat/linux/linux_socket.c index 539d153431c4..0e07b0a60ced 100644 --- a/sys/compat/linux/linux_socket.c +++ b/sys/compat/linux/linux_socket.c @@ -2179,6 +2179,7 @@ static int linux_getsockopt_so_peergroups(struct thread *td, struct linux_getsockopt_args *args) { + l_gid_t *out = PTRIN(args->optval); struct xucred xu; socklen_t xulen, len; int error, i; @@ -2197,13 +2198,12 @@ linux_getsockopt_so_peergroups(struct thread *td, return (error); } - /* - * "- 1" to skip the primary group. - */ + /* "- 1" to skip the primary group. */ for (i = 0; i < xu.cr_ngroups - 1; i++) { - error = copyout(xu.cr_groups + i + 1, - (void *)(args->optval + i * sizeof(l_gid_t)), - sizeof(l_gid_t)); + /* Copy to cope with a possible type discrepancy. */ + const l_gid_t g = xu.cr_groups[i + 1]; + + error = copyout(&g, out + i, sizeof(l_gid_t)); if (error != 0) return (error); } diff --git a/sys/compat/linux/linux_uid16.c b/sys/compat/linux/linux_uid16.c index 1d9a19916412..8ac093e004d0 100644 --- a/sys/compat/linux/linux_uid16.c +++ b/sys/compat/linux/linux_uid16.c @@ -85,13 +85,13 @@ linux_lchown16(struct thread *td, struct linux_lchown16_args *args) int linux_setgroups16(struct thread *td, struct linux_setgroups16_args *args) { + const int ngrp = args->gidsetsize; struct ucred *newcred, *oldcred; l_gid16_t *linux_gidset; - int ngrp, error; + int error; struct proc *p; - ngrp = args->gidsetsize; - if (ngrp < 0 || ngrp >= ngroups_max) + if (ngrp < 0 || ngrp > ngroups_max) return (EINVAL); linux_gidset = malloc(ngrp * sizeof(*linux_gidset), M_LINUX, M_WAITOK); error = copyin(args->gidset, linux_gidset, ngrp * sizeof(l_gid16_t)); @@ -100,7 +100,9 @@ linux_setgroups16(struct thread *td, struct linux_setgroups16_args *args) free(linux_gidset, M_LINUX); return (error); } + newcred = crget(); + crextend(newcred, ngrp); p = td->td_proc; PROC_LOCK(p); oldcred = crcopysafe(p, newcred); @@ -133,34 +135,29 @@ out: int linux_getgroups16(struct thread *td, struct linux_getgroups16_args *args) { - struct ucred *cred; + const struct ucred *const cred = td->td_ucred; l_gid16_t *linux_gidset; - gid_t *bsd_gidset; - int bsd_gidsetsz, ngrp, error; + int ngrp, error; - cred = td->td_ucred; - bsd_gidset = cred->cr_groups; - bsd_gidsetsz = cred->cr_ngroups; + ngrp = args->gidsetsize; - if ((ngrp = args->gidsetsize) == 0) { - td->td_retval[0] = bsd_gidsetsz; + if (ngrp == 0) { + td->td_retval[0] = cred->cr_ngroups; return (0); } - - if (ngrp < bsd_gidsetsz) + if (ngrp < cred->cr_ngroups) return (EINVAL); - ngrp = 0; - linux_gidset = malloc(bsd_gidsetsz * sizeof(*linux_gidset), - M_LINUX, M_WAITOK); - while (ngrp < bsd_gidsetsz) { - linux_gidset[ngrp] = bsd_gidset[ngrp]; - ngrp++; - } + ngrp = cred->cr_ngroups; + + linux_gidset = malloc(ngrp * sizeof(*linux_gidset), M_LINUX, M_WAITOK); + for (int i = 0; i < ngrp; ++i) + linux_gidset[i] = cred->cr_groups[i]; error = copyout(linux_gidset, args->gidset, ngrp * sizeof(l_gid16_t)); free(linux_gidset, M_LINUX); - if (error) { + + if (error != 0) { LIN_SDT_PROBE1(uid16, linux_getgroups16, copyout_error, error); return (error); } diff --git a/sys/compat/linuxkpi/common/include/acpi/acpi.h b/sys/compat/linuxkpi/common/include/acpi/acpi.h index 1e398d05ba20..9bb435591daa 100644 --- a/sys/compat/linuxkpi/common/include/acpi/acpi.h +++ b/sys/compat/linuxkpi/common/include/acpi/acpi.h @@ -37,7 +37,7 @@ /* * LINUXKPI_WANT_LINUX_ACPI is a temporary workaround to allow drm-kmod * to update all needed branches without breaking builds. - * Once that happened and checks are implemented based on __FreeBSD_verison + * Once that happened and checks are implemented based on __FreeBSD_version * we will remove these conditions again. */ @@ -131,7 +131,7 @@ acpi_format_exception(ACPI_STATUS Exception) } static inline ACPI_STATUS -acpi_get_handle(ACPI_HANDLE Parent, ACPI_STRING Pathname, +acpi_get_handle(ACPI_HANDLE Parent, const char *Pathname, ACPI_HANDLE *RetHandle) { return (AcpiGetHandle(Parent, Pathname, RetHandle)); diff --git a/sys/compat/linuxkpi/common/include/kunit/static_stub.h b/sys/compat/linuxkpi/common/include/kunit/static_stub.h new file mode 100644 index 000000000000..9d425d46dbb0 --- /dev/null +++ b/sys/compat/linuxkpi/common/include/kunit/static_stub.h @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2025 The FreeBSD Foundation + * + * This software was developed by Björn Zeeb under sponsorship from + * the FreeBSD Foundation. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#ifndef _LINUXKPI_KUNIT_STATIC_STUB_H +#define _LINUXKPI_KUNIT_STATIC_STUB_H + +#define KUNIT_STATIC_STUB_REDIRECT(_fn, ...) do { } while(0) + +#endif /* _LINUXKPI_KUNIT_STATIC_STUB_H */ diff --git a/sys/compat/linuxkpi/common/include/linux/cleanup.h b/sys/compat/linuxkpi/common/include/linux/cleanup.h index 01f234f0cbe7..5bb146f082ed 100644 --- a/sys/compat/linuxkpi/common/include/linux/cleanup.h +++ b/sys/compat/linuxkpi/common/include/linux/cleanup.h @@ -1,7 +1,7 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * - * Copyright (c) 2024 The FreeBSD Foundation + * Copyright (c) 2024-2025 The FreeBSD Foundation * * This software was developed by Björn Zeeb under sponsorship from * the FreeBSD Foundation. @@ -43,4 +43,51 @@ guard_ ## _n ## _t guard_ ## _n ## _ ## __COUNTER__ \ __cleanup(guard_ ## _n ## _destroy) = guard_ ## _n ## _create +#define DEFINE_FREE(_n, _t, _f) \ + static inline void \ + __free_ ## _n(void *p) \ + { \ + _t _T; \ + \ + _T = *(_t *)p; \ + _f; \ + } + +#define __free(_n) __cleanup(__free_##_n) + +/* + * Given this is a _0 version it should likely be broken up into parts. + * But we have no idead what a _1, _2, ... version would do different + * until we see a call. + * This is used for a not-real-type (rcu). We use a bool to "simulate" + * the lock held. Also _T still special, may not always be used, so tag + * with __unused (or better the LinuxKPI __maybe_unused). + */ +#define DEFINE_LOCK_GUARD_0(_n, _lock, _unlock, ...) \ + \ + typedef struct { \ + bool lock; \ + __VA_ARGS__; \ + } guard_ ## _n ## _t; \ + \ + static inline void \ + guard_ ## _n ## _destroy(guard_ ## _n ## _t *_T) \ + { \ + if (_T->lock) { \ + _unlock; \ + } \ + } \ + \ + static inline guard_ ## _n ## _t \ + guard_ ## _n ## _create(void) \ + { \ + guard_ ## _n ## _t _tmp; \ + guard_ ## _n ## _t *_T __maybe_unused; \ + \ + _tmp.lock = true; \ + _T = &_tmp; \ + _lock; \ + return (_tmp); \ + } + #endif /* _LINUXKPI_LINUX_CLEANUP_H */ diff --git a/sys/compat/linuxkpi/common/include/linux/compiler.h b/sys/compat/linuxkpi/common/include/linux/compiler.h index fb5ad3bf4fe4..948396144ad6 100644 --- a/sys/compat/linuxkpi/common/include/linux/compiler.h +++ b/sys/compat/linuxkpi/common/include/linux/compiler.h @@ -130,4 +130,10 @@ #define is_signed_type(t) ((t)-1 < (t)1) #define is_unsigned_type(t) ((t)-1 > (t)1) +#if __has_builtin(__builtin_dynamic_object_size) +#define __struct_size(_s) __builtin_dynamic_object_size(_s, 0) +#else +#define __struct_size(_s) __builtin_object_size(_s, 0) +#endif + #endif /* _LINUXKPI_LINUX_COMPILER_H_ */ diff --git a/sys/compat/linuxkpi/common/include/linux/device.h b/sys/compat/linuxkpi/common/include/linux/device.h index 2556b0c45e49..7dd6340746d2 100644 --- a/sys/compat/linuxkpi/common/include/linux/device.h +++ b/sys/compat/linuxkpi/common/include/linux/device.h @@ -4,7 +4,7 @@ * Copyright (c) 2010 Panasas, Inc. * Copyright (c) 2013-2016 Mellanox Technologies, Ltd. * All rights reserved. - * Copyright (c) 2021-2022 The FreeBSD Foundation + * Copyright (c) 2021-2025 The FreeBSD Foundation * * Portions of this software were developed by Björn Zeeb * under sponsorship from the FreeBSD Foundation. @@ -284,7 +284,8 @@ int lkpi_devres_destroy(struct device *, void(*release)(struct device *, void *) void lkpi_devres_release_free_list(struct device *); void lkpi_devres_unlink(struct device *, void *); void lkpi_devm_kmalloc_release(struct device *, void *); -#define devm_kfree(_d, _p) lkpi_devm_kmalloc_release(_d, _p) +void lkpi_devm_kfree(struct device *, const void *); +#define devm_kfree(_d, _p) lkpi_devm_kfree(_d, _p) static inline const char * dev_driver_string(const struct device *dev) diff --git a/sys/compat/linuxkpi/common/include/linux/ieee80211.h b/sys/compat/linuxkpi/common/include/linux/ieee80211.h index b9161c586d07..17041bb03ce8 100644 --- a/sys/compat/linuxkpi/common/include/linux/ieee80211.h +++ b/sys/compat/linuxkpi/common/include/linux/ieee80211.h @@ -408,6 +408,14 @@ enum ieee80211_sta_state { IEEE80211_STA_AUTHORIZED = 4, /* 802.1x */ }; +enum ieee80211_sta_rx_bandwidth { + IEEE80211_STA_RX_BW_20 = 0, + IEEE80211_STA_RX_BW_40, + IEEE80211_STA_RX_BW_80, + IEEE80211_STA_RX_BW_160, + IEEE80211_STA_RX_BW_320, +}; + enum ieee80211_tx_info_flags { /* XXX TODO .. right shift numbers - not sure where that came from? */ IEEE80211_TX_CTL_AMPDU = BIT(0), @@ -524,24 +532,24 @@ struct ieee80211_mgmt { uint16_t beacon_int; uint16_t capab_info; uint8_t variable[0]; - } beacon; + } __packed beacon; /* 9.3.3.5 Association Request frame format */ struct { uint16_t capab_info; uint16_t listen_interval; uint8_t variable[0]; - } assoc_req; + } __packed assoc_req; /* 9.3.3.10 Probe Request frame format */ struct { uint8_t variable[0]; - } probe_req; + } __packed probe_req; /* 9.3.3.11 Probe Response frame format */ struct { uint64_t timestamp; uint16_t beacon_int; uint16_t capab_info; uint8_t variable[0]; - } probe_resp; + } __packed probe_resp; /* 9.3.3.14 Action frame format */ struct { /* 9.4.1.11 Action field */ @@ -557,7 +565,7 @@ struct ieee80211_mgmt { uint8_t tpc_elem_length; uint8_t tpc_elem_tx_power; uint8_t tpc_elem_link_margin; - } tpc_report; + } __packed tpc_report; /* 9.6.8.33 Fine Timing Measurement frame format */ struct { uint8_t dialog_token; @@ -567,7 +575,7 @@ struct ieee80211_mgmt { uint16_t tod_error; uint16_t toa_error; uint8_t variable[0]; - } ftm; + } __packed ftm; /* 802.11-2016, 9.6.5.2 ADDBA Request frame format */ struct { uint8_t action_code; @@ -577,16 +585,16 @@ struct ieee80211_mgmt { uint16_t start_seq_num; /* Optional follows... */ uint8_t variable[0]; - } addba_req; + } __packed addba_req; /* XXX */ struct { uint8_t dialog_token; - } wnm_timing_msr; + } __packed wnm_timing_msr; } u; - } action; + } __packed action; DECLARE_FLEX_ARRAY(uint8_t, body); } u; -}; +} __packed __aligned(2); struct ieee80211_cts { /* net80211::ieee80211_frame_cts */ __le16 frame_control; diff --git a/sys/compat/linuxkpi/common/include/linux/math.h b/sys/compat/linuxkpi/common/include/linux/math.h index 5a348a57747b..1d50e011f66d 100644 --- a/sys/compat/linuxkpi/common/include/linux/math.h +++ b/sys/compat/linuxkpi/common/include/linux/math.h @@ -56,7 +56,7 @@ __ret; \ }) -#if defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 60600 +#if !defined(LINUXKPI_VERSION) || (LINUXKPI_VERSION >= 60600) #define abs_diff(x, y) ({ \ __typeof(x) _x = (x); \ __typeof(y) _y = (y); \ diff --git a/sys/compat/linuxkpi/common/include/linux/math64.h b/sys/compat/linuxkpi/common/include/linux/math64.h index a216d350570f..25ca9da1b622 100644 --- a/sys/compat/linuxkpi/common/include/linux/math64.h +++ b/sys/compat/linuxkpi/common/include/linux/math64.h @@ -98,6 +98,12 @@ div64_u64_round_up(uint64_t dividend, uint64_t divisor) return ((dividend + divisor - 1) / divisor); } +static inline uint64_t +roundup_u64(uint64_t x1, uint32_t x2) +{ + return (div_u64(x1 + x2 - 1, x2) * x2); +} + #define DIV64_U64_ROUND_UP(...) \ div64_u64_round_up(__VA_ARGS__) diff --git a/sys/compat/linuxkpi/common/include/linux/overflow.h b/sys/compat/linuxkpi/common/include/linux/overflow.h index 9ba9b9500f11..e811037b8ecc 100644 --- a/sys/compat/linuxkpi/common/include/linux/overflow.h +++ b/sys/compat/linuxkpi/common/include/linux/overflow.h @@ -33,8 +33,10 @@ * credit to Christian Biere. */ #define __type_half_max(type) ((type)1 << (8*sizeof(type) - 1 - is_signed_type(type))) -#define type_max(T) ((T)((__type_half_max(T) - 1) + __type_half_max(T))) -#define type_min(T) ((T)((T)-type_max(T)-(T)1)) +#define __type_max(T) ((T)((__type_half_max(T) - 1) + __type_half_max(T))) +#define type_max(t) __type_max(typeof(t)) +#define __type_min(T) ((T)((T)-type_max(T)-(T)1)) +#define type_min(t) __type_min(typeof(t)) /* * Avoids triggering -Wtype-limits compilation warning, @@ -59,46 +61,123 @@ static inline bool __must_check __must_check_overflow(bool overflow) * @b: second addend * @d: pointer to store sum * - * Returns 0 on success. + * Returns true on wrap-around, false otherwise. * - * *@d holds the results of the attempted addition, but is not considered - * "safe for use" on a non-zero return value, which indicates that the - * sum has overflowed or been truncated. + * *@d holds the results of the attempted addition, regardless of whether + * wrap-around occurred. */ #define check_add_overflow(a, b, d) \ __must_check_overflow(__builtin_add_overflow(a, b, d)) /** + * wrapping_add() - Intentionally perform a wrapping addition + * @type: type for result of calculation + * @a: first addend + * @b: second addend + * + * Return the potentially wrapped-around addition without + * tripping any wrap-around sanitizers that may be enabled. + */ +#define wrapping_add(type, a, b) \ + ({ \ + type __val; \ + __builtin_add_overflow(a, b, &__val); \ + __val; \ + }) + +/** + * wrapping_assign_add() - Intentionally perform a wrapping increment assignment + * @var: variable to be incremented + * @offset: amount to add + * + * Increments @var by @offset with wrap-around. Returns the resulting + * value of @var. Will not trip any wrap-around sanitizers. + * + * Returns the new value of @var. + */ +#define wrapping_assign_add(var, offset) \ + ({ \ + typeof(var) *__ptr = &(var); \ + *__ptr = wrapping_add(typeof(var), *__ptr, offset); \ + }) + +/** * check_sub_overflow() - Calculate subtraction with overflow checking * @a: minuend; value to subtract from * @b: subtrahend; value to subtract from @a * @d: pointer to store difference * - * Returns 0 on success. + * Returns true on wrap-around, false otherwise. * - * *@d holds the results of the attempted subtraction, but is not considered - * "safe for use" on a non-zero return value, which indicates that the - * difference has underflowed or been truncated. + * *@d holds the results of the attempted subtraction, regardless of whether + * wrap-around occurred. */ #define check_sub_overflow(a, b, d) \ __must_check_overflow(__builtin_sub_overflow(a, b, d)) /** + * wrapping_sub() - Intentionally perform a wrapping subtraction + * @type: type for result of calculation + * @a: minuend; value to subtract from + * @b: subtrahend; value to subtract from @a + * + * Return the potentially wrapped-around subtraction without + * tripping any wrap-around sanitizers that may be enabled. + */ +#define wrapping_sub(type, a, b) \ + ({ \ + type __val; \ + __builtin_sub_overflow(a, b, &__val); \ + __val; \ + }) + +/** + * wrapping_assign_sub() - Intentionally perform a wrapping decrement assign + * @var: variable to be decremented + * @offset: amount to subtract + * + * Decrements @var by @offset with wrap-around. Returns the resulting + * value of @var. Will not trip any wrap-around sanitizers. + * + * Returns the new value of @var. + */ +#define wrapping_assign_sub(var, offset) \ + ({ \ + typeof(var) *__ptr = &(var); \ + *__ptr = wrapping_sub(typeof(var), *__ptr, offset); \ + }) + +/** * check_mul_overflow() - Calculate multiplication with overflow checking * @a: first factor * @b: second factor * @d: pointer to store product * - * Returns 0 on success. + * Returns true on wrap-around, false otherwise. * - * *@d holds the results of the attempted multiplication, but is not - * considered "safe for use" on a non-zero return value, which indicates - * that the product has overflowed or been truncated. + * *@d holds the results of the attempted multiplication, regardless of whether + * wrap-around occurred. */ #define check_mul_overflow(a, b, d) \ __must_check_overflow(__builtin_mul_overflow(a, b, d)) /** + * wrapping_mul() - Intentionally perform a wrapping multiplication + * @type: type for result of calculation + * @a: first factor + * @b: second factor + * + * Return the potentially wrapped-around multiplication without + * tripping any wrap-around sanitizers that may be enabled. + */ +#define wrapping_mul(type, a, b) \ + ({ \ + type __val; \ + __builtin_mul_overflow(a, b, &__val); \ + __val; \ + }) + +/** * check_shl_overflow() - Calculate a left-shifted value and check overflow * @a: Value to be shifted * @s: How many bits left to shift @@ -122,7 +201,7 @@ static inline bool __must_check __must_check_overflow(bool overflow) typeof(a) _a = a; \ typeof(s) _s = s; \ typeof(d) _d = d; \ - u64 _a_full = _a; \ + unsigned long long _a_full = _a; \ unsigned int _to_shift = \ is_non_negative(_s) && _s < 8 * sizeof(*d) ? _s : 0; \ *_d = (_a_full << _to_shift); \ @@ -132,10 +211,10 @@ static inline bool __must_check __must_check_overflow(bool overflow) #define __overflows_type_constexpr(x, T) ( \ is_unsigned_type(typeof(x)) ? \ - (x) > type_max(typeof(T)) : \ + (x) > type_max(T) : \ is_unsigned_type(typeof(T)) ? \ - (x) < 0 || (x) > type_max(typeof(T)) : \ - (x) < type_min(typeof(T)) || (x) > type_max(typeof(T))) + (x) < 0 || (x) > type_max(T) : \ + (x) < type_min(T) || (x) > type_max(T)) #define __overflows_type(x, T) ({ \ typeof(T) v = 0; \ @@ -312,27 +391,40 @@ static inline size_t __must_check size_sub(size_t minuend, size_t subtrahend) struct_size((type *)NULL, member, count) /** - * _DEFINE_FLEX() - helper macro for DEFINE_FLEX() family. - * Enables caller macro to pass (different) initializer. + * __DEFINE_FLEX() - helper macro for DEFINE_FLEX() family. + * Enables caller macro to pass arbitrary trailing expressions * * @type: structure type name, including "struct" keyword. * @name: Name for a variable to define. * @member: Name of the array member. * @count: Number of elements in the array; must be compile-time const. - * @initializer: initializer expression (could be empty for no init). + * @trailer: Trailing expressions for attributes and/or initializers. */ -#define _DEFINE_FLEX(type, name, member, count, initializer) \ +#define __DEFINE_FLEX(type, name, member, count, trailer...) \ _Static_assert(__builtin_constant_p(count), \ "onstack flex array members require compile-time const count"); \ union { \ u8 bytes[struct_size_t(type, member, count)]; \ type obj; \ - } name##_u initializer; \ + } name##_u trailer; \ type *name = (type *)&name##_u /** - * DEFINE_FLEX() - Define an on-stack instance of structure with a trailing - * flexible array member. + * _DEFINE_FLEX() - helper macro for DEFINE_FLEX() family. + * Enables caller macro to pass (different) initializer. + * + * @type: structure type name, including "struct" keyword. + * @name: Name for a variable to define. + * @member: Name of the array member. + * @count: Number of elements in the array; must be compile-time const. + * @initializer: Initializer expression (e.g., pass `= { }` at minimum). + */ +#define _DEFINE_FLEX(type, name, member, count, initializer...) \ + __DEFINE_FLEX(type, name, member, count, = { .obj initializer }) + +/** + * DEFINE_RAW_FLEX() - Define an on-stack instance of structure with a trailing + * flexible array member, when it does not have a __counted_by annotation. * * @type: structure type name, including "struct" keyword. * @name: Name for a variable to define. @@ -342,8 +434,42 @@ static inline size_t __must_check size_sub(size_t minuend, size_t subtrahend) * Define a zeroed, on-stack, instance of @type structure with a trailing * flexible array member. * Use __struct_size(@name) to get compile-time size of it afterwards. + * Use __member_size(@name->member) to get compile-time size of @name members. + * Use STACK_FLEX_ARRAY_SIZE(@name, @member) to get compile-time number of + * elements in array @member. + */ +#define DEFINE_RAW_FLEX(type, name, member, count) \ + __DEFINE_FLEX(type, name, member, count, = { }) + +/** + * DEFINE_FLEX() - Define an on-stack instance of structure with a trailing + * flexible array member. + * + * @TYPE: structure type name, including "struct" keyword. + * @NAME: Name for a variable to define. + * @MEMBER: Name of the array member. + * @COUNTER: Name of the __counted_by member. + * @COUNT: Number of elements in the array; must be compile-time const. + * + * Define a zeroed, on-stack, instance of @TYPE structure with a trailing + * flexible array member. + * Use __struct_size(@NAME) to get compile-time size of it afterwards. + * Use __member_size(@NAME->member) to get compile-time size of @NAME members. + * Use STACK_FLEX_ARRAY_SIZE(@name, @member) to get compile-time number of + * elements in array @member. + */ +#define DEFINE_FLEX(TYPE, NAME, MEMBER, COUNTER, COUNT) \ + _DEFINE_FLEX(TYPE, NAME, MEMBER, COUNT, = { .COUNTER = COUNT, }) + +/** + * STACK_FLEX_ARRAY_SIZE() - helper macro for DEFINE_FLEX() family. + * Returns the number of elements in @array. + * + * @name: Name for a variable defined in DEFINE_RAW_FLEX()/DEFINE_FLEX(). + * @array: Name of the array member. */ -#define DEFINE_FLEX(type, name, member, count) \ - _DEFINE_FLEX(type, name, member, count, = {}) +#define STACK_FLEX_ARRAY_SIZE(name, array) \ + (__member_size((name)->array) / sizeof(*(name)->array) + \ + __must_be_array((name)->array)) #endif /* _LINUXKPI_LINUX_OVERFLOW_H */ diff --git a/sys/compat/linuxkpi/common/include/linux/pci.h b/sys/compat/linuxkpi/common/include/linux/pci.h index 3fd4191b9917..ffc2be600c22 100644 --- a/sys/compat/linuxkpi/common/include/linux/pci.h +++ b/sys/compat/linuxkpi/common/include/linux/pci.h @@ -355,7 +355,6 @@ struct pci_dev { TAILQ_HEAD(, pci_mmio_region) mmio; }; -int pci_request_region(struct pci_dev *pdev, int bar, const char *res_name); int pci_alloc_irq_vectors(struct pci_dev *pdev, int minv, int maxv, unsigned int flags); bool pci_device_is_present(struct pci_dev *pdev); @@ -365,10 +364,13 @@ void __iomem **linuxkpi_pcim_iomap_table(struct pci_dev *pdev); void *linuxkpi_pci_iomap_range(struct pci_dev *, int, unsigned long, unsigned long); void *linuxkpi_pci_iomap(struct pci_dev *, int, unsigned long); +void *linuxkpi_pcim_iomap(struct pci_dev *, int, unsigned long); void linuxkpi_pci_iounmap(struct pci_dev *pdev, void *res); int linuxkpi_pcim_iomap_regions(struct pci_dev *pdev, uint32_t mask, const char *name); +int linuxkpi_pci_request_region(struct pci_dev *, int, const char *); int linuxkpi_pci_request_regions(struct pci_dev *pdev, const char *res_name); +int linuxkpi_pcim_request_all_regions(struct pci_dev *, const char *); void linuxkpi_pci_release_region(struct pci_dev *pdev, int bar); void linuxkpi_pci_release_regions(struct pci_dev *pdev); int linuxkpi_pci_enable_msix(struct pci_dev *pdev, struct msix_entry *entries, @@ -561,12 +563,16 @@ done: return (pdev->bus->self); } +#define pci_request_region(pdev, bar, res_name) \ + linuxkpi_pci_request_region(pdev, bar, res_name) #define pci_release_region(pdev, bar) \ linuxkpi_pci_release_region(pdev, bar) -#define pci_release_regions(pdev) \ - linuxkpi_pci_release_regions(pdev) #define pci_request_regions(pdev, res_name) \ linuxkpi_pci_request_regions(pdev, res_name) +#define pci_release_regions(pdev) \ + linuxkpi_pci_release_regions(pdev) +#define pcim_request_all_regions(pdev, name) \ + linuxkpi_pcim_request_all_regions(pdev, name) static inline void lkpi_pci_disable_msix(struct pci_dev *pdev) @@ -803,6 +809,8 @@ static inline void pci_disable_sriov(struct pci_dev *dev) linuxkpi_pci_iomap_range(pdev, mmio_bar, mmio_off, mmio_size) #define pci_iomap(pdev, mmio_bar, mmio_size) \ linuxkpi_pci_iomap(pdev, mmio_bar, mmio_size) +#define pcim_iomap(pdev, bar, maxlen) \ + linuxkpi_pcim_iomap(pdev, bar, maxlen) #define pci_iounmap(pdev, res) \ linuxkpi_pci_iounmap(pdev, res) @@ -1324,6 +1332,12 @@ struct pci_dev *lkpi_pci_get_domain_bus_and_slot(int domain, #define pci_get_domain_bus_and_slot(domain, bus, devfn) \ lkpi_pci_get_domain_bus_and_slot(domain, bus, devfn) +struct pci_dev *lkpi_pci_get_slot(struct pci_bus *, unsigned int); +#ifndef WANT_NATIVE_PCI_GET_SLOT +#define pci_get_slot(_pbus, _devfn) \ + lkpi_pci_get_slot(_pbus, _devfn) +#endif + static inline int pci_domain_nr(struct pci_bus *pbus) { @@ -1445,6 +1459,9 @@ linuxkpi_pci_get_device(uint32_t vendor, uint32_t device, struct pci_dev *odev) return (lkpi_pci_get_device(vendor, device, odev)); } +#define for_each_pci_dev(_pdev) \ + while ((_pdev = linuxkpi_pci_get_device(PCI_ANY_ID, PCI_ANY_ID, _pdev)) != NULL) + /* This is a FreeBSD extension so we can use bus_*(). */ static inline void linuxkpi_pcim_want_to_use_bus_functions(struct pci_dev *pdev) diff --git a/sys/compat/linuxkpi/common/include/linux/rcupdate.h b/sys/compat/linuxkpi/common/include/linux/rcupdate.h index 85d766c8dbc9..4aceb7296cd6 100644 --- a/sys/compat/linuxkpi/common/include/linux/rcupdate.h +++ b/sys/compat/linuxkpi/common/include/linux/rcupdate.h @@ -1,7 +1,7 @@ /*- * Copyright (c) 2016-2017 Mellanox Technologies, Ltd. * All rights reserved. - * Copyright (c) 2024 The FreeBSD Foundation + * Copyright (c) 2024-2025 The FreeBSD Foundation * * Portions of this software were developed by Björn Zeeb * under sponsorship from the FreeBSD Foundation. @@ -35,6 +35,7 @@ #include <linux/compiler.h> #include <linux/types.h> #include <linux/kernel.h> +#include <linux/cleanup.h> #include <machine/atomic.h> @@ -162,4 +163,6 @@ void linux_synchronize_rcu(unsigned type); #define init_rcu_head_on_stack(...) #define destroy_rcu_head_on_stack(...) +DEFINE_LOCK_GUARD_0(rcu, rcu_read_lock(), rcu_read_unlock()) + #endif /* _LINUXKPI_LINUX_RCUPDATE_H_ */ diff --git a/sys/compat/linuxkpi/common/include/linux/skbuff.h b/sys/compat/linuxkpi/common/include/linux/skbuff.h index c8ad90281e34..6e41c368a8b8 100644 --- a/sys/compat/linuxkpi/common/include/linux/skbuff.h +++ b/sys/compat/linuxkpi/common/include/linux/skbuff.h @@ -1,6 +1,6 @@ /*- * Copyright (c) 2020-2025 The FreeBSD Foundation - * Copyright (c) 2021-2023 Bjoern A. Zeeb + * Copyright (c) 2021-2025 Bjoern A. Zeeb * * This software was developed by Björn Zeeb under sponsorship from * the FreeBSD Foundation. @@ -47,13 +47,11 @@ #include <linux/ktime.h> #include <linux/compiler.h> -#include "opt_wlan.h" - -/* Currently this is only used for wlan so we can depend on that. */ -#if defined(IEEE80211_DEBUG) && !defined(SKB_DEBUG) -#define SKB_DEBUG -#endif - +/* + * At least the net/intel-irdma-kmod port pulls this header in; likely through + * if_ether.h (see PR289268). This means we no longer can rely on + * IEEE80211_DEBUG (opt_wlan.h) to automatically set SKB_DEBUG. + */ /* #define SKB_DEBUG */ #ifdef SKB_DEBUG @@ -120,7 +118,7 @@ enum sk_checksum_flags { CHECKSUM_NONE = 0x00, CHECKSUM_UNNECESSARY = 0x01, CHECKSUM_PARTIAL = 0x02, - CHECKSUM_COMPLETE = 0x04, + CHECKSUM_COMPLETE = 0x03, }; struct skb_frag { @@ -170,7 +168,7 @@ struct sk_buff { }; }; uint16_t protocol; - uint8_t ip_summed; + uint8_t ip_summed; /* 2 bit only. */ /* uint8_t */ /* "Scratch" area for layers to store metadata. */ diff --git a/sys/compat/linuxkpi/common/include/linux/slab.h b/sys/compat/linuxkpi/common/include/linux/slab.h index 47e3d133eb6c..0e649e1e3c4a 100644 --- a/sys/compat/linuxkpi/common/include/linux/slab.h +++ b/sys/compat/linuxkpi/common/include/linux/slab.h @@ -40,8 +40,10 @@ #include <linux/compat.h> #include <linux/types.h> #include <linux/gfp.h> +#include <linux/err.h> #include <linux/llist.h> #include <linux/overflow.h> +#include <linux/cleanup.h> MALLOC_DECLARE(M_KMALLOC); @@ -153,6 +155,8 @@ kfree(const void *ptr) lkpi_kfree(ptr); } +DEFINE_FREE(kfree, void *, if (!IS_ERR_OR_NULL(_T)) kfree(_T)) + /* * Other k*alloc() funtions using the above as underlying allocator. */ diff --git a/sys/compat/linuxkpi/common/include/linux/string_choices.h b/sys/compat/linuxkpi/common/include/linux/string_choices.h new file mode 100644 index 000000000000..74aa3fd019b2 --- /dev/null +++ b/sys/compat/linuxkpi/common/include/linux/string_choices.h @@ -0,0 +1,71 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2023 Jean-Sébastien Pédron <dumbbell@FreeBSD.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _LINUXKPI_LINUX_STRING_CHOICES_H_ +#define _LINUXKPI_LINUX_STRING_CHOICES_H_ + +#include <sys/types.h> + +static inline const char * +str_yes_no(bool value) +{ + if (value) + return "yes"; + else + return "no"; +} + +static inline const char * +str_on_off(bool value) +{ + if (value) + return "on"; + else + return "off"; +} + +static inline const char * +str_enabled_disabled(bool value) +{ + if (value) + return "enabled"; + else + return "disabled"; +} + +static inline const char * +str_enable_disable(bool value) +{ + if (value) + return "enable"; + else + return "disable"; +} + +#define str_disable_enable(_v) str_enable_disable(!(_v)) + +#endif diff --git a/sys/compat/linuxkpi/common/include/linux/string_helpers.h b/sys/compat/linuxkpi/common/include/linux/string_helpers.h index 1bdff2730361..07d113c0cb21 100644 --- a/sys/compat/linuxkpi/common/include/linux/string_helpers.h +++ b/sys/compat/linuxkpi/common/include/linux/string_helpers.h @@ -1,69 +1,12 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 2023 Jean-Sébastien Pédron <dumbbell@FreeBSD.org> +/* + * Copyright (c) 2025 The FreeBSD Foundation * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice unmodified, this list of conditions, and the following - * disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * SPDX-License-Identifier: BSD-2-Clause */ #ifndef _LINUXKPI_LINUX_STRING_HELPERS_H_ #define _LINUXKPI_LINUX_STRING_HELPERS_H_ -#include <sys/types.h> - -static inline const char * -str_yes_no(bool value) -{ - if (value) - return "yes"; - else - return "no"; -} - -static inline const char * -str_on_off(bool value) -{ - if (value) - return "on"; - else - return "off"; -} - -static inline const char * -str_enabled_disabled(bool value) -{ - if (value) - return "enabled"; - else - return "disabled"; -} - -static inline const char * -str_enable_disable(bool value) -{ - if (value) - return "enable"; - else - return "disable"; -} +#include <linux/string_choices.h> #endif diff --git a/sys/compat/linuxkpi/common/include/linux/timer.h b/sys/compat/linuxkpi/common/include/linux/timer.h index a635f0faea59..d48939e28a02 100644 --- a/sys/compat/linuxkpi/common/include/linux/timer.h +++ b/sys/compat/linuxkpi/common/include/linux/timer.h @@ -49,8 +49,13 @@ extern unsigned long linux_timer_hz_mask; #define TIMER_IRQSAFE 0x0001 +#if defined(LINUXKPI_VERSION) && (LINUXKPI_VERSION < 61600) #define from_timer(var, arg, field) \ container_of(arg, typeof(*(var)), field) +#else +#define timer_container_of(var, arg, field) \ + container_of(arg, typeof(*(var)), field) +#endif #define timer_setup(timer, func, flags) do { \ CTASSERT(((flags) & ~TIMER_IRQSAFE) == 0); \ @@ -79,11 +84,23 @@ extern unsigned long linux_timer_hz_mask; extern int mod_timer(struct timer_list *, unsigned long); extern void add_timer(struct timer_list *); extern void add_timer_on(struct timer_list *, int cpu); -extern int del_timer(struct timer_list *); -extern int del_timer_sync(struct timer_list *); + +extern int timer_delete(struct timer_list *); extern int timer_delete_sync(struct timer_list *); extern int timer_shutdown_sync(struct timer_list *); +static inline int +del_timer(struct timer_list *tl) +{ + return (timer_delete(tl)); +} + +static inline int +del_timer_sync(struct timer_list *tl) +{ + return (timer_delete_sync(tl)); +} + #define timer_pending(timer) callout_pending(&(timer)->callout) #define round_jiffies(j) \ ((unsigned long)(((j) + linux_timer_hz_mask) & ~linux_timer_hz_mask)) diff --git a/sys/compat/linuxkpi/common/include/net/mac80211.h b/sys/compat/linuxkpi/common/include/net/mac80211.h index 0106e6648bd4..8de03410c6b6 100644 --- a/sys/compat/linuxkpi/common/include/net/mac80211.h +++ b/sys/compat/linuxkpi/common/include/net/mac80211.h @@ -737,7 +737,7 @@ struct ieee80211_link_sta { struct ieee80211_he_6ghz_capa he_6ghz_capa; struct ieee80211_sta_eht_cap eht_cap; uint8_t rx_nss; - enum ieee80211_sta_rx_bw bandwidth; + enum ieee80211_sta_rx_bandwidth bandwidth; enum ieee80211_smps_mode smps_mode; struct ieee80211_sta_agg agg; struct ieee80211_sta_txpwr txpwr; diff --git a/sys/compat/linuxkpi/common/src/linux_80211.c b/sys/compat/linuxkpi/common/src/linux_80211.c index e248588dd275..bc4b334de28e 100644 --- a/sys/compat/linuxkpi/common/src/linux_80211.c +++ b/sys/compat/linuxkpi/common/src/linux_80211.c @@ -77,6 +77,8 @@ #include <linux/rculist.h> #include "linux_80211.h" +/* #define LKPI_80211_USE_SCANLIST */ +/* #define LKPI_80211_BGSCAN */ #define LKPI_80211_WME #define LKPI_80211_HW_CRYPTO #define LKPI_80211_HT @@ -103,6 +105,10 @@ SYSCTL_DECL(_compat_linuxkpi); SYSCTL_NODE(_compat_linuxkpi, OID_AUTO, 80211, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, "LinuxKPI 802.11 compatibility layer"); +static bool lkpi_order_scanlist = false; +SYSCTL_BOOL(_compat_linuxkpi_80211, OID_AUTO, order_scanlist, CTLFLAG_RW, + &lkpi_order_scanlist, 0, "Enable LinuxKPI 802.11 scan list shuffeling"); + #if defined(LKPI_80211_HW_CRYPTO) static bool lkpi_hwcrypto = false; SYSCTL_BOOL(_compat_linuxkpi_80211, OID_AUTO, hw_crypto, CTLFLAG_RDTUN, @@ -167,6 +173,7 @@ const struct cfg80211_ops linuxkpi_mac80211cfgops = { static struct lkpi_sta *lkpi_find_lsta_by_ni(struct lkpi_vif *, struct ieee80211_node *); #endif +static void lkpi_sw_scan_task(void *, int); static void lkpi_80211_txq_tx_one(struct lkpi_sta *, struct mbuf *); static void lkpi_80211_txq_task(void *, int); static void lkpi_80211_lhw_rxq_task(void *, int); @@ -394,7 +401,7 @@ lkpi_80211_dump_stas(SYSCTL_HANDLER_ARGS) return (0); } -static enum ieee80211_sta_rx_bw +static enum ieee80211_sta_rx_bandwidth lkpi_cw_to_rx_bw(enum nl80211_chan_width cw) { switch (cw) { @@ -418,7 +425,7 @@ lkpi_cw_to_rx_bw(enum nl80211_chan_width cw) } static enum nl80211_chan_width -lkpi_rx_bw_to_cw(enum ieee80211_sta_rx_bw rx_bw) +lkpi_rx_bw_to_cw(enum ieee80211_sta_rx_bandwidth rx_bw) { switch (rx_bw) { case IEEE80211_STA_RX_BW_20: @@ -439,7 +446,7 @@ lkpi_sync_chanctx_cw_from_rx_bw(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct ieee80211_chanctx_conf *chanctx_conf; - enum ieee80211_sta_rx_bw old_bw; + enum ieee80211_sta_rx_bandwidth old_bw; uint32_t changed; chanctx_conf = rcu_dereference_protected(vif->bss_conf.chanctx_conf, @@ -544,7 +551,7 @@ static void lkpi_sta_sync_vht_from_ni(struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_node *ni) { - enum ieee80211_sta_rx_bw bw; + enum ieee80211_sta_rx_bandwidth bw; uint32_t width; int rx_nss; uint16_t rx_mcs_map; @@ -955,6 +962,30 @@ lkpi_nl80211_band_to_net80211_band(enum nl80211_band band) return (0x00); } +#ifdef LINUXKPI_DEBUG_80211 +static const char * +lkpi_nl80211_band_name(enum nl80211_band band) +{ + switch (band) { + case NL80211_BAND_2GHZ: + return "2Ghz"; + break; + case NL80211_BAND_5GHZ: + return "5Ghz"; + break; + case NL80211_BAND_60GHZ: + return "60Ghz"; + break; + case NL80211_BAND_6GHZ: + return "6Ghz"; + break; + default: + panic("%s: unsupported band %u\n", __func__, band); + break; + } +} +#endif + #if 0 static enum ieee80211_ac_numbers lkpi_ac_net_to_l80211(int ac) @@ -1319,6 +1350,7 @@ lkpi_iv_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k) lhw = ic->ic_softc; hw = LHW_TO_HW(lhw); lvif = VAP_TO_LVIF(vap); + vif = LVIF_TO_VIF(lvif); /* * Make sure we do not make it here without going through @@ -1326,6 +1358,23 @@ lkpi_iv_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k) */ lockdep_assert_wiphy(hw->wiphy); + /* + * While we are assoc we may still send packets. We cannot delete the + * keys as otherwise packets could go out unencrypted. Some firmware + * does not like this and will fire an assert. + * net80211 needs to drive this better but given we want the disassoc + * frame out and have to unlock we are open to a race currently. + * This check should prevent problems. + * How to test: run 800Mbit/s UDP traffic and during that restart your + * supplicant. You want to survive that. + */ + if (vif->cfg.assoc) { + if (linuxkpi_debug_80211 & D80211_TRACE_HW_CRYPTO) + ic_printf(ic, "%d %lu %s: vif still assoc; not deleting keys\n", + curthread->td_tid, jiffies, __func__); + return (0); + } + if (IEEE80211_KEY_UNDEFINED(k)) { ic_printf(ic, "%s: vap %p key %p is undefined: %p %u\n", __func__, vap, k, k->wk_cipher, k->wk_keyix); @@ -1370,7 +1419,6 @@ lkpi_iv_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k) kc->keyidx, kc->hw_key_idx, kc->flags, IEEE80211_KEY_FLAG_BITS); #endif - vif = LVIF_TO_VIF(lvif); error = lkpi_80211_mo_set_key(hw, DISABLE_KEY, vif, sta, kc); if (error != 0) { ic_printf(ic, "%d %lu %s: set_key cmd %d(%s) for sta %6D failed: %d\n", @@ -1842,13 +1890,31 @@ lkpi_update_dtim_tsf(struct ieee80211_vif *vif, struct ieee80211_node *ni, vif->bss_conf.beacon_int = 16; bss_changed |= BSS_CHANGED_BEACON_INT; } - if (vif->bss_conf.dtim_period != vap->iv_dtim_period && - vap->iv_dtim_period > 0) { - vif->bss_conf.dtim_period = vap->iv_dtim_period; + + /* + * lkpi_iv_sta_recv_mgmt() will directly call into this function. + * iwlwifi(4) in iwl_mvm_bss_info_changed_station_common() will + * stop seesion protection the moment it sees + * BSS_CHANGED_BEACON_INFO (with the expectations that it was + * "a beacon from the associated AP"). It will also update + * the beacon filter in that case. This is the only place + * we set the BSS_CHANGED_BEACON_INFO on the non-teardown + * path so make sure we only do run this check once we are + * assoc. (*iv_recv_mgmt)() will be called before we enter + * here so the ni will be updates with information from the + * beacon via net80211::sta_recv_mgmt(). We also need to + * make sure we do not do it on every beacon we still may + * get so only do if something changed. vif->bss_conf.dtim_period + * should be 0 as we start up (we also reset it on teardown). + */ + if (vif->cfg.assoc && + vif->bss_conf.dtim_period != ni->ni_dtim_period && + ni->ni_dtim_period > 0) { + vif->bss_conf.dtim_period = ni->ni_dtim_period; bss_changed |= BSS_CHANGED_BEACON_INFO; } - vif->bss_conf.sync_dtim_count = vap->iv_dtim_count; + vif->bss_conf.sync_dtim_count = ni->ni_dtim_count; vif->bss_conf.sync_tsf = le64toh(ni->ni_tstamp.tsf); /* vif->bss_conf.sync_device_ts = set in linuxkpi_ieee80211_rx. */ @@ -1876,6 +1942,8 @@ lkpi_stop_hw_scan(struct lkpi_hw *lhw, struct ieee80211_vif *vif) int error; bool cancel; + TRACE_SCAN(lhw->ic, "scan_flags %b", lhw->scan_flags, LKPI_LHW_SCAN_BITS); + LKPI_80211_LHW_SCAN_LOCK(lhw); cancel = (lhw->scan_flags & LKPI_LHW_SCAN_RUNNING) != 0; LKPI_80211_LHW_SCAN_UNLOCK(lhw); @@ -2500,12 +2568,6 @@ lkpi_sta_auth_to_scan(struct ieee80211vap *vap, enum ieee80211_state nstate, int lvif->lvif_bss_synched = false; LKPI_80211_LVIF_UNLOCK(lvif); lkpi_lsta_remove(lsta, lvif); - /* - * The very last release the reference on the ni for the ni/lsta on - * lvif->lvif_bss. Upon return from this both ni and lsta are invalid - * and potentially freed. - */ - ieee80211_free_node(ni); /* conf_tx */ @@ -2514,6 +2576,18 @@ lkpi_sta_auth_to_scan(struct ieee80211vap *vap, enum ieee80211_state nstate, int out: wiphy_unlock(hw->wiphy); IEEE80211_LOCK(vap->iv_ic); + if (error == 0) { + /* + * We do this outside the wiphy lock as net80211::node_free() may call + * into crypto code to delete keys and we have a recursed on + * non-recursive sx panic. Also only do this if we get here w/o error. + * + * The very last release the reference on the ni for the ni/lsta on + * lvif->lvif_bss. Upon return from this both ni and lsta are invalid + * and potentially freed. + */ + ieee80211_free_node(ni); + } return (error); } @@ -2798,6 +2872,14 @@ _lkpi_sta_assoc_to_down(struct ieee80211vap *vap, enum ieee80211_state nstate, i bss_changed = 0; bss_changed |= lkpi_disassoc(sta, vif, lhw); +#ifdef LKPI_80211_HW_CRYPTO + /* + * In theory we remove keys here but there must not exist any for this + * state change until we clean them up again into small steps and no + * code duplication. + */ +#endif + lkpi_lsta_dump(lsta, ni, __func__, __LINE__); /* Adjust sta and change state (from NONE) to NOTEXIST. */ @@ -2830,12 +2912,6 @@ _lkpi_sta_assoc_to_down(struct ieee80211vap *vap, enum ieee80211_state nstate, i lvif->lvif_bss_synched = false; LKPI_80211_LVIF_UNLOCK(lvif); lkpi_lsta_remove(lsta, lvif); - /* - * The very last release the reference on the ni for the ni/lsta on - * lvif->lvif_bss. Upon return from this both ni and lsta are invalid - * and potentially freed. - */ - ieee80211_free_node(ni); /* conf_tx */ @@ -2845,6 +2921,18 @@ _lkpi_sta_assoc_to_down(struct ieee80211vap *vap, enum ieee80211_state nstate, i out: wiphy_unlock(hw->wiphy); IEEE80211_LOCK(vap->iv_ic); + if (error == EALREADY) { + /* + * We do this outside the wiphy lock as net80211::node_free() may call + * into crypto code to delete keys and we have a recursed on + * non-recursive sx panic. Also only do this if we get here w/o error. + * + * The very last release the reference on the ni for the ni/lsta on + * lvif->lvif_bss. Upon return from this both ni and lsta are invalid + * and potentially freed. + */ + ieee80211_free_node(ni); + } outni: return (error); } @@ -3333,6 +3421,16 @@ lkpi_sta_run_to_init(struct ieee80211vap *vap, enum ieee80211_state nstate, int #ifdef LKPI_80211_HW_CRYPTO if (lkpi_hwcrypto) { + /* + * In theory we only need to do this if we changed assoc. + * If we were not assoc, there should be no keys and we + * should not be here. + */ +#ifdef notyet + KASSERT((bss_changed & BSS_CHANGED_ASSOC) != 0, ("%s: " + "trying to remove keys but were not assoc: %#010jx, lvif %p\n", + __func__, (uintmax_t)bss_changed, lvif)); +#endif error = lkpi_sta_del_keys(hw, vif, lsta); if (error != 0) { ic_printf(vap->iv_ic, "%s:%d: lkpi_sta_del_keys " @@ -3394,6 +3492,9 @@ lkpi_sta_run_to_init(struct ieee80211vap *vap, enum ieee80211_state nstate, int * 4) call unassign_vif_chanctx * 5) call lkpi_hw_conf_idle * 6) call remove_chanctx + * + * Note: vif->driver_flags & IEEE80211_VIF_REMOVE_AP_AFTER_DISASSOC + * might change this. */ bss_changed |= lkpi_disassoc(sta, vif, lhw); @@ -3433,12 +3534,6 @@ lkpi_sta_run_to_init(struct ieee80211vap *vap, enum ieee80211_state nstate, int lvif->lvif_bss = NULL; lvif->lvif_bss_synched = false; LKPI_80211_LVIF_UNLOCK(lvif); - /* - * The very last release the reference on the ni for the ni/lsta on - * lvif->lvif_bss. Upon return from this both ni and lsta are invalid - * and potentially freed. - */ - ieee80211_free_node(ni); /* conf_tx */ @@ -3448,6 +3543,18 @@ lkpi_sta_run_to_init(struct ieee80211vap *vap, enum ieee80211_state nstate, int out: wiphy_unlock(hw->wiphy); IEEE80211_LOCK(vap->iv_ic); + if (error == EALREADY) { + /* + * We do this outside the wiphy lock as net80211::node_free() may call + * into crypto code to delete keys and we have a recursed on + * non-recursive sx panic. Also only do this if we get here w/o error. + * + * The very last release the reference on the ni for the ni/lsta on + * lvif->lvif_bss. Upon return from this both ni and lsta are invalid + * and potentially freed. + */ + ieee80211_free_node(ni); + } outni: return (error); } @@ -3545,7 +3652,7 @@ lkpi_iv_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) vif = LVIF_TO_VIF(lvif); /* No need to replicate this in most state handlers. */ - if (ostate == IEEE80211_S_SCAN && nstate != IEEE80211_S_SCAN) + if (nstate > IEEE80211_S_SCAN) lkpi_stop_hw_scan(lhw, vif); s = sta_state_fsm; @@ -3739,6 +3846,7 @@ lkpi_iv_sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, enum ieee80211_bss_changed bss_changed; lvif = VAP_TO_LVIF(ni->ni_vap); + vif = LVIF_TO_VIF(lvif); lvif->iv_recv_mgmt(ni, m0, subtype, rxs, rssi, nf); @@ -3746,13 +3854,18 @@ lkpi_iv_sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, case IEEE80211_FC0_SUBTYPE_PROBE_RESP: break; case IEEE80211_FC0_SUBTYPE_BEACON: - lvif->beacons++; + /* + * Only count beacons when assoc. SCAN has its own logging. + * This is for connection/beacon loss/session protection almost + * over debugging when trying to get into a stable RUN state. + */ + if (vif->cfg.assoc) + lvif->beacons++; break; default: return; } - vif = LVIF_TO_VIF(lvif); lhw = ni->ni_ic->ic_softc; hw = LHW_TO_HW(lhw); @@ -3824,6 +3937,7 @@ lkpi_ic_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], lvif = malloc(len, M_80211_VAP, M_WAITOK | M_ZERO); mtx_init(&lvif->mtx, "lvif", NULL, MTX_DEF); + TASK_INIT(&lvif->sw_scan_task, 0, lkpi_sw_scan_task, lvif); INIT_LIST_HEAD(&lvif->lsta_list); lvif->lvif_bss = NULL; refcount_init(&lvif->nt_unlocked, 0); @@ -3987,13 +4101,9 @@ lkpi_ic_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], * Modern chipset/fw/drv will do A-MPDU in drv/fw and fail * to do so if they cannot do the crypto too. */ - if (!lkpi_hwcrypto && ieee80211_hw_check(hw, AMPDU_AGGREGATION)) + if (!lkpi_hwcrypto && IEEE80211_CONF_AMPDU_OFFLOAD(ic)) vap->iv_flags_ht &= ~IEEE80211_FHT_AMPDU_RX; #endif -#if defined(LKPI_80211_HT) - /* 20250125-BZ Keep A-MPDU TX cleared until we sorted out AddBA for all drivers. */ - vap->iv_flags_ht &= ~IEEE80211_FHT_AMPDU_TX; -#endif if (hw->max_listen_interval == 0) hw->max_listen_interval = 7 * (ic->ic_lintval / ic->ic_bintval); @@ -4062,6 +4172,8 @@ lkpi_ic_vap_delete(struct ieee80211vap *vap) /* Clear up per-VIF/VAP sysctls. */ sysctl_ctx_free(&lvif->sysctl_ctx); + ieee80211_draintask(ic, &lvif->sw_scan_task); + LKPI_80211_LHW_LVIF_LOCK(lhw); TAILQ_REMOVE(&lhw->lvif_head, lvif, lvif_entry); LKPI_80211_LHW_LVIF_UNLOCK(lhw); @@ -4303,6 +4415,113 @@ lkpi_scan_ies_add(uint8_t *p, struct ieee80211_scan_ies *scan_ies, } static void +lkpi_enable_hw_scan(struct lkpi_hw *lhw) +{ + + if (lhw->ops->hw_scan) { + /* + * Advertise full-offload scanning. + * + * Not limiting to SINGLE_SCAN_ON_ALL_BANDS here as otherwise + * we essentially disable hw_scan for all drivers not setting + * the flag. + */ + lhw->ic->ic_flags_ext |= IEEE80211_FEXT_SCAN_OFFLOAD; + lhw->scan_flags |= LKPI_LHW_SCAN_HW; + } +} + +#ifndef LKPI_80211_USE_SCANLIST +static const uint32_t chan_pri[] = { + 5180, 5500, 5745, + 5260, 5580, 5660, 5825, + 5220, 5300, 5540, 5620, 5700, 5785, 5865, + 2437, 2412, 2422, 2462, 2472, 2432, 2452 +}; + +static int +lkpi_scan_chan_list_idx(const struct linuxkpi_ieee80211_channel *lc) +{ + int i; + + for (i = 0; i < nitems(chan_pri); i++) { + if (lc->center_freq == chan_pri[i]) + return (i); + } + + return (-1); +} + +static int +lkpi_scan_chan_list_comp(const struct linuxkpi_ieee80211_channel *lc1, + const struct linuxkpi_ieee80211_channel *lc2) +{ + int idx1, idx2; + + /* Find index in list. */ + idx1 = lkpi_scan_chan_list_idx(lc1); + idx2 = lkpi_scan_chan_list_idx(lc2); + + if (idx1 == -1 && idx2 != -1) + return (1); + if (idx1 != -1 && idx2 == -1) + return (-1); + + /* Neither on the list, use center_freq. */ + if (idx1 == -1 && idx2 == -1) + return (lc1->center_freq - lc2->center_freq); + + /* Whichever is first in the list. */ + return (idx1 - idx2); +} + +static void +lkpi_scan_chan_list_resort(struct linuxkpi_ieee80211_channel **cpp, size_t nchan) +{ + struct linuxkpi_ieee80211_channel *lc, *nc; + size_t i, j; + int rc; + + for (i = (nchan - 1); i > 0; i--) { + for (j = i; j > 0 ; j--) { + lc = *(cpp + j); + nc = *(cpp + j - 1); + rc = lkpi_scan_chan_list_comp(lc, nc); + if (rc < 0) { + *(cpp + j) = nc; + *(cpp + j - 1) = lc; + } + } + } +} + +static bool +lkpi_scan_chan(struct linuxkpi_ieee80211_channel *c, + struct ieee80211com *ic, bool log) +{ + + if ((c->flags & IEEE80211_CHAN_DISABLED) != 0) { + if (log) + TRACE_SCAN(ic, "Skipping disabled chan " + "on band %s [%#x/%u/%#x]", + lkpi_nl80211_band_name(c->band), c->hw_value, + c->center_freq, c->flags); + return (false); + } + if (isclr(ic->ic_chan_active, ieee80211_mhz2ieee(c->center_freq, + lkpi_nl80211_band_to_net80211_band(c->band)))) { + if (log) + TRACE_SCAN(ic, "Skipping !active chan " + "on band %s [%#x/%u/%#x]", + lkpi_nl80211_band_name(c->band), c->hw_value, + c->center_freq, c->flags); + return (false); + } + return (true); +} +#endif + +static void lkpi_ic_scan_start(struct ieee80211com *ic) { struct lkpi_hw *lhw; @@ -4315,35 +4534,52 @@ lkpi_ic_scan_start(struct ieee80211com *ic) bool is_hw_scan; lhw = ic->ic_softc; + ss = ic->ic_scan; + vap = ss->ss_vap; + TRACE_SCAN(ic, "scan_flags %b", lhw->scan_flags, LKPI_LHW_SCAN_BITS); + LKPI_80211_LHW_SCAN_LOCK(lhw); if ((lhw->scan_flags & LKPI_LHW_SCAN_RUNNING) != 0) { /* A scan is still running. */ LKPI_80211_LHW_SCAN_UNLOCK(lhw); + TRACE_SCAN(ic, "Trying to start new scan while still running; " + "cancelling new net80211 scan; scan_flags %b", + lhw->scan_flags, LKPI_LHW_SCAN_BITS); + ieee80211_cancel_scan(vap); return; } is_hw_scan = (lhw->scan_flags & LKPI_LHW_SCAN_HW) != 0; LKPI_80211_LHW_SCAN_UNLOCK(lhw); - ss = ic->ic_scan; - vap = ss->ss_vap; +#if 0 if (vap->iv_state != IEEE80211_S_SCAN) { - IMPROVE("We need to be able to scan if not in S_SCAN"); + TODO("We need to be able to scan if not in S_SCAN"); + TRACE_SCAN(ic, "scan_flags %b iv_state %d", + lhw->scan_flags, LKPI_LHW_SCAN_BITS, vap->iv_state); + ieee80211_cancel_scan(vap); return; } +#endif hw = LHW_TO_HW(lhw); if (!is_hw_scan) { /* If hw_scan is cleared clear FEXT_SCAN_OFFLOAD too. */ vap->iv_flags_ext &= ~IEEE80211_FEXT_SCAN_OFFLOAD; -sw_scan: + lvif = VAP_TO_LVIF(vap); vif = LVIF_TO_VIF(lvif); if (vap->iv_state == IEEE80211_S_SCAN) lkpi_hw_conf_idle(hw, false); + LKPI_80211_LHW_SCAN_LOCK(lhw); + lhw->scan_flags |= LKPI_LHW_SCAN_RUNNING; + LKPI_80211_LHW_SCAN_UNLOCK(lhw); + lkpi_update_mcast_filter(ic); + TRACE_SCAN(vap->iv_ic, "Starting SW_SCAN: scan_flags %b", + lhw->scan_flags, LKPI_LHW_SCAN_BITS); lkpi_80211_mo_sw_scan_start(hw, vif, vif->addr); /* net80211::scan_start() handled PS for us. */ IMPROVE(); @@ -4358,6 +4594,9 @@ sw_scan: struct cfg80211_scan_6ghz_params *s6gp; size_t chan_len, nchan, ssids_len, s6ghzlen; int band, i, ssid_count, common_ie_len; +#ifndef LKPI_80211_USE_SCANLIST + int n; +#endif uint32_t band_mask; uint8_t *ie, *ieend; bool running; @@ -4369,7 +4608,8 @@ sw_scan: band_mask = 0; nchan = 0; if (ieee80211_hw_check(hw, SINGLE_SCAN_ON_ALL_BANDS)) { -#if 0 /* Avoid net80211 scan lists until it has proper scan offload support. */ +#ifdef LKPI_80211_USE_SCANLIST + /* Avoid net80211 scan lists until it has proper scan offload support. */ for (i = ss->ss_next; i < ss->ss_last; i++) { nchan++; band = lkpi_net80211_chan_to_nl80211_band( @@ -4387,8 +4627,17 @@ sw_scan: continue; } if (hw->wiphy->bands[band] != NULL) { - nchan += hw->wiphy->bands[band]->n_channels; + struct linuxkpi_ieee80211_channel *channels; + int n; + band_mask |= (1 << band); + + channels = hw->wiphy->bands[band]->channels; + n = hw->wiphy->bands[band]->n_channels; + for (i = 0; i < n; i++) { + if (lkpi_scan_chan(&channels[i], ic, true)) + nchan++; + } } } #endif @@ -4427,11 +4676,32 @@ sw_scan: /* hw_req->req.wdev */ hw_req->req.wiphy = hw->wiphy; hw_req->req.no_cck = false; /* XXX */ -#if 0 - /* This seems to pessimise default scanning behaviour. */ - hw_req->req.duration_mandatory = TICKS_2_USEC(ss->ss_mindwell); - hw_req->req.duration = TICKS_2_USEC(ss->ss_maxdwell); -#endif + + /* + * In general setting duration[_mandatory] seems to pessimise + * default scanning behaviour. We only use it for BGSCANnig + * to keep the dwell times small. + * Setting duration_mandatory makes this the maximum dwell + * time (otherwise may be shorter). Duration is in TU. + */ + if ((ic->ic_flags_ext & IEEE80211_FEXT_BGSCAN) != 0) { + unsigned long dwell; + + if ((ic->ic_caps & IEEE80211_C_BGSCAN) == 0 || + (vap->iv_flags & IEEE80211_F_BGSCAN) == 0) + ic_printf(ic, "BGSCAN despite off: %b, %b, %b\n", + ic->ic_flags_ext, IEEE80211_FEXT_BITS, + vap->iv_flags, IEEE80211_F_BITS, + ic->ic_caps, IEEE80211_C_BITS); + + dwell = ss->ss_mindwell; + if (dwell == 0) + dwell = msecs_to_ticks(20); + + hw_req->req.duration_mandatory = true; + hw_req->req.duration = TICKS_2_USEC(dwell) / 1024; + } + #ifdef __notyet__ hw_req->req.flags |= NL80211_SCAN_FLAG_RANDOM_ADDR; memcpy(hw_req->req.mac_addr, xxx, IEEE80211_ADDR_LEN); @@ -4442,11 +4712,12 @@ sw_scan: hw_req->req.n_channels = nchan; cpp = (struct linuxkpi_ieee80211_channel **)(hw_req + 1); lc = (struct linuxkpi_ieee80211_channel *)(cpp + nchan); +#ifdef LKPI_80211_USE_SCANLIST for (i = 0; i < nchan; i++) { *(cpp + i) = (struct linuxkpi_ieee80211_channel *)(lc + i); } -#if 0 /* Avoid net80211 scan lists until it has proper scan offload support. */ + /* Avoid net80211 scan lists until it has proper scan offload support. */ for (i = 0; i < nchan; i++) { struct ieee80211_channel *c; @@ -4459,7 +4730,9 @@ sw_scan: lc++; } #else - for (band = 0; band < NUM_NL80211_BANDS; band++) { + /* Add bands in reverse order for scanning. */ + n = 0; + for (band = NUM_NL80211_BANDS - 1; band >= 0; band--) { struct ieee80211_supported_band *supband; struct linuxkpi_ieee80211_channel *channels; @@ -4474,11 +4747,30 @@ sw_scan: channels = supband->channels; for (i = 0; i < supband->n_channels; i++) { - *lc = channels[i]; - lc++; + if (lkpi_scan_chan(&channels[i], ic, false)) + *(cpp + n++) = &channels[i]; + } + } + if (lkpi_order_scanlist) + lkpi_scan_chan_list_resort(cpp, nchan); + + if ((linuxkpi_debug_80211 & D80211_SCAN) != 0) { + printf("%s:%d: %s SCAN Channel List (nchan=%zu): ", + __func__, __LINE__, ic->ic_name, nchan); + for (i = 0; i < nchan; i++) { + struct linuxkpi_ieee80211_channel *xc; + + xc = *(cpp + i); + printf(" %d(%d)", + ieee80211_mhz2ieee(xc->center_freq, + lkpi_nl80211_band_to_net80211_band( + xc->band)), + xc->center_freq); } + printf("\n"); } #endif + hw_req->req.n_ssids = ssid_count; if (hw_req->req.n_ssids > 0) { ssids = (struct cfg80211_ssid *)lc; @@ -4505,6 +4797,7 @@ sw_scan: ieend = lkpi_scan_ies_add(ie, &hw_req->ies, band_mask, vap, hw); hw_req->req.ie = ie; hw_req->req.ie_len = ieend - ie; + hw_req->req.scan_start = jiffies; lvif = VAP_TO_LVIF(vap); vif = LVIF_TO_VIF(lvif); @@ -4522,13 +4815,30 @@ sw_scan: LKPI_80211_LHW_SCAN_UNLOCK(lhw); if (running) { free(hw_req, M_LKPI80211); + TRACE_SCAN(ic, "Trying to start new scan while still " + "running (2); cancelling new net80211 scan; " + "scan_flags %b", + lhw->scan_flags, LKPI_LHW_SCAN_BITS); + ieee80211_cancel_scan(vap); return; } lkpi_update_mcast_filter(ic); + TRACE_SCAN(ic, "Starting HW_SCAN: scan_flags %b, " + "ie_len %d, n_ssids %d, n_chan %d, common_ie_len %d [%d, %d]", + lhw->scan_flags, LKPI_LHW_SCAN_BITS, hw_req->req.ie_len, + hw_req->req.n_ssids, hw_req->req.n_channels, + hw_req->ies.common_ie_len, + hw_req->ies.len[NL80211_BAND_2GHZ], + hw_req->ies.len[NL80211_BAND_5GHZ]); error = lkpi_80211_mo_hw_scan(hw, vif, hw_req); if (error != 0) { + bool scan_done; + int e; + + TRACE_SCAN(ic, "hw_scan failed; scan_flags %b, error %d", + lhw->scan_flags, LKPI_LHW_SCAN_BITS, error); ieee80211_cancel_scan(vap); /* @@ -4545,14 +4855,35 @@ sw_scan: * So we cannot rely on that behaviour and have to check * and balance between both code paths. */ + e = 0; + scan_done = true; LKPI_80211_LHW_SCAN_LOCK(lhw); if ((lhw->scan_flags & LKPI_LHW_SCAN_RUNNING) != 0) { + free(lhw->hw_req, M_LKPI80211); lhw->hw_req = NULL; + /* + * The ieee80211_cancel_scan() above runs in a + * taskq and it may take ages for the previous + * scan to clear; starting a new one right away + * we run into the problem that the old one is + * still active. + */ + e = msleep(lhw, &lhw->scan_mtx, 0, "lhwscanstop", hz); + scan_done = (lhw->scan_flags & LKPI_LHW_SCAN_RUNNING) != 0; + + /* + * Now we can clear running if no one else did. + */ lhw->scan_flags &= ~LKPI_LHW_SCAN_RUNNING; } LKPI_80211_LHW_SCAN_UNLOCK(lhw); lkpi_update_mcast_filter(ic); + if (!scan_done) { + ic_printf(ic, "ERROR: %s: timeout/error to wait " + "for ieee80211_cancel_scan: %d\n", __func__, e); + return; + } /* * XXX-SIGH magic number. @@ -4560,24 +4891,15 @@ sw_scan: * not possible. Fall back to sw scan in that case. */ if (error == 1) { - LKPI_80211_LHW_SCAN_LOCK(lhw); - lhw->scan_flags &= ~LKPI_LHW_SCAN_HW; - LKPI_80211_LHW_SCAN_UNLOCK(lhw); /* - * XXX If we clear this now and later a driver - * thinks it * can do a hw_scan again, we will - * currently not re-enable it? + * We need to put this into some defered context + * the net80211 scan may not be done yet + * (ic_flags & IEEE80211_F_SCAN) and we cannot + * wait here; if we do scan_curchan_task always + * runs after our timeout to finalize the scan. */ - vap->iv_flags_ext &= ~IEEE80211_FEXT_SCAN_OFFLOAD; - ieee80211_start_scan(vap, - IEEE80211_SCAN_ACTIVE | - IEEE80211_SCAN_NOPICK | - IEEE80211_SCAN_ONCE, - IEEE80211_SCAN_FOREVER, - ss->ss_mindwell ? ss->ss_mindwell : msecs_to_ticks(20), - ss->ss_maxdwell ? ss->ss_maxdwell : msecs_to_ticks(200), - vap->iv_des_nssid, vap->iv_des_ssid); - goto sw_scan; + ieee80211_runtask(ic, &lvif->sw_scan_task); + return; } ic_printf(ic, "ERROR: %s: hw_scan returned %d\n", @@ -4587,12 +4909,50 @@ sw_scan: } static void +lkpi_sw_scan_task(void *arg, int pending __unused) +{ + struct lkpi_hw *lhw; + struct lkpi_vif *lvif; + struct ieee80211vap *vap; + struct ieee80211_scan_state *ss; + + lvif = arg; + vap = LVIF_TO_VAP(lvif); + lhw = vap->iv_ic->ic_softc; + ss = vap->iv_ic->ic_scan; + + LKPI_80211_LHW_SCAN_LOCK(lhw); + /* + * We will re-enable this at scan_end calling lkpi_enable_hw_scan(). + * IEEE80211_FEXT_SCAN_OFFLOAD will be cleared by lkpi_ic_scan_start. + */ + lhw->scan_flags &= ~LKPI_LHW_SCAN_HW; + LKPI_80211_LHW_SCAN_UNLOCK(lhw); + + TRACE_SCAN(vap->iv_ic, "Triggering SW_SCAN: pending %d, scan_flags %b", + pending, lhw->scan_flags, LKPI_LHW_SCAN_BITS); + + /* + * This will call ic_scan_start() and we will get into the right path + * unless other scans started in between. + */ + ieee80211_start_scan(vap, + IEEE80211_SCAN_ONCE, + msecs_to_ticks(10000), /* 10000 ms (=~ 50 chan * 200 ms) */ + ss->ss_mindwell ? ss->ss_mindwell : msecs_to_ticks(20), + ss->ss_maxdwell ? ss->ss_maxdwell : msecs_to_ticks(200), + vap->iv_des_nssid, vap->iv_des_ssid); +} + +static void lkpi_ic_scan_end(struct ieee80211com *ic) { struct lkpi_hw *lhw; bool is_hw_scan; lhw = ic->ic_softc; + TRACE_SCAN(ic, "scan_flags %b", lhw->scan_flags, LKPI_LHW_SCAN_BITS); + LKPI_80211_LHW_SCAN_LOCK(lhw); if ((lhw->scan_flags & LKPI_LHW_SCAN_RUNNING) == 0) { LKPI_80211_LHW_SCAN_UNLOCK(lhw); @@ -4621,6 +4981,16 @@ lkpi_ic_scan_end(struct ieee80211com *ic) if (vap->iv_state == IEEE80211_S_SCAN) lkpi_hw_conf_idle(hw, true); } + + /* + * In case we disabled the hw_scan in lkpi_ic_scan_start() and + * switched to swscan, re-enable hw_scan if available. + */ + lkpi_enable_hw_scan(lhw); + + LKPI_80211_LHW_SCAN_LOCK(lhw); + wakeup(lhw); + LKPI_80211_LHW_SCAN_UNLOCK(lhw); } static void @@ -4631,6 +5001,10 @@ lkpi_ic_scan_curchan(struct ieee80211_scan_state *ss, bool is_hw_scan; lhw = ss->ss_ic->ic_softc; + TRACE_SCAN(ss->ss_ic, "scan_flags %b chan %d maxdwell %lu", + lhw->scan_flags, LKPI_LHW_SCAN_BITS, + ss->ss_ic->ic_curchan->ic_ieee, maxdwell); + LKPI_80211_LHW_SCAN_LOCK(lhw); is_hw_scan = (lhw->scan_flags & LKPI_LHW_SCAN_HW) != 0; LKPI_80211_LHW_SCAN_UNLOCK(lhw); @@ -4645,6 +5019,10 @@ lkpi_ic_scan_mindwell(struct ieee80211_scan_state *ss) bool is_hw_scan; lhw = ss->ss_ic->ic_softc; + TRACE_SCAN(ss->ss_ic, "scan_flags %b chan %d mindwell %lu", + lhw->scan_flags, LKPI_LHW_SCAN_BITS, + ss->ss_ic->ic_curchan->ic_ieee, ss->ss_mindwell); + LKPI_80211_LHW_SCAN_LOCK(lhw); is_hw_scan = (lhw->scan_flags & LKPI_LHW_SCAN_HW) != 0; LKPI_80211_LHW_SCAN_UNLOCK(lhw); @@ -6042,6 +6420,7 @@ linuxkpi_ieee80211_alloc_hw(size_t priv_len, const struct ieee80211_ops *ops) LKPI_80211_LHW_SCAN_LOCK_INIT(lhw); LKPI_80211_LHW_TXQ_LOCK_INIT(lhw); + spin_lock_init(&lhw->txq_lock); sx_init_flags(&lhw->lvif_sx, "lhw-lvif", SX_RECURSE | SX_DUPOK); LKPI_80211_LHW_MC_LOCK_INIT(lhw); TAILQ_INIT(&lhw->lvif_head); @@ -6147,6 +6526,7 @@ linuxkpi_ieee80211_iffree(struct ieee80211_hw *hw) LKPI_80211_LHW_MC_UNLOCK(lhw); /* Cleanup more of lhw here or in wiphy_free()? */ + spin_lock_destroy(&lhw->txq_lock); LKPI_80211_LHW_TXQ_LOCK_DESTROY(lhw); LKPI_80211_LHW_SCAN_LOCK_DESTROY(lhw); sx_destroy(&lhw->lvif_sx); @@ -6255,26 +6635,26 @@ linuxkpi_ieee80211_ifattach(struct ieee80211_hw *hw) IEEE80211_C_SHSLOT | /* short slot time supported */ IEEE80211_C_SHPREAMBLE /* short preamble supported */ ; -#if 0 - /* Scanning is a different kind of beast to re-work. */ - ic->ic_caps |= IEEE80211_C_BGSCAN; + +#ifdef LKPI_80211_BGSCAN + if (lhw->ops->hw_scan) + ic->ic_caps |= IEEE80211_C_BGSCAN; #endif - if (lhw->ops->hw_scan) { - /* - * Advertise full-offload scanning. - * - * Not limiting to SINGLE_SCAN_ON_ALL_BANDS here as otherwise - * we essentially disable hw_scan for all drivers not setting - * the flag. - */ - ic->ic_flags_ext |= IEEE80211_FEXT_SCAN_OFFLOAD; - lhw->scan_flags |= LKPI_LHW_SCAN_HW; - } + + lkpi_enable_hw_scan(lhw); /* Does HW support Fragmentation offload? */ if (ieee80211_hw_check(hw, SUPPORTS_TX_FRAG)) ic->ic_flags_ext |= IEEE80211_FEXT_FRAG_OFFLOAD; + /* Does HW support full AMPDU[-TX] offload? */ + if (ieee80211_hw_check(hw, AMPDU_AGGREGATION)) + ic->ic_flags_ext |= IEEE80211_FEXT_AMPDU_OFFLOAD; +#ifdef __notyet__ + if (ieee80211_hw_check(hw, TX_AMSDU)) + if (ieee80211_hw_check(hw, SUPPORTS_AMSDU_IN_AMPDU)) +#endif + /* * The wiphy variables report bitmasks of avail antennas. * (*get_antenna) get the current bitmask sets which can be @@ -6726,13 +7106,19 @@ linuxkpi_ieee80211_scan_completed(struct ieee80211_hw *hw, ic = lhw->ic; ss = ic->ic_scan; + TRACE_SCAN(ic, "scan_flags %b info { %ju, %6D, aborted %d }", + lhw->scan_flags, LKPI_LHW_SCAN_BITS, + (uintmax_t)info->scan_start_tsf, info->tsf_bssid, ":", + info->aborted); + ieee80211_scan_done(ss->ss_vap); LKPI_80211_LHW_SCAN_LOCK(lhw); free(lhw->hw_req, M_LKPI80211); lhw->hw_req = NULL; lhw->scan_flags &= ~LKPI_LHW_SCAN_RUNNING; - wakeup(lhw); + /* The wakeup(lhw) will be called from lkpi_ic_scan_end(). */ + /* wakeup(lhw); */ LKPI_80211_LHW_SCAN_UNLOCK(lhw); return; @@ -7002,6 +7388,63 @@ lkpi_convert_rx_status(struct ieee80211_hw *hw, struct lkpi_sta *lsta, } } +#ifdef LINUXKPI_DEBUG_80211 +static void +lkpi_rx_log_beacon(struct mbuf *m, struct lkpi_hw *lhw, + struct ieee80211_rx_status *rx_status) +{ + struct ieee80211_mgmt *f; + uint8_t *e; + char ssid[IEEE80211_NWID_LEN * 4 + 1]; + + memset(ssid, '\0', sizeof(ssid)); + + f = mtod(m, struct ieee80211_mgmt *); + e = f->u.beacon.variable; + /* + * Usually SSID is right after the fixed part and for debugging we will + * be fine should we miss it if it is not. + */ + while ((e - (uint8_t *)f) < m->m_len) { + if (*e == IEEE80211_ELEMID_SSID) + break; + e += (2 + *(e + 1)); + } + if (*e == IEEE80211_ELEMID_SSID) { + int i, len; + char *p; + + p = ssid; + len = m->m_len - ((e + 2) - (uint8_t *)f); + if (len > *(e + 1)) + len = *(e + 1); + e += 2; + for (i = 0; i < len; i++) { + /* Printable character? */ + if (*e >= 0x20 && *e < 0x7f) { + *p++ = *e++; + } else { + snprintf(p, 5, "%#04x", *e++); + p += 4; + } + } + *p = '\0'; + } + + /* We print skb, skb->data, m as we are seeing 'ghost beacons'. */ + TRACE_SCAN_BEACON(lhw->ic, "Beacon: scan_flags %b, band %s freq %u chan %-4d " + "len %d { %#06x %#06x %6D %6D %6D %#06x %ju %u %#06x SSID '%s' }", + lhw->scan_flags, LKPI_LHW_SCAN_BITS, + lkpi_nl80211_band_name(rx_status->band), rx_status->freq, + linuxkpi_ieee80211_frequency_to_channel(rx_status->freq, 0), + m->m_pkthdr.len, f->frame_control, f->duration_id, + f->da, ":", f->sa, ":", f->bssid, ":", f->seq_ctrl, + (uintmax_t)le64_to_cpu(f->u.beacon.timestamp), + le16_to_cpu(f->u.beacon.beacon_int), + le16_to_cpu(f->u.beacon.capab_info), ssid); +} +#endif + /* For %list see comment towards the end of the function. */ void linuxkpi_ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, @@ -7058,7 +7501,15 @@ linuxkpi_ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, is_beacon = ieee80211_is_beacon(hdr->frame_control); #ifdef LINUXKPI_DEBUG_80211 - if (is_beacon && (linuxkpi_debug_80211 & D80211_TRACE_RX_BEACONS) == 0) + /* + * We use the mbuf here as otherwise the variable part might + * be in skb frags. + */ + if (is_beacon && ((linuxkpi_debug_80211 & D80211_SCAN_BEACON) != 0)) + lkpi_rx_log_beacon(m, lhw, rx_status); + + if (is_beacon && (linuxkpi_debug_80211 & D80211_TRACE_RX_BEACONS) == 0 && + (linuxkpi_debug_80211 & D80211_SCAN_BEACON) == 0) goto no_trace_beacons; if (linuxkpi_debug_80211 & D80211_TRACE_RX) @@ -7073,7 +7524,8 @@ linuxkpi_ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, hexdump(mtod(m, const void *), m->m_len, "RX (raw) ", 0); /* Implement a dump_rxcb() !!! */ - if (linuxkpi_debug_80211 & D80211_TRACE_RX) + if ((linuxkpi_debug_80211 & D80211_TRACE_RX) != 0 || + (linuxkpi_debug_80211 & D80211_SCAN_BEACON) != 0) printf("TRACE-RX: %s: RXCB: %ju %ju %u, %b, %u, %#0x, %#0x, " "%u band %u, %u { %d %d %d %d }, %d, %#x %#x %#x %#x %u %u %u\n", __func__, @@ -7380,7 +7832,7 @@ lkpi_wiphy_delayed_work_timer(struct timer_list *tl) { struct wiphy_delayed_work *wdwk; - wdwk = from_timer(wdwk, tl, timer); + wdwk = timer_container_of(wdwk, tl, timer); wiphy_work_queue(wdwk->wiphy, &wdwk->work); } @@ -8124,21 +8576,30 @@ lkpi_ieee80211_wake_queues_locked(struct ieee80211_hw *hw) void linuxkpi_ieee80211_wake_queues(struct ieee80211_hw *hw) { - wiphy_lock(hw->wiphy); + struct lkpi_hw *lhw; + unsigned long flags; + + lhw = HW_TO_LHW(hw); + + spin_lock_irqsave(&lhw->txq_lock, flags); lkpi_ieee80211_wake_queues_locked(hw); - wiphy_unlock(hw->wiphy); + spin_unlock_irqrestore(&lhw->txq_lock, flags); } void linuxkpi_ieee80211_wake_queue(struct ieee80211_hw *hw, int qnum) { + struct lkpi_hw *lhw; + unsigned long flags; KASSERT(qnum < hw->queues, ("%s: qnum %d >= hw->queues %d, hw %p\n", __func__, qnum, hw->queues, hw)); - wiphy_lock(hw->wiphy); + lhw = HW_TO_LHW(hw); + + spin_lock_irqsave(&lhw->txq_lock, flags); lkpi_ieee80211_wake_queues(hw, qnum); - wiphy_unlock(hw->wiphy); + spin_unlock_irqrestore(&lhw->txq_lock, flags); } /* This is just hardware queues. */ diff --git a/sys/compat/linuxkpi/common/src/linux_80211.h b/sys/compat/linuxkpi/common/src/linux_80211.h index eaf6d804af4c..0dfcd7646c34 100644 --- a/sys/compat/linuxkpi/common/src/linux_80211.h +++ b/sys/compat/linuxkpi/common/src/linux_80211.h @@ -59,6 +59,8 @@ #define D80211_IMPROVE_TXQ 0x00000004 #define D80211_TRACE 0x00000010 #define D80211_TRACEOK 0x00000020 +#define D80211_SCAN 0x00000040 +#define D80211_SCAN_BEACON 0x00000080 #define D80211_TRACE_TX 0x00000100 #define D80211_TRACE_TX_DUMP 0x00000200 #define D80211_TRACE_RX 0x00001000 @@ -75,6 +77,20 @@ #define D80211_TRACE_MODE_HE 0x04000000 #define D80211_TRACE_MODE_EHT 0x08000000 +#ifdef LINUXKPI_DEBUG_80211 +#define TRACE_SCAN(ic, fmt, ...) \ + if (linuxkpi_debug_80211 & D80211_SCAN) \ + printf("%s:%d: %s SCAN " fmt "\n", \ + __func__, __LINE__, ic->ic_name, ##__VA_ARGS__) +#define TRACE_SCAN_BEACON(ic, fmt, ...) \ + if (linuxkpi_debug_80211 & D80211_SCAN_BEACON) \ + printf("%s:%d: %s SCAN " fmt "\n", \ + __func__, __LINE__, ic->ic_name, ##__VA_ARGS__) +#else +#define TRACE_SCAN(...) do {} while (0) +#define TRACE_SCAN_BEACON(...) do {} while (0) +#endif + #define IMPROVE_TXQ(...) \ if (linuxkpi_debug_80211 & D80211_IMPROVE_TXQ) \ printf("%s:%d: XXX LKPI80211 IMPROVE_TXQ\n", __func__, __LINE__) @@ -191,6 +207,7 @@ struct lkpi_vif { struct mbuf *, int, const struct ieee80211_rx_stats *, int, int); + struct task sw_scan_task; struct list_head lsta_list; @@ -236,6 +253,7 @@ struct lkpi_hw { /* name it mac80211_sc? */ struct mtx txq_mtx; uint32_t txq_generation[IEEE80211_NUM_ACS]; TAILQ_HEAD(, lkpi_txq) scheduled_txqs[IEEE80211_NUM_ACS]; + spinlock_t txq_lock; /* Deferred RX path. */ struct task rxq_task; @@ -298,6 +316,9 @@ struct lkpi_hw { /* name it mac80211_sc? */ #define LHW_TO_HW(_lhw) (&(_lhw)->hw) #define HW_TO_LHW(_hw) container_of(_hw, struct lkpi_hw, hw) +#define LKPI_LHW_SCAN_BITS \ + "\010\1RUNING\2HW" + struct lkpi_chanctx { struct list_head entry; diff --git a/sys/compat/linuxkpi/common/src/linux_compat.c b/sys/compat/linuxkpi/common/src/linux_compat.c index dcdec0dfcc78..458744a9fec6 100644 --- a/sys/compat/linuxkpi/common/src/linux_compat.c +++ b/sys/compat/linuxkpi/common/src/linux_compat.c @@ -2120,7 +2120,7 @@ add_timer_on(struct timer_list *timer, int cpu) } int -del_timer(struct timer_list *timer) +timer_delete(struct timer_list *timer) { if (callout_stop(&(timer)->callout) == -1) @@ -2129,7 +2129,7 @@ del_timer(struct timer_list *timer) } int -del_timer_sync(struct timer_list *timer) +timer_delete_sync(struct timer_list *timer) { if (callout_drain(&(timer)->callout) == -1) @@ -2138,13 +2138,6 @@ del_timer_sync(struct timer_list *timer) } int -timer_delete_sync(struct timer_list *timer) -{ - - return (del_timer_sync(timer)); -} - -int timer_shutdown_sync(struct timer_list *timer) { diff --git a/sys/compat/linuxkpi/common/src/linux_devres.c b/sys/compat/linuxkpi/common/src/linux_devres.c index 84f03ba0dd7d..23c91cb5ab2f 100644 --- a/sys/compat/linuxkpi/common/src/linux_devres.c +++ b/sys/compat/linuxkpi/common/src/linux_devres.c @@ -1,7 +1,7 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * - * Copyright (c) 2020-2021 The FreeBSD Foundation + * Copyright (c) 2020-2025 The FreeBSD Foundation * * This software was developed by Bj\xc3\xb6rn Zeeb under sponsorship from * the FreeBSD Foundation. @@ -223,6 +223,30 @@ lkpi_devm_kmalloc_release(struct device *dev __unused, void *p __unused) /* Nothing to do. Freed with the devres. */ } +static int +lkpi_devm_kmalloc_match(struct device *dev __unused, void *p, void *mp) +{ + return (p == mp); +} + +void +lkpi_devm_kfree(struct device *dev, const void *p) +{ + void *mp; + int error; + + if (p == NULL) + return; + + /* I assume Linux simply casts the const away... */ + mp = __DECONST(void *, p); + error = lkpi_devres_destroy(dev, lkpi_devm_kmalloc_release, + lkpi_devm_kmalloc_match, mp); + if (error != 0) + dev_warn(dev, "%s: lkpi_devres_destroy failed with %d\n", + __func__, error); +} + struct devres_action { void *data; void (*action)(void *); diff --git a/sys/compat/linuxkpi/common/src/linux_pci.c b/sys/compat/linuxkpi/common/src/linux_pci.c index d5bbbea1eb2c..8507a59a8df3 100644 --- a/sys/compat/linuxkpi/common/src/linux_pci.c +++ b/sys/compat/linuxkpi/common/src/linux_pci.c @@ -67,6 +67,7 @@ #include <linux/mm.h> #include <linux/io.h> #include <linux/vmalloc.h> +#define WANT_NATIVE_PCI_GET_SLOT #include <linux/pci.h> #include <linux/compat.h> @@ -111,6 +112,9 @@ static device_method_t pci_methods[] = { DEVMETHOD(pci_iov_uninit, linux_pci_iov_uninit), DEVMETHOD(pci_iov_add_vf, linux_pci_iov_add_vf), + /* Bus interface. */ + DEVMETHOD(bus_add_child, bus_generic_add_child), + /* backlight interface */ DEVMETHOD(backlight_update_status, linux_backlight_update_status), DEVMETHOD(backlight_get_status, linux_backlight_get_status), @@ -145,6 +149,23 @@ struct linux_dma_priv { #define DMA_PRIV_LOCK(priv) mtx_lock(&(priv)->lock) #define DMA_PRIV_UNLOCK(priv) mtx_unlock(&(priv)->lock) +static void +lkpi_set_pcim_iomap_devres(struct pcim_iomap_devres *dr, int bar, + void *res) +{ + dr->mmio_table[bar] = (void *)rman_get_bushandle(res); + dr->res_table[bar] = res; +} + +static bool +lkpi_pci_bar_id_valid(int bar) +{ + if (bar < 0 || bar > PCIR_MAX_BAR_0) + return (false); + + return (true); +} + static int linux_pdev_dma_uninit(struct pci_dev *pdev) { @@ -289,12 +310,18 @@ lkpi_pci_get_device(uint32_t vendor, uint32_t device, struct pci_dev *odev) { struct pci_dev *pdev, *found; - KASSERT(odev == NULL, ("%s: odev argument not yet supported\n", __func__)); - found = NULL; spin_lock(&pci_lock); list_for_each_entry(pdev, &pci_devices, links) { - if (pdev->vendor == vendor && pdev->device == device) { + /* Walk until we find odev. */ + if (odev != NULL) { + if (pdev == odev) + odev = NULL; + continue; + } + + if ((pdev->vendor == vendor || vendor == PCI_ANY_ID) && + (pdev->device == device || device == PCI_ANY_ID)) { found = pdev; break; } @@ -316,6 +343,7 @@ lkpi_pci_dev_release(struct device *dev) static int lkpifill_pci_dev(device_t dev, struct pci_dev *pdev) { + struct pci_devinfo *dinfo; int error; error = kobject_init_and_add(&pdev->dev.kobj, &linux_dev_ktype, @@ -336,15 +364,24 @@ lkpifill_pci_dev(device_t dev, struct pci_dev *pdev) pdev->path_name = kasprintf(GFP_KERNEL, "%04d:%02d:%02d.%d", pci_get_domain(dev), pci_get_bus(dev), pci_get_slot(dev), pci_get_function(dev)); + pdev->bus = malloc(sizeof(*pdev->bus), M_DEVBUF, M_WAITOK | M_ZERO); - /* - * This should be the upstream bridge; pci_upstream_bridge() - * handles that case on demand as otherwise we'll shadow the - * entire PCI hierarchy. - */ - pdev->bus->self = pdev; pdev->bus->number = pci_get_bus(dev); pdev->bus->domain = pci_get_domain(dev); + + /* Check if we have reached the root to satisfy pci_is_root_bus() */ + dinfo = device_get_ivars(dev); + if (dinfo->cfg.pcie.pcie_location != 0 && + dinfo->cfg.pcie.pcie_type == PCIEM_TYPE_ROOT_PORT) { + pdev->bus->self = NULL; + } else { + /* + * This should be the upstream bridge; pci_upstream_bridge() + * handles that case on demand as otherwise we'll shadow the + * entire PCI hierarchy. + */ + pdev->bus->self = pdev; + } pdev->dev.bsddev = dev; pdev->dev.parent = &linux_root_device; pdev->dev.release = lkpi_pci_dev_release; @@ -369,7 +406,7 @@ lkpinew_pci_dev_release(struct device *dev) pdev = to_pci_dev(dev); if (pdev->root != NULL) pci_dev_put(pdev->root); - if (pdev->bus->self != pdev) + if (pdev->bus->self != pdev && pdev->bus->self != NULL) pci_dev_put(pdev->bus->self); free(pdev->bus, M_DEVBUF); if (pdev->msi_desc != NULL) { @@ -449,6 +486,20 @@ lkpi_pci_get_domain_bus_and_slot(int domain, unsigned int bus, return (pdev); } +struct pci_dev * +lkpi_pci_get_slot(struct pci_bus *pbus, unsigned int devfn) +{ + device_t dev; + struct pci_dev *pdev; + + dev = pci_find_bsf(pbus->number, PCI_SLOT(devfn), PCI_FUNC(devfn)); + if (dev == NULL) + return (NULL); + + pdev = lkpinew_pci_dev(dev); + return (pdev); +} + static int linux_pci_probe(device_t dev) { @@ -525,6 +576,7 @@ linux_pci_attach_device(device_t dev, struct pci_driver *pdrv, { struct resource_list_entry *rle; device_t parent; + struct pci_dev *pbus, *ppbus; uintptr_t rid; int error; bool isdrm; @@ -568,6 +620,27 @@ linux_pci_attach_device(device_t dev, struct pci_driver *pdrv, list_add(&pdev->links, &pci_devices); spin_unlock(&pci_lock); + /* + * Create the hierarchy now as we cannot on demand later. + * Take special care of DRM as there is a non-PCI device in the chain. + */ + pbus = pdev; + if (isdrm) { + pbus = lkpinew_pci_dev(parent); + if (pbus == NULL) { + error = ENXIO; + goto out_dma_init; + } + } + pcie_find_root_port(pbus); + if (isdrm) + pdev->root = pbus->root; + ppbus = pci_upstream_bridge(pbus); + while (ppbus != NULL && ppbus != pbus) { + pbus = ppbus; + ppbus = pci_upstream_bridge(pbus); + } + if (pdrv != NULL) { error = pdrv->probe(pdev, id); if (error) @@ -575,6 +648,7 @@ linux_pci_attach_device(device_t dev, struct pci_driver *pdrv, } return (0); +/* XXX the cleanup does not match the allocation up there. */ out_probe: free(pdev->bus, M_DEVBUF); spin_lock_destroy(&pdev->pcie_cap_lock); @@ -757,6 +831,9 @@ _lkpi_pci_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen __unused) struct pci_mmio_region *mmio, *p; int type; + if (!lkpi_pci_bar_id_valid(bar)) + return (NULL); + type = pci_resource_type(pdev, bar); if (type < 0) { device_printf(pdev->dev.bsddev, "%s: bar %d type %d\n", @@ -797,6 +874,9 @@ linuxkpi_pci_iomap_range(struct pci_dev *pdev, int bar, { struct resource *res; + if (!lkpi_pci_bar_id_valid(bar)) + return (NULL); + res = _lkpi_pci_iomap(pdev, bar, maxlen); if (res == NULL) return (NULL); @@ -810,9 +890,41 @@ linuxkpi_pci_iomap_range(struct pci_dev *pdev, int bar, void * linuxkpi_pci_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen) { + if (!lkpi_pci_bar_id_valid(bar)) + return (NULL); + return (linuxkpi_pci_iomap_range(pdev, bar, 0, maxlen)); } +void * +linuxkpi_pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen) +{ + struct pcim_iomap_devres *dr; + void *res; + + if (!lkpi_pci_bar_id_valid(bar)) + return (NULL); + + dr = lkpi_pcim_iomap_devres_find(pdev); + if (dr == NULL) + return (NULL); + + if (dr->res_table[bar] != NULL) + return (dr->res_table[bar]); + + res = linuxkpi_pci_iomap(pdev, bar, maxlen); + if (res == NULL) { + /* + * Do not free the devres in case there were + * other valid mappings before already. + */ + return (NULL); + } + lkpi_set_pcim_iomap_devres(dr, bar, res); + + return (res); +} + void linuxkpi_pci_iounmap(struct pci_dev *pdev, void *res) { @@ -864,8 +976,7 @@ linuxkpi_pcim_iomap_regions(struct pci_dev *pdev, uint32_t mask, const char *nam res = _lkpi_pci_iomap(pdev, bar, 0); if (res == NULL) goto err; - dr->mmio_table[bar] = (void *)rman_get_bushandle(res); - dr->res_table[bar] = res; + lkpi_set_pcim_iomap_devres(dr, bar, res); mappings |= (1 << bar); } @@ -1099,8 +1210,9 @@ pci_resource_len(struct pci_dev *pdev, int bar) return (rle->count); } -int -pci_request_region(struct pci_dev *pdev, int bar, const char *res_name) +static int +lkpi_pci_request_region(struct pci_dev *pdev, int bar, const char *res_name, + bool managed) { struct resource *res; struct pci_devres *dr; @@ -1108,9 +1220,20 @@ pci_request_region(struct pci_dev *pdev, int bar, const char *res_name) int rid; int type; + if (!lkpi_pci_bar_id_valid(bar)) + return (-EINVAL); + + /* + * If the bar is not valid, return success without adding the BAR; + * otherwise linuxkpi_pcim_request_all_regions() will error. + */ + if (pci_resource_len(pdev, bar) == 0) + return (0); + /* Likewise if it is neither IO nor MEM, nothing to do for us. */ type = pci_resource_type(pdev, bar); if (type < 0) - return (-ENODEV); + return (0); + rid = PCIR_BAR(bar); res = bus_alloc_resource_any(pdev->dev.bsddev, type, &rid, RF_ACTIVE|RF_SHAREABLE); @@ -1123,11 +1246,16 @@ pci_request_region(struct pci_dev *pdev, int bar, const char *res_name) /* * It seems there is an implicit devres tracking on these if the device - * is managed; otherwise the resources are not automatiaclly freed on - * FreeBSD/LinuxKPI tough they should be/are expected to be by Linux - * drivers. + * is managed (lkpi_pci_devres_find() case); otherwise the resources are + * not automatically freed on FreeBSD/LinuxKPI though they should be/are + * expected to be by Linux drivers. + * Otherwise if we are called from a pcim-function with the managed + * argument set, we need to track devres independent of pdev->managed. */ - dr = lkpi_pci_devres_find(pdev); + if (managed) + dr = lkpi_pci_devres_get_alloc(pdev); + else + dr = lkpi_pci_devres_find(pdev); if (dr != NULL) { dr->region_mask |= (1 << bar); dr->region_table[bar] = res; @@ -1144,6 +1272,12 @@ pci_request_region(struct pci_dev *pdev, int bar, const char *res_name) } int +linuxkpi_pci_request_region(struct pci_dev *pdev, int bar, const char *res_name) +{ + return (lkpi_pci_request_region(pdev, bar, res_name, false)); +} + +int linuxkpi_pci_request_regions(struct pci_dev *pdev, const char *res_name) { int error; @@ -1159,6 +1293,24 @@ linuxkpi_pci_request_regions(struct pci_dev *pdev, const char *res_name) return (0); } +int +linuxkpi_pcim_request_all_regions(struct pci_dev *pdev, const char *res_name) +{ + int bar, error; + + for (bar = 0; bar <= PCIR_MAX_BAR_0; bar++) { + error = lkpi_pci_request_region(pdev, bar, res_name, true); + if (error != 0) { + device_printf(pdev->dev.bsddev, "%s: bar %d res_name '%s': " + "lkpi_pci_request_region returned %d\n", __func__, + bar, res_name, error); + pci_release_regions(pdev); + return (error); + } + } + return (0); +} + void linuxkpi_pci_release_region(struct pci_dev *pdev, int bar) { diff --git a/sys/compat/linuxkpi/dummy/include/kunit/skbuff.h b/sys/compat/linuxkpi/dummy/include/kunit/skbuff.h new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/sys/compat/linuxkpi/dummy/include/kunit/skbuff.h diff --git a/sys/compat/linuxkpi/dummy/include/kunit/test-bug.h b/sys/compat/linuxkpi/dummy/include/kunit/test-bug.h new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/sys/compat/linuxkpi/dummy/include/kunit/test-bug.h diff --git a/sys/compat/linuxkpi/dummy/include/kunit/test.h b/sys/compat/linuxkpi/dummy/include/kunit/test.h new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/sys/compat/linuxkpi/dummy/include/kunit/test.h |