EN JA
NG_PPPOE(4)
NG_PPPOE(4) FreeBSD Kernel Interfaces Manual NG_PPPOE(4)

名称

ng_pppoeRFC 2516 PPPoE プロトコル netgraph ノードタイプ

書式

#include < sys/types.h>
#include < net/ethernet.h>
#include < netgraph.h>
#include < netgraph/ng_pppoe.h>

解説

pppoe ノードタイプは、PPPoE プロトコルを実行します。それは、(指定されない) PPP エージェントのやりとりをイーサネットパケットを流用して投入するためにイーサネットフレームワークへの netgraph(4) 拡張と連動して使用されます。

NGM_PPPOE_GET_STATUS コントロールメッセージは、 PPPOE モジュールの現在の状態を問い合わせるためにいつでも使用することができます。現在利用可能な唯一の統計値は、入出力のためのパケットの総数です。このノードは、まだ NGM_TEXT_STATUS コントロールメッセージをサポートしていません。

フック

このノードタイプは、次のフックをサポートします:
ethernet
通常 ng_ether(4) ノードに接続されるはずのフック。いったん接続されると、 ng_pppoe は、基本的なノードのイーサネットアドレスを決定するためにメッセージをこのフックに送信します。得られたアドレスは、格納され、次に発信データグラムのために使用します。
debug
現在使用されていません。
[不特定]
その他の名前は、PPP クライアントエージェント、または PPP サーバエージェントに接続されるセッションフックであると仮定されます。

コントロールメッセージ

このノードタイプは、次を加えて、一般的なコントロールメッセージをサポートします:
NGM_PPPOE_GET_STATUS
このコマンドは、 struct ngpppoestat の状態情報を返します:

struct ngpppoestat { 
    u_int   packets_in;     /* イーサネットからの入力パケット */ 
    u_int   packets_out;    /* イーサネットに向かう出力パケット */ 
};
NGM_TEXT_STATUS
この一般メッセージは、ノード状態の人間が読み込み可能なバージョンを返します。 (まだ)
NGM_PPPOE_CONNECT ( pppoe_connect)
セッションがクライアントとしてステートマシンを入れるべきであるという指名されて新しく作成されたフックに伝えます。それは、新たに作成されなければなりません、そして、引数としてサービス名を与えることができます。長さ 0 のサービス名を指定することは正当で、これは、いくつかの DSL 設定で共通です。 "AC-Name\Service-Name"構文を使用してその名前によって特定のアクセスコンセントレータ (集中装置) に接続を要求することは可能です。セッションリクエストパケットは、イーサネットでブロードキャスト (放送) されます。このコマンドは、以下に示された ngpppoe_init_data 構造体を使用します。
NGM_PPPOE_LISTEN ( pppoe_listen)
セッションがサーバのリスナとしてステートマシンを入れるべきであるという指名されて新しく作成されたフックに伝えます。与えられた引数は、listen (接続を受け付け) しようとするサービスの名前です。長さが 0 のサービス名は、サービスのためのすべての要求に適合します。マッチングサービスリクエストパケットは、サービスを始めるための原因となるプロセスに変更さずに元に手渡されます。次にそれを調べることができ、要求に答えるために始められるセッションにそれを渡します。このコマンドは、以下に示された ngpppoe_init_data 構造体を使用します。
NGM_PPPOE_OFFER ( pppoe_offer)
セッションがサーバとしてステートマシンを入れるべきであるという指名されて新しく作成されたフックに伝えます。与えられた引数は、提供するサービスの名前です。長さ 0 のサービスは、正当です。ステートマシンは、LISTEN モードフック (上記参照) からそれをたぶん順番に受信した始動サーバからそれに転送されるリクエストパケットを待つ状態に進みます。オリジナルのセッションリクエストパケットに組み込まれているセッションに要求される状態は、結局要求に答えるためのステートマシンを利用可能にします。セッションリクエストパケットが受信されるとき、セッション交渉は、進行します。このコマンドは、以下に示された ngpppoe_init_data 構造体を使用します。

上記の 3 つコマンドは、共通データ構造体を使用します:

