/*	
 *	clipnet.h
 *
 *	ネットワーク関連のサポートルーチン
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2005 Naoyuki Sawa
 *
 *	* Sun Jul 24 04:08:00 JST 2005 Naoyuki Sawa
 *	- 作成開始。
 *	* Tue Aug 02 06:25:00 JST 2005 Naoyuki Sawa
 *	- update_internet_checksum()、ip_unpack_header()、ip_pack_header()を追加しました。
 *	* Sun Aug 07 04:10:00 JST 2005 Naoyuki Sawa
 *	- ip_pack_header()、ip_unpack_header()をpack_ip_header()、unpack_ip_header()に改名しました。
 *	* Thu Aug 25 12:46:00 JST 2005 Naoyuki Sawa
 *	- address_class_mask()を追加しました。
 *	* Fri Aug 26 04:09:00 JST 2005 Naoyuki Sawa
 *	- IP_ADDRESS()マクロを追加しました。
 *	* Mon Sep 12 05:27:00 JST 2005 Naoyuki Sawa
 *	- internet_checksum_pseudo_header()、update_internet_checksum_pseudo_header()を追加しました。
 *	* Tue Sep 13 22:28:00 JST 2005 Naoyuki Sawa
 *	- address_class_mask()をip_address_class_mask()に改名しました。
 *	- unpack_tcp_header()、pack_tcp_header()を追加しました。
 *	* Thu Sep 15 19:51:00 JST 2005 Naoyuki Sawa
 *	- pack_ip_header()、pack_tcp_header()にて、data_length=0の場合に、data=NULLを許可としました。
 */
#ifndef __CLIP_NET_H__
#define __CLIP_NET_H__

/****************************************************************************
 *	
 ****************************************************************************/

/* IPアドレスやサブネットマスクを作成するマクロ */
#define IP_ADDRESS(a,b,c,d)	(((a)<<24)|((b)<<16)|((c)<<8)|(d))

/* IPデータグラム・ヘッダ (必要な部分だけ) */
typedef struct _IPHEADER {
	int identification;		/* 識別 */
	int flags;			/* フラグ */
	int fragment_offset;		/* フラグメントオフセット */
	int protocol;			/* プロトコル */
	int source_ip_address;		/* 送信元IPアドレス */
	int destination_ip_address;	/* 宛先IPアドレス */
	//
	unsigned char* data;		/* データ */
	int data_length;		/* データ長 */
} IPHEADER;

/* IPHEADER.flags */
//#define ...	(1<<0)	/* ビット0 予約 (0) */
#define IP_DF	(1<<1)	/* ビット1 (DF : Don't Fragment) 0=フラグメント化する、1=フラグメント化しない */
#define IP_MF	(1<<2)	/* ビット2 (MF : More Fragments) 0=最後のフラグメント、1=継続フラグメント */

/****************************************************************************
 *	
 ****************************************************************************/

/* TCPセグメントヘッダ */
typedef struct _TCPHEADER {
	/*----- ヘッダ -----*/
	int source_port;		/* 送信元ポート */
	int destination_port;		/* 宛て先ポート */
	int sequence_number;		/* シーケンス番号 */
	int acknowledgement_number;	/* 応答確認番号 */
	int control_flag;		/* コントロールフラグ */
	int window;			/* ウインドウ */
	/*----- データ -----*/
	unsigned char* data;		/* データ */
	int data_length;		/* データ長 */
} TCPHEADER;

/* TCPHEADER.control_flag */
#define TCP_FIN	(1<<0)	/* 送信側からの後続データ無し */
#define TCP_SYN	(1<<1)	/* シーケンス番号の同期 */
#define TCP_RST	(1<<2)	/* コネクションのリセット */
#define TCP_PSH	(1<<3)	/* プッシュ機能 */
#define TCP_ACK	(1<<4)	/* 応答確認フィールドが有効 */
#define TCP_URG	(1<<5)	/* 緊急ポインタフィールドが有効 */

/****************************************************************************
 *	
 ****************************************************************************/

/* インターネットチェックサムを計算します。
 * [in]
 *	data		チェックサムを計算するデータの先頭アドレス。
 *	size		データのバイト数。(奇数サイズでも構いません)
 * [out]
 *	戻り値		チェックサム。($0000〜$FFFF)
 * [note]
 *	* データの中にチェックサムフィールドがある場合は、仮に0を設定しておいてください。
 *	* UDPやVMTPなどでは、最終的なチェックサムの値の計算結果が「0000」になった場合には
 *	  「FFFF」をセットし、「0000」は特別な意味(チェックサムなし)としています。
 *	  この関数には、「0000」を「FFFF」に置き換える処理は含めていません。
 *	  必要に応じて、呼び出し側で「0000」を「FFFF」に置き換えてください。
 *	* インターネットチェックサムの仕様は、以下の資料を参照してください。
 *		電子資料: RFC 1071 (Computing the Internet Checksum)
 *		書籍:    『インターネットRFC辞典』 アスキー出版局 (初版 p.611〜)
 */
int internet_checksum(const void* data, int size);

