start: initial minimal implementation
3 tabs: bitcoin, lightning and settings. only settings is populated, with wifi info and shutdown. see build.zig for how everything ties up together.add-custom-font
parent
68dd23525e
commit
bfc71fec92
@ -0,0 +1,5 @@
|
||||
build for rpi:
|
||||
|
||||
zig build -Dtarget=aarch64-linux-musl -Ddriver=fbev -Drelease-safe -Dstrip
|
||||
|
||||
otherwise just `zig build` on dev host
|
@ -1,34 +1,283 @@
|
||||
const std = @import("std");
|
||||
const nifbuild = @import("lib/nif/build.zig");
|
||||
|
||||
pub fn build(b: *std.build.Builder) void {
|
||||
// Standard target options allows the person running `zig build` to choose
|
||||
// what target to build for. Here we do not override the defaults, which
|
||||
// means any target is allowed, and the default is native. Other options
|
||||
// for restricting supported target set are available.
|
||||
const target = b.standardTargetOptions(.{});
|
||||
b.use_stage1 = true;
|
||||
|
||||
// Standard release options allow the person running `zig build` to select
|
||||
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall.
|
||||
const target = b.standardTargetOptions(.{});
|
||||
const mode = b.standardReleaseOptions();
|
||||
const strip = b.option(bool, "strip", "strip output binary; default: false") orelse false;
|
||||
const drv = b.option(DriverTarget, "driver", "display and input drivers combo; default: sdl2") orelse .sdl2;
|
||||
const disp_horiz = b.option(u32, "horiz", "display horizontal pixels count; default: 800") orelse 800;
|
||||
const disp_vert = b.option(u32, "vert", "display vertical pixels count; default: 480") orelse 480;
|
||||
|
||||
// gui build
|
||||
const ngui = b.addExecutable("ngui", "src/ngui.zig");
|
||||
ngui.setTarget(target);
|
||||
ngui.setBuildMode(mode);
|
||||
ngui.pie = true;
|
||||
ngui.strip = strip;
|
||||
|
||||
ngui.addIncludePath("lib");
|
||||
ngui.addIncludePath("src/ui/c");
|
||||
ngui.linkLibC();
|
||||
|
||||
const exe = b.addExecutable("ngui", "src/main.zig");
|
||||
exe.setTarget(target);
|
||||
exe.setBuildMode(mode);
|
||||
exe.install();
|
||||
const lvgl_flags = &.{
|
||||
"-std=c11",
|
||||
"-fstack-protector",
|
||||
"-Wall",
|
||||
"-Wextra",
|
||||
"-Wformat",
|
||||
"-Wformat-security",
|
||||
"-Wundef",
|
||||
};
|
||||
ngui.addCSourceFiles(lvgl_generic_src, lvgl_flags);
|
||||
|
||||
const run_cmd = exe.run();
|
||||
run_cmd.step.dependOn(b.getInstallStep());
|
||||
if (b.args) |args| {
|
||||
run_cmd.addArgs(args);
|
||||
const ngui_cflags: []const []const u8 = &.{
|
||||
"-std=c11",
|
||||
"-Wall",
|
||||
"-Wextra",
|
||||
"-Wshadow",
|
||||
"-Wundef",
|
||||
"-Wunused-parameter",
|
||||
"-Werror",
|
||||
};
|
||||
ngui.addCSourceFiles(&.{
|
||||
"src/ui/c/ui.c",
|
||||
"src/ui/c/lv_font_courierprimecode_14.c",
|
||||
//"src/ui/c/lv_font_courierprimecode_16.c",
|
||||
"src/ui/c/lv_font_courierprimecode_24.c",
|
||||
}, ngui_cflags);
|
||||
|
||||
ngui.defineCMacroRaw(b.fmt("NM_DISP_HOR={}", .{disp_horiz}));
|
||||
ngui.defineCMacroRaw(b.fmt("NM_DISP_VER={}", .{disp_vert}));
|
||||
ngui.defineCMacro("LV_CONF_INCLUDE_SIMPLE", null);
|
||||
ngui.defineCMacro("LV_TICK_CUSTOM", "1");
|
||||
ngui.defineCMacro("LV_TICK_CUSTOM_INCLUDE", "\"ui.h\"");
|
||||
ngui.defineCMacro("LV_TICK_CUSTOM_SYS_TIME_EXPR", "(nm_get_curr_tick())");
|
||||
switch (drv) {
|
||||
.sdl2 => {
|
||||
ngui.addCSourceFiles(lvgl_sdl2_src, lvgl_flags);
|
||||
ngui.addCSourceFile("src/ui/c/drv_sdl2.c", ngui_cflags);
|
||||
ngui.defineCMacro("NM_DRV_SDL2", null);
|
||||
ngui.defineCMacro("USE_SDL", null);
|
||||
ngui.linkSystemLibrary("SDL2");
|
||||
},
|
||||
.fbev => {
|
||||
ngui.addCSourceFiles(lvgl_fbev_src, lvgl_flags);
|
||||
ngui.addCSourceFile("src/ui/c/drv_fbev.c", ngui_cflags);
|
||||
ngui.defineCMacro("NM_DRV_FBEV", null);
|
||||
ngui.defineCMacro("USE_FBDEV", null);
|
||||
ngui.defineCMacro("USE_EVDEV", null);
|
||||
},
|
||||
}
|
||||
|
||||
const run_step = b.step("run", "Run the app");
|
||||
run_step.dependOn(&run_cmd.step);
|
||||
const ngui_build_step = b.step("ngui", "build ngui (nakamochi gui)");
|
||||
ngui_build_step.dependOn(&b.addInstallArtifact(ngui).step);
|
||||
|
||||
// daemon build
|
||||
const nd = b.addExecutable("nd", "src/nd.zig");
|
||||
nd.setTarget(target);
|
||||
nd.setBuildMode(mode);
|
||||
nd.pie = true;
|
||||
nd.strip = strip;
|
||||
|
||||
nifbuild.addPkg(b, nd, "lib/nif");
|
||||
const niflib = nifbuild.library(b, "lib/nif");
|
||||
niflib.setTarget(target);
|
||||
niflib.setBuildMode(mode);
|
||||
nd.linkLibrary(niflib);
|
||||
|
||||
const exe_tests = b.addTest("src/main.zig");
|
||||
exe_tests.setTarget(target);
|
||||
exe_tests.setBuildMode(mode);
|
||||
const nd_build_step = b.step("nd", "build nd (nakamochi daemon)");
|
||||
nd_build_step.dependOn(&b.addInstallArtifact(nd).step);
|
||||
|
||||
const test_step = b.step("test", "Run unit tests");
|
||||
test_step.dependOn(&exe_tests.step);
|
||||
// default build
|
||||
const build_all_step = b.step("all", "build everything");
|
||||
build_all_step.dependOn(ngui_build_step);
|
||||
build_all_step.dependOn(nd_build_step);
|
||||
b.default_step.dependOn(build_all_step);
|
||||
|
||||
{
|
||||
const tests = b.addTest("src/test.zig");
|
||||
tests.setTarget(target);
|
||||
tests.setBuildMode(mode);
|
||||
tests.linkLibC();
|
||||
if (b.args) |args| {
|
||||
for (args) |a, i| {
|
||||
if (std.mem.eql(u8, a, "--test-filter")) {
|
||||
tests.setFilter(args[i + 1]); // don't care about OOB
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const test_step = b.step("test", "run tests");
|
||||
test_step.dependOn(&tests.step);
|
||||
}
|
||||
}
|
||||
|
||||
const DriverTarget = enum {
|
||||
sdl2,
|
||||
fbev, // framebuffer + evdev
|
||||
};
|
||||
|
||||
const lvgl_sdl2_src: []const []const u8 = &.{
|
||||
"lib/lv_drivers/sdl/sdl.c",
|
||||
"lib/lv_drivers/sdl/sdl_common.c",
|
||||
};
|
||||
|
||||
const lvgl_fbev_src: []const []const u8 = &.{
|
||||
"lib/lv_drivers/display/fbdev.c",
|
||||
"lib/lv_drivers/indev/evdev.c",
|
||||
};
|
||||
|
||||
const lvgl_generic_src: []const []const u8 = &.{
|
||||
"lib/lvgl/src/core/lv_disp.c",
|
||||
"lib/lvgl/src/core/lv_event.c",
|
||||
"lib/lvgl/src/core/lv_group.c",
|
||||
"lib/lvgl/src/core/lv_indev.c",
|
||||
"lib/lvgl/src/core/lv_indev_scroll.c",
|
||||
"lib/lvgl/src/core/lv_obj.c",
|
||||
"lib/lvgl/src/core/lv_obj_class.c",
|
||||
"lib/lvgl/src/core/lv_obj_draw.c",
|
||||
"lib/lvgl/src/core/lv_obj_pos.c",
|
||||
"lib/lvgl/src/core/lv_obj_scroll.c",
|
||||
"lib/lvgl/src/core/lv_obj_style.c",
|
||||
"lib/lvgl/src/core/lv_obj_style_gen.c",
|
||||
"lib/lvgl/src/core/lv_obj_tree.c",
|
||||
"lib/lvgl/src/core/lv_refr.c",
|
||||
"lib/lvgl/src/core/lv_theme.c",
|
||||
"lib/lvgl/src/draw/arm2d/lv_gpu_arm2d.c",
|
||||
"lib/lvgl/src/draw/lv_draw.c",
|
||||
"lib/lvgl/src/draw/lv_draw_arc.c",
|
||||
"lib/lvgl/src/draw/lv_draw_img.c",
|
||||
"lib/lvgl/src/draw/lv_draw_label.c",
|
||||
"lib/lvgl/src/draw/lv_draw_layer.c",
|
||||
"lib/lvgl/src/draw/lv_draw_line.c",
|
||||
"lib/lvgl/src/draw/lv_draw_mask.c",
|
||||
"lib/lvgl/src/draw/lv_draw_rect.c",
|
||||
"lib/lvgl/src/draw/lv_draw_transform.c",
|
||||
"lib/lvgl/src/draw/lv_draw_triangle.c",
|
||||
"lib/lvgl/src/draw/lv_img_buf.c",
|
||||
"lib/lvgl/src/draw/lv_img_cache.c",
|
||||
"lib/lvgl/src/draw/lv_img_decoder.c",
|
||||
"lib/lvgl/src/draw/sdl/lv_draw_sdl.c",
|
||||
"lib/lvgl/src/draw/sdl/lv_draw_sdl_arc.c",
|
||||
"lib/lvgl/src/draw/sdl/lv_draw_sdl_bg.c",
|
||||
"lib/lvgl/src/draw/sdl/lv_draw_sdl_composite.c",
|
||||
"lib/lvgl/src/draw/sdl/lv_draw_sdl_img.c",
|
||||
"lib/lvgl/src/draw/sdl/lv_draw_sdl_label.c",
|
||||
"lib/lvgl/src/draw/sdl/lv_draw_sdl_layer.c",
|
||||
"lib/lvgl/src/draw/sdl/lv_draw_sdl_line.c",
|
||||
"lib/lvgl/src/draw/sdl/lv_draw_sdl_mask.c",
|
||||
"lib/lvgl/src/draw/sdl/lv_draw_sdl_polygon.c",
|
||||
"lib/lvgl/src/draw/sdl/lv_draw_sdl_rect.c",
|
||||
"lib/lvgl/src/draw/sdl/lv_draw_sdl_stack_blur.c",
|
||||
"lib/lvgl/src/draw/sdl/lv_draw_sdl_texture_cache.c",
|
||||
"lib/lvgl/src/draw/sdl/lv_draw_sdl_utils.c",
|
||||
"lib/lvgl/src/draw/sw/lv_draw_sw.c",
|
||||
"lib/lvgl/src/draw/sw/lv_draw_sw_arc.c",
|
||||
"lib/lvgl/src/draw/sw/lv_draw_sw_blend.c",
|
||||
"lib/lvgl/src/draw/sw/lv_draw_sw_dither.c",
|
||||
"lib/lvgl/src/draw/sw/lv_draw_sw_gradient.c",
|
||||
"lib/lvgl/src/draw/sw/lv_draw_sw_img.c",
|
||||
"lib/lvgl/src/draw/sw/lv_draw_sw_layer.c",
|
||||
"lib/lvgl/src/draw/sw/lv_draw_sw_letter.c",
|
||||
"lib/lvgl/src/draw/sw/lv_draw_sw_line.c",
|
||||
"lib/lvgl/src/draw/sw/lv_draw_sw_polygon.c",
|
||||
"lib/lvgl/src/draw/sw/lv_draw_sw_rect.c",
|
||||
"lib/lvgl/src/draw/sw/lv_draw_sw_transform.c",
|
||||
"lib/lvgl/src/extra/layouts/flex/lv_flex.c",
|
||||
"lib/lvgl/src/extra/layouts/grid/lv_grid.c",
|
||||
"lib/lvgl/src/extra/libs/bmp/lv_bmp.c",
|
||||
"lib/lvgl/src/extra/libs/ffmpeg/lv_ffmpeg.c",
|
||||
"lib/lvgl/src/extra/libs/freetype/lv_freetype.c",
|
||||
"lib/lvgl/src/extra/libs/fsdrv/lv_fs_fatfs.c",
|
||||
"lib/lvgl/src/extra/libs/fsdrv/lv_fs_posix.c",
|
||||
"lib/lvgl/src/extra/libs/fsdrv/lv_fs_stdio.c",
|
||||
"lib/lvgl/src/extra/libs/fsdrv/lv_fs_win32.c",
|
||||
"lib/lvgl/src/extra/libs/gif/gifdec.c",
|
||||
"lib/lvgl/src/extra/libs/gif/lv_gif.c",
|
||||
"lib/lvgl/src/extra/libs/png/lodepng.c",
|
||||
"lib/lvgl/src/extra/libs/png/lv_png.c",
|
||||
"lib/lvgl/src/extra/libs/qrcode/lv_qrcode.c",
|
||||
"lib/lvgl/src/extra/libs/qrcode/qrcodegen.c",
|
||||
"lib/lvgl/src/extra/libs/rlottie/lv_rlottie.c",
|
||||
"lib/lvgl/src/extra/libs/sjpg/lv_sjpg.c",
|
||||
"lib/lvgl/src/extra/libs/sjpg/tjpgd.c",
|
||||
"lib/lvgl/src/extra/lv_extra.c",
|
||||
"lib/lvgl/src/extra/others/fragment/lv_fragment.c",
|
||||
"lib/lvgl/src/extra/others/fragment/lv_fragment_manager.c",
|
||||
"lib/lvgl/src/extra/others/gridnav/lv_gridnav.c",
|
||||
"lib/lvgl/src/extra/others/ime/lv_ime_pinyin.c",
|
||||
"lib/lvgl/src/extra/others/imgfont/lv_imgfont.c",
|
||||
"lib/lvgl/src/extra/others/monkey/lv_monkey.c",
|
||||
"lib/lvgl/src/extra/others/msg/lv_msg.c",
|
||||
"lib/lvgl/src/extra/others/snapshot/lv_snapshot.c",
|
||||
"lib/lvgl/src/extra/themes/basic/lv_theme_basic.c",
|
||||
"lib/lvgl/src/extra/themes/default/lv_theme_default.c",
|
||||
"lib/lvgl/src/extra/themes/mono/lv_theme_mono.c",
|
||||
"lib/lvgl/src/extra/widgets/animimg/lv_animimg.c",
|
||||
"lib/lvgl/src/extra/widgets/calendar/lv_calendar.c",
|
||||
"lib/lvgl/src/extra/widgets/calendar/lv_calendar_header_arrow.c",
|
||||
"lib/lvgl/src/extra/widgets/calendar/lv_calendar_header_dropdown.c",
|
||||
"lib/lvgl/src/extra/widgets/chart/lv_chart.c",
|
||||
"lib/lvgl/src/extra/widgets/colorwheel/lv_colorwheel.c",
|
||||
"lib/lvgl/src/extra/widgets/imgbtn/lv_imgbtn.c",
|
||||
"lib/lvgl/src/extra/widgets/keyboard/lv_keyboard.c",
|
||||
"lib/lvgl/src/extra/widgets/led/lv_led.c",
|
||||
"lib/lvgl/src/extra/widgets/list/lv_list.c",
|
||||
"lib/lvgl/src/extra/widgets/menu/lv_menu.c",
|
||||
"lib/lvgl/src/extra/widgets/meter/lv_meter.c",
|
||||
"lib/lvgl/src/extra/widgets/msgbox/lv_msgbox.c",
|
||||
"lib/lvgl/src/extra/widgets/span/lv_span.c",
|
||||
"lib/lvgl/src/extra/widgets/spinbox/lv_spinbox.c",
|
||||
"lib/lvgl/src/extra/widgets/spinner/lv_spinner.c",
|
||||
"lib/lvgl/src/extra/widgets/tabview/lv_tabview.c",
|
||||
"lib/lvgl/src/extra/widgets/tileview/lv_tileview.c",
|
||||
"lib/lvgl/src/extra/widgets/win/lv_win.c",
|
||||
"lib/lvgl/src/font/lv_font.c",
|
||||
"lib/lvgl/src/font/lv_font_fmt_txt.c",
|
||||
"lib/lvgl/src/font/lv_font_loader.c",
|
||||
"lib/lvgl/src/hal/lv_hal_disp.c",
|
||||
"lib/lvgl/src/hal/lv_hal_indev.c",
|
||||
"lib/lvgl/src/hal/lv_hal_tick.c",
|
||||
"lib/lvgl/src/misc/lv_anim.c",
|
||||
"lib/lvgl/src/misc/lv_anim_timeline.c",
|
||||
"lib/lvgl/src/misc/lv_area.c",
|
||||
"lib/lvgl/src/misc/lv_async.c",
|
||||
"lib/lvgl/src/misc/lv_bidi.c",
|
||||
"lib/lvgl/src/misc/lv_color.c",
|
||||
"lib/lvgl/src/misc/lv_fs.c",
|
||||
"lib/lvgl/src/misc/lv_gc.c",
|
||||
"lib/lvgl/src/misc/lv_ll.c",
|
||||
"lib/lvgl/src/misc/lv_log.c",
|
||||
"lib/lvgl/src/misc/lv_lru.c",
|
||||
"lib/lvgl/src/misc/lv_math.c",
|
||||
"lib/lvgl/src/misc/lv_mem.c",
|
||||
"lib/lvgl/src/misc/lv_printf.c",
|
||||
"lib/lvgl/src/misc/lv_style.c",
|
||||
"lib/lvgl/src/misc/lv_style_gen.c",
|
||||
"lib/lvgl/src/misc/lv_templ.c",
|
||||
"lib/lvgl/src/misc/lv_timer.c",
|
||||
"lib/lvgl/src/misc/lv_tlsf.c",
|
||||
"lib/lvgl/src/misc/lv_txt.c",
|
||||
"lib/lvgl/src/misc/lv_txt_ap.c",
|
||||
"lib/lvgl/src/misc/lv_utils.c",
|
||||
"lib/lvgl/src/widgets/lv_arc.c",
|
||||
"lib/lvgl/src/widgets/lv_bar.c",
|
||||
"lib/lvgl/src/widgets/lv_btn.c",
|
||||
"lib/lvgl/src/widgets/lv_btnmatrix.c",
|
||||
"lib/lvgl/src/widgets/lv_canvas.c",
|
||||
"lib/lvgl/src/widgets/lv_checkbox.c",
|
||||
"lib/lvgl/src/widgets/lv_dropdown.c",
|
||||
"lib/lvgl/src/widgets/lv_img.c",
|
||||
"lib/lvgl/src/widgets/lv_label.c",
|
||||
"lib/lvgl/src/widgets/lv_line.c",
|
||||
"lib/lvgl/src/widgets/lv_objx_templ.c",
|
||||
"lib/lvgl/src/widgets/lv_roller.c",
|
||||
"lib/lvgl/src/widgets/lv_slider.c",
|
||||
"lib/lvgl/src/widgets/lv_switch.c",
|
||||
"lib/lvgl/src/widgets/lv_table.c",
|
||||
"lib/lvgl/src/widgets/lv_textarea.c",
|
||||
};
|
||||
|
@ -0,0 +1,73 @@
|
||||
the trouble is fontawesome now supplies multiple files,
|
||||
fa-brands-400.woff2, fa-regular-400.woff2 and fa-solid-900.woff2.
|
||||
don't know which symbol is in which file.
|
||||
|
||||
list all defined symbols into a file:
|
||||
|
||||
grep 0x ../ngui/lib/lvgl/src/font/lv_symbol_def.h | grep -v 0x2022 | \
|
||||
cut -d, -f2 | cut -c4-7 | tr 'A-F' 'a-f' \
|
||||
> /tmp/sym.txt
|
||||
|
||||
download and unzip fontawesome. expect to find metadata/icons.yml file.
|
||||
grep metadata to find out which set each icon is in:
|
||||
|
||||
for c in $(cat /tmp/sym.txt); do
|
||||
t=$(grep -B3 "unicode: $c" metadata/icons.yml | grep -- '- ' | head -n1 | tr -d ' -')
|
||||
echo "$c\t$t"
|
||||
done
|
||||
|
||||
some icons are in multiple styles. search for the code on https://fontawesome.com/icons/
|
||||
and compare to the image on https://docs.lvgl.io/8.3/overview/font.html.
|
||||
the command above takes the first one listed in icons.yml, which is usually "solid".
|
||||
when searching on fontawesome, make sure it's a free icon, as opposed to their pro version.
|
||||
|
||||
not all icons might be present. at the time of writing, the following codes are amiss:
|
||||
|
||||
- 0xf067 `LV_SYMBOL_PLUS`; actually exists but listed as unicode:2b in icons.yml
|
||||
- 0xf8a2 `LV_SYMBOL_NEW_LINE`; looks like fontawesome removed `level-down-alt` from v6
|
||||
so i picked an alternative 0xf177 `arrow-left-long`
|
||||
|
||||
dump previous command output into an fa-icon-style.txt file. add missing "solid" style
|
||||
in the second column and replace f8a2 with `f177=>0xf8a2` mapping. the latter is
|
||||
the syntax for when running [lvgl font convertion tool](https://github.com/lvgl/lv_font_conv).
|
||||
|
||||
while there, add more codes to the file, separating columns with a single tab:
|
||||
|
||||
- 0xf379 brands (bitcoin)
|
||||
- 0xe0b4 solid (bitcoin-sign)
|
||||
- 0xf0e7 solid (lightning bolt)
|
||||
|
||||
split the previously generated fa-icon-style.txt file into chunks suitable for
|
||||
constructing lvgl's font converter arguments.
|
||||
|
||||
first, check which styles are present. at the moment, only "brands" and "solid"
|
||||
are used:
|
||||
|
||||
$ cut -f2 fa-icon-style.txt | sort | uniq -c
|
||||
3 brands
|
||||
61 solid
|
||||
|
||||
then split the file, for each style from the previous command. example for "solid":
|
||||
|
||||
grep solid fa-icon-style.txt | cut -f1 | tr 'a-f' 'A-F' | \
|
||||
while IFS= read -r line; do printf "0x$line\n"; done | \
|
||||
paste -s -d, | tr -d '\n' > fa-solid.txt
|
||||
|
||||
typically, you'll want to bundle the symbols from fontawesome with a regular font.
|
||||
i'll use [courier prime code](https://github.com/quoteunquoteapps/courierprimecode)
|
||||
as an example.
|
||||
|
||||
install the font converter tool; requires nodejs:
|
||||
|
||||
npm i lvgl/lv_font_conv
|
||||
|
||||
finally, convert and bundle all fonts, for 14px size as an example:
|
||||
|
||||
./node_modules/.bin/lv_font_conv --no-compress --no-prefilter --bpp 4 --size 14 \
|
||||
--font courier-prime-code.ttf -r 0x20-0x7F,0xB0,0x2022 \
|
||||
--font fa-brands-400.ttf -r $(cat fa-brands.txt) \
|
||||
--font fa-solid-900.ttf -r $(cat fa-solid.txt) \
|
||||
--format lvgl --force-fast-kern-format \
|
||||
-o lv_font_courierprimecode_14.c
|
||||
|
||||
the arguments are similar to those in the header of any LVGL font in `lib/lvgl/src/font/lv_font/xxx.c`.
|
@ -0,0 +1,29 @@
|
||||
const build = @import("std").build;
|
||||
|
||||
pub fn addPkg(b: *build.Builder, obj: *build.LibExeObjStep, prefix: []const u8) void {
|
||||
obj.addPackagePath("nif", pkgPath(b, prefix));
|
||||
}
|
||||
|
||||
pub fn pkgPath(b: *build.Builder, prefix: []const u8) []const u8 {
|
||||
return b.pathJoin(&.{prefix, "nif.zig"});
|
||||
}
|
||||
|
||||
pub fn library(b: *build.Builder, prefix: []const u8) *build.LibExeObjStep {
|
||||
const lib = b.addStaticLibrary("nif", b.pathJoin(&.{prefix, "nif.zig"}));
|
||||
lib.addIncludePath(b.pathJoin(&.{prefix, "wpa_supplicant"}));
|
||||
lib.defineCMacro("CONFIG_CTRL_IFACE", null);
|
||||
lib.defineCMacro("CONFIG_CTRL_IFACE_UNIX", null);
|
||||
lib.addCSourceFiles(&.{
|
||||
b.pathJoin(&.{prefix, "wpa_supplicant/wpa_ctrl.c"}),
|
||||
b.pathJoin(&.{prefix, "wpa_supplicant/os_unix.c"}),
|
||||
}, &.{
|
||||
"-Wall",
|
||||
"-Wextra",
|
||||
"-Wshadow",
|
||||
"-Wundef",
|
||||
"-Wunused-parameter",
|
||||
"-Werror",
|
||||
});
|
||||
lib.linkLibC();
|
||||
return lib;
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
const std = @import("std");
|
||||
const mem = std.mem;
|
||||
const net = std.net;
|
||||
const os = std.os;
|
||||
|
||||
pub const wpa = @import("wpa.zig");
|
||||
|
||||
const IFF_UP = 1 << 0; //0b1;
|
||||
const IFF_LOOPBACK = 1 << 3; //0b1000;
|
||||
|
||||
const ifaddrs = extern struct {
|
||||
next: ?*ifaddrs,
|
||||
name: [*:0]const u8,
|
||||
flags: c_uint, // see IFF_xxx SIOCGIFFLAGS in netdevice(7)
|
||||
addr: ?*std.os.sockaddr,
|
||||
netmask: ?*std.os.sockaddr,
|
||||
ifu: extern union {
|
||||
broad: *os.sockaddr, // flags & IFF_BROADCAST
|
||||
dst: *os.sockaddr, // flags & IFF_POINTOPOINT
|
||||
},
|
||||
data: ?*anyopaque,
|
||||
};
|
||||
|
||||
extern "c" fn getifaddrs(ptrp: **ifaddrs) c_int;
|
||||
extern "c" fn freeifaddrs(ptr: *ifaddrs) void;
|
||||
|
||||
/// retrieves a list of all public IP addresses assigned to the network interfaces,
|
||||
/// optionally filtering by the interface name.
|
||||
/// caller owns the returned value.
|
||||
pub fn pubAddresses(allocator: mem.Allocator, ifname: ?[]const u8) ![]net.Address {
|
||||
var res: *ifaddrs = undefined;
|
||||
if (getifaddrs(&res) != 0) {
|
||||
return error.Getifaddrs;
|
||||
}
|
||||
defer freeifaddrs(res);
|
||||
|
||||
var list = std.ArrayList(net.Address).init(allocator);
|
||||
var it: ?*ifaddrs = res;
|
||||
while (it) |ifa| : (it = ifa.next) {
|
||||
const sa: *os.sockaddr = ifa.addr orelse continue;
|
||||
if (sa.family != os.AF.INET and sa.family != os.AF.INET6) {
|
||||
// not an IP address
|
||||
continue;
|
||||
}
|
||||
if (ifa.flags & IFF_UP == 0 or ifa.flags & IFF_LOOPBACK != 0) {
|
||||
// skip loopbacks and those which are not "up"
|
||||
continue;
|
||||
}
|
||||
const ipaddr = net.Address.initPosix(@alignCast(4, sa)); // initPosix makes a copy
|
||||
if (ipaddr.any.family == os.AF.INET6 and ipaddr.in6.sa.scope_id > 0) {
|
||||
// want only global, with 0 scope
|
||||
// non-zero scopes make sense for link-local addr only.
|
||||
continue;
|
||||
}
|
||||
if (ifname) |name| {
|
||||
if (!mem.eql(u8, name, mem.sliceTo(ifa.name, 0))) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
try list.append(ipaddr);
|
||||
}
|
||||
return list.toOwnedSlice();
|
||||
}
|
@ -0,0 +1,384 @@
|
||||
const std = @import("std");
|
||||
const mem = std.mem;
|
||||
const Thread = std.Thread;
|
||||
|
||||
const WPACtrl = opaque {};
|
||||
const WPAReqCallback = *const fn ([*:0]const u8, usize) callconv(.C) void;
|
||||
|
||||
extern fn wpa_ctrl_open(ctrl_path: [*:0]const u8) ?*WPACtrl;
|
||||
extern fn wpa_ctrl_close(ctrl: *WPACtrl) void;
|
||||
extern fn wpa_ctrl_request(ctrl: *WPACtrl, cmd: [*:0]const u8, clen: usize, reply: [*:0]u8, rlen: *usize, cb: ?WPAReqCallback) c_int;
|
||||
extern fn wpa_ctrl_pending(ctrl: *WPACtrl) c_int;
|
||||
extern fn wpa_ctrl_recv(ctrl: *WPACtrl, reply: [*:0]u8, reply_len: *usize) c_int;
|
||||
|
||||
pub const Control = struct {
|
||||
//mu: Thread.Mutext = .{},
|
||||
wpa_ctrl: *WPACtrl,
|
||||
attached: bool = false,
|
||||
|
||||
const Self = @This();
|
||||
pub const Error = error{
|
||||
NameTooLong,
|
||||
WpaCtrlFailure,
|
||||
WpaCtrlTimeout,
|
||||
WpaCtrlAttach,
|
||||
WpaCtrlDetach,
|
||||
WpaCtrlScanStart,
|
||||
WpaCtrlSaveConfig,
|
||||
WpaCtrlAddNetwork,
|
||||
WpaCtrlRemoveNetwork,
|
||||
WpaCtrlSelectNetwork,
|
||||
WpaCtrlEnableNetwork,
|
||||
WpaCtrlSetNetworkParam,
|
||||
} || std.fmt.BufPrintError;
|
||||
|
||||
// TODO: using this in Self.request
|
||||
pub const RequestCallback = *const fn (msg: [:0]const u8) void;
|
||||
|
||||
fn wpaErr(i: c_int) Error {
|
||||
return switch (i) {
|
||||
-2 => error.WpaCtrlTimeout,
|
||||
else => error.WpaCtrlFailure,
|
||||
};
|
||||
}
|
||||
|
||||
/// open a WPA control interface identified by the path.
|
||||
/// the returned instance must be close'd when done to free resources.
|
||||
/// TODO: describe @android: and @abstract: prefixes
|
||||
/// TODO: what about UDP, on windows?
|
||||
pub fn open(path: [:0]const u8) Error!Self {
|
||||
const ctrl = wpa_ctrl_open(path);
|
||||
if (ctrl == null) {
|
||||
return error.WpaCtrlFailure;
|
||||
}
|
||||
return Self{ .wpa_ctrl = ctrl.? };
|
||||
}
|
||||
|
||||
/// release all associated resources, including detach'ing a monitor.
|
||||
pub fn close(self: *Self) Error!void {
|
||||
//self.mu.lock();
|
||||
//defer self.mu.unlock();
|
||||
if (self.attached) {
|
||||
try self.detach();
|
||||
}
|
||||
wpa_ctrl_close(self.wpa_ctrl);
|
||||
}
|
||||
|
||||
/// start control interface events monitoring.
|
||||
/// presence of events is reported by self.pending; then can be read using self.receive.
|
||||
pub fn attach(self: *Self) Error!void {
|
||||
self.reqOK("ATTACH") catch return error.WpaCtrlAttach;
|
||||
self.attached = true;
|
||||
}
|
||||
|
||||
/// stop control interface events monitoring.
|
||||
pub fn detach(self: *Self) Error!void {
|
||||
self.reqOK("DETACH") catch return error.WpaCtrlDetach;
|
||||
self.attached = false;
|
||||
}
|
||||
|
||||
/// request wifi scan
|
||||
pub fn scan(self: *Self) Error!void {
|
||||
self.reqOK("SCAN") catch return error.WpaCtrlScanStart;
|
||||
}
|
||||
|
||||
/// dump in-memory config to a file, typically /etc/wpa_supplicant/wpa_supplicant.conf.
|
||||
/// fails if update_config set to 0.
|
||||
pub fn saveConfig(self: *Self) Error!void {
|
||||
self.reqOK("SAVE_CONFIG") catch return error.WpaCtrlSaveConfig;
|
||||
}
|
||||
|
||||
/// add a new blank network, returning its ID.
|
||||
/// the newly added network can be configured with self.setNetworkParam.
|
||||
pub fn addNetwork(self: *Self) (Error||std.fmt.ParseIntError)!u32 {
|
||||
var buf: [10:0]u8 = undefined;
|
||||
const resp = self.request("ADD_NETWORK", &buf, null) catch return error.WpaCtrlAddNetwork;
|
||||
return std.fmt.parseUnsigned(u32, mem.trim(u8, resp, "\n "), 10);
|
||||
}
|
||||
|
||||
pub fn removeNetwork(self: *Self, id: u32) Error!void {
|
||||
var buf: [48:0]u8 = undefined;
|
||||
const cmd = try std.fmt.bufPrintZ(&buf, "REMOVE_NETWORK {d}", .{id});
|
||||
return self.reqOK(cmd) catch return error.WpaCtrlRemoveNetwork;
|
||||
}
|
||||
|
||||
pub fn selectNetwork(self: *Self, id: u32) Error!void {
|
||||
var buf: [48:0]u8 = undefined;
|
||||
const cmd = try std.fmt.bufPrintZ(&buf, "SELECT_NETWORK {d}", .{id});
|
||||
return self.reqOK(cmd) catch return error.WpaCtrlSelectNetwork;
|
||||
}
|
||||
|
||||
pub fn enableNetwork(self: *Self, id: u32) Error!void {
|
||||
var buf: [48:0]u8 = undefined;
|
||||
const cmd = try std.fmt.bufPrintZ(&buf, "ENABLE_NETWORK {d}", .{id});
|
||||
return self.reqOK(cmd) catch return error.WpaCtrlEnableNetwork;
|
||||
}
|
||||
|
||||
pub fn setNetworkParam(self: *Self, id: u32, name: []const u8, value: []const u8) Error!void {
|
||||
var buf: [512:0]u8 = undefined;
|
||||
const cmd = try std.fmt.bufPrintZ(&buf, "SET_NETWORK {d} {s} {s}", .{id, name, value});
|
||||
return self.reqOK(cmd) catch return error.WpaCtrlSetNetworkParam;
|
||||
}
|
||||
|
||||
fn reqOK(self: *Self, cmd: [:0]const u8) Error!void {
|
||||
var buf: [10:0]u8 = undefined;
|
||||
const resp = try self.request(cmd, &buf, null);
|
||||
if (!mem.startsWith(u8, resp, "OK\n")) {
|
||||
return error.WpaCtrlFailure;
|
||||
}
|
||||
}
|
||||
|
||||
/// send a command to the control interface, returning a response owned by buf.
|
||||
/// callback receives a message from the same buf.
|
||||
pub fn request(self: Self, cmd: [:0]const u8, buf: [:0]u8, callback: ?WPAReqCallback) Error![]const u8 {
|
||||
//self.mu.lock();
|
||||
//defer self.mu.unlock();
|
||||
var n: usize = buf.len;
|
||||
const e = wpa_ctrl_request(self.wpa_ctrl, cmd, cmd.len, buf, &n, callback);
|
||||
if (e != 0) {
|
||||
return wpaErr(e);
|
||||
}
|
||||
return buf[0..n];
|
||||
}
|
||||
|
||||
/// reports whether pending messages are waiting to be read using self.receive.
|
||||
/// requires self to be attach'ed.
|
||||
pub fn pending(self: Self) Error!bool {
|
||||
//self.mu.lock();
|
||||
//defer self.mu.unlock();
|
||||
const n = wpa_ctrl_pending(self.wpa_ctrl);
|
||||
if (n < 0) {
|
||||
return wpaErr(n);
|
||||
}
|
||||
return n > 0;
|
||||
}
|
||||
|
||||
/// retrieve a pending message using the provided buf.
|
||||
/// returned slice is owned by the buf.
|
||||
/// requires self to be attach'ed.
|
||||
pub fn receive(self: Self, buf: [:0]u8) Error![]const u8 {
|
||||
//self.mu.lock();
|
||||
//defer self.mu.unlock();
|
||||
var n: usize = buf.len;
|
||||
const e = wpa_ctrl_recv(self.wpa_ctrl, buf, &n);
|
||||
if (e != 0) {
|
||||
return wpaErr(e);
|
||||
}
|
||||
return buf[0..n];
|
||||
}
|
||||
};
|
||||
|
||||
//pub const WPA_CTRL_REQ = "CTRL-REQ-";
|
||||
//pub const WPA_CTRL_RSP = "CTRL-RSP-";
|
||||
//pub const WPA_EVENT_CONNECTED = "CTRL-EVENT-CONNECTED ";
|
||||
//pub const WPA_EVENT_DISCONNECTED = "CTRL-EVENT-DISCONNECTED ";
|
||||
//pub const WPA_EVENT_ASSOC_REJECT = "CTRL-EVENT-ASSOC-REJECT ";
|
||||
//pub const WPA_EVENT_AUTH_REJECT = "CTRL-EVENT-AUTH-REJECT ";
|
||||
//pub const WPA_EVENT_TERMINATING = "CTRL-EVENT-TERMINATING ";
|
||||
//pub const WPA_EVENT_PASSWORD_CHANGED = "CTRL-EVENT-PASSWORD-CHANGED ";
|
||||
//pub const WPA_EVENT_EAP_NOTIFICATION = "CTRL-EVENT-EAP-NOTIFICATION ";
|
||||
//pub const WPA_EVENT_EAP_STARTED = "CTRL-EVENT-EAP-STARTED ";
|
||||
//pub const WPA_EVENT_EAP_PROPOSED_METHOD = "CTRL-EVENT-EAP-PROPOSED-METHOD ";
|
||||
//pub const WPA_EVENT_EAP_METHOD = "CTRL-EVENT-EAP-METHOD ";
|
||||
//pub const WPA_EVENT_EAP_PEER_CERT = "CTRL-EVENT-EAP-PEER-CERT ";
|
||||
//pub const WPA_EVENT_EAP_PEER_ALT = "CTRL-EVENT-EAP-PEER-ALT ";
|
||||
//pub const WPA_EVENT_EAP_TLS_CERT_ERROR = "CTRL-EVENT-EAP-TLS-CERT-ERROR ";
|
||||
//pub const WPA_EVENT_EAP_STATUS = "CTRL-EVENT-EAP-STATUS ";
|
||||
//pub const WPA_EVENT_EAP_RETRANSMIT = "CTRL-EVENT-EAP-RETRANSMIT ";
|
||||
//pub const WPA_EVENT_EAP_RETRANSMIT2 = "CTRL-EVENT-EAP-RETRANSMIT2 ";
|
||||
//pub const WPA_EVENT_EAP_SUCCESS = "CTRL-EVENT-EAP-SUCCESS ";
|
||||
//pub const WPA_EVENT_EAP_SUCCESS2 = "CTRL-EVENT-EAP-SUCCESS2 ";
|
||||
//pub const WPA_EVENT_EAP_FAILURE = "CTRL-EVENT-EAP-FAILURE ";
|
||||
//pub const WPA_EVENT_EAP_FAILURE2 = "CTRL-EVENT-EAP-FAILURE2 ";
|
||||
//pub const WPA_EVENT_EAP_TIMEOUT_FAILURE = "CTRL-EVENT-EAP-TIMEOUT-FAILURE ";
|
||||
//pub const WPA_EVENT_EAP_TIMEOUT_FAILURE2 = "CTRL-EVENT-EAP-TIMEOUT-FAILURE2 ";
|
||||
//pub const WPA_EVENT_EAP_ERROR_CODE = "EAP-ERROR-CODE ";
|
||||
//pub const WPA_EVENT_TEMP_DISABLED = "CTRL-EVENT-SSID-TEMP-DISABLED ";
|
||||
//pub const WPA_EVENT_REENABLED = "CTRL-EVENT-SSID-REENABLED ";
|
||||
//pub const WPA_EVENT_SCAN_STARTED = "CTRL-EVENT-SCAN-STARTED ";
|
||||
//pub const WPA_EVENT_SCAN_RESULTS = "CTRL-EVENT-SCAN-RESULTS ";
|
||||
//pub const WPA_EVENT_SCAN_FAILED = "CTRL-EVENT-SCAN-FAILED ";
|
||||
//pub const WPA_EVENT_STATE_CHANGE = "CTRL-EVENT-STATE-CHANGE ";
|
||||
//pub const WPA_EVENT_BSS_ADDED = "CTRL-EVENT-BSS-ADDED ";
|
||||
//pub const WPA_EVENT_BSS_REMOVED = "CTRL-EVENT-BSS-REMOVED ";
|
||||
//pub const WPA_EVENT_NETWORK_NOT_FOUND = "CTRL-EVENT-NETWORK-NOT-FOUND ";
|
||||
//pub const WPA_EVENT_SIGNAL_CHANGE = "CTRL-EVENT-SIGNAL-CHANGE ";
|
||||
//pub const WPA_EVENT_BEACON_LOSS = "CTRL-EVENT-BEACON-LOSS ";
|
||||
//pub const WPA_EVENT_REGDOM_CHANGE = "CTRL-EVENT-REGDOM-CHANGE ";
|
||||
//pub const WPA_EVENT_CHANNEL_SWITCH_STARTED = "CTRL-EVENT-STARTED-CHANNEL-SWITCH ";
|
||||
//pub const WPA_EVENT_CHANNEL_SWITCH = "CTRL-EVENT-CHANNEL-SWITCH ";
|
||||
//pub const WPA_EVENT_SAE_UNKNOWN_PASSWORD_IDENTIFIER = "CTRL-EVENT-SAE-UNKNOWN-PASSWORD-IDENTIFIER ";
|
||||
//pub const WPA_EVENT_UNPROT_BEACON = "CTRL-EVENT-UNPROT-BEACON ";
|
||||
//pub const WPA_EVENT_DO_ROAM = "CTRL-EVENT-DO-ROAM ";
|
||||
//pub const WPA_EVENT_SKIP_ROAM = "CTRL-EVENT-SKIP-ROAM ";
|
||||
//pub const WPA_EVENT_SUBNET_STATUS_UPDATE = "CTRL-EVENT-SUBNET-STATUS-UPDATE ";
|
||||
//pub const IBSS_RSN_COMPLETED = "IBSS-RSN-COMPLETED ";
|
||||
//pub const WPA_EVENT_FREQ_CONFLICT = "CTRL-EVENT-FREQ-CONFLICT ";
|
||||
//pub const WPA_EVENT_AVOID_FREQ = "CTRL-EVENT-AVOID-FREQ ";
|
||||
//pub const WPA_EVENT_NETWORK_ADDED = "CTRL-EVENT-NETWORK-ADDED ";
|
||||
//pub const WPA_EVENT_NETWORK_REMOVED = "CTRL-EVENT-NETWORK-REMOVED ";
|
||||
//pub const WPA_EVENT_MSCS_RESULT = "CTRL-EVENT-MSCS-RESULT ";
|
||||
//pub const WPS_EVENT_OVERLAP = "WPS-OVERLAP-DETECTED ";
|
||||
//pub const WPS_EVENT_AP_AVAILABLE_PBC = "WPS-AP-AVAILABLE-PBC ";
|
||||
//pub const WPS_EVENT_AP_AVAILABLE_AUTH = "WPS-AP-AVAILABLE-AUTH ";
|
||||
//pub const WPS_EVENT_AP_AVAILABLE_PIN = "WPS-AP-AVAILABLE-PIN ";
|
||||
//pub const WPS_EVENT_AP_AVAILABLE = "WPS-AP-AVAILABLE ";
|
||||
//pub const WPS_EVENT_CRED_RECEIVED = "WPS-CRED-RECEIVED ";
|
||||
//pub const WPS_EVENT_M2D = "WPS-M2D ";
|
||||
//pub const WPS_EVENT_FAIL = "WPS-FAIL ";
|
||||
//pub const WPS_EVENT_SUCCESS = "WPS-SUCCESS ";
|
||||
//pub const WPS_EVENT_TIMEOUT = "WPS-TIMEOUT ";
|
||||
//pub const WPS_EVENT_ACTIVE = "WPS-PBC-ACTIVE ";
|
||||
//pub const WPS_EVENT_DISABLE = "WPS-PBC-DISABLE ";
|
||||
//pub const WPS_EVENT_ENROLLEE_SEEN = "WPS-ENROLLEE-SEEN ";
|
||||
//pub const WPS_EVENT_OPEN_NETWORK = "WPS-OPEN-NETWORK ";
|
||||
//pub const WPA_EVENT_SCS_RESULT = "CTRL-EVENT-SCS-RESULT ";
|
||||
//pub const WPA_EVENT_DSCP_POLICY = "CTRL-EVENT-DSCP-POLICY ";
|
||||
//pub const WPS_EVENT_ER_AP_ADD = "WPS-ER-AP-ADD ";
|
||||
//pub const WPS_EVENT_ER_AP_REMOVE = "WPS-ER-AP-REMOVE ";
|
||||
//pub const WPS_EVENT_ER_ENROLLEE_ADD = "WPS-ER-ENROLLEE-ADD ";
|
||||
//pub const WPS_EVENT_ER_ENROLLEE_REMOVE = "WPS-ER-ENROLLEE-REMOVE ";
|
||||
//pub const WPS_EVENT_ER_AP_SETTINGS = "WPS-ER-AP-SETTINGS ";
|
||||
//pub const WPS_EVENT_ER_SET_SEL_REG = "WPS-ER-AP-SET-SEL-REG ";
|
||||
//pub const DPP_EVENT_AUTH_SUCCESS = "DPP-AUTH-SUCCESS ";
|
||||
//pub const DPP_EVENT_AUTH_INIT_FAILED = "DPP-AUTH-INIT-FAILED ";
|
||||
//pub const DPP_EVENT_NOT_COMPATIBLE = "DPP-NOT-COMPATIBLE ";
|
||||
//pub const DPP_EVENT_RESPONSE_PENDING = "DPP-RESPONSE-PENDING ";
|
||||
//pub const DPP_EVENT_SCAN_PEER_QR_CODE = "DPP-SCAN-PEER-QR-CODE ";
|
||||
//pub const DPP_EVENT_AUTH_DIRECTION = "DPP-AUTH-DIRECTION ";
|
||||
//pub const DPP_EVENT_CONF_RECEIVED = "DPP-CONF-RECEIVED ";
|
||||
//pub const DPP_EVENT_CONF_SENT = "DPP-CONF-SENT ";
|
||||
//pub const DPP_EVENT_CONF_FAILED = "DPP-CONF-FAILED ";
|
||||
//pub const DPP_EVENT_CONN_STATUS_RESULT = "DPP-CONN-STATUS-RESULT ";
|
||||
//pub const DPP_EVENT_CONFOBJ_AKM = "DPP-CONFOBJ-AKM ";
|
||||
//pub const DPP_EVENT_CONFOBJ_SSID = "DPP-CONFOBJ-SSID ";
|
||||
//pub const DPP_EVENT_CONFOBJ_SSID_CHARSET = "DPP-CONFOBJ-SSID-CHARSET ";
|
||||
//pub const DPP_EVENT_CONFOBJ_PASS = "DPP-CONFOBJ-PASS ";
|
||||
//pub const DPP_EVENT_CONFOBJ_PSK = "DPP-CONFOBJ-PSK ";
|
||||
//pub const DPP_EVENT_CONNECTOR = "DPP-CONNECTOR ";
|
||||
//pub const DPP_EVENT_C_SIGN_KEY = "DPP-C-SIGN-KEY ";
|
||||
//pub const DPP_EVENT_PP_KEY = "DPP-PP-KEY ";
|
||||
//pub const DPP_EVENT_NET_ACCESS_KEY = "DPP-NET-ACCESS-KEY ";
|
||||
//pub const DPP_EVENT_SERVER_NAME = "DPP-SERVER-NAME ";
|
||||
//pub const DPP_EVENT_CERTBAG = "DPP-CERTBAG ";
|
||||
//pub const DPP_EVENT_CACERT = "DPP-CACERT ";
|
||||
//pub const DPP_EVENT_MISSING_CONNECTOR = "DPP-MISSING-CONNECTOR ";
|
||||
//pub const DPP_EVENT_NETWORK_ID = "DPP-NETWORK-ID ";
|
||||
//pub const DPP_EVENT_CONFIGURATOR_ID = "DPP-CONFIGURATOR-ID ";
|
||||
//pub const DPP_EVENT_RX = "DPP-RX ";
|
||||
//pub const DPP_EVENT_TX = "DPP-TX ";
|
||||
//pub const DPP_EVENT_TX_STATUS = "DPP-TX-STATUS ";
|
||||
//pub const DPP_EVENT_FAIL = "DPP-FAIL ";
|
||||
//pub const DPP_EVENT_PKEX_T_LIMIT = "DPP-PKEX-T-LIMIT ";
|
||||
//pub const DPP_EVENT_INTRO = "DPP-INTRO ";
|
||||
//pub const DPP_EVENT_CONF_REQ_RX = "DPP-CONF-REQ-RX ";
|
||||
//pub const DPP_EVENT_CHIRP_STOPPED = "DPP-CHIRP-STOPPED ";
|
||||
//pub const DPP_EVENT_MUD_URL = "DPP-MUD-URL ";
|
||||
//pub const DPP_EVENT_BAND_SUPPORT = "DPP-BAND-SUPPORT ";
|
||||
//pub const DPP_EVENT_CSR = "DPP-CSR ";
|
||||
//pub const DPP_EVENT_CHIRP_RX = "DPP-CHIRP-RX ";
|
||||
//pub const MESH_GROUP_STARTED = "MESH-GROUP-STARTED ";
|
||||
//pub const MESH_GROUP_REMOVED = "MESH-GROUP-REMOVED ";
|
||||
//pub const MESH_PEER_CONNECTED = "MESH-PEER-CONNECTED ";
|
||||
//pub const MESH_PEER_DISCONNECTED = "MESH-PEER-DISCONNECTED ";
|
||||
//pub const MESH_SAE_AUTH_FAILURE = "MESH-SAE-AUTH-FAILURE ";
|
||||
//pub const MESH_SAE_AUTH_BLOCKED = "MESH-SAE-AUTH-BLOCKED ";
|
||||
//pub const WMM_AC_EVENT_TSPEC_ADDED = "TSPEC-ADDED ";
|
||||
//pub const WMM_AC_EVENT_TSPEC_REMOVED = "TSPEC-REMOVED ";
|
||||
//pub const WMM_AC_EVENT_TSPEC_REQ_FAILED = "TSPEC-REQ-FAILED ";
|
||||
//pub const P2P_EVENT_DEVICE_FOUND = "P2P-DEVICE-FOUND ";
|
||||
//pub const P2P_EVENT_DEVICE_LOST = "P2P-DEVICE-LOST ";
|
||||
//pub const P2P_EVENT_GO_NEG_REQUEST = "P2P-GO-NEG-REQUEST ";
|
||||
//pub const P2P_EVENT_GO_NEG_SUCCESS = "P2P-GO-NEG-SUCCESS ";
|
||||
//pub const P2P_EVENT_GO_NEG_FAILURE = "P2P-GO-NEG-FAILURE ";
|
||||
//pub const P2P_EVENT_GROUP_FORMATION_SUCCESS = "P2P-GROUP-FORMATION-SUCCESS ";
|
||||
//pub const P2P_EVENT_GROUP_FORMATION_FAILURE = "P2P-GROUP-FORMATION-FAILURE ";
|
||||
//pub const P2P_EVENT_GROUP_STARTED = "P2P-GROUP-STARTED ";
|
||||
//pub const P2P_EVENT_GROUP_REMOVED = "P2P-GROUP-REMOVED ";
|
||||
//pub const P2P_EVENT_CROSS_CONNECT_ENABLE = "P2P-CROSS-CONNECT-ENABLE ";
|
||||
//pub const P2P_EVENT_CROSS_CONNECT_DISABLE = "P2P-CROSS-CONNECT-DISABLE ";
|
||||
//pub const P2P_EVENT_PROV_DISC_SHOW_PIN = "P2P-PROV-DISC-SHOW-PIN ";
|
||||
//pub const P2P_EVENT_PROV_DISC_ENTER_PIN = "P2P-PROV-DISC-ENTER-PIN ";
|
||||
//pub const P2P_EVENT_PROV_DISC_PBC_REQ = "P2P-PROV-DISC-PBC-REQ ";
|
||||
//pub const P2P_EVENT_PROV_DISC_PBC_RESP = "P2P-PROV-DISC-PBC-RESP ";
|
||||
//pub const P2P_EVENT_PROV_DISC_FAILURE = "P2P-PROV-DISC-FAILURE";
|
||||
//pub const P2P_EVENT_SERV_DISC_REQ = "P2P-SERV-DISC-REQ ";
|
||||
//pub const P2P_EVENT_SERV_DISC_RESP = "P2P-SERV-DISC-RESP ";
|
||||
//pub const P2P_EVENT_SERV_ASP_RESP = "P2P-SERV-ASP-RESP ";
|
||||
//pub const P2P_EVENT_INVITATION_RECEIVED = "P2P-INVITATION-RECEIVED ";
|
||||
//pub const P2P_EVENT_INVITATION_RESULT = "P2P-INVITATION-RESULT ";
|
||||
//pub const P2P_EVENT_INVITATION_ACCEPTED = "P2P-INVITATION-ACCEPTED ";
|
||||
//pub const P2P_EVENT_FIND_STOPPED = "P2P-FIND-STOPPED ";
|
||||
//pub const P2P_EVENT_PERSISTENT_PSK_FAIL = "P2P-PERSISTENT-PSK-FAIL id=";
|
||||
//pub const P2P_EVENT_PRESENCE_RESPONSE = "P2P-PRESENCE-RESPONSE ";
|
||||
//pub const P2P_EVENT_NFC_BOTH_GO = "P2P-NFC-BOTH-GO ";
|
||||
//pub const P2P_EVENT_NFC_PEER_CLIENT = "P2P-NFC-PEER-CLIENT ";
|
||||
//pub const P2P_EVENT_NFC_WHILE_CLIENT = "P2P-NFC-WHILE-CLIENT ";
|
||||
//pub const P2P_EVENT_FALLBACK_TO_GO_NEG = "P2P-FALLBACK-TO-GO-NEG ";
|
||||
//pub const P2P_EVENT_FALLBACK_TO_GO_NEG_ENABLED = "P2P-FALLBACK-TO-GO-NEG-ENABLED ";
|
||||
//pub const ESS_DISASSOC_IMMINENT = "ESS-DISASSOC-IMMINENT ";
|
||||
//pub const P2P_EVENT_REMOVE_AND_REFORM_GROUP = "P2P-REMOVE-AND-REFORM-GROUP ";
|
||||
//pub const P2P_EVENT_P2PS_PROVISION_START = "P2PS-PROV-START ";
|
||||
//pub const P2P_EVENT_P2PS_PROVISION_DONE = "P2PS-PROV-DONE ";
|
||||
//pub const INTERWORKING_AP = "INTERWORKING-AP ";
|
||||
//pub const INTERWORKING_EXCLUDED = "INTERWORKING-BLACKLISTED ";
|
||||
//pub const INTERWORKING_NO_MATCH = "INTERWORKING-NO-MATCH ";
|
||||
//pub const INTERWORKING_ALREADY_CONNECTED = "INTERWORKING-ALREADY-CONNECTED ";
|
||||
//pub const INTERWORKING_SELECTED = "INTERWORKING-SELECTED ";
|
||||
//pub const CRED_ADDED = "CRED-ADDED ";
|
||||
//pub const CRED_MODIFIED = "CRED-MODIFIED ";
|
||||
//pub const CRED_REMOVED = "CRED-REMOVED ";
|
||||
//pub const GAS_RESPONSE_INFO = "GAS-RESPONSE-INFO ";
|
||||
//pub const GAS_QUERY_START = "GAS-QUERY-START ";
|
||||
//pub const GAS_QUERY_DONE = "GAS-QUERY-DONE ";
|
||||
//pub const ANQP_QUERY_DONE = "ANQP-QUERY-DONE ";
|
||||
//pub const RX_ANQP = "RX-ANQP ";
|
||||
//pub const RX_HS20_ANQP = "RX-HS20-ANQP ";
|
||||
//pub const RX_HS20_ANQP_ICON = "RX-HS20-ANQP-ICON ";
|
||||
//pub const RX_HS20_ICON = "RX-HS20-ICON ";
|
||||
//pub const RX_MBO_ANQP = "RX-MBO-ANQP ";
|
||||
//pub const RX_VENUE_URL = "RX-VENUE-URL ";
|
||||
//pub const HS20_SUBSCRIPTION_REMEDIATION = "HS20-SUBSCRIPTION-REMEDIATION ";
|
||||
//pub const HS20_DEAUTH_IMMINENT_NOTICE = "HS20-DEAUTH-IMMINENT-NOTICE ";
|
||||
//pub const HS20_T_C_ACCEPTANCE = "HS20-T-C-ACCEPTANCE ";
|
||||
//pub const EXT_RADIO_WORK_START = "EXT-RADIO-WORK-START ";
|
||||
//pub const EXT_RADIO_WORK_TIMEOUT = "EXT-RADIO-WORK-TIMEOUT ";
|
||||
//pub const RRM_EVENT_NEIGHBOR_REP_RXED = "RRM-NEIGHBOR-REP-RECEIVED ";
|
||||
//pub const RRM_EVENT_NEIGHBOR_REP_FAILED = "RRM-NEIGHBOR-REP-REQUEST-FAILED ";
|
||||
//pub const WPS_EVENT_PIN_NEEDED = "WPS-PIN-NEEDED ";
|
||||
//pub const WPS_EVENT_NEW_AP_SETTINGS = "WPS-NEW-AP-SETTINGS ";
|
||||
//pub const WPS_EVENT_REG_SUCCESS = "WPS-REG-SUCCESS ";
|
||||
//pub const WPS_EVENT_AP_SETUP_LOCKED = "WPS-AP-SETUP-LOCKED ";
|
||||
//pub const WPS_EVENT_AP_SETUP_UNLOCKED = "WPS-AP-SETUP-UNLOCKED ";
|
||||
//pub const WPS_EVENT_AP_PIN_ENABLED = "WPS-AP-PIN-ENABLED ";
|
||||
//pub const WPS_EVENT_AP_PIN_DISABLED = "WPS-AP-PIN-DISABLED ";
|
||||
//pub const WPS_EVENT_PIN_ACTIVE = "WPS-PIN-ACTIVE ";
|
||||
//pub const WPS_EVENT_CANCEL = "WPS-CANCEL ";
|
||||
//pub const AP_STA_CONNECTED = "AP-STA-CONNECTED ";
|
||||
//pub const AP_STA_DISCONNECTED = "AP-STA-DISCONNECTED ";
|
||||
//pub const AP_STA_POSSIBLE_PSK_MISMATCH = "AP-STA-POSSIBLE-PSK-MISMATCH ";
|
||||
//pub const AP_STA_POLL_OK = "AP-STA-POLL-OK ";
|
||||
//pub const AP_REJECTED_MAX_STA = "AP-REJECTED-MAX-STA ";
|
||||
//pub const AP_REJECTED_BLOCKED_STA = "AP-REJECTED-BLOCKED-STA ";
|
||||
//pub const HS20_T_C_FILTERING_ADD = "HS20-T-C-FILTERING-ADD ";
|
||||
//pub const HS20_T_C_FILTERING_REMOVE = "HS20-T-C-FILTERING-REMOVE ";
|
||||
//pub const AP_EVENT_ENABLED = "AP-ENABLED ";
|
||||
//pub const AP_EVENT_DISABLED = "AP-DISABLED ";
|
||||
//pub const INTERFACE_ENABLED = "INTERFACE-ENABLED ";
|
||||
//pub const INTERFACE_DISABLED = "INTERFACE-DISABLED ";
|
||||
//pub const ACS_EVENT_STARTED = "ACS-STARTED ";
|
||||
//pub const ACS_EVENT_COMPLETED = "ACS-COMPLETED ";
|
||||
//pub const ACS_EVENT_FAILED = "ACS-FAILED ";
|
||||
//pub const DFS_EVENT_RADAR_DETECTED = "DFS-RADAR-DETECTED ";
|
||||
//pub const DFS_EVENT_NEW_CHANNEL = "DFS-NEW-CHANNEL ";
|
||||
//pub const DFS_EVENT_CAC_START = "DFS-CAC-START ";
|
||||
//pub const DFS_EVENT_CAC_COMPLETED = "DFS-CAC-COMPLETED ";
|
||||
//pub const DFS_EVENT_NOP_FINISHED = "DFS-NOP-FINISHED ";
|
||||
//pub const DFS_EVENT_PRE_CAC_EXPIRED = "DFS-PRE-CAC-EXPIRED ";
|
||||
//pub const AP_CSA_FINISHED = "AP-CSA-FINISHED ";
|
||||
//pub const P2P_EVENT_LISTEN_OFFLOAD_STOP = "P2P-LISTEN-OFFLOAD-STOPPED ";
|
||||
//pub const P2P_LISTEN_OFFLOAD_STOP_REASON = "P2P-LISTEN-OFFLOAD-STOP-REASON ";
|
||||
//pub const BSS_TM_RESP = "BSS-TM-RESP ";
|
||||
//pub const COLOC_INTF_REQ = "COLOC-INTF-REQ ";
|
||||
//pub const COLOC_INTF_REPORT = "COLOC-INTF-REPORT ";
|
||||
//pub const MBO_CELL_PREFERENCE = "MBO-CELL-PREFERENCE ";
|
@ -0,0 +1,22 @@
|
||||
wpa_supplicant and hostapd
|
||||
--------------------------
|
||||
|
||||
Copyright (c) 2002-2022, Jouni Malinen <j@w1.fi> and contributors
|
||||
All Rights Reserved.
|
||||
|
||||
|
||||
See the README file for the current license terms.
|
||||
|
||||
This software was previously distributed under BSD/GPL v2 dual license
|
||||
terms that allowed either of those license alternatives to be
|
||||
selected. As of February 11, 2012, the project has chosen to use only
|
||||
the BSD license option for future distribution. As such, the GPL v2
|
||||
license option is no longer used. It should be noted that the BSD
|
||||
license option (the one with advertisement clause removed) is compatible
|
||||
with GPL and as such, does not prevent use of this software in projects
|
||||
that use GPL.
|
||||
|
||||
Some of the files may still include pointers to GPL version 2 license
|
||||
terms. However, such copyright and license notifications are maintained
|
||||
only for attribution purposes and any distribution of this software
|
||||
after February 11, 2012 is no longer under the GPL v2 option.
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,56 @@
|
||||
wpa_supplicant and hostapd
|
||||
--------------------------
|
||||
|
||||
Copyright (c) 2002-2022, Jouni Malinen <j@w1.fi> and contributors
|
||||
All Rights Reserved.
|
||||
|
||||
These programs are licensed under the BSD license (the one with
|
||||
advertisement clause removed).
|
||||
|
||||
If you are submitting changes to the project, please see CONTRIBUTIONS
|
||||
file for more instructions.
|
||||
|
||||
|
||||
This package may include either wpa_supplicant, hostapd, or both. See
|
||||
README file respective subdirectories (wpa_supplicant/README or
|
||||
hostapd/README) for more details.
|
||||
|
||||
Source code files were moved around in v0.6.x releases and compared to
|
||||
earlier releases, the programs are now built by first going to a
|
||||
subdirectory (wpa_supplicant or hostapd) and creating build
|
||||
configuration (.config) and running 'make' there (for Linux/BSD/cygwin
|
||||
builds).
|
||||
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
This software may be distributed, used, and modified under the terms of
|
||||
BSD license:
|
||||
|
||||
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, 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.
|
||||
|
||||
3. Neither the name(s) of the above-listed copyright holder(s) nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"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 COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS 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.
|
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* wpa_supplicant/hostapd - Build time configuration defines
|
||||
* Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*
|
||||
* This header file can be used to define configuration defines that were
|
||||
* originally defined in Makefile. This is mainly meant for IDE use or for
|
||||
* systems that do not have suitable 'make' tool. In these cases, it may be
|
||||
* easier to have a single place for defining all the needed C pre-processor
|
||||
* defines.
|
||||
*/
|
||||
|
||||
#ifndef BUILD_CONFIG_H
|
||||
#define BUILD_CONFIG_H
|
||||
|
||||
/* Insert configuration defines, e.g., #define EAP_MD5, here, if needed. */
|
||||
|
||||
#ifdef CONFIG_WIN32_DEFAULTS
|
||||
#define CONFIG_NATIVE_WINDOWS
|
||||
#define CONFIG_ANSI_C_EXTRA
|
||||
#define CONFIG_WINPCAP
|
||||
#define IEEE8021X_EAPOL
|
||||
#define PKCS12_FUNCS
|
||||
#define PCSC_FUNCS
|
||||
#define CONFIG_CTRL_IFACE
|
||||
#define CONFIG_CTRL_IFACE_NAMED_PIPE
|
||||
#define CONFIG_DRIVER_NDIS
|
||||
#define CONFIG_NDIS_EVENTS_INTEGRATED
|
||||
#define CONFIG_DEBUG_FILE
|
||||
#define EAP_MD5
|
||||
#define EAP_TLS
|
||||
#define EAP_MSCHAPv2
|
||||
#define EAP_PEAP
|
||||
#define EAP_TTLS
|
||||
#define EAP_GTC
|
||||
#define EAP_OTP
|
||||
#define EAP_LEAP
|
||||
#define EAP_TNC
|
||||
#define _CRT_SECURE_NO_DEPRECATE
|
||||
|
||||
#ifdef USE_INTERNAL_CRYPTO
|
||||
#define CONFIG_TLS_INTERNAL_CLIENT
|
||||
#define CONFIG_INTERNAL_LIBTOMMATH
|
||||
#define CONFIG_CRYPTO_INTERNAL
|
||||
#endif /* USE_INTERNAL_CRYPTO */
|
||||
#endif /* CONFIG_WIN32_DEFAULTS */
|
||||
|
||||
#endif /* BUILD_CONFIG_H */
|
@ -0,0 +1,598 @@
|
||||
/*
|
||||
* wpa_supplicant/hostapd / common helper functions, etc.
|
||||
* Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef COMMON_H
|
||||
#define COMMON_H
|
||||
|
||||
#include "os.h"
|
||||
|
||||
#if defined(__linux__) || defined(__GLIBC__)
|
||||
#include <endian.h>
|
||||
#include <byteswap.h>
|
||||
#endif /* __linux__ */
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || \
|
||||
defined(__OpenBSD__)
|
||||
#include <sys/types.h>
|
||||
#include <sys/endian.h>
|
||||
#define __BYTE_ORDER _BYTE_ORDER
|
||||
#define __LITTLE_ENDIAN _LITTLE_ENDIAN
|
||||
#define __BIG_ENDIAN _BIG_ENDIAN
|
||||
#ifdef __OpenBSD__
|
||||
#define bswap_16 swap16
|
||||
#define bswap_32 swap32
|
||||
#define bswap_64 swap64
|
||||
#else /* __OpenBSD__ */
|
||||
#define bswap_16 bswap16
|
||||
#define bswap_32 bswap32
|
||||
#define bswap_64 bswap64
|
||||
#endif /* __OpenBSD__ */
|
||||
#endif /* defined(__FreeBSD__) || defined(__NetBSD__) ||
|
||||
* defined(__DragonFly__) || defined(__OpenBSD__) */
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <sys/types.h>
|
||||
#include <machine/endian.h>
|
||||
#define __BYTE_ORDER _BYTE_ORDER
|
||||
#define __LITTLE_ENDIAN _LITTLE_ENDIAN
|
||||
#define __BIG_ENDIAN _BIG_ENDIAN
|
||||
static inline unsigned short bswap_16(unsigned short v)
|
||||
{
|
||||
return ((v & 0xff) << 8) | (v >> 8);
|
||||
}
|
||||
|
||||
static inline unsigned int bswap_32(unsigned int v)
|
||||
{
|
||||
return ((v & 0xff) << 24) | ((v & 0xff00) << 8) |
|
||||
((v & 0xff0000) >> 8) | (v >> 24);
|
||||
}
|
||||
#endif /* __APPLE__ */
|
||||
|
||||
#ifdef __rtems__
|
||||
#include <rtems/endian.h>
|
||||
#define __BYTE_ORDER BYTE_ORDER
|
||||
#define __LITTLE_ENDIAN LITTLE_ENDIAN
|
||||
#define __BIG_ENDIAN BIG_ENDIAN
|
||||
#define bswap_16 CPU_swap_u16
|
||||
#define bswap_32 CPU_swap_u32
|
||||
#endif /* __rtems__ */
|
||||
|
||||
#ifdef CONFIG_NATIVE_WINDOWS
|
||||
#include <winsock.h>
|
||||
|
||||
typedef int socklen_t;
|
||||
|
||||
#ifndef MSG_DONTWAIT
|
||||
#define MSG_DONTWAIT 0 /* not supported */
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_NATIVE_WINDOWS */
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define inline __inline
|
||||
|
||||
#undef vsnprintf
|
||||
#define vsnprintf _vsnprintf
|
||||
#undef close
|
||||
#define close closesocket
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
|
||||
/* Define platform specific integer types */
|
||||
|
||||
#ifdef _MSC_VER
|
||||
typedef UINT64 u64;
|
||||
typedef UINT32 u32;
|
||||
typedef UINT16 u16;
|
||||
typedef UINT8 u8;
|
||||
typedef INT64 s64;
|
||||
typedef INT32 s32;
|
||||
typedef INT16 s16;
|
||||
typedef INT8 s8;
|
||||
#define WPA_TYPES_DEFINED
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
#ifdef __vxworks
|
||||
typedef unsigned long long u64;
|
||||
typedef UINT32 u32;
|
||||
typedef UINT16 u16;
|
||||
typedef UINT8 u8;
|
||||
typedef long long s64;
|
||||
typedef INT32 s32;
|
||||
typedef INT16 s16;
|
||||
typedef INT8 s8;
|
||||
#define WPA_TYPES_DEFINED
|
||||
#endif /* __vxworks */
|
||||
|
||||
#ifndef WPA_TYPES_DEFINED
|
||||
#ifdef CONFIG_USE_INTTYPES_H
|
||||
#include <inttypes.h>
|
||||
#else
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
typedef uint64_t u64;
|
||||
typedef uint32_t u32;
|
||||
typedef uint16_t u16;
|
||||
typedef uint8_t u8;
|
||||
typedef int64_t s64;
|
||||
typedef int32_t s32;
|
||||
typedef int16_t s16;
|
||||
typedef int8_t s8;
|
||||
#define WPA_TYPES_DEFINED
|
||||
#endif /* !WPA_TYPES_DEFINED */
|
||||
|
||||
|
||||
/* Define platform specific byte swapping macros */
|
||||
|
||||
#if defined(__CYGWIN__) || defined(CONFIG_NATIVE_WINDOWS)
|
||||
|
||||
static inline unsigned short wpa_swap_16(unsigned short v)
|
||||
{
|
||||
return ((v & 0xff) << 8) | (v >> 8);
|
||||
}
|
||||
|
||||
static inline unsigned int wpa_swap_32(unsigned int v)
|
||||
{
|
||||
return ((v & 0xff) << 24) | ((v & 0xff00) << 8) |
|
||||
((v & 0xff0000) >> 8) | (v >> 24);
|
||||
}
|
||||
|
||||
#define le_to_host16(n) (n)
|
||||
#define host_to_le16(n) (n)
|
||||
#define be_to_host16(n) wpa_swap_16(n)
|
||||
#define host_to_be16(n) wpa_swap_16(n)
|
||||
#define le_to_host32(n) (n)
|
||||
#define host_to_le32(n) (n)
|
||||
#define be_to_host32(n) wpa_swap_32(n)
|
||||
#define host_to_be32(n) wpa_swap_32(n)
|
||||
#define host_to_le64(n) (n)
|
||||
|
||||
#define WPA_BYTE_SWAP_DEFINED
|
||||
|
||||
#endif /* __CYGWIN__ || CONFIG_NATIVE_WINDOWS */
|
||||
|
||||
|
||||
#ifndef WPA_BYTE_SWAP_DEFINED
|
||||
|
||||
#ifndef __BYTE_ORDER
|
||||
#ifndef __LITTLE_ENDIAN
|
||||
#ifndef __BIG_ENDIAN
|
||||
#define __LITTLE_ENDIAN 1234
|
||||
#define __BIG_ENDIAN 4321
|
||||
#if defined(sparc)
|
||||
#define __BYTE_ORDER __BIG_ENDIAN
|
||||
#endif
|
||||
#endif /* __BIG_ENDIAN */
|
||||
#endif /* __LITTLE_ENDIAN */
|
||||
#endif /* __BYTE_ORDER */
|
||||
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
#define le_to_host16(n) ((__force u16) (le16) (n))
|
||||
#define host_to_le16(n) ((__force le16) (u16) (n))
|
||||
#define be_to_host16(n) bswap_16((__force u16) (be16) (n))
|
||||
#define host_to_be16(n) ((__force be16) bswap_16((n)))
|
||||
#define le_to_host32(n) ((__force u32) (le32) (n))
|
||||
#define host_to_le32(n) ((__force le32) (u32) (n))
|
||||
#define be_to_host32(n) bswap_32((__force u32) (be32) (n))
|
||||
#define host_to_be32(n) ((__force be32) bswap_32((n)))
|
||||
#define le_to_host64(n) ((__force u64) (le64) (n))
|
||||
#define host_to_le64(n) ((__force le64) (u64) (n))
|
||||
#define be_to_host64(n) bswap_64((__force u64) (be64) (n))
|
||||
#define host_to_be64(n) ((__force be64) bswap_64((n)))
|
||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
#define le_to_host16(n) bswap_16(n)
|
||||
#define host_to_le16(n) bswap_16(n)
|
||||
#define be_to_host16(n) (n)
|
||||
#define host_to_be16(n) (n)
|
||||
#define le_to_host32(n) bswap_32(n)
|
||||
#define host_to_le32(n) bswap_32(n)
|
||||
#define be_to_host32(n) (n)
|
||||
#define host_to_be32(n) (n)
|
||||
#define le_to_host64(n) bswap_64(n)
|
||||
#define host_to_le64(n) bswap_64(n)
|
||||
#define be_to_host64(n) (n)
|
||||
#define host_to_be64(n) (n)
|
||||
#ifndef WORDS_BIGENDIAN
|
||||
#define WORDS_BIGENDIAN
|
||||
#endif
|
||||
#else
|
||||
#error Could not determine CPU byte order
|
||||
#endif
|
||||
|
||||
#define WPA_BYTE_SWAP_DEFINED
|
||||
#endif /* !WPA_BYTE_SWAP_DEFINED */
|
||||
|
||||
|
||||
/* Macros for handling unaligned memory accesses */
|
||||
|
||||
static inline u16 WPA_GET_BE16(const u8 *a)
|
||||
{
|
||||
return (a[0] << 8) | a[1];
|
||||
}
|
||||
|
||||
static inline void WPA_PUT_BE16(u8 *a, u16 val)
|
||||
{
|
||||
a[0] = val >> 8;
|
||||
a[1] = val & 0xff;
|
||||
}
|
||||
|
||||
static inline u16 WPA_GET_LE16(const u8 *a)
|
||||
{
|
||||
return (a[1] << 8) | a[0];
|
||||
}
|
||||
|
||||
static inline void WPA_PUT_LE16(u8 *a, u16 val)
|
||||
{
|
||||
a[1] = val >> 8;
|
||||
a[0] = val & 0xff;
|
||||
}
|
||||
|
||||
static inline u32 WPA_GET_BE24(const u8 *a)
|
||||
{
|
||||
return (a[0] << 16) | (a[1] << 8) | a[2];
|
||||
}
|
||||
|
||||
static inline void WPA_PUT_BE24(u8 *a, u32 val)
|
||||
{
|
||||
a[0] = (val >> 16) & 0xff;
|
||||
a[1] = (val >> 8) & 0xff;
|
||||
a[2] = val & 0xff;
|
||||
}
|
||||
|
||||
static inline u32 WPA_GET_BE32(const u8 *a)
|
||||
{
|
||||
return ((u32) a[0] << 24) | (a[1] << 16) | (a[2] << 8) | a[3];
|
||||
}
|
||||
|
||||
static inline void WPA_PUT_BE32(u8 *a, u32 val)
|
||||
{
|
||||
a[0] = (val >> 24) & 0xff;
|
||||
a[1] = (val >> 16) & 0xff;
|
||||
a[2] = (val >> 8) & 0xff;
|
||||
a[3] = val & 0xff;
|
||||
}
|
||||
|
||||
static inline u32 WPA_GET_LE32(const u8 *a)
|
||||
{
|
||||
return ((u32) a[3] << 24) | (a[2] << 16) | (a[1] << 8) | a[0];
|
||||
}
|
||||
|
||||
static inline void WPA_PUT_LE32(u8 *a, u32 val)
|
||||
{
|
||||
a[3] = (val >> 24) & 0xff;
|
||||
a[2] = (val >> 16) & 0xff;
|
||||
a[1] = (val >> 8) & 0xff;
|
||||
a[0] = val & 0xff;
|
||||
}
|
||||
|
||||
static inline u64 WPA_GET_BE64(const u8 *a)
|
||||
{
|
||||
return (((u64) a[0]) << 56) | (((u64) a[1]) << 48) |
|
||||
(((u64) a[2]) << 40) | (((u64) a[3]) << 32) |
|
||||
(((u64) a[4]) << 24) | (((u64) a[5]) << 16) |
|
||||
(((u64) a[6]) << 8) | ((u64) a[7]);
|
||||
}
|
||||
|
||||
static inline void WPA_PUT_BE64(u8 *a, u64 val)
|
||||
{
|
||||
a[0] = val >> 56;
|
||||
a[1] = val >> 48;
|
||||
a[2] = val >> 40;
|
||||
a[3] = val >> 32;
|
||||
a[4] = val >> 24;
|
||||
a[5] = val >> 16;
|
||||
a[6] = val >> 8;
|
||||
a[7] = val & 0xff;
|
||||
}
|
||||
|
||||
static inline u64 WPA_GET_LE64(const u8 *a)
|
||||
{
|
||||
return (((u64) a[7]) << 56) | (((u64) a[6]) << 48) |
|
||||
(((u64) a[5]) << 40) | (((u64) a[4]) << 32) |
|
||||
(((u64) a[3]) << 24) | (((u64) a[2]) << 16) |
|
||||
(((u64) a[1]) << 8) | ((u64) a[0]);
|
||||
}
|
||||
|
||||
static inline void WPA_PUT_LE64(u8 *a, u64 val)
|
||||
{
|
||||
a[7] = val >> 56;
|
||||
a[6] = val >> 48;
|
||||
a[5] = val >> 40;
|
||||
a[4] = val >> 32;
|
||||
a[3] = val >> 24;
|
||||
a[2] = val >> 16;
|
||||
a[1] = val >> 8;
|
||||
a[0] = val & 0xff;
|
||||
}
|
||||
|
||||
|
||||
#ifndef ETH_ALEN
|
||||
#define ETH_ALEN 6
|
||||
#endif
|
||||
#ifndef ETH_HLEN
|
||||
#define ETH_HLEN 14
|
||||
#endif
|
||||
#ifndef IFNAMSIZ
|
||||
#define IFNAMSIZ 16
|
||||
#endif
|
||||
#ifndef ETH_P_ALL
|
||||
#define ETH_P_ALL 0x0003
|
||||
#endif
|
||||
#ifndef ETH_P_IP
|
||||
#define ETH_P_IP 0x0800
|
||||
#endif
|
||||
#ifndef ETH_P_80211_ENCAP
|
||||
#define ETH_P_80211_ENCAP 0x890d /* TDLS comes under this category */
|
||||
#endif
|
||||
#ifndef ETH_P_PAE
|
||||
#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */
|
||||
#endif /* ETH_P_PAE */
|
||||
#ifndef ETH_P_EAPOL
|
||||
#define ETH_P_EAPOL ETH_P_PAE
|
||||
#endif /* ETH_P_EAPOL */
|
||||
#ifndef ETH_P_RSN_PREAUTH
|
||||
#define ETH_P_RSN_PREAUTH 0x88c7
|
||||
#endif /* ETH_P_RSN_PREAUTH */
|
||||
#ifndef ETH_P_RRB
|
||||
#define ETH_P_RRB 0x890D
|
||||
#endif /* ETH_P_RRB */
|
||||
#ifndef ETH_P_OUI
|
||||
#define ETH_P_OUI 0x88B7
|
||||
#endif /* ETH_P_OUI */
|
||||
#ifndef ETH_P_8021Q
|
||||
#define ETH_P_8021Q 0x8100
|
||||
#endif /* ETH_P_8021Q */
|
||||
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define PRINTF_FORMAT(a,b) __attribute__ ((format (printf, (a), (b))))
|
||||
#define STRUCT_PACKED __attribute__ ((packed))
|
||||
#else
|
||||
#define PRINTF_FORMAT(a,b)
|
||||
#define STRUCT_PACKED
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef CONFIG_ANSI_C_EXTRA
|
||||
|
||||
#if !defined(_MSC_VER) || _MSC_VER < 1400
|
||||
/* snprintf - used in number of places; sprintf() is _not_ a good replacement
|
||||
* due to possible buffer overflow; see, e.g.,
|
||||
* http://www.ijs.si/software/snprintf/ for portable implementation of
|
||||
* snprintf. */
|
||||
int snprintf(char *str, size_t size, const char *format, ...);
|
||||
|
||||
/* vsnprintf - only used for wpa_msg() in wpa_supplicant.c */
|
||||
int vsnprintf(char *str, size_t size, const char *format, va_list ap);
|
||||
#endif /* !defined(_MSC_VER) || _MSC_VER < 1400 */
|
||||
|
||||
/* getopt - only used in main.c */
|
||||
int getopt(int argc, char *const argv[], const char *optstring);
|
||||
extern char *optarg;
|
||||
extern int optind;
|
||||
|
||||
#ifndef CONFIG_NO_SOCKLEN_T_TYPEDEF
|
||||
#ifndef __socklen_t_defined
|
||||
typedef int socklen_t;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* inline - define as __inline or just define it to be empty, if needed */
|
||||
#ifdef CONFIG_NO_INLINE
|
||||
#define inline
|
||||
#else
|
||||
#define inline __inline
|
||||
#endif
|
||||
|
||||
#ifndef __func__
|
||||
#define __func__ "__func__ not defined"
|
||||
#endif
|
||||
|
||||
#ifndef bswap_16
|
||||
#define bswap_16(a) ((((u16) (a) << 8) & 0xff00) | (((u16) (a) >> 8) & 0xff))
|
||||
#endif
|
||||
|
||||
#ifndef bswap_32
|
||||
#define bswap_32(a) ((((u32) (a) << 24) & 0xff000000) | \
|
||||
(((u32) (a) << 8) & 0xff0000) | \
|
||||
(((u32) (a) >> 8) & 0xff00) | \
|
||||
(((u32) (a) >> 24) & 0xff))
|
||||
#endif
|
||||
|
||||
#ifndef MSG_DONTWAIT
|
||||
#define MSG_DONTWAIT 0
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32_WCE
|
||||
void perror(const char *s);
|
||||
#endif /* _WIN32_WCE */
|
||||
|
||||
#endif /* CONFIG_ANSI_C_EXTRA */
|
||||
|
||||
#ifndef MAC2STR
|
||||
#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
|
||||
#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
|
||||
|
||||
/*
|
||||
* Compact form for string representation of MAC address
|
||||
* To be used, e.g., for constructing dbus paths for P2P Devices
|
||||
*/
|
||||
#define COMPACT_MACSTR "%02x%02x%02x%02x%02x%02x"
|
||||
#endif
|
||||
|
||||
#ifndef BIT
|
||||
#define BIT(x) (1U << (x))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Definitions for sparse validation
|
||||
* (http://kernel.org/pub/linux/kernel/people/josh/sparse/)
|
||||
*/
|
||||
#ifdef __CHECKER__
|
||||
#define __force __attribute__((force))
|
||||
#undef __bitwise
|
||||
#define __bitwise __attribute__((bitwise))
|
||||
#else
|
||||
#define __force
|
||||
#undef __bitwise
|
||||
#define __bitwise
|
||||
#endif
|
||||
|
||||
typedef u16 __bitwise be16;
|
||||
typedef u16 __bitwise le16;
|
||||
typedef u32 __bitwise be32;
|
||||
typedef u32 __bitwise le32;
|
||||
typedef u64 __bitwise be64;
|
||||
typedef u64 __bitwise le64;
|
||||
|
||||
#ifndef __must_check
|
||||
#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
|
||||
#define __must_check __attribute__((__warn_unused_result__))
|
||||
#else
|
||||
#define __must_check
|
||||
#endif /* __GNUC__ */
|
||||
#endif /* __must_check */
|
||||
|
||||
#ifndef __maybe_unused
|
||||
#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
|
||||
#define __maybe_unused __attribute__((unused))
|
||||
#else
|
||||
#define __maybe_unused
|
||||
#endif /* __GNUC__ */
|
||||
#endif /* __must_check */
|
||||
|
||||
#define SSID_MAX_LEN 32
|
||||
|
||||
struct wpa_ssid_value {
|
||||
u8 ssid[SSID_MAX_LEN];
|
||||
size_t ssid_len;
|
||||
};
|
||||
|
||||
int hwaddr_aton(const char *txt, u8 *addr);
|
||||
int hwaddr_masked_aton(const char *txt, u8 *addr, u8 *mask, u8 maskable);
|
||||
int hwaddr_compact_aton(const char *txt, u8 *addr);
|
||||
int hwaddr_aton2(const char *txt, u8 *addr);
|
||||
int hex2byte(const char *hex);
|
||||
int hexstr2bin(const char *hex, u8 *buf, size_t len);
|
||||
void inc_byte_array(u8 *counter, size_t len);
|
||||
void buf_shift_right(u8 *buf, size_t len, size_t bits);
|
||||
void wpa_get_ntp_timestamp(u8 *buf);
|
||||
int wpa_scnprintf(char *buf, size_t size, const char *fmt, ...)
|
||||
PRINTF_FORMAT(3, 4);
|
||||
int wpa_snprintf_hex_sep(char *buf, size_t buf_size, const u8 *data, size_t len,
|
||||
char sep);
|
||||
int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len);
|
||||
int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data,
|
||||
size_t len);
|
||||
|
||||
int hwaddr_mask_txt(char *buf, size_t len, const u8 *addr, const u8 *mask);
|
||||
int ssid_parse(const char *buf, struct wpa_ssid_value *ssid);
|
||||
|
||||
#ifdef CONFIG_NATIVE_WINDOWS
|
||||
void wpa_unicode2ascii_inplace(TCHAR *str);
|
||||
TCHAR * wpa_strdup_tchar(const char *str);
|
||||
#else /* CONFIG_NATIVE_WINDOWS */
|
||||
#define wpa_unicode2ascii_inplace(s) do { } while (0)
|
||||
#define wpa_strdup_tchar(s) strdup((s))
|
||||
#endif /* CONFIG_NATIVE_WINDOWS */
|
||||
|
||||
void printf_encode(char *txt, size_t maxlen, const u8 *data, size_t len);
|
||||
size_t printf_decode(u8 *buf, size_t maxlen, const char *str);
|
||||
|
||||
const char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len);
|
||||
|
||||
char * wpa_config_parse_string(const char *value, size_t *len);
|
||||
int is_hex(const u8 *data, size_t len);
|
||||
int has_ctrl_char(const u8 *data, size_t len);
|
||||
int has_newline(const char *str);
|
||||
size_t merge_byte_arrays(u8 *res, size_t res_len,
|
||||
const u8 *src1, size_t src1_len,
|
||||
const u8 *src2, size_t src2_len);
|
||||
char * dup_binstr(const void *src, size_t len);
|
||||
|
||||
static inline int is_zero_ether_addr(const u8 *a)
|
||||
{
|
||||
return !(a[0] | a[1] | a[2] | a[3] | a[4] | a[5]);
|
||||
}
|
||||
|
||||
static inline int is_broadcast_ether_addr(const u8 *a)
|
||||
{
|
||||
return (a[0] & a[1] & a[2] & a[3] & a[4] & a[5]) == 0xff;
|
||||
}
|
||||
|
||||
static inline int is_multicast_ether_addr(const u8 *a)
|
||||
{
|
||||
return a[0] & 0x01;
|
||||
}
|
||||
|
||||
#define broadcast_ether_addr (const u8 *) "\xff\xff\xff\xff\xff\xff"
|
||||
|
||||
#include "wpa_debug.h"
|
||||
|
||||
|
||||
struct wpa_freq_range_list {
|
||||
struct wpa_freq_range {
|
||||
unsigned int min;
|
||||
unsigned int max;
|
||||
} *range;
|
||||
unsigned int num;
|
||||
};
|
||||
|
||||
int freq_range_list_parse(struct wpa_freq_range_list *res, const char *value);
|
||||
int freq_range_list_includes(const struct wpa_freq_range_list *list,
|
||||
unsigned int freq);
|
||||
char * freq_range_list_str(const struct wpa_freq_range_list *list);
|
||||
|
||||
size_t int_array_len(const int *a);
|
||||
void int_array_concat(int **res, const int *a);
|
||||
void int_array_sort_unique(int *a);
|
||||
void int_array_add_unique(int **res, int a);
|
||||
|
||||
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
|
||||
|
||||
void str_clear_free(char *str);
|
||||
void bin_clear_free(void *bin, size_t len);
|
||||
|
||||
int random_mac_addr(u8 *addr);
|
||||
int random_mac_addr_keep_oui(u8 *addr);
|
||||
|
||||
const char * cstr_token(const char *str, const char *delim, const char **last);
|
||||
char * str_token(char *str, const char *delim, char **context);
|
||||
size_t utf8_escape(const char *inp, size_t in_size,
|
||||
char *outp, size_t out_size);
|
||||
size_t utf8_unescape(const char *inp, size_t in_size,
|
||||
char *outp, size_t out_size);
|
||||
int is_ctrl_char(char c);
|
||||
|
||||
int str_starts(const char *str, const char *start);
|
||||
|
||||
u8 rssi_to_rcpi(int rssi);
|
||||
char * get_param(const char *cmd, const char *param);
|
||||
|
||||
void forced_memzero(void *ptr, size_t len);
|
||||
|
||||
/*
|
||||
* gcc 4.4 ends up generating strict-aliasing warnings about some very common
|
||||
* networking socket uses that do not really result in a real problem and
|
||||
* cannot be easily avoided with union-based type-punning due to struct
|
||||
* definitions including another struct in system header files. To avoid having
|
||||
* to fully disable strict-aliasing warnings, provide a mechanism to hide the
|
||||
* typecast from aliasing for now. A cleaner solution will hopefully be found
|
||||
* in the future to handle these cases.
|
||||
*/
|
||||
void * __hide_aliasing_typecast(void *foo);
|
||||
#define aliasing_hide_typecast(a,t) (t *) __hide_aliasing_typecast((a))
|
||||
|
||||
#ifdef CONFIG_VALGRIND
|
||||
#include <valgrind/memcheck.h>
|
||||
#define WPA_MEM_DEFINED(ptr, len) VALGRIND_MAKE_MEM_DEFINED((ptr), (len))
|
||||
#else /* CONFIG_VALGRIND */
|
||||
#define WPA_MEM_DEFINED(ptr, len) do { } while (0)
|
||||
#endif /* CONFIG_VALGRIND */
|
||||
|
||||
#endif /* COMMON_H */
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* wpa_supplicant/hostapd - Default include files
|
||||
* Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*
|
||||
* This header file is included into all C files so that commonly used header
|
||||
* files can be selected with OS specific ifdef blocks in one place instead of
|
||||
* having to have OS/C library specific selection in many files.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDES_H
|
||||
#define INCLUDES_H
|
||||
|
||||
/* Include possible build time configuration before including anything else */
|
||||
#include "build_config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#ifndef _WIN32_WCE
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <errno.h>
|
||||
#endif /* _WIN32_WCE */
|
||||
#include <ctype.h>
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#include <unistd.h>
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
#ifndef CONFIG_NATIVE_WINDOWS
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#ifndef __vxworks
|
||||
#include <sys/uio.h>
|
||||
#include <sys/time.h>
|
||||
#endif /* __vxworks */
|
||||
#endif /* CONFIG_NATIVE_WINDOWS */
|
||||
|
||||
#endif /* INCLUDES_H */
|
@ -0,0 +1,680 @@
|
||||
/*
|
||||
* OS specific functions
|
||||
* Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef OS_H
|
||||
#define OS_H
|
||||
|
||||
typedef long os_time_t;
|
||||
|
||||
/**
|
||||
* os_sleep - Sleep (sec, usec)
|
||||
* @sec: Number of seconds to sleep
|
||||
* @usec: Number of microseconds to sleep
|
||||
*/
|
||||
void os_sleep(os_time_t sec, os_time_t usec);
|
||||
|
||||
struct os_time {
|
||||
os_time_t sec;
|
||||
os_time_t usec;
|
||||
};
|
||||
|
||||
struct os_reltime {
|
||||
os_time_t sec;
|
||||
os_time_t usec;
|
||||
};
|
||||
|
||||
/**
|
||||
* os_get_time - Get current time (sec, usec)
|
||||
* @t: Pointer to buffer for the time
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*/
|
||||
int os_get_time(struct os_time *t);
|
||||
|
||||
/**
|
||||
* os_get_reltime - Get relative time (sec, usec)
|
||||
* @t: Pointer to buffer for the time
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*/
|
||||
int os_get_reltime(struct os_reltime *t);
|
||||
|
||||
|
||||
/* Helpers for handling struct os_time */
|
||||
|
||||
static inline int os_time_before(struct os_time *a, struct os_time *b)
|
||||
{
|
||||
return (a->sec < b->sec) ||
|
||||
(a->sec == b->sec && a->usec < b->usec);
|
||||
}
|
||||
|
||||
|
||||
static inline void os_time_sub(struct os_time *a, struct os_time *b,
|
||||
struct os_time *res)
|
||||
{
|
||||
res->sec = a->sec - b->sec;
|
||||
res->usec = a->usec - b->usec;
|
||||
if (res->usec < 0) {
|
||||
res->sec--;
|
||||
res->usec += 1000000;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Helpers for handling struct os_reltime */
|
||||
|
||||
static inline int os_reltime_before(struct os_reltime *a,
|
||||
struct os_reltime *b)
|
||||
{
|
||||
return (a->sec < b->sec) ||
|
||||
(a->sec == b->sec && a->usec < b->usec);
|
||||
}
|
||||
|
||||
|
||||
static inline void os_reltime_sub(struct os_reltime *a, struct os_reltime *b,
|
||||
struct os_reltime *res)
|
||||
{
|
||||
res->sec = a->sec - b->sec;
|
||||
res->usec = a->usec - b->usec;
|
||||
if (res->usec < 0) {
|
||||
res->sec--;
|
||||
res->usec += 1000000;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static inline void os_reltime_age(struct os_reltime *start,
|
||||
struct os_reltime *age)
|
||||
{
|
||||
struct os_reltime now;
|
||||
|
||||
os_get_reltime(&now);
|
||||
os_reltime_sub(&now, start, age);
|
||||
}
|
||||
|
||||
|
||||
static inline int os_reltime_expired(struct os_reltime *now,
|
||||
struct os_reltime *ts,
|
||||
os_time_t timeout_secs)
|
||||
{
|
||||
struct os_reltime age;
|
||||
|
||||
os_reltime_sub(now, ts, &age);
|
||||
return (age.sec > timeout_secs) ||
|
||||
(age.sec == timeout_secs && age.usec > 0);
|
||||
}
|
||||
|
||||
|
||||
static inline int os_reltime_initialized(struct os_reltime *t)
|
||||
{
|
||||
return t->sec != 0 || t->usec != 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* os_mktime - Convert broken-down time into seconds since 1970-01-01
|
||||
* @year: Four digit year
|
||||
* @month: Month (1 .. 12)
|
||||
* @day: Day of month (1 .. 31)
|
||||
* @hour: Hour (0 .. 23)
|
||||
* @min: Minute (0 .. 59)
|
||||
* @sec: Second (0 .. 60)
|
||||
* @t: Buffer for returning calendar time representation (seconds since
|
||||
* 1970-01-01 00:00:00)
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*
|
||||
* Note: The result is in seconds from Epoch, i.e., in UTC, not in local time
|
||||
* which is used by POSIX mktime().
|
||||
*/
|
||||
int os_mktime(int year, int month, int day, int hour, int min, int sec,
|
||||
os_time_t *t);
|
||||
|
||||
struct os_tm {
|
||||
int sec; /* 0..59 or 60 for leap seconds */
|
||||
int min; /* 0..59 */
|
||||
int hour; /* 0..23 */
|
||||
int day; /* 1..31 */
|
||||
int month; /* 1..12 */
|
||||
int year; /* Four digit year */
|
||||
};
|
||||
|
||||
int os_gmtime(os_time_t t, struct os_tm *tm);
|
||||
|
||||
/**
|
||||
* os_daemonize - Run in the background (detach from the controlling terminal)
|
||||
* @pid_file: File name to write the process ID to or %NULL to skip this
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*/
|
||||
int os_daemonize(const char *pid_file);
|
||||
|
||||
/**
|
||||
* os_daemonize_terminate - Stop running in the background (remove pid file)
|
||||
* @pid_file: File name to write the process ID to or %NULL to skip this
|
||||
*/
|
||||
void os_daemonize_terminate(const char *pid_file);
|
||||
|
||||
/**
|
||||
* os_get_random - Get cryptographically strong pseudo random data
|
||||
* @buf: Buffer for pseudo random data
|
||||
* @len: Length of the buffer
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*/
|
||||
int os_get_random(unsigned char *buf, size_t len);
|
||||
|
||||
/**
|
||||
* os_random - Get pseudo random value (not necessarily very strong)
|
||||
* Returns: Pseudo random value
|
||||
*/
|
||||
unsigned long os_random(void);
|
||||
|
||||
/**
|
||||
* os_rel2abs_path - Get an absolute path for a file
|
||||
* @rel_path: Relative path to a file
|
||||
* Returns: Absolute path for the file or %NULL on failure
|
||||
*
|
||||
* This function tries to convert a relative path of a file to an absolute path
|
||||
* in order for the file to be found even if current working directory has
|
||||
* changed. The returned value is allocated and caller is responsible for
|
||||
* freeing it. It is acceptable to just return the same path in an allocated
|
||||
* buffer, e.g., return strdup(rel_path). This function is only used to find
|
||||
* configuration files when os_daemonize() may have changed the current working
|
||||
* directory and relative path would be pointing to a different location.
|
||||
*/
|
||||
char * os_rel2abs_path(const char *rel_path);
|
||||
|
||||
/**
|
||||
* os_program_init - Program initialization (called at start)
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*
|
||||
* This function is called when a programs starts. If there are any OS specific
|
||||
* processing that is needed, it can be placed here. It is also acceptable to
|
||||
* just return 0 if not special processing is needed.
|
||||
*/
|
||||
int os_program_init(void);
|
||||
|
||||
/**
|
||||
* os_program_deinit - Program deinitialization (called just before exit)
|
||||
*
|
||||
* This function is called just before a program exists. If there are any OS
|
||||
* specific processing, e.g., freeing resourced allocated in os_program_init(),
|
||||
* it should be done here. It is also acceptable for this function to do
|
||||
* nothing.
|
||||
*/
|
||||
void os_program_deinit(void);
|
||||
|
||||
/**
|
||||
* os_setenv - Set environment variable
|
||||
* @name: Name of the variable
|
||||
* @value: Value to set to the variable
|
||||
* @overwrite: Whether existing variable should be overwritten
|
||||
* Returns: 0 on success, -1 on error
|
||||
*
|
||||
* This function is only used for wpa_cli action scripts. OS wrapper does not
|
||||
* need to implement this if such functionality is not needed.
|
||||
*/
|
||||
int os_setenv(const char *name, const char *value, int overwrite);
|
||||
|
||||
/**
|
||||
* os_unsetenv - Delete environent variable
|
||||
* @name: Name of the variable
|
||||
* Returns: 0 on success, -1 on error
|
||||
*
|
||||
* This function is only used for wpa_cli action scripts. OS wrapper does not
|
||||
* need to implement this if such functionality is not needed.
|
||||
*/
|
||||
int os_unsetenv(const char *name);
|
||||
|
||||
/**
|
||||
* os_readfile - Read a file to an allocated memory buffer
|
||||
* @name: Name of the file to read
|
||||
* @len: For returning the length of the allocated buffer
|
||||
* Returns: Pointer to the allocated buffer or %NULL on failure
|
||||
*
|
||||
* This function allocates memory and reads the given file to this buffer. Both
|
||||
* binary and text files can be read with this function. The caller is
|
||||
* responsible for freeing the returned buffer with os_free().
|
||||
*/
|
||||
char * os_readfile(const char *name, size_t *len);
|
||||
|
||||
/**
|
||||
* os_file_exists - Check whether the specified file exists
|
||||
* @fname: Path and name of the file
|
||||
* Returns: 1 if the file exists or 0 if not
|
||||
*/
|
||||
int os_file_exists(const char *fname);
|
||||
|
||||
/**
|
||||
* os_fdatasync - Sync a file's (for a given stream) state with storage device
|
||||
* @stream: the stream to be flushed
|
||||
* Returns: 0 if the operation succeeded or -1 on failure
|
||||
*/
|
||||
int os_fdatasync(FILE *stream);
|
||||
|
||||
/**
|
||||
* os_zalloc - Allocate and zero memory
|
||||
* @size: Number of bytes to allocate
|
||||
* Returns: Pointer to allocated and zeroed memory or %NULL on failure
|
||||
*
|
||||
* Caller is responsible for freeing the returned buffer with os_free().
|
||||
*/
|
||||
void * os_zalloc(size_t size);
|
||||
|
||||
/**
|
||||
* os_calloc - Allocate and zero memory for an array
|
||||
* @nmemb: Number of members in the array
|
||||
* @size: Number of bytes in each member
|
||||
* Returns: Pointer to allocated and zeroed memory or %NULL on failure
|
||||
*
|
||||
* This function can be used as a wrapper for os_zalloc(nmemb * size) when an
|
||||
* allocation is used for an array. The main benefit over os_zalloc() is in
|
||||
* having an extra check to catch integer overflows in multiplication.
|
||||
*
|
||||
* Caller is responsible for freeing the returned buffer with os_free().
|
||||
*/
|
||||
static inline void * os_calloc(size_t nmemb, size_t size)
|
||||
{
|
||||
if (size && nmemb > (~(size_t) 0) / size)
|
||||
return NULL;
|
||||
return os_zalloc(nmemb * size);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The following functions are wrapper for standard ANSI C or POSIX functions.
|
||||
* By default, they are just defined to use the standard function name and no
|
||||
* os_*.c implementation is needed for them. This avoids extra function calls
|
||||
* by allowing the C pre-processor take care of the function name mapping.
|
||||
*
|
||||
* If the target system uses a C library that does not provide these functions,
|
||||
* build_config.h can be used to define the wrappers to use a different
|
||||
* function name. This can be done on function-by-function basis since the
|
||||
* defines here are only used if build_config.h does not define the os_* name.
|
||||
* If needed, os_*.c file can be used to implement the functions that are not
|
||||
* included in the C library on the target system. Alternatively,
|
||||
* OS_NO_C_LIB_DEFINES can be defined to skip all defines here in which case
|
||||
* these functions need to be implemented in os_*.c file for the target system.
|
||||
*/
|
||||
|
||||
#ifdef OS_NO_C_LIB_DEFINES
|
||||
|
||||
/**
|
||||
* os_malloc - Allocate dynamic memory
|
||||
* @size: Size of the buffer to allocate
|
||||
* Returns: Allocated buffer or %NULL on failure
|
||||
*
|
||||
* Caller is responsible for freeing the returned buffer with os_free().
|
||||
*/
|
||||
void * os_malloc(size_t size);
|
||||
|
||||
/**
|
||||
* os_realloc - Re-allocate dynamic memory
|
||||
* @ptr: Old buffer from os_malloc() or os_realloc()
|
||||
* @size: Size of the new buffer
|
||||
* Returns: Allocated buffer or %NULL on failure
|
||||
*
|
||||
* Caller is responsible for freeing the returned buffer with os_free().
|
||||
* If re-allocation fails, %NULL is returned and the original buffer (ptr) is
|
||||
* not freed and caller is still responsible for freeing it.
|
||||
*/
|
||||
void * os_realloc(void *ptr, size_t size);
|
||||
|
||||
/**
|
||||
* os_free - Free dynamic memory
|
||||
* @ptr: Old buffer from os_malloc() or os_realloc(); can be %NULL
|
||||
*/
|
||||
void os_free(void *ptr);
|
||||
|
||||
/**
|
||||
* os_memcpy - Copy memory area
|
||||
* @dest: Destination
|
||||
* @src: Source
|
||||
* @n: Number of bytes to copy
|
||||
* Returns: dest
|
||||
*
|
||||
* The memory areas src and dst must not overlap. os_memmove() can be used with
|
||||
* overlapping memory.
|
||||
*/
|
||||
void * os_memcpy(void *dest, const void *src, size_t n);
|
||||
|
||||
/**
|
||||
* os_memmove - Copy memory area
|
||||
* @dest: Destination
|
||||
* @src: Source
|
||||
* @n: Number of bytes to copy
|
||||
* Returns: dest
|
||||
*
|
||||
* The memory areas src and dst may overlap.
|
||||
*/
|
||||
void * os_memmove(void *dest, const void *src, size_t n);
|
||||
|
||||
/**
|
||||
* os_memset - Fill memory with a constant byte
|
||||
* @s: Memory area to be filled
|
||||
* @c: Constant byte
|
||||
* @n: Number of bytes started from s to fill with c
|
||||
* Returns: s
|
||||
*/
|
||||
void * os_memset(void *s, int c, size_t n);
|
||||
|
||||
/**
|
||||
* os_memcmp - Compare memory areas
|
||||
* @s1: First buffer
|
||||
* @s2: Second buffer
|
||||
* @n: Maximum numbers of octets to compare
|
||||
* Returns: An integer less than, equal to, or greater than zero if s1 is
|
||||
* found to be less than, to match, or be greater than s2. Only first n
|
||||
* characters will be compared.
|
||||
*/
|
||||
int os_memcmp(const void *s1, const void *s2, size_t n);
|
||||
|
||||
/**
|
||||
* os_strdup - Duplicate a string
|
||||
* @s: Source string
|
||||
* Returns: Allocated buffer with the string copied into it or %NULL on failure
|
||||
*
|
||||
* Caller is responsible for freeing the returned buffer with os_free().
|
||||
*/
|
||||
char * os_strdup(const char *s);
|
||||
|
||||
/**
|
||||
* os_strlen - Calculate the length of a string
|
||||
* @s: '\0' terminated string
|
||||
* Returns: Number of characters in s (not counting the '\0' terminator)
|
||||
*/
|
||||
size_t os_strlen(const char *s);
|
||||
|
||||
/**
|
||||
* os_strcasecmp - Compare two strings ignoring case
|
||||
* @s1: First string
|
||||
* @s2: Second string
|
||||
* Returns: An integer less than, equal to, or greater than zero if s1 is
|
||||
* found to be less than, to match, or be greatred than s2
|
||||
*/
|
||||
int os_strcasecmp(const char *s1, const char *s2);
|
||||
|
||||
/**
|
||||
* os_strncasecmp - Compare two strings ignoring case
|
||||
* @s1: First string
|
||||
* @s2: Second string
|
||||
* @n: Maximum numbers of characters to compare
|
||||
* Returns: An integer less than, equal to, or greater than zero if s1 is
|
||||
* found to be less than, to match, or be greater than s2. Only first n
|
||||
* characters will be compared.
|
||||
*/
|
||||
int os_strncasecmp(const char *s1, const char *s2, size_t n);
|
||||
|
||||
/**
|
||||
* os_strchr - Locate the first occurrence of a character in string
|
||||
* @s: String
|
||||
* @c: Character to search for
|
||||
* Returns: Pointer to the matched character or %NULL if not found
|
||||
*/
|
||||
char * os_strchr(const char *s, int c);
|
||||
|
||||
/**
|
||||
* os_strrchr - Locate the last occurrence of a character in string
|
||||
* @s: String
|
||||
* @c: Character to search for
|
||||
* Returns: Pointer to the matched character or %NULL if not found
|
||||
*/
|
||||
char * os_strrchr(const char *s, int c);
|
||||
|
||||
/**
|
||||
* os_strcmp - Compare two strings
|
||||
* @s1: First string
|
||||
* @s2: Second string
|
||||
* Returns: An integer less than, equal to, or greater than zero if s1 is
|
||||
* found to be less than, to match, or be greatred than s2
|
||||
*/
|
||||
int os_strcmp(const char *s1, const char *s2);
|
||||
|
||||
/**
|
||||
* os_strncmp - Compare two strings
|
||||
* @s1: First string
|
||||
* @s2: Second string
|
||||
* @n: Maximum numbers of characters to compare
|
||||
* Returns: An integer less than, equal to, or greater than zero if s1 is
|
||||
* found to be less than, to match, or be greater than s2. Only first n
|
||||
* characters will be compared.
|
||||
*/
|
||||
int os_strncmp(const char *s1, const char *s2, size_t n);
|
||||
|
||||
/**
|
||||
* os_strstr - Locate a substring
|
||||
* @haystack: String (haystack) to search from
|
||||
* @needle: Needle to search from haystack
|
||||
* Returns: Pointer to the beginning of the substring or %NULL if not found
|
||||
*/
|
||||
char * os_strstr(const char *haystack, const char *needle);
|
||||
|
||||
/**
|
||||
* os_snprintf - Print to a memory buffer
|
||||
* @str: Memory buffer to print into
|
||||
* @size: Maximum length of the str buffer
|
||||
* @format: printf format
|
||||
* Returns: Number of characters printed (not including trailing '\0').
|
||||
*
|
||||
* If the output buffer is truncated, number of characters which would have
|
||||
* been written is returned. Since some C libraries return -1 in such a case,
|
||||
* the caller must be prepared on that value, too, to indicate truncation.
|
||||
*
|
||||
* Note: Some C library implementations of snprintf() may not guarantee null
|
||||
* termination in case the output is truncated. The OS wrapper function of
|
||||
* os_snprintf() should provide this guarantee, i.e., to null terminate the
|
||||
* output buffer if a C library version of the function is used and if that
|
||||
* function does not guarantee null termination.
|
||||
*
|
||||
* If the target system does not include snprintf(), see, e.g.,
|
||||
* http://www.ijs.si/software/snprintf/ for an example of a portable
|
||||
* implementation of snprintf.
|
||||
*/
|
||||
int os_snprintf(char *str, size_t size, const char *format, ...);
|
||||
|
||||
#else /* OS_NO_C_LIB_DEFINES */
|
||||
|
||||
#ifdef WPA_TRACE
|
||||
void * os_malloc(size_t size);
|
||||
void * os_realloc(void *ptr, size_t size);
|
||||
void os_free(void *ptr);
|
||||
char * os_strdup(const char *s);
|
||||
#else /* WPA_TRACE */
|
||||
#ifndef os_malloc
|
||||
#define os_malloc(s) malloc((s))
|
||||
#endif
|
||||
#ifndef os_realloc
|
||||
#define os_realloc(p, s) realloc((p), (s))
|
||||
#endif
|
||||
#ifndef os_free
|
||||
#define os_free(p) free((p))
|
||||
#endif
|
||||
#ifndef os_strdup
|
||||
#ifdef _MSC_VER
|
||||
#define os_strdup(s) _strdup(s)
|
||||
#else
|
||||
#define os_strdup(s) strdup(s)
|
||||
#endif
|
||||
#endif
|
||||
#endif /* WPA_TRACE */
|
||||
|
||||
#ifndef os_memcpy
|
||||
#define os_memcpy(d, s, n) memcpy((d), (s), (n))
|
||||
#endif
|
||||
#ifndef os_memmove
|
||||
#define os_memmove(d, s, n) memmove((d), (s), (n))
|
||||
#endif
|
||||
#ifndef os_memset
|
||||
#define os_memset(s, c, n) memset(s, c, n)
|
||||
#endif
|
||||
#ifndef os_memcmp
|
||||
#define os_memcmp(s1, s2, n) memcmp((s1), (s2), (n))
|
||||
#endif
|
||||
|
||||
#ifndef os_strlen
|
||||
#define os_strlen(s) strlen(s)
|
||||
#endif
|
||||
#ifndef os_strcasecmp
|
||||
#ifdef _MSC_VER
|
||||
#define os_strcasecmp(s1, s2) _stricmp((s1), (s2))
|
||||
#else
|
||||
#define os_strcasecmp(s1, s2) strcasecmp((s1), (s2))
|
||||
#endif
|
||||
#endif
|
||||
#ifndef os_strncasecmp
|
||||
#ifdef _MSC_VER
|
||||
#define os_strncasecmp(s1, s2, n) _strnicmp((s1), (s2), (n))
|
||||
#else
|
||||
#define os_strncasecmp(s1, s2, n) strncasecmp((s1), (s2), (n))
|
||||
#endif
|
||||
#endif
|
||||
#ifndef os_strchr
|
||||
#define os_strchr(s, c) strchr((s), (c))
|
||||
#endif
|
||||
#ifndef os_strcmp
|
||||
#define os_strcmp(s1, s2) strcmp((s1), (s2))
|
||||
#endif
|
||||
#ifndef os_strncmp
|
||||
#define os_strncmp(s1, s2, n) strncmp((s1), (s2), (n))
|
||||
#endif
|
||||
#ifndef os_strrchr
|
||||
#define os_strrchr(s, c) strrchr((s), (c))
|
||||
#endif
|
||||
#ifndef os_strstr
|
||||
#define os_strstr(h, n) strstr((h), (n))
|
||||
#endif
|
||||
|
||||
#ifndef os_snprintf
|
||||
#ifdef _MSC_VER
|
||||
#define os_snprintf _snprintf
|
||||
#else
|
||||
#define os_snprintf snprintf
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* OS_NO_C_LIB_DEFINES */
|
||||
|
||||
|
||||
static inline int os_snprintf_error(size_t size, int res)
|
||||
{
|
||||
return res < 0 || (unsigned int) res >= size;
|
||||
}
|
||||
|
||||
|
||||
static inline void * os_realloc_array(void *ptr, size_t nmemb, size_t size)
|
||||
{
|
||||
if (size && nmemb > (~(size_t) 0) / size)
|
||||
return NULL;
|
||||
return os_realloc(ptr, nmemb * size);
|
||||
}
|
||||
|
||||
/**
|
||||
* os_remove_in_array - Remove a member from an array by index
|
||||
* @ptr: Pointer to the array
|
||||
* @nmemb: Current member count of the array
|
||||
* @size: The size per member of the array
|
||||
* @idx: Index of the member to be removed
|
||||
*/
|
||||
static inline void os_remove_in_array(void *ptr, size_t nmemb, size_t size,
|
||||
size_t idx)
|
||||
{
|
||||
if (idx < nmemb - 1)
|
||||
os_memmove(((unsigned char *) ptr) + idx * size,
|
||||
((unsigned char *) ptr) + (idx + 1) * size,
|
||||
(nmemb - idx - 1) * size);
|
||||
}
|
||||
|
||||
/**
|
||||
* os_strlcpy - Copy a string with size bound and NUL-termination
|
||||
* @dest: Destination
|
||||
* @src: Source
|
||||
* @siz: Size of the target buffer
|
||||
* Returns: Total length of the target string (length of src) (not including
|
||||
* NUL-termination)
|
||||
*
|
||||
* This function matches in behavior with the strlcpy(3) function in OpenBSD.
|
||||
*/
|
||||
size_t os_strlcpy(char *dest, const char *src, size_t siz);
|
||||
|
||||
/**
|
||||
* os_memcmp_const - Constant time memory comparison
|
||||
* @a: First buffer to compare
|
||||
* @b: Second buffer to compare
|
||||
* @len: Number of octets to compare
|
||||
* Returns: 0 if buffers are equal, non-zero if not
|
||||
*
|
||||
* This function is meant for comparing passwords or hash values where
|
||||
* difference in execution time could provide external observer information
|
||||
* about the location of the difference in the memory buffers. The return value
|
||||
* does not behave like os_memcmp(), i.e., os_memcmp_const() cannot be used to
|
||||
* sort items into a defined order. Unlike os_memcmp(), execution time of
|
||||
* os_memcmp_const() does not depend on the contents of the compared memory
|
||||
* buffers, but only on the total compared length.
|
||||
*/
|
||||
int os_memcmp_const(const void *a, const void *b, size_t len);
|
||||
|
||||
|
||||
/**
|
||||
* os_memdup - Allocate duplicate of passed memory chunk
|
||||
* @src: Source buffer to duplicate
|
||||
* @len: Length of source buffer
|
||||
* Returns: %NULL if allocation failed, copy of src buffer otherwise
|
||||
*
|
||||
* This function allocates a memory block like os_malloc() would, and
|
||||
* copies the given source buffer into it.
|
||||
*/
|
||||
void * os_memdup(const void *src, size_t len);
|
||||
|
||||
/**
|
||||
* os_exec - Execute an external program
|
||||
* @program: Path to the program
|
||||
* @arg: Command line argument string
|
||||
* @wait_completion: Whether to wait until the program execution completes
|
||||
* Returns: 0 on success, -1 on error
|
||||
*/
|
||||
int os_exec(const char *program, const char *arg, int wait_completion);
|
||||
|
||||
|
||||
#ifdef OS_REJECT_C_LIB_FUNCTIONS
|
||||
#define malloc OS_DO_NOT_USE_malloc
|
||||
#define realloc OS_DO_NOT_USE_realloc
|
||||
#define free OS_DO_NOT_USE_free
|
||||
#define memcpy OS_DO_NOT_USE_memcpy
|
||||
#define memmove OS_DO_NOT_USE_memmove
|
||||
#define memset OS_DO_NOT_USE_memset
|
||||
#define memcmp OS_DO_NOT_USE_memcmp
|
||||
#undef strdup
|
||||
#define strdup OS_DO_NOT_USE_strdup
|
||||
#define strlen OS_DO_NOT_USE_strlen
|
||||
#define strcasecmp OS_DO_NOT_USE_strcasecmp
|
||||
#define strncasecmp OS_DO_NOT_USE_strncasecmp
|
||||
#undef strchr
|
||||
#define strchr OS_DO_NOT_USE_strchr
|
||||
#undef strcmp
|
||||
#define strcmp OS_DO_NOT_USE_strcmp
|
||||
#undef strncmp
|
||||
#define strncmp OS_DO_NOT_USE_strncmp
|
||||
#undef strncpy
|
||||
#define strncpy OS_DO_NOT_USE_strncpy
|
||||
#define strrchr OS_DO_NOT_USE_strrchr
|
||||
#define strstr OS_DO_NOT_USE_strstr
|
||||
#undef snprintf
|
||||
#define snprintf OS_DO_NOT_USE_snprintf
|
||||
|
||||
#define strcpy OS_DO_NOT_USE_strcpy
|
||||
#endif /* OS_REJECT_C_LIB_FUNCTIONS */
|
||||
|
||||
|
||||
#if defined(WPA_TRACE_BFD) && defined(CONFIG_TESTING_OPTIONS)
|
||||
#define TEST_FAIL() testing_test_fail()
|
||||
int testing_test_fail(void);
|
||||
extern char wpa_trace_fail_func[256];
|
||||
extern unsigned int wpa_trace_fail_after;
|
||||
extern char wpa_trace_test_fail_func[256];
|
||||
extern unsigned int wpa_trace_test_fail_after;
|
||||
#else
|
||||
#define TEST_FAIL() 0
|
||||
#endif
|
||||
|
||||
#endif /* OS_H */
|
@ -0,0 +1,853 @@
|
||||
/*
|
||||
* OS specific functions for UNIX/POSIX systems
|
||||
* Copyright (c) 2005-2019, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include <time.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#ifdef ANDROID
|
||||
#include <sys/capability.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <private/android_filesystem_config.h>
|
||||
#endif /* ANDROID */
|
||||
|
||||
#ifdef __MACH__
|
||||
#include <CoreServices/CoreServices.h>
|
||||
#include <mach/mach.h>
|
||||
#include <mach/mach_time.h>
|
||||
#endif /* __MACH__ */
|
||||
|
||||
#include "os.h"
|
||||
#include "common.h"
|
||||
|
||||
#ifdef WPA_TRACE
|
||||
|
||||
#include "wpa_debug.h"
|
||||
#include "trace.h"
|
||||
#include "list.h"
|
||||
|
||||
static struct dl_list alloc_list = DL_LIST_HEAD_INIT(alloc_list);
|
||||
|
||||
#define ALLOC_MAGIC 0xa84ef1b2
|
||||
#define FREED_MAGIC 0x67fd487a
|
||||
|
||||
struct os_alloc_trace {
|
||||
unsigned int magic;
|
||||
struct dl_list list __attribute__((aligned(16)));
|
||||
size_t len;
|
||||
WPA_TRACE_INFO
|
||||
} __attribute__((aligned(16)));
|
||||
|
||||
#endif /* WPA_TRACE */
|
||||
|
||||
|
||||
void os_sleep(os_time_t sec, os_time_t usec)
|
||||
{
|
||||
#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200809L)
|
||||
const struct timespec req = { sec, usec * 1000 };
|
||||
|
||||
nanosleep(&req, NULL);
|
||||
#else
|
||||
if (sec)
|
||||
sleep(sec);
|
||||
if (usec)
|
||||
usleep(usec);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int os_get_time(struct os_time *t)
|
||||
{
|
||||
int res;
|
||||
struct timeval tv;
|
||||
res = gettimeofday(&tv, NULL);
|
||||
t->sec = tv.tv_sec;
|
||||
t->usec = tv.tv_usec;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
int os_get_reltime(struct os_reltime *t)
|
||||
{
|
||||
#ifndef __MACH__
|
||||
#if defined(CLOCK_BOOTTIME)
|
||||
static clockid_t clock_id = CLOCK_BOOTTIME;
|
||||
#elif defined(CLOCK_MONOTONIC)
|
||||
static clockid_t clock_id = CLOCK_MONOTONIC;
|
||||
#else
|
||||
static clockid_t clock_id = CLOCK_REALTIME;
|
||||
#endif
|
||||
struct timespec ts;
|
||||
int res;
|
||||
|
||||
if (TEST_FAIL())
|
||||
return -1;
|
||||
|
||||
while (1) {
|
||||
res = clock_gettime(clock_id, &ts);
|
||||
if (res == 0) {
|
||||
t->sec = ts.tv_sec;
|
||||
t->usec = ts.tv_nsec / 1000;
|
||||
return 0;
|
||||
}
|
||||
switch (clock_id) {
|
||||
#ifdef CLOCK_BOOTTIME
|
||||
case CLOCK_BOOTTIME:
|
||||
clock_id = CLOCK_MONOTONIC;
|
||||
break;
|
||||
#endif
|
||||
#ifdef CLOCK_MONOTONIC
|
||||
case CLOCK_MONOTONIC:
|
||||
clock_id = CLOCK_REALTIME;
|
||||
break;
|
||||
#endif
|
||||
case CLOCK_REALTIME:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#else /* __MACH__ */
|
||||
uint64_t abstime, nano;
|
||||
static mach_timebase_info_data_t info = { 0, 0 };
|
||||
|
||||
if (!info.denom) {
|
||||
if (mach_timebase_info(&info) != KERN_SUCCESS)
|
||||
return -1;
|
||||
}
|
||||
|
||||
abstime = mach_absolute_time();
|
||||
nano = (abstime * info.numer) / info.denom;
|
||||
|
||||
t->sec = nano / NSEC_PER_SEC;
|
||||
t->usec = (nano - (((uint64_t) t->sec) * NSEC_PER_SEC)) / NSEC_PER_USEC;
|
||||
|
||||
return 0;
|
||||
#endif /* __MACH__ */
|
||||
}
|
||||
|
||||
|
||||
int os_mktime(int year, int month, int day, int hour, int min, int sec,
|
||||
os_time_t *t)
|
||||
{
|
||||
struct tm tm, *tm1;
|
||||
time_t t_local, t1, t2;
|
||||
os_time_t tz_offset;
|
||||
|
||||
if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 ||
|
||||
hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 ||
|
||||
sec > 60)
|
||||
return -1;
|
||||
|
||||
memset(&tm, 0, sizeof(tm));
|
||||
tm.tm_year = year - 1900;
|
||||
tm.tm_mon = month - 1;
|
||||
tm.tm_mday = day;
|
||||
tm.tm_hour = hour;
|
||||
tm.tm_min = min;
|
||||
tm.tm_sec = sec;
|
||||
|
||||
t_local = mktime(&tm);
|
||||
|
||||
/* figure out offset to UTC */
|
||||
tm1 = localtime(&t_local);
|
||||
if (tm1) {
|
||||
t1 = mktime(tm1);
|
||||
tm1 = gmtime(&t_local);
|
||||
if (tm1) {
|
||||
t2 = mktime(tm1);
|
||||
tz_offset = t2 - t1;
|
||||
} else
|
||||
tz_offset = 0;
|
||||
} else
|
||||
tz_offset = 0;
|
||||
|
||||
*t = (os_time_t) t_local - tz_offset;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int os_gmtime(os_time_t t, struct os_tm *tm)
|
||||
{
|
||||
struct tm *tm2;
|
||||
time_t t2 = t;
|
||||
|
||||
tm2 = gmtime(&t2);
|
||||
if (tm2 == NULL)
|
||||
return -1;
|
||||
tm->sec = tm2->tm_sec;
|
||||
tm->min = tm2->tm_min;
|
||||
tm->hour = tm2->tm_hour;
|
||||
tm->day = tm2->tm_mday;
|
||||
tm->month = tm2->tm_mon + 1;
|
||||
tm->year = tm2->tm_year + 1900;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <fcntl.h>
|
||||
static int os_daemon(int nochdir, int noclose)
|
||||
{
|
||||
int devnull;
|
||||
|
||||
if (chdir("/") < 0)
|
||||
return -1;
|
||||
|
||||
devnull = open("/dev/null", O_RDWR);
|
||||
if (devnull < 0)
|
||||
return -1;
|
||||
|
||||
if (dup2(devnull, STDIN_FILENO) < 0) {
|
||||
close(devnull);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (dup2(devnull, STDOUT_FILENO) < 0) {
|
||||
close(devnull);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (dup2(devnull, STDERR_FILENO) < 0) {
|
||||
close(devnull);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else /* __APPLE__ */
|
||||
#define os_daemon daemon
|
||||
#endif /* __APPLE__ */
|
||||
|
||||
|
||||
int os_daemonize(const char *pid_file)
|
||||
{
|
||||
#if defined(__uClinux__) || defined(__sun__)
|
||||
return -1;
|
||||
#else /* defined(__uClinux__) || defined(__sun__) */
|
||||
if (os_daemon(0, 0)) {
|
||||
perror("daemon");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pid_file) {
|
||||
FILE *f = fopen(pid_file, "w");
|
||||
if (f) {
|
||||
fprintf(f, "%u\n", getpid());
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
|
||||
return -0;
|
||||
#endif /* defined(__uClinux__) || defined(__sun__) */
|
||||
}
|
||||
|
||||
|
||||
void os_daemonize_terminate(const char *pid_file)
|
||||
{
|
||||
if (pid_file)
|
||||
unlink(pid_file);
|
||||
}
|
||||
|
||||
|
||||
int os_get_random(unsigned char *buf, size_t len)
|
||||
{
|
||||
#ifdef TEST_FUZZ
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
buf[i] = i & 0xff;
|
||||
return 0;
|
||||
#else /* TEST_FUZZ */
|
||||
FILE *f;
|
||||
size_t rc;
|
||||
|
||||
if (TEST_FAIL())
|
||||
return -1;
|
||||
|
||||
f = fopen("/dev/urandom", "rb");
|
||||
if (f == NULL) {
|
||||
printf("Could not open /dev/urandom.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = fread(buf, 1, len, f);
|
||||
fclose(f);
|
||||
|
||||
return rc != len ? -1 : 0;
|
||||
#endif /* TEST_FUZZ */
|
||||
}
|
||||
|
||||
|
||||
unsigned long os_random(void)
|
||||
{
|
||||
return random();
|
||||
}
|
||||
|
||||
|
||||
char * os_rel2abs_path(const char *rel_path)
|
||||
{
|
||||
char *buf = NULL, *cwd, *ret;
|
||||
size_t len = 128, cwd_len, rel_len, ret_len;
|
||||
int last_errno;
|
||||
|
||||
if (!rel_path)
|
||||
return NULL;
|
||||
|
||||
if (rel_path[0] == '/')
|
||||
return os_strdup(rel_path);
|
||||
|
||||
for (;;) {
|
||||
buf = os_malloc(len);
|
||||
if (buf == NULL)
|
||||
return NULL;
|
||||
cwd = getcwd(buf, len);
|
||||
if (cwd == NULL) {
|
||||
last_errno = errno;
|
||||
os_free(buf);
|
||||
if (last_errno != ERANGE)
|
||||
return NULL;
|
||||
len *= 2;
|
||||
if (len > 2000)
|
||||
return NULL;
|
||||
} else {
|
||||
buf[len - 1] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
cwd_len = os_strlen(cwd);
|
||||
rel_len = os_strlen(rel_path);
|
||||
ret_len = cwd_len + 1 + rel_len + 1;
|
||||
ret = os_malloc(ret_len);
|
||||
if (ret) {
|
||||
os_memcpy(ret, cwd, cwd_len);
|
||||
ret[cwd_len] = '/';
|
||||
os_memcpy(ret + cwd_len + 1, rel_path, rel_len);
|
||||
ret[ret_len - 1] = '\0';
|
||||
}
|
||||
os_free(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int os_program_init(void)
|
||||
{
|
||||
unsigned int seed;
|
||||
|
||||
#ifdef ANDROID
|
||||
/*
|
||||
* We ignore errors here since errors are normal if we
|
||||
* are already running as non-root.
|
||||
*/
|
||||
#ifdef ANDROID_SETGROUPS_OVERRIDE
|
||||
gid_t groups[] = { ANDROID_SETGROUPS_OVERRIDE };
|
||||
#else /* ANDROID_SETGROUPS_OVERRIDE */
|
||||
gid_t groups[] = { AID_INET, AID_WIFI, AID_KEYSTORE };
|
||||
#endif /* ANDROID_SETGROUPS_OVERRIDE */
|
||||
struct __user_cap_header_struct header;
|
||||
struct __user_cap_data_struct cap;
|
||||
|
||||
setgroups(ARRAY_SIZE(groups), groups);
|
||||
|
||||
prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
|
||||
|
||||
setgid(AID_WIFI);
|
||||
setuid(AID_WIFI);
|
||||
|
||||
header.version = _LINUX_CAPABILITY_VERSION;
|
||||
header.pid = 0;
|
||||
cap.effective = cap.permitted =
|
||||
(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
|
||||
cap.inheritable = 0;
|
||||
capset(&header, &cap);
|
||||
#endif /* ANDROID */
|
||||
|
||||
if (os_get_random((unsigned char *) &seed, sizeof(seed)) == 0)
|
||||
srandom(seed);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void os_program_deinit(void)
|
||||
{
|
||||
#ifdef WPA_TRACE
|
||||
struct os_alloc_trace *a;
|
||||
unsigned long total = 0;
|
||||
dl_list_for_each(a, &alloc_list, struct os_alloc_trace, list) {
|
||||
total += a->len;
|
||||
if (a->magic != ALLOC_MAGIC) {
|
||||
wpa_printf(MSG_INFO, "MEMLEAK[%p]: invalid magic 0x%x "
|
||||
"len %lu",
|
||||
a, a->magic, (unsigned long) a->len);
|
||||
continue;
|
||||
}
|
||||
wpa_printf(MSG_INFO, "MEMLEAK[%p]: len %lu",
|
||||
a, (unsigned long) a->len);
|
||||
wpa_trace_dump("memleak", a);
|
||||
}
|
||||
if (total)
|
||||
wpa_printf(MSG_INFO, "MEMLEAK: total %lu bytes",
|
||||
(unsigned long) total);
|
||||
wpa_trace_deinit();
|
||||
#endif /* WPA_TRACE */
|
||||
}
|
||||
|
||||
|
||||
int os_setenv(const char *name, const char *value, int overwrite)
|
||||
{
|
||||
return setenv(name, value, overwrite);
|
||||
}
|
||||
|
||||
|
||||
int os_unsetenv(const char *name)
|
||||
{
|
||||
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__) || \
|
||||
defined(__OpenBSD__)
|
||||
unsetenv(name);
|
||||
return 0;
|
||||
#else
|
||||
return unsetenv(name);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
char * os_readfile(const char *name, size_t *len)
|
||||
{
|
||||
FILE *f;
|
||||
char *buf;
|
||||
long pos;
|
||||
|
||||
f = fopen(name, "rb");
|
||||
if (f == NULL)
|
||||
return NULL;
|
||||
|
||||
if (fseek(f, 0, SEEK_END) < 0 || (pos = ftell(f)) < 0) {
|
||||
fclose(f);
|
||||
return NULL;
|
||||
}
|
||||
*len = pos;
|
||||
if (fseek(f, 0, SEEK_SET) < 0) {
|
||||
fclose(f);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
buf = os_malloc(*len);
|
||||
if (buf == NULL) {
|
||||
fclose(f);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (fread(buf, 1, *len, f) != *len) {
|
||||
fclose(f);
|
||||
os_free(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
int os_file_exists(const char *fname)
|
||||
{
|
||||
return access(fname, F_OK) == 0;
|
||||
}
|
||||
|
||||
|
||||
int os_fdatasync(FILE *stream)
|
||||
{
|
||||
if (!fflush(stream)) {
|
||||
#if defined __FreeBSD__ || defined __linux__
|
||||
return fdatasync(fileno(stream));
|
||||
#else /* !__linux__ && !__FreeBSD__ */
|
||||
#ifdef F_FULLFSYNC
|
||||
/* OS X does not implement fdatasync(). */
|
||||
return fcntl(fileno(stream), F_FULLFSYNC);
|
||||
#else /* F_FULLFSYNC */
|
||||
return fsync(fileno(stream));
|
||||
#endif /* F_FULLFSYNC */
|
||||
#endif /* __linux__ */
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
#ifndef WPA_TRACE
|
||||
void * os_zalloc(size_t size)
|
||||
{
|
||||
return calloc(1, size);
|
||||
}
|
||||
#endif /* WPA_TRACE */
|
||||
|
||||
|
||||
size_t os_strlcpy(char *dest, const char *src, size_t siz)
|
||||
{
|
||||
const char *s = src;
|
||||
size_t left = siz;
|
||||
|
||||
if (left) {
|
||||
/* Copy string up to the maximum size of the dest buffer */
|
||||
while (--left != 0) {
|
||||
if ((*dest++ = *s++) == '\0')
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (left == 0) {
|
||||
/* Not enough room for the string; force NUL-termination */
|
||||
if (siz != 0)
|
||||
*dest = '\0';
|
||||
while (*s++)
|
||||
; /* determine total src string length */
|
||||
}
|
||||
|
||||
return s - src - 1;
|
||||
}
|
||||
|
||||
|
||||
int os_memcmp_const(const void *a, const void *b, size_t len)
|
||||
{
|
||||
const u8 *aa = a;
|
||||
const u8 *bb = b;
|
||||
size_t i;
|
||||
u8 res;
|
||||
|
||||
for (res = 0, i = 0; i < len; i++)
|
||||
res |= aa[i] ^ bb[i];
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
void * os_memdup(const void *src, size_t len)
|
||||
{
|
||||
void *r = os_malloc(len);
|
||||
|
||||
if (r && src)
|
||||
os_memcpy(r, src, len);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
#ifdef WPA_TRACE
|
||||
|
||||
#if defined(WPA_TRACE_BFD) && defined(CONFIG_TESTING_OPTIONS)
|
||||
char wpa_trace_fail_func[256] = { 0 };
|
||||
unsigned int wpa_trace_fail_after;
|
||||
|
||||
static int testing_fail_alloc(void)
|
||||
{
|
||||
const char *func[WPA_TRACE_LEN];
|
||||
size_t i, res, len;
|
||||
char *pos, *next;
|
||||
int match;
|
||||
|
||||
if (!wpa_trace_fail_after)
|
||||
return 0;
|
||||
|
||||
res = wpa_trace_calling_func(func, WPA_TRACE_LEN);
|
||||
i = 0;
|
||||
if (i < res && os_strcmp(func[i], __func__) == 0)
|
||||
i++;
|
||||
if (i < res && os_strcmp(func[i], "os_malloc") == 0)
|
||||
i++;
|
||||
if (i < res && os_strcmp(func[i], "os_zalloc") == 0)
|
||||
i++;
|
||||
if (i < res && os_strcmp(func[i], "os_calloc") == 0)
|
||||
i++;
|
||||
if (i < res && os_strcmp(func[i], "os_realloc") == 0)
|
||||
i++;
|
||||
if (i < res && os_strcmp(func[i], "os_realloc_array") == 0)
|
||||
i++;
|
||||
if (i < res && os_strcmp(func[i], "os_strdup") == 0)
|
||||
i++;
|
||||
if (i < res && os_strcmp(func[i], "os_memdup") == 0)
|
||||
i++;
|
||||
|
||||
pos = wpa_trace_fail_func;
|
||||
|
||||
match = 0;
|
||||
while (i < res) {
|
||||
int allow_skip = 1;
|
||||
int maybe = 0;
|
||||
|
||||
if (*pos == '=') {
|
||||
allow_skip = 0;
|
||||
pos++;
|
||||
} else if (*pos == '?') {
|
||||
maybe = 1;
|
||||
pos++;
|
||||
}
|
||||
next = os_strchr(pos, ';');
|
||||
if (next)
|
||||
len = next - pos;
|
||||
else
|
||||
len = os_strlen(pos);
|
||||
if (os_memcmp(pos, func[i], len) != 0) {
|
||||
if (maybe && next) {
|
||||
pos = next + 1;
|
||||
continue;
|
||||
}
|
||||
if (allow_skip) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (!next) {
|
||||
match = 1;
|
||||
break;
|
||||
}
|
||||
pos = next + 1;
|
||||
i++;
|
||||
}
|
||||
if (!match)
|
||||
return 0;
|
||||
|
||||
wpa_trace_fail_after--;
|
||||
if (wpa_trace_fail_after == 0) {
|
||||
wpa_printf(MSG_INFO, "TESTING: fail allocation at %s",
|
||||
wpa_trace_fail_func);
|
||||
for (i = 0; i < res; i++)
|
||||
wpa_printf(MSG_INFO, "backtrace[%d] = %s",
|
||||
(int) i, func[i]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
char wpa_trace_test_fail_func[256] = { 0 };
|
||||
unsigned int wpa_trace_test_fail_after;
|
||||
|
||||
int testing_test_fail(void)
|
||||
{
|
||||
const char *func[WPA_TRACE_LEN];
|
||||
size_t i, res, len;
|
||||
char *pos, *next;
|
||||
int match;
|
||||
|
||||
if (!wpa_trace_test_fail_after)
|
||||
return 0;
|
||||
|
||||
res = wpa_trace_calling_func(func, WPA_TRACE_LEN);
|
||||
i = 0;
|
||||
if (i < res && os_strcmp(func[i], __func__) == 0)
|
||||
i++;
|
||||
|
||||
pos = wpa_trace_test_fail_func;
|
||||
|
||||
match = 0;
|
||||
while (i < res) {
|
||||
int allow_skip = 1;
|
||||
int maybe = 0;
|
||||
|
||||
if (*pos == '=') {
|
||||
allow_skip = 0;
|
||||
pos++;
|
||||
} else if (*pos == '?') {
|
||||
maybe = 1;
|
||||
pos++;
|
||||
}
|
||||
next = os_strchr(pos, ';');
|
||||
if (next)
|
||||
len = next - pos;
|
||||
else
|
||||
len = os_strlen(pos);
|
||||
if (os_memcmp(pos, func[i], len) != 0) {
|
||||
if (maybe && next) {
|
||||
pos = next + 1;
|
||||
continue;
|
||||
}
|
||||
if (allow_skip) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (!next) {
|
||||
match = 1;
|
||||
break;
|
||||
}
|
||||
pos = next + 1;
|
||||
i++;
|
||||
}
|
||||
if (!match)
|
||||
return 0;
|
||||
|
||||
wpa_trace_test_fail_after--;
|
||||
if (wpa_trace_test_fail_after == 0) {
|
||||
wpa_printf(MSG_INFO, "TESTING: fail at %s",
|
||||
wpa_trace_test_fail_func);
|
||||
for (i = 0; i < res; i++)
|
||||
wpa_printf(MSG_INFO, "backtrace[%d] = %s",
|
||||
(int) i, func[i]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline int testing_fail_alloc(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void * os_malloc(size_t size)
|
||||
{
|
||||
struct os_alloc_trace *a;
|
||||
|
||||
if (testing_fail_alloc())
|
||||
return NULL;
|
||||
|
||||
a = malloc(sizeof(*a) + size);
|
||||
if (a == NULL)
|
||||
return NULL;
|
||||
a->magic = ALLOC_MAGIC;
|
||||
dl_list_add(&alloc_list, &a->list);
|
||||
a->len = size;
|
||||
wpa_trace_record(a);
|
||||
return a + 1;
|
||||
}
|
||||
|
||||
|
||||
void * os_realloc(void *ptr, size_t size)
|
||||
{
|
||||
struct os_alloc_trace *a;
|
||||
size_t copy_len;
|
||||
void *n;
|
||||
|
||||
if (ptr == NULL)
|
||||
return os_malloc(size);
|
||||
|
||||
a = (struct os_alloc_trace *) ptr - 1;
|
||||
if (a->magic != ALLOC_MAGIC) {
|
||||
wpa_printf(MSG_INFO, "REALLOC[%p]: invalid magic 0x%x%s",
|
||||
a, a->magic,
|
||||
a->magic == FREED_MAGIC ? " (already freed)" : "");
|
||||
wpa_trace_show("Invalid os_realloc() call");
|
||||
abort();
|
||||
}
|
||||
n = os_malloc(size);
|
||||
if (n == NULL)
|
||||
return NULL;
|
||||
copy_len = a->len;
|
||||
if (copy_len > size)
|
||||
copy_len = size;
|
||||
os_memcpy(n, a + 1, copy_len);
|
||||
os_free(ptr);
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
void os_free(void *ptr)
|
||||
{
|
||||
struct os_alloc_trace *a;
|
||||
|
||||
if (ptr == NULL)
|
||||
return;
|
||||
a = (struct os_alloc_trace *) ptr - 1;
|
||||
if (a->magic != ALLOC_MAGIC) {
|
||||
wpa_printf(MSG_INFO, "FREE[%p]: invalid magic 0x%x%s",
|
||||
a, a->magic,
|
||||
a->magic == FREED_MAGIC ? " (already freed)" : "");
|
||||
wpa_trace_show("Invalid os_free() call");
|
||||
abort();
|
||||
}
|
||||
dl_list_del(&a->list);
|
||||
a->magic = FREED_MAGIC;
|
||||
|
||||
wpa_trace_check_ref(ptr);
|
||||
free(a);
|
||||
}
|
||||
|
||||
|
||||
void * os_zalloc(size_t size)
|
||||
{
|
||||
void *ptr = os_malloc(size);
|
||||
if (ptr)
|
||||
os_memset(ptr, 0, size);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
char * os_strdup(const char *s)
|
||||
{
|
||||
size_t len;
|
||||
char *d;
|
||||
len = os_strlen(s);
|
||||
d = os_malloc(len + 1);
|
||||
if (d == NULL)
|
||||
return NULL;
|
||||
os_memcpy(d, s, len);
|
||||
d[len] = '\0';
|
||||
return d;
|
||||
}
|
||||
|
||||
#endif /* WPA_TRACE */
|
||||
|
||||
|
||||
int os_exec(const char *program, const char *arg, int wait_completion)
|
||||
{
|
||||
pid_t pid;
|
||||
int pid_status;
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
perror("fork");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
/* run the external command in the child process */
|
||||
const int MAX_ARG = 30;
|
||||
char *_program, *_arg, *pos;
|
||||
char *argv[MAX_ARG + 1];
|
||||
int i;
|
||||
|
||||
_program = os_strdup(program);
|
||||
_arg = os_strdup(arg);
|
||||
|
||||
argv[0] = _program;
|
||||
|
||||
i = 1;
|
||||
pos = _arg;
|
||||
while (i < MAX_ARG && pos && *pos) {
|
||||
while (*pos == ' ')
|
||||
pos++;
|
||||
if (*pos == '\0')
|
||||
break;
|
||||
argv[i++] = pos;
|
||||
pos = os_strchr(pos, ' ');
|
||||
if (pos)
|
||||
*pos++ = '\0';
|
||||
}
|
||||
argv[i] = NULL;
|
||||
|
||||
execv(program, argv);
|
||||
perror("execv");
|
||||
os_free(_program);
|
||||
os_free(_arg);
|
||||
exit(0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (wait_completion) {
|
||||
/* wait for the child process to complete in the parent */
|
||||
waitpid(pid, &pid_status, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,766 @@
|
||||
/*
|
||||
* wpa_supplicant/hostapd control interface library
|
||||
* Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#ifdef CONFIG_CTRL_IFACE
|
||||
|
||||
#ifdef CONFIG_CTRL_IFACE_UNIX
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/un.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#endif /* CONFIG_CTRL_IFACE_UNIX */
|
||||
#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
|
||||
#include <netdb.h>
|
||||
#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
|
||||
|
||||
#ifdef ANDROID
|
||||
#include <dirent.h>
|
||||
#include <sys/stat.h>
|
||||
#include <cutils/sockets.h>
|
||||
#include "private/android_filesystem_config.h"
|
||||
#endif /* ANDROID */
|
||||
|
||||
#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
|
||||
#include <net/if.h>
|
||||
#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
|
||||
|
||||
#include "wpa_ctrl.h"
|
||||
#include "common.h"
|
||||
|
||||
|
||||
#if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP)
|
||||
#define CTRL_IFACE_SOCKET
|
||||
#endif /* CONFIG_CTRL_IFACE_UNIX || CONFIG_CTRL_IFACE_UDP */
|
||||
|
||||
|
||||
/**
|
||||
* struct wpa_ctrl - Internal structure for control interface library
|
||||
*
|
||||
* This structure is used by the wpa_supplicant/hostapd control interface
|
||||
* library to store internal data. Programs using the library should not touch
|
||||
* this data directly. They can only use the pointer to the data structure as
|
||||
* an identifier for the control interface connection and use this as one of
|
||||
* the arguments for most of the control interface library functions.
|
||||
*/
|
||||
struct wpa_ctrl {
|
||||
#ifdef CONFIG_CTRL_IFACE_UDP
|
||||
int s;
|
||||
#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
|
||||
struct sockaddr_in6 local;
|
||||
struct sockaddr_in6 dest;
|
||||
#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
|
||||
struct sockaddr_in local;
|
||||
struct sockaddr_in dest;
|
||||
#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
|
||||
char *cookie;
|
||||
char *remote_ifname;
|
||||
char *remote_ip;
|
||||
#endif /* CONFIG_CTRL_IFACE_UDP */
|
||||
#ifdef CONFIG_CTRL_IFACE_UNIX
|
||||
int s;
|
||||
struct sockaddr_un local;
|
||||
struct sockaddr_un dest;
|
||||
#endif /* CONFIG_CTRL_IFACE_UNIX */
|
||||
#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
|
||||
HANDLE pipe;
|
||||
#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
|
||||
};
|
||||
|
||||
|
||||
#ifdef CONFIG_CTRL_IFACE_UNIX
|
||||
|
||||
#ifndef CONFIG_CTRL_IFACE_CLIENT_DIR
|
||||
#define CONFIG_CTRL_IFACE_CLIENT_DIR "/tmp"
|
||||
#endif /* CONFIG_CTRL_IFACE_CLIENT_DIR */
|
||||
#ifndef CONFIG_CTRL_IFACE_CLIENT_PREFIX
|
||||
#define CONFIG_CTRL_IFACE_CLIENT_PREFIX "wpa_ctrl_"
|
||||
#endif /* CONFIG_CTRL_IFACE_CLIENT_PREFIX */
|
||||
|
||||
|
||||
struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
|
||||
{
|
||||
return wpa_ctrl_open2(ctrl_path, NULL);
|
||||
}
|
||||
|
||||
|
||||
struct wpa_ctrl * wpa_ctrl_open2(const char *ctrl_path,
|
||||
const char *cli_path)
|
||||
{
|
||||
struct wpa_ctrl *ctrl;
|
||||
static int counter = 0;
|
||||
int ret;
|
||||
size_t res;
|
||||
int tries = 0;
|
||||
int flags;
|
||||
|
||||
if (ctrl_path == NULL)
|
||||
return NULL;
|
||||
|
||||
ctrl = os_zalloc(sizeof(*ctrl));
|
||||
if (ctrl == NULL)
|
||||
return NULL;
|
||||
|
||||
ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0);
|
||||
if (ctrl->s < 0) {
|
||||
os_free(ctrl);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ctrl->local.sun_family = AF_UNIX;
|
||||
counter++;
|
||||
try_again:
|
||||
if (cli_path && cli_path[0] == '/') {
|
||||
ret = os_snprintf(ctrl->local.sun_path,
|
||||
sizeof(ctrl->local.sun_path),
|
||||
"%s/" CONFIG_CTRL_IFACE_CLIENT_PREFIX "%d-%d",
|
||||
cli_path, (int) getpid(), counter);
|
||||
} else {
|
||||
ret = os_snprintf(ctrl->local.sun_path,
|
||||
sizeof(ctrl->local.sun_path),
|
||||
CONFIG_CTRL_IFACE_CLIENT_DIR "/"
|
||||
CONFIG_CTRL_IFACE_CLIENT_PREFIX "%d-%d",
|
||||
(int) getpid(), counter);
|
||||
}
|
||||
if (os_snprintf_error(sizeof(ctrl->local.sun_path), ret)) {
|
||||
close(ctrl->s);
|
||||
os_free(ctrl);
|
||||
return NULL;
|
||||
}
|
||||
tries++;
|
||||
#ifdef ANDROID
|
||||
/* Set client socket file permissions so that bind() creates the client
|
||||
* socket with these permissions and there is no need to try to change
|
||||
* them with chmod() after bind() which would have potential issues with
|
||||
* race conditions. These permissions are needed to make sure the server
|
||||
* side (wpa_supplicant or hostapd) can reply to the control interface
|
||||
* messages.
|
||||
*
|
||||
* The lchown() calls below after bind() are also part of the needed
|
||||
* operations to allow the response to go through. Those are using the
|
||||
* no-deference-symlinks version to avoid races. */
|
||||
fchmod(ctrl->s, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
|
||||
#endif /* ANDROID */
|
||||
if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
|
||||
sizeof(ctrl->local)) < 0) {
|
||||
if (errno == EADDRINUSE && tries < 2) {
|
||||
/*
|
||||
* getpid() returns unique identifier for this instance
|
||||
* of wpa_ctrl, so the existing socket file must have
|
||||
* been left by unclean termination of an earlier run.
|
||||
* Remove the file and try again.
|
||||
*/
|
||||
unlink(ctrl->local.sun_path);
|
||||
goto try_again;
|
||||
}
|
||||
close(ctrl->s);
|
||||
os_free(ctrl);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef ANDROID
|
||||
/* Set group even if we do not have privileges to change owner */
|
||||
lchown(ctrl->local.sun_path, -1, AID_WIFI);
|
||||
lchown(ctrl->local.sun_path, AID_SYSTEM, AID_WIFI);
|
||||
|
||||
if (os_strncmp(ctrl_path, "@android:", 9) == 0) {
|
||||
if (socket_local_client_connect(
|
||||
ctrl->s, ctrl_path + 9,
|
||||
ANDROID_SOCKET_NAMESPACE_RESERVED,
|
||||
SOCK_DGRAM) < 0) {
|
||||
close(ctrl->s);
|
||||
unlink(ctrl->local.sun_path);
|
||||
os_free(ctrl);
|
||||
return NULL;
|
||||
}
|
||||
return ctrl;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the ctrl_path isn't an absolute pathname, assume that
|
||||
* it's the name of a socket in the Android reserved namespace.
|
||||
* Otherwise, it's a normal UNIX domain socket appearing in the
|
||||
* filesystem.
|
||||
*/
|
||||
if (*ctrl_path != '/') {
|
||||
char buf[21];
|
||||
os_snprintf(buf, sizeof(buf), "wpa_%s", ctrl_path);
|
||||
if (socket_local_client_connect(
|
||||
ctrl->s, buf,
|
||||
ANDROID_SOCKET_NAMESPACE_RESERVED,
|
||||
SOCK_DGRAM) < 0) {
|
||||
close(ctrl->s);
|
||||
unlink(ctrl->local.sun_path);
|
||||
os_free(ctrl);
|
||||
return NULL;
|
||||
}
|
||||
return ctrl;
|
||||
}
|
||||
#endif /* ANDROID */
|
||||
|
||||
ctrl->dest.sun_family = AF_UNIX;
|
||||
if (os_strncmp(ctrl_path, "@abstract:", 10) == 0) {
|
||||
ctrl->dest.sun_path[0] = '\0';
|
||||
os_strlcpy(ctrl->dest.sun_path + 1, ctrl_path + 10,
|
||||
sizeof(ctrl->dest.sun_path) - 1);
|
||||
} else {
|
||||
res = os_strlcpy(ctrl->dest.sun_path, ctrl_path,
|
||||
sizeof(ctrl->dest.sun_path));
|
||||
if (res >= sizeof(ctrl->dest.sun_path)) {
|
||||
close(ctrl->s);
|
||||
os_free(ctrl);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
|
||||
sizeof(ctrl->dest)) < 0) {
|
||||
close(ctrl->s);
|
||||
unlink(ctrl->local.sun_path);
|
||||
os_free(ctrl);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make socket non-blocking so that we don't hang forever if
|
||||
* target dies unexpectedly.
|
||||
*/
|
||||
flags = fcntl(ctrl->s, F_GETFL);
|
||||
if (flags >= 0) {
|
||||
flags |= O_NONBLOCK;
|
||||
if (fcntl(ctrl->s, F_SETFL, flags) < 0) {
|
||||
perror("fcntl(ctrl->s, O_NONBLOCK)");
|
||||
/* Not fatal, continue on.*/
|
||||
}
|
||||
}
|
||||
|
||||
return ctrl;
|
||||
}
|
||||
|
||||
|
||||
void wpa_ctrl_close(struct wpa_ctrl *ctrl)
|
||||
{
|
||||
if (ctrl == NULL)
|
||||
return;
|
||||
unlink(ctrl->local.sun_path);
|
||||
if (ctrl->s >= 0)
|
||||
close(ctrl->s);
|
||||
os_free(ctrl);
|
||||
}
|
||||
|
||||
|
||||
#ifdef ANDROID
|
||||
/**
|
||||
* wpa_ctrl_cleanup() - Delete any local UNIX domain socket files that
|
||||
* may be left over from clients that were previously connected to
|
||||
* wpa_supplicant. This keeps these files from being orphaned in the
|
||||
* event of crashes that prevented them from being removed as part
|
||||
* of the normal orderly shutdown.
|
||||
*/
|
||||
void wpa_ctrl_cleanup(void)
|
||||
{
|
||||
DIR *dir;
|
||||
struct dirent *result;
|
||||
size_t dirnamelen;
|
||||
size_t maxcopy;
|
||||
char pathname[PATH_MAX];
|
||||
char *namep;
|
||||
|
||||
if ((dir = opendir(CONFIG_CTRL_IFACE_CLIENT_DIR)) == NULL)
|
||||
return;
|
||||
|
||||
dirnamelen = (size_t) os_snprintf(pathname, sizeof(pathname), "%s/",
|
||||
CONFIG_CTRL_IFACE_CLIENT_DIR);
|
||||
if (dirnamelen >= sizeof(pathname)) {
|
||||
closedir(dir);
|
||||
return;
|
||||
}
|
||||
namep = pathname + dirnamelen;
|
||||
maxcopy = PATH_MAX - dirnamelen;
|
||||
while ((result = readdir(dir)) != NULL) {
|
||||
if (os_strlcpy(namep, result->d_name, maxcopy) < maxcopy)
|
||||
unlink(pathname);
|
||||
}
|
||||
closedir(dir);
|
||||
}
|
||||
#endif /* ANDROID */
|
||||
|
||||
#else /* CONFIG_CTRL_IFACE_UNIX */
|
||||
|
||||
#ifdef ANDROID
|
||||
void wpa_ctrl_cleanup(void)
|
||||
{
|
||||
}
|
||||
#endif /* ANDROID */
|
||||
|
||||
#endif /* CONFIG_CTRL_IFACE_UNIX */
|
||||
|
||||
|
||||
#ifdef CONFIG_CTRL_IFACE_UDP
|
||||
|
||||
struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
|
||||
{
|
||||
struct wpa_ctrl *ctrl;
|
||||
char buf[128];
|
||||
size_t len;
|
||||
#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
|
||||
struct hostent *h;
|
||||
#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
|
||||
|
||||
ctrl = os_zalloc(sizeof(*ctrl));
|
||||
if (ctrl == NULL)
|
||||
return NULL;
|
||||
|
||||
#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
|
||||
ctrl->s = socket(PF_INET6, SOCK_DGRAM, 0);
|
||||
#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
|
||||
ctrl->s = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
|
||||
if (ctrl->s < 0) {
|
||||
perror("socket");
|
||||
os_free(ctrl);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
|
||||
ctrl->local.sin6_family = AF_INET6;
|
||||
#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
|
||||
ctrl->local.sin6_addr = in6addr_any;
|
||||
#else /* CONFIG_CTRL_IFACE_UDP_REMOTE */
|
||||
inet_pton(AF_INET6, "::1", &ctrl->local.sin6_addr);
|
||||
#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
|
||||
#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
|
||||
ctrl->local.sin_family = AF_INET;
|
||||
#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
|
||||
ctrl->local.sin_addr.s_addr = INADDR_ANY;
|
||||
#else /* CONFIG_CTRL_IFACE_UDP_REMOTE */
|
||||
ctrl->local.sin_addr.s_addr = htonl((127 << 24) | 1);
|
||||
#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
|
||||
#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
|
||||
|
||||
if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
|
||||
sizeof(ctrl->local)) < 0) {
|
||||
close(ctrl->s);
|
||||
os_free(ctrl);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
|
||||
ctrl->dest.sin6_family = AF_INET6;
|
||||
inet_pton(AF_INET6, "::1", &ctrl->dest.sin6_addr);
|
||||
ctrl->dest.sin6_port = htons(WPA_CTRL_IFACE_PORT);
|
||||
#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
|
||||
ctrl->dest.sin_family = AF_INET;
|
||||
ctrl->dest.sin_addr.s_addr = htonl((127 << 24) | 1);
|
||||
ctrl->dest.sin_port = htons(WPA_CTRL_IFACE_PORT);
|
||||
#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
|
||||
|
||||
#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
|
||||
if (ctrl_path) {
|
||||
char *port, *name;
|
||||
int port_id;
|
||||
#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
|
||||
char *scope;
|
||||
int scope_id = 0;
|
||||
#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
|
||||
|
||||
name = os_strdup(ctrl_path);
|
||||
if (name == NULL) {
|
||||
close(ctrl->s);
|
||||
os_free(ctrl);
|
||||
return NULL;
|
||||
}
|
||||
#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
|
||||
port = os_strchr(name, ',');
|
||||
#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
|
||||
port = os_strchr(name, ':');
|
||||
#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
|
||||
|
||||
if (port) {
|
||||
port_id = atoi(&port[1]);
|
||||
port[0] = '\0';
|
||||
} else
|
||||
port_id = WPA_CTRL_IFACE_PORT;
|
||||
|
||||
#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
|
||||
scope = os_strchr(name, '%');
|
||||
if (scope) {
|
||||
scope_id = if_nametoindex(&scope[1]);
|
||||
scope[0] = '\0';
|
||||
}
|
||||
h = gethostbyname2(name, AF_INET6);
|
||||
#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
|
||||
h = gethostbyname(name);
|
||||
#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
|
||||
ctrl->remote_ip = os_strdup(name);
|
||||
os_free(name);
|
||||
if (h == NULL) {
|
||||
perror("gethostbyname");
|
||||
close(ctrl->s);
|
||||
os_free(ctrl->remote_ip);
|
||||
os_free(ctrl);
|
||||
return NULL;
|
||||
}
|
||||
#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
|
||||
ctrl->dest.sin6_scope_id = scope_id;
|
||||
ctrl->dest.sin6_port = htons(port_id);
|
||||
os_memcpy(&ctrl->dest.sin6_addr, h->h_addr, h->h_length);
|
||||
#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
|
||||
ctrl->dest.sin_port = htons(port_id);
|
||||
os_memcpy(&ctrl->dest.sin_addr.s_addr, h->h_addr, h->h_length);
|
||||
#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
|
||||
} else
|
||||
ctrl->remote_ip = os_strdup("localhost");
|
||||
#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
|
||||
|
||||
if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
|
||||
sizeof(ctrl->dest)) < 0) {
|
||||
#ifdef CONFIG_CTRL_IFACE_UDP_IPV6
|
||||
char addr[INET6_ADDRSTRLEN];
|
||||
wpa_printf(MSG_ERROR, "connect(%s:%d) failed: %s",
|
||||
inet_ntop(AF_INET6, &ctrl->dest.sin6_addr, addr,
|
||||
sizeof(ctrl->dest)),
|
||||
ntohs(ctrl->dest.sin6_port),
|
||||
strerror(errno));
|
||||
#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
|
||||
wpa_printf(MSG_ERROR, "connect(%s:%d) failed: %s",
|
||||
inet_ntoa(ctrl->dest.sin_addr),
|
||||
ntohs(ctrl->dest.sin_port),
|
||||
strerror(errno));
|
||||
#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
|
||||
close(ctrl->s);
|
||||
os_free(ctrl->remote_ip);
|
||||
os_free(ctrl);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
len = sizeof(buf) - 1;
|
||||
if (wpa_ctrl_request(ctrl, "GET_COOKIE", 10, buf, &len, NULL) == 0) {
|
||||
buf[len] = '\0';
|
||||
ctrl->cookie = os_strdup(buf);
|
||||
}
|
||||
|
||||
if (wpa_ctrl_request(ctrl, "IFNAME", 6, buf, &len, NULL) == 0) {
|
||||
buf[len] = '\0';
|
||||
ctrl->remote_ifname = os_strdup(buf);
|
||||
}
|
||||
|
||||
return ctrl;
|
||||
}
|
||||
|
||||
|
||||
char * wpa_ctrl_get_remote_ifname(struct wpa_ctrl *ctrl)
|
||||
{
|
||||
#define WPA_CTRL_MAX_PS_NAME 100
|
||||
static char ps[WPA_CTRL_MAX_PS_NAME] = {};
|
||||
os_snprintf(ps, WPA_CTRL_MAX_PS_NAME, "%s/%s",
|
||||
ctrl->remote_ip, ctrl->remote_ifname);
|
||||
return ps;
|
||||
}
|
||||
|
||||
|
||||
void wpa_ctrl_close(struct wpa_ctrl *ctrl)
|
||||
{
|
||||
close(ctrl->s);
|
||||
os_free(ctrl->cookie);
|
||||
os_free(ctrl->remote_ifname);
|
||||
os_free(ctrl->remote_ip);
|
||||
os_free(ctrl);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_CTRL_IFACE_UDP */
|
||||
|
||||
|
||||
#ifdef CTRL_IFACE_SOCKET
|
||||
int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
|
||||
char *reply, size_t *reply_len,
|
||||
void (*msg_cb)(char *msg, size_t len))
|
||||
{
|
||||
struct timeval tv;
|
||||
struct os_reltime started_at;
|
||||
int res;
|
||||
fd_set rfds;
|
||||
const char *_cmd;
|
||||
char *cmd_buf = NULL;
|
||||
size_t _cmd_len;
|
||||
|
||||
#ifdef CONFIG_CTRL_IFACE_UDP
|
||||
if (ctrl->cookie) {
|
||||
char *pos;
|
||||
_cmd_len = os_strlen(ctrl->cookie) + 1 + cmd_len;
|
||||
cmd_buf = os_malloc(_cmd_len);
|
||||
if (cmd_buf == NULL)
|
||||
return -1;
|
||||
_cmd = cmd_buf;
|
||||
pos = cmd_buf;
|
||||
os_strlcpy(pos, ctrl->cookie, _cmd_len);
|
||||
pos += os_strlen(ctrl->cookie);
|
||||
*pos++ = ' ';
|
||||
os_memcpy(pos, cmd, cmd_len);
|
||||
} else
|
||||
#endif /* CONFIG_CTRL_IFACE_UDP */
|
||||
{
|
||||
_cmd = cmd;
|
||||
_cmd_len = cmd_len;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
started_at.sec = 0;
|
||||
started_at.usec = 0;
|
||||
retry_send:
|
||||
if (send(ctrl->s, _cmd, _cmd_len, 0) < 0) {
|
||||
if (errno == EAGAIN || errno == EBUSY || errno == EWOULDBLOCK)
|
||||
{
|
||||
/*
|
||||
* Must be a non-blocking socket... Try for a bit
|
||||
* longer before giving up.
|
||||
*/
|
||||
if (started_at.sec == 0)
|
||||
os_get_reltime(&started_at);
|
||||
else {
|
||||
struct os_reltime n;
|
||||
os_get_reltime(&n);
|
||||
/* Try for a few seconds. */
|
||||
if (os_reltime_expired(&n, &started_at, 5))
|
||||
goto send_err;
|
||||
}
|
||||
os_sleep(1, 0);
|
||||
goto retry_send;
|
||||
}
|
||||
send_err:
|
||||
os_free(cmd_buf);
|
||||
return -1;
|
||||
}
|
||||
os_free(cmd_buf);
|
||||
|
||||
for (;;) {
|
||||
tv.tv_sec = 10;
|
||||
tv.tv_usec = 0;
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(ctrl->s, &rfds);
|
||||
res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
|
||||
if (res < 0 && errno == EINTR)
|
||||
continue;
|
||||
if (res < 0)
|
||||
return res;
|
||||
if (FD_ISSET(ctrl->s, &rfds)) {
|
||||
res = recv(ctrl->s, reply, *reply_len, 0);
|
||||
if (res < 0)
|
||||
return res;
|
||||
if ((res > 0 && reply[0] == '<') ||
|
||||
(res > 6 && strncmp(reply, "IFNAME=", 7) == 0)) {
|
||||
/* This is an unsolicited message from
|
||||
* wpa_supplicant, not the reply to the
|
||||
* request. Use msg_cb to report this to the
|
||||
* caller. */
|
||||
if (msg_cb) {
|
||||
/* Make sure the message is nul
|
||||
* terminated. */
|
||||
if ((size_t) res == *reply_len)
|
||||
res = (*reply_len) - 1;
|
||||
reply[res] = '\0';
|
||||
msg_cb(reply, res);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
*reply_len = res;
|
||||
break;
|
||||
} else {
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif /* CTRL_IFACE_SOCKET */
|
||||
|
||||
|
||||
static int wpa_ctrl_attach_helper(struct wpa_ctrl *ctrl, int attach)
|
||||
{
|
||||
char buf[10];
|
||||
int ret;
|
||||
size_t len = 10;
|
||||
|
||||
ret = wpa_ctrl_request(ctrl, attach ? "ATTACH" : "DETACH", 6,
|
||||
buf, &len, NULL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (len == 3 && os_memcmp(buf, "OK\n", 3) == 0)
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int wpa_ctrl_attach(struct wpa_ctrl *ctrl)
|
||||
{
|
||||
return wpa_ctrl_attach_helper(ctrl, 1);
|
||||
}
|
||||
|
||||
|
||||
int wpa_ctrl_detach(struct wpa_ctrl *ctrl)
|
||||
{
|
||||
return wpa_ctrl_attach_helper(ctrl, 0);
|
||||
}
|
||||
|
||||
|
||||
#ifdef CTRL_IFACE_SOCKET
|
||||
|
||||
int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = recv(ctrl->s, reply, *reply_len, 0);
|
||||
if (res < 0)
|
||||
return res;
|
||||
*reply_len = res;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int wpa_ctrl_pending(struct wpa_ctrl *ctrl)
|
||||
{
|
||||
struct timeval tv;
|
||||
fd_set rfds;
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 0;
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(ctrl->s, &rfds);
|
||||
select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
|
||||
return FD_ISSET(ctrl->s, &rfds);
|
||||
}
|
||||
|
||||
|
||||
int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl)
|
||||
{
|
||||
return ctrl->s;
|
||||
}
|
||||
|
||||
#endif /* CTRL_IFACE_SOCKET */
|
||||
|
||||
|
||||
#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
|
||||
|
||||
#ifndef WPA_SUPPLICANT_NAMED_PIPE
|
||||
#define WPA_SUPPLICANT_NAMED_PIPE "WpaSupplicant"
|
||||
#endif
|
||||
#define NAMED_PIPE_PREFIX TEXT("\\\\.\\pipe\\") TEXT(WPA_SUPPLICANT_NAMED_PIPE)
|
||||
|
||||
struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
|
||||
{
|
||||
struct wpa_ctrl *ctrl;
|
||||
DWORD mode;
|
||||
TCHAR name[256];
|
||||
int i, ret;
|
||||
|
||||
ctrl = os_malloc(sizeof(*ctrl));
|
||||
if (ctrl == NULL)
|
||||
return NULL;
|
||||
os_memset(ctrl, 0, sizeof(*ctrl));
|
||||
|
||||
#ifdef UNICODE
|
||||
if (ctrl_path == NULL)
|
||||
ret = _snwprintf(name, 256, NAMED_PIPE_PREFIX);
|
||||
else
|
||||
ret = _snwprintf(name, 256, NAMED_PIPE_PREFIX TEXT("-%S"),
|
||||
ctrl_path);
|
||||
#else /* UNICODE */
|
||||
if (ctrl_path == NULL)
|
||||
ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX);
|
||||
else
|
||||
ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX "-%s",
|
||||
ctrl_path);
|
||||
#endif /* UNICODE */
|
||||
if (os_snprintf_error(256, ret)) {
|
||||
os_free(ctrl);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
ctrl->pipe = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0,
|
||||
NULL, OPEN_EXISTING, 0, NULL);
|
||||
/*
|
||||
* Current named pipe server side in wpa_supplicant is
|
||||
* re-opening the pipe for new clients only after the previous
|
||||
* one is taken into use. This leaves a small window for race
|
||||
* conditions when two connections are being opened at almost
|
||||
* the same time. Retry if that was the case.
|
||||
*/
|
||||
if (ctrl->pipe != INVALID_HANDLE_VALUE ||
|
||||
GetLastError() != ERROR_PIPE_BUSY)
|
||||
break;
|
||||
WaitNamedPipe(name, 1000);
|
||||
}
|
||||
if (ctrl->pipe == INVALID_HANDLE_VALUE) {
|
||||
os_free(ctrl);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mode = PIPE_READMODE_MESSAGE;
|
||||
if (!SetNamedPipeHandleState(ctrl->pipe, &mode, NULL, NULL)) {
|
||||
CloseHandle(ctrl->pipe);
|
||||
os_free(ctrl);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ctrl;
|
||||
}
|
||||
|
||||
|
||||
void wpa_ctrl_close(struct wpa_ctrl *ctrl)
|
||||
{
|
||||
CloseHandle(ctrl->pipe);
|
||||
os_free(ctrl);
|
||||
}
|
||||
|
||||
|
||||
int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
|
||||
char *reply, size_t *reply_len,
|
||||
void (*msg_cb)(char *msg, size_t len))
|
||||
{
|
||||
DWORD written;
|
||||
DWORD readlen = *reply_len;
|
||||
|
||||
if (!WriteFile(ctrl->pipe, cmd, cmd_len, &written, NULL))
|
||||
return -1;
|
||||
|
||||
if (!ReadFile(ctrl->pipe, reply, *reply_len, &readlen, NULL))
|
||||
return -1;
|
||||
*reply_len = readlen;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
|
||||
{
|
||||
DWORD len = *reply_len;
|
||||
if (!ReadFile(ctrl->pipe, reply, *reply_len, &len, NULL))
|
||||
return -1;
|
||||
*reply_len = len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int wpa_ctrl_pending(struct wpa_ctrl *ctrl)
|
||||
{
|
||||
DWORD left;
|
||||
|
||||
if (!PeekNamedPipe(ctrl->pipe, NULL, 0, NULL, &left, NULL))
|
||||
return -1;
|
||||
return left ? 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
|
||||
|
||||
#endif /* CONFIG_CTRL_IFACE */
|
@ -0,0 +1,643 @@
|
||||
/*
|
||||
* wpa_supplicant/hostapd control interface library
|
||||
* Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef WPA_CTRL_H
|
||||
#define WPA_CTRL_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/* wpa_supplicant control interface - fixed message prefixes */
|
||||
|
||||
/** Interactive request for identity/password/pin */
|
||||
#define WPA_CTRL_REQ "CTRL-REQ-"
|
||||
|
||||
/** Response to identity/password/pin request */
|
||||
#define WPA_CTRL_RSP "CTRL-RSP-"
|
||||
|
||||
/* Event messages with fixed prefix */
|
||||
/** Authentication completed successfully and data connection enabled */
|
||||
#define WPA_EVENT_CONNECTED "CTRL-EVENT-CONNECTED "
|
||||
/** Disconnected, data connection is not available */
|
||||
#define WPA_EVENT_DISCONNECTED "CTRL-EVENT-DISCONNECTED "
|
||||
/** Association rejected during connection attempt */
|
||||
#define WPA_EVENT_ASSOC_REJECT "CTRL-EVENT-ASSOC-REJECT "
|
||||
/** Authentication rejected during connection attempt */
|
||||
#define WPA_EVENT_AUTH_REJECT "CTRL-EVENT-AUTH-REJECT "
|
||||
/** wpa_supplicant is exiting */
|
||||
#define WPA_EVENT_TERMINATING "CTRL-EVENT-TERMINATING "
|
||||
/** Password change was completed successfully */
|
||||
#define WPA_EVENT_PASSWORD_CHANGED "CTRL-EVENT-PASSWORD-CHANGED "
|
||||
/** EAP-Request/Notification received */
|
||||
#define WPA_EVENT_EAP_NOTIFICATION "CTRL-EVENT-EAP-NOTIFICATION "
|
||||
/** EAP authentication started (EAP-Request/Identity received) */
|
||||
#define WPA_EVENT_EAP_STARTED "CTRL-EVENT-EAP-STARTED "
|
||||
/** EAP method proposed by the server */
|
||||
#define WPA_EVENT_EAP_PROPOSED_METHOD "CTRL-EVENT-EAP-PROPOSED-METHOD "
|
||||
/** EAP method selected */
|
||||
#define WPA_EVENT_EAP_METHOD "CTRL-EVENT-EAP-METHOD "
|
||||
/** EAP peer certificate from TLS */
|
||||
#define WPA_EVENT_EAP_PEER_CERT "CTRL-EVENT-EAP-PEER-CERT "
|
||||
/** EAP peer certificate alternative subject name component from TLS */
|
||||
#define WPA_EVENT_EAP_PEER_ALT "CTRL-EVENT-EAP-PEER-ALT "
|
||||
/** EAP TLS certificate chain validation error */
|
||||
#define WPA_EVENT_EAP_TLS_CERT_ERROR "CTRL-EVENT-EAP-TLS-CERT-ERROR "
|
||||
/** EAP status */
|
||||
#define WPA_EVENT_EAP_STATUS "CTRL-EVENT-EAP-STATUS "
|
||||
/** Retransmit the previous request packet */
|
||||
#define WPA_EVENT_EAP_RETRANSMIT "CTRL-EVENT-EAP-RETRANSMIT "
|
||||
#define WPA_EVENT_EAP_RETRANSMIT2 "CTRL-EVENT-EAP-RETRANSMIT2 "
|
||||
/** EAP authentication completed successfully */
|
||||
#define WPA_EVENT_EAP_SUCCESS "CTRL-EVENT-EAP-SUCCESS "
|
||||
#define WPA_EVENT_EAP_SUCCESS2 "CTRL-EVENT-EAP-SUCCESS2 "
|
||||
/** EAP authentication failed (EAP-Failure received) */
|
||||
#define WPA_EVENT_EAP_FAILURE "CTRL-EVENT-EAP-FAILURE "
|
||||
#define WPA_EVENT_EAP_FAILURE2 "CTRL-EVENT-EAP-FAILURE2 "
|
||||
/** EAP authentication failed due to no response received */
|
||||
#define WPA_EVENT_EAP_TIMEOUT_FAILURE "CTRL-EVENT-EAP-TIMEOUT-FAILURE "
|
||||
#define WPA_EVENT_EAP_TIMEOUT_FAILURE2 "CTRL-EVENT-EAP-TIMEOUT-FAILURE2 "
|
||||
#define WPA_EVENT_EAP_ERROR_CODE "EAP-ERROR-CODE "
|
||||
/** Network block temporarily disabled (e.g., due to authentication failure) */
|
||||
#define WPA_EVENT_TEMP_DISABLED "CTRL-EVENT-SSID-TEMP-DISABLED "
|
||||
/** Temporarily disabled network block re-enabled */
|
||||
#define WPA_EVENT_REENABLED "CTRL-EVENT-SSID-REENABLED "
|
||||
/** New scan started */
|
||||
#define WPA_EVENT_SCAN_STARTED "CTRL-EVENT-SCAN-STARTED "
|
||||
/** New scan results available */
|
||||
#define WPA_EVENT_SCAN_RESULTS "CTRL-EVENT-SCAN-RESULTS "
|
||||
/** Scan command failed */
|
||||
#define WPA_EVENT_SCAN_FAILED "CTRL-EVENT-SCAN-FAILED "
|
||||
/** wpa_supplicant state change */
|
||||
#define WPA_EVENT_STATE_CHANGE "CTRL-EVENT-STATE-CHANGE "
|
||||
/** A new BSS entry was added (followed by BSS entry id and BSSID) */
|
||||
#define WPA_EVENT_BSS_ADDED "CTRL-EVENT-BSS-ADDED "
|
||||
/** A BSS entry was removed (followed by BSS entry id and BSSID) */
|
||||
#define WPA_EVENT_BSS_REMOVED "CTRL-EVENT-BSS-REMOVED "
|
||||
/** No suitable network was found */
|
||||
#define WPA_EVENT_NETWORK_NOT_FOUND "CTRL-EVENT-NETWORK-NOT-FOUND "
|
||||
/** Change in the signal level was reported by the driver */
|
||||
#define WPA_EVENT_SIGNAL_CHANGE "CTRL-EVENT-SIGNAL-CHANGE "
|
||||
/** Beacon loss reported by the driver */
|
||||
#define WPA_EVENT_BEACON_LOSS "CTRL-EVENT-BEACON-LOSS "
|
||||
/** Regulatory domain channel */
|
||||
#define WPA_EVENT_REGDOM_CHANGE "CTRL-EVENT-REGDOM-CHANGE "
|
||||
/** Channel switch started (followed by freq=<MHz> and other channel parameters)
|
||||
*/
|
||||
#define WPA_EVENT_CHANNEL_SWITCH_STARTED "CTRL-EVENT-STARTED-CHANNEL-SWITCH "
|
||||
/** Channel switch (followed by freq=<MHz> and other channel parameters) */
|
||||
#define WPA_EVENT_CHANNEL_SWITCH "CTRL-EVENT-CHANNEL-SWITCH "
|
||||
/** SAE authentication failed due to unknown password identifier */
|
||||
#define WPA_EVENT_SAE_UNKNOWN_PASSWORD_IDENTIFIER \
|
||||
"CTRL-EVENT-SAE-UNKNOWN-PASSWORD-IDENTIFIER "
|
||||
/** Unprotected Beacon frame dropped */
|
||||
#define WPA_EVENT_UNPROT_BEACON "CTRL-EVENT-UNPROT-BEACON "
|
||||
/** Decision made to do a within-ESS roam */
|
||||
#define WPA_EVENT_DO_ROAM "CTRL-EVENT-DO-ROAM "
|
||||
/** Decision made to skip a within-ESS roam */
|
||||
#define WPA_EVENT_SKIP_ROAM "CTRL-EVENT-SKIP-ROAM "
|
||||
|
||||
/** IP subnet status change notification
|
||||
*
|
||||
* When using an offloaded roaming mechanism where driver/firmware takes care
|
||||
* of roaming and IP subnet validation checks post-roaming, this event can
|
||||
* indicate whether IP subnet has changed.
|
||||
*
|
||||
* The event has a status=<0/1/2> parameter where
|
||||
* 0 = unknown
|
||||
* 1 = IP subnet unchanged (can continue to use the old IP address)
|
||||
* 2 = IP subnet changed (need to get a new IP address)
|
||||
*/
|
||||
#define WPA_EVENT_SUBNET_STATUS_UPDATE "CTRL-EVENT-SUBNET-STATUS-UPDATE "
|
||||
|
||||
/** RSN IBSS 4-way handshakes completed with specified peer */
|
||||
#define IBSS_RSN_COMPLETED "IBSS-RSN-COMPLETED "
|
||||
|
||||
/** Notification of frequency conflict due to a concurrent operation.
|
||||
*
|
||||
* The indicated network is disabled and needs to be re-enabled before it can
|
||||
* be used again.
|
||||
*/
|
||||
#define WPA_EVENT_FREQ_CONFLICT "CTRL-EVENT-FREQ-CONFLICT "
|
||||
/** Frequency ranges that the driver recommends to avoid */
|
||||
#define WPA_EVENT_AVOID_FREQ "CTRL-EVENT-AVOID-FREQ "
|
||||
/** A new network profile was added (followed by network entry id) */
|
||||
#define WPA_EVENT_NETWORK_ADDED "CTRL-EVENT-NETWORK-ADDED "
|
||||
/** A network profile was removed (followed by prior network entry id) */
|
||||
#define WPA_EVENT_NETWORK_REMOVED "CTRL-EVENT-NETWORK-REMOVED "
|
||||
/** Result of MSCS setup */
|
||||
#define WPA_EVENT_MSCS_RESULT "CTRL-EVENT-MSCS-RESULT "
|
||||
/** WPS overlap detected in PBC mode */
|
||||
#define WPS_EVENT_OVERLAP "WPS-OVERLAP-DETECTED "
|
||||
/** Available WPS AP with active PBC found in scan results */
|
||||
#define WPS_EVENT_AP_AVAILABLE_PBC "WPS-AP-AVAILABLE-PBC "
|
||||
/** Available WPS AP with our address as authorized in scan results */
|
||||
#define WPS_EVENT_AP_AVAILABLE_AUTH "WPS-AP-AVAILABLE-AUTH "
|
||||
/** Available WPS AP with recently selected PIN registrar found in scan results
|
||||
*/
|
||||
#define WPS_EVENT_AP_AVAILABLE_PIN "WPS-AP-AVAILABLE-PIN "
|
||||
/** Available WPS AP found in scan results */
|
||||
#define WPS_EVENT_AP_AVAILABLE "WPS-AP-AVAILABLE "
|
||||
/** A new credential received */
|
||||
#define WPS_EVENT_CRED_RECEIVED "WPS-CRED-RECEIVED "
|
||||
/** M2D received */
|
||||
#define WPS_EVENT_M2D "WPS-M2D "
|
||||
/** WPS registration failed after M2/M2D */
|
||||
#define WPS_EVENT_FAIL "WPS-FAIL "
|
||||
/** WPS registration completed successfully */
|
||||
#define WPS_EVENT_SUCCESS "WPS-SUCCESS "
|
||||
/** WPS enrollment attempt timed out and was terminated */
|
||||
#define WPS_EVENT_TIMEOUT "WPS-TIMEOUT "
|
||||
/* PBC mode was activated */
|
||||
#define WPS_EVENT_ACTIVE "WPS-PBC-ACTIVE "
|
||||
/* PBC mode was disabled */
|
||||
#define WPS_EVENT_DISABLE "WPS-PBC-DISABLE "
|
||||
|
||||
#define WPS_EVENT_ENROLLEE_SEEN "WPS-ENROLLEE-SEEN "
|
||||
|
||||
#define WPS_EVENT_OPEN_NETWORK "WPS-OPEN-NETWORK "
|
||||
/** Result of SCS setup */
|
||||
#define WPA_EVENT_SCS_RESULT "CTRL-EVENT-SCS-RESULT "
|
||||
/* Event indicating DSCP policy */
|
||||
#define WPA_EVENT_DSCP_POLICY "CTRL-EVENT-DSCP-POLICY "
|
||||
|
||||
/* WPS ER events */
|
||||
#define WPS_EVENT_ER_AP_ADD "WPS-ER-AP-ADD "
|
||||
#define WPS_EVENT_ER_AP_REMOVE "WPS-ER-AP-REMOVE "
|
||||
#define WPS_EVENT_ER_ENROLLEE_ADD "WPS-ER-ENROLLEE-ADD "
|
||||
#define WPS_EVENT_ER_ENROLLEE_REMOVE "WPS-ER-ENROLLEE-REMOVE "
|
||||
#define WPS_EVENT_ER_AP_SETTINGS "WPS-ER-AP-SETTINGS "
|
||||
#define WPS_EVENT_ER_SET_SEL_REG "WPS-ER-AP-SET-SEL-REG "
|
||||
|
||||
/* DPP events */
|
||||
#define DPP_EVENT_AUTH_SUCCESS "DPP-AUTH-SUCCESS "
|
||||
#define DPP_EVENT_AUTH_INIT_FAILED "DPP-AUTH-INIT-FAILED "
|
||||
#define DPP_EVENT_NOT_COMPATIBLE "DPP-NOT-COMPATIBLE "
|
||||
#define DPP_EVENT_RESPONSE_PENDING "DPP-RESPONSE-PENDING "
|
||||
#define DPP_EVENT_SCAN_PEER_QR_CODE "DPP-SCAN-PEER-QR-CODE "
|
||||
#define DPP_EVENT_AUTH_DIRECTION "DPP-AUTH-DIRECTION "
|
||||
#define DPP_EVENT_CONF_RECEIVED "DPP-CONF-RECEIVED "
|
||||
#define DPP_EVENT_CONF_SENT "DPP-CONF-SENT "
|
||||
#define DPP_EVENT_CONF_FAILED "DPP-CONF-FAILED "
|
||||
#define DPP_EVENT_CONN_STATUS_RESULT "DPP-CONN-STATUS-RESULT "
|
||||
#define DPP_EVENT_CONFOBJ_AKM "DPP-CONFOBJ-AKM "
|
||||
#define DPP_EVENT_CONFOBJ_SSID "DPP-CONFOBJ-SSID "
|
||||
#define DPP_EVENT_CONFOBJ_SSID_CHARSET "DPP-CONFOBJ-SSID-CHARSET "
|
||||
#define DPP_EVENT_CONFOBJ_PASS "DPP-CONFOBJ-PASS "
|
||||
#define DPP_EVENT_CONFOBJ_PSK "DPP-CONFOBJ-PSK "
|
||||
#define DPP_EVENT_CONNECTOR "DPP-CONNECTOR "
|
||||
#define DPP_EVENT_C_SIGN_KEY "DPP-C-SIGN-KEY "
|
||||
#define DPP_EVENT_PP_KEY "DPP-PP-KEY "
|
||||
#define DPP_EVENT_NET_ACCESS_KEY "DPP-NET-ACCESS-KEY "
|
||||
#define DPP_EVENT_SERVER_NAME "DPP-SERVER-NAME "
|
||||
#define DPP_EVENT_CERTBAG "DPP-CERTBAG "
|
||||
#define DPP_EVENT_CACERT "DPP-CACERT "
|
||||
#define DPP_EVENT_MISSING_CONNECTOR "DPP-MISSING-CONNECTOR "
|
||||
#define DPP_EVENT_NETWORK_ID "DPP-NETWORK-ID "
|
||||
#define DPP_EVENT_CONFIGURATOR_ID "DPP-CONFIGURATOR-ID "
|
||||
#define DPP_EVENT_RX "DPP-RX "
|
||||
#define DPP_EVENT_TX "DPP-TX "
|
||||
#define DPP_EVENT_TX_STATUS "DPP-TX-STATUS "
|
||||
#define DPP_EVENT_FAIL "DPP-FAIL "
|
||||
#define DPP_EVENT_PKEX_T_LIMIT "DPP-PKEX-T-LIMIT "
|
||||
#define DPP_EVENT_INTRO "DPP-INTRO "
|
||||
#define DPP_EVENT_CONF_REQ_RX "DPP-CONF-REQ-RX "
|
||||
#define DPP_EVENT_CHIRP_STOPPED "DPP-CHIRP-STOPPED "
|
||||
#define DPP_EVENT_MUD_URL "DPP-MUD-URL "
|
||||
#define DPP_EVENT_BAND_SUPPORT "DPP-BAND-SUPPORT "
|
||||
#define DPP_EVENT_CSR "DPP-CSR "
|
||||
#define DPP_EVENT_CHIRP_RX "DPP-CHIRP-RX "
|
||||
|
||||
/* MESH events */
|
||||
#define MESH_GROUP_STARTED "MESH-GROUP-STARTED "
|
||||
#define MESH_GROUP_REMOVED "MESH-GROUP-REMOVED "
|
||||
#define MESH_PEER_CONNECTED "MESH-PEER-CONNECTED "
|
||||
#define MESH_PEER_DISCONNECTED "MESH-PEER-DISCONNECTED "
|
||||
/** Mesh SAE authentication failure. Wrong password suspected. */
|
||||
#define MESH_SAE_AUTH_FAILURE "MESH-SAE-AUTH-FAILURE "
|
||||
#define MESH_SAE_AUTH_BLOCKED "MESH-SAE-AUTH-BLOCKED "
|
||||
|
||||
/* WMM AC events */
|
||||
#define WMM_AC_EVENT_TSPEC_ADDED "TSPEC-ADDED "
|
||||
#define WMM_AC_EVENT_TSPEC_REMOVED "TSPEC-REMOVED "
|
||||
#define WMM_AC_EVENT_TSPEC_REQ_FAILED "TSPEC-REQ-FAILED "
|
||||
|
||||
/** P2P device found */
|
||||
#define P2P_EVENT_DEVICE_FOUND "P2P-DEVICE-FOUND "
|
||||
|
||||
/** P2P device lost */
|
||||
#define P2P_EVENT_DEVICE_LOST "P2P-DEVICE-LOST "
|
||||
|
||||
/** A P2P device requested GO negotiation, but we were not ready to start the
|
||||
* negotiation */
|
||||
#define P2P_EVENT_GO_NEG_REQUEST "P2P-GO-NEG-REQUEST "
|
||||
#define P2P_EVENT_GO_NEG_SUCCESS "P2P-GO-NEG-SUCCESS "
|
||||
#define P2P_EVENT_GO_NEG_FAILURE "P2P-GO-NEG-FAILURE "
|
||||
#define P2P_EVENT_GROUP_FORMATION_SUCCESS "P2P-GROUP-FORMATION-SUCCESS "
|
||||
#define P2P_EVENT_GROUP_FORMATION_FAILURE "P2P-GROUP-FORMATION-FAILURE "
|
||||
#define P2P_EVENT_GROUP_STARTED "P2P-GROUP-STARTED "
|
||||
#define P2P_EVENT_GROUP_REMOVED "P2P-GROUP-REMOVED "
|
||||
#define P2P_EVENT_CROSS_CONNECT_ENABLE "P2P-CROSS-CONNECT-ENABLE "
|
||||
#define P2P_EVENT_CROSS_CONNECT_DISABLE "P2P-CROSS-CONNECT-DISABLE "
|
||||
/* parameters: <peer address> <PIN> */
|
||||
#define P2P_EVENT_PROV_DISC_SHOW_PIN "P2P-PROV-DISC-SHOW-PIN "
|
||||
/* parameters: <peer address> */
|
||||
#define P2P_EVENT_PROV_DISC_ENTER_PIN "P2P-PROV-DISC-ENTER-PIN "
|
||||
/* parameters: <peer address> */
|
||||
#define P2P_EVENT_PROV_DISC_PBC_REQ "P2P-PROV-DISC-PBC-REQ "
|
||||
/* parameters: <peer address> */
|
||||
#define P2P_EVENT_PROV_DISC_PBC_RESP "P2P-PROV-DISC-PBC-RESP "
|
||||
/* parameters: <peer address> <status> */
|
||||
#define P2P_EVENT_PROV_DISC_FAILURE "P2P-PROV-DISC-FAILURE"
|
||||
/* parameters: <freq> <src addr> <dialog token> <update indicator> <TLVs> */
|
||||
#define P2P_EVENT_SERV_DISC_REQ "P2P-SERV-DISC-REQ "
|
||||
/* parameters: <src addr> <update indicator> <TLVs> */
|
||||
#define P2P_EVENT_SERV_DISC_RESP "P2P-SERV-DISC-RESP "
|
||||
#define P2P_EVENT_SERV_ASP_RESP "P2P-SERV-ASP-RESP "
|
||||
#define P2P_EVENT_INVITATION_RECEIVED "P2P-INVITATION-RECEIVED "
|
||||
#define P2P_EVENT_INVITATION_RESULT "P2P-INVITATION-RESULT "
|
||||
#define P2P_EVENT_INVITATION_ACCEPTED "P2P-INVITATION-ACCEPTED "
|
||||
#define P2P_EVENT_FIND_STOPPED "P2P-FIND-STOPPED "
|
||||
#define P2P_EVENT_PERSISTENT_PSK_FAIL "P2P-PERSISTENT-PSK-FAIL id="
|
||||
#define P2P_EVENT_PRESENCE_RESPONSE "P2P-PRESENCE-RESPONSE "
|
||||
#define P2P_EVENT_NFC_BOTH_GO "P2P-NFC-BOTH-GO "
|
||||
#define P2P_EVENT_NFC_PEER_CLIENT "P2P-NFC-PEER-CLIENT "
|
||||
#define P2P_EVENT_NFC_WHILE_CLIENT "P2P-NFC-WHILE-CLIENT "
|
||||
#define P2P_EVENT_FALLBACK_TO_GO_NEG "P2P-FALLBACK-TO-GO-NEG "
|
||||
#define P2P_EVENT_FALLBACK_TO_GO_NEG_ENABLED "P2P-FALLBACK-TO-GO-NEG-ENABLED "
|
||||
|
||||
/* parameters: <PMF enabled> <timeout in ms> <Session Information URL> */
|
||||
#define ESS_DISASSOC_IMMINENT "ESS-DISASSOC-IMMINENT "
|
||||
#define P2P_EVENT_REMOVE_AND_REFORM_GROUP "P2P-REMOVE-AND-REFORM-GROUP "
|
||||
|
||||
#define P2P_EVENT_P2PS_PROVISION_START "P2PS-PROV-START "
|
||||
#define P2P_EVENT_P2PS_PROVISION_DONE "P2PS-PROV-DONE "
|
||||
|
||||
#define INTERWORKING_AP "INTERWORKING-AP "
|
||||
#define INTERWORKING_EXCLUDED "INTERWORKING-BLACKLISTED "
|
||||
#define INTERWORKING_NO_MATCH "INTERWORKING-NO-MATCH "
|
||||
#define INTERWORKING_ALREADY_CONNECTED "INTERWORKING-ALREADY-CONNECTED "
|
||||
#define INTERWORKING_SELECTED "INTERWORKING-SELECTED "
|
||||
|
||||
/* Credential block added; parameters: <id> */
|
||||
#define CRED_ADDED "CRED-ADDED "
|
||||
/* Credential block modified; parameters: <id> <field> */
|
||||
#define CRED_MODIFIED "CRED-MODIFIED "
|
||||
/* Credential block removed; parameters: <id> */
|
||||
#define CRED_REMOVED "CRED-REMOVED "
|
||||
|
||||
#define GAS_RESPONSE_INFO "GAS-RESPONSE-INFO "
|
||||
/* parameters: <addr> <dialog_token> <freq> */
|
||||
#define GAS_QUERY_START "GAS-QUERY-START "
|
||||
/* parameters: <addr> <dialog_token> <freq> <status_code> <result> */
|
||||
#define GAS_QUERY_DONE "GAS-QUERY-DONE "
|
||||
|
||||
/* parameters: <addr> <result> */
|
||||
#define ANQP_QUERY_DONE "ANQP-QUERY-DONE "
|
||||
|
||||
#define RX_ANQP "RX-ANQP "
|
||||
#define RX_HS20_ANQP "RX-HS20-ANQP "
|
||||
#define RX_HS20_ANQP_ICON "RX-HS20-ANQP-ICON "
|
||||
#define RX_HS20_ICON "RX-HS20-ICON "
|
||||
#define RX_MBO_ANQP "RX-MBO-ANQP "
|
||||
|
||||
/* parameters: <Venue Number> <Venue URL> */
|
||||
#define RX_VENUE_URL "RX-VENUE-URL "
|
||||
|
||||
#define HS20_SUBSCRIPTION_REMEDIATION "HS20-SUBSCRIPTION-REMEDIATION "
|
||||
#define HS20_DEAUTH_IMMINENT_NOTICE "HS20-DEAUTH-IMMINENT-NOTICE "
|
||||
#define HS20_T_C_ACCEPTANCE "HS20-T-C-ACCEPTANCE "
|
||||
|
||||
#define EXT_RADIO_WORK_START "EXT-RADIO-WORK-START "
|
||||
#define EXT_RADIO_WORK_TIMEOUT "EXT-RADIO-WORK-TIMEOUT "
|
||||
|
||||
#define RRM_EVENT_NEIGHBOR_REP_RXED "RRM-NEIGHBOR-REP-RECEIVED "
|
||||
#define RRM_EVENT_NEIGHBOR_REP_FAILED "RRM-NEIGHBOR-REP-REQUEST-FAILED "
|
||||
|
||||
/* hostapd control interface - fixed message prefixes */
|
||||
#define WPS_EVENT_PIN_NEEDED "WPS-PIN-NEEDED "
|
||||
#define WPS_EVENT_NEW_AP_SETTINGS "WPS-NEW-AP-SETTINGS "
|
||||
#define WPS_EVENT_REG_SUCCESS "WPS-REG-SUCCESS "
|
||||
#define WPS_EVENT_AP_SETUP_LOCKED "WPS-AP-SETUP-LOCKED "
|
||||
#define WPS_EVENT_AP_SETUP_UNLOCKED "WPS-AP-SETUP-UNLOCKED "
|
||||
#define WPS_EVENT_AP_PIN_ENABLED "WPS-AP-PIN-ENABLED "
|
||||
#define WPS_EVENT_AP_PIN_DISABLED "WPS-AP-PIN-DISABLED "
|
||||
#define WPS_EVENT_PIN_ACTIVE "WPS-PIN-ACTIVE "
|
||||
#define WPS_EVENT_CANCEL "WPS-CANCEL "
|
||||
#define AP_STA_CONNECTED "AP-STA-CONNECTED "
|
||||
#define AP_STA_DISCONNECTED "AP-STA-DISCONNECTED "
|
||||
#define AP_STA_POSSIBLE_PSK_MISMATCH "AP-STA-POSSIBLE-PSK-MISMATCH "
|
||||
#define AP_STA_POLL_OK "AP-STA-POLL-OK "
|
||||
|
||||
#define AP_REJECTED_MAX_STA "AP-REJECTED-MAX-STA "
|
||||
#define AP_REJECTED_BLOCKED_STA "AP-REJECTED-BLOCKED-STA "
|
||||
|
||||
#define HS20_T_C_FILTERING_ADD "HS20-T-C-FILTERING-ADD "
|
||||
#define HS20_T_C_FILTERING_REMOVE "HS20-T-C-FILTERING-REMOVE "
|
||||
|
||||
#define AP_EVENT_ENABLED "AP-ENABLED "
|
||||
#define AP_EVENT_DISABLED "AP-DISABLED "
|
||||
|
||||
#define INTERFACE_ENABLED "INTERFACE-ENABLED "
|
||||
#define INTERFACE_DISABLED "INTERFACE-DISABLED "
|
||||
|
||||
#define ACS_EVENT_STARTED "ACS-STARTED "
|
||||
#define ACS_EVENT_COMPLETED "ACS-COMPLETED "
|
||||
#define ACS_EVENT_FAILED "ACS-FAILED "
|
||||
|
||||
#define DFS_EVENT_RADAR_DETECTED "DFS-RADAR-DETECTED "
|
||||
#define DFS_EVENT_NEW_CHANNEL "DFS-NEW-CHANNEL "
|
||||
#define DFS_EVENT_CAC_START "DFS-CAC-START "
|
||||
#define DFS_EVENT_CAC_COMPLETED "DFS-CAC-COMPLETED "
|
||||
#define DFS_EVENT_NOP_FINISHED "DFS-NOP-FINISHED "
|
||||
#define DFS_EVENT_PRE_CAC_EXPIRED "DFS-PRE-CAC-EXPIRED "
|
||||
|
||||
#define AP_CSA_FINISHED "AP-CSA-FINISHED "
|
||||
|
||||
#define P2P_EVENT_LISTEN_OFFLOAD_STOP "P2P-LISTEN-OFFLOAD-STOPPED "
|
||||
#define P2P_LISTEN_OFFLOAD_STOP_REASON "P2P-LISTEN-OFFLOAD-STOP-REASON "
|
||||
|
||||
/* BSS Transition Management Response frame received */
|
||||
#define BSS_TM_RESP "BSS-TM-RESP "
|
||||
|
||||
/* Collocated Interference Request frame received;
|
||||
* parameters: <dialog token> <automatic report enabled> <report timeout> */
|
||||
#define COLOC_INTF_REQ "COLOC-INTF-REQ "
|
||||
/* Collocated Interference Report frame received;
|
||||
* parameters: <STA address> <dialog token> <hexdump of report elements> */
|
||||
#define COLOC_INTF_REPORT "COLOC-INTF-REPORT "
|
||||
|
||||
/* MBO IE with cellular data connection preference received */
|
||||
#define MBO_CELL_PREFERENCE "MBO-CELL-PREFERENCE "
|
||||
|
||||
/* BSS Transition Management Request received with MBO transition reason */
|
||||
#define MBO_TRANSITION_REASON "MBO-TRANSITION-REASON "
|
||||
|
||||
/* parameters: <STA address> <dialog token> <ack=0/1> */
|
||||
#define BEACON_REQ_TX_STATUS "BEACON-REQ-TX-STATUS "
|
||||
/* parameters: <STA address> <dialog token> <report mode> <beacon report> */
|
||||
#define BEACON_RESP_RX "BEACON-RESP-RX "
|
||||
|
||||
/* PMKSA cache entry added; parameters: <BSSID> <network_id> */
|
||||
#define PMKSA_CACHE_ADDED "PMKSA-CACHE-ADDED "
|
||||
/* PMKSA cache entry removed; parameters: <BSSID> <network_id> */
|
||||
#define PMKSA_CACHE_REMOVED "PMKSA-CACHE-REMOVED "
|
||||
|
||||
/* FILS HLP Container receive; parameters: dst=<addr> src=<addr> frame=<hexdump>
|
||||
*/
|
||||
#define FILS_HLP_RX "FILS-HLP-RX "
|
||||
|
||||
/* Event to indicate Probe Request frame;
|
||||
* parameters: sa=<STA MAC address> signal=<signal> */
|
||||
#define RX_PROBE_REQUEST "RX-PROBE-REQUEST "
|
||||
|
||||
/* Event to indicate station's HT/VHT operation mode change information */
|
||||
#define STA_OPMODE_MAX_BW_CHANGED "STA-OPMODE-MAX-BW-CHANGED "
|
||||
#define STA_OPMODE_SMPS_MODE_CHANGED "STA-OPMODE-SMPS-MODE-CHANGED "
|
||||
#define STA_OPMODE_N_SS_CHANGED "STA-OPMODE-N_SS-CHANGED "
|
||||
|
||||
/* New interface addition or removal for 4addr WDS SDA */
|
||||
#define WDS_STA_INTERFACE_ADDED "WDS-STA-INTERFACE-ADDED "
|
||||
#define WDS_STA_INTERFACE_REMOVED "WDS-STA-INTERFACE-REMOVED "
|
||||
|
||||
/* Transition mode disabled indication - followed by bitmap */
|
||||
#define TRANSITION_DISABLE "TRANSITION-DISABLE "
|
||||
|
||||
/* OCV validation failure; parameters: addr=<src addr>
|
||||
* frame=<saqueryreq/saqueryresp> error=<error string> */
|
||||
#define OCV_FAILURE "OCV-FAILURE "
|
||||
|
||||
/* Event triggered for received management frame */
|
||||
#define AP_MGMT_FRAME_RECEIVED "AP-MGMT-FRAME-RECEIVED "
|
||||
|
||||
#ifndef BIT
|
||||
#define BIT(x) (1U << (x))
|
||||
#endif
|
||||
|
||||
/* PASN authentication status */
|
||||
#define PASN_AUTH_STATUS "PASN-AUTH-STATUS "
|
||||
|
||||
/* BSS command information masks */
|
||||
|
||||
#define WPA_BSS_MASK_ALL 0xFFFDFFFF
|
||||
#define WPA_BSS_MASK_ID BIT(0)
|
||||
#define WPA_BSS_MASK_BSSID BIT(1)
|
||||
#define WPA_BSS_MASK_FREQ BIT(2)
|
||||
#define WPA_BSS_MASK_BEACON_INT BIT(3)
|
||||
#define WPA_BSS_MASK_CAPABILITIES BIT(4)
|
||||
#define WPA_BSS_MASK_QUAL BIT(5)
|
||||
#define WPA_BSS_MASK_NOISE BIT(6)
|
||||
#define WPA_BSS_MASK_LEVEL BIT(7)
|
||||
#define WPA_BSS_MASK_TSF BIT(8)
|
||||
#define WPA_BSS_MASK_AGE BIT(9)
|
||||
#define WPA_BSS_MASK_IE BIT(10)
|
||||
#define WPA_BSS_MASK_FLAGS BIT(11)
|
||||
#define WPA_BSS_MASK_SSID BIT(12)
|
||||
#define WPA_BSS_MASK_WPS_SCAN BIT(13)
|
||||
#define WPA_BSS_MASK_P2P_SCAN BIT(14)
|
||||
#define WPA_BSS_MASK_INTERNETW BIT(15)
|
||||
#define WPA_BSS_MASK_WIFI_DISPLAY BIT(16)
|
||||
#define WPA_BSS_MASK_DELIM BIT(17)
|
||||
#define WPA_BSS_MASK_MESH_SCAN BIT(18)
|
||||
#define WPA_BSS_MASK_SNR BIT(19)
|
||||
#define WPA_BSS_MASK_EST_THROUGHPUT BIT(20)
|
||||
#define WPA_BSS_MASK_FST BIT(21)
|
||||
#define WPA_BSS_MASK_UPDATE_IDX BIT(22)
|
||||
#define WPA_BSS_MASK_BEACON_IE BIT(23)
|
||||
#define WPA_BSS_MASK_FILS_INDICATION BIT(24)
|
||||
|
||||
|
||||
/* VENDOR_ELEM_* frame id values */
|
||||
enum wpa_vendor_elem_frame {
|
||||
VENDOR_ELEM_PROBE_REQ_P2P = 0,
|
||||
VENDOR_ELEM_PROBE_RESP_P2P = 1,
|
||||
VENDOR_ELEM_PROBE_RESP_P2P_GO = 2,
|
||||
VENDOR_ELEM_BEACON_P2P_GO = 3,
|
||||
VENDOR_ELEM_P2P_PD_REQ = 4,
|
||||
VENDOR_ELEM_P2P_PD_RESP = 5,
|
||||
VENDOR_ELEM_P2P_GO_NEG_REQ = 6,
|
||||
VENDOR_ELEM_P2P_GO_NEG_RESP = 7,
|
||||
VENDOR_ELEM_P2P_GO_NEG_CONF = 8,
|
||||
VENDOR_ELEM_P2P_INV_REQ = 9,
|
||||
VENDOR_ELEM_P2P_INV_RESP = 10,
|
||||
VENDOR_ELEM_P2P_ASSOC_REQ = 11,
|
||||
VENDOR_ELEM_P2P_ASSOC_RESP = 12,
|
||||
VENDOR_ELEM_ASSOC_REQ = 13,
|
||||
VENDOR_ELEM_PROBE_REQ = 14,
|
||||
NUM_VENDOR_ELEM_FRAMES
|
||||
};
|
||||
|
||||
|
||||
/* wpa_supplicant/hostapd control interface access */
|
||||
|
||||
/**
|
||||
* wpa_ctrl_open - Open a control interface to wpa_supplicant/hostapd
|
||||
* @ctrl_path: Path for UNIX domain sockets; ignored if UDP sockets are used.
|
||||
* Returns: Pointer to abstract control interface data or %NULL on failure
|
||||
*
|
||||
* This function is used to open a control interface to wpa_supplicant/hostapd.
|
||||
* ctrl_path is usually /var/run/wpa_supplicant or /var/run/hostapd. This path
|
||||
* is configured in wpa_supplicant/hostapd and other programs using the control
|
||||
* interface need to use matching path configuration.
|
||||
*/
|
||||
struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path);
|
||||
|
||||
/**
|
||||
* wpa_ctrl_open2 - Open a control interface to wpa_supplicant/hostapd
|
||||
* @ctrl_path: Path for UNIX domain sockets; ignored if UDP sockets are used.
|
||||
* @cli_path: Path for client UNIX domain sockets; ignored if UDP socket
|
||||
* is used.
|
||||
* Returns: Pointer to abstract control interface data or %NULL on failure
|
||||
*
|
||||
* This function is used to open a control interface to wpa_supplicant/hostapd
|
||||
* when the socket path for client need to be specified explicitly. Default
|
||||
* ctrl_path is usually /var/run/wpa_supplicant or /var/run/hostapd and client
|
||||
* socket path is /tmp.
|
||||
*/
|
||||
struct wpa_ctrl * wpa_ctrl_open2(const char *ctrl_path, const char *cli_path);
|
||||
|
||||
|
||||
/**
|
||||
* wpa_ctrl_close - Close a control interface to wpa_supplicant/hostapd
|
||||
* @ctrl: Control interface data from wpa_ctrl_open()
|
||||
*
|
||||
* This function is used to close a control interface.
|
||||
*/
|
||||
void wpa_ctrl_close(struct wpa_ctrl *ctrl);
|
||||
|
||||
|
||||
/**
|
||||
* wpa_ctrl_request - Send a command to wpa_supplicant/hostapd
|
||||
* @ctrl: Control interface data from wpa_ctrl_open()
|
||||
* @cmd: Command; usually, ASCII text, e.g., "PING"
|
||||
* @cmd_len: Length of the cmd in bytes
|
||||
* @reply: Buffer for the response
|
||||
* @reply_len: Reply buffer length
|
||||
* @msg_cb: Callback function for unsolicited messages or %NULL if not used
|
||||
* Returns: 0 on success, -1 on error (send or receive failed), -2 on timeout
|
||||
*
|
||||
* This function is used to send commands to wpa_supplicant/hostapd. Received
|
||||
* response will be written to reply and reply_len is set to the actual length
|
||||
* of the reply. This function will block for up to 10 seconds while waiting
|
||||
* for the reply. If unsolicited messages are received, the blocking time may
|
||||
* be longer.
|
||||
*
|
||||
* msg_cb can be used to register a callback function that will be called for
|
||||
* unsolicited messages received while waiting for the command response. These
|
||||
* messages may be received if wpa_ctrl_request() is called at the same time as
|
||||
* wpa_supplicant/hostapd is sending such a message. This can happen only if
|
||||
* the program has used wpa_ctrl_attach() to register itself as a monitor for
|
||||
* event messages. Alternatively to msg_cb, programs can register two control
|
||||
* interface connections and use one of them for commands and the other one for
|
||||
* receiving event messages, in other words, call wpa_ctrl_attach() only for
|
||||
* the control interface connection that will be used for event messages.
|
||||
*/
|
||||
int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
|
||||
char *reply, size_t *reply_len,
|
||||
void (*msg_cb)(char *msg, size_t len));
|
||||
|
||||
|
||||
/**
|
||||
* wpa_ctrl_attach - Register as an event monitor for the control interface
|
||||
* @ctrl: Control interface data from wpa_ctrl_open()
|
||||
* Returns: 0 on success, -1 on failure, -2 on timeout
|
||||
*
|
||||
* This function registers the control interface connection as a monitor for
|
||||
* wpa_supplicant/hostapd events. After a success wpa_ctrl_attach() call, the
|
||||
* control interface connection starts receiving event messages that can be
|
||||
* read with wpa_ctrl_recv().
|
||||
*/
|
||||
int wpa_ctrl_attach(struct wpa_ctrl *ctrl);
|
||||
|
||||
|
||||
/**
|
||||
* wpa_ctrl_detach - Unregister event monitor from the control interface
|
||||
* @ctrl: Control interface data from wpa_ctrl_open()
|
||||
* Returns: 0 on success, -1 on failure, -2 on timeout
|
||||
*
|
||||
* This function unregisters the control interface connection as a monitor for
|
||||
* wpa_supplicant/hostapd events, i.e., cancels the registration done with
|
||||
* wpa_ctrl_attach().
|
||||
*/
|
||||
int wpa_ctrl_detach(struct wpa_ctrl *ctrl);
|
||||
|
||||
|
||||
/**
|
||||
* wpa_ctrl_recv - Receive a pending control interface message
|
||||
* @ctrl: Control interface data from wpa_ctrl_open()
|
||||
* @reply: Buffer for the message data
|
||||
* @reply_len: Length of the reply buffer
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*
|
||||
* This function will receive a pending control interface message. The received
|
||||
* response will be written to reply and reply_len is set to the actual length
|
||||
* of the reply.
|
||||
|
||||
* wpa_ctrl_recv() is only used for event messages, i.e., wpa_ctrl_attach()
|
||||
* must have been used to register the control interface as an event monitor.
|
||||
*/
|
||||
int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len);
|
||||
|
||||
|
||||
/**
|
||||
* wpa_ctrl_pending - Check whether there are pending event messages
|
||||
* @ctrl: Control interface data from wpa_ctrl_open()
|
||||
* Returns: 1 if there are pending messages, 0 if no, or -1 on error
|
||||
*
|
||||
* This function will check whether there are any pending control interface
|
||||
* message available to be received with wpa_ctrl_recv(). wpa_ctrl_pending() is
|
||||
* only used for event messages, i.e., wpa_ctrl_attach() must have been used to
|
||||
* register the control interface as an event monitor.
|
||||
*/
|
||||
int wpa_ctrl_pending(struct wpa_ctrl *ctrl);
|
||||
|
||||
|
||||
/**
|
||||
* wpa_ctrl_get_fd - Get file descriptor used by the control interface
|
||||
* @ctrl: Control interface data from wpa_ctrl_open()
|
||||
* Returns: File descriptor used for the connection
|
||||
*
|
||||
* This function can be used to get the file descriptor that is used for the
|
||||
* control interface connection. The returned value can be used, e.g., with
|
||||
* select() while waiting for multiple events.
|
||||
*
|
||||
* The returned file descriptor must not be used directly for sending or
|
||||
* receiving packets; instead, the library functions wpa_ctrl_request() and
|
||||
* wpa_ctrl_recv() must be used for this.
|
||||
*/
|
||||
int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl);
|
||||
|
||||
#ifdef ANDROID
|
||||
/**
|
||||
* wpa_ctrl_cleanup() - Delete any local UNIX domain socket files that
|
||||
* may be left over from clients that were previously connected to
|
||||
* wpa_supplicant. This keeps these files from being orphaned in the
|
||||
* event of crashes that prevented them from being removed as part
|
||||
* of the normal orderly shutdown.
|
||||
*/
|
||||
void wpa_ctrl_cleanup(void);
|
||||
#endif /* ANDROID */
|
||||
|
||||
#ifdef CONFIG_CTRL_IFACE_UDP
|
||||
/* Port range for multiple wpa_supplicant instances and multiple VIFs */
|
||||
#define WPA_CTRL_IFACE_PORT 9877
|
||||
#define WPA_CTRL_IFACE_PORT_LIMIT 50 /* decremented from start */
|
||||
#define WPA_GLOBAL_CTRL_IFACE_PORT 9878
|
||||
#define WPA_GLOBAL_CTRL_IFACE_PORT_LIMIT 20 /* incremented from start */
|
||||
|
||||
char * wpa_ctrl_get_remote_ifname(struct wpa_ctrl *ctrl);
|
||||
#endif /* CONFIG_CTRL_IFACE_UDP */
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* WPA_CTRL_H */
|
@ -0,0 +1,370 @@
|
||||
/*
|
||||
* wpa_supplicant/hostapd / Debug prints
|
||||
* Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef WPA_DEBUG_H
|
||||
#define WPA_DEBUG_H
|
||||
|
||||
#include "wpabuf.h"
|
||||
|
||||
extern int wpa_debug_level;
|
||||
extern int wpa_debug_show_keys;
|
||||
extern int wpa_debug_timestamp;
|
||||
extern int wpa_debug_syslog;
|
||||
|
||||
/* Debugging function - conditional printf and hex dump. Driver wrappers can
|
||||
* use these for debugging purposes. */
|
||||
|
||||
enum {
|
||||
MSG_EXCESSIVE, MSG_MSGDUMP, MSG_DEBUG, MSG_INFO, MSG_WARNING, MSG_ERROR
|
||||
};
|
||||
|
||||
#ifdef CONFIG_NO_STDOUT_DEBUG
|
||||
|
||||
#define wpa_debug_print_timestamp() do { } while (0)
|
||||
#define wpa_printf(args...) do { } while (0)
|
||||
#define wpa_hexdump(l,t,b,le) do { } while (0)
|
||||
#define wpa_hexdump_buf(l,t,b) do { } while (0)
|
||||
#define wpa_hexdump_key(l,t,b,le) do { } while (0)
|
||||
#define wpa_hexdump_buf_key(l,t,b) do { } while (0)
|
||||
#define wpa_hexdump_ascii(l,t,b,le) do { } while (0)
|
||||
#define wpa_hexdump_ascii_key(l,t,b,le) do { } while (0)
|
||||
#define wpa_debug_open_file(p) do { } while (0)
|
||||
#define wpa_debug_close_file() do { } while (0)
|
||||
#define wpa_debug_setup_stdout() do { } while (0)
|
||||
#define wpa_dbg(args...) do { } while (0)
|
||||
|
||||
static inline int wpa_debug_reopen_file(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else /* CONFIG_NO_STDOUT_DEBUG */
|
||||
|
||||
int wpa_debug_open_file(const char *path);
|
||||
int wpa_debug_reopen_file(void);
|
||||
void wpa_debug_close_file(void);
|
||||
void wpa_debug_setup_stdout(void);
|
||||
|
||||
/**
|
||||
* wpa_debug_printf_timestamp - Print timestamp for debug output
|
||||
*
|
||||
* This function prints a timestamp in seconds_from_1970.microsoconds
|
||||
* format if debug output has been configured to include timestamps in debug
|
||||
* messages.
|
||||
*/
|
||||
void wpa_debug_print_timestamp(void);
|
||||
|
||||
/**
|
||||
* wpa_printf - conditional printf
|
||||
* @level: priority level (MSG_*) of the message
|
||||
* @fmt: printf format string, followed by optional arguments
|
||||
*
|
||||
* This function is used to print conditional debugging and error messages. The
|
||||
* output may be directed to stdout, stderr, and/or syslog based on
|
||||
* configuration.
|
||||
*
|
||||
* Note: New line '\n' is added to the end of the text when printing to stdout.
|
||||
*/
|
||||
void wpa_printf(int level, const char *fmt, ...)
|
||||
PRINTF_FORMAT(2, 3);
|
||||
|
||||
/**
|
||||
* wpa_hexdump - conditional hex dump
|
||||
* @level: priority level (MSG_*) of the message
|
||||
* @title: title of for the message
|
||||
* @buf: data buffer to be dumped
|
||||
* @len: length of the buf
|
||||
*
|
||||
* This function is used to print conditional debugging and error messages. The
|
||||
* output may be directed to stdout, stderr, and/or syslog based on
|
||||
* configuration. The contents of buf is printed out has hex dump.
|
||||
*/
|
||||
void wpa_hexdump(int level, const char *title, const void *buf, size_t len);
|
||||
|
||||
static inline void wpa_hexdump_buf(int level, const char *title,
|
||||
const struct wpabuf *buf)
|
||||
{
|
||||
wpa_hexdump(level, title, buf ? wpabuf_head(buf) : NULL,
|
||||
buf ? wpabuf_len(buf) : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* wpa_hexdump_key - conditional hex dump, hide keys
|
||||
* @level: priority level (MSG_*) of the message
|
||||
* @title: title of for the message
|
||||
* @buf: data buffer to be dumped
|
||||
* @len: length of the buf
|
||||
*
|
||||
* This function is used to print conditional debugging and error messages. The
|
||||
* output may be directed to stdout, stderr, and/or syslog based on
|
||||
* configuration. The contents of buf is printed out has hex dump. This works
|
||||
* like wpa_hexdump(), but by default, does not include secret keys (passwords,
|
||||
* etc.) in debug output.
|
||||
*/
|
||||
void wpa_hexdump_key(int level, const char *title, const void *buf, size_t len);
|
||||
|
||||
static inline void wpa_hexdump_buf_key(int level, const char *title,
|
||||
const struct wpabuf *buf)
|
||||
{
|
||||
wpa_hexdump_key(level, title, buf ? wpabuf_head(buf) : NULL,
|
||||
buf ? wpabuf_len(buf) : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* wpa_hexdump_ascii - conditional hex dump
|
||||
* @level: priority level (MSG_*) of the message
|
||||
* @title: title of for the message
|
||||
* @buf: data buffer to be dumped
|
||||
* @len: length of the buf
|
||||
*
|
||||
* This function is used to print conditional debugging and error messages. The
|
||||
* output may be directed to stdout, stderr, and/or syslog based on
|
||||
* configuration. The contents of buf is printed out has hex dump with both
|
||||
* the hex numbers and ASCII characters (for printable range) are shown. 16
|
||||
* bytes per line will be shown.
|
||||
*/
|
||||
void wpa_hexdump_ascii(int level, const char *title, const void *buf,
|
||||
size_t len);
|
||||
|
||||
/**
|
||||
* wpa_hexdump_ascii_key - conditional hex dump, hide keys
|
||||
* @level: priority level (MSG_*) of the message
|
||||
* @title: title of for the message
|
||||
* @buf: data buffer to be dumped
|
||||
* @len: length of the buf
|
||||
*
|
||||
* This function is used to print conditional debugging and error messages. The
|
||||
* output may be directed to stdout, stderr, and/or syslog based on
|
||||
* configuration. The contents of buf is printed out has hex dump with both
|
||||
* the hex numbers and ASCII characters (for printable range) are shown. 16
|
||||
* bytes per line will be shown. This works like wpa_hexdump_ascii(), but by
|
||||
* default, does not include secret keys (passwords, etc.) in debug output.
|
||||
*/
|
||||
void wpa_hexdump_ascii_key(int level, const char *title, const void *buf,
|
||||
size_t len);
|
||||
|
||||
/*
|
||||
* wpa_dbg() behaves like wpa_msg(), but it can be removed from build to reduce
|
||||
* binary size. As such, it should be used with debugging messages that are not
|
||||
* needed in the control interface while wpa_msg() has to be used for anything
|
||||
* that needs to shown to control interface monitors.
|
||||
*/
|
||||
#define wpa_dbg(args...) wpa_msg(args)
|
||||
|
||||
#endif /* CONFIG_NO_STDOUT_DEBUG */
|
||||
|
||||
|
||||
#ifdef CONFIG_NO_WPA_MSG
|
||||
#define wpa_msg(args...) do { } while (0)
|
||||
#define wpa_msg_ctrl(args...) do { } while (0)
|
||||
#define wpa_msg_global(args...) do { } while (0)
|
||||
#define wpa_msg_global_ctrl(args...) do { } while (0)
|
||||
#define wpa_msg_no_global(args...) do { } while (0)
|
||||
#define wpa_msg_global_only(args...) do { } while (0)
|
||||
#define wpa_msg_register_cb(f) do { } while (0)
|
||||
#define wpa_msg_register_ifname_cb(f) do { } while (0)
|
||||
#else /* CONFIG_NO_WPA_MSG */
|
||||
/**
|
||||
* wpa_msg - Conditional printf for default target and ctrl_iface monitors
|
||||
* @ctx: Pointer to context data; this is the ctx variable registered
|
||||
* with struct wpa_driver_ops::init()
|
||||
* @level: priority level (MSG_*) of the message
|
||||
* @fmt: printf format string, followed by optional arguments
|
||||
*
|
||||
* This function is used to print conditional debugging and error messages. The
|
||||
* output may be directed to stdout, stderr, and/or syslog based on
|
||||
* configuration. This function is like wpa_printf(), but it also sends the
|
||||
* same message to all attached ctrl_iface monitors.
|
||||
*
|
||||
* Note: New line '\n' is added to the end of the text when printing to stdout.
|
||||
*/
|
||||
void wpa_msg(void *ctx, int level, const char *fmt, ...) PRINTF_FORMAT(3, 4);
|
||||
|
||||
/**
|
||||
* wpa_msg_ctrl - Conditional printf for ctrl_iface monitors
|
||||
* @ctx: Pointer to context data; this is the ctx variable registered
|
||||
* with struct wpa_driver_ops::init()
|
||||
* @level: priority level (MSG_*) of the message
|
||||
* @fmt: printf format string, followed by optional arguments
|
||||
*
|
||||
* This function is used to print conditional debugging and error messages.
|
||||
* This function is like wpa_msg(), but it sends the output only to the
|
||||
* attached ctrl_iface monitors. In other words, it can be used for frequent
|
||||
* events that do not need to be sent to syslog.
|
||||
*/
|
||||
void wpa_msg_ctrl(void *ctx, int level, const char *fmt, ...)
|
||||
PRINTF_FORMAT(3, 4);
|
||||
|
||||
/**
|
||||
* wpa_msg_global - Global printf for ctrl_iface monitors
|
||||
* @ctx: Pointer to context data; this is the ctx variable registered
|
||||
* with struct wpa_driver_ops::init()
|
||||
* @level: priority level (MSG_*) of the message
|
||||
* @fmt: printf format string, followed by optional arguments
|
||||
*
|
||||
* This function is used to print conditional debugging and error messages.
|
||||
* This function is like wpa_msg(), but it sends the output as a global event,
|
||||
* i.e., without being specific to an interface. For backwards compatibility,
|
||||
* an old style event is also delivered on one of the interfaces (the one
|
||||
* specified by the context data).
|
||||
*/
|
||||
void wpa_msg_global(void *ctx, int level, const char *fmt, ...)
|
||||
PRINTF_FORMAT(3, 4);
|
||||
|
||||
/**
|
||||
* wpa_msg_global_ctrl - Conditional global printf for ctrl_iface monitors
|
||||
* @ctx: Pointer to context data; this is the ctx variable registered
|
||||
* with struct wpa_driver_ops::init()
|
||||
* @level: priority level (MSG_*) of the message
|
||||
* @fmt: printf format string, followed by optional arguments
|
||||
*
|
||||
* This function is used to print conditional debugging and error messages.
|
||||
* This function is like wpa_msg_global(), but it sends the output only to the
|
||||
* attached global ctrl_iface monitors. In other words, it can be used for
|
||||
* frequent events that do not need to be sent to syslog.
|
||||
*/
|
||||
void wpa_msg_global_ctrl(void *ctx, int level, const char *fmt, ...)
|
||||
PRINTF_FORMAT(3, 4);
|
||||
|
||||
/**
|
||||
* wpa_msg_no_global - Conditional printf for ctrl_iface monitors
|
||||
* @ctx: Pointer to context data; this is the ctx variable registered
|
||||
* with struct wpa_driver_ops::init()
|
||||
* @level: priority level (MSG_*) of the message
|
||||
* @fmt: printf format string, followed by optional arguments
|
||||
*
|
||||
* This function is used to print conditional debugging and error messages.
|
||||
* This function is like wpa_msg(), but it does not send the output as a global
|
||||
* event.
|
||||
*/
|
||||
void wpa_msg_no_global(void *ctx, int level, const char *fmt, ...)
|
||||
PRINTF_FORMAT(3, 4);
|
||||
|
||||
/**
|
||||
* wpa_msg_global_only - Conditional printf for ctrl_iface monitors
|
||||
* @ctx: Pointer to context data; this is the ctx variable registered
|
||||
* with struct wpa_driver_ops::init()
|
||||
* @level: priority level (MSG_*) of the message
|
||||
* @fmt: printf format string, followed by optional arguments
|
||||
*
|
||||
* This function is used to print conditional debugging and error messages.
|
||||
* This function is like wpa_msg_global(), but it sends the output only as a
|
||||
* global event.
|
||||
*/
|
||||
void wpa_msg_global_only(void *ctx, int level, const char *fmt, ...)
|
||||
PRINTF_FORMAT(3, 4);
|
||||
|
||||
enum wpa_msg_type {
|
||||
WPA_MSG_PER_INTERFACE,
|
||||
WPA_MSG_GLOBAL,
|
||||
WPA_MSG_NO_GLOBAL,
|
||||
WPA_MSG_ONLY_GLOBAL,
|
||||
};
|
||||
|
||||
typedef void (*wpa_msg_cb_func)(void *ctx, int level, enum wpa_msg_type type,
|
||||
const char *txt, size_t len);
|
||||
|
||||
/**
|
||||
* wpa_msg_register_cb - Register callback function for wpa_msg() messages
|
||||
* @func: Callback function (%NULL to unregister)
|
||||
*/
|
||||
void wpa_msg_register_cb(wpa_msg_cb_func func);
|
||||
|
||||
typedef const char * (*wpa_msg_get_ifname_func)(void *ctx);
|
||||
void wpa_msg_register_ifname_cb(wpa_msg_get_ifname_func func);
|
||||
|
||||
#endif /* CONFIG_NO_WPA_MSG */
|
||||
|
||||
#ifdef CONFIG_NO_HOSTAPD_LOGGER
|
||||
#define hostapd_logger(args...) do { } while (0)
|
||||
#define hostapd_logger_register_cb(f) do { } while (0)
|
||||
#else /* CONFIG_NO_HOSTAPD_LOGGER */
|
||||
void hostapd_logger(void *ctx, const u8 *addr, unsigned int module, int level,
|
||||
const char *fmt, ...) PRINTF_FORMAT(5, 6);
|
||||
|
||||
typedef void (*hostapd_logger_cb_func)(void *ctx, const u8 *addr,
|
||||
unsigned int module, int level,
|
||||
const char *txt, size_t len);
|
||||
|
||||
/**
|
||||
* hostapd_logger_register_cb - Register callback function for hostapd_logger()
|
||||
* @func: Callback function (%NULL to unregister)
|
||||
*/
|
||||
void hostapd_logger_register_cb(hostapd_logger_cb_func func);
|
||||
#endif /* CONFIG_NO_HOSTAPD_LOGGER */
|
||||
|
||||
#define HOSTAPD_MODULE_IEEE80211 0x00000001
|
||||
#define HOSTAPD_MODULE_IEEE8021X 0x00000002
|
||||
#define HOSTAPD_MODULE_RADIUS 0x00000004
|
||||
#define HOSTAPD_MODULE_WPA 0x00000008
|
||||
#define HOSTAPD_MODULE_DRIVER 0x00000010
|
||||
#define HOSTAPD_MODULE_MLME 0x00000040
|
||||
|
||||
enum hostapd_logger_level {
|
||||
HOSTAPD_LEVEL_DEBUG_VERBOSE = 0,
|
||||
HOSTAPD_LEVEL_DEBUG = 1,
|
||||
HOSTAPD_LEVEL_INFO = 2,
|
||||
HOSTAPD_LEVEL_NOTICE = 3,
|
||||
HOSTAPD_LEVEL_WARNING = 4
|
||||
};
|
||||
|
||||
|
||||
#ifdef CONFIG_DEBUG_SYSLOG
|
||||
|
||||
void wpa_debug_open_syslog(void);
|
||||
void wpa_debug_close_syslog(void);
|
||||
|
||||
#else /* CONFIG_DEBUG_SYSLOG */
|
||||
|
||||
static inline void wpa_debug_open_syslog(void)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void wpa_debug_close_syslog(void)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* CONFIG_DEBUG_SYSLOG */
|
||||
|
||||
#ifdef CONFIG_DEBUG_LINUX_TRACING
|
||||
|
||||
int wpa_debug_open_linux_tracing(void);
|
||||
void wpa_debug_close_linux_tracing(void);
|
||||
|
||||
#else /* CONFIG_DEBUG_LINUX_TRACING */
|
||||
|
||||
static inline int wpa_debug_open_linux_tracing(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void wpa_debug_close_linux_tracing(void)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* CONFIG_DEBUG_LINUX_TRACING */
|
||||
|
||||
|
||||
#ifdef EAPOL_TEST
|
||||
#define WPA_ASSERT(a) \
|
||||
do { \
|
||||
if (!(a)) { \
|
||||
printf("WPA_ASSERT FAILED '" #a "' " \
|
||||
"%s %s:%d\n", \
|
||||
__FUNCTION__, __FILE__, __LINE__); \
|
||||
exit(1); \
|
||||
} \
|
||||
} while (0)
|
||||
#else
|
||||
#define WPA_ASSERT(a) do { } while (0)
|
||||
#endif
|
||||
|
||||
const char * debug_level_str(int level);
|
||||
int str_to_debug_level(const char *s);
|
||||
|
||||
#endif /* WPA_DEBUG_H */
|
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* wpa_supplicant ctrl_iface helpers
|
||||
* Copyright (c) 2010-2011, Atheros Communications, Inc.
|
||||
* Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef WPA_HELPERS_H
|
||||
#define WPA_HELPERS_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
int wpa_command(const char *ifname, const char *cmd);
|
||||
int wpa_command_resp(const char *ifname, const char *cmd,
|
||||
char *resp, size_t resp_size);
|
||||
int get_wpa_status(const char *ifname, const char *field, char *obuf,
|
||||
size_t obuf_size);
|
||||
|
||||
struct wpa_ctrl * open_wpa_mon(const char *ifname);
|
||||
int wait_ip_addr(const char *ifname, int timeout);
|
||||
int get_wpa_cli_event(struct wpa_ctrl *mon,
|
||||
const char *event, char *buf, size_t buf_size);
|
||||
int get_wpa_cli_event2(struct wpa_ctrl *mon,
|
||||
const char *event, const char *event2,
|
||||
char *buf, size_t buf_size);
|
||||
|
||||
int add_network(const char *ifname);
|
||||
int set_network(const char *ifname, int id, const char *field,
|
||||
const char *value);
|
||||
int set_network_quoted(const char *ifname, int id, const char *field,
|
||||
const char *value);
|
||||
int add_cred(const char *ifname);
|
||||
int set_cred(const char *ifname, int id, const char *field, const char *value);
|
||||
int set_cred_quoted(const char *ifname, int id, const char *field,
|
||||
const char *value);
|
||||
|
||||
#endif /* WPA_HELPERS_H */
|
@ -0,0 +1,191 @@
|
||||
/*
|
||||
* Dynamic data buffer
|
||||
* Copyright (c) 2007-2012, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef WPABUF_H
|
||||
#define WPABUF_H
|
||||
|
||||
/* wpabuf::buf is a pointer to external data */
|
||||
#define WPABUF_FLAG_EXT_DATA BIT(0)
|
||||
|
||||
/*
|
||||
* Internal data structure for wpabuf. Please do not touch this directly from
|
||||
* elsewhere. This is only defined in header file to allow inline functions
|
||||
* from this file to access data.
|
||||
*/
|
||||
struct wpabuf {
|
||||
size_t size; /* total size of the allocated buffer */
|
||||
size_t used; /* length of data in the buffer */
|
||||
u8 *buf; /* pointer to the head of the buffer */
|
||||
unsigned int flags;
|
||||
/* optionally followed by the allocated buffer */
|
||||
};
|
||||
|
||||
|
||||
int wpabuf_resize(struct wpabuf **buf, size_t add_len);
|
||||
struct wpabuf * wpabuf_alloc(size_t len);
|
||||
struct wpabuf * wpabuf_alloc_ext_data(u8 *data, size_t len);
|
||||
struct wpabuf * wpabuf_alloc_copy(const void *data, size_t len);
|
||||
struct wpabuf * wpabuf_dup(const struct wpabuf *src);
|
||||
void wpabuf_free(struct wpabuf *buf);
|
||||
void wpabuf_clear_free(struct wpabuf *buf);
|
||||
void * wpabuf_put(struct wpabuf *buf, size_t len);
|
||||
struct wpabuf * wpabuf_concat(struct wpabuf *a, struct wpabuf *b);
|
||||
struct wpabuf * wpabuf_zeropad(struct wpabuf *buf, size_t len);
|
||||
void wpabuf_printf(struct wpabuf *buf, char *fmt, ...) PRINTF_FORMAT(2, 3);
|
||||
struct wpabuf * wpabuf_parse_bin(const char *buf);
|
||||
|
||||
|
||||
/**
|
||||
* wpabuf_size - Get the currently allocated size of a wpabuf buffer
|
||||
* @buf: wpabuf buffer
|
||||
* Returns: Currently allocated size of the buffer
|
||||
*/
|
||||
static inline size_t wpabuf_size(const struct wpabuf *buf)
|
||||
{
|
||||
return buf->size;
|
||||
}
|
||||
|
||||
/**
|
||||
* wpabuf_len - Get the current length of a wpabuf buffer data
|
||||
* @buf: wpabuf buffer
|
||||
* Returns: Currently used length of the buffer
|
||||
*/
|
||||
static inline size_t wpabuf_len(const struct wpabuf *buf)
|
||||
{
|
||||
return buf->used;
|
||||
}
|
||||
|
||||
/**
|
||||
* wpabuf_tailroom - Get size of available tail room in the end of the buffer
|
||||
* @buf: wpabuf buffer
|
||||
* Returns: Tail room (in bytes) of available space in the end of the buffer
|
||||
*/
|
||||
static inline size_t wpabuf_tailroom(const struct wpabuf *buf)
|
||||
{
|
||||
return buf->size - buf->used;
|
||||
}
|
||||
|
||||
/**
|
||||
* wpabuf_cmp - Check if two buffers contain the same data
|
||||
* @a: wpabuf buffer
|
||||
* @b: wpabuf buffer
|
||||
* Returns: 0 if the two buffers contain the same data and non-zero otherwise
|
||||
*/
|
||||
static inline int wpabuf_cmp(const struct wpabuf *a, const struct wpabuf *b)
|
||||
{
|
||||
if (!a && !b)
|
||||
return 0;
|
||||
if (a && b && wpabuf_size(a) == wpabuf_size(b))
|
||||
return os_memcmp(a->buf, b->buf, wpabuf_size(a));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* wpabuf_head - Get pointer to the head of the buffer data
|
||||
* @buf: wpabuf buffer
|
||||
* Returns: Pointer to the head of the buffer data
|
||||
*/
|
||||
static inline const void * wpabuf_head(const struct wpabuf *buf)
|
||||
{
|
||||
return buf->buf;
|
||||
}
|
||||
|
||||
static inline const u8 * wpabuf_head_u8(const struct wpabuf *buf)
|
||||
{
|
||||
return (const u8 *) wpabuf_head(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* wpabuf_mhead - Get modifiable pointer to the head of the buffer data
|
||||
* @buf: wpabuf buffer
|
||||
* Returns: Pointer to the head of the buffer data
|
||||
*/
|
||||
static inline void * wpabuf_mhead(struct wpabuf *buf)
|
||||
{
|
||||
return buf->buf;
|
||||
}
|
||||
|
||||
static inline u8 * wpabuf_mhead_u8(struct wpabuf *buf)
|
||||
{
|
||||
return (u8 *) wpabuf_mhead(buf);
|
||||
}
|
||||
|
||||
static inline void wpabuf_put_u8(struct wpabuf *buf, u8 data)
|
||||
{
|
||||
u8 *pos = (u8 *) wpabuf_put(buf, 1);
|
||||
*pos = data;
|
||||
}
|
||||
|
||||
static inline void wpabuf_put_le16(struct wpabuf *buf, u16 data)
|
||||
{
|
||||
u8 *pos = (u8 *) wpabuf_put(buf, 2);
|
||||
WPA_PUT_LE16(pos, data);
|
||||
}
|
||||
|
||||
static inline void wpabuf_put_le32(struct wpabuf *buf, u32 data)
|
||||
{
|
||||
u8 *pos = (u8 *) wpabuf_put(buf, 4);
|
||||
WPA_PUT_LE32(pos, data);
|
||||
}
|
||||
|
||||
static inline void wpabuf_put_le64(struct wpabuf *buf, u64 data)
|
||||
{
|
||||
u8 *pos = (u8 *) wpabuf_put(buf, 8);
|
||||
WPA_PUT_LE64(pos, data);
|
||||
}
|
||||
|
||||
static inline void wpabuf_put_be16(struct wpabuf *buf, u16 data)
|
||||
{
|
||||
u8 *pos = (u8 *) wpabuf_put(buf, 2);
|
||||
WPA_PUT_BE16(pos, data);
|
||||
}
|
||||
|
||||
static inline void wpabuf_put_be24(struct wpabuf *buf, u32 data)
|
||||
{
|
||||
u8 *pos = (u8 *) wpabuf_put(buf, 3);
|
||||
WPA_PUT_BE24(pos, data);
|
||||
}
|
||||
|
||||
static inline void wpabuf_put_be32(struct wpabuf *buf, u32 data)
|
||||
{
|
||||
u8 *pos = (u8 *) wpabuf_put(buf, 4);
|
||||
WPA_PUT_BE32(pos, data);
|
||||
}
|
||||
|
||||
static inline void wpabuf_put_be64(struct wpabuf *buf, u64 data)
|
||||
{
|
||||
u8 *pos = (u8 *) wpabuf_put(buf, 8);
|
||||
WPA_PUT_BE64(pos, data);
|
||||
}
|
||||
|
||||
static inline void wpabuf_put_data(struct wpabuf *buf, const void *data,
|
||||
size_t len)
|
||||
{
|
||||
if (data)
|
||||
os_memcpy(wpabuf_put(buf, len), data, len);
|
||||
}
|
||||
|
||||
static inline void wpabuf_put_buf(struct wpabuf *dst,
|
||||
const struct wpabuf *src)
|
||||
{
|
||||
wpabuf_put_data(dst, wpabuf_head(src), wpabuf_len(src));
|
||||
}
|
||||
|
||||
static inline void wpabuf_set(struct wpabuf *buf, const void *data, size_t len)
|
||||
{
|
||||
buf->buf = (u8 *) data;
|
||||
buf->flags = WPABUF_FLAG_EXT_DATA;
|
||||
buf->size = buf->used = len;
|
||||
}
|
||||
|
||||
static inline void wpabuf_put_str(struct wpabuf *dst, const char *str)
|
||||
{
|
||||
wpabuf_put_data(dst, str, os_strlen(str));
|
||||
}
|
||||
|
||||
#endif /* WPABUF_H */
|
@ -0,0 +1,198 @@
|
||||
///! daemon <-> gui communication
|
||||
const std = @import("std");
|
||||
const json = std.json;
|
||||
const mem = std.mem;
|
||||
|
||||
pub const Message = union(MessageTag) {
|
||||
ping: void,
|
||||
pong: void,
|
||||
poweroff: void,
|
||||
wifi_connect: WifiConnect,
|
||||
network_report: NetworkReport,
|
||||
get_network_report: GetNetworkReport,
|
||||
|
||||
pub const WifiConnect = struct {
|
||||
ssid: []const u8,
|
||||
password: []const u8,
|
||||
};
|
||||
|
||||
pub const NetworkReport = struct {
|
||||
ipaddrs: []const []const u8,
|
||||
wifi_ssid: ?[]const u8, // null indicates disconnected from wifi
|
||||
wifi_scan_networks: []const []const u8,
|
||||
};
|
||||
|
||||
pub const GetNetworkReport = struct {
|
||||
scan: bool, // true starts a wifi scan and send NetworkReport only after completion
|
||||
};
|
||||
};
|
||||
|
||||
pub const MessageTag = enum(u8) {
|
||||
ping,
|
||||
pong,
|
||||
poweroff,
|
||||
wifi_connect,
|
||||
network_report,
|
||||
get_network_report,
|
||||
};
|
||||
|
||||
const Header = extern struct {
|
||||
tag: MessageTag,
|
||||
len: usize,
|
||||
};
|
||||
|
||||
/// reads and parses a single message from the input stream reader.
|
||||
/// callers must deallocate resources with free when done.
|
||||
pub fn read(allocator: mem.Allocator, reader: anytype) anyerror!Message {
|
||||
const h = try reader.readStruct(Header);
|
||||
if (h.len == 0) {
|
||||
const m = switch (h.tag) {
|
||||
.ping => Message{ .ping = {} },
|
||||
.pong => Message{ .pong = {} },
|
||||
.poweroff => Message{ .poweroff = {} },
|
||||
else => error.ZeroLenInNonVoidTag,
|
||||
};
|
||||
return m;
|
||||
}
|
||||
|
||||
// TODO: limit h.len to some max value
|
||||
var bytes = try allocator.alloc(u8, h.len);
|
||||
defer allocator.free(bytes);
|
||||
try reader.readNoEof(bytes);
|
||||
|
||||
const jopt = json.ParseOptions{ .allocator = allocator, .ignore_unknown_fields = true };
|
||||
var jstream = json.TokenStream.init(bytes);
|
||||
return switch (h.tag) {
|
||||
.ping, .pong, .poweroff => unreachable, // void
|
||||
.wifi_connect => Message{
|
||||
.wifi_connect = try json.parse(Message.WifiConnect, &jstream, jopt),
|
||||
},
|
||||
.network_report => Message{
|
||||
.network_report = try json.parse(Message.NetworkReport, &jstream, jopt),
|
||||
},
|
||||
.get_network_report => Message{
|
||||
.get_network_report = try json.parse(Message.GetNetworkReport, &jstream, jopt),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/// outputs the message msg using writer.
|
||||
/// all allocated resources are freed upon return.
|
||||
pub fn write(allocator: mem.Allocator, writer: anytype, msg: Message) !void {
|
||||
var header = Header{ .tag = msg, .len = 0 };
|
||||
switch (msg) {
|
||||
.ping, .pong, .poweroff => return writer.writeStruct(header),
|
||||
else => {}, // non-zero payload; continue
|
||||
}
|
||||
|
||||
var data = std.ArrayList(u8).init(allocator);
|
||||
defer data.deinit();
|
||||
const jopt = .{ .whitespace = null };
|
||||
switch (msg) {
|
||||
.ping, .pong, .poweroff => unreachable,
|
||||
.wifi_connect => try json.stringify(msg.wifi_connect, jopt, data.writer()),
|
||||
.network_report => try json.stringify(msg.network_report, jopt, data.writer()),
|
||||
.get_network_report => try json.stringify(msg.get_network_report, jopt, data.writer()),
|
||||
}
|
||||
|
||||
header.len = data.items.len;
|
||||
try writer.writeStruct(header);
|
||||
try writer.writeAll(data.items);
|
||||
}
|
||||
|
||||
pub fn free(allocator: mem.Allocator, m: Message) void {
|
||||
switch (m) {
|
||||
.ping, .pong, .poweroff => {},
|
||||
else => |v| {
|
||||
json.parseFree(@TypeOf(v), v, .{ .allocator = allocator });
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
test "read" {
|
||||
const t = std.testing;
|
||||
|
||||
var data = std.ArrayList(u8).init(t.allocator);
|
||||
defer data.deinit();
|
||||
const msg = Message{ .wifi_connect = .{ .ssid = "hello", .password = "world" } };
|
||||
try json.stringify(msg.wifi_connect, .{}, data.writer());
|
||||
|
||||
var buf = std.ArrayList(u8).init(t.allocator);
|
||||
defer buf.deinit();
|
||||
try buf.writer().writeStruct(Header{ .tag = msg, .len = data.items.len });
|
||||
try buf.writer().writeAll(data.items);
|
||||
|
||||
var bs = std.io.fixedBufferStream(buf.items);
|
||||
const res = try read(t.allocator, bs.reader());
|
||||
defer free(t.allocator, res);
|
||||
|
||||
try t.expectEqualStrings(msg.wifi_connect.ssid, res.wifi_connect.ssid);
|
||||
try t.expectEqualStrings(msg.wifi_connect.password, res.wifi_connect.password);
|
||||
}
|
||||
|
||||
test "write" {
|
||||
const t = std.testing;
|
||||
|
||||
var buf = std.ArrayList(u8).init(t.allocator);
|
||||
defer buf.deinit();
|
||||
const msg = Message{ .wifi_connect = .{ .ssid = "wlan", .password = "secret" } };
|
||||
try write(t.allocator, buf.writer(), msg);
|
||||
|
||||
const payload = "{\"ssid\":\"wlan\",\"password\":\"secret\"}";
|
||||
var js = std.ArrayList(u8).init(t.allocator);
|
||||
defer js.deinit();
|
||||
try js.writer().writeStruct(Header{ .tag = msg, .len = payload.len });
|
||||
try js.appendSlice(payload);
|
||||
|
||||
try t.expectEqualSlices(u8, js.items, buf.items);
|
||||
}
|
||||
|
||||
test "write/read void tags" {
|
||||
const t = std.testing;
|
||||
|
||||
var buf = std.ArrayList(u8).init(t.allocator);
|
||||
defer buf.deinit();
|
||||
|
||||
const msg = [_]Message{
|
||||
Message.ping,
|
||||
Message.pong,
|
||||
Message.poweroff,
|
||||
};
|
||||
|
||||
for (msg) |m| {
|
||||
buf.clearAndFree();
|
||||
try write(t.allocator, buf.writer(), m);
|
||||
var bs = std.io.fixedBufferStream(buf.items);
|
||||
const res = try read(t.allocator, bs.reader());
|
||||
free(t.allocator, res); // noop
|
||||
try t.expectEqual(m, res);
|
||||
}
|
||||
}
|
||||
|
||||
test "msg sequence" {
|
||||
const t = std.testing;
|
||||
|
||||
var buf = std.ArrayList(u8).init(t.allocator);
|
||||
defer buf.deinit();
|
||||
|
||||
const msgs = [_]Message{
|
||||
Message.ping,
|
||||
Message{ .wifi_connect = .{ .ssid = "wlan", .password = "secret" } },
|
||||
Message.pong,
|
||||
Message{ .network_report = .{
|
||||
.ipaddrs = &.{},
|
||||
.wifi_ssid = null,
|
||||
.wifi_scan_networks = &.{ "foo", "bar" },
|
||||
} },
|
||||
};
|
||||
for (msgs) |m| {
|
||||
try write(t.allocator, buf.writer(), m);
|
||||
}
|
||||
|
||||
var bs = std.io.fixedBufferStream(buf.items);
|
||||
for (msgs) |m| {
|
||||
const res = try read(t.allocator, bs.reader());
|
||||
defer free(t.allocator, res);
|
||||
try t.expectEqual(@as(MessageTag, m), @as(MessageTag, res));
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
const std = @import("std");
|
||||
|
||||
pub fn main() anyerror!void {
|
||||
// Note that info level log messages are by default printed only in Debug
|
||||
// and ReleaseSafe build modes.
|
||||
std.log.info("All your codebase are belong to us.", .{});
|
||||
}
|
||||
|
||||
test "basic test" {
|
||||
try std.testing.expectEqual(10, 3 + 7);
|
||||
}
|
@ -0,0 +1,225 @@
|
||||
const std = @import("std");
|
||||
const os = std.os;
|
||||
const sys = os.system;
|
||||
const time = std.time;
|
||||
const Address = std.net.Address;
|
||||
|
||||
const nif = @import("nif");
|
||||
|
||||
const comm = @import("comm.zig");
|
||||
const Daemon = @import("nd/Daemon.zig");
|
||||
|
||||
const logger = std.log.scoped(.nd);
|
||||
const stderr = std.io.getStdErr().writer();
|
||||
|
||||
/// prints usage help text to stderr.
|
||||
fn usage(prog: []const u8) !void {
|
||||
try stderr.print(
|
||||
\\usage: {s} -gui path/to/ngui -gui-user username -wpa path
|
||||
\\
|
||||
\\nd is a short for nakamochi daemon.
|
||||
\\the daemon executes ngui as a child process and runs until
|
||||
\\TERM or INT signal is received.
|
||||
\\
|
||||
\\nd logs messages to stderr.
|
||||
\\
|
||||
, .{prog});
|
||||
}
|
||||
|
||||
/// prints messages in the same way std.fmt.format does and exits the process
|
||||
/// with a non-zero code.
|
||||
fn fatal(comptime fmt: []const u8, args: anytype) noreturn {
|
||||
stderr.print(fmt, args) catch {};
|
||||
if (fmt[fmt.len - 1] != '\n') {
|
||||
stderr.writeByte('\n') catch {};
|
||||
}
|
||||
std.process.exit(1);
|
||||
}
|
||||
|
||||
/// nd program args. see usage.
|
||||
const NdArgs = struct {
|
||||
gui: ?[:0]const u8 = null, // = "ngui",
|
||||
gui_user: ?[:0]const u8 = null, // u8 = "uiuser",
|
||||
wpa: ?[:0]const u8 = null, // = "/var/run/wpa_supplicant/wlan0",
|
||||
|
||||
fn deinit(self: @This(), allocator: std.mem.Allocator) void {
|
||||
if (self.gui) |p| allocator.free(p);
|
||||
if (self.gui_user) |p| allocator.free(p);
|
||||
if (self.wpa) |p| allocator.free(p);
|
||||
}
|
||||
};
|
||||
|
||||
/// parses and validates program args.
|
||||
fn parseArgs(gpa: std.mem.Allocator) !NdArgs {
|
||||
var flags: NdArgs = .{};
|
||||
|
||||
var args = try std.process.ArgIterator.initWithAllocator(gpa);
|
||||
defer args.deinit();
|
||||
const prog = args.next() orelse return error.NoProgName;
|
||||
|
||||
var lastarg: enum {
|
||||
none,
|
||||
gui,
|
||||
gui_user,
|
||||
wpa,
|
||||
} = .none;
|
||||
while (args.next()) |a| {
|
||||
switch (lastarg) {
|
||||
.gui => {
|
||||
flags.gui = try gpa.dupeZ(u8, a);
|
||||
lastarg = .none;
|
||||
continue;
|
||||
},
|
||||
.gui_user => {
|
||||
flags.gui_user = try gpa.dupeZ(u8, a);
|
||||
lastarg = .none;
|
||||
continue;
|
||||
},
|
||||
.wpa => {
|
||||
flags.wpa = try gpa.dupeZ(u8, a);
|
||||
lastarg = .none;
|
||||
continue;
|
||||
},
|
||||
.none => {},
|
||||
}
|
||||
if (std.mem.eql(u8, a, "-h") or std.mem.eql(u8, a, "-help") or std.mem.eql(u8, a, "--help")) {
|
||||
usage(prog) catch {};
|
||||
std.process.exit(1);
|
||||
} else if (std.mem.eql(u8, a, "-gui")) {
|
||||
lastarg = .gui;
|
||||
} else if (std.mem.eql(u8, a, "-gui-user")) {
|
||||
lastarg = .gui_user;
|
||||
} else if (std.mem.eql(u8, a, "-wpa")) {
|
||||
lastarg = .wpa;
|
||||
} else {
|
||||
fatal("unknown arg name {s}", .{a});
|
||||
}
|
||||
}
|
||||
|
||||
if (lastarg != .none) {
|
||||
fatal("invalid arg: {s} requires a value", .{@tagName(lastarg)});
|
||||
}
|
||||
if (flags.gui == null) fatal("missing -gui arg", .{});
|
||||
if (flags.gui_user == null) fatal("missing -gui-user arg", .{});
|
||||
if (flags.wpa == null) fatal("missing -wpa arg", .{});
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
/// quit signals nd to exit.
|
||||
/// TODO: thread-safety?
|
||||
var quit = false;
|
||||
|
||||
fn sighandler(sig: c_int) callconv(.C) void {
|
||||
logger.info("got signal {}; exiting...\n", .{sig});
|
||||
quit = true;
|
||||
}
|
||||
|
||||
pub fn main() !void {
|
||||
// main heap allocator used throughout the lifetime of nd
|
||||
var gpa_state = std.heap.GeneralPurposeAllocator(.{}){};
|
||||
defer if (gpa_state.deinit()) {
|
||||
logger.err("memory leaks detected", .{});
|
||||
};
|
||||
const gpa = gpa_state.allocator();
|
||||
// parse program args first thing and fail fast if invalid
|
||||
const args = try parseArgs(gpa);
|
||||
defer args.deinit(gpa);
|
||||
|
||||
// start ngui, unless -nogui mode
|
||||
var ngui = std.ChildProcess.init(&.{args.gui.?}, gpa);
|
||||
ngui.stdin_behavior = .Pipe;
|
||||
ngui.stdout_behavior = .Pipe;
|
||||
ngui.stderr_behavior = .Inherit;
|
||||
// fix zig std: child_process.zig:125:33: error: container 'std.os' has no member called 'getUserInfo'
|
||||
//ngui.setUserName(args.gui_user) catch |err| {
|
||||
// fatal("unable to set gui username to {s}: {s}", .{args.gui_user.?, err});
|
||||
//};
|
||||
// TODO: the following fails with "cannot open framebuffer device: Permission denied"
|
||||
// but works with "doas -u uiuser ngui"
|
||||
// ftr, zig uses setreuid and setregid
|
||||
//const uiuser = std.process.getUserInfo(args.gui_user.?) catch |err| {
|
||||
// fatal("unable to set gui username to {s}: {any}", .{ args.gui_user.?, err });
|
||||
//};
|
||||
//ngui.uid = uiuser.uid;
|
||||
//ngui.gid = uiuser.gid;
|
||||
// ngui.env_map = ...
|
||||
ngui.spawn() catch |err| {
|
||||
fatal("unable to start ngui: {any}", .{err});
|
||||
};
|
||||
// TODO: thread-safety, esp. uiwriter
|
||||
const uireader = ngui.stdout.?.reader();
|
||||
const uiwriter = ngui.stdin.?.writer();
|
||||
|
||||
// graceful shutdown; see sigaction(2)
|
||||
const sa = os.Sigaction{
|
||||
.handler = .{ .handler = sighandler },
|
||||
.mask = os.empty_sigset,
|
||||
.flags = 0,
|
||||
};
|
||||
try os.sigaction(os.SIG.INT, &sa, null);
|
||||
//TODO: try os.sigaction(os.SIG.TERM, &sa, null);
|
||||
|
||||
// start network monitor
|
||||
var ctrl = try nif.wpa.Control.open(args.wpa.?);
|
||||
defer ctrl.close() catch {};
|
||||
var nd: Daemon = .{
|
||||
.allocator = gpa,
|
||||
.uiwriter = uiwriter,
|
||||
.wpa_ctrl = ctrl,
|
||||
};
|
||||
try nd.start();
|
||||
// send the UI network report right away, without scanning wifi
|
||||
nd.reportNetworkStatus(.{ .scan = false });
|
||||
|
||||
// comm with ui loop; run until exit is requested
|
||||
var poweroff = false;
|
||||
while (!quit) {
|
||||
time.sleep(100 * time.ns_per_ms);
|
||||
// note: uireader.read is blocking
|
||||
// TODO: handle error.EndOfStream - ngui exited
|
||||
const msg = comm.read(gpa, uireader) catch |err| {
|
||||
logger.err("comm.read: {any}", .{err});
|
||||
continue;
|
||||
};
|
||||
logger.debug("got ui msg tagged {s}", .{@tagName(msg)});
|
||||
switch (msg) {
|
||||
.pong => {},
|
||||
.poweroff => {
|
||||
logger.info("poweroff requested; terminating", .{});
|
||||
quit = true;
|
||||
poweroff = true;
|
||||
},
|
||||
.get_network_report => |req| {
|
||||
nd.reportNetworkStatus(.{ .scan = req.scan });
|
||||
},
|
||||
.wifi_connect => |req| {
|
||||
nd.startConnectWifi(req.ssid, req.password) catch |err| {
|
||||
logger.err("startConnectWifi: {any}", .{err});
|
||||
};
|
||||
},
|
||||
else => logger.warn("unhandled msg tag {s}", .{@tagName(msg)}),
|
||||
}
|
||||
comm.free(gpa, msg);
|
||||
}
|
||||
|
||||
// shutdown
|
||||
_ = ngui.kill() catch |err| logger.err("ngui.kill: {any}", .{err});
|
||||
nd.stop();
|
||||
if (poweroff) {
|
||||
svShutdown(gpa);
|
||||
var off = std.ChildProcess.init(&.{"poweroff"}, gpa);
|
||||
_ = try off.spawnAndWait();
|
||||
}
|
||||
}
|
||||
|
||||
/// shut down important services manually.
|
||||
/// TODO: make this OS-agnostic
|
||||
fn svShutdown(allocator: std.mem.Allocator) void {
|
||||
// sv waits 7sec by default but bitcoind needs more
|
||||
// http://smarden.org/runit/
|
||||
var stop_lnd = std.ChildProcess.init(&.{"sv", "-w", "25", "stop", "lnd"}, allocator);
|
||||
_ = stop_lnd.spawnAndWait() catch |err| logger.err("stop lnd: {any}", .{err});
|
||||
var stop_btc = std.ChildProcess.init(&.{"sv", "-w", "30", "stop", "bitcoind"}, allocator);
|
||||
_ = stop_btc.spawnAndWait() catch |err| logger.err("stop bitcoind: {any}", .{err});
|
||||
}
|
@ -0,0 +1,401 @@
|
||||
///! daemon watches network status and communicates updates to the gui
|
||||
///! using uiwriter
|
||||
const std = @import("std");
|
||||
const mem = std.mem;
|
||||
const time = std.time;
|
||||
|
||||
const nif = @import("nif");
|
||||
|
||||
const comm = @import("../comm.zig");
|
||||
//const ioq = @import("../ioq.zig");
|
||||
|
||||
const logger = std.log.scoped(.netmon);
|
||||
|
||||
// pub fields
|
||||
allocator: mem.Allocator,
|
||||
uiwriter: std.fs.File.Writer, // ngui stdin
|
||||
wpa_ctrl: nif.wpa.Control, // guarded by mu once start'ed
|
||||
|
||||
// private fields
|
||||
mu: std.Thread.Mutex = .{},
|
||||
quit: bool = false, // tells daemon to quit
|
||||
main_thread: ?std.Thread = null, // non-nill if started
|
||||
want_report: bool = false,
|
||||
want_wifi_scan: bool = false,
|
||||
wifi_scan_in_progress: bool = false,
|
||||
report_ready: bool = true, // no need to scan for an immediate report
|
||||
wpa_save_config_on_connected: bool = false,
|
||||
|
||||
const Daemon = @This();
|
||||
|
||||
pub fn start(self: *Daemon) !void {
|
||||
// TODO: return error if already started
|
||||
self.main_thread = try std.Thread.spawn(.{}, mainThreadLoop, .{self});
|
||||
}
|
||||
|
||||
pub fn stop(self: *Daemon) void {
|
||||
self.mu.lock();
|
||||
self.quit = true;
|
||||
self.mu.unlock();
|
||||
if (self.main_thread) |th| {
|
||||
th.join();
|
||||
}
|
||||
}
|
||||
|
||||
/// main thread entry point.
|
||||
fn mainThreadLoop(self: *Daemon) !void {
|
||||
try self.wpa_ctrl.attach();
|
||||
defer self.wpa_ctrl.detach() catch |err| logger.err("wpa_ctrl.detach failed on exit: {any}", .{err});
|
||||
|
||||
while (true) {
|
||||
time.sleep(1 * time.ns_per_s);
|
||||
self.mainThreadLoopCycle();
|
||||
|
||||
self.mu.lock();
|
||||
const do_quit = self.quit;
|
||||
self.mu.unlock();
|
||||
if (do_quit) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// run one cycle of the main thread loop iteration.
|
||||
/// holds self.mu for the whole duration.
|
||||
fn mainThreadLoopCycle(self: *Daemon) void {
|
||||
self.mu.lock();
|
||||
defer self.mu.unlock();
|
||||
self.readWPACtrlMsg() catch |err| logger.err("readWPACtrlMsg: {any}", .{err});
|
||||
if (self.want_wifi_scan) {
|
||||
if (self.startWifiScan()) {
|
||||
self.want_wifi_scan = false;
|
||||
} else |err| {
|
||||
logger.err("startWifiScan: {any}", .{err});
|
||||
}
|
||||
}
|
||||
if (self.want_report and self.report_ready) {
|
||||
if (self.sendNetworkReport()) {
|
||||
self.want_report = false;
|
||||
} else |err| {
|
||||
logger.err("sendNetworkReport: {any}", .{err});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// caller must hold self.mu.
|
||||
fn startWifiScan(self: *Daemon) !void {
|
||||
try self.wpa_ctrl.scan();
|
||||
self.wifi_scan_in_progress = true;
|
||||
self.report_ready = false;
|
||||
}
|
||||
|
||||
/// invoked when CTRL-EVENT-SCAN-RESULTS event is seen.
|
||||
/// caller must hold self.mu.
|
||||
fn wifiScanComplete(self: *Daemon) void {
|
||||
self.wifi_scan_in_progress = false;
|
||||
self.report_ready = true;
|
||||
}
|
||||
|
||||
/// invoked when CTRL-EVENT-CONNECTED event is seen.
|
||||
/// caller must hold self.mu.
|
||||
fn wifiConnected(self: *Daemon) void {
|
||||
if (self.wpa_save_config_on_connected) {
|
||||
// fails if update_config=0 in wpa_supplicant.conf
|
||||
const ok_saved = self.wpa_ctrl.saveConfig();
|
||||
if (ok_saved) {
|
||||
self.wpa_save_config_on_connected = false;
|
||||
} else |err| {
|
||||
logger.err("wifiConnected: {any}", .{err});
|
||||
}
|
||||
}
|
||||
// always send a network report when connected
|
||||
self.want_report = true;
|
||||
}
|
||||
|
||||
/// invoked when CTRL-EVENT-SSID-TEMP-DISABLED event with authentication failures is seen.
|
||||
/// caller must hold self.mu.
|
||||
fn wifiInvalidKey(self: *Daemon) void {
|
||||
self.wpa_save_config_on_connected = false;
|
||||
self.want_report = true;
|
||||
self.report_ready = true;
|
||||
}
|
||||
|
||||
pub const ReportNetworkStatusOpt = struct {
|
||||
scan: bool,
|
||||
};
|
||||
|
||||
pub fn reportNetworkStatus(self: *Daemon, opt: ReportNetworkStatusOpt) void {
|
||||
self.mu.lock();
|
||||
defer self.mu.unlock();
|
||||
self.want_report = true;
|
||||
self.want_wifi_scan = opt.scan and !self.wifi_scan_in_progress;
|
||||
if (self.want_wifi_scan and self.report_ready) {
|
||||
self.report_ready = false;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn startConnectWifi(self: *Daemon, ssid: []const u8, password: []const u8) !void {
|
||||
if (ssid.len == 0) {
|
||||
return error.ConnectWifiEmptySSID;
|
||||
}
|
||||
const ssid_copy = try self.allocator.dupe(u8, ssid);
|
||||
const pwd_copy = try self.allocator.dupe(u8, password);
|
||||
const th = try std.Thread.spawn(.{}, connectWifiThread, .{ self, ssid_copy, pwd_copy });
|
||||
th.detach();
|
||||
}
|
||||
|
||||
fn connectWifiThread(self: *Daemon, ssid: []const u8, password: []const u8) void {
|
||||
defer {
|
||||
self.allocator.free(ssid);
|
||||
self.allocator.free(password);
|
||||
}
|
||||
// https://hostap.epitest.fi/wpa_supplicant/devel/ctrl_iface_page.html
|
||||
// https://wiki.archlinux.org/title/WPA_supplicant
|
||||
|
||||
// unfortunately, this prevents main thread from looping until released.
|
||||
// but the following commands and expected to be pretty quick.
|
||||
self.mu.lock();
|
||||
defer self.mu.unlock();
|
||||
|
||||
const id = self.addWifiNetwork(ssid, password) catch |err| {
|
||||
logger.err("addWifiNetwork: {any}; exiting", .{err});
|
||||
return;
|
||||
};
|
||||
// SELECT_NETWORK <id> - this disables others
|
||||
// ENABLE_NETWORK <id>
|
||||
self.wpa_ctrl.selectNetwork(id) catch |err| {
|
||||
logger.err("selectNetwork({d}): {any}", .{ id, err });
|
||||
// non-critical; can try to continue
|
||||
};
|
||||
self.wpa_ctrl.enableNetwork(id) catch |err| {
|
||||
logger.err("enableNetwork({d}): {any}; cannot continue", .{ id, err });
|
||||
self.wpa_ctrl.removeNetwork(id) catch {};
|
||||
return;
|
||||
};
|
||||
|
||||
// wait for CTRL-EVENT-CONNECTED, SAVE_CONFIG and send network report.
|
||||
self.wpa_save_config_on_connected = true;
|
||||
}
|
||||
|
||||
/// adds a new network and configures its parameters.
|
||||
/// caller must hold self.mu.
|
||||
fn addWifiNetwork(self: *Daemon, ssid: []const u8, password: []const u8) !u32 {
|
||||
// - ADD_NETWORK -> get id and set parameters
|
||||
// - SET_NETWORK <id> ssid "ssid"
|
||||
// - if password:
|
||||
// SET_NETWORK <id> psk "password"
|
||||
// else:
|
||||
// SET_NETWORK <id> key_mgmt NONE
|
||||
const newWifiId = try self.wpa_ctrl.addNetwork();
|
||||
errdefer self.wpa_ctrl.removeNetwork(newWifiId) catch |err| {
|
||||
logger.err("addWifiNetwork cleanup: {any}", .{err});
|
||||
};
|
||||
var buf: [128:0]u8 = undefined;
|
||||
// TODO: convert ssid to hex string, to support special characters
|
||||
const ssidZ = try std.fmt.bufPrintZ(&buf, "\"{s}\"", .{ssid});
|
||||
try self.wpa_ctrl.setNetworkParam(newWifiId, "ssid", ssidZ);
|
||||
if (password.len > 0) {
|
||||
// TODO: switch to wpa_passphrase
|
||||
const v = try std.fmt.bufPrintZ(&buf, "\"{s}\"", .{password});
|
||||
try self.wpa_ctrl.setNetworkParam(newWifiId, "psk", v);
|
||||
} else {
|
||||
try self.wpa_ctrl.setNetworkParam(newWifiId, "key_mgmt", "NONE");
|
||||
}
|
||||
|
||||
// - LIST_NETWORKS: network id / ssid / bssid / flags
|
||||
// - for each matching ssid unless it's newly created: REMOVE_NETWORK <id>
|
||||
if (self.queryWifiNetworksList(.{ .ssid = ssid })) |res| {
|
||||
defer self.allocator.free(res);
|
||||
for (res) |id| {
|
||||
if (id == newWifiId) {
|
||||
continue;
|
||||
}
|
||||
self.wpa_ctrl.removeNetwork(id) catch |err| {
|
||||
logger.err("wpa_ctrl.removeNetwork({}): {any}", .{ id, err });
|
||||
};
|
||||
}
|
||||
} else |err| {
|
||||
logger.err("queryWifiNetworksList({s}): {any}; won't remove existing, if any", .{ ssid, err });
|
||||
}
|
||||
|
||||
return newWifiId;
|
||||
}
|
||||
|
||||
/// caller must hold self.mu.
|
||||
fn readWPACtrlMsg(self: *Daemon) !void {
|
||||
var buf: [512:0]u8 = undefined;
|
||||
while (try self.wpa_ctrl.pending()) {
|
||||
const m = try self.wpa_ctrl.receive(&buf);
|
||||
logger.debug("wpa_ctrl msg: {s}", .{m});
|
||||
if (mem.indexOf(u8, m, "CTRL-EVENT-SCAN-RESULTS") != null) {
|
||||
self.wifiScanComplete();
|
||||
}
|
||||
if (mem.indexOf(u8, m, "CTRL-EVENT-CONNECTED") != null) {
|
||||
self.wifiConnected();
|
||||
}
|
||||
if (mem.indexOf(u8, m, "CTRL-EVENT-SSID-TEMP-DISABLED") != null) {
|
||||
// TODO: what about CTRL-EVENT-DISCONNECTED bssid=xx:xx:xx:xx:xx:xx reason=15
|
||||
// CTRL-EVENT-SSID-TEMP-DISABLED id=1 ssid="<ssid>" auth_failures=3 duration=49 reason=WRONG_KEY
|
||||
var it = mem.tokenize(u8, m, " ");
|
||||
while (it.next()) |kv_str| {
|
||||
var kv = mem.split(u8, kv_str, "=");
|
||||
if (mem.eql(u8, kv.first(), "auth_failures")) {
|
||||
const v = kv.next();
|
||||
if (v != null and !mem.eql(u8, v.?, "0")) {
|
||||
self.wifiInvalidKey();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO: CTRL-EVENT-DISCONNECTED
|
||||
}
|
||||
}
|
||||
|
||||
/// report network status to ngui.
|
||||
/// caller must hold self.mu.
|
||||
fn sendNetworkReport(self: *Daemon) !void {
|
||||
var report = comm.Message.NetworkReport{
|
||||
.ipaddrs = undefined,
|
||||
.wifi_ssid = null,
|
||||
.wifi_scan_networks = undefined,
|
||||
};
|
||||
|
||||
// fetch all public IP addresses using getifaddrs
|
||||
const pubaddr = try nif.pubAddresses(self.allocator, null);
|
||||
defer self.allocator.free(pubaddr);
|
||||
//var addrs = std.ArrayList([]).init(t.allocator);
|
||||
var ipaddrs = try self.allocator.alloc([]const u8, pubaddr.len);
|
||||
for (pubaddr) |a, i| {
|
||||
ipaddrs[i] = try std.fmt.allocPrint(self.allocator, "{s}", .{a});
|
||||
}
|
||||
defer {
|
||||
for (ipaddrs) |a| self.allocator.free(a);
|
||||
self.allocator.free(ipaddrs);
|
||||
}
|
||||
report.ipaddrs = ipaddrs;
|
||||
|
||||
// get currently connected SSID, if any, from WPA ctrl
|
||||
const ssid = self.queryWifiSSID() catch |err| blk: {
|
||||
logger.err("queryWifiSsid: {any}", .{err});
|
||||
break :blk null;
|
||||
};
|
||||
defer if (ssid) |v| self.allocator.free(v);
|
||||
report.wifi_ssid = ssid;
|
||||
|
||||
// fetch available wifi networks from scan results using WPA ctrl
|
||||
var wifi_networks: ?StringList = if (self.queryWifiScanResults()) |v| v else |err| blk: {
|
||||
logger.err("queryWifiScanResults: {any}", .{err});
|
||||
break :blk null;
|
||||
};
|
||||
defer if (wifi_networks) |*list| list.deinit();
|
||||
if (wifi_networks) |list| {
|
||||
report.wifi_scan_networks = list.items();
|
||||
}
|
||||
|
||||
// report everything back to ngui
|
||||
return comm.write(self.allocator, self.uiwriter, comm.Message{ .network_report = report });
|
||||
}
|
||||
|
||||
fn queryWifiSSID(self: *Daemon) !?[]const u8 {
|
||||
var buf: [512:0]u8 = undefined;
|
||||
const resp = try self.wpa_ctrl.request("STATUS", &buf, null);
|
||||
const ssid = "ssid=";
|
||||
var it = mem.tokenize(u8, resp, "\n");
|
||||
while (it.next()) |line| {
|
||||
if (mem.startsWith(u8, line, ssid)) {
|
||||
// TODO: check line.len vs ssid.len
|
||||
const v = try self.allocator.dupe(u8, line[ssid.len..]);
|
||||
return v;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// callers must free with StringList.deinit.
|
||||
fn queryWifiScanResults(self: *Daemon) !StringList {
|
||||
var buf: [8192:0]u8 = undefined; // TODO: what if isn't enough?
|
||||
// first line is banner: "bssid / frequency / signal level / flags / ssid"
|
||||
const resp = try self.wpa_ctrl.request("SCAN_RESULTS", &buf, null);
|
||||
var it = mem.tokenize(u8, resp, "\n");
|
||||
if (it.next() == null) {
|
||||
return error.MissingWifiScanHeader;
|
||||
}
|
||||
|
||||
var seen = std.BufSet.init(self.allocator);
|
||||
defer seen.deinit();
|
||||
var list = StringList.init(self.allocator);
|
||||
errdefer list.deinit();
|
||||
while (it.next()) |line| {
|
||||
// TODO: wpactrl's text protocol won't work for names with control characters
|
||||
if (mem.lastIndexOfScalar(u8, line, '\t')) |i| {
|
||||
const s = mem.trim(u8, line[i..], "\t\n");
|
||||
if (s.len == 0 or seen.contains(s)) {
|
||||
continue;
|
||||
}
|
||||
try seen.insert(s);
|
||||
try list.append(s);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
const WifiNetworksListFilter = struct {
|
||||
ssid: ?[]const u8, // ignore networks whose ssid doesn't match
|
||||
};
|
||||
|
||||
/// caller must release results with allocator.free.
|
||||
fn queryWifiNetworksList(self: *Daemon, filter: WifiNetworksListFilter) ![]u32 {
|
||||
var buf: [8192:0]u8 = undefined; // TODO: is this enough?
|
||||
// first line is banner: "network id / ssid / bssid / flags"
|
||||
const resp = try self.wpa_ctrl.request("LIST_NETWORKS", &buf, null);
|
||||
var it = mem.tokenize(u8, resp, "\n");
|
||||
if (it.next() == null) {
|
||||
return error.MissingWifiNetworksListHeader;
|
||||
}
|
||||
|
||||
var list = std.ArrayList(u32).init(self.allocator);
|
||||
while (it.next()) |line| {
|
||||
var cols = mem.tokenize(u8, line, "\t");
|
||||
const id_str = cols.next() orelse continue; // bad line format?
|
||||
const ssid = cols.next() orelse continue; // bad line format?
|
||||
const id = std.fmt.parseUnsigned(u32, id_str, 10) catch continue; // skip bad line
|
||||
if (filter.ssid != null and !mem.eql(u8, filter.ssid.?, ssid)) {
|
||||
continue;
|
||||
}
|
||||
list.append(id) catch {}; // grab anything we can
|
||||
}
|
||||
return list.toOwnedSlice();
|
||||
}
|
||||
|
||||
// TODO: turns this into a UniqStringList backed by StringArrayHashMap; also see std.BufSet
|
||||
const StringList = struct {
|
||||
l: std.ArrayList([]const u8),
|
||||
allocator: mem.Allocator,
|
||||
|
||||
const Self = @This();
|
||||
|
||||
pub fn init(allocator: mem.Allocator) Self {
|
||||
return Self{
|
||||
.l = std.ArrayList([]const u8).init(allocator),
|
||||
.allocator = allocator,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Self) void {
|
||||
for (self.l.items) |a| {
|
||||
self.allocator.free(a);
|
||||
}
|
||||
self.l.deinit();
|
||||
}
|
||||
|
||||
pub fn append(self: *Self, s: []const u8) !void {
|
||||
const item = try self.allocator.dupe(u8, s);
|
||||
errdefer self.allocator.free(item);
|
||||
try self.l.append(item);
|
||||
}
|
||||
|
||||
pub fn items(self: Self) []const []const u8 {
|
||||
return self.l.items;
|
||||
}
|
||||
};
|
@ -0,0 +1,225 @@
|
||||
const std = @import("std");
|
||||
const mem = std.mem;
|
||||
const time = std.time;
|
||||
const Thread = std.Thread;
|
||||
|
||||
const comm = @import("comm.zig");
|
||||
const types = @import("types.zig");
|
||||
const symbol = @import("ui/symbol.zig");
|
||||
|
||||
/// SIGPIPE is triggered when a process attempts to write to a broken pipe.
|
||||
/// by default, SIGPIPE terminates the process without invoking a panic handler.
|
||||
/// this declaration makes such writes result in EPIPE (error.BrokenPipe) to let
|
||||
/// the program can handle it.
|
||||
pub const keep_sigpipe = true;
|
||||
|
||||
const stdin = std.io.getStdIn().reader();
|
||||
const stdout = std.io.getStdOut().writer();
|
||||
const logger = std.log.scoped(.ngui);
|
||||
const lvgl_logger = std.log.scoped(.lvgl); // logs LV_LOG_xxx messages
|
||||
|
||||
extern "c" fn lv_timer_handler() u32;
|
||||
extern "c" fn lv_log_register_print_cb(fn (msg: [*:0]const u8) callconv(.C) void) void;
|
||||
const LvTimer = opaque {};
|
||||
//const LvTimerCallback = *const fn (timer: *LvTimer) callconv(.C) void; // stage2
|
||||
const LvTimerCallback = fn (timer: *LvTimer) callconv(.C) void;
|
||||
extern "c" fn lv_timer_create(callback: LvTimerCallback, period_ms: u32, userdata: ?*anyopaque) *LvTimer;
|
||||
extern "c" fn lv_timer_del(timer: *LvTimer) void;
|
||||
extern "c" fn lv_timer_set_repeat_count(timer: *LvTimer, n: i32) void;
|
||||
|
||||
extern "c" fn ui_init() c_int;
|
||||
extern "c" fn ui_update_network_status(text: [*:0]const u8, wifi_list: ?[*:0]const u8) void;
|
||||
|
||||
/// global heap allocator used throughout the gui program.
|
||||
/// TODO: thread-safety?
|
||||
var gpa: mem.Allocator = undefined;
|
||||
|
||||
/// the mutex must be held before any call reaching into lv_xxx functions.
|
||||
/// all nm_xxx functions assume it is the case since they are invoked from lvgl c code.
|
||||
var ui_mutex: Thread.Mutex = .{};
|
||||
/// the program runs until quit is true.
|
||||
var quit: bool = false;
|
||||
|
||||
/// a monotonic clock for reporting elapsed ticks to LVGL.
|
||||
/// the timer runs throughout the whole duration of the UI program.
|
||||
var tick_timer: types.Timer = undefined;
|
||||
|
||||
/// reports elapsed time in ms since the program start, overflowing at u32 max.
|
||||
/// it is defined as LVGL custom tick.
|
||||
export fn nm_get_curr_tick() u32 {
|
||||
const ms = tick_timer.read() / time.ns_per_ms;
|
||||
const over = ms >> 32;
|
||||
if (over > 0) {
|
||||
return @truncate(u32, over); // LVGL deals with overflow correctly
|
||||
}
|
||||
return @truncate(u32, ms);
|
||||
}
|
||||
|
||||
export fn nm_lvgl_log(msg: [*:0]const u8) void {
|
||||
const s = mem.span(msg);
|
||||
lvgl_logger.debug("{s}", .{mem.trimRight(u8, s, "\n")});
|
||||
}
|
||||
|
||||
/// initiate system shutdown.
|
||||
export fn nm_sys_shutdown() void {
|
||||
logger.info("initiating system shutdown", .{});
|
||||
const msg = comm.Message.poweroff;
|
||||
comm.write(gpa, stdout, msg) catch |err| logger.err("nm_sys_shutdown: {any}", .{err});
|
||||
quit = true;
|
||||
}
|
||||
|
||||
export fn nm_tab_settings_active() void {
|
||||
logger.info("starting wifi scan", .{});
|
||||
const msg = comm.Message{ .get_network_report = .{ .scan = true } };
|
||||
comm.write(gpa, stdout, msg) catch |err| logger.err("nm_tab_settings_active: {any}", .{err});
|
||||
}
|
||||
|
||||
export fn nm_request_network_status(t: *LvTimer) void {
|
||||
lv_timer_del(t);
|
||||
const msg: comm.Message = .{ .get_network_report = .{ .scan = false } };
|
||||
comm.write(gpa, stdout, msg) catch |err| logger.err("nm_request_network_status: {any}", .{err});
|
||||
}
|
||||
|
||||
/// ssid and password args must not outlive this function.
|
||||
export fn nm_wifi_start_connect(ssid: [*:0]const u8, password: [*:0]const u8) void {
|
||||
const msg = comm.Message{ .wifi_connect = .{
|
||||
.ssid = mem.span(ssid),
|
||||
.password = mem.span(password),
|
||||
} };
|
||||
logger.info("connect to wifi [{s}]", .{msg.wifi_connect.ssid});
|
||||
comm.write(gpa, stdout, msg) catch |err| {
|
||||
logger.err("comm.write: {any}", .{err});
|
||||
};
|
||||
}
|
||||
|
||||
fn updateNetworkStatus(report: comm.Message.NetworkReport) !void {
|
||||
ui_mutex.lock();
|
||||
defer ui_mutex.unlock();
|
||||
|
||||
var wifi_list: ?[:0]const u8 = null;
|
||||
var wifi_list_ptr: ?[*:0]const u8 = null;
|
||||
if (report.wifi_scan_networks.len > 0) {
|
||||
wifi_list = try mem.joinZ(gpa, "\n", report.wifi_scan_networks);
|
||||
wifi_list_ptr = wifi_list.?.ptr;
|
||||
}
|
||||
defer if (wifi_list) |v| gpa.free(v);
|
||||
|
||||
var status = std.ArrayList(u8).init(gpa); // free'd as owned slice below
|
||||
const w = status.writer();
|
||||
if (report.wifi_ssid) |ssid| {
|
||||
try w.writeAll(symbol.Ok);
|
||||
try w.print(" connected to {s}", .{ssid});
|
||||
} else {
|
||||
try w.writeAll(symbol.Warning);
|
||||
try w.print(" disconnected", .{});
|
||||
}
|
||||
|
||||
if (report.ipaddrs.len > 0) {
|
||||
const ipaddrs = try mem.join(gpa, "\n", report.ipaddrs);
|
||||
defer gpa.free(ipaddrs);
|
||||
try w.print("\n\nIP addresses:\n{s}", .{ipaddrs});
|
||||
}
|
||||
|
||||
const text = try status.toOwnedSliceSentinel(0);
|
||||
defer gpa.free(text);
|
||||
ui_update_network_status(text, wifi_list_ptr);
|
||||
|
||||
// request network status again if we're connected but IP addr list is empty.
|
||||
// can happen with a fresh connection while dhcp is still in progress.
|
||||
if (report.wifi_ssid != null and report.ipaddrs.len == 0) {
|
||||
// TODO: sometimes this is too fast, not all ip addrs are avail (ipv4 vs ipv6)
|
||||
var t = lv_timer_create(nm_request_network_status, 1000, null);
|
||||
lv_timer_set_repeat_count(t, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/// reads messages from nd; loops indefinitely until program exit
|
||||
fn commThread() void {
|
||||
while (true) {
|
||||
commThreadLoopCycle() catch |err| logger.err("commThreadLoopCycle: {any}", .{err});
|
||||
ui_mutex.lock();
|
||||
const do_quit = quit;
|
||||
ui_mutex.unlock();
|
||||
if (do_quit) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn commThreadLoopCycle() !void {
|
||||
const msg = comm.read(gpa, stdin) catch |err| {
|
||||
if (err == error.EndOfStream) {
|
||||
// pointless to continue running if comms is broken
|
||||
ui_mutex.lock();
|
||||
quit = true;
|
||||
ui_mutex.unlock();
|
||||
}
|
||||
return err;
|
||||
};
|
||||
defer comm.free(gpa, msg);
|
||||
logger.debug("got msg tagged {s}", .{@tagName(msg)});
|
||||
switch (msg) {
|
||||
.ping => try comm.write(gpa, stdout, comm.Message.pong),
|
||||
.network_report => |report| {
|
||||
updateNetworkStatus(report) catch |err| logger.err("updateNetworkStatus: {any}", .{err});
|
||||
},
|
||||
else => logger.warn("unhandled msg tag {s}", .{@tagName(msg)}),
|
||||
}
|
||||
}
|
||||
|
||||
/// nakamochi UI program entry point.
|
||||
pub fn main() anyerror!void {
|
||||
// ensure timer is available on this platform before doing anything else;
|
||||
// the UI is unusable otherwise.
|
||||
tick_timer = try time.Timer.start();
|
||||
|
||||
// main heap allocator used through the lifetime of nd
|
||||
var gpa_state = std.heap.GeneralPurposeAllocator(.{}){};
|
||||
defer if (gpa_state.deinit()) {
|
||||
logger.err("memory leaks detected", .{});
|
||||
};
|
||||
gpa = gpa_state.allocator();
|
||||
|
||||
// info level log messages are by default printed only in Debug and ReleaseSafe build modes.
|
||||
lv_log_register_print_cb(nm_lvgl_log);
|
||||
|
||||
const c_res = ui_init();
|
||||
if (c_res != 0) {
|
||||
logger.err("ui_init failed with code {}", .{c_res});
|
||||
std.process.exit(1);
|
||||
}
|
||||
const th = try Thread.spawn(.{}, commThread, .{});
|
||||
th.detach();
|
||||
|
||||
// TODO: handle sigterm
|
||||
while (true) {
|
||||
ui_mutex.lock();
|
||||
var till_next_ms = lv_timer_handler();
|
||||
const do_quit = quit;
|
||||
ui_mutex.unlock();
|
||||
if (do_quit) {
|
||||
return;
|
||||
}
|
||||
// sleep at least 1ms
|
||||
time.sleep(@maximum(1, till_next_ms) * time.ns_per_ms);
|
||||
}
|
||||
}
|
||||
|
||||
test "tick" {
|
||||
const t = std.testing;
|
||||
|
||||
tick_timer = types.Timer{ .value = 0 };
|
||||
try t.expectEqual(@as(u32, 0), nm_get_curr_tick());
|
||||
|
||||
tick_timer.value = 1 * time.ns_per_ms;
|
||||
try t.expectEqual(@as(u32, 1), nm_get_curr_tick());
|
||||
|
||||
tick_timer.value = 13 * time.ns_per_ms;
|
||||
try t.expectEqual(@as(u32, 13), nm_get_curr_tick());
|
||||
|
||||
tick_timer.value = @as(u64, ~@as(u32, 0)) * time.ns_per_ms;
|
||||
try t.expectEqual(@as(u32, std.math.maxInt(u32)), nm_get_curr_tick());
|
||||
|
||||
tick_timer.value = (1 << 32) * time.ns_per_ms;
|
||||
try t.expectEqual(@as(u32, 1), nm_get_curr_tick());
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
const std = @import("std");
|
||||
|
||||
export fn wifi_ssid_add_network(name: [*:0]const u8) void {
|
||||
_ = name;
|
||||
}
|
||||
|
||||
export fn lv_timer_del(timer: *opaque{}) void {
|
||||
_ = timer;
|
||||
}
|
||||
|
||||
test {
|
||||
std.testing.refAllDecls(@This());
|
||||
|
||||
_ = @import("comm.zig");
|
||||
_ = @import("ngui.zig");
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
|
||||
pub const Timer = if (builtin.is_test) TestTimer else std.time.Timer;
|
||||
|
||||
/// TestTimer always reports the same fixed value.
|
||||
pub const TestTimer = if (!builtin.is_test) @compileError("TestTimer is for tests only") else struct {
|
||||
value: u64,
|
||||
|
||||
pub fn read(self: *Timer) u64 {
|
||||
return self.value;
|
||||
}
|
||||
};
|
||||
|
@ -0,0 +1,56 @@
|
||||
/**
|
||||
* framebuffer display + evdev touchpad drivers init
|
||||
*/
|
||||
|
||||
#include "lvgl/lvgl.h"
|
||||
#include "lv_drivers/display/fbdev.h"
|
||||
#include "lv_drivers/indev/evdev.h"
|
||||
|
||||
#define DISP_BUF_SIZE NM_DISP_HOR * NM_DISP_VER / 10
|
||||
|
||||
lv_disp_t* drv_init(void)
|
||||
{
|
||||
fbdev_init();
|
||||
|
||||
static lv_disp_draw_buf_t buf;
|
||||
static lv_color_t cb[DISP_BUF_SIZE];
|
||||
lv_disp_draw_buf_init(&buf, cb, NULL, DISP_BUF_SIZE);
|
||||
uint32_t hor, vert;
|
||||
fbdev_get_sizes(&hor, &vert, NULL);
|
||||
if (hor != NM_DISP_HOR || vert != NM_DISP_VER) {
|
||||
LV_LOG_WARN("framebuffer display mismatch; expected %dx%d", NM_DISP_HOR, NM_DISP_VER);
|
||||
}
|
||||
|
||||
static lv_disp_drv_t disp_drv;
|
||||
lv_disp_drv_init(&disp_drv);
|
||||
disp_drv.draw_buf = &buf;
|
||||
disp_drv.hor_res = NM_DISP_HOR;
|
||||
disp_drv.ver_res = NM_DISP_VER;
|
||||
disp_drv.antialiasing = 1;
|
||||
disp_drv.flush_cb = fbdev_flush;
|
||||
lv_disp_t* disp = lv_disp_drv_register(&disp_drv);
|
||||
if (disp == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* keypad input devices default group;
|
||||
* future-proof: don't have any atm */
|
||||
lv_group_t* g = lv_group_create();
|
||||
if (g == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
lv_group_set_default(g);
|
||||
|
||||
evdev_init();
|
||||
static lv_indev_drv_t touchpad_drv;
|
||||
lv_indev_drv_init(&touchpad_drv);
|
||||
touchpad_drv.type = LV_INDEV_TYPE_POINTER;
|
||||
touchpad_drv.read_cb = evdev_read;
|
||||
lv_indev_t* touchpad = lv_indev_drv_register(&touchpad_drv);
|
||||
if (touchpad == NULL) {
|
||||
/* TODO: or continue without the touchpad? */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return disp;
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
/**
|
||||
* SDL2 drivers init for display, keyboard and mouse
|
||||
*/
|
||||
|
||||
#include "lvgl/lvgl.h"
|
||||
#include "lvgl/src/misc/lv_log.h"
|
||||
#include "lv_drivers/sdl/sdl.h"
|
||||
|
||||
#define SDL_MAIN_HANDLED /*To fix SDL's "undefined reference to WinMain" issue*/
|
||||
#include SDL_INCLUDE_PATH
|
||||
|
||||
lv_disp_t* drv_init(void)
|
||||
{
|
||||
sdl_init();
|
||||
SDL_DisplayMode dm;
|
||||
int dm_err = SDL_GetDesktopDisplayMode(0, &dm);
|
||||
if (dm_err != 0) {
|
||||
LV_LOG_WARN("SDL_GetDesktopDisplayMode: %i", dm_err);
|
||||
} else {
|
||||
unsigned char bpp = SDL_BITSPERPIXEL(dm.format);
|
||||
LV_LOG_INFO("%ix%i %dbpp %s", dm.w, dm.h, bpp, SDL_GetPixelFormatName(dm.format));
|
||||
if (dm.w != NM_DISP_HOR || dm.h != NM_DISP_VER || bpp != LV_COLOR_DEPTH) {
|
||||
LV_LOG_WARN("SDL display mismatch; expected %dx%d %dbpp", NM_DISP_HOR, NM_DISP_VER, LV_COLOR_DEPTH);
|
||||
}
|
||||
}
|
||||
|
||||
static lv_disp_draw_buf_t buf;
|
||||
static lv_color_t cb1[NM_DISP_HOR * 100];
|
||||
static lv_color_t cb2[NM_DISP_HOR * 100];
|
||||
lv_disp_draw_buf_init(&buf, cb1, cb2, NM_DISP_HOR * 100);
|
||||
|
||||
static lv_disp_drv_t disp_drv;
|
||||
lv_disp_drv_init(&disp_drv);
|
||||
disp_drv.draw_buf = &buf;
|
||||
disp_drv.flush_cb = sdl_display_flush;
|
||||
disp_drv.hor_res = NM_DISP_HOR;
|
||||
disp_drv.ver_res = NM_DISP_VER;
|
||||
disp_drv.antialiasing = 1;
|
||||
lv_disp_t* disp = lv_disp_drv_register(&disp_drv);
|
||||
if (disp == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static lv_indev_drv_t mouse_drv;
|
||||
lv_indev_drv_init(&mouse_drv);
|
||||
mouse_drv.type = LV_INDEV_TYPE_POINTER;
|
||||
mouse_drv.read_cb = sdl_mouse_read;
|
||||
lv_indev_t* mouse = lv_indev_drv_register(&mouse_drv);
|
||||
if (mouse == NULL) {
|
||||
LV_LOG_WARN("lv_indev_drv_register(&mouse_drv) returned NULL");
|
||||
}
|
||||
|
||||
/* keypad input devices default group */
|
||||
lv_group_t * g = lv_group_create();
|
||||
if (g == NULL) {
|
||||
LV_LOG_WARN("lv_group_create returned NULL; won't set default group");
|
||||
} else {
|
||||
lv_group_set_default(g);
|
||||
}
|
||||
|
||||
static lv_indev_drv_t keyboard_drv;
|
||||
lv_indev_drv_init(&keyboard_drv);
|
||||
keyboard_drv.type = LV_INDEV_TYPE_KEYPAD;
|
||||
keyboard_drv.read_cb = sdl_keyboard_read;
|
||||
lv_indev_t *kb = lv_indev_drv_register(&keyboard_drv);
|
||||
if (kb == NULL) {
|
||||
LV_LOG_WARN("lv_indev_drv_register(&keyboard_drv) returned NULL");
|
||||
} else if (g) {
|
||||
lv_indev_set_group(kb, g);
|
||||
}
|
||||
|
||||
return disp;
|
||||
}
|
@ -0,0 +1,718 @@
|
||||
/**
|
||||
* LVGL config file for v8.3.1
|
||||
* see lib/lvgl/lv_conf_template.h for initial values
|
||||
*/
|
||||
|
||||
#ifndef LV_CONF_H
|
||||
#define LV_CONF_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/*====================
|
||||
COLOR SETTINGS
|
||||
*====================*/
|
||||
|
||||
/*Color depth: 1 (1 byte per pixel), 8 (RGB332), 16 (RGB565), 32 (ARGB8888)*/
|
||||
#define LV_COLOR_DEPTH 16
|
||||
|
||||
/*Swap the 2 bytes of RGB565 color. Useful if the display has an 8-bit interface (e.g. SPI)*/
|
||||
#define LV_COLOR_16_SWAP 0
|
||||
|
||||
/*Enable features to draw on transparent background.
|
||||
*It's required if opa, and transform_* style properties are used.
|
||||
*Can be also used if the UI is above another layer, e.g. an OSD menu or video player.*/
|
||||
#define LV_COLOR_SCREEN_TRANSP 0
|
||||
|
||||
/* Adjust color mix functions rounding. GPUs might calculate color mix (blending) differently.
|
||||
* 0: round down, 64: round up from x.75, 128: round up from half, 192: round up from x.25, 254: round up */
|
||||
#define LV_COLOR_MIX_ROUND_OFS 0
|
||||
|
||||
/*Images pixels with this color will not be drawn if they are chroma keyed)*/
|
||||
#define LV_COLOR_CHROMA_KEY lv_color_hex(0x00ff00) /*pure green*/
|
||||
|
||||
/*=========================
|
||||
MEMORY SETTINGS
|
||||
*=========================*/
|
||||
|
||||
/*1: use custom malloc/free, 0: use the built-in `lv_mem_alloc()` and `lv_mem_free()`*/
|
||||
// TODO: research benefits of lv_mem_alloc
|
||||
#define LV_MEM_CUSTOM 1
|
||||
#define LV_MEM_CUSTOM_INCLUDE <stdlib.h>
|
||||
#define LV_MEM_CUSTOM_ALLOC malloc
|
||||
#define LV_MEM_CUSTOM_FREE free
|
||||
#define LV_MEM_CUSTOM_REALLOC realloc
|
||||
|
||||
/*Number of the intermediate memory buffer used during rendering and other internal processing mechanisms.
|
||||
*You will see an error log message if there wasn't enough buffers. */
|
||||
#define LV_MEM_BUF_MAX_NUM 16
|
||||
|
||||
/*Use the standard `memcpy` and `memset` instead of LVGL's own functions. (Might or might not be faster).*/
|
||||
#define LV_MEMCPY_MEMSET_STD 0
|
||||
|
||||
/*====================
|
||||
HAL SETTINGS
|
||||
*====================*/
|
||||
|
||||
/*Default display refresh period. LVG will redraw changed areas with this period time*/
|
||||
#define LV_DISP_DEF_REFR_PERIOD 30 /*[ms]*/
|
||||
|
||||
/*Input device read period in milliseconds*/
|
||||
#define LV_INDEV_DEF_READ_PERIOD 30 /*[ms]*/
|
||||
|
||||
/*Default Dot Per Inch. Used to initialize default sizes such as widgets sized, style paddings.
|
||||
*(Not so important, you can adjust it to modify default sizes and spaces)*/
|
||||
#define LV_DPI_DEF 130 /*[px/inch]*/
|
||||
|
||||
/*=======================
|
||||
* FEATURE CONFIGURATION
|
||||
*=======================*/
|
||||
|
||||
/*-------------
|
||||
* Drawing
|
||||
*-----------*/
|
||||
|
||||
/*Enable complex draw engine.
|
||||
*Required to draw shadow, gradient, rounded corners, circles, arc, skew lines, image transformations or any masks*/
|
||||
#define LV_DRAW_COMPLEX 1
|
||||
|
||||
/*Allow buffering some shadow calculation.
|
||||
*LV_SHADOW_CACHE_SIZE is the max. shadow size to buffer, where shadow size is `shadow_width + radius`
|
||||
*Caching has LV_SHADOW_CACHE_SIZE^2 RAM cost*/
|
||||
#define LV_SHADOW_CACHE_SIZE 0
|
||||
|
||||
/* Set number of maximally cached circle data.
|
||||
* The circumference of 1/4 circle are saved for anti-aliasing
|
||||
* radius * 4 bytes are used per circle (the most often used radiuses are saved)
|
||||
* 0: to disable caching */
|
||||
#define LV_CIRCLE_CACHE_SIZE 4
|
||||
|
||||
/**
|
||||
* "Simple layers" are used when a widget has `style_opa < 255` to buffer the widget into a layer
|
||||
* and blend it as an image with the given opacity.
|
||||
* Note that `bg_opa`, `text_opa` etc don't require buffering into layer)
|
||||
* The widget can be buffered in smaller chunks to avoid using large buffers.
|
||||
*
|
||||
* - LV_LAYER_SIMPLE_BUF_SIZE: [bytes] the optimal target buffer size. LVGL will try to allocate it
|
||||
* - LV_LAYER_SIMPLE_FALLBACK_BUF_SIZE: [bytes] used if `LV_LAYER_SIMPLE_BUF_SIZE` couldn't be allocated.
|
||||
*
|
||||
* Both buffer sizes are in bytes.
|
||||
* "Transformed layers" (where transform_angle/zoom properties are used) use larger buffers
|
||||
* and can't be drawn in chunks. So these settings affects only widgets with opacity.
|
||||
*/
|
||||
#define LV_LAYER_SIMPLE_BUF_SIZE (24 * 1024)
|
||||
#define LV_LAYER_SIMPLE_FALLBACK_BUF_SIZE (3 * 1024)
|
||||
|
||||
/*Default image cache size. Image caching keeps the images opened.
|
||||
*If only the built-in image formats are used there is no real advantage of caching. (I.e. if no new image decoder is added)
|
||||
*With complex image decoders (e.g. PNG or JPG) caching can save the continuous open/decode of images.
|
||||
*However the opened images might consume additional RAM.
|
||||
*0: to disable caching*/
|
||||
#define LV_IMG_CACHE_DEF_SIZE 0
|
||||
|
||||
/*Number of stops allowed per gradient. Increase this to allow more stops.
|
||||
*This adds (sizeof(lv_color_t) + 1) bytes per additional stop*/
|
||||
#define LV_GRADIENT_MAX_STOPS 2
|
||||
|
||||
/*Default gradient buffer size.
|
||||
*When LVGL calculates the gradient "maps" it can save them into a cache to avoid calculating them again.
|
||||
*LV_GRAD_CACHE_DEF_SIZE sets the size of this cache in bytes.
|
||||
*If the cache is too small the map will be allocated only while it's required for the drawing.
|
||||
*0 mean no caching.*/
|
||||
#define LV_GRAD_CACHE_DEF_SIZE 0
|
||||
|
||||
/*Allow dithering the gradients (to achieve visual smooth color gradients on limited color depth display)
|
||||
*LV_DITHER_GRADIENT implies allocating one or two more lines of the object's rendering surface
|
||||
*The increase in memory consumption is (32 bits * object width) plus 24 bits * object width if using error diffusion */
|
||||
#define LV_DITHER_GRADIENT 0
|
||||
|
||||
/*Maximum buffer size to allocate for rotation.
|
||||
*Only used if software rotation is enabled in the display driver.*/
|
||||
#define LV_DISP_ROT_MAX_BUF (10*1024)
|
||||
|
||||
/*-------------
|
||||
* GPU
|
||||
*-----------*/
|
||||
|
||||
/*Use Arm's 2D acceleration library Arm-2D */
|
||||
/* TODO: consider enabling for rpi? */
|
||||
#define LV_USE_GPU_ARM2D 0
|
||||
|
||||
/*Use STM32's DMA2D (aka Chrom Art) GPU*/
|
||||
#define LV_USE_GPU_STM32_DMA2D 0
|
||||
#if LV_USE_GPU_STM32_DMA2D
|
||||
/*Must be defined to include path of CMSIS header of target processor
|
||||
e.g. "stm32f769xx.h" or "stm32f429xx.h"*/
|
||||
#define LV_GPU_DMA2D_CMSIS_INCLUDE
|
||||
#endif
|
||||
|
||||
/*Use SWM341's DMA2D GPU*/
|
||||
#define LV_USE_GPU_SWM341_DMA2D 0
|
||||
#if LV_USE_GPU_SWM341_DMA2D
|
||||
#define LV_GPU_SWM341_DMA2D_INCLUDE "SWM341.h"
|
||||
#endif
|
||||
|
||||
/*Use NXP's PXP GPU iMX RTxxx platforms*/
|
||||
#define LV_USE_GPU_NXP_PXP 0
|
||||
#if LV_USE_GPU_NXP_PXP
|
||||
/*1: Add default bare metal and FreeRTOS interrupt handling routines for PXP (lv_gpu_nxp_pxp_osa.c)
|
||||
* and call lv_gpu_nxp_pxp_init() automatically during lv_init(). Note that symbol SDK_OS_FREE_RTOS
|
||||
* has to be defined in order to use FreeRTOS OSA, otherwise bare-metal implementation is selected.
|
||||
*0: lv_gpu_nxp_pxp_init() has to be called manually before lv_init()
|
||||
*/
|
||||
#define LV_USE_GPU_NXP_PXP_AUTO_INIT 0
|
||||
#endif
|
||||
|
||||
/*Use NXP's VG-Lite GPU iMX RTxxx platforms*/
|
||||
#define LV_USE_GPU_NXP_VG_LITE 0
|
||||
|
||||
/*Use SDL renderer API*/
|
||||
#define LV_USE_GPU_SDL 0
|
||||
#if LV_USE_GPU_SDL
|
||||
#define LV_GPU_SDL_INCLUDE_PATH <SDL2/SDL.h>
|
||||
/*Texture cache size, 8MB by default*/
|
||||
#define LV_GPU_SDL_LRU_SIZE (1024 * 1024 * 8)
|
||||
/*Custom blend mode for mask drawing, disable if you need to link with older SDL2 lib*/
|
||||
#define LV_GPU_SDL_CUSTOM_BLEND_MODE (SDL_VERSION_ATLEAST(2, 0, 6))
|
||||
#endif
|
||||
|
||||
/*-------------
|
||||
* Logging
|
||||
*-----------*/
|
||||
|
||||
/*Enable the log module*/
|
||||
#define LV_USE_LOG 1
|
||||
#if LV_USE_LOG
|
||||
|
||||
/*How important log should be added:
|
||||
*LV_LOG_LEVEL_TRACE A lot of logs to give detailed information
|
||||
*LV_LOG_LEVEL_INFO Log important events
|
||||
*LV_LOG_LEVEL_WARN Log if something unwanted happened but didn't cause a problem
|
||||
*LV_LOG_LEVEL_ERROR Only critical issue, when the system may fail
|
||||
*LV_LOG_LEVEL_USER Only logs added by the user
|
||||
*LV_LOG_LEVEL_NONE Do not log anything*/
|
||||
#define LV_LOG_LEVEL LV_LOG_LEVEL_INFO
|
||||
|
||||
/*1: Print the log with 'printf';
|
||||
*0: User need to register a callback with `lv_log_register_print_cb()`*/
|
||||
#define LV_LOG_PRINTF 0
|
||||
|
||||
/*Enable/disable LV_LOG_TRACE in modules that produces a huge number of logs*/
|
||||
#define LV_LOG_TRACE_MEM 0
|
||||
#define LV_LOG_TRACE_TIMER 0
|
||||
#define LV_LOG_TRACE_INDEV 1
|
||||
#define LV_LOG_TRACE_DISP_REFR 1
|
||||
#define LV_LOG_TRACE_EVENT 1
|
||||
#define LV_LOG_TRACE_OBJ_CREATE 0
|
||||
#define LV_LOG_TRACE_LAYOUT 0
|
||||
#define LV_LOG_TRACE_ANIM 0
|
||||
|
||||
#endif /*LV_USE_LOG*/
|
||||
|
||||
/*-------------
|
||||
* Asserts
|
||||
*-----------*/
|
||||
|
||||
/*Enable asserts if an operation is failed or an invalid data is found.
|
||||
*If LV_USE_LOG is enabled an error message will be printed on failure*/
|
||||
#define LV_USE_ASSERT_NULL 1 /*Check if the parameter is NULL. (Very fast, recommended)*/
|
||||
#define LV_USE_ASSERT_MALLOC 1 /*Checks is the memory is successfully allocated or no. (Very fast, recommended)*/
|
||||
#define LV_USE_ASSERT_STYLE 0 /*Check if the styles are properly initialized. (Very fast, recommended)*/
|
||||
#define LV_USE_ASSERT_MEM_INTEGRITY 0 /*Check the integrity of `lv_mem` after critical operations. (Slow)*/
|
||||
#define LV_USE_ASSERT_OBJ 0 /*Check the object's type and existence (e.g. not deleted). (Slow)*/
|
||||
|
||||
/*Add a custom handler when assert happens e.g. to restart the MCU*/
|
||||
#define LV_ASSERT_HANDLER_INCLUDE <stdint.h>
|
||||
#define LV_ASSERT_HANDLER while(1); /*Halt by default*/
|
||||
|
||||
/*-------------
|
||||
* Others
|
||||
*-----------*/
|
||||
|
||||
/*1: Show CPU usage and FPS count*/
|
||||
#define LV_USE_PERF_MONITOR 0
|
||||
#if LV_USE_PERF_MONITOR
|
||||
#define LV_USE_PERF_MONITOR_POS LV_ALIGN_BOTTOM_RIGHT
|
||||
#endif
|
||||
|
||||
/*1: Show the used memory and the memory fragmentation
|
||||
* Requires LV_MEM_CUSTOM = 0*/
|
||||
#define LV_USE_MEM_MONITOR 0
|
||||
#if LV_USE_MEM_MONITOR
|
||||
#define LV_USE_MEM_MONITOR_POS LV_ALIGN_BOTTOM_LEFT
|
||||
#endif
|
||||
|
||||
/*1: Draw random colored rectangles over the redrawn areas*/
|
||||
#define LV_USE_REFR_DEBUG 0
|
||||
|
||||
/*Change the built in (v)snprintf functions*/
|
||||
#define LV_SPRINTF_CUSTOM 0
|
||||
#if LV_SPRINTF_CUSTOM
|
||||
#define LV_SPRINTF_INCLUDE <stdio.h>
|
||||
#define lv_snprintf snprintf
|
||||
#define lv_vsnprintf vsnprintf
|
||||
#else /*LV_SPRINTF_CUSTOM*/
|
||||
#define LV_SPRINTF_USE_FLOAT 0
|
||||
#endif /*LV_SPRINTF_CUSTOM*/
|
||||
|
||||
#define LV_USE_USER_DATA 1
|
||||
|
||||
/*Garbage Collector settings
|
||||
*Used if lvgl is bound to higher level language and the memory is managed by that language*/
|
||||
#define LV_ENABLE_GC 0
|
||||
#if LV_ENABLE_GC != 0
|
||||
#define LV_GC_INCLUDE "gc.h" /*Include Garbage Collector related things*/
|
||||
#endif /*LV_ENABLE_GC*/
|
||||
|
||||
/*=====================
|
||||
* COMPILER SETTINGS
|
||||
*====================*/
|
||||
|
||||
/*For big endian systems set to 1*/
|
||||
#define LV_BIG_ENDIAN_SYSTEM 0
|
||||
|
||||
/*Define a custom attribute to `lv_tick_inc` function*/
|
||||
#define LV_ATTRIBUTE_TICK_INC
|
||||
|
||||
/*Define a custom attribute to `lv_timer_handler` function*/
|
||||
#define LV_ATTRIBUTE_TIMER_HANDLER
|
||||
|
||||
/*Define a custom attribute to `lv_disp_flush_ready` function*/
|
||||
#define LV_ATTRIBUTE_FLUSH_READY
|
||||
|
||||
/*Required alignment size for buffers*/
|
||||
#define LV_ATTRIBUTE_MEM_ALIGN_SIZE 1
|
||||
|
||||
/*Will be added where memories needs to be aligned (with -Os data might not be aligned to boundary by default).
|
||||
* E.g. __attribute__((aligned(4)))*/
|
||||
#define LV_ATTRIBUTE_MEM_ALIGN
|
||||
|
||||
/*Attribute to mark large constant arrays for example font's bitmaps*/
|
||||
#define LV_ATTRIBUTE_LARGE_CONST
|
||||
|
||||
/*Compiler prefix for a big array declaration in RAM*/
|
||||
#define LV_ATTRIBUTE_LARGE_RAM_ARRAY
|
||||
|
||||
/*Place performance critical functions into a faster memory (e.g RAM)*/
|
||||
#define LV_ATTRIBUTE_FAST_MEM
|
||||
|
||||
/*Prefix variables that are used in GPU accelerated operations, often these need to be placed in RAM sections that are DMA accessible*/
|
||||
#define LV_ATTRIBUTE_DMA
|
||||
|
||||
/*Export integer constant to binding. This macro is used with constants in the form of LV_<CONST> that
|
||||
*should also appear on LVGL binding API such as Micropython.*/
|
||||
#define LV_EXPORT_CONST_INT(int_value) struct _silence_gcc_warning /*The default value just prevents GCC warning*/
|
||||
|
||||
/*Extend the default -32k..32k coordinate range to -4M..4M by using int32_t for coordinates instead of int16_t*/
|
||||
#define LV_USE_LARGE_COORD 0
|
||||
|
||||
/*==================
|
||||
* FONT USAGE
|
||||
*===================*/
|
||||
|
||||
/*Montserrat fonts with ASCII range and some symbols using bpp = 4
|
||||
*https://fonts.google.com/specimen/Montserrat*/
|
||||
#define LV_FONT_MONTSERRAT_8 0
|
||||
#define LV_FONT_MONTSERRAT_10 0
|
||||
#define LV_FONT_MONTSERRAT_12 0
|
||||
#define LV_FONT_MONTSERRAT_14 0
|
||||
#define LV_FONT_MONTSERRAT_16 0
|
||||
#define LV_FONT_MONTSERRAT_18 0
|
||||
#define LV_FONT_MONTSERRAT_20 0
|
||||
#define LV_FONT_MONTSERRAT_22 0
|
||||
#define LV_FONT_MONTSERRAT_24 0
|
||||
#define LV_FONT_MONTSERRAT_26 0
|
||||
#define LV_FONT_MONTSERRAT_28 0
|
||||
#define LV_FONT_MONTSERRAT_30 0
|
||||
#define LV_FONT_MONTSERRAT_32 0
|
||||
#define LV_FONT_MONTSERRAT_34 0
|
||||
#define LV_FONT_MONTSERRAT_36 0
|
||||
#define LV_FONT_MONTSERRAT_38 0
|
||||
#define LV_FONT_MONTSERRAT_40 0
|
||||
#define LV_FONT_MONTSERRAT_42 0
|
||||
#define LV_FONT_MONTSERRAT_44 0
|
||||
#define LV_FONT_MONTSERRAT_46 0
|
||||
#define LV_FONT_MONTSERRAT_48 0
|
||||
|
||||
/*Demonstrate special features*/
|
||||
#define LV_FONT_MONTSERRAT_12_SUBPX 0
|
||||
#define LV_FONT_MONTSERRAT_28_COMPRESSED 0 /*bpp = 3*/
|
||||
#define LV_FONT_DEJAVU_16_PERSIAN_HEBREW 0 /*Hebrew, Arabic, Persian letters and all their forms*/
|
||||
#define LV_FONT_SIMSUN_16_CJK 0 /*1000 most common CJK radicals*/
|
||||
|
||||
/*Pixel perfect monospace fonts*/
|
||||
#define LV_FONT_UNSCII_8 0
|
||||
#define LV_FONT_UNSCII_16 0
|
||||
|
||||
/*Optionally declare custom fonts here.
|
||||
*You can use these fonts as default font too and they will be available globally.
|
||||
*E.g. #define LV_FONT_CUSTOM_DECLARE LV_FONT_DECLARE(my_font_1) LV_FONT_DECLARE(my_font_2)*/
|
||||
#define LV_FONT_CUSTOM_DECLARE LV_FONT_DECLARE(lv_font_courierprimecode_14) LV_FONT_DECLARE(lv_font_courierprimecode_24)
|
||||
|
||||
/*Always set a default font*/
|
||||
//#define LV_FONT_DEFAULT &lv_font_montserrat_14
|
||||
#define LV_FONT_DEFAULT &lv_font_courierprimecode_14
|
||||
|
||||
/* additional fontawesome symbols to complement LV_SYMBOL_xxx */
|
||||
#define NM_SYMBOL_BITCOIN "\xEF\x8D\xB9" /* 0xF379 */
|
||||
#define NM_SYMBOL_BITCOIN_SIGN "\xEE\x82\xB4" /* 0xE0B4 */
|
||||
#define NM_SYMBOL_BOLT "\xEF\x83\xA7" /* 0xF0E7 */
|
||||
|
||||
/*Enable handling large font and/or fonts with a lot of characters.
|
||||
*The limit depends on the font size, font face and bpp.
|
||||
*Compiler error will be triggered if a font needs it.*/
|
||||
#define LV_FONT_FMT_TXT_LARGE 0
|
||||
|
||||
/*Enables/disables support for compressed fonts.*/
|
||||
#define LV_USE_FONT_COMPRESSED 0
|
||||
|
||||
/*Enable subpixel rendering*/
|
||||
#define LV_USE_FONT_SUBPX 0
|
||||
#if LV_USE_FONT_SUBPX
|
||||
/*Set the pixel order of the display. Physical order of RGB channels. Doesn't matter with "normal" fonts.*/
|
||||
#define LV_FONT_SUBPX_BGR 0 /*0: RGB; 1:BGR order*/
|
||||
#endif
|
||||
|
||||
/*Enable drawing placeholders when glyph dsc is not found*/
|
||||
#define LV_USE_FONT_PLACEHOLDER 1
|
||||
|
||||
/*=================
|
||||
* TEXT SETTINGS
|
||||
*=================*/
|
||||
|
||||
/**
|
||||
* Select a character encoding for strings.
|
||||
* Your IDE or editor should have the same character encoding
|
||||
* - LV_TXT_ENC_UTF8
|
||||
* - LV_TXT_ENC_ASCII
|
||||
*/
|
||||
#define LV_TXT_ENC LV_TXT_ENC_UTF8
|
||||
|
||||
/*Can break (wrap) texts on these chars*/
|
||||
#define LV_TXT_BREAK_CHARS " ,.;:-_"
|
||||
|
||||
/*If a word is at least this long, will break wherever "prettiest"
|
||||
*To disable, set to a value <= 0*/
|
||||
#define LV_TXT_LINE_BREAK_LONG_LEN 0
|
||||
|
||||
/*Minimum number of characters in a long word to put on a line before a break.
|
||||
*Depends on LV_TXT_LINE_BREAK_LONG_LEN.*/
|
||||
#define LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN 3
|
||||
|
||||
/*Minimum number of characters in a long word to put on a line after a break.
|
||||
*Depends on LV_TXT_LINE_BREAK_LONG_LEN.*/
|
||||
#define LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN 3
|
||||
|
||||
/*The control character to use for signalling text recoloring.*/
|
||||
#define LV_TXT_COLOR_CMD "#"
|
||||
|
||||
/*Support bidirectional texts. Allows mixing Left-to-Right and Right-to-Left texts.
|
||||
*The direction will be processed according to the Unicode Bidirectional Algorithm:
|
||||
*https://www.w3.org/International/articles/inline-bidi-markup/uba-basics*/
|
||||
#define LV_USE_BIDI 1
|
||||
#if LV_USE_BIDI
|
||||
/*Set the default direction. Supported values:
|
||||
*`LV_BASE_DIR_LTR` Left-to-Right
|
||||
*`LV_BASE_DIR_RTL` Right-to-Left
|
||||
*`LV_BASE_DIR_AUTO` detect texts base direction*/
|
||||
#define LV_BIDI_BASE_DIR_DEF LV_BASE_DIR_AUTO
|
||||
#endif
|
||||
|
||||
/*Enable Arabic/Persian processing
|
||||
*In these languages characters should be replaced with an other form based on their position in the text*/
|
||||
#define LV_USE_ARABIC_PERSIAN_CHARS 0
|
||||
|
||||
/*==================
|
||||
* WIDGET USAGE
|
||||
*================*/
|
||||
|
||||
/*Documentation of the widgets: https://docs.lvgl.io/latest/en/html/widgets/index.html*/
|
||||
|
||||
#define LV_USE_ARC 1
|
||||
|
||||
#define LV_USE_BAR 1
|
||||
|
||||
#define LV_USE_BTN 1
|
||||
|
||||
#define LV_USE_BTNMATRIX 1
|
||||
|
||||
#define LV_USE_CANVAS 1
|
||||
|
||||
#define LV_USE_CHECKBOX 1
|
||||
|
||||
#define LV_USE_DROPDOWN 1 /*Requires: lv_label*/
|
||||
|
||||
#define LV_USE_IMG 1 /*Requires: lv_label*/
|
||||
|
||||
#define LV_USE_LABEL 1
|
||||
#if LV_USE_LABEL
|
||||
#define LV_LABEL_TEXT_SELECTION 1 /*Enable selecting text of the label*/
|
||||
#define LV_LABEL_LONG_TXT_HINT 1 /*Store some extra info in labels to speed up drawing of very long texts*/
|
||||
#endif
|
||||
|
||||
#define LV_USE_LINE 1
|
||||
|
||||
#define LV_USE_ROLLER 1 /*Requires: lv_label*/
|
||||
#if LV_USE_ROLLER
|
||||
#define LV_ROLLER_INF_PAGES 7 /*Number of extra "pages" when the roller is infinite*/
|
||||
#endif
|
||||
|
||||
#define LV_USE_SLIDER 1 /*Requires: lv_bar*/
|
||||
|
||||
#define LV_USE_SWITCH 1
|
||||
|
||||
#define LV_USE_TEXTAREA 1 /*Requires: lv_label*/
|
||||
#define LV_TEXTAREA_DEF_PWD_SHOW_TIME 1500 /*ms*/
|
||||
|
||||
#define LV_USE_TABLE 1
|
||||
|
||||
/*==================
|
||||
* EXTRA COMPONENTS
|
||||
*==================*/
|
||||
|
||||
/*-----------
|
||||
* Widgets
|
||||
*----------*/
|
||||
#define LV_USE_ANIMIMG 1
|
||||
|
||||
#define LV_USE_CALENDAR 1
|
||||
#define LV_CALENDAR_WEEK_STARTS_MONDAY 1
|
||||
#if LV_CALENDAR_WEEK_STARTS_MONDAY
|
||||
#define LV_CALENDAR_DEFAULT_DAY_NAMES {"Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"}
|
||||
#else
|
||||
#define LV_CALENDAR_DEFAULT_DAY_NAMES {"Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"}
|
||||
#endif
|
||||
|
||||
#define LV_CALENDAR_DEFAULT_MONTH_NAMES {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"}
|
||||
#define LV_USE_CALENDAR_HEADER_ARROW 1
|
||||
#define LV_USE_CALENDAR_HEADER_DROPDOWN 1
|
||||
|
||||
#define LV_USE_CHART 1
|
||||
|
||||
#define LV_USE_COLORWHEEL 1
|
||||
|
||||
#define LV_USE_IMGBTN 1
|
||||
|
||||
#define LV_USE_KEYBOARD 1
|
||||
|
||||
#define LV_USE_LED 1
|
||||
|
||||
#define LV_USE_LIST 1
|
||||
|
||||
#define LV_USE_MENU 1
|
||||
|
||||
#define LV_USE_METER 1
|
||||
|
||||
#define LV_USE_MSGBOX 1
|
||||
|
||||
#define LV_USE_SPAN 1
|
||||
/*A line text can contain maximum num of span descriptor */
|
||||
#define LV_SPAN_SNIPPET_STACK_SIZE 64
|
||||
|
||||
#define LV_USE_SPINBOX 1
|
||||
|
||||
#define LV_USE_SPINNER 1
|
||||
|
||||
#define LV_USE_TABVIEW 1
|
||||
|
||||
#define LV_USE_TILEVIEW 1
|
||||
|
||||
#define LV_USE_WIN 1
|
||||
|
||||
/*-----------
|
||||
* Themes
|
||||
*----------*/
|
||||
|
||||
/*A simple, impressive and very complete theme*/
|
||||
#define LV_USE_THEME_DEFAULT 1
|
||||
#if LV_USE_THEME_DEFAULT
|
||||
|
||||
/*0: Light mode; 1: Dark mode*/
|
||||
#define LV_THEME_DEFAULT_DARK 0
|
||||
|
||||
/*1: Enable grow on press*/
|
||||
#define LV_THEME_DEFAULT_GROW 1
|
||||
|
||||
/*Default transition time in [ms]*/
|
||||
#define LV_THEME_DEFAULT_TRANSITION_TIME 80
|
||||
#endif /*LV_USE_THEME_DEFAULT*/
|
||||
|
||||
/*A very simple theme that is a good starting point for a custom theme*/
|
||||
#define LV_USE_THEME_BASIC 1
|
||||
|
||||
/*A theme designed for monochrome displays*/
|
||||
#define LV_USE_THEME_MONO 1
|
||||
|
||||
/*-----------
|
||||
* Layouts
|
||||
*----------*/
|
||||
|
||||
/*A layout similar to Flexbox in CSS.*/
|
||||
#define LV_USE_FLEX 1
|
||||
|
||||
/*A layout similar to Grid in CSS.*/
|
||||
#define LV_USE_GRID 1
|
||||
|
||||
/*---------------------
|
||||
* 3rd party libraries
|
||||
*--------------------*/
|
||||
|
||||
/*File system interfaces for common APIs */
|
||||
|
||||
/*API for fopen, fread, etc*/
|
||||
#define LV_USE_FS_STDIO 0
|
||||
#if LV_USE_FS_STDIO
|
||||
#define LV_FS_STDIO_LETTER '\0' /*Set an upper cased letter on which the drive will accessible (e.g. 'A')*/
|
||||
#define LV_FS_STDIO_PATH "" /*Set the working directory. File/directory paths will be appended to it.*/
|
||||
#define LV_FS_STDIO_CACHE_SIZE 0 /*>0 to cache this number of bytes in lv_fs_read()*/
|
||||
#endif
|
||||
|
||||
/*API for open, read, etc*/
|
||||
#define LV_USE_FS_POSIX 0
|
||||
#if LV_USE_FS_POSIX
|
||||
#define LV_FS_POSIX_LETTER '\0' /*Set an upper cased letter on which the drive will accessible (e.g. 'A')*/
|
||||
#define LV_FS_POSIX_PATH "" /*Set the working directory. File/directory paths will be appended to it.*/
|
||||
#define LV_FS_POSIX_CACHE_SIZE 0 /*>0 to cache this number of bytes in lv_fs_read()*/
|
||||
#endif
|
||||
|
||||
/*API for CreateFile, ReadFile, etc*/
|
||||
#define LV_USE_FS_WIN32 0
|
||||
#if LV_USE_FS_WIN32
|
||||
#define LV_FS_WIN32_LETTER '\0' /*Set an upper cased letter on which the drive will accessible (e.g. 'A')*/
|
||||
#define LV_FS_WIN32_PATH "" /*Set the working directory. File/directory paths will be appended to it.*/
|
||||
#define LV_FS_WIN32_CACHE_SIZE 0 /*>0 to cache this number of bytes in lv_fs_read()*/
|
||||
#endif
|
||||
|
||||
/*API for FATFS (needs to be added separately). Uses f_open, f_read, etc*/
|
||||
#define LV_USE_FS_FATFS 0
|
||||
#if LV_USE_FS_FATFS
|
||||
#define LV_FS_FATFS_LETTER '\0' /*Set an upper cased letter on which the drive will accessible (e.g. 'A')*/
|
||||
#define LV_FS_FATFS_CACHE_SIZE 0 /*>0 to cache this number of bytes in lv_fs_read()*/
|
||||
#endif
|
||||
|
||||
/*PNG decoder library*/
|
||||
#define LV_USE_PNG 0
|
||||
|
||||
/*BMP decoder library*/
|
||||
#define LV_USE_BMP 0
|
||||
|
||||
/* JPG + split JPG decoder library.
|
||||
* Split JPG is a custom format optimized for embedded systems. */
|
||||
#define LV_USE_SJPG 0
|
||||
|
||||
/*GIF decoder library*/
|
||||
#define LV_USE_GIF 0
|
||||
|
||||
/*QR code library*/
|
||||
#define LV_USE_QRCODE 0
|
||||
|
||||
/*FreeType library*/
|
||||
#define LV_USE_FREETYPE 0
|
||||
#if LV_USE_FREETYPE
|
||||
/*Memory used by FreeType to cache characters [bytes] (-1: no caching)*/
|
||||
#define LV_FREETYPE_CACHE_SIZE (16 * 1024)
|
||||
#if LV_FREETYPE_CACHE_SIZE >= 0
|
||||
/* 1: bitmap cache use the sbit cache, 0:bitmap cache use the image cache. */
|
||||
/* sbit cache:it is much more memory efficient for small bitmaps(font size < 256) */
|
||||
/* if font size >= 256, must be configured as image cache */
|
||||
#define LV_FREETYPE_SBIT_CACHE 0
|
||||
/* Maximum number of opened FT_Face/FT_Size objects managed by this cache instance. */
|
||||
/* (0:use system defaults) */
|
||||
#define LV_FREETYPE_CACHE_FT_FACES 0
|
||||
#define LV_FREETYPE_CACHE_FT_SIZES 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*Rlottie library*/
|
||||
#define LV_USE_RLOTTIE 0
|
||||
|
||||
/*FFmpeg library for image decoding and playing videos
|
||||
*Supports all major image formats so do not enable other image decoder with it*/
|
||||
#define LV_USE_FFMPEG 0
|
||||
#if LV_USE_FFMPEG
|
||||
/*Dump input information to stderr*/
|
||||
#define LV_FFMPEG_DUMP_FORMAT 0
|
||||
#endif
|
||||
|
||||
/*-----------
|
||||
* Others
|
||||
*----------*/
|
||||
|
||||
/*1: Enable API to take snapshot for object*/
|
||||
#define LV_USE_SNAPSHOT 0
|
||||
|
||||
/*1: Enable Monkey test*/
|
||||
#define LV_USE_MONKEY 0
|
||||
|
||||
/*1: Enable grid navigation*/
|
||||
#define LV_USE_GRIDNAV 0
|
||||
|
||||
/*1: Enable lv_obj fragment*/
|
||||
#define LV_USE_FRAGMENT 0
|
||||
|
||||
/*1: Support using images as font in label or span widgets */
|
||||
#define LV_USE_IMGFONT 0
|
||||
|
||||
/*1: Enable a published subscriber based messaging system */
|
||||
#define LV_USE_MSG 0
|
||||
|
||||
/*1: Enable Pinyin input method*/
|
||||
/*Requires: lv_keyboard*/
|
||||
#define LV_USE_IME_PINYIN 0
|
||||
#if LV_USE_IME_PINYIN
|
||||
/*1: Use default thesaurus*/
|
||||
/*If you do not use the default thesaurus, be sure to use `lv_ime_pinyin` after setting the thesauruss*/
|
||||
#define LV_IME_PINYIN_USE_DEFAULT_DICT 1
|
||||
/*Set the maximum number of candidate panels that can be displayed*/
|
||||
/*This needs to be adjusted according to the size of the screen*/
|
||||
#define LV_IME_PINYIN_CAND_TEXT_NUM 6
|
||||
|
||||
/*Use 9 key input(k9)*/
|
||||
#define LV_IME_PINYIN_USE_K9_MODE 1
|
||||
#if LV_IME_PINYIN_USE_K9_MODE == 1
|
||||
#define LV_IME_PINYIN_K9_CAND_TEXT_NUM 3
|
||||
#endif // LV_IME_PINYIN_USE_K9_MODE
|
||||
#endif
|
||||
|
||||
/*==================
|
||||
* EXAMPLES
|
||||
*==================*/
|
||||
|
||||
/*Enable the examples to be built with the library*/
|
||||
#define LV_BUILD_EXAMPLES 0
|
||||
|
||||
/*===================
|
||||
* DEMO USAGE
|
||||
====================*/
|
||||
|
||||
/*Show some widget. It might be required to increase `LV_MEM_SIZE` */
|
||||
#define LV_USE_DEMO_WIDGETS 0
|
||||
#if LV_USE_DEMO_WIDGETS
|
||||
#define LV_DEMO_WIDGETS_SLIDESHOW 0
|
||||
#endif
|
||||
|
||||
/*Demonstrate the usage of encoder and keyboard*/
|
||||
#define LV_USE_DEMO_KEYPAD_AND_ENCODER 0
|
||||
|
||||
/*Benchmark your system*/
|
||||
#define LV_USE_DEMO_BENCHMARK 0
|
||||
#if LV_USE_DEMO_BENCHMARK
|
||||
/*Use RGB565A8 images with 16 bit color depth instead of ARGB8565*/
|
||||
#define LV_DEMO_BENCHMARK_RGB565A8 0
|
||||
#endif
|
||||
|
||||
/*Stress test for LVGL*/
|
||||
#define LV_USE_DEMO_STRESS 0
|
||||
|
||||
/*Music player demo*/
|
||||
#define LV_USE_DEMO_MUSIC 0
|
||||
#if LV_USE_DEMO_MUSIC
|
||||
#define LV_DEMO_MUSIC_SQUARE 0
|
||||
#define LV_DEMO_MUSIC_LANDSCAPE 0
|
||||
#define LV_DEMO_MUSIC_ROUND 0
|
||||
#define LV_DEMO_MUSIC_LARGE 0
|
||||
#define LV_DEMO_MUSIC_AUTO_PLAY 0
|
||||
#endif
|
||||
|
||||
/*--END OF LV_CONF_H--*/
|
||||
|
||||
#endif /*LV_CONF_H*/
|
@ -0,0 +1,487 @@
|
||||
/**
|
||||
* LVGL display/touch drivers config file for v8.3.0
|
||||
* see lib/lvgl/lv_conf_template.h for initial values
|
||||
*/
|
||||
|
||||
#ifndef LV_DRV_CONF_H
|
||||
#define LV_DRV_CONF_H
|
||||
|
||||
#include "lv_conf.h"
|
||||
|
||||
/*********************
|
||||
* DELAY INTERFACE
|
||||
*********************/
|
||||
#define LV_DRV_DELAY_INCLUDE <stdint.h> /*Dummy include by default*/
|
||||
#define LV_DRV_DELAY_US(us) /*delay_us(us)*/ /*Delay the given number of microseconds*/
|
||||
#define LV_DRV_DELAY_MS(ms) /*delay_ms(ms)*/ /*Delay the given number of milliseconds*/
|
||||
|
||||
/*********************
|
||||
* DISPLAY INTERFACE
|
||||
*********************/
|
||||
|
||||
/*------------
|
||||
* Common
|
||||
*------------*/
|
||||
#define LV_DRV_DISP_INCLUDE <stdint.h> /*Dummy include by default*/
|
||||
#define LV_DRV_DISP_CMD_DATA(val) /*pin_x_set(val)*/ /*Set the command/data pin to 'val'*/
|
||||
#define LV_DRV_DISP_RST(val) /*pin_x_set(val)*/ /*Set the reset pin to 'val'*/
|
||||
|
||||
/*---------
|
||||
* SPI
|
||||
*---------*/
|
||||
#define LV_DRV_DISP_SPI_CS(val) /*spi_cs_set(val)*/ /*Set the SPI's Chip select to 'val'*/
|
||||
#define LV_DRV_DISP_SPI_WR_BYTE(data) /*spi_wr(data)*/ /*Write a byte the SPI bus*/
|
||||
#define LV_DRV_DISP_SPI_WR_ARRAY(adr, n) /*spi_wr_mem(adr, n)*/ /*Write 'n' bytes to SPI bus from 'adr'*/
|
||||
|
||||
/*------------------
|
||||
* Parallel port
|
||||
*-----------------*/
|
||||
#define LV_DRV_DISP_PAR_CS(val) /*par_cs_set(val)*/ /*Set the Parallel port's Chip select to 'val'*/
|
||||
#define LV_DRV_DISP_PAR_SLOW /*par_slow()*/ /*Set low speed on the parallel port*/
|
||||
#define LV_DRV_DISP_PAR_FAST /*par_fast()*/ /*Set high speed on the parallel port*/
|
||||
#define LV_DRV_DISP_PAR_WR_WORD(data) /*par_wr(data)*/ /*Write a word to the parallel port*/
|
||||
#define LV_DRV_DISP_PAR_WR_ARRAY(adr, n) /*par_wr_mem(adr,n)*/ /*Write 'n' bytes to Parallel ports from 'adr'*/
|
||||
|
||||
/***************************
|
||||
* INPUT DEVICE INTERFACE
|
||||
***************************/
|
||||
|
||||
/*----------
|
||||
* Common
|
||||
*----------*/
|
||||
#define LV_DRV_INDEV_INCLUDE <stdint.h> /*Dummy include by default*/
|
||||
#define LV_DRV_INDEV_RST(val) /*pin_x_set(val)*/ /*Set the reset pin to 'val'*/
|
||||
#define LV_DRV_INDEV_IRQ_READ 0 /*pn_x_read()*/ /*Read the IRQ pin*/
|
||||
|
||||
/*---------
|
||||
* SPI
|
||||
*---------*/
|
||||
#define LV_DRV_INDEV_SPI_CS(val) /*spi_cs_set(val)*/ /*Set the SPI's Chip select to 'val'*/
|
||||
#define LV_DRV_INDEV_SPI_XCHG_BYTE(data) 0 /*spi_xchg(val)*/ /*Write 'val' to SPI and give the read value*/
|
||||
|
||||
/*---------
|
||||
* I2C
|
||||
*---------*/
|
||||
#define LV_DRV_INDEV_I2C_START /*i2c_start()*/ /*Make an I2C start*/
|
||||
#define LV_DRV_INDEV_I2C_STOP /*i2c_stop()*/ /*Make an I2C stop*/
|
||||
#define LV_DRV_INDEV_I2C_RESTART /*i2c_restart()*/ /*Make an I2C restart*/
|
||||
#define LV_DRV_INDEV_I2C_WR(data) /*i2c_wr(data)*/ /*Write a byte to the I1C bus*/
|
||||
#define LV_DRV_INDEV_I2C_READ(last_read) 0 /*i2c_rd()*/ /*Read a byte from the I2C bud*/
|
||||
|
||||
|
||||
/*********************
|
||||
* DISPLAY DRIVERS
|
||||
*********************/
|
||||
|
||||
/*-------------------
|
||||
* SDL
|
||||
*-------------------*/
|
||||
|
||||
/* SDL based drivers for display, mouse, mousewheel and keyboard*/
|
||||
#ifndef USE_SDL
|
||||
# define USE_SDL 0
|
||||
#endif
|
||||
|
||||
/* Hardware accelerated SDL driver */
|
||||
#ifndef USE_SDL_GPU
|
||||
# define USE_SDL_GPU 0
|
||||
#endif
|
||||
|
||||
#if USE_SDL || USE_SDL_GPU
|
||||
# define SDL_HOR_RES 800
|
||||
# define SDL_VER_RES 480
|
||||
|
||||
/* Scale window by this factor (useful when simulating small screens) */
|
||||
# define SDL_ZOOM 1
|
||||
|
||||
/* Used to test true double buffering with only address changing.
|
||||
* Use 2 draw buffers, bith with SDL_HOR_RES x SDL_VER_RES size*/
|
||||
# define SDL_DOUBLE_BUFFERED 0
|
||||
|
||||
/*Eclipse: <SDL2/SDL.h> Visual Studio: <SDL.h>*/
|
||||
# define SDL_INCLUDE_PATH <SDL2/SDL.h>
|
||||
|
||||
/*Open two windows to test multi display support*/
|
||||
# define SDL_DUAL_DISPLAY 0
|
||||
#endif
|
||||
|
||||
/*-------------------
|
||||
* Monitor of PC
|
||||
*-------------------*/
|
||||
|
||||
/*DEPRECATED: Use the SDL driver instead. */
|
||||
#ifndef USE_MONITOR
|
||||
# define USE_MONITOR 0
|
||||
#endif
|
||||
|
||||
#if USE_MONITOR
|
||||
# define MONITOR_HOR_RES 480
|
||||
# define MONITOR_VER_RES 320
|
||||
|
||||
/* Scale window by this factor (useful when simulating small screens) */
|
||||
# define MONITOR_ZOOM 1
|
||||
|
||||
/* Used to test true double buffering with only address changing.
|
||||
* Use 2 draw buffers, bith with MONITOR_HOR_RES x MONITOR_VER_RES size*/
|
||||
# define MONITOR_DOUBLE_BUFFERED 0
|
||||
|
||||
/*Eclipse: <SDL2/SDL.h> Visual Studio: <SDL.h>*/
|
||||
# define MONITOR_SDL_INCLUDE_PATH <SDL2/SDL.h>
|
||||
|
||||
/*Open two windows to test multi display support*/
|
||||
# define MONITOR_DUAL 0
|
||||
#endif
|
||||
|
||||
/*-----------------------------------
|
||||
* Native Windows (including mouse)
|
||||
*----------------------------------*/
|
||||
#ifndef USE_WINDOWS
|
||||
# define USE_WINDOWS 0
|
||||
#endif
|
||||
|
||||
#if USE_WINDOWS
|
||||
# define WINDOW_HOR_RES 480
|
||||
# define WINDOW_VER_RES 320
|
||||
#endif
|
||||
|
||||
/*----------------------------
|
||||
* Native Windows (win32drv)
|
||||
*---------------------------*/
|
||||
#ifndef USE_WIN32DRV
|
||||
# define USE_WIN32DRV 0
|
||||
#endif
|
||||
|
||||
#if USE_WIN32DRV
|
||||
/* Scale window by this factor (useful when simulating small screens) */
|
||||
# define WIN32DRV_MONITOR_ZOOM 1
|
||||
#endif
|
||||
|
||||
/*----------------------------------------
|
||||
* GTK drivers (monitor, mouse, keyboard
|
||||
*---------------------------------------*/
|
||||
#ifndef USE_GTK
|
||||
# define USE_GTK 0
|
||||
#endif
|
||||
|
||||
/*----------------------------------------
|
||||
* Wayland drivers (monitor, mouse, keyboard, touchscreen)
|
||||
*---------------------------------------*/
|
||||
#ifndef USE_WAYLAND
|
||||
# define USE_WAYLAND 0
|
||||
#endif
|
||||
|
||||
#if USE_WAYLAND
|
||||
/* Support for client-side decorations */
|
||||
# ifndef LV_WAYLAND_CLIENT_SIDE_DECORATIONS
|
||||
# define LV_WAYLAND_CLIENT_SIDE_DECORATIONS 1
|
||||
# endif
|
||||
/* Support for (deprecated) wl-shell protocol */
|
||||
# ifndef LV_WAYLAND_WL_SHELL
|
||||
# define LV_WAYLAND_WL_SHELL 1
|
||||
# endif
|
||||
/* Support for xdg-shell protocol */
|
||||
# ifndef LV_WAYLAND_XDG_SHELL
|
||||
# define LV_WAYLAND_XDG_SHELL 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*----------------
|
||||
* SSD1963
|
||||
*--------------*/
|
||||
#ifndef USE_SSD1963
|
||||
# define USE_SSD1963 0
|
||||
#endif
|
||||
|
||||
#if USE_SSD1963
|
||||
# define SSD1963_HOR_RES LV_HOR_RES
|
||||
# define SSD1963_VER_RES LV_VER_RES
|
||||
# define SSD1963_HT 531
|
||||
# define SSD1963_HPS 43
|
||||
# define SSD1963_LPS 8
|
||||
# define SSD1963_HPW 10
|
||||
# define SSD1963_VT 288
|
||||
# define SSD1963_VPS 12
|
||||
# define SSD1963_FPS 4
|
||||
# define SSD1963_VPW 10
|
||||
# define SSD1963_HS_NEG 0 /*Negative hsync*/
|
||||
# define SSD1963_VS_NEG 0 /*Negative vsync*/
|
||||
# define SSD1963_ORI 0 /*0, 90, 180, 270*/
|
||||
# define SSD1963_COLOR_DEPTH 16
|
||||
#endif
|
||||
|
||||
/*----------------
|
||||
* R61581
|
||||
*--------------*/
|
||||
#ifndef USE_R61581
|
||||
# define USE_R61581 0
|
||||
#endif
|
||||
|
||||
#if USE_R61581
|
||||
# define R61581_HOR_RES LV_HOR_RES
|
||||
# define R61581_VER_RES LV_VER_RES
|
||||
# define R61581_HSPL 0 /*HSYNC signal polarity*/
|
||||
# define R61581_HSL 10 /*HSYNC length (Not Implemented)*/
|
||||
# define R61581_HFP 10 /*Horitontal Front poarch (Not Implemented)*/
|
||||
# define R61581_HBP 10 /*Horitontal Back poarch (Not Implemented */
|
||||
# define R61581_VSPL 0 /*VSYNC signal polarity*/
|
||||
# define R61581_VSL 10 /*VSYNC length (Not Implemented)*/
|
||||
# define R61581_VFP 8 /*Vertical Front poarch*/
|
||||
# define R61581_VBP 8 /*Vertical Back poarch */
|
||||
# define R61581_DPL 0 /*DCLK signal polarity*/
|
||||
# define R61581_EPL 1 /*ENABLE signal polarity*/
|
||||
# define R61581_ORI 0 /*0, 180*/
|
||||
# define R61581_LV_COLOR_DEPTH 16 /*Fix 16 bit*/
|
||||
#endif
|
||||
|
||||
/*------------------------------
|
||||
* ST7565 (Monochrome, low res.)
|
||||
*-----------------------------*/
|
||||
#ifndef USE_ST7565
|
||||
# define USE_ST7565 0
|
||||
#endif
|
||||
|
||||
#if USE_ST7565
|
||||
/*No settings*/
|
||||
#endif /*USE_ST7565*/
|
||||
|
||||
/*------------------------------
|
||||
* GC9A01 (color, low res.)
|
||||
*-----------------------------*/
|
||||
#ifndef USE_GC9A01
|
||||
# define USE_GC9A01 0
|
||||
#endif
|
||||
|
||||
#if USE_GC9A01
|
||||
/*No settings*/
|
||||
#endif /*USE_GC9A01*/
|
||||
|
||||
/*------------------------------------------
|
||||
* UC1610 (4 gray 160*[104|128])
|
||||
* (EA DOGXL160 160x104 tested)
|
||||
*-----------------------------------------*/
|
||||
#ifndef USE_UC1610
|
||||
# define USE_UC1610 0
|
||||
#endif
|
||||
|
||||
#if USE_UC1610
|
||||
# define UC1610_HOR_RES LV_HOR_RES
|
||||
# define UC1610_VER_RES LV_VER_RES
|
||||
# define UC1610_INIT_CONTRAST 33 /* init contrast, values in [%] */
|
||||
# define UC1610_INIT_HARD_RST 0 /* 1 : hardware reset at init, 0 : software reset */
|
||||
# define UC1610_TOP_VIEW 0 /* 0 : Bottom View, 1 : Top View */
|
||||
#endif /*USE_UC1610*/
|
||||
|
||||
/*-------------------------------------------------
|
||||
* SHARP memory in pixel monochrome display series
|
||||
* LS012B7DD01 (184x38 pixels.)
|
||||
* LS013B7DH03 (128x128 pixels.)
|
||||
* LS013B7DH05 (144x168 pixels.)
|
||||
* LS027B7DH01 (400x240 pixels.) (tested)
|
||||
* LS032B7DD02 (336x536 pixels.)
|
||||
* LS044Q7DH01 (320x240 pixels.)
|
||||
*------------------------------------------------*/
|
||||
#ifndef USE_SHARP_MIP
|
||||
# define USE_SHARP_MIP 0
|
||||
#endif
|
||||
|
||||
#if USE_SHARP_MIP
|
||||
# define SHARP_MIP_HOR_RES LV_HOR_RES
|
||||
# define SHARP_MIP_VER_RES LV_VER_RES
|
||||
# define SHARP_MIP_SOFT_COM_INVERSION 0
|
||||
# define SHARP_MIP_REV_BYTE(b) /*((uint8_t) __REV(__RBIT(b)))*/ /*Architecture / compiler dependent byte bits order reverse*/
|
||||
#endif /*USE_SHARP_MIP*/
|
||||
|
||||
/*-------------------------------------------------
|
||||
* ILI9341 240X320 TFT LCD
|
||||
*------------------------------------------------*/
|
||||
#ifndef USE_ILI9341
|
||||
# define USE_ILI9341 0
|
||||
#endif
|
||||
|
||||
#if USE_ILI9341
|
||||
# define ILI9341_HOR_RES LV_HOR_RES
|
||||
# define ILI9341_VER_RES LV_VER_RES
|
||||
# define ILI9341_GAMMA 1
|
||||
# define ILI9341_TEARING 0
|
||||
#endif /*USE_ILI9341*/
|
||||
|
||||
/*-----------------------------------------
|
||||
* Linux frame buffer device (/dev/fbx)
|
||||
*-----------------------------------------*/
|
||||
#ifndef USE_FBDEV
|
||||
# define USE_FBDEV 0
|
||||
#endif
|
||||
|
||||
#if USE_FBDEV
|
||||
# define FBDEV_PATH "/dev/fb0"
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------
|
||||
* FreeBSD frame buffer device (/dev/fbx)
|
||||
*.........................................*/
|
||||
#ifndef USE_BSD_FBDEV
|
||||
# define USE_BSD_FBDEV 0
|
||||
#endif
|
||||
|
||||
#if USE_BSD_FBDEV
|
||||
# define FBDEV_PATH "/dev/fb0"
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------
|
||||
* DRM/KMS device (/dev/dri/cardX)
|
||||
*-----------------------------------------*/
|
||||
// TODO: consider switching to DRM?
|
||||
// see https://forum.lvgl.io/t/drm-driver-is-slow/3479
|
||||
#ifndef USE_DRM
|
||||
# define USE_DRM 0
|
||||
#endif
|
||||
|
||||
#if USE_DRM
|
||||
# define DRM_CARD "/dev/dri/card0"
|
||||
# define DRM_CONNECTOR_ID -1 /* -1 for the first connected one */
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INPUT DEVICES
|
||||
*********************/
|
||||
|
||||
/*--------------
|
||||
* XPT2046
|
||||
*--------------*/
|
||||
#ifndef USE_XPT2046
|
||||
# define USE_XPT2046 0
|
||||
#endif
|
||||
|
||||
#if USE_XPT2046
|
||||
# define XPT2046_HOR_RES 480
|
||||
# define XPT2046_VER_RES 320
|
||||
# define XPT2046_X_MIN 200
|
||||
# define XPT2046_Y_MIN 200
|
||||
# define XPT2046_X_MAX 3800
|
||||
# define XPT2046_Y_MAX 3800
|
||||
# define XPT2046_AVG 4
|
||||
# define XPT2046_X_INV 0
|
||||
# define XPT2046_Y_INV 0
|
||||
# define XPT2046_XY_SWAP 0
|
||||
#endif
|
||||
|
||||
/*-----------------
|
||||
* FT5406EE8
|
||||
*-----------------*/
|
||||
#ifndef USE_FT5406EE8
|
||||
# define USE_FT5406EE8 0
|
||||
#endif
|
||||
|
||||
#if USE_FT5406EE8
|
||||
# define FT5406EE8_I2C_ADR 0x38 /*7 bit address*/
|
||||
#endif
|
||||
|
||||
/*---------------
|
||||
* AD TOUCH
|
||||
*--------------*/
|
||||
#ifndef USE_AD_TOUCH
|
||||
# define USE_AD_TOUCH 0
|
||||
#endif
|
||||
|
||||
#if USE_AD_TOUCH
|
||||
/*No settings*/
|
||||
#endif
|
||||
|
||||
|
||||
/*---------------------------------------
|
||||
* Mouse or touchpad on PC (using SDL)
|
||||
*-------------------------------------*/
|
||||
/*DEPRECATED: Use the SDL driver instead. */
|
||||
#ifndef USE_MOUSE
|
||||
# define USE_MOUSE 0
|
||||
#endif
|
||||
|
||||
#if USE_MOUSE
|
||||
/*No settings*/
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------
|
||||
* Mousewheel as encoder on PC (using SDL)
|
||||
*------------------------------------------*/
|
||||
/*DEPRECATED: Use the SDL driver instead. */
|
||||
#ifndef USE_MOUSEWHEEL
|
||||
# define USE_MOUSEWHEEL 0
|
||||
#endif
|
||||
|
||||
#if USE_MOUSEWHEEL
|
||||
/*No settings*/
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------
|
||||
* Touchscreen, mouse/touchpad or keyboard as libinput interface (for Linux based systems)
|
||||
*------------------------------------------------*/
|
||||
#ifndef USE_LIBINPUT
|
||||
# define USE_LIBINPUT 0
|
||||
#endif
|
||||
|
||||
#ifndef USE_BSD_LIBINPUT
|
||||
# define USE_BSD_LIBINPUT 0
|
||||
#endif
|
||||
|
||||
#if USE_LIBINPUT || USE_BSD_LIBINPUT
|
||||
/*If only a single device of the same type is connected, you can also auto detect it, e.g.:
|
||||
*#define LIBINPUT_NAME libinput_find_dev(LIBINPUT_CAPABILITY_TOUCH, false)*/
|
||||
# define LIBINPUT_NAME "/dev/input/event0" /*You can use the "evtest" Linux tool to get the list of devices and test them*/
|
||||
|
||||
#endif /*USE_LIBINPUT || USE_BSD_LIBINPUT*/
|
||||
|
||||
/*-------------------------------------------------
|
||||
* Mouse or touchpad as evdev interface (for Linux based systems)
|
||||
*------------------------------------------------*/
|
||||
#ifndef USE_EVDEV
|
||||
# define USE_EVDEV 0
|
||||
#endif
|
||||
|
||||
#ifndef USE_BSD_EVDEV
|
||||
# define USE_BSD_EVDEV 0
|
||||
#endif
|
||||
|
||||
#if USE_EVDEV || USE_BSD_EVDEV
|
||||
# define EVDEV_NAME "/dev/input/event0" /*You can use the "evtest" Linux tool to get the list of devices and test them*/
|
||||
# define EVDEV_SWAP_AXES 0 /*Swap the x and y axes of the touchscreen*/
|
||||
|
||||
# define EVDEV_CALIBRATE 0 /*Scale and offset the touchscreen coordinates by using maximum and minimum values for each axis*/
|
||||
|
||||
# if EVDEV_CALIBRATE
|
||||
# define EVDEV_HOR_MIN 0 /*to invert axis swap EVDEV_XXX_MIN by EVDEV_XXX_MAX*/
|
||||
# define EVDEV_HOR_MAX 4096 /*"evtest" Linux tool can help to get the correct calibraion values>*/
|
||||
# define EVDEV_VER_MIN 0
|
||||
# define EVDEV_VER_MAX 4096
|
||||
# endif /*EVDEV_CALIBRATE*/
|
||||
#endif /*USE_EVDEV*/
|
||||
|
||||
/*-------------------------------------------------
|
||||
* Full keyboard support for evdev and libinput interface
|
||||
*------------------------------------------------*/
|
||||
# ifndef USE_XKB
|
||||
# define USE_XKB 0
|
||||
# endif
|
||||
|
||||
#if USE_LIBINPUT || USE_BSD_LIBINPUT || USE_EVDEV || USE_BSD_EVDEV
|
||||
# if USE_XKB
|
||||
# define XKB_KEY_MAP { .rules = NULL, \
|
||||
.model = "pc101", \
|
||||
.layout = "us", \
|
||||
.variant = NULL, \
|
||||
.options = NULL } /*"setxkbmap -query" can help find the right values for your keyboard*/
|
||||
# endif /*USE_XKB*/
|
||||
#endif /*USE_LIBINPUT || USE_BSD_LIBINPUT || USE_EVDEV || USE_BSD_EVDEV*/
|
||||
|
||||
/*-------------------------------
|
||||
* Keyboard of a PC (using SDL)
|
||||
*------------------------------*/
|
||||
/*DEPRECATED: Use the SDL driver instead. */
|
||||
#ifndef USE_KEYBOARD
|
||||
# define USE_KEYBOARD 0
|
||||
#endif
|
||||
|
||||
#if USE_KEYBOARD
|
||||
/*No settings*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRV_CONF_H*/
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,327 @@
|
||||
#define _DEFAULT_SOURCE /* needed for usleep() */
|
||||
|
||||
#include "lvgl/lvgl.h"
|
||||
|
||||
#include "ui.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
lv_disp_t* drv_init(void);
|
||||
|
||||
static lv_style_t style_title;
|
||||
static lv_style_t style_text_muted;
|
||||
static lv_style_t style_btn_red;
|
||||
static const lv_font_t* font_large;
|
||||
static lv_obj_t* virt_keyboard;
|
||||
static lv_obj_t* tabview; /* main tabs content parent; lv_tabview_create */
|
||||
|
||||
static void textarea_event_cb(lv_event_t* e)
|
||||
{
|
||||
lv_obj_t* textarea = lv_event_get_target(e);
|
||||
lv_event_code_t code = lv_event_get_code(e);
|
||||
if (code == LV_EVENT_FOCUSED) {
|
||||
if (lv_indev_get_type(lv_indev_get_act()) != LV_INDEV_TYPE_KEYPAD) {
|
||||
lv_keyboard_set_textarea(virt_keyboard, textarea);
|
||||
lv_obj_set_style_max_height(virt_keyboard, NM_DISP_HOR * 2 / 3, 0);
|
||||
lv_obj_update_layout(tabview); /* make sure sizes are recalculated */
|
||||
lv_obj_set_height(tabview, NM_DISP_VER - lv_obj_get_height(virt_keyboard));
|
||||
lv_obj_clear_flag(virt_keyboard, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_scroll_to_view_recursive(textarea, LV_ANIM_OFF);
|
||||
}
|
||||
} else if (code == LV_EVENT_DEFOCUSED) {
|
||||
lv_keyboard_set_textarea(virt_keyboard, NULL);
|
||||
lv_obj_set_height(tabview, NM_DISP_VER);
|
||||
lv_obj_add_flag(virt_keyboard, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_indev_reset(NULL, textarea);
|
||||
} else if (code == LV_EVENT_READY || code == LV_EVENT_CANCEL) {
|
||||
lv_obj_set_height(tabview, NM_DISP_VER);
|
||||
lv_obj_add_flag(virt_keyboard, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_clear_state(textarea, LV_STATE_FOCUSED);
|
||||
lv_indev_reset(NULL, textarea); /* forget the last clicked object to make it focusable again */
|
||||
}
|
||||
}
|
||||
|
||||
static void create_bitcoin_panel(lv_obj_t* parent)
|
||||
{
|
||||
lv_obj_t* label = lv_label_create(parent);
|
||||
lv_label_set_text_static(label, "bitcoin tab isn't designed yet\nfollow https://nakamochi.io");
|
||||
lv_obj_center(label);
|
||||
}
|
||||
|
||||
static void create_lnd_panel(lv_obj_t* parent)
|
||||
{
|
||||
lv_obj_t* label = lv_label_create(parent);
|
||||
lv_label_set_text_static(label, "lightning tab isn't designed yet\nfollow https://nakamochi.io");
|
||||
lv_obj_center(label);
|
||||
}
|
||||
|
||||
static struct {
|
||||
lv_obj_t* wifi_spinner_obj; /* lv_spinner_create */
|
||||
lv_obj_t* wifi_status_obj; /* lv_label_create */
|
||||
lv_obj_t* wifi_connect_btn_obj; /* lv_btn_create */
|
||||
lv_obj_t* wifi_ssid_list_obj; /* lv_dropdown_create */
|
||||
lv_obj_t* wifi_pwd_obj; /* lv_textarea_create */
|
||||
lv_obj_t* power_halt_btn_obj; /* lv_btn_create */
|
||||
} settings;
|
||||
|
||||
/**
|
||||
* update the UI with network connection info, placing text into wifi_status_obj as is.
|
||||
* wifi_list is optional; items must be delimited by '\n' if non-null.
|
||||
* args are alloc-copied and owned by lvgl.
|
||||
*/
|
||||
extern void ui_update_network_status(const char *text, const char *wifi_list)
|
||||
{
|
||||
if (wifi_list) {
|
||||
lv_dropdown_set_options(settings.wifi_ssid_list_obj, wifi_list);
|
||||
}
|
||||
lv_obj_clear_state(settings.wifi_connect_btn_obj, LV_STATE_DISABLED);
|
||||
lv_obj_add_flag(settings.wifi_spinner_obj, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_label_set_text(settings.wifi_status_obj, text);
|
||||
}
|
||||
|
||||
static void wifi_connect_btn_callback(lv_event_t* e)
|
||||
{
|
||||
(void)e; /* unused */
|
||||
lv_obj_add_state(settings.wifi_connect_btn_obj, LV_STATE_DISABLED);
|
||||
lv_obj_clear_flag(settings.wifi_spinner_obj, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_label_set_text(settings.wifi_status_obj, "connecting ...");
|
||||
|
||||
char buf[100];
|
||||
lv_dropdown_get_selected_str(settings.wifi_ssid_list_obj, buf, sizeof(buf));
|
||||
nm_wifi_start_connect(buf, lv_textarea_get_text(settings.wifi_pwd_obj));
|
||||
}
|
||||
|
||||
static void power_halt_btn_callback(lv_event_t *e)
|
||||
{
|
||||
if (e->user_data) { /* ptr to msgbox */
|
||||
lv_obj_t *msgbox = e->user_data;
|
||||
/* first button is "proceed", do shutdown */
|
||||
if (lv_msgbox_get_active_btn(msgbox) == 0) {
|
||||
/* shutdown confirmed */
|
||||
nm_sys_shutdown();
|
||||
}
|
||||
/* shutdown aborted or passthrough from confirmed shutdown.
|
||||
* in the latter case, ui is still running for a brief moment,
|
||||
* until ngui terminates. */
|
||||
lv_msgbox_close(msgbox);
|
||||
return;
|
||||
}
|
||||
|
||||
/* first button must always be a "proceed", do shutdown;
|
||||
* text is irrelevant */
|
||||
static const char *btns[] = {"PROCEED", "ABORT", NULL};
|
||||
lv_obj_t *msgbox = lv_msgbox_create(
|
||||
NULL /* modal */,
|
||||
"SHUTDOWN", /* title */
|
||||
"are you sure?", /* text */
|
||||
btns,
|
||||
false /* close btn */);
|
||||
lv_obj_center(msgbox);
|
||||
lv_obj_add_event_cb(msgbox, power_halt_btn_callback, LV_EVENT_VALUE_CHANGED, msgbox);
|
||||
return;
|
||||
}
|
||||
|
||||
static void create_settings_panel(lv_obj_t* parent)
|
||||
{
|
||||
/********************
|
||||
* wifi panel
|
||||
********************/
|
||||
lv_obj_t* wifi_panel = lv_obj_create(parent);
|
||||
lv_obj_set_height(wifi_panel, LV_SIZE_CONTENT);
|
||||
lv_obj_t * wifi_panel_title = lv_label_create(wifi_panel);
|
||||
lv_label_set_text_static(wifi_panel_title, LV_SYMBOL_WIFI " WIFI");
|
||||
lv_obj_add_style(wifi_panel_title, &style_title, 0);
|
||||
|
||||
lv_obj_t* wifi_spinner = lv_spinner_create(wifi_panel, 1000 /* speed */, 60 /* arc in deg */);
|
||||
settings.wifi_spinner_obj = wifi_spinner;
|
||||
lv_obj_add_flag(wifi_spinner, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_set_size(wifi_spinner, 20, 20);
|
||||
lv_obj_set_style_arc_width(wifi_spinner, 4, LV_PART_INDICATOR);
|
||||
|
||||
lv_obj_t* wifi_status = lv_label_create(wifi_panel);
|
||||
settings.wifi_status_obj = wifi_status;
|
||||
lv_label_set_text_static(wifi_status, "unknown status");
|
||||
lv_label_set_long_mode(wifi_status, LV_LABEL_LONG_WRAP);
|
||||
lv_obj_set_height(wifi_status, LV_SIZE_CONTENT);
|
||||
lv_label_set_recolor(wifi_status, true);
|
||||
|
||||
lv_obj_t* wifi_ssid_label = lv_label_create(wifi_panel);
|
||||
lv_label_set_text_static(wifi_ssid_label, "network name");
|
||||
lv_obj_add_style(wifi_ssid_label, &style_text_muted, 0);
|
||||
lv_obj_t* wifi_ssid = lv_dropdown_create(wifi_panel);
|
||||
settings.wifi_ssid_list_obj = wifi_ssid;
|
||||
lv_dropdown_clear_options(wifi_ssid);
|
||||
|
||||
lv_obj_t* wifi_pwd_label = lv_label_create(wifi_panel);
|
||||
lv_label_set_text_static(wifi_pwd_label, "password");
|
||||
lv_obj_add_style(wifi_pwd_label, &style_text_muted, 0);
|
||||
lv_obj_t* wifi_pwd = lv_textarea_create(wifi_panel);
|
||||
settings.wifi_pwd_obj = wifi_pwd;
|
||||
lv_textarea_set_one_line(wifi_pwd, true);
|
||||
lv_textarea_set_password_mode(wifi_pwd, true);
|
||||
lv_obj_add_event_cb(wifi_pwd, textarea_event_cb, LV_EVENT_ALL, NULL);
|
||||
|
||||
lv_obj_t* wifi_connect_btn = lv_btn_create(wifi_panel);
|
||||
settings.wifi_connect_btn_obj = wifi_connect_btn;
|
||||
lv_obj_set_height(wifi_connect_btn, LV_SIZE_CONTENT);
|
||||
lv_obj_add_event_cb(wifi_connect_btn, wifi_connect_btn_callback, LV_EVENT_CLICKED, NULL);
|
||||
lv_obj_t* wifi_connect_btn_label = lv_label_create(wifi_connect_btn);
|
||||
lv_label_set_text_static(wifi_connect_btn_label, "CONNECT");
|
||||
lv_obj_center(wifi_connect_btn_label);
|
||||
|
||||
/********************
|
||||
* power panel
|
||||
********************/
|
||||
lv_obj_t* power_panel = lv_obj_create(parent);
|
||||
lv_obj_set_height(power_panel, LV_SIZE_CONTENT);
|
||||
lv_obj_t * power_panel_title = lv_label_create(power_panel);
|
||||
lv_label_set_text_static(power_panel_title, LV_SYMBOL_POWER " POWER");
|
||||
lv_obj_add_style(power_panel_title, &style_title, 0);
|
||||
|
||||
lv_obj_t* poweroff_text = lv_label_create(power_panel);
|
||||
lv_label_set_text_static(poweroff_text, "once shut down, the power cord\ncan be removed.");
|
||||
lv_label_set_long_mode(poweroff_text, LV_LABEL_LONG_WRAP);
|
||||
lv_obj_set_height(poweroff_text, LV_SIZE_CONTENT);
|
||||
lv_label_set_recolor(poweroff_text, true);
|
||||
|
||||
lv_obj_t* power_halt_btn = lv_btn_create(power_panel);
|
||||
settings.power_halt_btn_obj = power_halt_btn;
|
||||
lv_obj_set_height(power_halt_btn, LV_SIZE_CONTENT);
|
||||
lv_obj_add_style(power_halt_btn, &style_btn_red, 0);
|
||||
lv_obj_add_event_cb(power_halt_btn, power_halt_btn_callback, LV_EVENT_CLICKED, NULL);
|
||||
lv_obj_t* power_halt_btn_label = lv_label_create(power_halt_btn);
|
||||
lv_label_set_text_static(power_halt_btn_label, "SHUTDOWN");
|
||||
lv_obj_center(power_halt_btn_label);
|
||||
|
||||
/********************
|
||||
* layout
|
||||
********************/
|
||||
static lv_coord_t parent_grid_cols[] = {LV_GRID_FR(1), LV_GRID_TEMPLATE_LAST};
|
||||
static lv_coord_t parent_grid_rows[] = {
|
||||
LV_GRID_CONTENT, /* wifi panel */
|
||||
LV_GRID_CONTENT, /* power panel */
|
||||
LV_GRID_TEMPLATE_LAST
|
||||
};
|
||||
lv_obj_set_grid_dsc_array(parent, parent_grid_cols, parent_grid_rows);
|
||||
lv_obj_set_grid_cell(wifi_panel, LV_GRID_ALIGN_STRETCH, 0, 1, LV_GRID_ALIGN_CENTER, 0, 1);
|
||||
lv_obj_set_grid_cell(power_panel, LV_GRID_ALIGN_STRETCH, 0, 1, LV_GRID_ALIGN_CENTER, 1, 1);
|
||||
|
||||
static lv_coord_t wifi_grid_cols[] = {LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_TEMPLATE_LAST};
|
||||
static lv_coord_t wifi_grid_rows[] = {
|
||||
LV_GRID_CONTENT, /* title */
|
||||
5, /* separator */
|
||||
LV_GRID_CONTENT, /* wifi status text */
|
||||
30, /* wifi selector */
|
||||
5, /* separator */
|
||||
LV_GRID_CONTENT, /* password label */
|
||||
30, /* password input */
|
||||
5, /* separator */
|
||||
LV_GRID_CONTENT, /* connect btn */
|
||||
LV_GRID_TEMPLATE_LAST
|
||||
};
|
||||
lv_obj_set_grid_dsc_array(wifi_panel, wifi_grid_cols, wifi_grid_rows);
|
||||
lv_obj_set_grid_cell(wifi_panel_title, LV_GRID_ALIGN_STRETCH, 0, 1, LV_GRID_ALIGN_CENTER, 0, 1);
|
||||
lv_obj_set_grid_cell(wifi_spinner, LV_GRID_ALIGN_END, 1, 1, LV_GRID_ALIGN_CENTER, 0, 1);
|
||||
/* column 0 */
|
||||
lv_obj_set_grid_cell(wifi_status, LV_GRID_ALIGN_START, 0, 1, LV_GRID_ALIGN_START, 2, 7);
|
||||
/* column 1 */
|
||||
lv_obj_set_grid_cell(wifi_ssid_label, LV_GRID_ALIGN_START, 1, 1, LV_GRID_ALIGN_START, 2, 1);
|
||||
lv_obj_set_grid_cell(wifi_ssid, LV_GRID_ALIGN_STRETCH, 1, 1, LV_GRID_ALIGN_CENTER, 3, 1);
|
||||
lv_obj_set_grid_cell(wifi_pwd_label, LV_GRID_ALIGN_START, 1, 1, LV_GRID_ALIGN_START, 5, 1);
|
||||
lv_obj_set_grid_cell(wifi_pwd, LV_GRID_ALIGN_STRETCH, 1, 1, LV_GRID_ALIGN_CENTER, 6, 1);
|
||||
lv_obj_set_grid_cell(wifi_connect_btn, LV_GRID_ALIGN_STRETCH, 1, 1, LV_GRID_ALIGN_CENTER, 8, 1);
|
||||
|
||||
static lv_coord_t power_grid_cols[] = {LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_TEMPLATE_LAST};
|
||||
static lv_coord_t power_grid_rows[] = {
|
||||
LV_GRID_CONTENT, /* title */
|
||||
5, /* separator */
|
||||
LV_GRID_CONTENT, /* power off text and btn*/
|
||||
LV_GRID_TEMPLATE_LAST
|
||||
};
|
||||
lv_obj_set_grid_dsc_array(power_panel, power_grid_cols, power_grid_rows);
|
||||
lv_obj_set_grid_cell(power_panel_title, LV_GRID_ALIGN_STRETCH, 0, 2, LV_GRID_ALIGN_CENTER, 0, 1);
|
||||
/* column 0 */
|
||||
lv_obj_set_grid_cell(poweroff_text, LV_GRID_ALIGN_START, 0, 1, LV_GRID_ALIGN_START, 2, 1);
|
||||
/* column 1 */
|
||||
lv_obj_set_grid_cell(power_halt_btn, LV_GRID_ALIGN_STRETCH, 1, 1, LV_GRID_ALIGN_CENTER, 2, 1);
|
||||
}
|
||||
|
||||
static void tab_changed_event_cb(lv_event_t* e)
|
||||
{
|
||||
(void)e; /* unused */
|
||||
uint16_t n = lv_tabview_get_tab_act(tabview);
|
||||
switch (n) {
|
||||
case 2:
|
||||
nm_tab_settings_active();
|
||||
break;
|
||||
default:
|
||||
LV_LOG_INFO("unhandled tab index %i", n);
|
||||
}
|
||||
}
|
||||
|
||||
extern int ui_init()
|
||||
{
|
||||
lv_init();
|
||||
lv_disp_t* disp = drv_init();
|
||||
if (disp == NULL) {
|
||||
return -1;
|
||||
}
|
||||
/* default theme is static */
|
||||
lv_theme_t* theme = lv_theme_default_init(
|
||||
disp,
|
||||
lv_palette_main(LV_PALETTE_BLUE), /* primary */
|
||||
lv_palette_main(LV_PALETTE_RED), /* secondary */
|
||||
true /*LV_THEME_DEFAULT_DARK*/,
|
||||
LV_FONT_DEFAULT);
|
||||
lv_disp_set_theme(disp, theme);
|
||||
|
||||
font_large = &lv_font_courierprimecode_24; /* static */
|
||||
lv_style_init(&style_title);
|
||||
lv_style_set_text_font(&style_title, font_large);
|
||||
|
||||
lv_style_init(&style_text_muted);
|
||||
lv_style_set_text_opa(&style_text_muted, LV_OPA_50);
|
||||
|
||||
lv_style_init(&style_btn_red);
|
||||
lv_style_set_bg_color(&style_btn_red, lv_palette_main(LV_PALETTE_RED));
|
||||
|
||||
/* global virtual keyboard */
|
||||
virt_keyboard = lv_keyboard_create(lv_scr_act());
|
||||
if (virt_keyboard == NULL) {
|
||||
/* TODO: or continue without keyboard? */
|
||||
return -1;
|
||||
}
|
||||
lv_obj_add_flag(virt_keyboard, LV_OBJ_FLAG_HIDDEN);
|
||||
|
||||
const lv_coord_t tabh = 60;
|
||||
tabview = lv_tabview_create(lv_scr_act(), LV_DIR_TOP, tabh);
|
||||
if (tabview == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* tab_changed_event_cb relies on the specific tab order, 0-based index:
|
||||
* 0: bitcoin
|
||||
* 1: lightning
|
||||
* 2: settings
|
||||
*/
|
||||
lv_obj_t* tab_btc = lv_tabview_add_tab(tabview, NM_SYMBOL_BITCOIN " BITCOIN");
|
||||
if (tab_btc == NULL) {
|
||||
return -1;
|
||||
}
|
||||
create_bitcoin_panel(tab_btc);
|
||||
lv_obj_t* tab_lnd = lv_tabview_add_tab(tabview, NM_SYMBOL_BOLT " LIGHTNING");
|
||||
if (tab_lnd == NULL) {
|
||||
return -1;
|
||||
}
|
||||
create_lnd_panel(tab_lnd);
|
||||
lv_obj_t* tab_settings = lv_tabview_add_tab(tabview, LV_SYMBOL_SETTINGS " SETTINGS");
|
||||
if (tab_settings == NULL) {
|
||||
return -1;
|
||||
}
|
||||
create_settings_panel(tab_settings);
|
||||
|
||||
lv_obj_add_event_cb(tabview, tab_changed_event_cb, LV_EVENT_VALUE_CHANGED, NULL);
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
#ifndef NM_UI_H
|
||||
#define NM_UI_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* returns elapsed time since program start, in ms.
|
||||
* rolls over when overflow occurs.
|
||||
*/
|
||||
uint32_t nm_get_curr_tick();
|
||||
|
||||
/**
|
||||
* initiates system shutdown leading to poweroff.
|
||||
*/
|
||||
void nm_sys_shutdown();
|
||||
|
||||
/**
|
||||
* invoken when the UI is switched to the network settings tab.
|
||||
*/
|
||||
void nm_tab_settings_active();
|
||||
|
||||
/**
|
||||
* initiate connection to a wifi network with the given SSID and a password.
|
||||
* connection, if successful, is persisted in wpa_supplicant config.
|
||||
*/
|
||||
int nm_wifi_start_connect(const char* ssid, const char* password);
|
||||
|
||||
#endif
|
@ -0,0 +1,3 @@
|
||||
///! see lv_symbols_def.h
|
||||
pub const Warning = &[_]u8{ 0xef, 0x81, 0xb1 };
|
||||
pub const Ok = &[_]u8{ 0xef, 0x80, 0x8c };
|
Reference in New Issue