struct ngpppoe_init_data { 
    char       hook[NG_HOOKSIZ];       /* モニタをオンにする 
                                          フック */ 
    uint16_t   data_len;               /* サービス名の長さ */ 
    char       data[0];                /* 初期データはここから 
                                          始まる */ 
};
NGM_PPPOE_SUCCESS ( pppoe_success)
このコマンドを上記のメッセージの 1 つでこのセッションを開始したノードに送信し、状態の変化を報告します。このメッセージは、成功したセッション交渉を報告します。それは、以下に示される構造体を使用し、報告は、成功したセッションに対応するフック名を戻します。
NGM_PPPOE_FAIL ( pppoe_fail)
このコマンドを上記のメッセージの 1 つでこのセッションを開始したノードに送信し、状態の変化を報告します。このメッセージは、失敗したセッション交渉を報告します。それは、以下に示される構造体を使用し、報告は、失敗したセッションに対応するフック名を戻します。このフックは、このメッセージを送信する直後にたぶん削除されてしまうでしょう。
NGM_PPPOE_CLOSE ( pppoe_close)
このコマンドを上記のメッセージの 1 つでこのセッションを開始したノードに送信し、状態の変化を報告します。このメッセージは、セッションをクローズする要求を報告します。それは、以下に示される構造体を使用し、報告は、クローズされたセッションに対応するフック名を戻します。このフックは、このメッセージを送信する直後にたぶん削除されてしまうでしょう。現在のところ、まだこのメッセージを使用されていません。そして、代わりにクローズで NGM_PPPOE_FAIL メッセージを受信するでしょう。
NGM_PPPOE_ACNAME
このコマンドは、上記のメッセージの 1 つとともにこのセッションから始まるノードに送信し、 Access Concentrator Name を報告します。

上記の 4 つコマンドは、共通データ構造体を使用します:

struct ngpppoe_sts { 
    char    hook[NG_HOOKSIZ];    /* イベントセッションに関連している 
                                    フック */ 
};
NGM_PPPOE_GETMODE ( pppoe_getmode)
このコマンドは、文字列としてノードの現在の互換性モードを返します。このメッセージの ASCII 形式は、“ pppoe_getmode”です。次のキーワードを返すことができます:
“standard”
ノードは、RFC 2516 にしたがって動作します。
“3Com”
ng_pppoe が PPPoE クライアントであるときに、不正確な 3Com ethertype でカプセル化されたパケットのセッションを開始します。この互換性オプションは、サーバモードに影響しません。サーバモードで、 ng_pppoe は、接続するとき使用されるクライアントである ethertype によって、同時に両方のモードをサポートします。
“D-Link”
ng_pppoe が特定の Service-Name だけで役立つ PPPoE サーバであるときに、空の Service-Name タグ、ノード上で利用可能なすべての Service-Name を返す PADI 要求に応答します。特定の Service-Name だけに役立つとき、このオプションは、クライアントとして D-Link DI-614+ と DI-624+ SOHO との互換性が必要です。この互換性オプションは、クライアントモードに影響しません。
NGM_PPPOE_SETMODE ( pppoe_setmode)
ノードを指定されたモードに設定します。文字列引数が必要です。このコマンドは、同じキーワードを理解して、 NGM_PPPOE_GETMODE コマンドによって返されます。このメッセージの ASCII 形式は、“ pppoe_setmode”です。例えば、次のコマンドは、独自の 3Com モードで次のセッションを開始するためにノードを設定します:

ngctl msg fxp0:orphans pppoe_setmode '"3Com"'
NGM_PPPOE_SETENADDR ( setenaddr)
発信データグラムのためのノードイーサネットアドレスを設定します。ノードが ethernet フックでそのピア (相手側) からイーサネットアドレスの取得に失敗したとき、またはユーザが別のものでこのアドレスを上書きすることを望むとき、このメッセージは、重要です。このメッセージの ASCII 形式は、“ setenaddr”です。

シャットダウン

このノードは、すべてのセッションが切断されている時、または ethernet フックが切断されている時、 NGM_SHUTDOWN コントロールメッセージを受け取ってシャットダウンします。

使用例

次のコードは、 ng_pppoe ノードを設定するために libnetgraph を使用して、それをソケットノードとイーサネットノードの両方に接続します。それは、 ng_pppoe ノードが既にイーサネットに取り付けられている時の場合を扱うことができます。そして、それは、クライアントセッションを開始します。

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <ctype.h> 
#include <unistd.h> 
#include <sysexits.h> 
#include <errno.h> 
#include <err.h> 
 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <sys/select.h> 
