GLDv3 は、MAC_PLUGIN_IDENT_ETHER タイプのプラグインに登録するドライバ用のドライバ API を定義します。
GLDv3 デバイスドライバは、次の手順を実行して MAC 層に登録する必要があります。
sys/mac_ether.h、sys/mac_provider.h の 2 つの MAC ヘッダーファイルをインクルードします。その他の MAC 関連ヘッダーファイルはドライバにインクルードしないでください。
mac_callbacks 構造体を生成します。
mac_init_ops() 関数をその _init() エントリポイントで呼び出します。
mac_alloc() 関数をその attach() エントリポイントで呼び出し、mac_register 構造体を割り当てます。
mac_register 構造体を生成し、mac_register() 関数をその attach() エントリポイントで呼び出します。
mac_unregister() 関数をその detach() エントリポイントで呼び出します。
mac_fini_ops() 関数をその _fini() エントリポイントで呼び出します。
misc/mac への依存性とリンクします。
# ld -N"misc/mac" xx.o -o xx
GLDv3 インタフェースには、MAC 層への登録中に通知されるドライバエントリポイントと、ドライバによって呼び出される MAC エントリポイントが含まれています。
void mac_init_ops(struct dev_ops *ops, const char *name);
GLDv3 デバイスドライバは mod_install(9F) を呼び出す前に、mac_init_ops(9F) 関数をその _init(9E) エントリポイントで呼び出す必要があります。
void mac_fini_ops(struct dev_ops *ops);
GLDv3 デバイスドライバは mod_remove(9F) を呼び出したあとに、mac_fini_ops(9F) 関数をその _fini(9E) エントリポイントで呼び出す必要があります。
使用例 19-1 mac_init_ops() および mac_fini_ops() 関数int
_init(void)
{
int rv;
mac_init_ops(&xx_devops, "xx");
if ((rv = mod_install(&xx_modlinkage)) != DDI_SUCCESS) {
mac_fini_ops(&xx_devops);
}
return (rv);
}
int
_fini(void)
{
int rv;
if ((rv = mod_remove(&xx_modlinkage)) == DDI_SUCCESS) {
mac_fini_ops(&xx_devops);
}
return (rv);
}
mac_register_t *mac_alloc(uint_t version);
mac_alloc(9F) 関数は新しい mac_register 構造体を割り当て、この構造体へのポインタを返します。新しい構造体を mac_register() に渡す前に構造体のメンバーを初期化してください。mac_alloc() が戻る前に、MAC 専用要素が MAC 層によって初期化されます。version の値は MAC_VERSION_V1 である必要があります。
void mac_free(mac_register_t *mregp);
mac_free(9F) 関数は、以前に mac_alloc() によって割り当てられた mac_register 構造体を解放します。
int mac_register(mac_register_t *mregp, mac_handle_t *mhp);
新しいインスタンスを MAC 層に登録するために、GLDv3 ドライバは mac_register(9F) 関数をその attach (9E) エントリポイントで呼び出す必要があります。mregp 引数は、mac_register 登録情報構造体へのポインタです。成功した場合、mhp 引数は新しい MAC インスタンスの MAC ハンドルへのポインタです。このハンドルは、mac_tx_update()、mac_link_update()、mac_rx() などのほかのルーチンで必要になります。
使用例 19-2 mac_alloc()、mac_register()、および mac_free() 関数と mac_register 構造体int
xx_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
{
mac_register_t *macp;
/* ... */
if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
xx_error(dip, "mac_alloc failed");
goto failed;
}
macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
macp->m_driver = xxp;
macp->m_dip = dip;
macp->m_src_addr = xxp->xx_curraddr;
macp->m_callbacks = &xx_m_callbacks;
macp->m_min_sdu = 0;
macp->m_max_sdu = ETHERMTU;
macp->m_margin = VLAN_TAGSZ;
if (mac_register(macp, &xxp->xx_mh) == DDI_SUCCESS) {
mac_free(macp);
return (DDI_SUCCESS);
}
/* failed to register with MAC */
mac_free(macp);
failed:
/* ... */
}
int mac_unregister(mac_handle_t mh);
mac_unregister(9F) 関数は、以前に mac_register() によって登録された MAC インスタンスを登録解除します。mh 引数は、mac_register() によって割り当てられた MAC ハンドルです。mac_unregister() は detach (9E) エントリポイントから呼び出してください。
使用例 19-3 mac_unregister() 関数int
xx_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
{
xx_t *xxp; /* driver soft state */
/* ... */
switch (cmd) {
case DDI_DETACH:
if (mac_unregister(xxp->xx_mh) != 0) {
return (DDI_FAILURE);
}
/* ... */
}
このセクションで説明する構造体は、sys/mac_provider.h ヘッダーファイルで定義されます。sys/mac_ether.h および sys/mac_provider.h MAC ヘッダーファイルを GLDv3 ドライバにインクルードします。その他の MAC 関連ヘッダーファイルはインクルードしないでください。
mac_register (9S) データ構造体は、mac_alloc() によって割り当てられ、mac_register() に渡される MAC 登録情報構造体です。新しい構造体を mac_register() に渡す前に構造体のメンバーを初期化してください。mac_alloc() が戻る前に、MAC 専用要素が MAC 層によって初期化されます。構造体の m_version メンバーは MAC バージョンです。MAC バージョンを変更しないでください。構造体の m_type_ident メンバーは MAC タイプ識別子です。MAC タイプ識別子は MAC_PLUGIN_IDENT_ETHER に設定してください。mac_register 構造体の m_callbacks メンバーは、mac_callbacks 構造体のインスタンスへのポインタです。
mac_callbacks(9S) データ構造体は、デバイスドライバがそのエントリポイントを MAC 層に公開するために使用する構造体です。これらのエントリポイントは、ドライバを制御するために MAC 層によって使用されます。これらのエントリポイントは、アダプタの起動と停止、マルチキャストアドレスの管理、プロミスキュアス (promiscuous) モードの設定、アダプタの機能の照会、プロパティーの取得と設定などのタスクを実行するために使用されます。すべての必須およびオプション GLDv3 エントリポイントの一覧については、Table 19–1 を参照してください。mac_register 構造体の m_callbacks フィールドには、mac_callbacks 構造体へのポインタを指定します。
mac_callbacks 構造体の mc_callbacks メンバーは、次のフラグを組み合わせたビットマスクであり、ドライバで実装されるオプションエントリポイントを指定します。mac_callbacks 構造体のほかのメンバーは、ドライバの各エントリポイントへのポインタです。
mc_ioctl() エントリポイントが存在します。
mc_getcapab() エントリポイントが存在します。
mc_setprop() エントリポイントが存在します。
mc_getprop() エントリポイントが存在します。
mc_propinfo() エントリポイントが存在します。
すべてのプロパティーエントリポイントが存在します。MC_PROPERTIES を設定すると、MC_SETPROP、MC_GETPROP、および MC_PROPINFO の 3 つのフラグすべてを設定したことになります。
#define XX_M_CALLBACK_FLAGS \
(MC_IOCTL | MC_GETCAPAB | MC_PROPERTIES)
static mac_callbacks_t xx_m_callbacks = {
XX_M_CALLBACK_FLAGS,
xx_m_getstat, /* mc_getstat() */
xx_m_start, /* mc_start() */
xx_m_stop, /* mc_stop() */
xx_m_promisc, /* mc_setpromisc() */
xx_m_multicst, /* mc_multicst() */
xx_m_unicst, /* mc_unicst() */
xx_m_tx, /* mc_tx() */
NULL, /* Reserved, do not use */
xx_m_ioctl, /* mc_ioctl() */
xx_m_getcapab, /* mc_getcapab() */
NULL, /* Reserved, do not use */
NULL, /* Reserved, do not use */
xx_m_setprop, /* mc_setprop() */
xx_m_getprop, /* mc_getprop() */
xx_m_propinfo /* mc_propinfo() */
};