データ・リンク・インタフェース (DLI) はプログラムがデータ・リンク機能を直接使用して,リモート・システムで実行されているデータ・リンク・プログラムとの通信を行なうためのプログラミング・インタフェースです。
クライアントおよびサーバの DLI プログラム例は
F.5 項を参照してください。
F.1 DLI プログラミングの前提条件
DLI プログラミングには C 言語の知識とシステム・プログラムの経験が要求されます。 また,イーサネット・サブ構造体を使用する場合はイーサネット・プロトコルについての知識が,802 サブ構造体を使用する場合は 802.2,802.3 および FDDI プロトコルについての知識がそれぞれ必要です。
DLI インタフェースへのプログラムを書く場合はさらに次の概念についての知識が必要となります。
データグラム・ソケット
アプリケーションはソケットを使用してイーサネット,802.3 および FDDI フレームの送受信を行ないますが,DLI はデータグラム・ソケットのみを使用します。
ソケットについての詳細は第 4 章を参照してください。
論理リンク・コントロール (LLC)
LLC は 802.2 フレーム・フォーマットの値によって決定されるサービス群を提供する DLI の補助層です。
物理アドレスおよびマルチキャスト・アドレス
物理アドレスまたはマルチキャスト・アドレスを使用してネットワーク上にメッセージを送受信することができます。 デスティネーションが単一のシステムの場合は物理アドレスを使用してメッセージを送信します。 デスティネーションが不特定のシステムの場合はマルチキャスト・アドレスを使用してパケットを送信します。 マルチキャスト・アドレスに送信されたパケットはマルチキャスト・アドレスが有効になっているすべてのシステムに受信されます。
マルチキャスト・アドレスの詳細は4.7 節を参照してください。
標準フレーム・フォーマット
イーサネット・フレーム・フォーマットはコンパックコンピュータ社,インテル社およびゼロックス社が所有する標準フレーム・フォーマットです。 IEEE 802.3 フレーム・フォーマットはマルチベンダ・ネットワークの標準フレーム・フォーマットです。 FDDI フレーム・フォーマットと IEEE 802.3 フレーム・フォーマットは両者とも LLC (または 802.2) フレームを含む非常に類似しているフレーム・フォーマットです。 詳細についてはF.3.1 項を参照してください。
このオペレーティング・システムでの DLI アプリケーションの実行にはスーパユーザ特権またはルート特権が要求されます。
F.2 DLI 概略
DLI プログラムは標準イーサネット・フレーム・フォーマット,オープン・システム・インタコネクト (OSI) 802.3 フレーム・フォーマットまたは FDDI フレーム・フォーマットを使用してネットワーク上にデータを転送します。 オペレーティング・システムではインターネット・プログラム,DECnet プログラムおよび DLI プログラムを同時に実行することができます。
オペレーティング・システムはイーサネット・データ・リンク・サービスおよび 802.2 データ・リンク・サービスの両方をサポートします。 DLI および IP は両方ともイーサネットおよび 802.2 上で実行します。 FDDI と 802.3 は 802.2 論理リンク・コントロール (LLC) をデータ・リンクの補助層として使用します。 TCP および UDP は IP 上で実行し,両者を使用するプログラムにデータ配送サービスとメッセージ・ルーティング・サービスを提供します。 DLI はデータ・リンク層への直接アクセスを提供するので TCP および UDP が行なう高次レベル・サービスは提供しません。
図 F-1
は DLI と IP,DLI とイーサネットおよび DLI と 802.2 の関係を表した概念図です。
図 F-1: DLI とネットワーク・プログラミング環境
ソケットは TCP,UDP および DLI へのアクセスを容易にするユーザ・アプリケーション・インタフェースです。
DLI 通信ドメイン (AF_DLI) でのソケットのオープンについては第 4 章を参照してください。
F.2.1 DLI サービス
データグラム・サービス
論理リンク・コントロール (LLC) 層
ISO 802.2 クラス I,タイプ 1 サービス
マルチキャスト・アドレス・モード
媒体アクセス・コントロール (MAC) 層
イーサネット・フレーム
802.3 フレーム
FDDI フレーム
DLI は特定のシステムがどのドライバを構成しているかを
probe
ルーチンを使用して識別している,イーサネット・デバイス・ドライバまたは FDDI デバイス・ドライバを使用しますので,DLI ではハードウェアについての知識が必要とされません。
サポートされているネットワーク・デバイスの一覧は Tru64 UNIX の『ソフトウェア仕様書』に記載されています。
システムに構成されているネットワーク・デバイスは
/usr/sbin/netstat -i
コマンドを次のように使用して識別します。
% /usr/sbin/netstat -i Name Mtu Network Address Ipkts Ierrs Opkts Oerrs Coll ln0 1500 <Link> 746 0 234 0 18 ln0 1500 orange-net host1 746 0 234 0 18 sl0* 296 <Link> 0 0 0 0 0 sl1* 296 <Link> 0 0 0 0 0 lo0 1536 <Link> 74 0 74 0 0 lo0 1536 loop localhost 74 0 74 0 0
コマンドを入力すると,システムで構成されているインタフェースとデバイスの情報が画面に出力されます。
この例ではイーサネット・ハードウェア・デバイス (ln
) が 2 つのシリアル・ライン・インタフェース・プロトコル・デバイス (sl0
および
sl1
) として構成されています。
sl0
および
sl1
の後ろのアスタリスク (*) はインタフェースのサポートが有効になっていないことを示します。
F.2.3 DLI を使用してのローカル・エリア・ネットワークへのアクセス
単一のローカル・エリア・ネットワーク (LAN) コントローラ上のデータ・リンクは同時に複数のユーザをサポートします。 各局はネットワーク・チャネル上の使用可能なポートを表します。
ネットワーク・チャネルには同時に複数のユーザがアクセスするので,プログラムはメッセージを正しい受信者に確実に配送するアドレス機能を使用する必要があります。
ネットワークに転送するメッセージにはデスティネーション・システムを示すイーサネット・アドレスまたは FDDI アドレスが含まれている必要があります。
またメッセージがデスティネーション・システムの適切なユーザに届くために必要な識別子も含まれている必要があります (この識別子は使用するフレーム・フォーマットに依存します)。
DLI はイーサネット,IEEE 802.3 または FDDI 標準に従ってフレームを構築します。
F.2.4 高次レベル・サービスのインクルード
DLI はデータグラム・サービスのみを提供します。 DLI はデータ・リンク層への直接インタフェースなので,インターネットおよび DECnet では通常提供されている高次レベル・サービスを提供しません。 したがって,次のサービスをアプリケーションで提供する必要があります。
パケット・ルーティングおよび保証付き配送 (Guaranteed delivery)
フロー・コントロール
エラー回復
データ・セグメンテーション
この節ではイーサネット,802.3 および FDDI の標準フレーム・フォーマットおよび DLI ソケット・アドレスのデータ構造体 (sockaddr_dl
) の機能について記述します。
また,sockaddr_dl
を使用してドメイン・アドレス,ネットワーク・デバイスおよびイーサネット,802.3 または FDDI サブ構造体を指定する方法を説明します。
F.3.1 標準フレーム・フォーマット
以下の 4 つの図はイーサネット,802.3 および FDDI フレームの相違点と類似点を示す概念図です。
図 F-2
はイーサネット・フレーム・フォーマットの概念図です。
図 F-2: イーサネット・フレーム・フォーマット
図 F-3
は 802.3 フレーム・フォーマットの概念図です。
802.3 フレーム・フォーマットはその構造の中に図 F-5
の 802.2 構造を含んでいる点に注意してください。
図 F-3: 802.3 フレーム・フォーマット
図 F-4
は FDDI フレーム・フォーマットの概念図です。
FDDI フレーム・フォーマットもその構造の中に図 F-5
の 802.2 構造を含んでいます。
図 F-4: FDDI フレーム・フォーマット
図 F-5 は 802.2 LLC PDU および 802.2 LLC SNAP PDU の概念図です。 これらのうちの 1 つが 802.3 および FDDI フレーム・フォーマットに含まれます。
一般的に 802 アプリケーションは 802.2 LLC PDU フォーマットを使用します。 しかし,次のような理由から 802.2 LLC SNAP PDU フォーマットを選択することもできます。
イーサネット上と 802.2 上の両方で操作するアプリケーションおよびイーサネットから 802.2 へ移行するアプリケーションには,SNAP_SAP を使用するとイーサネット・プロトコルを 802.2 プロトコルにマップするのが便利である。
I/O コントロール・フラグ (DLI_NORMAL,DLI_EXCLUSIVE および DLI_DEFAULT) はイーサネットと 802.2 SNAP フレームのみで有効なので, SNAP 802.2 LLC PDU を使用しない場合にこれらのフラグが意味を持たなくなる。
通常の 802.2 LLC PDU は DSAP の上位 7 ビット上に多重化されているが,SNA_SAP は 5 バイトのプロトコル ID を持っているので,これを使用すると 802.2 上でより多くのアプリケーションを実行することができる。
DLI はデータ・リンク層の通信に必要とされるサービス群の構成に使用するソケット・アドレスのデータ構造体を提供します。
データ構造体
sockaddr_dl
はアプリケーションがネットワークにバインドした時またはネットワークにパケットを転送した時に DLI へ情報を伝送するのに使用されます。
また,アプリケーションがネットワークからパケットを受信した時にアプリケーションに情報を伝送するのにも使用されます。
この情報にはネットワーク・デバイス情報,使用されるパケット・フォーマットおよびアドレス情報が含まれます。
次の例はヘッダ・ファイル
<dli/dli_var.h>
で定義されている DLI ソケット・アドレス構造体です。
#define DLI_ETHERNET 0 #define DLI_802 2
.
.
.
struct sockaddr_dl { u_char dli_len; /* length of sockaddr */ u_char dli_family; /* address family (AF_DLI) */ struct dli_devid dli_device; /* id of comm device to use */ u_char dli_substructype; /* id to interpret following */ /* structure */ union { struct sockaddr_edl dli_eaddr; /* Ethernet */ struct sockaddr_802 dli_802addr; /* OSI 802 support */ caddr_t dli_aligner1; /* this needs to have */ /* longword alignment */ } choose_addr; };
すべてのアプリケーションはイーサネット・サブ構造体と 802 サブ構造体の両方を送受信することができます。 イーサネット・サブ構造体はアプリケーションのイーサネット間での通信を可能にし,802 サブ構造体はアプリケーションの 802.2,802.3 および FDDI プロトコル間での通信を可能にします。
イーサネット・サブ構造体または 802 サブ構造体を使用することで,ソケット・アドレス構造体の中でシステム・コールを使用して値を指定することができます。
サブ構造体のフィールドはシステム・コールの関数として更新されます。
たとえば
bind
システム・コールはドメイン,ネットワーク・デバイスおよびサブ構造体の指定に使用されます。
データの転送に
sendto
システム・コールを使用する場合はドメイン,ネットワーク・デバイスおよびサブ構造体の一部を指定する必要があります。
データの受信に
recvfrom
システム・コールを使用する場合,DLI は
sockaddr
構造体のすべてのメンバに値を代入します。
ユーザが作成する
dli_econn
および
dli_802_3_conn
サブルーチンはソケットをオープンし,関連するドメイン,ネットワーク・デバイス名,プロトコル・タイプおよびその他のサブ構造体の情報をソケットにバインドします。
ユーザ作成のサブルーチン
dli_econn
と
dli_802_3_conn
の例は
F.5 項を参照してください。
以下にイーサネット・サブ構造体と 802.2 サブ構造体が DLI
sockaddr_dl
データ構造体に提供する関数について説明します。
F.3.3 イーサネット・サブ構造体
以下は DLI イーサネット・ソケット・アドレス・サブ構造体の例です。
#define DLI_EADDRSIZE 6
.
.
.
struct sockaddr_edl { u_char dli_ioctlflg; /* i/o control flags */ u_char dli_options; /* Ethernet options */ u_short dli_protype; /* Ethernet protocol type */ u_char dli_target[DLI_EADDRSIZE]; /* Ethernet address of */ /* destination system */ u_char dli_dest[DLI_EADDRSIZE]; /* Ethernet address used to */ /* address the local system; */ }; /* DLI places the destination */ /* address of an incoming */ /* packet here to be used in */ /* the recvfrom call. This */ /* address can be the sys- */ /* tem's address or a multi */ /* cast address. */
イーサネット・サブ構造体は次の項目を指定します。
プロトコル・タイプ (dli_ioctlflg
) の I/O コントロール・フラグ
イーサネットの埋め込みの有効または無効 (dli_options
)
PAD は MAC/LLC ヘッダの後のリトル・エンディアン内の 2 バイト長のフィールドです。
<dli/dli_var.h>
ヘッダ・ファイルの以下のエントリが,埋め込みを有効にする場合に
dli_options
フィールドに設定される必要があるビットです。
#define DLI_ETHERPAD 0x01 /* Protocol is padded */
DLI プロトコル・タイプ (dli_prototype
)
デスティネーション・システムのイーサネット・アドレス (dli_target
)
ローカル・システムにアドレスするために使用されるイーサネット・アドレス (dli_dest
)
この情報はイーサネット・フレーム・フォーマットの作成に使用されます。
F.3.3.1 イーサネット・フレーム
すべてのイーサネット・フレームはイーサネット・プロトコル・タイプ (PType) と呼ばれる 16 ビットの ID 番号を含みます。
コントローラにメッセージが届くと,フレームを受信したポートの識別にプロトコル・タイプが使用されます。
イーサネット間で通信する DLI アプリケーションは常に同じイーサネット・プロトコル・タイプを有効にしておく必要があります。
また,プロトコル・タイプを使用して着信パケットの宛先ユーザを選択する方法に加えて,DLI を構成して,リモート・システムのプロトコル・タイプおよび物理アドレスの両方の関数としてユーザを選択する方法があります。
これにより,同一システムの複数のアプリケーションが同一のタイプを使用することができるのでアプリケーションの出入力が簡素化されます。
F.3.3.2 イーサネット・サブ構造体の値の定義
ユーザは次のイーサネット・ソケット・アドレスサブ構造体のフィールドの値を定義します。 他方のフィールドはシステム・コールまたは DLI によって代入されます。
デスティネーションのアドレス (dli_target[DLI_EADDRSIZE]
)
dli_target
フィールドを使用してデスティネーションのアドレスを指定することができます。
プロトコル・タイプ (dli_protype
)
dli_prototype
フィールドを使用してデータ転送に使用されるプロトコルを指定することができます。
I/O コントロール・フラグ (dli_ioctlflg
)
以下は,イーサネット・サブ構造体でユーザが定義することができるメンバの値の説明です。
デスティネーション・ノードの物理アドレス
デスティネーション・システムの物理アドレス (図 F-2 の DA) は製造元により各局に割り当てられるイーサネット上で固有の 48 ビットの値です。 物理アドレスは,たとえば 08-00-2b-XX-XX-XX (X は 16 進数) という形式で表わされます。 DA はローカル・システムから見たリモート・システムのアドレスです。
bind
コールで DA 値を指定しない場合は
sendto
コールでデータの送信時に指定し,recvfrom
コールでデータ・メッセージのソースを識別する必要があります。
sendto
システム・コールへのメッセージの送信は物理アドレスまたはマルチキャスト・アドレスのどちらかを使用して行なうことができます。
プロトコル・タイプ
プロトコル・タイプ (図 F-2 の PType) はソース・アドレスに続くイーサネット・フレームの 16 ビットの値です。 イーサネット・ドライバはフレーム内のデータの受信者の決定に使用するプロトコル・タイプを DLI に渡します。 リザーブされている値を除いて,工場出荷時に割り当てられたイーサネット・プロトコル・タイプのうちシステム内で他に使用されていないものを任意に使用することができます。
次の 16 進数値はシステム用にリザーブされています。
0X 0200 -- PUP プロトコル
0X 0800 -- インターネット・プロトコル
0X 0806 -- アドレス解決プロトコル
0X 6004 -- ローカル・エリア・トランスポート
0X 6003 -- Phase IV DECnet
0X 6002 -- MOP CCR プロトコル
0X 6001 -- MOP ダウンライン・ロード・プロトコル
0X 9000 -- MOP ループバック・プロトコル
0X 1000 to 0X 100f -- インターネット・トレイラ・プロトコル (VAX のみ使用)
<dli/dli_var.h>
ヘッダ・ファイルで定義されている I/O コントロール・フラグは DLI がプログラムのプロトコル・タイプのリザーブ方法の決定に使用する値です。
この値を使用して DLI はユーザをプロトコル・タイプに限った関数として選択するか,プロトコル・タイプとターゲット・オーディエンスの組み合わせの関数として選択するかを決定します。
次のリストは指定可能な I/O コントロール・フラグの定義と使用する際の条件の一覧です。
NORMAL
指定したプロトコル・タイプだけを使用して,プログラムが 1 つのデスティネーション・システムとメッセージの交換ができるようにします。
NORMAL
フラグを使用する場合は
bind
コールにデスティネーション・システムの物理アドレスを指定する必要があります。
またデータの送受信にすべてのデータ転送コールを使用することができます。
DLI は指定されたターゲットから指定されたプロトコル・タイプを含むすべてのメッセージをユーザにフォワードします。
EXCLUSIVE
指定されたプロトコル・タイプを排他的に使用して,プログラムが指定されたプロトコル・タイプを使用している任意のシステムとデータの交換ができるようにします。
つまり,プログラムは指定されたプロトコル・タイプですべてのメッセージを受信します。
EXCLUSIVE
フラグを使用する場合,ターゲットのアドレスを
bind
コールで指定することはできません。
この場合は
sendto
コールおよび
recvfrom
コールを使用して他のシステムとのデータ交換を行ない,ターゲットのアドレスは
sendto
コールで指定する必要があります。
DLI はアドレス構造体 (recvfrom
の戻り値) のターゲット・アドレスにイーサネット・フレームのソース・アドレスを代入します。
またデスティネーションのアドレスにイーサネット・フレームのデスティネーション・アドレスを代入します。
DEFAULT
プログラムは指定されたプロトコル・タイプを含むメッセージでシステムの他のプログラムに向けたものではないメッセージを受信することができるようにします。
メッセージのプロトコル・タイプまたはプロトコル・タイプとプロトコル・アドレスの組み合せに排他的にバインドされたプログラムがほかにない場合,プロトコル・タイプとバインドしたソケットが省略時の設定でメッセージを受け取ります。
このオペレーション・モードはメッセージのリッスンは行なうが送信する必要がないプログラムに対して使用すると効果的です。
DEFAULT
フラグを使用する場合はターゲット・アドレスの指定に
bind
コールを使用することはできません。
この場合,recvfrom
コールを使用して他のシステムからデータを受信してください。
DEFAULT
フラグを使用する場合,DLI がターゲット・アドレスにイーサネット・フレームのソース・アドレスを代入します。
またデスティネーション・アドレスにイーサネット・フレームのデスティネーション・アドレスを代入します。
802.2 サブ構造体によりアプリケーションは 802.2,802.3 および FDDI プロトコルを使用した相互通信が可能になります。 このサブ構造体はクラス I,タイプ 1 サービスとの 802.2 プロトコルを使用してアプリケーションされるサービスの 2 つのオペレーション・モードを使用します。
以下は DLI 802.3 ソケット・アドレスのサブ構造体の例です。
struct sockaddr_802 { /* 802.3 sockaddr struct */ u_char ioctl; /* filter on incoming packets */ /* addressed to the SNAP SAP */ u_char svc; /* service class for this portal */ struct osi_802hdr eh_802; /* OSI 802 header format */ };
802.2 サブ構造体は 802.3 フレーム・フォーマットと FDDI フレーム・フォーマットを包括します。 次のフィールドに値を指定することができます。
サービス・クラス
デスティネーションのサービス・アクセス・ポイント (図 F-5 の DSAP)
個人
グループ
ソース・サービス・アクセス・ポイント (図 F-5 の SSAP)
有効にする SSAP のタイプにより,プロトコル識別子と I/O コントロール・フィールドが必要とされることがあります。
コントロール・フィールド
以下は,802 サブ構造体で指定することができるすべてのメンバの値の説明です。
デスティネーション・ノードの物理アドレス
デスティネーション・システムの物理アドレス (DA) は製造元により各局に割り当てられるイーサネット上で固有の 48 ビットの値です。
物理アドレスは,たとえば 08-00-2b-XX-XX-XX (X は 16 進数) という形式で表されます。
このアドレスはアプリケーションがパケットの交換を試みるリモート・システムのアドレスです。
I/O コントロール・フィールドが
EXCLUSIVE
または
DEFAULT
で,サービス・アクセス・ポイント (SAP) が
SNAP_SAP
タイプである場合を除いて,このアドレスは
bind
コールで指定される必要があります。
また,SAP は
sendto
コールで指定される必要があります。
サービス・クラス
サービス・クラスはデータ・リンク層の論理リンク・コントロール (LLC) 補助層によって提供される機能を設定する 802.2 サブ構造体の値です。 指定可能なサービス・クラスは次のとおりです。
TYPE1
この値により DLI はすべてのヘッダ情報を中断し,クラス I,タイプ 1 サービスを提供します。
注意
タイプ 1 サービスが使用されているときには DLI ソフトウェアが
XID
およびTEST
パケットを処理するので,アプリケーションには透過的です。
DLI はソース・サービス・アクセス・ポイントとデスティネーション・サービス・アクセス・ポイントを使用してユーザに代わってコントロール・フィールドを解釈し,メッセージの受信者を決定します。 DLI がデータ・フィルドをユーザに渡すかどうかはコントロール・フィールドの値に依存します。
USER
この値によりごく限られたサービスのみが提供されます。
したがってユーザは 802.2 プロトコルの大部分をインプリメントする必要があります。
つまり,アプリケーションは
XID
および
TEST
パケットを処理しなければなりません。
DLI はソース・サービス・アクセス・ポイントおよびデスティネーション・サービス・アクセス・ポイントを使用しますが,データを含むコントロール・フィールドをユーザに渡すので,ユーザはこのコントロール・フィールドを解析する必要があります。
アプリケーションがクラス II,タイプ 2 サービスをインプリメントする必要がある場合はこのモードを選択しなければなりません。
デスティネーション・サービス・アクセス・ポイント (DSAP) はメッセージがどのアプリケーションに向けられているかを識別する 802.2 フレームのフィールドです。
1 人または 1 グループのユーザの識別に個人 DSAP またはグループ DSAP を使用することができます。
サービス・クラスが
USER
に設定されている場合に限りグループ DSAP を使用することができます。
このフィールドに指定することができる値は次のとおりです。
個人 DSAP
NULL_SAP
-- すべてゼロで構成される DSAP
TEST
および
XID
の各コマンドとレスポンスを送信することができますが,NULL_SAP
にデータを送信することはできません (TEST
および
XID
は後述)。
NULL_SAP
はデータ・リンク層が主にテストの目的で,他のデータ・リンク層と通信する際に使用されます。
ユーザ定義 DSAP -- メッセージが向けられる 1 人のユーザを識別
ユーザ定義個人 DSAP には 2 以上 254 以下の偶数を指定します。
SNAP_SAP
-- 802.3 サブネットワーク・アクセス・プロトコル
グループ DSAP (ユーザ定義)
メッセージが向けられる複数のユーザを識別します。
1 つのソケットで最大 127 のグループ DSAP に対してデータを送信できます。
ユーザ定義グループ DSAP には 3 以上 255 以下の奇数を指定します。
255 番はグローバル SAP なので,他のグループ SAP と同様に有効でなくてはならない点に注意してください。
グループ SAP はサービス・クラスが
USER
に設定されている場合に限り使用することができます。
ソース・ サービス・アクセス・ポイント (SSAP) はメッセージを送信したアプリケーションのアドレスを識別する 802.2 フレームのフィールドです。 1 つのソケットで有効にできる SSAP は 1 つに限られます。 SSAP は 2 以上 254 以下の偶数です。
注意
SNAP_SAP
を使用する場合は DSAP と SSAP の両方がSNAP_SAP
に設定されている必要があります。 さらに,プロトコル識別子とコントロール・フィールドを指定しなければなりません。 プロトコル識別子は 5 バイト,コントロール・フィールドは 1 バイトです。 サービス・クラスがTYPE1
の場合に限りSNAP_SAP
を有効にすることができます。また,IEEE 802.2 標準ではすべての SAP アドレスの最下位から 2 番目のビットを 1 に設定して定義しています。 SAP の値は,目的にあわせて IEEE 802.2 標準に定義に従って使用することをお勧めします。
コントロール・フィールドはパケット・タイプを指定します。 次の値がクラス I,タイプ 1 サービスに定義されています。 以下に記述されている値はクラス I,タイプ 1 サービス用に定義されたものです。 これらはクラス II,タイプ 2 サービスを提供するためにユーザ・サプライ・モードで使用することもできます。
注意
このユーザ・モードを使用するアプリケーションは適切なサービスを提供する役割を担います。 クラス II サービスでサポートされるその他のオペレーションについては,米国電気電子技術者協会 (IEEE) によって発行されている『IEEE Standards for Local Area Networks: Logical Link Control』を参照してください。
交換識別
値
XID
はコマンドまたはレスポンスの交換識別を識別します。
8 ビットのフォーマット識別子と 16 ビットのパラメータが
XID
コントロール・フィールドに続きます。
16 ビットのパラメータはサポートされている LLC サービスと受信ウィンドウ・サイズを識別します。
LLC は IEEE/Std 802 ローカル・エリア・ネットワーク・プロトコルのデータ・リンク層の最上位補助層です。
<dli/dli_var.h>
DLI ヘッダ・ファイルで定義されている
XID
値の値は次のとおりです。
XID_PCMD
ポール・ビットが設定された交換識別コマンド。
交換識別コマンドはサポートされた LLC サービスのタイプと受信ウィンドウ・サイズをデスティネーション LLC に伝送します。
このコマンドによりデスティネーション LLC は早い順に
XID
レスポンス・プロトコル・データ・ユニットでリプライを行ないます。
ポール・ビットは 1 に設定され,PDU のレスポンスを繰り返し要求します。
XID_NPCMD
ポール・ビットが設定されていない交換識別コマンド。
ポール・ビットをクリアする点を除いて上記の
XID_PCMD
と同じです。
レスポンスは期待しません。
XID_PRSP
ポール・ビットが設定された交換識別レスポンス。
データ・リンク層は交換識別レスポンスを使用して早い順に
XID
コマンドにリプライします。
XID
レスポンスの PDU はレスポンスを行なっている LLC を識別し,受信された
XID
コマンド PDU の情報フィールドにある情報の内容にかかわらず,XID
コマンド PDU に定義されているように情報フィールドをインクルードします。
最後のビットが 1 に設定され,このリプライが繰り返し要求を出しているコマンド PDU のリプライとして LLC によって送信されたことを示します。
XID_NPRSP
ポール・ビットが設定されていない交換識別レスポンス。
最後のビットがクリアされている点を除いて,上記の
XID_PRSP
と同じです。
値
TEST
は LLC PDU コマンド・テストまたはレスポンス・テストを識別します。
TEST
コントロール・フィールドの後ろにデータ・フィールドを続けることができます。
DLI ヘッダ・ファイル
<dli/dli_var.h>
で定義されている
TEST
の値は次のとおりです。
TEST_PCMD
ポール・ビットが設定されている
TEST
コマンド。
TEST
コマンドはデスティネーション LLC に早い順に
TEST
レスポンス PDU でレスポンスさせて,LLC 対 LLC の転送パスをテストします。
情報フィールドはこのコントロール・フィールド値ではオプションです。
使用された場合,受信している LLC は情報をユーザに渡すのではなく情報フィールドに代入します。
ポール・ビットが 1 に設定され,レスポンス PDU を繰り返し要求します。
TEST_NPCMD
ポール・ビットが設定されていない
TEST
コマンド。
ポール・ビットがクリアされている点を除き,上記の
TEST_PCMD
と同じです。
TEST_PRSP
ポール・ビットが設定されている
TEST
レスポンス。
TEST
レスポンス PDU は
TEST
コマンド PDU のリプライです。
TEST
コマンド PDU に情報フィールドがある場合は,対応する
TEST
レスポンス PDU に返されます。
最終ビットは 1 に設定され,要求を繰り返しているコマンド PDU のリプライとして LLC によってレスポンスが送信されたことを示します。
TEST_NPRSP
ポール・ビットが設定されていない
TEST
レスポンス。
最終ビットがクリアされている点を除いて上記の
TEST_PRSP
と同じです。
非番号情報コマンド
ポールが設定されていない非番号情報コマンド (UI_NPCMD
) は単一または複数の LLC に情報を送信します。
UI_NPCMD
コマンドは LLC レスポンス PDU を持ちません。
これは通常直接アプリケーションに渡されます。
一般的にクラス I,タイプ 1 アプリケーションはこのコマンドを使用してデータの送受信を行ないます。
この節では,DLI プログラムを書く際のシステム・コールの使用方法,およびイーサネット・サブ構造体と 802 サブ構造体内で値を指定する際の手順について説明します。
F.5 項にこの節で説明する手順の DLI プログラミング例が記載されています。
アプリケーション・プログラムを書く際のソケットおよびシステム・コールの使用方法の詳細は第 4 章を参照してください。
F.4.1 データ・リンク・サービスの提供
DLI はデータグラム・サービスのみを提供するので,DLI アプリケーションは高次レベルのネットワーク・ソフトウェアが通常提供するサービスを提供する必要があります。
フロー・コントロール -- 異なるシステムで実行している DLI プログラムはデータを同期転送しないとデータが失われます。
エラー回復 -- DLI はエラー報告をしますが,エラーの回復はアプリケーションで行なわなくてはなりません。
データ・セグメンテーション -- アプリケーションは転送中にデータのセグメントを行なわなければなりません (イーサネット,802.3,および FDDI パケットのバッファ・サイズについての詳細は F.4.7 項を参照してください)。
DLI プログラムは入力引数,構造体および DLI に特化したサブ構造体とともにソケット・インタフェースを使用します。
たとえば
socket
システム・コールを発行するときにプログラムはアドレス・フォーマット
AF_DLI
およびプロトコル
DLPROTO_DLI
を使用します。
DLI プログラムの先頭で
<dli/dli_var.h>.
ヘッダ・ファイルをインクルードする必要があります。
プログラムの本文は表 F-1
の呼び出し順序に従って記述します。
表 F-1: DLI プログラムの呼び出し順序
機能 | システム・コール |
ソケットの作成 | socket |
アドレス・ファミリ,フレーム・フォーマットおよび
sockaddr_dl
構造体を使用してプログラムがデータを送信するデバイスを指定してソケットとデバイスをバインド |
bind |
ソケット・オプションの設定。 このコールはオプションです。 | setsockopt |
データの転送 | send ,
recv ,
read ,
write ,
sendto ,
recvfrom |
ソケット・デスクリプタの非アクティブ化 | close |
各システム・コールの詳細は第 4 章およびリファレンス・ページを参照してください。
以降の各項では DLI 関数,入力引数および構造体について説明します。
F.4.3 ソケットの作成
DLI アプリケーションでは
socket
システム・コールに次の入力引数を指定してソケットを作成する必要があります。
アドレス・ファミリ: | AF_DLI |
ソケット・タイプ: | SOCK_DGRAM |
プロトコル: | DLPROTO_DLI |
値
AF_DLI
は DLI アドレス・ファミリを指定します。
SOCK_DGRAM
は DLI で使用できる唯一のソケット・タイプのデータグラム・ソケットを作成します。
DLI は他のプログラムに接続するために必要なサービスおよび他のソケット・タイプを使用するために必要なサービスを提供していません。
値
DLPROTO_DLI
は DLI プロトコル・モジュールを指定します。
以下は DLI にソケットをオープンする際の
socket
コールの使用例です。
int so;
.
.
.
if ( (so = socket(AF_DLI,SOCK_DGRAM,DLPROTO_DLI))<0) { perror("cannot open DLI socket"); return (-1); }
setsockopt
コールを使用して,sockaddr_dl
構造体に次のソケット・オプションを設定します。
オプション | 説明 |
DLI_ENAGSAP |
グループ・サービス・アクセス・ポイント (DSAP) を使用可能にする。 |
DLI_DISGSAP |
グループ・サービス・アクセス・ポイント(DSAP)を使用不可にする。 |
DLI_SET802CTL |
802 コントロール・フィールドを設定する。 |
DLI_MULTICAST |
マルチキャスト・アドレスにアドレスされたすべてのメッセージの受信を可能にする。 |
以下のコードはソケット・オプションを設定する際の
setsockopt
コールの例です。
この例は
setsockopt
コールを使用して GSAP オプションを使用可能にするものです。
/* enable GSAPs supplied by user */ j = 3; i = 0; while (j < argc ) { sscanf(argv[j++], "%x", &k); out_opt[i++] = k; } optlen = i; if (setsockopt(sock,DLPROTO_DLI,DLI_ENAGSAP,&out_opt[0],optlen) < 0){ perror("dli_setsockopt: Can't enable gsap"); exit(1); }
この例は
setsockopt
コールを使用して GSAP オプションを使用不可にするものです。
/* disable all but the last 4 or all GSAPs, */ /* whichever is smallest */ if ( optlen > 4 ) optlen -= 4; if (setsockopt(sock,DLPROTO_DLI,DLI_DISGSAP,&out_opt[0],optlen) < 0){ perror("dli_setsockopt: Can't disable gsap"); }
この例は
setsockopt
コールを使用して 802 コントロール・フィールドを設定するものです。
/* set 802 control field */ out_opt[0] = TEST_PCMD; optlen = 1; if (setsockopt(sock,DLPROTO_DLI,DLI_SET802CTL, &out_opt[0],optlen)<0){ perror("dli_setsockopt: Can't set 802 control"); exit(1); }
この例は
setsockopt
コールを使用して 2 つのマルチキャスト・アドレスを使用可能にするものです。
/* enable two multicast addresses */ bcopy(mcast0, out_opt, sizeof(mcast0)); bcopy(mcast1, out_opt+sizeof(mcast0), sizeof(mcast1)); if ( setsockopt(sock, DLPROTO_DLI, DLI_MULTICAST, &out_opt[0], (sizeof(mcast0) + sizeof(mcast1))) < 0 ) { perror("dli_setsockopt: can't enable multicast"); }
詳細な例についてはF.5 項を参照してください。
F.4.5 ソケットのバインド
ソケットの作成後,アプリケーションはソケットとネットワーク・デバイスをバインドしなければなりません。
この時点でメッセージのフォーマット・タイプを指定します。
まずソケットに名前を割り当てます。
変数
name
は
sockaddr_dl
タイプの構造体のポインタとなります。
次に,sockaddr_dl
データ構造体に情報を代入し適当なサブ構造体 (イーサネットまたは 802) をインクルードします。
ソケットのバインドには次の
bind
システム・コールを使用します。
詳細は
bind
(2)
bind
システム・コールについての詳細はリファレンス・ページ
bind
(2)F.4.6 sockaddr_dl 構造体
アドレス・ファミリ
I/O デバイス ID
サブ構造体のタイプ
アドレス・ファミリの指定には,socket
コール内で値
AF_DLI
を使用します。
F.4.6.2 I/O デバイス ID の指定
I/O デバイスはプログラムがどのターゲット・システムを送信先および送信元とするかを制御するコントローラです。 I/O デバイス ID はデバイス名 dli_devname およびデバイス番号 dli_devnumber を含みます。 各変数の定義は次の情報をもとに行ないます。
dli_devname
netstat -i
コマンドがシステムで使用可能なデバイスの一覧を表示します。
dli_devnumber
デバイス番号はシステム構成ファイルで設定されています。
サブ構造体はプログラムが使用するフレーム・フォーマットのタイプを指定します。
dli_eaddr
イーサネット・フレーム・フォーマット (DLI_ETHERNET
)
dli_802addr
802.3 フレーム・フォーマット (DLI_802
)
各タイプに関連するソケットがある場合,プログラムはイーサネット,802.3 および FDDI フレームを送受信することができます。 たとえば,あるシステムではイーサネット・フレームを使用して通信を行ない,他のシステムでは 802.3 または FDDI フレームを使用している場合があります。 フレーム・フォーマットの選択はターゲット・プログラムが使用しているフレームのタイプに依存します。 しかし,1 つのソケットが対応するフレームのタイプは 1 つに限られます。
プログラムはサブ構造体にユーザの選択を代入することでメッセージの送信用のパケット・ヘッダを指定します。
例 F-1
はイーサネット・プロトコル用に
sockaddr_dl
構造体に値を代入する例です。
例 F-2
は 802 プロトコル用に
sockaddr_dl
構造体に値を代入する例です。
例 F-1: イーサネット用 sockaddr_dl 構造体の代入
/* * Fill out the sockaddr_dl structure for the bind call */ bzero(&out_bind, sizeof(out_bind)); out_bind.dli_family = AF_DLI; out_bind.dli_substructype = DLI_ETHERNET; bcopy(devname, out_bind.dli_device.dli_devname, i); out_bind.dli_device.dli_devnumber = devunit; out_bind.choose_addr.dli_eaddr.dli_ioctlflg = ioctl; out_bind.choose_addr.dli_eaddr.dli_protype = ptype; if ( taddr ) bcopy(taddr, out_bind.choose_addr.dli_eaddr.dli_target, DLI_EADDRSIZE); if ( bind(sock, &out_bind, sizeof(out_bind)) < 0 ) { perror("dli_eth, can't bind DLI socket"); return(-1); } return(sock); }
例 F-2: 802.2 用 sockaddr_dl 構造体の代入
/* * Fill out sockaddr_dl structure for the bind call. * Note that we need to determine whether the * control field is 8 bits (unnumbered format) or * 16 bits (informational/supervisory format). We do this * by checking the low order 2 bits, which are both 1 only * for unnumbered control fields. */ bzero(&out_bind, sizeof(out_bind)); out_bind.dli_family = AF_DLI; out_bind.dli_substructype = DLI_802; bcopy(devname, out_bind.dli_device.dli_devname, i); out_bind.dli_device.dli_devnumber = devunit; out_bind.choose_addr.dli_802addr.ioctl = ioctl; out_bind.choose_addr.dli_802addr.svc = svc; if(ctl & 3) out_bind.choose_addr.dli_802addr.eh_802.ctl.U_fmt=(u_char)ctl; else out_bind.choose_addr.dli_802addr.eh_802.ctl.I_S_fmt = ctl; out_bind.choose_addr.dli_802addr.eh_802.ssap = sap; out_bind.choose_addr.dli_802addr.eh_802.dsap = dsap; if ( ptype ) bcopy(ptype,out_bind.choose_addr.dli_802addr.eh_802.osi_pi,5); if ( taddr ) bcopy(taddr, out_bind.choose_addr.dli_802addr.eh_802.dst, DLI_EADDRSIZE); if ( bind(sock, &out_bind, sizeof(out_bind)) < 0 ) { perror("dli_802, can't bind DLI socket"); return(-1); } return(sock); }
バッファ・サイズは通信しているシステムのコントローラが処理できるサイズを超えてはなりません。 超えた場合データは失われます。 イーサネット・パケットのバッファ・サイズの最大値は 1500 バイトです。
802.3 パケットのバッファ・サイズの最大値は次の式で算出します。
bytes = 1500 - [ 2 + (control field == UI? 1:2) + (Source SAP == SNAP SAP ? 5:0)]
コントロール・フィールドおよび
Source SAP
のバイト数は
bind
コールに指定されています。
FDDI パケットのバッファ・サイズの最大値は 4352 バイトです。
F.4.8 データ転送
DLI プログラムは
write
,send
または
sendto
コールを使用してデータを送信,read
,recv
または
recvfrom
コールを使用してデータを受信することができます。
表 F-2
の "○" は
bind
コール中に設定される I/O コントロール・フラグの関数として使用することができるシステム・コールの条件を示します。
注意
Normal コントロール・フラグを使用する場合は
bind
コールでターゲット・アドレスを設定する必要があります。 Exclusive または Default コントロール・フラグを使用する場合はbind
コールでターゲット・アドレスを指定する必要はありません。 しかし,ターゲット・アドレスを設定しない場合はsendto
およびrecvfrom
システム・コールを使用する必要があります。
表 F-2: DLI で使用されるデータ転送システム・コール
システム・コール | Normalコントロール | Exclusiveコントロール | Defaultコントロール |
write |
○ | ||
send |
○ | ||
sendto |
○ | ○ | ○ |
read |
○ | ||
recv |
○ | ||
recvfrom |
○ | ○ | ○ |
コントロール・フラグを
NORMAL
に設定した場合は
bind
コールでターゲット・アドレスを設定して,write
,send
,sendto
,read
,recv
,recvfrom
コールを使用してデータを転送します。
コントロール・フラグを
EXCLUSIVE
に設定した場合は
bind
コールのターゲット・アドレスの値をゼロにして,sendto
コールでターゲット・アドレスを設定します。
データ転送には
sendto
および
recvfrom
コールだけを使用します。
コントロール・フラグを
DEFAULT
に設定した場合は
bind
コールのターゲット・アドレスの値をゼロにして,sendto
コール使用してデータの送信を行ない,このコール内でターゲット・アドレスを設定します。
データのソース・アドレスの識別には
recvfrom
コールを使用します。
F.4.9 ソケットの非アクティブ化
データの送受信が終了したら,close
システム・コールを発行してソケットを非アクティブ化します。
F.5 DLI プログラミング例
イーサネット・フォーマット・パケットを使用した DLI クライアント・プログラム例
イーサネット・フォーマット・パケットを使用した DLI サーバ・プログラム例
802.3 フォーマット・パケットを使用した DLI クライアント・プログラム例
802.3 フォーマット・パケットを使用した DLI サーバ・プログラム例
getsockopt
および
setsockopt
システム・コールを使用した DLI プログラム例
上記のプログラム例は
/usr/examples/dli
ディレクトリにあります。
F.5.1 イーサネット・フォーマット・パケットを使用した DLI クライアント・プログラム例
#include <stdio.h> #include <errno.h> #include <string.h> #include <memory.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <net/if.h> #include <net/route.h> #include <dli/dli_var.h> /* * d l i _ e x a m p l e : d l i _ e t h * * Description: This program sends out a message to a node where a * companion program, dli_ethd, echoes the message back. * The ethernet packet format is used. The ethernet * address of the node where the companion program is * running, the protocol type, and the message are * supplied by the user. The companion program should * be started before executing this program. * * Inputs: device, target address, protocol type, short message. * * Outputs: Exit status. * * To compile: cc -o dli_eth dli_eth.c * * Example: dli_eth ln0 08-00-2b-02-e2-ff 6006 "Echo this" * * Comments: This example demonstrates the use of the "NORMAL" I/O * control flag. The use of the "NORMAL" flag means that * we can communicate only with a single specific node * whose address is specified during the bind. Because * of this, we can use the normal write & read system * calls on the socket, because the source/destination of * all data that is read/written on the socket is fixed. * */ /* * Compaq Computer Corporation supplies this software example on * an "as-is" basis for general customer use. Note that Compaq * does not offer any support for it, nor is it covered under any * of Compaq's support contracts. */ main( int argc, char **argv) { struct sockaddr_dl sdl; size_t sdllen; int ch, fd, rsize, itarget[6], ptype, ioctlflg = DLI_NORMAL, errflg = 0; u_char inbuf[4800], u_char *src; memset(&sdl, 0, sizeof(sdl)); while ((ch = getopt(argc, argv, "xp:")) != EOF) { case 'x': ioctlflg = DLI_EXCLUSIVE; break; case 'p': { if (sscanf(optarg, "%x", &ptype, &ch) != 1) { fprintf(stderr, "%s: invalid protocol type "s argv[0], optarg); errflg++; break; } } default: errflg++; break; } if (errflg || argc - optind < 5) { fprintf(stderr, "%s %s %s\n", "usage:", argv[0], "device lan-address short-message"); exit(1); } /* * Get device name and unit number. */ if (sscanf(argv[optind], "%[a-z]%hd%c", sdl.dli_device.dli_devname, &sdl.dli_device.dli_devnumber, &ch) != 2) { fprintf(stderr, "%s: invalid device name argv[0], argv[optind]); exit(1); } /* * Get the address to which we will be sending */ if (sscanf(argv[++optind], "%x%*[:-]%x%*[:-]%x%*[:-]\ %x%*[:-]%x%*[:-]%x%c", &itarget[0], &itarget[1], &itarget[2], &itarget[3], &itarget[4], &itarget[5], &ch) != 6) { fprintf(stderr, "%s: invalid lan address argv[0], argv[optind]); exit(1); } /* * If the LAN Address is a multicast, then we can't * use DLI_NORMAL. Use DLI_DEFAULT instead. */ if ((itarget[0] & 1) && ioctflg == DLI_NORMAL) ioctlflg = DLI_DEFAULT; /* * Fill out sockaddr structure for bind/sento/recvfrom */ sdl.dli_family = AF_DLI; if (ptype < GLOBAL_SAP) { sdl.dli_substructype = DLI_802; sdl.choose_addr.dli_802addr.ioctl = ioctlflg; sdl.choose_addr.dli_802addr.svc = TYPE1; sdl.choose_addr.dli_802addr.eh_802.dsap = ptype; sdl.choose_addr.dli_802addr.eh_802.ssap = ptype; sdl.choose_addr.dli_802addr.eh_802.ctl.U_fmt = UI_NPCMD; src = sdl.choose_addr.dli_802addr.eh_802.dst; } else { sdl.dli_substructype = DLI_ETHERNET; sdl.choose_addr.dli_eaddr.dli_ioctlflg = ioctlflg; sdl.choose_addr.dli_eaddr.dli_protype = ptype; src = sdl.choose_addr.dli_eaddr.dli_target; } /* * If we are using DLI_NORMAL, we must supply */ if (ioctlflg == DLI_NORMAL) { src[0] = itarget[0]; src[1] = itarget[1]; src[2] = itarget[2]; src[3] = itarget[3]; src[4] = itarget[4]; src[5] = itarget[5]; } /* * Open a socket to DLI and then bind to our protocol/address. */ if ((fd = socket(AF_DLI, SOCK_DGRAM, DLPROTO_DLI)) < 0) { fprintf(stderr, "%s: DLI open failed: %s\n", argv[0], strerror(errno)); exit(1); } if (bind(fd, (struct sockaddr *) &sdl, sizeof(sdl)) < 0) { fprintf(stderr, "%s: DLI bind failed: %s\n", argv[0], strerror(errno)); exit(2); } if (ioctlflg != DLI_NORMAL) { src[0] = itarget[0]; src[1] = itarget[1]; src[2] = itarget[2]; src[3] = itarget[3]; src[4] = itarget[4]; src[5] = itarget[5]; } /* send response to originator. */ sdllen = sizeof(sdl); if (sendto(fd, argv[4], strlen(argv[4]), 0, (struct sockaddr *) &sdl, sdllen) < 0) { fprintf(stderr, "%s: DLI transmission failed: %s\n", argv[0], strerror(errno)); exit(1); } if ((rsize = recvfrom(fd, inbuf, sizeof(inbuf), 0, (struct sockaddr *) &sdl, &sdllen)) < 0 ) { fprintf(stderr, "%s: DLI reception failed: %s\n", argv[0], strerror(errno)); exit(1); } /* check header */ if (sdllen != sizeof(struct sockaddr_dl)) { fprintf(stderr, "%s, incorrect header supplied\n", argv[0]); exit(1); } if (from.dli_substructype == DLI_802) src = from.dli_choose_addr.dli_802addr.eh_802.dst; else src = from.dli_choose_addr.dli_eaddr.dli_target; /* any data? */ fprintf(stderr, "%s: %sdata received from ", argv[0], rsize ? : "NO "); fprintf(stderr, "%02x-%02x-%02x-%02x-%02x-%02x", src[0], src[1], src[2], src[3], src[4], src[5]); if (from.dli_substructype == DLI_802) fprintf(stderr, " SAP %02x\n\n", sdl.choose_addr.dli_802addr.eh_802.ssap & ~1); else fprintf(stderr, " on protocol type %04x\n\n", sdl.choose_addr.dli_eaddr.dli_protype); /* print results */ printf("%s\n", inbuf); close(fd); return 0; }
F.5.2 イーサネット・フォーマット・パケットを使用した DLI サーバ・プログラム例
#ifndef lint static char *rcsid = "@(#)$RCSfile: ap-dli.sgml,v $ \ $Revision: 1.1.6.3 $ (DEC) $Date: 1999/07/08 20:46:48 $"; #endif #include <stdio.h> #include <ctype.h> #include <errno.h> #include <strings.h> #include <sys/types.h> #include <sys/socket.h> #include <net/if.h> #include <netinet/in.h> #include <netinet/if_ether.h> #include <dli/dli_var.h> #include <sys/ioctl.h> extern int errno; /* * d l i _ e x a m p l e : d l i _ e t h d * * Description: This daemon program transmits any message it * receives to the originating system, i.e., it echoes the * message back. The device and protocol type are supplied * by the user. The program uses ethernet format packets. * * Inputs: device, protocol type. * * Outputs: Exit status. * * To compile: cc -o dli_ethd dli_ethd.c * * Example: dli_ethd de0 6006 * * Comments: This example demonstrates the use of the "DEFAULT" * I/O control flag, and the recvfrom & sendto system calls. * By specifying "DEFAULT" when binding the DLI socket to * the device we inform the system that this program will * receive any ethernet format packet with the given * protocol type which is not meant for any other program * on the system. Since packets may arrive from * different systems we use the recvfrom call to read the * packets. This call gives us access to the packet * header information so that we can determine where the * packet came from. When we write on the socket we must * use the sendto system call to explicitly give the * destination of the packet. */ /* * Compaq Computer Corporation supplies this software * example on an "as-is" basis for general customer use. Note * that Compaq does not offer any support for it, nor is it * covered under any of Compaq's support contracts. */ main(argc, argv, envp) int argc; char **argv, **envp; { u_char inbuf[1500], outbuf[1500]; u_char devname[16]; u_char target_eaddr[6]; char *cp; int rsize; unsigned int devunit; int i, sock, fromlen; unsigned int ptype; struct sockaddr_dl from; if ( argc < 3 ) { fprintf(stderr, "usage: %s device hex-protocol-type\n", argv[0]); exit(1); } /* get device name and unit number. */ bzero(devname, sizeof(devname)); i = 0; cp = argv[1]; while ( isalpha(*cp) ) devname[i++] = *cp++; sscanf(cp, "%d", &devunit); /* get protocol type */ sscanf(argv[2], "%x", &ptype); /* open dli socket */ if ((sock = dli_econn(devname, devunit, ptype, NULL, \ DLI_DEFAULT))<0) { perror("dli_ethd, dli_econn failed"); exit(1); } while ( 1 ) { /* wait for message */ from.dli_family = AF_DLI; fromlen = sizeof(struct sockaddr_dl); if ((rsize = recvfrom(sock, inbuf, sizeof(inbuf), NULL, &from, &fromlen)) < 0 ) { sprintf(inbuf, "%s: DLI reception failed", argv[0]); perror(inbuf); exit(2); } /* check header */ if ( fromlen != sizeof(struct sockaddr_dl) ) { fprintf(stderr,"%s, incorrect header supplied\n",argv[0]); continue; } /* any data? */ if ( ! rsize ) fprintf(stderr, "%s, NO data received from ", argv[0]); else fprintf(stderr, "%s, data received from ", argv[0]); for ( i = 0; i < 6; i++ ) fprintf(stderr, "%x%s", from.choose_addr.dli_eaddr.dli_target[i], ((i<5)?"-":" ")); fprintf(stderr, "on protocol type %x\n", from.choose_addr.dli_eaddr.dli_protype); /* send response to originator. */ if ( sendto(sock, inbuf, rsize, NULL, &from, fromlen) < 0 ) { sprintf(outbuf, "%s: DLI transmission failed", argv[0]); perror(outbuf); exit(2); } } } /* * d l i _ e c o n n * * * * Description: * This subroutine opens a dli socket, then binds an associated * device name and protocol type to the socket. * * Inputs: * devname = ptr to device name * devunit = device unit number * ptype = protocol type * taddr = target address * ioctl = io control flag * * Outputs: * returns = socket handle if success, otherwise -1 */ dli_econn(devname, devunit, ptype, taddr, ioctl) char *devname; unsigned devunit; unsigned ptype; u_char *taddr; u_char ioctl; { int i, sock; struct sockaddr_dl out_bind; if ( (i = strlen(devname)) > sizeof(out_bind.dli_device.dli_devname) ) { fprintf(stderr, "dli_ethd: bad device name"); return(-1); } if ((sock = socket(AF_DLI, SOCK_DGRAM, DLPROTO_DLI)) < 0) { perror("dli_ethd, can't open DLI socket"); return(-1); } /* Fill out bind structure */ bzero(&out_bind, sizeof(out_bind)); out_bind.dli_family = AF_DLI; out_bind.dli_substructype = DLI_ETHERNET; bcopy(devname, out_bind.dli_device.dli_devname, i); out_bind.dli_device.dli_devnumber = devunit; out_bind.choose_addr.dli_eaddr.dli_ioctlflg = ioctl; out_bind.choose_addr.dli_eaddr.dli_protype = ptype; if ( taddr ) bcopy(taddr, out_bind.choose_addr.dli_eaddr.dli_target, DLI_EADDRSIZE); if ( bind(sock, &out_bind, sizeof(out_bind)) < 0 ) { perror("dli_ethd, can't bind DLI socket"); return(-1); } return(sock); }
F.5.3 802.3 フォーマット・パケットを使用した DLI クライアント・プログラム例
#ifndef lint static char *sccsid = "@(#)dli_802.c 1.1 (DEC OSF/1) 5/29/92"; #endif lint #include <stdio.h> #include <ctype.h> #include <errno.h> #include <strings.h> #include <sys/types.h> #include <sys/socket.h> #include <net/if.h> #include <netinet/in.h> #include <netinet/if_ether.h> #include <dli/dli_var.h> #include <sys/ioctl.h> extern int errno; #define PROTOCOL_ID {0x00, 0x00, 0x00, 0x00, 0x5} u_char protocolid[] = PROTOCOL_ID; /* * d l i _ e x a m p l e : d l i _ 8 0 2 * * Description: This program sends out a message to a system * where a companion program, dli_802d, echoes the message * back. The 802.3 packet format is used. The ethernet * address of the system where the companion program is * running, the sap, and the message are supplied by the * user. The companion program should be started before * executing this program. * * Inputs: device, target address, sap, short message. * * Outputs: Exit status. * */ #ifndef lint static char *rcsid = "@(#)$RCSfile: ap-dli.sgml,v $ \ $Revision: 1.1.6.3 $ (DEC) $Date: 1999/07/08 20:46:48 $"; #endif #include <stdio.h> #include <ctype.h> #include <errno.h> #include <strings.h> #include <sys/types.h> #include <sys/socket.h> #include <net/if.h> #include <netinet/in.h> #include <netinet/if_ether.h> #include <dli/dli_var.h> #include <sys/ioctl.h> extern int errno; #define PROTOCOL_ID {0x00, 0x00, 0x00, 0x00, 0x5} u_char protocolid[] = PROTOCOL_ID; /* * d l i _ e x a m p l e : d l i _ 8 0 2 * * Description: This program sends out a message to a system * where a companion program, dli_802d, echoes the message * back. The 802.3 packet format is used. The ethernet * address of the system where the companion program is * running, the sap, and the message are supplied by the * user. The companion program should be started before * executing this program. * * Inputs: device, target address, sap, short message. * * Outputs: Exit status. * * To compile: cc -o dli_802 dli_802.c * * Example: dli_802 qe0 08-00-2b-02-e2-ff ac "Echo this" * * Comments: This example demonstrates the use of 802 "TYPE1" * service. With TYPE1 service, the processing of * XID and TEST messages is handled transparently by * DLI, i.e., this program doesn't have to be concerned * with handling them. If the SNAP SAP (0xAA) is * selected, a 5 byte protocol id is also required. * This example automatically uses a protocol id of * of PROTOCOL_ID when the SNAP SAP is used. Also, * note the use of DLI_NORMAL for the i/o control flag. * DLI makes use of this only when that SNAP_SAP/Protocol * ID pair is used. DLI will filter all incoming messages * by comparing the Ethernet source address and Protocol * ID against the target address and Protocol ID set up * in the bind call. Only if a match occurs will DLI * pass the message up to the application. */ /* * Compaq Computer Corporation supplies this software * example on an "as-is" basis for general customer use. Note * that Compaq does not offer any support for it, nor is it * covered under any of Compaq's support contracts. */ main(argc, argv, envp) int argc; char **argv, **envp; { u_char inbuf[1500], outbuf[1500]; u_char target_eaddr[6]; u_char devname[16]; int rsize, devunit; char *cp; int i, sock, fromlen; struct sockaddr_dl from; unsigned int obsiz, byteval; u_int sap; u_char *pi = 0; if ( argc < 5 ) { fprintf(stderr, "%s %s %s\n", "usage:", argv[0], "device ethernet-address hex-sap short-message"); exit(1); } /* get device name and unit number. */ bzero(devname, sizeof(devname)); i = 0; cp = argv[1]; while ( isalpha(*cp) ) devname[i++] = *cp++; sscanf(cp, "%d", &devunit); /* get phys addr of remote system */ bzero(target_eaddr, sizeof(target_eaddr)); i = 0; cp = argv[2]; while ( *cp ) { if ( *cp == '-' ) { cp++; continue; } else { sscanf(cp, "%2x", &byteval ); target_eaddr[i++] = byteval; cp += 2; } } /* get sap */ sscanf(argv[3], "%x", &sap); /* get message */ bzero(outbuf, sizeof(outbuf)); if ( (obsiz = strlen(argv[4])) > 1500 ) { fprintf(stderr, "%s: message is too long\n", argv[0]); exit(2); } strcpy(outbuf, argv[4]); /* open dli socket. notice that if (and only if) the */ /* snap sap was selected then a protocol id must also */ /* be provided. */ if ( sap == SNAP_SAP ) pi = protocolid; if ( (sock = dli_802_3_conn(devname, devunit, pi, target_eaddr, DLI_NORMAL, TYPE1, sap, sap, UI_NPCMD)) < 0 ) { perror("dli_802, dli_econn failed"); exit(3); } /* send message to target. minimum message size is 46 bytes. */ if ( write(sock, outbuf, (obsiz < 46 ? 46 : obsiz)) < 0 ) { sprintf(outbuf, "%s: DLI transmission failed", argv[0]); perror(outbuf); exit(4); } /* wait for response from correct address */ while (1) { bzero(&from, sizeof(from)); from.dli_family = AF_DLI; fromlen = sizeof(struct sockaddr_dl); if ((rsize = recvfrom(sock, inbuf, sizeof(inbuf), NULL, &from, &fromlen)) < 0 ) { sprintf(inbuf, "%s: DLI reception failed", argv[0]); perror(inbuf); exit(5); } if ( fromlen != sizeof(struct sockaddr_dl) ) { fprintf(stderr,"%s, invalid address size\n",argv[0]); exit(6); } if ( bcmp(from.choose_addr.dli_802addr.eh_802.dst, target_eaddr, sizeof(target_eaddr)) == 0 ) break; } if ( ! rsize ) { fprintf(stderr, "%s, no data returned\n", argv[0]); exit(7); } /* print message */ printf("%s\n", inbuf); close(sock); } /* * d l i _8 0 2 _ 3 _ c o n n * * * * Description: * This subroutine opens a dli 802.3 socket, then binds an * associated device name and protocol type to the socket. * * Inputs: * devname = ptr to device name * devunit = device unit number * ptype = protocol type * taddr = target address * ioctl = io control flag * svc = service class * sap = source sap * dsap = destination sap * ctl = control field * * * Outputs: * returns = socket handle if success, otherwise -1 * * */ dli_802_3_conn (devname,devunit,ptype,taddr,ioctl,svc,sap,dsap,ctl) char *devname; u_short devunit; u_char *ptype; u_char *taddr; u_char ioctl; u_char svc; u_char sap; u_char dsap; u_short ctl; { int i, sock; struct sockaddr_dl out_bind; if ( (i = strlen(devname)) > sizeof(out_bind.dli_device.dli_devname) ) { fprintf(stderr, "dli_802: bad device name"); return(-1); } if ((sock = socket(AF_DLI, SOCK_DGRAM, DLPROTO_DLI)) < 0) { perror("dli_802, can't open DLI socket"); return(-1); } /* * Fill out bind structure. Note that we need to determine * whether the ctl field is 8 bits (unnumbered format) or * 16 bits (informational/supervisory format). We do this * by checking the low order 2 bits, which are both 1 only * for unnumbered control fields. */ bzero(&out_bind, sizeof(out_bind)); out_bind.dli_family = AF_DLI; out_bind.dli_substructype = DLI_802; bcopy(devname, out_bind.dli_device.dli_devname, i); out_bind.dli_device.dli_devnumber = devunit; out_bind.choose_addr.dli_802addr.ioctl = ioctl; out_bind.choose_addr.dli_802addr.svc = svc; if(ctl & 3) out_bind.choose_addr.dli_802addr.eh_802.ctl.U_fmt=\ (u_char)ctl; else out_bind.choose_addr.dli_802addr.eh_802.ctl.I_S_fmt = \ ctl; out_bind.choose_addr.dli_802addr.eh_802.ssap = sap; out_bind.choose_addr.dli_802addr.eh_802.dsap = dsap; if ( ptype ) bcopy(ptype,out_bind.choose_addr.dli_802addr.eh_802.osi_pi,\ 5); if ( taddr ) bcopy(taddr, out_bind.choose_addr.dli_802addr.eh_802.dst, DLI_EADDRSIZE); if ( bind(sock, &out_bind, sizeof(out_bind)) < 0 ) { perror("dli_802, can't bind DLI socket"); return(-1); } return(sock); }
F.5.4 802.3 フォーマット・パケットを使用した DLI サーバ・プログラム例
#ifndef lint static char *rcsid = "@(#)$RCSfile: ap-dli.sgml,v $ \ $Revision: 1.1.6.3 $ (DEC) $Date: 1999/07/08 20:46:48 $"; #endif #include <stdio.h> #include <ctype.h> #include <errno.h> #include <strings.h> #include <sys/types.h> #include <sys/socket.h> #include <net/if.h> #include <netinet/in.h> #include <netinet/if_ether.h> #include <dli/dli_var.h> #include <sys/ioctl.h> extern int errno; #define PROTOCOL_ID {0x00, 0x00, 0x00, 0x00, 0x5} u_char protocolid[] = PROTOCOL_ID; /* * d l i _ e x a m p l e : d l i _ 8 0 2 d * * Description: This daemon program transmits any message it * receives to the originating system, i.e., it echoes the * message back. The device and sap are supplied by the * user. The program uses 802.3 format packets. * * Inputs: device, sap. * * Outputs: Exit status. * * To compile: cc -o dli_802d dli_802d.c * * Example: dli_802d de0 ac * * Comments: This example demonstrates the recvfrom & sendto * system calls. Since packets may arrive from different * systems we use the recvfrom call to read the packets. * This call gives us access to the packet header information * so that we can determine where the packet came from. * When we write on the socket we must use the sendto * system call to explicitly give the destination of * the packet. The use of the "DEFAULT" I/O control flag * only applies (i.e. only has an affect) when the SNAP SAP * is used. When the SNAP SAP is used, any arriving packets * which have the specified protocol id and which are not * destined for some other program will be given to this * program. */ /* * Compaq Computer Corporation supplies this software * example on an "as-is" basis for general customer use. * Note that Compaq does not offer any support for it, nor * is it covered under any of Compaq's support contracts. */ main(argc, argv, envp) int argc; char **argv, **envp; { u_char inbuf[1500], outbuf[1500]; u_char devname[16]; u_char target_eaddr[6]; char *cp; int rsize, devunit; int i, sock, fromlen; u_char tmpsap, sap; struct sockaddr_dl from; u_char *pi = 0; if ( argc < 3 ) { fprintf(stderr, "usage: %s device hex-sap\n", argv[0]); exit(1); } /* get device name and unit number. */ bzero(devname, sizeof(devname)); i = 0; cp = argv[1]; while ( isalpha(*cp) ) devname[i++] = *cp++; sscanf(cp, "%d", &devunit); /* get sap */ sscanf(argv[2], "%x", &sap); /* open dli socket. note that if (and only if) the snap sap */ /* was selected then a protocol id must also be specified. */ if ( sap == SNAP_SAP ) pi = protocolid; if ((sock = dli_802_3_conn(devname, devunit, pi, target_eaddr, DLI_DEFAULT, TYPE1, sap, sap, UI_NPCMD)) < 0) { perror("dli_802d, dli_conn failed"); exit(1); } /* listen and respond */ while ( 1 ) { /* wait for message */ from.dli_family = AF_DLI; fromlen = sizeof(struct sockaddr_dl); if ((rsize = recvfrom(sock, inbuf, sizeof(inbuf), NULL, &from, &fromlen)) < 0 ) { sprintf(inbuf, "%s: DLI reception failed", argv[0]); perror(inbuf); exit(2); } /* check header */ if ( fromlen != sizeof(struct sockaddr_dl) ) { fprintf(stderr,"%s, incorrect header supplied\n",\ argv[0]); continue; } /* * Note that DLI swaps the source & destination saps and * lan addresses in the sockaddr_dl structure returned * by the recvfrom call. That is, it places the DSAP in * eh_802.ssap and the SSAP in eh_802.dsap; it also places * the destination lan address in eh_802.src and the source * lan address in eh_802.dst. This allows for minimal to * no manipulation of the address structure for subsequent * sendto or dli connection calls. */ /* any data? */ if ( ! rsize ) fprintf(stderr, "%s: NO data received from ", \ argv[0]); else fprintf(stderr, "%s: data received from ", argv[0]); for ( i = 0; i < 6; i++ ) fprintf(stderr, "%x%s", from.choose_addr.dli_802addr.eh_802.dst[i], ((i<5)?"-":" ")); fprintf(stderr, "\n on dsap %x ", from.choose_addr.dli_802addr.eh_802.ssap); if ( from.choose_addr.dli_802addr.eh_802.dsap == \ SNAP_SAP ) fprintf(stderr, "(SNAP SAP), protocol id= %x-%x-%x-%x-%x\n ", from.choose_addr.dli_802addr.eh_802.osi_pi[0], from.choose_addr.dli_802addr.eh_802.osi_pi[1], from.choose_addr.dli_802addr.eh_802.osi_pi[2], from.choose_addr.dli_802addr.eh_802.osi_pi[3], from.choose_addr.dli_802addr.eh_802.osi_pi[4]); fprintf(stderr, " from ssap %x ", from.choose_addr.dli_802addr.eh_802.dsap); fprintf(stderr, "\n\n"); /* send response to originator. */ if ( from.choose_addr.dli_802addr.eh_802.dsap == \ SNAP_SAP ) bcopy(protocolid, from.choose_addr.dli_802addr.eh_802.osi_pi, 5); if ( sendto(sock, inbuf, rsize, NULL, &from, fromlen) \ < 0 ) { sprintf(outbuf, "%s: DLI transmission failed", \ argv[0]); perror(outbuf); exit(2); } } } /* * d l i _8 0 2 _ 3 _ c o n n * * * * Description: * This subroutine opens a dli 802.3 socket, then binds an * associated device name and protocol type to the socket. * * Inputs: * devname = ptr to device name * devunit = device unit number * ptype = protocol type * taddr = target address * ioctl = io control flag * svc = service class * sap = source sap * dsap = destination sap * ctl = control field * * * Outputs: * returns = socket handle if success, otherwise -1 * * */ dli_802_3_conn (devname,devunit,ptype,taddr,ioctl,svc,sap,\ dsap,ctl) char *devname; u_short devunit; u_char *ptype; u_char *taddr; u_char ioctl; u_char svc; u_char sap; u_char dsap; u_short ctl; { int i, sock; struct sockaddr_dl out_bind; if ( (i = strlen(devname)) > sizeof(out_bind.dli_device.dli_devname) ) { fprintf(stderr, "dli_802d: bad device name"); return(-1); } if ((sock = socket(AF_DLI, SOCK_DGRAM, DLPROTO_DLI)) < 0) { perror("dli_802d, can't open DLI socket"); return(-1); } /* * fill out bind structure. note that we need to determine * whether the ctl field is 8 bits (unnumbered format) or * 16 bits (informational/supervisory format). We do this * by checking the low order 2 bits, which are both 1 only * for unnumbered control fields. */ bzero(&out_bind, sizeof(out_bind)); out_bind.dli_family = AF_DLI; out_bind.dli_substructype = DLI_802; bzero(&out_bind, sizeof(out_bind)); out_bind.dli_family = AF_DLI; out_bind.dli_substructype = DLI_802; bcopy(devname, out_bind.dli_device.dli_devname, i); out_bind.dli_device.dli_devnumber = devunit; out_bind.choose_addr.dli_802addr.ioctl = ioctl; out_bind.choose_addr.dli_802addr.svc = svc; if(ctl & 3) out_bind.choose_addr.dli_802addr.eh_802.ctl.U_fmt=\ (u_char)ctl; else out_bind.choose_addr.dli_802addr.eh_802.ctl.I_S_fmt = \ ctl; out_bind.choose_addr.dli_802addr.eh_802.ssap = sap; out_bind.choose_addr.dli_802addr.eh_802.dsap = dsap; if ( ptype ) bcopy(ptype,out_bind.choose_addr.dli_802addr.eh_802.osi_pi,\ 5); if ( taddr ) bcopy(taddr, out_bind.choose_addr.dli_802addr.eh_802.dst, DLI_EADDRSIZE); if ( bind(sock, &out_bind, sizeof(out_bind)) < 0 ) { perror("dli_802d, can't bind DLI socket"); return(-1); } return(sock); }
F.5.5 getsockopt および setsockopt を使用した DLI プログラム例
#ifndef lint static char *sccsid = "@(#)dli_setsockopt.c 1.5 3/27/90"; #endif lint #include <stdio.h> #include <ctype.h> #include <errno.h> #include <strings.h> #include <sys/types.h> #include <sys/socket.h> #include <net/if.h> #include <netinet/in.h> #include <netinet/if_ether.h> #include <dli/dli_var.h> #include <sys/ioctl.h> extern int errno; int debug = 0; #define PROTOCOL_ID {0x00, 0x00, 0x00, 0x00, 0x5} #define CUSTOMER0 {0xab, 0x00, 0x04, 0x00, 0x00, 0x00} #define CUSTOMER1 {0xab, 0x00, 0x04, 0x00, 0x00, 0x01} u_char mcast0[] = CUSTOMER0; u_char mcast1[] = CUSTOMER1; u_char protocolid[] = PROTOCOL_ID; /* * * d l i e x a m p l e : d l i s e t s o c k o p t * * Description: This program demonstrates the use of the DLI * get- and setsockopt calls. It opens a socket, enables * 2 multicast addresses, changes the 802 control * field, enables a number of group saps supplied by * the user, and reads the group saps that are enabled. * * Inputs: device, sap, group-saps. * * Outputs: Exit status. * * To compile: cc -o dli_setsockopt dli_setsockopt.c * * Example: dli_setsockopt qe0 ac 5 9 d * * Comments: When a packet arrives with a group dsap, * all dli programs that have that group sap enabled will * receive copies of that packet. Group saps are * those with the low order bit set. Group sap 1 * is currently not allowed for customer use. Group * saps with the second bit set (eg 3,7,etc) are * reserved by IEEE. */ /* * Compaq Computer Corporation supplies this software example * on an "as-is" basis for general customer use. Note that * Compaq does not offer any support for it, nor is it covered * under any of Compaq's support contracts. */ main(argc, argv, envp) int argc; char **argv, **envp; { u_char inbuf[1500], outbuf[1500]; u_char devname[16]; u_char target_eaddr[6]; char *cp; int rsize, devunit; int i, j, k, sock, fromlen; u_short obsiz; u_char tmpsap, sap; struct sockaddr_dl from; u_char *pi = 0; u_char out_opt[1000], in_opt[1000]; int optlen, ioptlen = sizeof(in_opt); if ( argc < 4 ) { fprintf(stderr, "usage: %s device hex-sap hex-groupsaps\n", argv[0]); exit(1); } /* get device name and unit number. */ bzero(devname, sizeof(devname)); i = 0; cp = argv[1]; while ( isalpha(*cp) ) devname[i++] = *cp++; sscanf(cp, "%d", &devunit); /* get protocol type */ sscanf(argv[2], "%x", &sap); /* open dli socket */ if ( sap == SNAP_SAP ) { fprintf(stderr, "%s: can't use SNAP_SAP in USER mode\n", argv[0]); exit(1); } if ( (sock = dli_802_3_conn(devname, devunit, pi,\ target_eaddr, DLI_DEFAULT, USER, sap, sap, UI_NPCMD)) \ < 0 ) { perror("dli_setsockopt: dli_conn failed"); exit(1); } /* enable two multicast addresses */ bcopy(mcast0, out_opt, sizeof(mcast0)); bcopy(mcast1, out_opt+sizeof(mcast0), sizeof(mcast1)); if ( setsockopt(sock, DLPROTO_DLI, DLI_MULTICAST, \ &out_opt[0], (sizeof(mcast0) + sizeof(mcast1))) < 0 ) { perror("dli_setsockopt: can't enable multicast"); } /* set 802 control field */ out_opt[0] = TEST_PCMD; optlen = 1; if (setsockopt(sock,DLPROTO_DLI,DLI_SET802CTL,&out_opt[0],\ optlen)<0){ perror("dli_setsockopt: Can't set 802 control"); exit(1); } /* enable GSAPs supplied by user */ j = 3; i = 0; while (j < argc ) { sscanf(argv[j++], "%x", &k); out_opt[i++] = k; } optlen = i; if (setsockopt(sock,DLPROTO_DLI,DLI_ENAGSAP,&out_opt[0],\ optlen) < 0){ perror("dli_setsockopt: Can't enable gsap"); exit(1); } /* verify all gsaps are enabled */ bzero(in_opt, (ioptlen = sizeof(in_opt))); if (getsockopt(sock,DLPROTO_DLI,DLI_GETGSAP,in_opt,\ &ioptlen) < 0){ perror("dli_setsockopt: DLI getsockopt 2 failed"); exit(1); } printf("number of enabled GSAPs = %d, GSAPS:", ioptlen); for(i = 0; i < ioptlen; i++) { if ( ! (i % 10) ) printf("\n"); printf("%2x ",in_opt[i]); } printf("\n"); /* disable all but the last 4 or all GSAPs, */ /* whichever is smallest */ if ( optlen > 4 ) optlen -= 4; if (setsockopt(sock,DLPROTO_DLI,DLI_DISGSAP,&out_opt[0],\ optlen) < 0){ perror("dli_setsockopt: Can't disable gsap"); } /* verify some gsaps still enabled */ bzero(in_opt, (ioptlen = sizeof(in_opt))); if (getsockopt(sock,DLPROTO_DLI,DLI_GETGSAP,in_opt,\ &ioptlen) < 0){ perror("dli_setsockopt: getsockopt 3 failed"); exit(1); } printf("number of enabled GSAPs = %d, GSAPS:", ioptlen); for(i = 0; i < ioptlen; i++) { if ( ! (i % 10) ) printf("\n"); printf("%2x ",in_opt[i]); } printf("\n"); } /* * d l i _8 0 2 _ 3 _ c o n n * * * * Description: * This subroutine opens a dli 802.3 socket and then binds * an associated device name and protocol type to it. * * Inputs: * devname = ptr to device name * devunit = device unit number * ptype = protocol type * taddr = target address * ioctl = io control flag * svc = service class * sap = source sap * dsap = destination sap * ctl = control field * * * Outputs: * returns = socket handle if success, otherwise -1 * */ dli_802_3_conn (devname,devunit,ptype,taddr,ioctl,svc,sap,\ dsap,ctl) char *devname; u_short devunit; u_char *ptype; u_char *taddr; u_char ioctl; u_char svc; u_char sap; u_char dsap; u_short ctl; { int i, sock; struct sockaddr_dl out_bind; if ( (i = strlen(devname)) > sizeof(out_bind.dli_device.dli_devname) ) { fprintf(stderr, "dli_setsockopt: bad device name"); return(-1); } if ((sock = socket(AF_DLI, SOCK_DGRAM, DLPROTO_DLI)) < 0) { perror("dli_setsockopt: can't open DLI socket"); return(-1); } /* * Fill out bind structure */ bzero(&out_bind, sizeof(out_bind)); out_bind.dli_family = AF_DLI; out_bind.dli_substructype = DLI_802; bcopy(devname, out_bind.dli_device.dli_devname, i); out_bind.dli_device.dli_devnumber = devunit; out_bind.choose_addr.dli_802addr.ioctl = ioctl; out_bind.choose_addr.dli_802addr.svc = svc; if(ctl & 3) out_bind.choose_addr.dli_802addr.eh_802.ctl.U_fmt=\ (u_char)ctl; else out_bind.choose_addr.dli_802addr.eh_802.ctl.I_S_fmt = \ ctl; out_bind.choose_addr.dli_802addr.eh_802.ssap = sap; out_bind.choose_addr.dli_802addr.eh_802.dsap = dsap; if ( ptype ) bcopy(ptype,out_bind.choose_addr.dli_802addr.eh_802.osi_pi,\ 5); if ( taddr ) bcopy(taddr, out_bind.choose_addr.dli_802addr.eh_802.dst, DLI_EADDRSIZE); if ( bind(sock, &out_bind, sizeof(out_bind)) < 0 ) { perror("dli_setsockopt: can't bind DLI socket"); return(-1); } return(sock); }