chapter 03-03

資料的存取 (核心端程式)

此章節說明核心程式如何透過提供的介面存取資料.


Makefile 的編譯參數 :
# 路徑設定.
MCM_PATH       = mint_cm
MCM_LKLIB_PATH = $(MCM_PATH)/mcm_lib/mcm_lklib


# 標頭檔路徑.
INCLUDE_PATH = -I$(MCM_PATH)

# 導出符號路徑.
export KBUILD_EXTRA_SYMBOLS = $(MCM_LKLIB_PATH)/Module.symvers

MintCM 的核心端函式庫在 mint_cm/mcm_lib/mcm_lklib.
程式使用前必須先將 mcm_lklib_api.ko 載入到核心 (insmod).

需要的標頭檔 :
#include "mcm_lib/mcm_lheader/mcm_type.h"
#include "mcm_lib/mcm_lheader/mcm_size.h"
#include "mcm_lib/mcm_lheader/mcm_connect.h"
#include "mcm_lib/mcm_lheader/mcm_return.h"
#include "mcm_lib/mcm_lheader/mcm_data_exinfo_auto.h"
#include "mcm_lib/mcm_lklib/mcm_lklib_api.h"



變數格式的說明

這邊先說明使用 mcm_lklib_api.ko 提供的函式的變數的用途和格式.


使用的資料模型範例, 參考 #02-02#.


[struct mcm_lklib_lib_t *this_lklib]
用來儲存 mcm_lklib_api.ko 使用時需要的資訊.
會用到的結構成員 :
[char *socket_path]
伺服器的位址路徑. [詳細]
[MCM_DTYPE_LIST_TD call_from]
表示是誰要求資料存取. [詳細]
核心端程式使用 MCM_CFROM_KERNEL.
[MCM_DTYPE_LIST_TD session_permission]
表示資料存取的模式. [詳細]
[MCM_DTYPE_USIZE_TD session_stack_size]
伺服器端負責此連線的執行緒的堆疊大小. [詳細]


[char *mask_path]
取得 group 的資訊的路徑. [詳細]


[char *mix_path]
存取多個 entry 的路徑. [詳細]


[char *full_path]
存取的目標 entry 或 member 的路徑. [詳細]


[char *insert_path]
在增加 entry 時, 指定要插入到哪個 entry 之前. [詳細]


存取 member 資料的變數的型態
根據在資料模型中指定的資料類型, 需要使用對應的型態的變數來紀錄. [詳細]


存取 entry 資料的變數的型態
可以當作 struct 來存取, member 是成員變數. [詳細]


可用的函式

範例程式顯示的訊息必須使用系統指令 dmesg 觀看.

mcm_lklib_init
初始化, 發出資料存取請求.
參數 說明
struct mcm_lklib_lib_t *
this_lklib
紀錄 mcm_lklib_api 所需要的資料
需要先設定好會用到的結構成員 :
socket_path [詳細]
call_from [詳細]
session_permission [詳細]
session_stack_size [詳細]
回傳 說明
>= MCM_RCODE_PASS 成功
 < MCM_RCODE_PASS 錯誤

範例 :
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/random.h>
#include "mcm_lib/mcm_lheader/mcm_type.h"
#include "mcm_lib/mcm_lheader/mcm_size.h"
#include "mcm_lib/mcm_lheader/mcm_connect.h"
#include "mcm_lib/mcm_lheader/mcm_return.h"
#include "mcm_lib/mcm_lheader/mcm_data_exinfo_auto.h"
#include "mcm_lib/mcm_lklib/mcm_lklib_api.h"