/* データの中の、インターネットチェックサムフィールドを更新します。
 * [in]
 *	data		チェックサムを計算するデータの先頭アドレス。
 *	size		データのバイト数。(奇数サイズでも構いません)
 *	sum_ofs		チェックサムフィールドのdata相対オフセット。
 * [note]
 *	* チェックサムフィールドは、データ中に無ければいけません。
 *	  すなわち、(size <= sum_ofs <= size-2) である必要があります。
 *	  この範囲を超える値が指定された場合、エラーを表示して停止します。
 *	* この関数は、チェックサムフィールドに0を格納してチェックサムを計算し、
 *	  その後、チェックサムフィールドに本当のチェックサムを格納します。
 *	  呼び出し側にて、チェックサムフィールドを0にしておく必要はありません。
 */
void update_internet_checksum(void* data, int size, int sum_ofs);

/* 疑似ヘッダを含めて、インターネットチェックサムを計算します。
 * [in]
 *	source_ip_address	送信元IPアドレス
 *	destination_ip_address	送信先IPアドレス
 *	protocol		プロトコル (TCP=6, UDP=17, etc)
 *	packet			パケット
 *	packet_length		パケット長
 * [out]
 *	戻り値			チェックサム
 * [note]
 *	* 本関数は、UDPチェックサムの特例を考慮しません。
 *	  UDPチェックサムの特例は、呼び出し側にて処理してください。
 */
int internet_checksum_pseudo_header(int source_ip_address, int destination_ip_address, int protocol, const void* packet, int packet_length);

/* パケット中の、チェックサムフィールド(疑似ヘッダ含む)を更新します。
 *	source_ip_address	送信元IPアドレス
 *	destination_ip_address	送信先IPアドレス
 *	protocol		プロトコル (TCP=6, UDP=17, etc)
 *	packet			パケット
 *	packet_length		パケット長
 *	checksum_offset		チェックサムフィールドのpacket相対オフセット
 * [note]
 *	* 本関数は、UDPチェックサムの特例を考慮しません。
 *	  UDPチェックサムの特例は、呼び出し側にて処理してください。
 */
void update_internet_checksum_pseudo_header(int source_ip_address, int destination_ip_address, int protocol, void* _packet, int packet_length, int checksum_offset);

/****************************************************************************
 *	
 ****************************************************************************/

/* IPアドレスクラスに対応する、サブネットマスクを取得します。
 * [in]
 *	ip_address	IPアドレス。
 * [out]
 *	戻り値		サブネットマスク。
 */
int ip_address_class_mask(int ip_address);

/* IPデータグラムを解析し、ヘッダ情報を取得します。
 * [in]
 *	header		ヘッダ情報を格納するIPHEADER構造体。
 *	buffer		IPデータグラムが格納されているバッファ。
 *	buffer_length	バッファ長。
 *			実際のIPデータグラムよりも大きくても構いません。
 * [out]
 *	戻り値		成功ならば、IPデータグラムのバイト数を返します。
 *			この値は特に意味が無いので、正数ならば成功と考えてください。
 *			失敗ならば、負値を返します。
 */
int unpack_ip_header(IPHEADER* header, const void* buffer, int buffer_length);

/* IPヘッダ情報から、IPデータグラムを組み立てます。
 * [in]
 *	header		ヘッダ情報が格納されているIPHEADER構造体。
 *	buffer		IPデータグラムを格納するバッファ。
 *	buffer_length	バッファ長。
 *			IPデータグラムを格納する充分な大きさが必要です。
 *			バッファが不足ならば、関数は失敗し、負数を返します。
 * [out]
 *	戻り値		成功ならば、IPデータグラムのバイト数を返します。
 *			このバイト数を用いて、IPデータグラムの送信を行ってください。
 *			失敗ならば、負値を返します。
 * [note]
 *	* header->data_length=0の場合に限り、header->data=NULLとしても構いません。
 *	  それ以外の場合にheader->data=NULLとすると、エラー終了します。
 */
int pack_ip_header(const IPHEADER* header, void* buffer, int buffer_length);

/****************************************************************************
 *	
 ****************************************************************************/

/* TCPセグメントを解析し、ヘッダ情報を取得します。
 * [in]
 *	header			ヘッダ情報を格納するTCPHEADER構造体。
 *	buffer			TCPセグメントが格納されているバッファ。
 *	buffer_length		TCPセグメント長。
 *	source_ip_address	送信元IPアドレス。
 *	destination_ip_address	宛て先IPアドレス。
 * [out]
 *	戻り値			成功ならば、TCPセグメント長をそのまま返します。
 *				失敗ならば、負値を返します。
 */
int unpack_tcp_header(TCPHEADER* header, const void* buffer, int buffer_length, int source_ip_address, int destination_ip_address);

/* TCPヘッダ情報から、TCPセグメントを組み立てます。
 * [in]
 *	header			ヘッダ情報が格納されているTCPHEADER構造体。
 *	buffer			TCPセグメントを格納するバッファ。
 *	buffer_length		バッファ長。
 *				TCPセグメントを格納する充分な大きさが必要です。
 *				バッファが不足ならば、関数は失敗し、負数を返します。
 *	source_ip_address	送信元IPアドレス。
 *	destination_ip_address	宛て先IPアドレス。
 * [out]
 *	戻り値			成功ならば、TCPセグメント長を返します。
 *				このバイト数を用いて、TCPセグメントの送信を行ってください。
 *				失敗ならば、負値を返します。
 *	* header->data_length=0の場合に限り、header->data=NULLとしても構いません。
 *	  それ以外の場合にheader->data=NULLとすると、エラー終了します。
 */
int pack_tcp_header(TCPHEADER* header, void* buffer, int buffer_length, int source_ip_address, int destination_ip_address);

#endif /*__CLIP_NET_H__*/