#include <net/ethernet.h> 
 
#include <netgraph.h> 
#include <netgraph/ng_ether.h> 
#include <netgraph/ng_pppoe.h> 
#include <netgraph/ng_socket.h> 
static int setup(char *ethername, char *service, char *sessname, 
    int *dfd, int *cfd); 
 
int 
main() 
{ 
 int  fd1, fd2; 
 setup("xl0", NULL, "fred", &fd1, &fd2); 
 sleep (30); 
} 
 
static int 
setup(char *ethername, char *service, char *sessname, 
   int *dfd, int *cfd) 
{ 
 struct ngm_connect ngc; /* connect */ 
 struct ngm_mkpeer mkp; /* mkpeer */ 
 /******** nodeinfo 要素 **********/ 
 u_char          rbuf[2 * 1024]; 
 struct ng_mesg *const resp = (struct ng_mesg *) rbuf; 
 struct hooklist *const hlist 
   = (struct hooklist *) resp->data; 
 struct nodeinfo *const ninfo = &hlist->nodeinfo; 
 int             ch, no_hooks = 0; 
 struct linkinfo *link; 
 struct nodeinfo *peer; 
 /**** PPPoE セッションに接続するメッセージ *****/ 
 struct { 
  struct ngpppoe_init_data idata; 
  char            service[100]; 
 }               message; 
 /******** 私たちの小さいグラフを追跡 ********/ 
 char            path[100]; 
 char            source_ID[NG_NODESIZ]; 
 char            pppoe_node_name[100]; 
 int             k; 
 
 /* 
  * データと制御ソケットを作成 
  */ 
 if (NgMkSockNode(NULL, cfd, dfd) < 0) { 
  return (errno); 
 } 
 /* 
  * 問い合せ情報のために質問によって要求された名前の ether ノード 
  * を見つける. 
  */ 
 if (strlen(ethername) > 16) 
  return (EINVAL); 
 sprintf(path, "%s:", ethername); 
 if (NgSendMsg(*cfd, path, NGM_GENERIC_COOKIE, 
        NGM_LISTHOOKS, NULL, 0) < 0) { 
  return (errno); 
 } 
 /* 
  * コマンドは存在しているので受け入れられました. 
  * 返答を待ちます (それはほぼ確実に既に待っています). 
  */ 
 if (NgRecvMsg(*cfd, resp, sizeof(rbuf), NULL) < 0) { 
  return (errno); 
 } 
 /** 
  * 次はノードに関して利用可能です: 
  * ninfo->name  (string) 
  * ninfo->type  (string) 
  * ninfo->id  (uint32_t) 
  * ninfo->hooks  (uint32_t) (count of hooks) 
  * 正しいタイプかチェックします. そして、後で mkpeer 
  * で使用するためにその ID を取得します. 
  */ 
 if (strncmp(ninfo->type, NG_ETHER_NODE_TYPE, 
      strlen(NG_ETHER_NODE_TYPE)) != 0) { 
  return (EPROTOTYPE); 
 } 
 sprintf(source_ID, "[%08x]:", ninfo->id); 
 
 /* 
  * 既に取り付けられたフックを検索. 
  */ 
 for (k = 0; k < ninfo->hooks; k++) { 
  /** 
   * 次は各フックで利用可能です. 
   * link->ourhook (string) 
   * link->peerhook (string) 
   * peer->name  (string) 
   * peer->type  (string) 
   * peer->id  (uint32_t) 
   * peer->hooks  (uint32_t) 
   */ 
  link = &hlist->link[k]; 
  peer = &hlist->link[k].nodeinfo; 
 
  /* debug フックを無視 */ 
  if (strcmp("debug", link->ourhook) == 0) 
   continue; 
 
  /* orphans フックが取り付けられていれば、それを使用 */ 
  if (strcmp(NG_ETHER_HOOK_ORPHAN, 
      link->ourhook) == 0) { 
   break; 
  } 
  /* 他のオプションは 'divert' フック */ 
  if (strcmp("NG_ETHER_HOOK_DIVERT", 
      link->ourhook) == 0) { 
   break; 
  } 
 } 
 
 /* 
  * 私たちがそこでフックを見つけたかどうかを見る. 
  */ 
 if (k < ninfo->hooks) { 
  if (strcmp(peer->type, NG_PPPOE_NODE_TYPE) == 0) { 
   /* 
    * それがタイプ PPPoE であるなら、私たち自身で作成 
    * したものをスキップしますが、存在するものを使用 
    * して、私たちは続けます. 
    */ 
   sprintf(pppoe_node_name, "[%08x]:", peer->id); 
  } else { 
   /* 
    * 既にだれかが消費したデータがあり、 
    * エラーを返します. いつか私たちは 
    * デイジチェーンを試みるでしょう. 
    */ 
   return (EBUSY); 
  } 
 } else { 
 
  /* 
   * フック NG_ETHER_HOOK_ORPHAN でノード "ID"対して 
   * タイプ PPPoE のノードの作成を試みます. 
   */ 
  snprintf(mkp.type, sizeof(mkp.type), 
    "%s", NG_PPPOE_NODE_TYPE); 
  snprintf(mkp.ourhook, sizeof(mkp.ourhook), 
    "%s", NG_ETHER_HOOK_ORPHAN); 
  snprintf(mkp.peerhook, sizeof(mkp.peerhook), 
    "%s", NG_PPPOE_HOOK_ETHERNET); 
  /* メッセージ送信 */ 
  if (NgSendMsg(*cfd, source_ID, NGM_GENERIC_COOKIE, 
         NGM_MKPEER, &mkp, sizeof(mkp)) < 0) { 
   return (errno); 
  } 
  /* 
   * 新しいノードのために名前を考え出す. 
   */ 
  sprintf(pppoe_node_name, "%s:%s", 
   source_ID, NG_ETHER_HOOK_ORPHAN); 
 } 
 /* 
  * 私たちは今、PPPoE ノードをイーサネットカードに取り付けます. 
  * イーサネットは ethername として記述されます: PPPoE ノードは、 
  * pppoe_node_name として記述されます: それに取り付けます. 
  * ソケットノードをリンクの両端で同じフック名を使用する指定された 
  * ノードに接続します. 
  */ 
 snprintf(ngc.path, sizeof(ngc.path), "%s", pppoe_node_name); 
 snprintf(ngc.ourhook, sizeof(ngc.ourhook), "%s", sessname); 
 snprintf(ngc.peerhook, sizeof(ngc.peerhook), "%s", sessname); 
 
 if (NgSendMsg(*cfd, ".:", NGM_GENERIC_COOKIE, 
        NGM_CONNECT, &ngc, sizeof(ngc)) < 0) { 
  return (errno); 
 } 
 
#ifdef NONSTANDARD 
 /* 
  * ある場合には、我々は 3Com ハードウェアと話しているので、 
  * ノードを標準でないモードに設定します. 
  */ 
 if (NgSendMsg(*cfd, ngc.path, NGM_PPPOE_COOKIE, 
   NGM_PPPOE_SETMODE, NG_PPPOE_NONSTANDARD, 
   strlen(NG_PPPOE_NONSTANDARD) + 1) == -1) { 
  return (errno); 
 } 
#endif 
 
 /* 
  * 始動するように伝えるメッセージを送信. 
  */ 
 bzero(&message, sizeof(message)); 
 snprintf(message.idata.hook, sizeof(message.idata.hook), 
    "%s", sessname); 
 if (service == NULL) { 
  message.idata.data_len = 0; 
 } else { 
  snprintf(message.idata.data, 
    sizeof(message.idata.data), "%s", service); 
  message.idata.data_len = strlen(service); 
 } 
 /* クライアントとして始動するようにセッション/フックに伝える */ 
 if (NgSendMsg(*cfd, ngc.path, 
        NGM_PPPOE_COOKIE, NGM_PPPOE_CONNECT, &message.idata, 
        sizeof(message.idata) + message.idata.data_len) < 0) { 
  return (errno); 
 } 
 return (0); 
}

関連項目

netgraph(3), netgraph(4), ng_ether(4), ng_ppp(4), ng_socket(4), ngctl(8), ppp(8) L. Mamakos, K. Lidl, J. Evarts, D. Carrel, D. Simone, and R. Wheeler, A Method for transmitting PPP over Ethernet (PPPoE), RFC 2516.

歴史

ng_pppoe ノードタイプは、 FreeBSD 4.0 で実装されました。

作者

Julian Elischer <julian@FreeBSD.org>
November 13, 2012 FreeBSD