#define DMSG(msg_fmt, msgs...) \
    printk(KERN_INFO "%s(%04u): " msg_fmt "\n", \
           strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__, __LINE__, ##msgs)

static int __init main_init(
    void)
{
    struct mcm_lklib_lib_t self_lklib;

    self_lklib.socket_path = "@mintcm";
    self_lklib.call_from = MCM_CFROM_KERNEL;
    self_lklib.session_permission = MCM_SPERMISSION_RW;
    self_lklib.session_stack_size = 0;
    if(mcm_lklib_init(&self_lklib) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_init() fail");
        goto FREE_01;
    }

    // 資料存取.
    // ...

FREE_01:
    return 0;
}

static void __exit main_exit(
    void)
{
    return;
}

module_init(main_init);
module_exit(main_exit);

MODULE_LICENSE("GPL");

mcm_lklib_exit
使用完畢, 釋放使用權.
參數 說明
struct mcm_lklib_lib_t *
this_lklib
紀錄 mcm_lklib_api 的資料
回傳 說明
>= MCM_RCODE_PASS 成功

範例 :
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/random.h>
#include "mcm_lib/mcm_lheader/mcm_type.h"
#include "mcm_lib/mcm_lheader/mcm_size.h"
#include "mcm_lib/mcm_lheader/mcm_connect.h"
#include "mcm_lib/mcm_lheader/mcm_return.h"
#include "mcm_lib/mcm_lheader/mcm_data_exinfo_auto.h"
#include "mcm_lib/mcm_lklib/mcm_lklib_api.h"

#define DMSG(msg_fmt, msgs...) \
    printk(KERN_INFO "%s(%04u): " msg_fmt "\n", \
           strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__, __LINE__, ##msgs)

static int __init main_init(
    void)
{
    struct mcm_lklib_lib_t self_lklib;

    self_lklib.socket_path = "@mintcm";
    self_lklib.call_from = MCM_CFROM_KERNEL;
    self_lklib.session_permission = MCM_SPERMISSION_RW;
    self_lklib.session_stack_size = 0;
    if(mcm_lklib_init(&self_lklib) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_init() fail");
        goto FREE_01;
    }

    // 資料存取.
    // ...

    mcm_lklib_exit(&self_lklib);
FREE_01:
    return 0;
}

static void __exit main_exit(
    void)
{
    return;
}

module_init(main_init);
module_exit(main_exit);

MODULE_LICENSE("GPL");

mcm_lklib_get_max_count
取得資料筆數上限, 也就是資料模型中的 $(max) 值.
參數 說明
struct mcm_lklib_lib_t *
this_lklib
紀錄 mcm_lklib_api 所需要的資料
char *
mask_path
目標的路徑 [詳細]
MCM_DTYPE_EK_TD *
count_buf
紀錄資料筆數的緩衝
回傳 說明
>= MCM_RCODE_PASS 成功
 < MCM_RCODE_PASS 錯誤

注意事項 :
01.  資料存取模式可以是 MCM_SPERMISSION_RO 或 MCM_SPERMISSION_RW.

範例 :
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/random.h>
#include "mcm_lib/mcm_lheader/mcm_type.h"
#include "mcm_lib/mcm_lheader/mcm_size.h"
#include "mcm_lib/mcm_lheader/mcm_connect.h"
#include "mcm_lib/mcm_lheader/mcm_return.h"
#include "mcm_lib/mcm_lheader/mcm_data_exinfo_auto.h"
#include "mcm_lib/mcm_lklib/mcm_lklib_api.h"

#define DMSG(msg_fmt, msgs...) \
    printk(KERN_INFO "%s(%04u): " msg_fmt "\n", \
           strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__, __LINE__, ##msgs)

static int __init main_init(
    void)
{
    char *path1;
    struct mcm_lklib_lib_t self_lklib;
    MCM_DTYPE_EK_TD max_count;

    self_lklib.socket_path = "@mintcm";
    self_lklib.call_from = MCM_CFROM_KERNEL;
    self_lklib.session_permission = MCM_SPERMISSION_RO;
    self_lklib.session_stack_size = 0;
    if(mcm_lklib_init(&self_lklib) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_init() fail");
        goto FREE_01;
    }

    // 範例 : 取得 device.system 的資料筆數上限.
    // 路徑 : "device.system"
    path1 = "device.system";
    if(mcm_lklib_get_max_count(&self_lklib, path1, &max_count) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_get_max_count(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[max-count] %s = " MCM_DTYPE_EK_PF, path1, max_count);

    // 範例 : 取得 device.vap.* 的資料筆數上限.
    // 路徑 : "device.vap.*"
    path1 = "device.vap.*";
    if(mcm_lklib_get_max_count(&self_lklib, path1, &max_count) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_get_max_count(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[max-count] %s = " MCM_DTYPE_EK_PF, path1, max_count);

    // 範例 : 取得 device.vap.*.station.* 的資料筆數上限.
    // 路徑 : "device.vap.*.station.*"
    path1 = "device.vap.*.station.*";
    if(mcm_lklib_get_max_count(&self_lklib, path1, &max_count) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_get_max_count(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[max-count] %s = " MCM_DTYPE_EK_PF, path1, max_count);

FREE_02:
    mcm_lklib_exit(&self_lklib);
FREE_01:
    return 0;
}

static void __exit main_exit(
    void)
{
    return;
}

module_init(main_init);
module_exit(main_exit);

MODULE_LICENSE("GPL");


除了上述方式外, 可以使用另一種方式取得 group 的資料筆數上限. [詳細]

範例 :
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/random.h>
#include "mcm_lib/mcm_lheader/mcm_type.h"
#include "mcm_lib/mcm_lheader/mcm_size.h"
#include "mcm_lib/mcm_lheader/mcm_connect.h"
#include "mcm_lib/mcm_lheader/mcm_return.h"
#include "mcm_lib/mcm_lheader/mcm_data_exinfo_auto.h"
#include "mcm_lib/mcm_lklib/mcm_lklib_api.h"

#define DMSG(msg_fmt, msgs...) \
    printk(KERN_INFO "%s(%04u): " msg_fmt "\n", \
           strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__, __LINE__, ##msgs)

static int __init main_init(
    void)
{
    char *path1;

    // 範例 : 取得 device.system 的資料筆數上限.
    // 路徑 : "device.system"
    path1 = "device.system";
    DMSG("[max-count] %s = " MCM_DTYPE_EK_PF, path1, MCM_MCOUNT_DEVICE_SYSTEM_MAX_COUNT);

    // 範例 : 取得 device.vap.* 的資料筆數上限.
    // 路徑 : "device.vap.*"
    path1 = "device.vap.*";
    DMSG("[max-count] %s = " MCM_DTYPE_EK_PF, path1, MCM_MCOUNT_DEVICE_VAP_MAX_COUNT);

    // 範例 : 取得 device.vap.*.station.* 的資料筆數上限.
    // 路徑 : "device.vap.*.station.*"
    path1 = "device.vap.*.station.*";
    DMSG("[max-count] %s = " MCM_DTYPE_EK_PF, path1, MCM_MCOUNT_DEVICE_VAP_STATION_MAX_COUNT);

    return 0;
}

static void __exit main_exit(
    void)
{
    return;
}

module_init(main_init);
module_exit(main_exit);

MODULE_LICENSE("GPL");

mcm_lklib_get_count
取得目前的資料筆數.
參數 說明
struct mcm_lklib_lib_t *
this_lklib
紀錄 mcm_lklib_api 所需要的資料
char *
mix_path
目標的路徑 [詳細]
[index / key 模式]
MCM_DTYPE_EK_TD *
count_buf
紀錄資料筆數的緩衝
回傳 說明
>= MCM_RCODE_PASS 成功
 < MCM_RCODE_PASS
(MCM_RCODE_CONFIG_NOT_FIND_STORE)
錯誤, 目標 entry 不存在
 < MCM_RCODE_PASS
(other)
錯誤, 其他錯誤

注意事項 :
01.  資料存取模式可以是 MCM_SPERMISSION_RO 或 MCM_SPERMISSION_RW.

範例 :
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/random.h>
#include "mcm_lib/mcm_lheader/mcm_type.h"
#include "mcm_lib/mcm_lheader/mcm_size.h"
#include "mcm_lib/mcm_lheader/mcm_connect.h"
#include "mcm_lib/mcm_lheader/mcm_return.h"
#include "mcm_lib/mcm_lheader/mcm_data_exinfo_auto.h"
#include "mcm_lib/mcm_lklib/mcm_lklib_api.h"

#define DMSG(msg_fmt, msgs...) \
    printk(KERN_INFO "%s(%04u): " msg_fmt "\n", \
           strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__, __LINE__, ##msgs)

static int __init main_init(
    void)
{
    char *path1;
    struct mcm_lklib_lib_t self_lklib;
    MCM_DTYPE_EK_TD count;

    self_lklib.socket_path = "@mintcm";
    self_lklib.call_from = MCM_CFROM_KERNEL;
    self_lklib.session_permission = MCM_SPERMISSION_RO;
    self_lklib.session_stack_size = 0;
    if(mcm_lklib_init(&self_lklib) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_init() fail");
        goto FREE_01;
    }

    // 指定目標路徑, 再使用函式取得.
    // 對於多層的目標, 可以使用 index + key 模式取值.

    // 範例 : 取得 device.system 的資料筆數. (對於 gs 類型 group, 總是 1)
    // 路徑 : "device.system"
    path1 = "device.system";
    if(mcm_lklib_get_count(&self_lklib, path1, &count) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_get_count(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[count] %s = " MCM_DTYPE_EK_PF, path1, count);

    // 範例 : 取得 device.vap.* 的資料筆數.
    // 路徑 : "device.vap.*"
    path1 = "device.vap.*";
    if(mcm_lklib_get_count(&self_lklib, path1, &count) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_get_count(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[count] %s = " MCM_DTYPE_EK_PF, path1, count);

    // 範例 : 取得 device.vap.@2.station.* 的資料筆數.
    // 路徑 : "device.vap.@2.station.*"
    path1 = "device.vap.@2.station.*";
    if(mcm_lklib_get_count(&self_lklib, path1, &count) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_get_count(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[count] %s = " MCM_DTYPE_EK_PF, path1, count);

    // 範例 : 取得 device.vap.#23.station.* 的資料筆數.
    // 路徑 : "device.vap.#23.tation.*"
    path1 = "device.vap.#23.station.*";
    if(mcm_lklib_get_count(&self_lklib, path1, &count) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_get_count(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[count] %s = " MCM_DTYPE_EK_PF, path1, count);

FREE_02:
    mcm_lklib_exit(&self_lklib);
FREE_01:
    return 0;
}

static void __exit main_exit(
    void)
{
    return;
}

module_init(main_init);
module_exit(main_exit);

MODULE_LICENSE("GPL");

mcm_lklib_get_alone
讀出 member 的資料.
參數 說明
struct mcm_lklib_lib_t *
this_lklib
紀錄 mcm_lklib_api 所需要的資料
char *
full_path
目標的路徑 [詳細]
[member 格式][index / key 模式]
void *
data_buf
紀錄資料的變數的緩衝 (變數的資料型態 [詳細])
回傳 說明
>= MCM_RCODE_PASS 成功
 < MCM_RCODE_PASS
(MCM_RCODE_CONFIG_NOT_FIND_STORE)
錯誤, 目標 entry 不存在
 < MCM_RCODE_PASS
(other)
錯誤, 其他錯誤

注意事項 :
01.  資料存取模式可以是 MCM_SPERMISSION_RO 或 MCM_SPERMISSION_RW.

範例 :
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/random.h>
#include "mcm_lib/mcm_lheader/mcm_type.h"
#include "mcm_lib/mcm_lheader/mcm_size.h"
#include "mcm_lib/mcm_lheader/mcm_connect.h"
#include "mcm_lib/mcm_lheader/mcm_return.h"
#include "mcm_lib/mcm_lheader/mcm_data_exinfo_auto.h"
#include "mcm_lib/mcm_lklib/mcm_lklib_api.h"

#define DMSG(msg_fmt, msgs...) \
    printk(KERN_INFO "%s(%04u): " msg_fmt "\n", \
           strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__, __LINE__, ##msgs)

static int __init main_init(
    void)
{
    char *path1;
    struct mcm_lklib_lib_t self_lklib;
    MCM_DTYPE_B_TD serial_number[MCM_BSIZE_DEVICE_SERIAL_NUMBER];
    MCM_DTYPE_FD_TD loading;
    MCM_DTYPE_EK_TD ekey;
    MCM_DTYPE_ISS_TD tx_power;
    MCM_DTYPE_S_TD mac_addr[MCM_BSIZE_DEVICE_VAP_STATION_MAC_ADDR];
    MCM_DTYPE_RK_TD rule;

    self_lklib.socket_path = "@mintcm";
    self_lklib.call_from = MCM_CFROM_KERNEL;
    self_lklib.session_permission = MCM_SPERMISSION_RO;
    self_lklib.session_stack_size = 0;
    if(mcm_lklib_init(&self_lklib) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_init() fail");
        goto FREE_01;
    }

    // 指定目標路徑, 指定目標的資料類型, 指定儲存的變數.
    // 對於 gd 類型的 group, 可以使用 index + key 模式.

    // 範例 : 讀出 device.serial_number
    // 路徑 : "device.serial_number"
    // 型態 : b -> MCM_DTYPE_B_TD
    // 變數 : serial_number
    path1 = "device.serial_number";
    if(mcm_lklib_get_alone(&self_lklib, path1, serial_number) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_get_alone(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[get-alone] %s = "
         MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF
         MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF,
         path1,
         serial_number[0], serial_number[1], serial_number[2], serial_number[3],
         serial_number[4], serial_number[5], serial_number[6], serial_number[7],
         serial_number[8], serial_number[9]);

    // 範例 : 讀出 device.system.loading
    // 路徑 : "device.system.loading"
    // 型態 : fd -> MCM_DTYPE_FD_TD
    // 變數 : loading
    path1 = "device.system.loading";
    if(mcm_lklib_get_alone(&self_lklib, path1, &loading) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_get_alone(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[get-alone] %s = " MCM_DTYPE_FD_PF, path1, loading);

    // 範例 : 讀出 device.vap.@3.ekey
    // 路徑 : "device.vap.@3.ekey"
    // 型態 : ek -> MCM_DTYPE_EK_TD
    // 變數 : vap_ekey
    path1 = "device.vap.@3.ekey";
    if(mcm_lklib_get_alone(&self_lklib, path1, &ekey) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_get_alone(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[get-alone] %s = " MCM_DTYPE_EK_PF, path1, ekey);

    // 範例 : 讀出 device.vap.#8.extra.tx_power
    // 路徑 : "device.vap.#8.extra.tx_power"
    // 型態 : iss -> MCM_DTYPE_ISS_TD
    // 變數 : tx_power
    path1 = "device.vap.#8.extra.tx_power";
    if(mcm_lklib_get_alone(&self_lklib, path1, &tx_power) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_get_alone(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[get-alone] %s = " MCM_DTYPE_ISS_PF, path1, tx_power);

    // 範例 : 讀出 device.vap.@2.station.#30.mac_addr
    // 路徑 : "device.vap.@2.station.#30.mac_addr"
    // 型態 : s -> MCM_DTYPE_S_TD
    // 變數 : mac_addr
    path1 = "device.vap.@2.station.#30.mac_addr";
    if(mcm_lklib_get_alone(&self_lklib, path1, mac_addr) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_get_alone(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[get-alone] %s = " MCM_DTYPE_S_PF, path1, mac_addr);

    // 範例 : 讀出 device.vap.#15.station.@2.rule
    // 路徑 : "device.vap.#15.station.@2.rule"
    // 型態 : rk -> MCM_DTYPE_RK_TD
    // 變數 : mac_addr
    path1 = "device.vap.#15.station.@2.rule";
    if(mcm_lklib_get_alone(&self_lklib, path1, &rule) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_get_alone(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[get-alone] %s = " MCM_DTYPE_RK_PF, path1, rule);

FREE_02:
    mcm_lklib_exit(&self_lklib);
FREE_01:
    return 0;
}

static void __exit main_exit(
    void)
{
    return;
}

module_init(main_init);
module_exit(main_exit);

MODULE_LICENSE("GPL");

mcm_lklib_set_alone
將資料寫入 member.
參數 說明
struct mcm_lklib_lib_t *
this_lklib
紀錄 mcm_lklib_api 所需要的資料
char *
full_path
目標的路徑 [詳細]
[member 格式][index / key 模式]
void *
data_con
寫入的資料 (變數的資料型態 [詳細])
MCM_DTYPE_USIZE_TD
data_len
寫入的資料的長度
字串類型填入字串長度, 其他類型填入變數大小
回傳 說明
>= MCM_RCODE_PASS 成功
 < MCM_RCODE_PASS
(MCM_RCODE_CONFIG_NOT_FIND_STORE)
錯誤, 目標 entry 不存在
 < MCM_RCODE_PASS
(other)
錯誤, 其他錯誤

注意事項 :
01.  資料存取模式必須是 MCM_SPERMISSION_RW.
02.  因為 ek 類型的 member 是唯讀的, 所以不可寫入.
03.  字串類型的資料在寫入時必須是 UTF-8 格式.

範例 :
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/random.h>
#include "mcm_lib/mcm_lheader/mcm_type.h"
#include "mcm_lib/mcm_lheader/mcm_size.h"
#include "mcm_lib/mcm_lheader/mcm_connect.h"
#include "mcm_lib/mcm_lheader/mcm_return.h"
#include "mcm_lib/mcm_lheader/mcm_data_exinfo_auto.h"
#include "mcm_lib/mcm_lklib/mcm_lklib_api.h"

#define DMSG(msg_fmt, msgs...) \
    printk(KERN_INFO "%s(%04u): " msg_fmt "\n", \
           strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__, __LINE__, ##msgs)

static unsigned int rand(
    void)
{
    unsigned int tmp_value;

    get_random_bytes(&tmp_value, sizeof(tmp_value));

    return tmp_value;
}

static int __init main_init(
    void)
{
    char *path1;
    struct mcm_lklib_lib_t self_lklib;
    MCM_DTYPE_S_TD descript[MCM_BSIZE_DEVICE_DESCRIPT];
    MCM_DTYPE_B_TD serial_number[MCM_BSIZE_DEVICE_SERIAL_NUMBER];
    MCM_DTYPE_FD_TD loading;
    MCM_DTYPE_IUI_TD channel;
    MCM_DTYPE_ISC_TD hidden;
    MCM_DTYPE_RK_TD rule;
    MCM_DTYPE_USIZE_TD i;

    self_lklib.socket_path = "@mintcm";
    self_lklib.call_from = MCM_CFROM_KERNEL;
    self_lklib.session_permission = MCM_SPERMISSION_RW;
    self_lklib.session_stack_size = 0;
    if(mcm_lklib_init(&self_lklib) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_init() fail");
        goto FREE_01;
    }

    // 修改資料後可以開啟 mint_cm/run/mcm_store_profile_current.txt 確認數值.

    // 範例 : 設定 device.descript
    // 路徑 : "device.descript"
    // 型態 : s -> MCM_DTYPE_S_TD
    // 變數 : descript / strlen(descript)
    path1 = "device.descript";
    snprintf(descript, sizeof(descript), "network-device-%02u", rand() % 100);
    DMSG("[set-alone] %s = " MCM_DTYPE_S_PF, path1, descript);
    if(mcm_lklib_set_alone(&self_lklib, path1, descript, strlen(descript)) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_set_alone(%s) fail", path1);
        goto FREE_02;
    }

    // 範例 : 設定 device.serial_number
    // 路徑 : "device.serial_number"
    // 型態 : b -> MCM_DTYPE_B_TD
    // 變數 : serial_number / sizeof(serial_number)
    path1 = "device.serial_number";
    for(i = 0; i < sizeof(serial_number); i++)
        serial_number[i] = rand() % 256;
    DMSG("[set-alone] %s = "
         MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF
         MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF,
         path1,
         serial_number[0], serial_number[1], serial_number[2], serial_number[3],
         serial_number[4], serial_number[5], serial_number[6], serial_number[7],
         serial_number[8], serial_number[9]);
    if(mcm_lklib_set_alone(&self_lklib, path1, serial_number, sizeof(serial_number))
                           < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_set_alone(%s) fail", path1);
        goto FREE_02;
    }

    // 範例 : 設定 device.system.loading
    // 路徑 : "device.system.loading"
    // 型態 : fd -> MCM_DTYPE_FD_TD
    // 變數 : loading / sizeof(loading)
    path1 = "device.system.loading";
    loading = 2000.0 / 30.5;
    DMSG("[set-alone] %s = " MCM_DTYPE_FD_PF, path1, loading);
    if(mcm_lklib_set_alone(&self_lklib, path1, &loading, sizeof(loading)) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_set_alone(%s) fail", path1);
        goto FREE_02;
    }

    // 範例 : 設定 device.vap.@1.channel
    // 路徑 : "device.vap.@1.channel"
    // 型態 : iui -> MCM_DTYPE_IUI_TD
    // 變數 : channel / sizeof(channel)
    path1 = "device.vap.@1.channel";
    channel = rand() % 200;
    DMSG("[set-alone] %s = " MCM_DTYPE_IUI_PF, path1, channel);
    if(mcm_lklib_set_alone(&self_lklib, path1, &channel, sizeof(channel)) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_set_alone(%s) fail", path1);
        goto FREE_02;
    }

    // 範例 : 設定 device.vap.#8.extra.hidden
    // 路徑 : "device.vap.#8.extra.hidden"
    // 型態 : isc -> MCM_DTYPE_ISC_TD
    // 變數 : hidden / sizeof(hidden)
    path1 = "device.vap.#8.extra.hidden";
    hidden = rand() % 2;
    DMSG("[set-alone] %s = " MCM_DTYPE_ISC_PF, path1, hidden);
    if(mcm_lklib_set_alone(&self_lklib, path1, &hidden, sizeof(hidden)) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_set_alone(%s) fail", path1);
        goto FREE_02;
    }

    // 範例 : 設定 device.vap.@2.station.#33.rule
    // 路徑 : "device.vap.@2.station.#33.rule"
    // 型態 : rk -> MCM_DTYPE_RK_TD
    // 變數 : rule / sizeof(rule)
    path1 = "device.vap.@2.station.#33.rule";
    rule = rand() % 50;
    DMSG("[set-alone] %s = " MCM_DTYPE_RK_PF, path1, rule);
    if(mcm_lklib_set_alone(&self_lklib, path1, &rule, sizeof(rule)) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_set_alone(%s) fail", path1);
        goto FREE_02;
    }

FREE_02:
    mcm_lklib_exit(&self_lklib);
FREE_01:
    return 0;
}

static void __exit main_exit(
    void)
{
    return;
}

module_init(main_init);
module_exit(main_exit);

MODULE_LICENSE("GPL");

mcm_lklib_get_entry
讀取 entry 的資料.
參數 說明
struct mcm_lklib_lib_t *
this_lklib
紀錄 mcm_lklib_api 所需要的資料
char *
full_path
目標的路徑 [詳細]
[entry 格式][index / key 模式]
void *
data_buf
紀錄資料的變數的緩衝 (變數的資料型態 [詳細])
回傳 說明
>= MCM_RCODE_PASS 成功
 < MCM_RCODE_PASS
(MCM_RCODE_CONFIG_NOT_FIND_STORE)
錯誤, 目標 entry 不存在
 < MCM_RCODE_PASS
(other)
錯誤, 其他錯誤

注意事項 :
01.  資料存取模式可以是 MCM_SPERMISSION_RO 或 MCM_SPERMISSION_RW.

範例 :
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/random.h>
#include "mcm_lib/mcm_lheader/mcm_type.h"
#include "mcm_lib/mcm_lheader/mcm_size.h"
#include "mcm_lib/mcm_lheader/mcm_connect.h"
#include "mcm_lib/mcm_lheader/mcm_return.h"
#include "mcm_lib/mcm_lheader/mcm_data_exinfo_auto.h"
#include "mcm_lib/mcm_lklib/mcm_lklib_api.h"

#define DMSG(msg_fmt, msgs...) \
    printk(KERN_INFO "%s(%04u): " msg_fmt "\n", \
           strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__, __LINE__, ##msgs)

static int __init main_init(
    void)
{
    char *path1;
    struct mcm_lklib_lib_t self_lklib;
    struct mcm_dv_device_t device_v;
    struct mcm_dv_device_vap_t vap_v;
    struct mcm_dv_device_vap_extra_t extra_v;
    struct mcm_dv_device_vap_station_t station_v;
    struct mcm_dv_device_limit_t limit_v;

    self_lklib.socket_path = "@mintcm";
    self_lklib.call_from = MCM_CFROM_KERNEL;
    self_lklib.session_permission = MCM_SPERMISSION_RO;
    self_lklib.session_stack_size = 0;
    if(mcm_lklib_init(&self_lklib) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_init() fail");
        goto FREE_01;
    }

    // 對於 gd 類型的 group, 可以使用 index + key 模式.

    // 範例 : 讀出 device
    // 路徑 : "device"
    // 型態 : struct mcm_dv_device_t
    // 變數 : device_v
    path1 = "device";
    if(mcm_lklib_get_entry(&self_lklib, path1, &device_v) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_get_entry(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[get-entry] %s.descript = " MCM_DTYPE_S_PF,
         path1, device_v.descript);
    DMSG("[get-entry] %s.serial_number = "
         MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF
         MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF,
         path1,
         device_v.serial_number[0], device_v.serial_number[1], device_v.serial_number[2],
         device_v.serial_number[3], device_v.serial_number[4], device_v.serial_number[5],
         device_v.serial_number[6], device_v.serial_number[7], device_v.serial_number[8],
         device_v.serial_number[9]);

    // 範例 : 讀出 device.vap.@1
    // 路徑 : "device.vap.@1"
    // 類型 : struct mcm_dv_device_vap_t
    // 變數 : vap_v
    path1 = "device.vap.@1";
    if(mcm_lklib_get_entry(&self_lklib, path1, &vap_v) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_get_entry(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[get-entry] %s.ekey = " MCM_DTYPE_EK_PF, path1, vap_v.ekey);
    DMSG("[get-entry] %s.ssid = " MCM_DTYPE_S_PF, path1, vap_v.ssid);
    DMSG("[get-entry] %s.channel = " MCM_DTYPE_IUI_PF, path1, vap_v.channel);

    // 範例 : 讀出 device.vap.#23.extra
    // 路徑 : "device.vap.#23.extra"
    // 類型 : struct mcm_dv_device_vap_extra_t
    // 變數 : extra_v
    path1 = "device.vap.#23.extra";
    if(mcm_lklib_get_entry(&self_lklib, path1, &extra_v) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_get_entry(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[get-entry] %s.hidden = " MCM_DTYPE_ISC_PF, path1, extra_v.hidden);
    DMSG("[get-entry] %s.tx_power = " MCM_DTYPE_ISS_PF, path1, extra_v.tx_power);

    // 範例 : 讀出 device.vap.@2.station.#30
    // 路徑 : "device.vap.@2.station.#30"
    // 類型 : struct mcm_dv_device_vap_station_t
    // 變數 : station_v
    path1 = "device.vap.@2.station.#30";
    if(mcm_lklib_get_entry(&self_lklib, path1, &station_v) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_get_entry(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[get-entry] %s.ekey = " MCM_DTYPE_EK_PF, path1, station_v.ekey);
    DMSG("[get-entry] %s.mac_addr = " MCM_DTYPE_S_PF, path1, station_v.mac_addr);
    DMSG("[get-entry] %s.rule = " MCM_DTYPE_RK_PF, path1, station_v.rule);

    // 範例 : 讀出 device.limit.#6
    // 路徑 : "device.limit.#6"
    // 類型 : struct mcm_dv_device_limit_t
    // 變數 : limit_v
    path1 = "device.limit.#6";
    if(mcm_lklib_get_entry(&self_lklib, path1, &limit_v) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_get_entry(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[get-entry] %s.ekey = " MCM_DTYPE_EK_PF, path1, limit_v.ekey);
    DMSG("[get-entry] %s.name = " MCM_DTYPE_S_PF, path1, limit_v.name);
    DMSG("[get-entry] %s.priority = " MCM_DTYPE_ISI_PF, path1, limit_v.priority);

FREE_02:
    mcm_lklib_exit(&self_lklib);
FREE_01:
    return 0;
}

static void __exit main_exit(
    void)
{
    return;
}

module_init(main_init);
module_exit(main_exit);

MODULE_LICENSE("GPL");

mcm_lklib_set_entry
將資料寫入 entry.
參數 說明
struct mcm_lklib_lib_t *
this_lklib
紀錄 mcm_lklib_api 所需要的資料
char *
full_path
目標的路徑 [詳細]
[entry 格式][index / key 模式]
void *
data_con
寫入的資料 (變數的資料型態 [詳細])
回傳 說明
>= MCM_RCODE_PASS 成功
 < MCM_RCODE_PASS
(MCM_RCODE_CONFIG_NOT_FIND_STORE)
錯誤, 目標 entry 不存在
 < MCM_RCODE_PASS
(other)
錯誤, 其他錯誤

注意事項 :
01.  資料存取模式必須是 MCM_SPERMISSION_RW.
02.  因為 ek 類型的 member 是唯讀的, 所以資料庫內 ek 的數值不會被寫入的資料覆蓋.
03.  字串類型的資料在寫入時必須是 UTF-8 格式.

範例 :
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/random.h>
#include "mcm_lib/mcm_lheader/mcm_type.h"
#include "mcm_lib/mcm_lheader/mcm_size.h"
#include "mcm_lib/mcm_lheader/mcm_connect.h"
#include "mcm_lib/mcm_lheader/mcm_return.h"
#include "mcm_lib/mcm_lheader/mcm_data_exinfo_auto.h"
#include "mcm_lib/mcm_lklib/mcm_lklib_api.h"

#define DMSG(msg_fmt, msgs...) \
    printk(KERN_INFO "%s(%04u): " msg_fmt "\n", \
           strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__, __LINE__, ##msgs)

static unsigned int rand(
    void)
{
    unsigned int tmp_value;

    get_random_bytes(&tmp_value, sizeof(tmp_value));

    return tmp_value;
}

static int __init main_init(
    void)
{
    char *path1;
    struct mcm_lklib_lib_t self_lklib;
    struct mcm_dv_device_t device_v;
    struct mcm_dv_device_system_t system_v;
    struct mcm_dv_device_vap_t vap_v;
    struct mcm_dv_device_vap_extra_t extra_v;
    struct mcm_dv_device_vap_station_t station_v;
    MCM_DTYPE_USIZE_TD i;

    self_lklib.socket_path = "@mintcm";
    self_lklib.call_from = MCM_CFROM_KERNEL;
    self_lklib.session_permission = MCM_SPERMISSION_RW;
    self_lklib.session_stack_size = 0;
    if(mcm_lklib_init(&self_lklib) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_init() fail");
        goto FREE_01;
    }

    // 修改資料後可以開啟 mint_cm/run/mcm_store_profile_current.txt 確認數值.

    // 範例 : 設定 device
    // 路徑 : "device"
    // 型態 : struct mcm_dv_device_t
    // 變數 : device_v
    path1 = "device";
    memset(&device_v, 0, sizeof(device_v));
    snprintf(device_v.descript, sizeof(device_v.descript), "network-device-%02u", rand() % 100);
    for(i = 0; i < sizeof(device_v.serial_number); i++)
        device_v.serial_number[i] = rand() % 256;
    DMSG("[set-entry] %s.descript = " MCM_DTYPE_S_PF, path1, device_v.descript);
    DMSG("[set-entry] %s.serial_number = "
         MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF
         MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF,
         path1,
         device_v.serial_number[0], device_v.serial_number[1], device_v.serial_number[2],
         device_v.serial_number[3], device_v.serial_number[4], device_v.serial_number[5],
         device_v.serial_number[6], device_v.serial_number[7], device_v.serial_number[8],
         device_v.serial_number[9]);
    if(mcm_lklib_set_entry(&self_lklib, path1, &device_v, sizeof(device_v)) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_set_entry(%s) fail", path1);
        goto FREE_02;
    }

    // 範例 : 設定 device.system
    // 路徑 : "device.system"
    // 型態 : struct mcm_dv_device_system_t
    // 變數 : system_v
    path1 = "device.system";
    memset(&system_v, 0, sizeof(system_v));
    snprintf(system_v.date, sizeof(system_v.date), "2016/05/%u", rand() % 30);
    snprintf(system_v.ip_addr, sizeof(system_v.ip_addr), "192.168.1.%u", rand() % 250);
    system_v.uptime = rand();
    system_v.loading = 31254.5 / -58.1;
    DMSG("[set-entry] %s.date = " MCM_DTYPE_S_PF, path1, system_v.date);
    DMSG("[set-entry] %s.ip_addr = " MCM_DTYPE_S_PF, path1, system_v.ip_addr);
    DMSG("[set-entry] %s.uptime = " MCM_DTYPE_IULL_PF, path1, system_v.uptime);
    DMSG("[set-entry] %s.loading = " MCM_DTYPE_FD_PF, path1, system_v.loading);
    if(mcm_lklib_set_entry(&self_lklib, path1, &system_v, sizeof(system_v)) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_set_entry(%s) fail", path1);
        goto FREE_02;
    }

    // 範例 : 設定 device.vap.@1
    // 路徑 : "device.vap.@1"
    // 型態 : struct mcm_dv_device_vap_t
    // 變數 : vap_v
    path1 = "device.vap.@1";
    memset(&vap_v, 0, sizeof(vap_v));
    snprintf(vap_v.ssid, sizeof(vap_v.ssid), "access-%u", rand() % 100);
    vap_v.channel = rand() % 200;
    DMSG("[set-entry] %s.ssid = " MCM_DTYPE_S_PF, path1, vap_v.ssid);
    DMSG("[set-entry] %s.channel = " MCM_DTYPE_IUI_PF, path1, vap_v.channel);
    if(mcm_lklib_set_entry(&self_lklib, path1, &vap_v, sizeof(vap_v)) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_set_entry(%s) fail", path1);
        goto FREE_02;
    }

    // 範例 : 設定 device.vap.#23.extra
    // 路徑 : "device.vap.#23.extra"
    // 型態 : struct mcm_dv_device_vap_extra_t
    // 變數 : extra_v
    path1 = "device.vap.#23.extra";
    memset(&extra_v, 0, sizeof(extra_v));
    extra_v.hidden = rand() % 2;
    extra_v.tx_power = (rand() % 20) - 10;
    DMSG("[set-entry] %s.hidden = " MCM_DTYPE_ISC_PF, path1, extra_v.hidden);
    DMSG("[set-entry] %s.tx_power = " MCM_DTYPE_ISS_PF, path1, extra_v.tx_power);
    if(mcm_lklib_set_entry(&self_lklib, path1, &extra_v, sizeof(extra_v)) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_set_entry(%s) fail", path1);
        goto FREE_02;
    }

    // 範例 : 設定 device.vap.@2.station.#30
    // 路徑 : "device.vap.@2.station.#30"
    // 型態 : struct mcm_dv_device_vap_station_t
    // 變數 : station_v
    path1 = "device.vap.@2.station.#30";
    memset(&station_v, 0, sizeof(station_v));
    snprintf(station_v.mac_addr, sizeof(station_v.mac_addr), "00:11:22:AA:BB:%02X", rand() % 255);
    station_v.rule = rand() % 50;
    DMSG("[set-entry] %s.mac_addr = " MCM_DTYPE_S_PF, path1, station_v.mac_addr);
    DMSG("[set-entry] %s.rule = " MCM_DTYPE_RK_PF, path1, station_v.rule);
    if(mcm_lklib_set_entry(&self_lklib, path1, &station_v, sizeof(station_v)) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_set_entry(%s) fail", path1);
        goto FREE_02;
    }

FREE_02:
    mcm_lklib_exit(&self_lklib);
FREE_01:
    return 0;
}

static void __exit main_exit(
    void)
{
    return;
}

module_init(main_init);
module_exit(main_exit);

MODULE_LICENSE("GPL");

mcm_lklib_add_entry
增加一筆 entry.
參數 說明
struct mcm_lklib_lib_t *
this_lklib
紀錄 mcm_lklib_api 所需要的資料
char *
full_path
目標的路徑 [詳細]
[entry 格式][index / key 模式]
加入的目標必須是 [key 模式]
char *
insert_path
要插入到何處的路徑 [詳細]
[index 模式] / [key 模式]
void *
data_con
寫入的資料 (變數的資料型態 [詳細])
可為 NULL, 表示使用初始值 (資料模型中設的 $(default)) [詳細]
MCM_DTYPE_USIZE_TD
data_len
寫入的資料的長度
若 data_con 是 NULL, 則為 0
回傳 說明
>= MCM_RCODE_PASS 成功
 < MCM_RCODE_PASS
(MCM_RCODE_CONFIG_NOT_FIND_STORE)
錯誤, 目標 entry 不存在
 < MCM_RCODE_PASS
(other)
錯誤, 其他錯誤

注意事項 :
01.  資料存取模式必須是 MCM_SPERMISSION_RW.
02.  路徑可以是 [indxe / key 模式], 但是最後一段要加入的目標必須是 [key 模式].
03.  增加 entry 需要指定新的 key (不可和存在的 entry 的 key 相同).
04.  key 值會使用 full_path 的值, data_con 內的 key 值會被忽略.
05.  增加多層資料時, 要逐層增加.

範例 :
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/random.h>
#include "mcm_lib/mcm_lheader/mcm_type.h"
#include "mcm_lib/mcm_lheader/mcm_size.h"
#include "mcm_lib/mcm_lheader/mcm_connect.h"
#include "mcm_lib/mcm_lheader/mcm_return.h"
#include "mcm_lib/mcm_lheader/mcm_data_exinfo_auto.h"
#include "mcm_lib/mcm_lklib/mcm_lklib_api.h"

#define DMSG(msg_fmt, msgs...) \
    printk(KERN_INFO "%s(%04u): " msg_fmt "\n", \
           strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__, __LINE__, ##msgs)

static unsigned int rand(
    void)
{
    unsigned int tmp_value;

    get_random_bytes(&tmp_value, sizeof(tmp_value));

    return tmp_value;
}

static int __init main_init(
    void)
{
    char *path1;
    struct mcm_lklib_lib_t self_lklib;
    struct mcm_dv_device_vap_t vap_v;
    struct mcm_dv_device_vap_station_t station_v;

    self_lklib.socket_path = "@mintcm";
    self_lklib.call_from = MCM_CFROM_KERNEL;
    self_lklib.session_permission = MCM_SPERMISSION_RW;
    self_lklib.session_stack_size = 0;
    if(mcm_lklib_init(&self_lklib) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_init() fail");
        goto FREE_01;
    }

    // 路徑可以是 [indxe / key 模式], 但是最後一段要加入的目標必須是 [key 模式].
    // 增加 entry 需要指定新的 key (不可和存在的 entry 的 key 相同).
    // key 值會使用 full_path 的值, data_con 內的 key 值會被忽略.
    // 增加多層資料時, 要逐層增加.
    // 修改資料後可以開啟 mint_cm/run/mcm_store_profile_current.txt 確認數值.

    // 範例 : 增加 device.vap.#123
    // 路徑 : "device.vap.#123"
    // 插入 : 放在串列尾端 (NULL)
    // 類型 : struct mcm_dv_device_vap_t
    // 變數 : vap_v / sizeof(vap_v)
    // 加入的目標 (vap) 必須是 key 模式.
    path1 = "device.vap.#123";
    memset(&vap_v, 0, sizeof(vap_v));
    snprintf(vap_v.ssid, sizeof(vap_v.ssid), "vap-%u", rand() % 100);
    vap_v.channel = rand() % 200;
    DMSG("[add-entry] %s.ssid = " MCM_DTYPE_S_PF, path1, vap_v.ssid);
    DMSG("[add-entry] %s.channel = " MCM_DTYPE_IUI_PF, path1, vap_v.channel);
    if(mcm_lklib_add_entry(&self_lklib, path1, NULL, &vap_v, sizeof(vap_v)) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_add_entry(%s) fail", path1);
        goto FREE_02;
    }
    // 如果 parent-group 是 gd 類型的 gs 類型 group, 當 parent-group 增加
    // entry 時, 也會一併被增加.
    // 以 device.vap.*.extra 為例, 當 device.vap.* 增加 entry,
    // 對應的 extra 也會被增加, 被增加的 extra 內容為資料模型中設定的初始值.


    // 範例 : 增加 device.vap.@3.station.#111
    // 路徑 : "device.vap.@3.station.#111"
    // 插入 : 放在串列尾端 ("")
    // 類型 : struct mcm_dv_device_vap_station_t
    // 變數 : station_v / sizeof(station_v)
    // 加入的目標 (station) 必須是 key 模式.
    path1 = "device.vap.@3.station.#111";
    memset(&station_v, 0, sizeof(station_v));
    snprintf(station_v.mac_addr, sizeof(station_v.mac_addr), "00:1a:2b:3c:4d:%02x", rand() % 255);
    station_v.rule = rand() % 50;
    DMSG("[add-entry] %s.mac_addr = " MCM_DTYPE_S_PF, path1, station_v.mac_addr);
    DMSG("[add-entry] %s.rule = " MCM_DTYPE_RK_PF, path1, station_v.rule);
    if(mcm_lklib_add_entry(&self_lklib, path1, "", &station_v, sizeof(station_v))
                           < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_add_entry(%s) fail", path1);
        goto FREE_02;
    }

    // 範例 : 增加 device.vap.#234.station.#1
    // 路徑 : "device.vap.#234.station.#1"
    // 插入 : 插入到第 1 筆 entry 之前 (@1)
    // 類型 : struct mcm_dv_device_vap_t
    // 變數 : vap_v / sizeof(vap_v)
    // 增加多層資料時, 要逐層增加.
    // device.vap.#234 並不存在, 先增加.
    path1 = "device.vap.#234";
    memset(&vap_v, 0, sizeof(vap_v));
    snprintf(vap_v.ssid, sizeof(vap_v.ssid), "vap-%u", rand() % 100);
    vap_v.channel = rand() % 200;
    DMSG("[add-entry] %s.ssid = " MCM_DTYPE_S_PF, path1, vap_v.ssid);
    DMSG("[add-entry] %s.channel = " MCM_DTYPE_IUI_PF, path1, vap_v.channel);
    if(mcm_lklib_add_entry(&self_lklib, path1, "", &vap_v, sizeof(vap_v)) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_add_entry(%s) fail", path1);
        goto FREE_02;
    }
    // 接著增加 device.vap.#234.station.#1
    path1 = "device.vap.#234.station.#1";
    memset(&station_v, 0, sizeof(station_v));
    snprintf(station_v.mac_addr, sizeof(station_v.mac_addr), "00:1a:2b:3c:4d:%02x", rand() % 255);
    station_v.rule = rand() % 50;
    DMSG("[add-entry] %s.mac_addr = " MCM_DTYPE_S_PF, path1, station_v.mac_addr);
    DMSG("[add-entry] %s.rule = " MCM_DTYPE_RK_PF, path1, station_v.rule);
    if(mcm_lklib_add_entry(&self_lklib, path1, "@1", &station_v, sizeof(station_v))
                           < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_add_entry(%s) fail", path1);
        goto FREE_02;
    }

    // 範例 : 增加 device.limit.#51
    // 路徑 : "device.limit.#51"
    // 插入 : 插入到 key 為 60 的 entry 之前 (#60)
    // 使用初始值.
    path1 = "device.limit.#51";
    DMSG("[add-entry] %s", path1);
    if(mcm_lklib_add_entry(&self_lklib, path1, "#60", NULL, 0) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_add_entry(%s) fail", path1);
        goto FREE_02;
    }

FREE_02:
    mcm_lklib_exit(&self_lklib);
FREE_01:
    return 0;
}

static void __exit main_exit(
    void)
{
    return;
}

module_init(main_init);
module_exit(main_exit);

MODULE_LICENSE("GPL");

mcm_lklib_del_entry
刪除一筆 entry.
參數 說明
struct mcm_lklib_lib_t *
this_lklib
紀錄 mcm_lklib_api 所需要的資料
char *
full_path
目標的路徑 [詳細]
[entry 格式][index / key 模式]
回傳 說明
>= MCM_RCODE_PASS 成功
 < MCM_RCODE_PASS
(MCM_RCODE_CONFIG_NOT_FIND_STORE)
錯誤, 目標 entry 不存在
 < MCM_RCODE_PASS
(other)
錯誤, 其他錯誤

注意事項 :
01.  資料存取模式必須是 MCM_SPERMISSION_RW.

範例 :
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/random.h>
#include "mcm_lib/mcm_lheader/mcm_type.h"
#include "mcm_lib/mcm_lheader/mcm_size.h"
#include "mcm_lib/mcm_lheader/mcm_connect.h"
#include "mcm_lib/mcm_lheader/mcm_return.h"
#include "mcm_lib/mcm_lheader/mcm_data_exinfo_auto.h"
#include "mcm_lib/mcm_lklib/mcm_lklib_api.h"

#define DMSG(msg_fmt, msgs...) \
    printk(KERN_INFO "%s(%04u): " msg_fmt "\n", \
           strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__, __LINE__, ##msgs)

static int __init main_init(
    void)
{
    char *path1;
    struct mcm_lklib_lib_t self_lklib;

    self_lklib.socket_path = "@mintcm";
    self_lklib.call_from = MCM_CFROM_KERNEL;
    self_lklib.session_permission = MCM_SPERMISSION_RW;
    self_lklib.session_stack_size = 0;
    if(mcm_lklib_init(&self_lklib) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_init() fail");
        goto FREE_01;
    }

    // 修改資料後可以開啟 mint_cm/run/mcm_store_profile_current.txt 確認數值.

    // 範例 : 刪除 device.vap.@1
    // 路徑 : "device.vap.@1"
    path1 = "device.vap.@1";
    DMSG("[del-entry] %s", path1);
    if(mcm_lklib_del_entry(&self_lklib, path1) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_del_entry(%s) fail", path1);
        goto FREE_02;
    }

    // 範例 : 刪除 device.vap.#15.station.@2
    // 路徑 : "device.vap.#15.station.@2"
    path1 = "device.vap.#15.station.@2";
    DMSG("[del-entry] %s", path1);
    if(mcm_lklib_del_entry(&self_lklib, path1) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_del_entry(%s) fail", path1);
        goto FREE_02;
    }

FREE_02:
    mcm_lklib_exit(&self_lklib);
FREE_01:
    return 0;
}

static void __exit main_exit(
    void)
{
    return;
}

module_init(main_init);
module_exit(main_exit);

MODULE_LICENSE("GPL");

mcm_lklib_check_exist
檢查 entry 是否存在.
參數 說明
struct mcm_lklib_lib_t *
this_lklib
紀錄 mcm_lklib_api 所需要的資料
char *
full_path
目標的路徑 [詳細]
[entry 格式][index / key 模式]
MCM_DTYPE_BOOL_TD *
exist_buf
紀錄 entry 是否存在的緩衝
回傳值 :
0 : 不存在
1 : 有存在
回傳 說明
>= MCM_RCODE_PASS 成功
 < MCM_RCODE_PASS 錯誤

注意事項 :
01.  資料存取模式可以是 MCM_SPERMISSION_RO 或 MCM_SPERMISSION_RW.
02.  entry 是否存在要看 exist_buf 的值.

範例 :
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/random.h>
#include "mcm_lib/mcm_lheader/mcm_type.h"
#include "mcm_lib/mcm_lheader/mcm_size.h"
#include "mcm_lib/mcm_lheader/mcm_connect.h"
#include "mcm_lib/mcm_lheader/mcm_return.h"
#include "mcm_lib/mcm_lheader/mcm_data_exinfo_auto.h"
#include "mcm_lib/mcm_lklib/mcm_lklib_api.h"

#define DMSG(msg_fmt, msgs...) \
    printk(KERN_INFO "%s(%04u): " msg_fmt "\n", \
           strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__, __LINE__, ##msgs)

static int __init main_init(
    void)
{
    char *path1;
    struct mcm_lklib_lib_t self_lklib;
    MCM_DTYPE_BOOL_TD is_exist;

    self_lklib.socket_path = "@mintcm";
    self_lklib.call_from = MCM_CFROM_KERNEL;
    self_lklib.session_permission = MCM_SPERMISSION_RO;
    self_lklib.session_stack_size = 0;
    if(mcm_lklib_init(&self_lklib) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_init() fail");
        goto FREE_01;
    }

    // 範例 : 檢查 device.syatem 是否存在 (因為是 gs 類型, 所以一定存在).
    // 路徑 : "device.system"
    path1 = "device.system";
    if(mcm_lklib_check_exist(&self_lklib, path1, &is_exist) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_check_exist(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[check-exist] %s = " MCM_DTYPE_BOOL_PF, path1, is_exist);

    // 範例 : 檢查 device.vap.@2 是否存在.
    // 路徑 : "device.vap.@2"
    path1 = "device.vap.@2";
    if(mcm_lklib_check_exist(&self_lklib, path1, &is_exist) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_check_exist(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[check-exist] %s = " MCM_DTYPE_BOOL_PF, path1, is_exist);

    // 範例 : 檢查 device.vap.#8.station.#1234 是否存在.
    // 路徑 : "device.vap.#8.station.#1234"
    path1 = "device.vap.#8.station.#1234";
    if(mcm_lklib_check_exist(&self_lklib, path1, &is_exist) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_check_exist(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[check-exist] %s = " MCM_DTYPE_BOOL_PF, path1, is_exist);

FREE_02:
    mcm_lklib_exit(&self_lklib);
FREE_01:
    return 0;
}

static void __exit main_exit(
    void)
{
    return;
}

module_init(main_init);
module_exit(main_exit);

MODULE_LICENSE("GPL");

mcm_lklib_get_all_key
讀取所有 entry 的 key 值.
參數 說明
struct mcm_lklib_lib_t *
this_lklib
紀錄 mcm_lklib_api 所需要的資料
char *
mix_path
目標的路徑 [詳細]
[index / key 模式]
MCM_DTYPE_EK_TD **
key_buf
內部函式會配置記憶體空間並放入資料, 使用完需要釋放, 傳入參數需要做強制轉型 (MCM_DTYPE_EK_TD **)
MCM_DTYPE_EK_TD *
count_buf
紀錄資料筆數的緩衝
回傳 說明
>= MCM_RCODE_PASS 成功
 < MCM_RCODE_PASS
(MCM_RCODE_CONFIG_NOT_FIND_STORE)
錯誤, 目標 entry 不存在
 < MCM_RCODE_PASS
(other)
錯誤, 其他錯誤

注意事項 :
01.  資料存取模式可以是 MCM_SPERMISSION_RO 或 MCM_SPERMISSION_RW.
02.  使用 index 模式和 key 模式的資料搜索的速度 :
A.  知道所有 entry 的 key 值, 使用 key 模式的路徑.
B.  不知道所有 entry 的 key 值, 先使用此函式取得所有 entry 的 key 值, 再使用 key 模式的路徑.
C.  不知道所有 entry 的 key 值, 使用 index 模式的路徑.

範例 :
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/random.h>
#include "mcm_lib/mcm_lheader/mcm_type.h"
#include "mcm_lib/mcm_lheader/mcm_size.h"
#include "mcm_lib/mcm_lheader/mcm_connect.h"
#include "mcm_lib/mcm_lheader/mcm_return.h"
#include "mcm_lib/mcm_lheader/mcm_data_exinfo_auto.h"
#include "mcm_lib/mcm_lklib/mcm_lklib_api.h"

#define DMSG(msg_fmt, msgs...) \
    printk(KERN_INFO "%s(%04u): " msg_fmt "\n", \
           strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__, __LINE__, ##msgs)

static int __init main_init(
    void)
{
    char *path1, path2[MCM_PATH_MAX_LENGTH];
    struct mcm_lklib_lib_t self_lklib;
    struct mcm_dv_device_vap_t vap_v;
    struct mcm_dv_device_vap_station_t station_v;
    MCM_DTYPE_EK_TD i, count, *key_array;

    self_lklib.socket_path = "@mintcm";
    self_lklib.call_from = MCM_CFROM_KERNEL;
    self_lklib.session_permission = MCM_SPERMISSION_RO;
    self_lklib.session_stack_size = 0;
    if(mcm_lklib_init(&self_lklib) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_init() fail");
        goto FREE_01;
    }

    // 範例 : 讀出 device.vap.* 所有的 key.
    // 路徑 : "device.vap.*"
    path1 = "device.vap.*";
    if(mcm_lklib_get_all_key(&self_lklib, path1, (MCM_DTYPE_EK_TD **) &key_array, &count)
                             < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_get_all_key(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[count] %s = " MCM_DTYPE_EK_PF, path1, count);
    // 接著使用 key 值讀出所有的 device.vap.*
    for(i = 0; i < count; i++)
    {
        // 範例 : 設定 device.vap.*
        // 路徑 : "device.vap.*"
        // 型態 : struct mcm_dv_device_vap_t
        // 變數 : vap_v
        snprintf(path2, sizeof(path2), "device.vap.#%u", key_array[i]);
        if(mcm_lklib_get_entry(&self_lklib, path2, &vap_v) < MCM_RCODE_PASS)
        {
            DMSG("call mcm_lklib_get_entry(%s) fail", path2);
            goto FREE_02;
        }
        DMSG("[get-entry] %s.ekey = " MCM_DTYPE_EK_PF, path2, vap_v.ekey);
        DMSG("[get-entry] %s.ssid = " MCM_DTYPE_S_PF, path2, vap_v.ssid);
        DMSG("[get-entry] %s.channel = " MCM_DTYPE_IUI_PF, path2, vap_v.channel);
    }
    kfree(key_array);

    // 範例 : 讀出 device.vap.@1.station.* 所有的 key.
    // 路徑 : "device.vap.@1.station.*"
    path1 = "device.vap.@1.station.*";
    if(mcm_lklib_get_all_key(&self_lklib, path1, (MCM_DTYPE_EK_TD **) &key_array, &count)
                             < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_get_all_key(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[count] %s = " MCM_DTYPE_EK_PF, path1, count);
    // 接著使用 key 值讀出所有的 device.vap.@1.station.*
    for(i = 0; i < count; i++)
    {
        // 範例 : 讀出 device.vap.@1.station.*
        // 路徑 : "device.vap.@1.station.#{key}"
        // 類型 : struct mcm_dv_device_vap_station_t
        // 變數 : station_v
        snprintf(path2, sizeof(path2), "device.vap.@1.station.#%u", key_array[i]);
        if(mcm_lklib_get_entry(&self_lklib, path2, &station_v) < MCM_RCODE_PASS)
        {
            DMSG("call mcm_lklib_get_entry(%s) fail", path2);
            goto FREE_02;
        }
        DMSG("[get-entry] %s.ekey = " MCM_DTYPE_EK_PF, path2, station_v.ekey);
        DMSG("[get-entry] %s.mac_addr = " MCM_DTYPE_S_PF, path2, station_v.mac_addr);
        DMSG("[get-entry] %s.rule = " MCM_DTYPE_RK_PF, path2, station_v.rule);
    }
    kfree(key_array);

    // 範例 : 讀出 device.vap.#15.station.* 所有的 key.
    // 路徑 : "device.vap.#15.station.*"
    path1 = "device.vap.#15.station.*";
    if(mcm_lklib_get_all_key(&self_lklib, path1, (MCM_DTYPE_EK_TD **) &key_array, &count)
                             < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_get_all_key(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[count] %s = " MCM_DTYPE_EK_PF, path1, count);
    // 接著使用 key 值讀出所有的 device.vap.#15.station.*
    for(i = 0; i < count; i++)
    {
        // 範例 : 讀出 device.vap.#15.station.*
        // 路徑 : "device.vap.#15.station.#{key}"
        // 類型 : struct mcm_dv_device_vap_station_t
        // 變數 : station_v
        snprintf(path2, sizeof(path2), "device.vap.#15.station.#%u", key_array[i]);
        if(mcm_lklib_get_entry(&self_lklib, path2, &station_v) < MCM_RCODE_PASS)
        {
            DMSG("call mcm_lklib_get_entry(%s) fail", path2);
            goto FREE_02;
        }
        DMSG("[get-entry] %s.ekey = " MCM_DTYPE_EK_PF, path2, station_v.ekey);
        DMSG("[get-entry] %s.mac_addr = " MCM_DTYPE_S_PF, path2, station_v.mac_addr);
        DMSG("[get-entry] %s.rule = " MCM_DTYPE_RK_PF, path2, station_v.rule);
    }
    kfree(key_array);

FREE_02:
    mcm_lklib_exit(&self_lklib);
FREE_01:
    return 0;
}

static void __exit main_exit(
    void)
{
    return;
}

module_init(main_init);
module_exit(main_exit);

MODULE_LICENSE("GPL");

mcm_lklib_get_all_entry
讀取所有 entry 的資料.
參數 說明
struct mcm_lklib_lib_t *
this_lklib
紀錄 mcm_lklib_api 所需要的資料
char *
mix_path
目標的路徑 [詳細]
[index / key 模式]
void **
data_buf
紀錄資料的變數的緩衝 (變數的資料型態 [詳細])
內部函式會配置記憶體空間並放入資料, 使用完需要釋放, 傳入參數需要做強制轉型 (void **)
MCM_DTYPE_EK_TD *
count_buf
紀錄資料筆數的緩衝
回傳 說明
>= MCM_RCODE_PASS 成功
 < MCM_RCODE_PASS
(MCM_RCODE_CONFIG_NOT_FIND_STORE)
錯誤, 目標 entry 不存在
 < MCM_RCODE_PASS
(other)
錯誤, 其他錯誤

注意事項 :
01.  資料存取模式可以是 MCM_SPERMISSION_RO 或 MCM_SPERMISSION_RW.

範例 :
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/random.h>
#include "mcm_lib/mcm_lheader/mcm_type.h"
#include "mcm_lib/mcm_lheader/mcm_size.h"
#include "mcm_lib/mcm_lheader/mcm_connect.h"
#include "mcm_lib/mcm_lheader/mcm_return.h"
#include "mcm_lib/mcm_lheader/mcm_data_exinfo_auto.h"
#include "mcm_lib/mcm_lklib/mcm_lklib_api.h"

#define DMSG(msg_fmt, msgs...) \
    printk(KERN_INFO "%s(%04u): " msg_fmt "\n", \
           strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__, __LINE__, ##msgs)

static int __init main_init(
    void)
{
    char *path1, path2[MCM_PATH_MAX_LENGTH];
    struct mcm_lklib_lib_t self_lklib;
    struct mcm_dv_device_t *device_v;
    struct mcm_dv_device_vap_t *vap_v;
    struct mcm_dv_device_vap_extra_t *extra_v;
    struct mcm_dv_device_vap_station_t *station_v;
    MCM_DTYPE_EK_TD i, count;

    self_lklib.socket_path = "@mintcm";
    self_lklib.call_from = MCM_CFROM_KERNEL;
    self_lklib.session_permission = MCM_SPERMISSION_RO;
    self_lklib.session_stack_size = 0;
    if(mcm_lklib_init(&self_lklib) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_init() fail");
        goto FREE_01;
    }

    // 對於 gd 類型的 group, 可以使用 index + key 模式.

    // 範例 : 讀出 device
    // 路徑 : "device"
    path1 = "device";
    if(mcm_lklib_get_all_entry(&self_lklib, path1, (void **) &device_v, &count) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_get_all_entry(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[get-all-entry] %s = " MCM_DTYPE_EK_PF, path1, count);
    DMSG("[get-all-entry] %s.descript = " MCM_DTYPE_S_PF, path1, device_v[0].descript);
    DMSG("[get-all-entry] %s.serial_number = "
         MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF
         MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF MCM_DTYPE_B_PF,
         path1,
         device_v[0].serial_number[0], device_v[0].serial_number[1],
         device_v[0].serial_number[2], device_v[0].serial_number[3],
         device_v[0].serial_number[4], device_v[0].serial_number[5],
         device_v[0].serial_number[6], device_v[0].serial_number[7],
         device_v[0].serial_number[8], device_v[0].serial_number[9]);
    kfree(device_v);

    // 範例 : 讀出 device.vap.*
    // 路徑 : "device.vap.*"
    path1 = "device.vap.*";
    if(mcm_lklib_get_all_entry(&self_lklib, path1, (void **) &vap_v, &count) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_get_all_entry(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[get-all-entry] %s = " MCM_DTYPE_EK_PF, path1, count);
    for(i = 0; i < count; i++)
    {
        snprintf(path2, sizeof(path2), "device.vap.@%u", i + 1);
        DMSG("[get-all-entry] %s.ekey = " MCM_DTYPE_EK_PF, path2, vap_v[i].ekey);
        DMSG("[get-all-entry] %s.ssid = " MCM_DTYPE_S_PF, path2, vap_v[i].ssid);
        DMSG("[get-all-entry] %s.channel = " MCM_DTYPE_IUI_PF, path2, vap_v[i].channel);
    }
    kfree(vap_v);

    // 範例 : 讀出 device.vap.@2.extra
    // 路徑 : "device.vap.@2.extra"
    path1 = "device.vap.@2.extra";
    if(mcm_lklib_get_all_entry(&self_lklib, path1, (void **) &extra_v, &count) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_get_all_entry(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[get-all-entry] %s = " MCM_DTYPE_EK_PF, path1, count);
    DMSG("[get-all-entry] %s.hidden = " MCM_DTYPE_ISC_PF, path1, extra_v[0].hidden);
    DMSG("[get-all-entry] %s.tx_power = " MCM_DTYPE_ISS_PF, path1, extra_v[0].tx_power);
    kfree(extra_v);

    // 範例 : 讀出 device.vap.#15.station.*
    // 路徑 : "device.vap.#15.station.*"
    path1 = "device.vap.#15.station.*";
    if(mcm_lklib_get_all_entry(&self_lklib, path1, (void **) &station_v, &count) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_get_all_entry(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[get-all-entry] %s = " MCM_DTYPE_EK_PF, path1, count);
    for(i = 0; i < count; i++)
    {
        snprintf(path2, sizeof(path2), "device.vap.#15.station.@%u", i + 1);
        DMSG("[get-all-entry] %s.ekey = " MCM_DTYPE_EK_PF, path2, station_v[i].ekey);
        DMSG("[get-all-entry] %s.mac_addr = " MCM_DTYPE_S_PF, path2, station_v[i].mac_addr);
        DMSG("[get-all-entry] %s.rule = " MCM_DTYPE_RK_PF, path2, station_v[i].rule);
    }
    kfree(station_v);

FREE_02:
    mcm_lklib_exit(&self_lklib);
FREE_01:
    return 0;
}

static void __exit main_exit(
    void)
{
    return;
}

module_init(main_init);
module_exit(main_exit);

MODULE_LICENSE("GPL");

mcm_lklib_del_all_entry
刪除所有 entry.
參數 說明
struct mcm_lklib_lib_t *
this_lklib
紀錄 mcm_lklib_api 所需要的資料
char *
mix_path
目標的路徑 [詳細]
[index / key 模式]
回傳 說明
>= MCM_RCODE_PASS 成功
 < MCM_RCODE_PASS
(MCM_RCODE_CONFIG_NOT_FIND_STORE)
錯誤, 目標 entry 不存在
 < MCM_RCODE_PASS
(other)
錯誤, 其他錯誤

注意事項 :
01.  資料存取模式必須是 MCM_SPERMISSION_RW.

範例 :
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/random.h>
#include "mcm_lib/mcm_lheader/mcm_type.h"
#include "mcm_lib/mcm_lheader/mcm_size.h"
#include "mcm_lib/mcm_lheader/mcm_connect.h"
#include "mcm_lib/mcm_lheader/mcm_return.h"
#include "mcm_lib/mcm_lheader/mcm_data_exinfo_auto.h"
#include "mcm_lib/mcm_lklib/mcm_lklib_api.h"

#define DMSG(msg_fmt, msgs...) \
    printk(KERN_INFO "%s(%04u): " msg_fmt "\n", \
           strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__, __LINE__, ##msgs)

static int __init main_init(
    void)
{
    char *path1;
    struct mcm_lklib_lib_t self_lklib;

    self_lklib.socket_path = "@mintcm";
    self_lklib.call_from = MCM_CFROM_KERNEL;
    self_lklib.session_permission = MCM_SPERMISSION_RW;
    self_lklib.session_stack_size = 0;
    if(mcm_lklib_init(&self_lklib) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_init() fail");
        goto FREE_01;
    }

    // 修改資料後可以開啟 mint_cm/run/mcm_store_profile_current.txt 確認數值.

    // 範例 : 刪除所有的 device.vap.@1.station.*
    // 路徑 : "device.vap.@1.station.*"
    path1 = "device.vap.@1.station.*";
    DMSG("[del-all-entry] %s", path1);
    if(mcm_lklib_del_all_entry(&self_lklib, path1) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_del_all_entry(%s) fail", path1);
        goto FREE_02;
    }

    // 範例 : 刪除所有的 device.vap.#15.station.*
    // 路徑 : "device.vap.#15.station.*"
    path1 = "device.vap.#15.station.*";
    DMSG("[del-all-entry] %s", path1);
    if(mcm_lklib_del_all_entry(&self_lklib, path1) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_del_all_entry(%s) fail", path1);
        goto FREE_02;
    }

    // 範例 : 刪除所有的 device.limit.*
    // 路徑 : "device.limit.*"
    path1 = "device.limit.*";
    DMSG("[del-all-entry] %s", path1);
    if(mcm_lklib_del_all_entry(&self_lklib, path1) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_del_all_entry(%s) fail", path1);
        goto FREE_02;
    }

FREE_02:
    mcm_lklib_exit(&self_lklib);
FREE_01:
    return 0;
}

static void __exit main_exit(
    void)
{
    return;
}

module_init(main_init);
module_exit(main_exit);

MODULE_LICENSE("GPL");

mcm_lklib_get_usable_key
取得可用的 key.
參數 說明
struct mcm_lklib_lib_t *
this_lklib
紀錄 mcm_lklib_api 所需要的資料
char *
mix_path
目標的路徑 [詳細]
[index / key 模式]
MCM_DTYPE_EK_TD *
key_buf
紀錄可用的 key 的緩衝
回傳 說明
>= MCM_RCODE_PASS 成功
 < MCM_RCODE_PASS
(MCM_RCODE_CONFIG_NOT_FIND_STORE)
錯誤, 目標 entry 不存在
 < MCM_RCODE_PASS
(other)
錯誤, 其他錯誤

注意事項 :
01.  資料存取模式可以是 MCM_SPERMISSION_RO 或 MCM_SPERMISSION_RW.
02.  key_buf 返回的值大於 0 才表示有可用的 key.

範例 :
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/random.h>
#include "mcm_lib/mcm_lheader/mcm_type.h"
#include "mcm_lib/mcm_lheader/mcm_size.h"
#include "mcm_lib/mcm_lheader/mcm_connect.h"
#include "mcm_lib/mcm_lheader/mcm_return.h"
#include "mcm_lib/mcm_lheader/mcm_data_exinfo_auto.h"
#include "mcm_lib/mcm_lklib/mcm_lklib_api.h"

#define DMSG(msg_fmt, msgs...) \
    printk(KERN_INFO "%s(%04u): " msg_fmt "\n", \
           strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__, __LINE__, ##msgs)

static int __init main_init(
    void)
{
    char *path1;
    struct mcm_lklib_lib_t self_lklib;
    MCM_DTYPE_EK_TD key;

    self_lklib.socket_path = "@mintcm";
    self_lklib.call_from = MCM_CFROM_KERNEL;
    self_lklib.session_permission = MCM_SPERMISSION_RO;
    self_lklib.session_stack_size = 0;
    if(mcm_lklib_init(&self_lklib) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_init() fail");
        goto FREE_01;
    }

    // 要增加 entry 時, 需要不能重複的 key,
    // 如果不知道如何分配 key, 可用此函式取得可用的 key.

    // 範例 : 取得 device.vap.* 內可用的 key.
    // 路徑 : "device.vap.*"
    path1 = "device.vap.*";
    if(mcm_lklib_get_usable_key(&self_lklib, path1, &key) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_get_usable_key(%s) fail", path1);
        goto FREE_02;
    }
    if(key == 0)
    {
        DMSG("[usable-key] %s = entry is full", path1);
    }
    else
    {
        DMSG("[usable-key] %s = " MCM_DTYPE_EK_PF, path1, key);
    }

FREE_02:
    mcm_lklib_exit(&self_lklib);
FREE_01:
    return 0;
}

static void __exit main_exit(
    void)
{
    return;
}

module_init(main_init);
module_exit(main_exit);

MODULE_LICENSE("GPL");

mcm_lklib_run
執行 mint_cm/mcm_daemon/mcm_module 內的模組函式.
參數 說明
struct mcm_lklib_lib_t *
this_lklib
紀錄 mcm_lklib_api 所需要的資料
char *
module_function
目標的函式名稱
void *
req_data_con
要傳給模組函式的資料
可為 NULL, 表示不傳送資料給模組函式
MCM_DTYPE_USIZE_TD
req_data_len
要傳給模組函式的資料的長度
若 req_data_con 是 NULL 則為 0
void **
rep_data_buf
紀錄模組函式回傳的資料的變數的緩衝
內部函式會配置記憶體空間並放入資料, 使用完需要釋放, 傳入參數需要做強制轉型 (void **)
可為 NULL, 表示不接收模組函式回傳的資料
MCM_DTYPE_USIZE_TD *
rep_data_len_buf
紀錄模組函式回傳的資料的長度的變數的緩衝
如果 rep_data_buf 是 NULL 則不會紀錄資料長度
可為 NULL, 表示不記錄資料長度
回傳 說明
>= MCM_RCODE_PASS 成功
 < MCM_RCODE_PASS 錯誤

注意事項 :
01.  如果內部模組函式只需要讀取資料, 資料存取模式可以是 MCM_SPERMISSION_RO 或 MCM_SPERMISSION_RW, 如果內部模組函式需要修改資料, 資料存取模必須是 MCM_SPERMISSION_RW.
02.  因為內部模組函式的內容是客制化的, 所以需要的堆疊空間不固定 (區域變數的多寡和函式呼叫的層數都會影響需要的堆疊空間), 透過 session_stack_size 調整伺服器端處理此連線的執行緒的堆疊空間.
03.  和內部模組函式的資料傳遞的用法會在 #05-01#, #05-03# 說明.

範例 :
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/random.h>
#include "mcm_lib/mcm_lheader/mcm_type.h"
#include "mcm_lib/mcm_lheader/mcm_size.h"
#include "mcm_lib/mcm_lheader/mcm_connect.h"
#include "mcm_lib/mcm_lheader/mcm_return.h"
#include "mcm_lib/mcm_lheader/mcm_data_exinfo_auto.h"
#include "mcm_lib/mcm_lklib/mcm_lklib_api.h"

#define DMSG(msg_fmt, msgs...) \
    printk(KERN_INFO "%s(%04u): " msg_fmt "\n", \
           strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__, __LINE__, ##msgs)

static int __init main_init(
    void)
{
    char *path1;
    struct mcm_lklib_lib_t self_lklib;

    self_lklib.socket_path = "@mintcm";
    self_lklib.call_from = MCM_CFROM_KERNEL;
    self_lklib.session_permission = MCM_SPERMISSION_RO;
    self_lklib.session_stack_size = 1048576;
    if(mcm_lklib_init(&self_lklib) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_init() fail");
        goto FREE_01;
    }

    // 範例 : 執行 mcm_module_kernel_test_01 此函式.
    path1 = "mcm_module_kernel_test_01";
    DMSG("[run] %s", path1);
    if(mcm_lklib_run(&self_lklib, path1, NULL, 0, NULL, NULL) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_run(%s) fail", path1);
        goto FREE_02;
    }

FREE_02:
    mcm_lklib_exit(&self_lklib);
FREE_01:
    return 0;
}

static void __exit main_exit(
    void)
{
    return;
}

module_init(main_init);
module_exit(main_exit);

MODULE_LICENSE("GPL");

模組部分 :
這部分程式要放在 mint_cm/mcm_daemon/mcm_module 之下, 檔案名稱隨意 (*.c),
之後在 mint_cm 使用 make all 重新編譯.

#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include "mcm_lib/mcm_lheader/mcm_type.h"
#include "mcm_lib/mcm_lheader/mcm_size.h"
#include "mcm_lib/mcm_lheader/mcm_control.h"
#include "mcm_lib/mcm_lheader/mcm_connect.h"
#include "mcm_lib/mcm_lheader/mcm_return.h"
#include "mcm_lib/mcm_lheader/mcm_debug.h"
#include "mcm_lib/mcm_lheader/mcm_data_exinfo_auto.h"
#include "../mcm_service_handle_define.h"
#include "../mcm_config_handle_extern.h"

#define DMSG(msg_fmt, msgs...) printf("%s(%04u): " msg_fmt "\n", __FILE__, __LINE__, ##msgs)

int mcm_module_kernel_test_01(
    struct mcm_service_session_t *this_session)
{
    srand(time(NULL));

    DMSG("module-%u", rand());

    return MCM_RCODE_PASS;
}

mcm_lklib_update
要求資料庫做資料更新.
參數 說明
struct mcm_lklib_lib_t *
this_lklib
紀錄 mcm_lklib_api 所需要的資料
回傳 說明
>= MCM_RCODE_PASS 成功
 < MCM_RCODE_PASS 錯誤

此功能只有在特殊情況才需要.

程式修改資料時, mcm_daemon 的大致處理步驟 :
01.  程式呼叫 mcm_lklib_init() 取得使用權.
02.  程式修改資料.
03.  mcm_daemon 會把修改的資料放到資料庫的新進資料區 (原始的資料是放在資料庫的系統資料區).
04.  程式呼叫內部模組處理修改的資料.
05.  程式使用完畢, 呼叫 mcm_lklib_exit() 釋放使用權.
06.  mcm_daemon 根據最後一次的執行結果決定如何處理修改的資料.
成功: 將所做的修改套用回資料庫.
失敗: 放棄所做的修改.

如果在 [02] 時候做刪除資料, 接著在 [04] 之後讀取被刪除的資料, 照理說應該要讀不到資料, 但是因為資料在 [06] 才會套用回系統資料區, 所以實際上是能夠讀到資料的, 此函式就是要求 mcm_daemon 馬上做 [06] 的處理, 避免發生此問題.

注意事項 :
01.  資料存取模式必須是 MCM_SPERMISSION_RW.

範例 :
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/random.h>
#include "mcm_lib/mcm_lheader/mcm_type.h"
#include "mcm_lib/mcm_lheader/mcm_size.h"
#include "mcm_lib/mcm_lheader/mcm_connect.h"
#include "mcm_lib/mcm_lheader/mcm_return.h"
#include "mcm_lib/mcm_lheader/mcm_data_exinfo_auto.h"
#include "mcm_lib/mcm_lklib/mcm_lklib_api.h"

#define DMSG(msg_fmt, msgs...) \
    printk(KERN_INFO "%s(%04u): " msg_fmt "\n", \
           strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__, __LINE__, ##msgs)

static int __init main_init(
    void)
{
    char *path1;
    struct mcm_lklib_lib_t self_lklib;
    MCM_DTYPE_EK_TD count;

    self_lklib.socket_path = "@mintcm";
    self_lklib.call_from = MCM_CFROM_KERNEL;
    self_lklib.session_permission = MCM_SPERMISSION_RW;
    self_lklib.session_stack_size = 0;
    if(mcm_lklib_init(&self_lklib) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_init() fail");
        goto FREE_01;
    }

    // 範例 :
    // 1. 刪除 device.limit.* 所有資料.
    // 2. 取得 device.limit.* 的資料筆數, 應該要是 0, 但是資料庫尚未更新,
    //    這時還是讀的到資料.
    // 3. 更新資料庫.
    // 4. 取得 device.limit.* 的資料筆數, 這時就會是 0.

    // 1. 刪除所有的 device.limit.*
    path1 = "device.limit.*";
    DMSG("[del-all-entry] %s", path1);
    if(mcm_lklib_del_all_entry(&self_lklib, path1) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_del_all_entry(%s) fail", path1);
        goto FREE_02;
    }

    // 2. 取得 device.limit.* 的資料筆數, 應該要是 0, 但是資料庫尚未更新,
    //    這時還是讀的到資料.
    path1 = "device.limit.*";
    if(mcm_lklib_get_count(&self_lklib, path1, &count) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_get_count(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[count (before)] %s = " MCM_DTYPE_EK_PF, path1, count);

    // 3. 更新資料庫.
    DMSG("[update]");
    if(mcm_lklib_update(&self_lklib) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_update() fail");
        goto FREE_02;
    }

    // 4. 取得 device.limit.* 的資料筆數, 這時就會是是 0.
    path1 = "device.limit.*";
    if(mcm_lklib_get_count(&self_lklib, path1, &count) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_get_count(%s) fail", path1);
        goto FREE_02;
    }
    DMSG("[count (after)] %s = " MCM_DTYPE_EK_PF, path1, count);

FREE_02:
    mcm_lklib_exit(&self_lklib);
FREE_01:
    return 0;
}

static void __exit main_exit(
    void)
{
    return;
}

module_init(main_init);
module_exit(main_exit);

MODULE_LICENSE("GPL");

mcm_lklib_save
要求 mcm_daemon 儲存資料到資料現在值檔案.
參數 說明
struct mcm_lklib_lib_t *
this_lklib
紀錄 mcm_lklib_api 所需要的資料
MCM_DTYPE_BOOL_TD
force_save
是否強制要求儲存資料
0 : 否, 有需要儲存的資料被修改才儲存
1 : 是, 不論有無修改都要儲存
回傳 說明
>= MCM_RCODE_PASS 成功
 < MCM_RCODE_PASS 錯誤

注意事項 :
01.  資料存取模式必須是 MCM_SPERMISSION_RW.

範例 :
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/random.h>
#include "mcm_lib/mcm_lheader/mcm_type.h"
#include "mcm_lib/mcm_lheader/mcm_size.h"
#include "mcm_lib/mcm_lheader/mcm_connect.h"
#include "mcm_lib/mcm_lheader/mcm_return.h"
#include "mcm_lib/mcm_lheader/mcm_data_exinfo_auto.h"
#include "mcm_lib/mcm_lklib/mcm_lklib_api.h"

#define DMSG(msg_fmt, msgs...) \
    printk(KERN_INFO "%s(%04u): " msg_fmt "\n", \
           strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__, __LINE__, ##msgs)

static int __init main_init(
    void)
{
    struct mcm_lklib_lib_t self_lklib;
    MCM_DTYPE_BOOL_TD force_save = 1;

    self_lklib.socket_path = "@mintcm";
    self_lklib.call_from = MCM_CFROM_KERNEL;
    self_lklib.session_permission = MCM_SPERMISSION_RW;
    self_lklib.session_stack_size = 0;
    if(mcm_lklib_init(&self_lklib) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_init() fail");
        goto FREE_01;
    }

    DMSG("[save] %s", force_save == 0 ? "check" : "force");
    if(mcm_lklib_save(&self_lklib, force_save) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_save() fail");
        goto FREE_02;
    }

FREE_02:
    mcm_lklib_exit(&self_lklib);
FREE_01:
    return 0;
}

static void __exit main_exit(
    void)
{
    return;
}

module_init(main_init);
module_exit(main_exit);

MODULE_LICENSE("GPL");

mcm_lklib_shutdown
關閉 mcm_daemon, 當系統需要關機或重開機時先讓 mcm_daemon 正常關閉.
參數 說明
struct mcm_lklib_lib_t *
this_lklib
紀錄 mcm_lklib_api 所需要的資料
回傳 說明
>= MCM_RCODE_PASS 成功
 < MCM_RCODE_PASS 錯誤

注意事項 :
01.  資料存取模式必須是 MCM_SPERMISSION_RW.
02.  使用後並不會馬上關閉, 要等到 mcm_lklib_exit() 之後才會關閉.

範例 :
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/random.h>
#include "mcm_lib/mcm_lheader/mcm_type.h"
#include "mcm_lib/mcm_lheader/mcm_size.h"
#include "mcm_lib/mcm_lheader/mcm_connect.h"
#include "mcm_lib/mcm_lheader/mcm_return.h"
#include "mcm_lib/mcm_lheader/mcm_data_exinfo_auto.h"
#include "mcm_lib/mcm_lklib/mcm_lklib_api.h"

#define DMSG(msg_fmt, msgs...) \
    printk(KERN_INFO "%s(%04u): " msg_fmt "\n", \
           strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__, __LINE__, ##msgs)

static int __init main_init(
    void)
{
    struct mcm_lklib_lib_t self_lklib;

    self_lklib.socket_path = "@mintcm";
    self_lklib.call_from = MCM_CFROM_KERNEL;
    self_lklib.session_permission = MCM_SPERMISSION_RW;
    self_lklib.session_stack_size = 0;
    if(mcm_lklib_init(&self_lklib) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_init() fail");
        goto FREE_01;
    }

    DMSG("[shutdown]");
    if(mcm_lklib_shutdown(&self_lklib) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_shutdown() fail");
        goto FREE_02;
    }

FREE_02:
    mcm_lklib_exit(&self_lklib);
FREE_01:
    return 0;
}

static void __exit main_exit(
    void)
{
    return;
}

module_init(main_init);
module_exit(main_exit);

MODULE_LICENSE("GPL");


函式的混合使用

在實際情況下, 函式需要混合使用來完成工作, 這邊說明如何使用以及使用的時機.

方便說明, 左邊的函式使用右邊的簡稱 :
mcm_lklib_get_count get
mcm_lklib_get_alone
mcm_lklib_get_entry
mcm_lklib_get_all_entry
mcm_lklib_set_alone set
mcm_lklib_set_entry
mcm_lklib_add_entry add
mcm_lklib_del_entry del
mcm_lklib_delall_entry_value
mcm_lklib_run run

在取值的情況

使用的時機 :
要取得的資料必須先從系統中取出, 再放到資料庫中供讀取. [詳細]

使用方式 :
01.  使用 [run] 執行內部模組, 並在模組函式中實作將資料從系統中取出放到資料庫的部分.
02.  使用 [get] 取出資料.

範例 :
// 執行 module_get_loading(), 取得 device.system.loading
path1 = "module_get_loading";
mcm_lklib_run(&self_lklib, path1, NULL, 0, NULL, NULL);
path1 = "device.system.loading";
mcm_lklib_get_alone(&self_lklib, path1, &loading);

// 執行 mcm_module_get_client(), 取得 device.client.*
path1 = "mcm_module_get_client";
mcm_lklib_run(&self_lklib, path1, NULL, 0, NULL, NULL);
path1 = device.client.*;
mcm_lklib_get_all_entry(&self_lklib, path1, &client_v, &count);

...

注意事項 :
01.  可以使用多個 [run] 分別處理不同種類的資料, 也可以只使用一個 [run] 處理全部的資料.

在設值的情況

使用的時機 :
資料送入資料庫後, 需要用這些資料對系統做實際的設定. [詳細]

使用方式 :
01.  使用 [set] [add] [del] 修改資料.
02.  使用 [run] 執行內部模組, 並在模組函式中實作將修改的資料套用到系統的部分.

範例程式 :
// 設定 device.system.ip_addr, 執行 module_config_sytem 實作.
path1 = "device.system.ip_addr";
mcm_lklib_set_alone(&self_lklib, path1, &ip_addr, sizeof(ip_addr));
path1 = "module_config_sytem";
mcm_lklib_run(&self_lklib, path1, NULL, 0, NULL, NULL);

// 設定 device.vap.@1, 執行 module_config_vap 實作.
path1 = "device.vap.@1";
mcm_lklib_set_entry(&self_lklib, path1, &vap_v, sizeof(vap_v));

// 刪除 device.vap.#15, 執行 module_config_vap 實作.
path1 = "device.vap.#15";
mcm_lklib_del_entry(&self_lklib, path1);

// 增加 device.vap.#55, 執行 module_config_vap 實作.
path1 = "device.vap.#55";
mcm_lklib_add_entry(&self_lklib, path1, NULL, &vap_v, sizeof(vap_v));

path1 = "module_config_vap";
mcm_lklib_run(&self_lklib, path1, NULL, 0, NULL, NULL);

...

注意事項 :
01.  可以使用多個 [run] 分別處理不同種類的資料, 也可以只使用一個 [run] 處理全部的資料.

後續的章節會說明在內部模組中如何存取資料.


封裝的函式

mcm_lklib_do_...
此類函式是 mcm_lklib_init, mcm_lklib_..., mcm_lklib_exit 的封裝, 如果只需要處理一件事情可使用此類函式.

mcm_lklib_do_get_max_count
等同 mcm_lklib_get_max_count
mcm_lklib_do_get_count
等同 mcm_lklib_get_count
mcm_lklib_do_get_alone
等同 mcm_lklib_get_alone
mcm_lklib_do_set_alone
等同 mcm_lklib_set_alone
mcm_lklib_do_get_entry
等同 mcm_lklib_get_entry
mcm_lklib_do_set_entry
等同 mcm_lklib_set_entry
mcm_lklib_do_add_entry
等同 mcm_lklib_add_entry
mcm_lklib_do_del_entry
等同 mcm_lklib_del_entry
mcm_lklib_do_check_exist
等同 mcm_lklib_check_exist
mcm_lklib_do_get_all_key
等同 mcm_lklib_get_all_key
mcm_lklib_do_get_all_entry
等同 mcm_lklib_get_all_entry
mcm_lklib_do_del_all_entry
等同 mcm_lklib_del_all_entry
mcm_lklib_do_get_usable_key
等同 mcm_lklib_get_usable_key
mcm_lklib_do_run
等同 mcm_lklib_run
mcm_lklib_do_update
等同 mcm_lklib_update
mcm_lklib_do_save
等同 mcm_lklib_save
mcm_lklib_do_shutdown
等同 mcm_lklib_shutdown

範例 :
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/random.h>
#include "mcm_lib/mcm_lheader/mcm_type.h"
#include "mcm_lib/mcm_lheader/mcm_size.h"
#include "mcm_lib/mcm_lheader/mcm_connect.h"
#include "mcm_lib/mcm_lheader/mcm_return.h"
#include "mcm_lib/mcm_lheader/mcm_data_exinfo_auto.h"
#include "mcm_lib/mcm_lklib/mcm_lklib_api.h"

#define DMSG(msg_fmt, msgs...) \
    printk(KERN_INFO "%s(%04u): " msg_fmt "\n", \
           strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__, __LINE__, ##msgs)

static int __init main_init(
    void)
{
    char *path1, path2[MCM_PATH_MAX_LENGTH];
    struct mcm_lklib_lib_t self_lklib;
    struct mcm_dv_device_vap_t vap_v;
    MCM_DTYPE_EK_TD count, i;
    MCM_DTYPE_FD_TD loading;
    MCM_DTYPE_S_TD descript[MCM_BSIZE_DEVICE_DESCRIPT];

    self_lklib.socket_path = "@mintcm";
    self_lklib.call_from = MCM_CFROM_KERNEL;
    self_lklib.session_permission = MCM_SPERMISSION_RO;
    self_lklib.session_stack_size = 0;

    // 範例 : 取得 device.limit.* 的資料筆數上限.
    path1 = "device.limit.*";
    if(mcm_lklib_do_get_max_count(&self_lklib, path1, &count) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_get_max_count(%s) fail", path1);
        goto FREE_01;
    }
    DMSG("[max-count] %s = " MCM_DTYPE_EK_PF, path1, count);

    // 範例 : 讀出 device.system.loading
    path1 = "device.system.loading";
    if(mcm_lklib_do_get_alone(&self_lklib, path1, &loading) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_get_alone(%s) fail", path1);
        goto FREE_01;
    }
    DMSG("[get-alone] %s = " MCM_DTYPE_FD_PF, path1, loading);

    // 做修改的動作, 先把資料存取模式改為 rw.
    self_lklib.session_permission = MCM_SPERMISSION_RW;

    // 範例 : 設定 device.descript
    path1 = "device.descript";
    snprintf(descript, sizeof(descript), "network-device-123");
    DMSG("[set-alone] %s = " MCM_DTYPE_S_PF, path1, descript);
    if(mcm_lklib_do_set_alone(&self_lklib, path1, descript, strlen(descript)) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_set_alone(%s) fail", path1);
        goto FREE_01;
    }

    // 做完修改的動作, 可以把資料存取模式改為 ro.
    self_lklib.session_permission = MCM_SPERMISSION_RO;

    // 範例 : 取得 device.vap.* 的資料筆數.
    path1 = "device.vap.*";
    if(mcm_lklib_do_get_count(&self_lklib, path1, &count) < MCM_RCODE_PASS)
    {
        DMSG("call mcm_lklib_get_max_count(%s) fail", path1);
        goto FREE_01;
    }
    DMSG("[count] %s = " MCM_DTYPE_EK_PF, path1, count);

    // 範例 : 讀出每一筆 device.vap.*
    for(i = 0; i < count; i++)
    {
        snprintf(path2, sizeof(path2), "device.vap.@%u", i + 1);
        if(mcm_lklib_do_get_entry(&self_lklib, path2, &vap_v) < MCM_RCODE_PASS)
        {
            DMSG("call mcm_lklib_get_entry(%s) fail", path2);
            goto FREE_01;
        }
        DMSG("[get-entry] %s.ekey = " MCM_DTYPE_EK_PF, path2, vap_v.ekey);
        DMSG("[get-entry] %s.ssid = " MCM_DTYPE_S_PF, path2, vap_v.ssid);
        DMSG("[get-entry] %s.channel = " MCM_DTYPE_IUI_PF, path2, vap_v.channel);
    }

    // 其他 mcm_lklib_do_xxxx() 函式.

FREE_01:
    return 0;
}

static void __exit main_exit(
    void)
{
    return;
}

module_init(main_init);
module_exit(main_exit);

MODULE_LICENSE("GPL");



注意事項

如果函式回傳的值小於 MCM_RCODE_PASS 的話, mcm_daemon 會結束連線並啟動恢復資料的動作 [詳細][06], 在 mcm_lklib_init() 和 mcm_lklib_exit() 期間所做的資料修改 (設定/增加/刪除) 都會廢棄並還原到修改前的資料. (如果有使用 mcm_lklib_update() 的話, 在呼叫 mcm_lklib_update() 之前的資料會保留)


如果要透過修改設定資料檔案來做讀取測試的話, 步驟 :
先關閉 mcm_daemon (有在執行的話), 修改設定值檔案, 重新執行 mcm_daemon.
修改設定值檔案有二個方法 :
初始值檔案
mcm_store_profile_default.txt
因為 mcm_daemon 會先讀取現在值檔案, 不存在才讀取初始值檔, 所以每次改好後執行 mcm_daemon 之前要先將現在值檔案刪除.
檔案內容格式 [詳細]
現在值檔案
mcm_store_profile_current.txt
檔案內容格式和初始值檔案相同 [詳細]

使用 [set] [add] [del] [delall] 操作後, 只要該 group 在資料模型中的 $(save) 為 1, 資料就會在 mcm_lklib_exit() 後寫現在值的檔案, 所以除了使用列印的方式觀察之外也可以直接看檔案內容.


範例程式的使用

01.  範例程式目錄在 mint_cm/usage/example/0303.


02.  下面關於 make 的操作沒有特別註明的話都是在 mint_cm 目錄.


03.  第一次使用, 使用 make example_add KEY=0303 載入範例並編譯.


04.  kernel_app/kernel_app_0303 是範例程式,
必須先在目錄內使用 make all 進行編譯.

使用方式 :
echo <test_item> > /proc/kernel_app_0303
<test_item> 列表 :
max-count mcm_lklib_get_max_count() 範例
count mcm_lklib_get_count() 範例
get-alone mcm_lklib_get_alone() 範例
set-alone mcm_lklib_set_alone() 範例
get-entry mcm_lklib_get_entry() 範例
set-entry mcm_lklib_set_entry() 範例
add-entry mcm_lklib_add_entry() 範例
del-entry mcm_lklib_del_entry() 範例
check-exist mcm_lklib_check_exist() 範例
get-all-key mcm_lklib_get_all_key() 範例
get-all-entry mcm_lklib_get_all_entry() 範例
del-all-entry mcm_lklib_del_all_entry() 範例
run mcm_lklib_run() 範例
update-store mcm_lklib_update() 範例
shutdown mcm_lklib_shutdown() 範例


05.  先載入 mcm_lklib_api.ko, 接著執行 mcm_daemon, 再載入 kernel_app_0303 做測試.


06.  測試完畢不使用後, 使用 make example_del KEY=0303 將範例移除.


07.  範例程式目錄下的檔案在做完 make example_add 後會複製到真正使用的位置, 要修改做測試的話要改在複製後的.
來源 profile/mcm_data_profile_0303.xml
目地 mint_cm/mcm_build/mcm_data_profile.xml
資料模型範例
有修改要使用 make all 重新編譯
來源 profile/mcm_store_profile_default_0303.txt
目地 mint_cm/mcm_build/mcm_store_profile_default.txt
資料預設值範例
使用 make all 後會再複製到 mint_cm/run
來源 module/mcm_module_0303.c
目地 mint_cm/mcm_daemon/mcm_module
搭配 mcm_lklib_run() 使用的內部模組範例
有修改要使用 make all 重新編譯