197903da2202008733f50e69997029d7a5cfffcb8mreed/******************************************************************************/
297903da2202008733f50e69997029d7a5cfffcb8mreed/*                                                                            */
397903da2202008733f50e69997029d7a5cfffcb8mreed/*   Copyright (c) International Business Machines  Corp., 2006               */
497903da2202008733f50e69997029d7a5cfffcb8mreed/*                                                                            */
597903da2202008733f50e69997029d7a5cfffcb8mreed/*   This program is free software;  you can redistribute it and/or modify    */
697903da2202008733f50e69997029d7a5cfffcb8mreed/*   it under the terms of the GNU General Public License as published by     */
797903da2202008733f50e69997029d7a5cfffcb8mreed/*   the Free Software Foundation; either version 2 of the License, or        */
897903da2202008733f50e69997029d7a5cfffcb8mreed/*   (at your option) any later version.                                      */
997903da2202008733f50e69997029d7a5cfffcb8mreed/*                                                                            */
1097903da2202008733f50e69997029d7a5cfffcb8mreed/*   This program is distributed in the hope that it will be useful,          */
1197903da2202008733f50e69997029d7a5cfffcb8mreed/*   but WITHOUT ANY WARRANTY;  without even the implied warranty of          */
1297903da2202008733f50e69997029d7a5cfffcb8mreed/*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See                */
1397903da2202008733f50e69997029d7a5cfffcb8mreed/*   the GNU General Public License for more details.                         */
1497903da2202008733f50e69997029d7a5cfffcb8mreed/*                                                                            */
1597903da2202008733f50e69997029d7a5cfffcb8mreed/*   You should have received a copy of the GNU General Public License        */
1697903da2202008733f50e69997029d7a5cfffcb8mreed/*   along with this program;  if not, write to the Free Software             */
174548c6cf9bcdd96d8303caa4130ab638b61f8a30Wanlong Gao/*   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA  */
1897903da2202008733f50e69997029d7a5cfffcb8mreed/*                                                                            */
1997903da2202008733f50e69997029d7a5cfffcb8mreed/******************************************************************************/
2097903da2202008733f50e69997029d7a5cfffcb8mreed
2197903da2202008733f50e69997029d7a5cfffcb8mreed/*
2297903da2202008733f50e69997029d7a5cfffcb8mreed * File:
2397903da2202008733f50e69997029d7a5cfffcb8mreed *	ns-icmp_redirector.c
2497903da2202008733f50e69997029d7a5cfffcb8mreed *
2597903da2202008733f50e69997029d7a5cfffcb8mreed * Description:
2697903da2202008733f50e69997029d7a5cfffcb8mreed *	This is ICMPv4/ICMPv6 redirect message sender.
2797903da2202008733f50e69997029d7a5cfffcb8mreed *	The host under test assume the host where this utility run is a
2897903da2202008733f50e69997029d7a5cfffcb8mreed *	gateway. When the utility receives the packet from the host
2997903da2202008733f50e69997029d7a5cfffcb8mreed *	under test. This utility reply ICMP redirect message.
3097903da2202008733f50e69997029d7a5cfffcb8mreed *
3197903da2202008733f50e69997029d7a5cfffcb8mreed * Author:
3297903da2202008733f50e69997029d7a5cfffcb8mreed *	Mitsuru Chinen <mitch@jp.ibm.com>
3397903da2202008733f50e69997029d7a5cfffcb8mreed *
3497903da2202008733f50e69997029d7a5cfffcb8mreed * History:
3597903da2202008733f50e69997029d7a5cfffcb8mreed *	Mar 31 2006 - Created (Mitsuru Chinen)
3697903da2202008733f50e69997029d7a5cfffcb8mreed *---------------------------------------------------------------------------*/
3797903da2202008733f50e69997029d7a5cfffcb8mreed
3897903da2202008733f50e69997029d7a5cfffcb8mreed/*
3997903da2202008733f50e69997029d7a5cfffcb8mreed * Header Files
4097903da2202008733f50e69997029d7a5cfffcb8mreed */
4197903da2202008733f50e69997029d7a5cfffcb8mreed#include <stdio.h>
4297903da2202008733f50e69997029d7a5cfffcb8mreed#include <stdlib.h>
4397903da2202008733f50e69997029d7a5cfffcb8mreed#include <string.h>
4497903da2202008733f50e69997029d7a5cfffcb8mreed#include <errno.h>
4597903da2202008733f50e69997029d7a5cfffcb8mreed#include <fcntl.h>
4697903da2202008733f50e69997029d7a5cfffcb8mreed#include <netdb.h>
4797903da2202008733f50e69997029d7a5cfffcb8mreed#include <signal.h>
4897903da2202008733f50e69997029d7a5cfffcb8mreed#include <time.h>
4997903da2202008733f50e69997029d7a5cfffcb8mreed#include <unistd.h>
5097903da2202008733f50e69997029d7a5cfffcb8mreed#include <sys/ioctl.h>
5197903da2202008733f50e69997029d7a5cfffcb8mreed#include <sys/socket.h>
5297903da2202008733f50e69997029d7a5cfffcb8mreed#include <arpa/inet.h>
5397903da2202008733f50e69997029d7a5cfffcb8mreed#include <net/ethernet.h>
5497903da2202008733f50e69997029d7a5cfffcb8mreed#include <net/if_arp.h>
5597903da2202008733f50e69997029d7a5cfffcb8mreed#include <netinet/if_ether.h>
5697903da2202008733f50e69997029d7a5cfffcb8mreed
5797903da2202008733f50e69997029d7a5cfffcb8mreed#include "ns-traffic.h"
5897903da2202008733f50e69997029d7a5cfffcb8mreed
5997903da2202008733f50e69997029d7a5cfffcb8mreed/*
6097903da2202008733f50e69997029d7a5cfffcb8mreed * Structure definition
6197903da2202008733f50e69997029d7a5cfffcb8mreed */
6297903da2202008733f50e69997029d7a5cfffcb8mreedstruct redirector_info {
63354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	int sd;
64354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	char *ifname;
65354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	double timeout;
6697903da2202008733f50e69997029d7a5cfffcb8mreed};
6797903da2202008733f50e69997029d7a5cfffcb8mreed
6897903da2202008733f50e69997029d7a5cfffcb8mreedstruct ip4_gateway_info {
69354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	unsigned char hd_addr[ETH_ALEN];
70354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	unsigned char ip_addr[4];
71354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	unsigned char nexthop[4];
7297903da2202008733f50e69997029d7a5cfffcb8mreed};
7397903da2202008733f50e69997029d7a5cfffcb8mreed
7497903da2202008733f50e69997029d7a5cfffcb8mreedstruct ip6_gateway_info {
75354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	unsigned char hd_addr[ETH_ALEN];
76354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	struct in6_addr ip_addr;
77354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	struct in6_addr nexthop;
7897903da2202008733f50e69997029d7a5cfffcb8mreed};
7997903da2202008733f50e69997029d7a5cfffcb8mreed
8097903da2202008733f50e69997029d7a5cfffcb8mreed/*
8197903da2202008733f50e69997029d7a5cfffcb8mreed * Gloval variables
8297903da2202008733f50e69997029d7a5cfffcb8mreed */
8397903da2202008733f50e69997029d7a5cfffcb8mreedchar *program_name;		/* program name */
8497903da2202008733f50e69997029d7a5cfffcb8mreedstruct sigaction handler;	/* Behavior for a signal */
8597903da2202008733f50e69997029d7a5cfffcb8mreedint catch_sighup;		/* When catch the SIGHUP, set to non-zero */
8697903da2202008733f50e69997029d7a5cfffcb8mreed
8797903da2202008733f50e69997029d7a5cfffcb8mreed/*
8897903da2202008733f50e69997029d7a5cfffcb8mreed * Function: usage()
8997903da2202008733f50e69997029d7a5cfffcb8mreed *
9097903da2202008733f50e69997029d7a5cfffcb8mreed * Descripton:
9197903da2202008733f50e69997029d7a5cfffcb8mreed *  Print the usage of this program. Then, terminate this program with
9297903da2202008733f50e69997029d7a5cfffcb8mreed *  the specified exit value.
9397903da2202008733f50e69997029d7a5cfffcb8mreed *
9497903da2202008733f50e69997029d7a5cfffcb8mreed * Argument:
9597903da2202008733f50e69997029d7a5cfffcb8mreed *  exit_value:	exit value
9697903da2202008733f50e69997029d7a5cfffcb8mreed *
9797903da2202008733f50e69997029d7a5cfffcb8mreed * Return value:
9897903da2202008733f50e69997029d7a5cfffcb8mreed *  This function does not return.
9997903da2202008733f50e69997029d7a5cfffcb8mreed */
100354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaovoid usage(char *program_name, int exit_value)
10197903da2202008733f50e69997029d7a5cfffcb8mreed{
102354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	FILE *stream = stdout;	/* stream where the usage is output */
103354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
104354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (exit_value == EXIT_FAILURE)
105354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		stream = stderr;
106354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
107354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	fprintf(stream, "%s [OPTION]\n"
108354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		"\t-I if_name\tInterface where input/output packets\n"
109354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		"\t-t value\ttimeout [sec]\n"
110354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		"\t-b\t\ttimeout [sec]\n"
111354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		"\t-d\t\tdisplay debug informations\n"
112354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		"\t-h\t\tdisplay this usage\n", program_name);
113354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	exit(exit_value);
11497903da2202008733f50e69997029d7a5cfffcb8mreed}
11597903da2202008733f50e69997029d7a5cfffcb8mreed
11697903da2202008733f50e69997029d7a5cfffcb8mreed/*
11797903da2202008733f50e69997029d7a5cfffcb8mreed * Function: set_signal_flag()
11897903da2202008733f50e69997029d7a5cfffcb8mreed *
11997903da2202008733f50e69997029d7a5cfffcb8mreed * Description:
12097903da2202008733f50e69997029d7a5cfffcb8mreed *  This function sets global variables according to a signal
12197903da2202008733f50e69997029d7a5cfffcb8mreed *
12297903da2202008733f50e69997029d7a5cfffcb8mreed * Argument:
12397903da2202008733f50e69997029d7a5cfffcb8mreed *  type: type of signal
12497903da2202008733f50e69997029d7a5cfffcb8mreed *
12597903da2202008733f50e69997029d7a5cfffcb8mreed * Return value:
12697903da2202008733f50e69997029d7a5cfffcb8mreed *  None
12797903da2202008733f50e69997029d7a5cfffcb8mreed */
128354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaovoid set_signal_flag(int type)
12997903da2202008733f50e69997029d7a5cfffcb8mreed{
130354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (debug)
131354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		fprintf(stderr, "Catch signal. type is %d\n", type);
13297903da2202008733f50e69997029d7a5cfffcb8mreed
133354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	switch (type) {
13497903da2202008733f50e69997029d7a5cfffcb8mreed	case SIGHUP:
135354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		catch_sighup = 1;
136354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		handler.sa_handler = SIG_IGN;
137354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		if (sigaction(type, &handler, NULL) < 0)
138354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			fatal_error("sigaction()");
139354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		break;
14097903da2202008733f50e69997029d7a5cfffcb8mreed
14197903da2202008733f50e69997029d7a5cfffcb8mreed	default:
142354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		fprintf(stderr, "Unexpected signal (%d) is caught\n", type);
143354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		exit(EXIT_FAILURE);
144354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	}
14597903da2202008733f50e69997029d7a5cfffcb8mreed}
14697903da2202008733f50e69997029d7a5cfffcb8mreed
14797903da2202008733f50e69997029d7a5cfffcb8mreed/*
14897903da2202008733f50e69997029d7a5cfffcb8mreed * Function: parse_options()
14997903da2202008733f50e69997029d7a5cfffcb8mreed *
15097903da2202008733f50e69997029d7a5cfffcb8mreed * Description:
15197903da2202008733f50e69997029d7a5cfffcb8mreed *  This function parse the options
15297903da2202008733f50e69997029d7a5cfffcb8mreed *
15397903da2202008733f50e69997029d7a5cfffcb8mreed * Argument:
15497903da2202008733f50e69997029d7a5cfffcb8mreed *     argc:	    number of argument
15597903da2202008733f50e69997029d7a5cfffcb8mreed *     argv:	    arguments
15697903da2202008733f50e69997029d7a5cfffcb8mreed *  redirector_p:   pointer to data for the redirector information
15797903da2202008733f50e69997029d7a5cfffcb8mreed *     bg_p:	    pointer to the flag of working in backgrond
15897903da2202008733f50e69997029d7a5cfffcb8mreed *
15997903da2202008733f50e69997029d7a5cfffcb8mreed * Return value:
16097903da2202008733f50e69997029d7a5cfffcb8mreed *  None
16197903da2202008733f50e69997029d7a5cfffcb8mreed */
16297903da2202008733f50e69997029d7a5cfffcb8mreedvoid
163354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaoparse_options(int argc, char *argv[], struct redirector_info *redirector_p,
164354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	      int *bg_p)
16597903da2202008733f50e69997029d7a5cfffcb8mreed{
166354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	int optc;		/* option */
167354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	double opt_d;		/* option value in double */
168354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
169354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	while ((optc = getopt(argc, argv, "I:N:t:bdh")) != EOF) {
170354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		switch (optc) {
171354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		case 'I':
172354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			redirector_p->ifname = strdup(optarg);
173354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			if (redirector_p->ifname == NULL)
174354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				fatal_error("strdup() failed.");
175354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			break;
176354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
177354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		case 't':
178354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			opt_d = strtod(optarg, NULL);
179354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			if (opt_d < 0.0) {
180354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				fprintf(stderr,
181354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					"Timeout should be positive value\n");
182354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				usage(program_name, EXIT_FAILURE);
183354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			}
184354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			redirector_p->timeout = opt_d;
185354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			break;
186354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
187354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		case 'b':
188354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			*bg_p = 1;
189354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			break;
190354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
191354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		case 'd':
192354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			debug = 1;
193354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			break;
194354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
195354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		case 'h':
196354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			usage(program_name, EXIT_SUCCESS);
197354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			break;
198354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
199354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		default:
200354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			usage(program_name, EXIT_FAILURE);
20197903da2202008733f50e69997029d7a5cfffcb8mreed		}
202354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	}
20397903da2202008733f50e69997029d7a5cfffcb8mreed
204354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (redirector_p->ifname == NULL) {
205354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		fprintf(stderr, "Interface name is not specified\n");
20697903da2202008733f50e69997029d7a5cfffcb8mreed		usage(program_name, EXIT_FAILURE);
20797903da2202008733f50e69997029d7a5cfffcb8mreed	}
20897903da2202008733f50e69997029d7a5cfffcb8mreed}
20997903da2202008733f50e69997029d7a5cfffcb8mreed
21097903da2202008733f50e69997029d7a5cfffcb8mreed/*
21197903da2202008733f50e69997029d7a5cfffcb8mreed * Function: open_socket()
21297903da2202008733f50e69997029d7a5cfffcb8mreed *
21397903da2202008733f50e69997029d7a5cfffcb8mreed * Description:
21497903da2202008733f50e69997029d7a5cfffcb8mreed *  This function opens a socket for capture/sending
21597903da2202008733f50e69997029d7a5cfffcb8mreed *
21697903da2202008733f50e69997029d7a5cfffcb8mreed * Argument:
21797903da2202008733f50e69997029d7a5cfffcb8mreed *  ifname: interface name
21897903da2202008733f50e69997029d7a5cfffcb8mreed *
21997903da2202008733f50e69997029d7a5cfffcb8mreed * Return value:
22097903da2202008733f50e69997029d7a5cfffcb8mreed *  socket file descriptor for receiving packets
22197903da2202008733f50e69997029d7a5cfffcb8mreed */
222354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaoint open_socket(const char *ifname)
22397903da2202008733f50e69997029d7a5cfffcb8mreed{
224354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	int sd;			/* Socket to packets */
225354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	struct ifreq ifinfo;	/* Interface information */
226354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	struct sockaddr_ll lla;	/* Link-local address info for receiving */
227354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
228354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* Create a socket for capture */
229354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if ((sd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) < 0)
230354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		fatal_error("socket()");
231354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
232354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* Make a socket into non-blocking mode */
233354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (fcntl(sd, F_SETFL, O_NONBLOCK) < 0)
234354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		fatal_error("fcntl()");
235354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
236354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* Get the logical interface number */
237354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	get_ifinfo(&ifinfo, sd, ifname, SIOCGIFINDEX);
238354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
239354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* Bind to the interface */
240354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	memset(&lla, '\0', sizeof(struct sockaddr_ll));
241354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	lla.sll_family = PF_PACKET;
242354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	lla.sll_protocol = htons(ETH_P_ALL);
243354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	lla.sll_ifindex = ifinfo.ifr_ifindex;
244354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (bind(sd, (struct sockaddr *)&lla, sizeof(struct sockaddr_ll)) < 0)
245354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		fatal_error("bind()");
246354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
247354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* Change into the promiscuous mode */
248354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	get_ifinfo(&ifinfo, sd, ifname, SIOCGIFFLAGS);
249354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	ifinfo.ifr_flags = ifinfo.ifr_flags | IFF_PROMISC;
250354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (ioctl(sd, SIOCSIFFLAGS, &ifinfo) < 0)
251354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		fatal_error("ioctl()");
252354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (debug)
253354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		fprintf(stderr, "%s is changed into promiscuous mode\n",
254354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			ifname);
255354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
256354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (debug)
257354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		fprintf(stderr, "Packet receiving socket is %d\n", sd);
258354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	return sd;
25997903da2202008733f50e69997029d7a5cfffcb8mreed}
26097903da2202008733f50e69997029d7a5cfffcb8mreed
26197903da2202008733f50e69997029d7a5cfffcb8mreed/*
26297903da2202008733f50e69997029d7a5cfffcb8mreed * Function: return_arp_reply()
26397903da2202008733f50e69997029d7a5cfffcb8mreed *
26497903da2202008733f50e69997029d7a5cfffcb8mreed * Description:
26597903da2202008733f50e69997029d7a5cfffcb8mreed *  This function returns arp reply message to arp request message.
26697903da2202008733f50e69997029d7a5cfffcb8mreed *  And it updates the IPv4 gateway information.
26797903da2202008733f50e69997029d7a5cfffcb8mreed *
26897903da2202008733f50e69997029d7a5cfffcb8mreed * Argument:
26997903da2202008733f50e69997029d7a5cfffcb8mreed *      sd     : socket to send arp reply message
27097903da2202008733f50e69997029d7a5cfffcb8mreed *   rcveth_p  : pointer to ether frame data
27197903da2202008733f50e69997029d7a5cfffcb8mreed *   gateway_p : pointer to IPv4 gateway information
27297903da2202008733f50e69997029d7a5cfffcb8mreed *
27397903da2202008733f50e69997029d7a5cfffcb8mreed * Return value:
27497903da2202008733f50e69997029d7a5cfffcb8mreed *  None
27597903da2202008733f50e69997029d7a5cfffcb8mreed */
27697903da2202008733f50e69997029d7a5cfffcb8mreedvoid
277354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaoreturn_arp_reply(int sd, struct eth_frame *rcveth_p,
278354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		 struct ip4_gateway_info *gateway_p)
27997903da2202008733f50e69997029d7a5cfffcb8mreed{
280354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	int retval;
281354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	struct arp_datagram *rcvarp_p;	/* ARP part of receiving frame */
282354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	unsigned char new_hd_addr[ETH_ALEN];	/* New MAC address */
283354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	unsigned char new_nexthop[4];	/* New next hop */
284354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	size_t sndeth_size;	/* Size of sending frame */
285354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	struct eth_frame sndeth;	/* sending frame */
286354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	struct arp_datagram *sndarp_p;	/* ARP part of sending frame */
287354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
288354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	rcvarp_p = (struct arp_datagram *)&(rcveth_p->data);
289354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
290354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* If arp message is not arp request, do nothing */
291354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (debug)
292354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		fprintf(stderr, "ARP OP code is %02x\n",
293354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			ntohs(rcvarp_p->hdr.ar_op));
294354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (rcvarp_p->hdr.ar_op != htons(ARPOP_REQUEST))
295354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		return;
296354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
297354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* Update the gateway information */
298354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	memset(new_hd_addr, '\0', ETH_ALEN);	/* MAC address */
299354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	for (;;) {
300354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		new_hd_addr[3] = rand_within(0, 254);
301354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		new_hd_addr[4] = rand_within(0, 254);
302354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		new_hd_addr[5] = rand_within(1, 254);
303354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		if (memcmp(gateway_p->hd_addr, new_hd_addr, ETH_ALEN)) {
304354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			memcpy(gateway_p->hd_addr, new_hd_addr, ETH_ALEN);
305354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			break;
306354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		}
30797903da2202008733f50e69997029d7a5cfffcb8mreed	}
30897903da2202008733f50e69997029d7a5cfffcb8mreed
309354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	memcpy(gateway_p->ip_addr, rcvarp_p->ar_tip, 4);	/* IP address */
31097903da2202008733f50e69997029d7a5cfffcb8mreed
311354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	for (;;) {		/* next hop */
312354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		memcpy(new_nexthop, gateway_p->ip_addr, 4);
313354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		new_nexthop[3] = rand_within(1, 254);
314354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		if (memcmp(gateway_p->nexthop, new_nexthop, 4)) {
315354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			memcpy(gateway_p->nexthop, new_nexthop, 4);
316354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			break;
317354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		}
31897903da2202008733f50e69997029d7a5cfffcb8mreed	}
319354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
320354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* Build a frame to send */
321354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	memset(&sndeth, '\0', sizeof(struct eth_frame));
322354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndarp_p = (struct arp_datagram *)&(sndeth.data);
323354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndeth_size = sizeof(struct ethhdr) + sizeof(struct arp_datagram);
324354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
325354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* Ether */
326354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	memcpy(sndeth.hdr.h_dest, rcveth_p->hdr.h_source, ETH_ALEN);
327354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	memcpy(sndeth.hdr.h_source, gateway_p->hd_addr, ETH_ALEN);
328354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndeth.hdr.h_proto = htons(ETH_P_ARP);
329354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
330354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* Arp */
331354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndarp_p->hdr.ar_hrd = htons(ARPHRD_ETHER);
332354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndarp_p->hdr.ar_pro = htons(ETH_P_IP);
333354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndarp_p->hdr.ar_hln = ETH_ALEN;
334354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndarp_p->hdr.ar_pln = 4;
335354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndarp_p->hdr.ar_op = htons(ARPOP_REPLY);
336354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	memcpy(sndarp_p->ar_sha, gateway_p->hd_addr, ETH_ALEN);
337354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	memcpy(sndarp_p->ar_sip, gateway_p->ip_addr, 4);
338354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	memcpy(sndarp_p->ar_tha, rcvarp_p->ar_sha, ETH_ALEN);
339354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	memcpy(sndarp_p->ar_tip, rcvarp_p->ar_sip, 4);
340354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
341354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* Send ARP reply */
342354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	retval = write(sd, &sndeth, sndeth_size);
343354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (retval != sndeth_size)
344354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		fatal_error("write()");
34597903da2202008733f50e69997029d7a5cfffcb8mreed}
34697903da2202008733f50e69997029d7a5cfffcb8mreed
34797903da2202008733f50e69997029d7a5cfffcb8mreed/*
34897903da2202008733f50e69997029d7a5cfffcb8mreed * Function: return_icmp4_redirect()
34997903da2202008733f50e69997029d7a5cfffcb8mreed *
35097903da2202008733f50e69997029d7a5cfffcb8mreed * Description:
35197903da2202008733f50e69997029d7a5cfffcb8mreed *  This function returns icmp redirect message
35297903da2202008733f50e69997029d7a5cfffcb8mreed *
35397903da2202008733f50e69997029d7a5cfffcb8mreed * Argument:
35497903da2202008733f50e69997029d7a5cfffcb8mreed *      sd     : socket to send arp reply message
35597903da2202008733f50e69997029d7a5cfffcb8mreed *   rcveth_p  : pointer to ether frame data
35697903da2202008733f50e69997029d7a5cfffcb8mreed *  rcveth_size: size of received ehter frame
35797903da2202008733f50e69997029d7a5cfffcb8mreed *    new_gw_p : pointer to new IPv4 gateway information
35897903da2202008733f50e69997029d7a5cfffcb8mreed *
35997903da2202008733f50e69997029d7a5cfffcb8mreed * Return value:
36097903da2202008733f50e69997029d7a5cfffcb8mreed *  None
36197903da2202008733f50e69997029d7a5cfffcb8mreed */
36297903da2202008733f50e69997029d7a5cfffcb8mreedvoid
363354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaoreturn_icmp4_redirect(int sd, struct eth_frame *rcveth_p, size_t rcveth_size,
364354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		      struct ip4_gateway_info *new_gw_p)
36597903da2202008733f50e69997029d7a5cfffcb8mreed{
366354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	static struct ip4_gateway_info *gw_p;	/* pointor to gateway */
367354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
368354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	int retval;
369354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	struct ip4_datagram *rcvip_p;	/* IPv4 part of receiving frame */
370354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	size_t sndeth_size;	/* Size of sending frame */
371354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	struct eth_frame sndeth;	/* sending frame */
372354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	struct ip4_datagram *sndip_p;	/* IPv4 part of sending frame */
373354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	struct icmp4_segment *sndicmp_p;	/* ICMPv4 part of sending frame */
374354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	size_t icmp4_datasize;	/* Size of sending ICMPv4 */
375354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
376354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* If MAC address in received frame is changed, update the gateway info */
377354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (memcmp(rcveth_p->hdr.h_dest, new_gw_p->hd_addr, ETH_ALEN) == 0) {
378354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		if (gw_p == NULL)
379d218f348c12b42a78fa0306d9a033bfa4f67238bCyril Hrubis			if ((gw_p = malloc(sizeof(struct ip4_gateway_info))) == NULL)
380354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				fatal_error("malloc()");
381354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		*gw_p = *new_gw_p;
382354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	} else if (gw_p == NULL
383354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		   || memcmp(rcveth_p->hdr.h_dest, gw_p->hd_addr, ETH_ALEN))
384354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		return;
385354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
386354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	rcvip_p = (struct ip4_datagram *)&(rcveth_p->data);
387354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
388354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* Build a frame to send */
389354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndeth_size = sizeof(struct ethhdr)	/* Ether header */
390354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	    +sizeof(struct iphdr)	/* IPv4 header */
391354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	    +sizeof(struct icmphdr)	/* ICMPv4 header */
392354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	    +rcveth_size - sizeof(struct ethhdr);	/* ICMPv4 payload */
393354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndeth_size = (sndeth_size < ETH_DATA_MAXSIZE)
394354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	    ? sndeth_size : ETH_DATA_MAXSIZE;
395354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	memset(&sndeth, '\0', sizeof(struct eth_frame));
396354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndip_p = (struct ip4_datagram *)&(sndeth.data);
397354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndicmp_p = (struct icmp4_segment *)&(sndip_p->payload);
398354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
399354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* Ether */
400354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	memcpy(sndeth.hdr.h_dest, rcveth_p->hdr.h_source, ETH_ALEN);
401354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	memcpy(sndeth.hdr.h_source, gw_p->hd_addr, ETH_ALEN);
402354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndeth.hdr.h_proto = htons(ETH_P_IP);
403354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
404354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* IP */
405354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndip_p->hdr.version = 4;
406354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndip_p->hdr.ihl = sizeof(struct iphdr) / 4;
407354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndip_p->hdr.tos = 0;
408354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndip_p->hdr.tot_len = htons(sndeth_size - sizeof(struct ethhdr));
409354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndip_p->hdr.id = htons(IPV4_PACKET_ID);
410354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndip_p->hdr.frag_off = htons(IPV4_DEFAULT_FLAG);
411354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndip_p->hdr.ttl = IPV4_DEFAULT_TTL;
412354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndip_p->hdr.protocol = IPPROTO_ICMP;
413354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndip_p->hdr.check = 0;	/* Calculate later */
414354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	memcpy((unsigned char *)&sndip_p->hdr.saddr, gw_p->ip_addr, 4);
415354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndip_p->hdr.daddr = rcvip_p->hdr.saddr;
416354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndip_p->hdr.check = calc_checksum((u_int16_t *) & (sndip_p->hdr),
417354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					   sizeof(struct iphdr));
418354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
419354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* ICMP */
420354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndicmp_p->hdr.type = ICMP_REDIRECT;
421354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndicmp_p->hdr.code = ICMP_REDIR_HOST;
422354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndicmp_p->hdr.checksum = 0;	/* Calculate later */
423354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	memcpy((unsigned char *)&(sndicmp_p->hdr.un.gateway), gw_p->nexthop, 4);
424354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
425354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* ICMP payload */
426354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	icmp4_datasize = rcveth_size - sizeof(struct ethhdr);
427354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	icmp4_datasize =
428354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	    (icmp4_datasize <
429354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	     ICMPV4_DATA_MAXSIZE) ? icmp4_datasize : ICMPV4_DATA_MAXSIZE;
430354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	memcpy(sndicmp_p->data, rcvip_p, icmp4_datasize);
431354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
432354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* Calculate ICMP checksum */
433354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndicmp_p->hdr.checksum = calc_checksum((u_int16_t *) sndicmp_p,
434354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao						sizeof(struct icmphdr) +
435354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao						icmp4_datasize);
436354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
437354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* Send ICMP redirect */
438354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	retval = write(sd, &sndeth, sndeth_size);
439354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (retval != sndeth_size)
440354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		fatal_error("write()");
44197903da2202008733f50e69997029d7a5cfffcb8mreed}
44297903da2202008733f50e69997029d7a5cfffcb8mreed
44397903da2202008733f50e69997029d7a5cfffcb8mreed/*
44497903da2202008733f50e69997029d7a5cfffcb8mreed * Function: return_neigh_adv()
44597903da2202008733f50e69997029d7a5cfffcb8mreed *
44697903da2202008733f50e69997029d7a5cfffcb8mreed * Description:
44797903da2202008733f50e69997029d7a5cfffcb8mreed *  This function returns neighbor advertisement message
44897903da2202008733f50e69997029d7a5cfffcb8mreed *  And this updates the gateway information.
44997903da2202008733f50e69997029d7a5cfffcb8mreed *
45097903da2202008733f50e69997029d7a5cfffcb8mreed * Argument:
45197903da2202008733f50e69997029d7a5cfffcb8mreed *      sd     : socket to send arp reply message
45297903da2202008733f50e69997029d7a5cfffcb8mreed *   rcveth_p  : pointer to ether frame data
45397903da2202008733f50e69997029d7a5cfffcb8mreed *  current_eth: current MAC address
45497903da2202008733f50e69997029d7a5cfffcb8mreed *   gateway_p : pointer to IPv6 gateway information
45597903da2202008733f50e69997029d7a5cfffcb8mreed *
45697903da2202008733f50e69997029d7a5cfffcb8mreed * Return value:
45797903da2202008733f50e69997029d7a5cfffcb8mreed *  None
45897903da2202008733f50e69997029d7a5cfffcb8mreed */
45997903da2202008733f50e69997029d7a5cfffcb8mreedvoid
460354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaoreturn_neigh_adv(int sd, struct eth_frame *rcveth_p,
461354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		 struct ip6_gateway_info *gateway_p)
46297903da2202008733f50e69997029d7a5cfffcb8mreed{
463354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	int retval;
464354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	struct ip6_datagram *rcvip6_p;	/* IPv6 part of receiving frame */
465354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	struct neighbor_sol *rcvns_p;	/* NS part of receiving frame */
466354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	unsigned char new_hd_addr[ETH_ALEN];	/* new MAC address */
467354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	struct in6_addr new_nexthop;	/* new next hop */
468354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	size_t sndeth_size;	/* size of sending frame */
469354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	struct eth_frame sndeth;	/* sending frame */
470354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	struct ip6_datagram *sndip6_p;	/* IPv6 part of sending frame */
471354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	struct pseudo_ip6_datagram p_ip6;	/* pseudo IP header */
472354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	struct neighbor_adv *sndna_p;	/* NA part of sending frame */
473354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
474354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	rcvip6_p = (struct ip6_datagram *)&(rcveth_p->data);
475354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	rcvns_p = (struct neighbor_sol *)&(rcvip6_p->payload);
476354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
477354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* If NS is DAD NS, do nothing */
478354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (memcmp
479354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	    (&(rcvip6_p->hdr.ip6_src), &in6addr_any,
480354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	     sizeof(struct in6_addr)) == 0) {
481354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		if (debug) {
482354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			fprintf(stderr, "Received NS is a DAD NS\n");
483354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			return;
484354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		}
48597903da2202008733f50e69997029d7a5cfffcb8mreed	}
486354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
487354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* Update the gateway information */
488354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	memset(new_hd_addr, '\0', ETH_ALEN);	/* MAC address */
489354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	for (;;) {
490354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		new_hd_addr[3] = rand_within(0, 254);
491354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		new_hd_addr[4] = rand_within(0, 254);
492354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		new_hd_addr[5] = rand_within(1, 254);
493354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		if (memcmp(gateway_p->hd_addr, new_hd_addr, ETH_ALEN)) {
494354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			memcpy(gateway_p->hd_addr, new_hd_addr, ETH_ALEN);
495354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			break;
496354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		}
49797903da2202008733f50e69997029d7a5cfffcb8mreed	}
498354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
499354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	gateway_p->ip_addr = rcvns_p->defs.nd_ns_target;	/* IP address */
500354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
501354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	for (;;) {		/* next hop */
502354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		memset(&new_nexthop, '\0', sizeof(struct in6_addr));
503354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		new_nexthop.s6_addr[0] = 0xfe;
504354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		new_nexthop.s6_addr[1] = 0x80;
505354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		new_nexthop.s6_addr[15] = rand_within(1, 254);
506354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		if (memcmp
507354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		    (&(gateway_p->nexthop), &new_nexthop,
508354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		     sizeof(struct in6_addr))) {
509354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			gateway_p->nexthop = new_nexthop;
510354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			break;
511354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		}
51297903da2202008733f50e69997029d7a5cfffcb8mreed	}
513354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
514354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* Build a frame to send */
515354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndeth_size = sizeof(struct ethhdr) + sizeof(struct ip6_hdr)
516354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	    + sizeof(struct neighbor_adv);
517354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	memset(&sndeth, '\0', sizeof(struct eth_frame));
518354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndip6_p = (struct ip6_datagram *)&(sndeth.data);
519354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndna_p = (struct neighbor_adv *)&(sndip6_p->payload);
520354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
521354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* Ether */
522354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	memcpy(sndeth.hdr.h_dest, rcvns_p->src_laddr, ETH_ALEN);
523354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	memcpy(sndeth.hdr.h_source, gateway_p->hd_addr, ETH_ALEN);
524354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndeth.hdr.h_proto = htons(ETH_P_IPV6);
525354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
526354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* IPv6 */
527354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndip6_p->hdr.ip6_vfc = 6 << 4;
528354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndip6_p->hdr.ip6_flow |= 0;
529354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndip6_p->hdr.ip6_plen = htons(sizeof(struct neighbor_adv));
530354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndip6_p->hdr.ip6_nxt = IPPROTO_ICMPV6;
531354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndip6_p->hdr.ip6_hlim = 255;
532354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndip6_p->hdr.ip6_src = gateway_p->ip_addr;
533354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndip6_p->hdr.ip6_dst = rcvip6_p->hdr.ip6_src;
534354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
535354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* Neighbor Advertisement */
536354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndna_p->defs.nd_na_type = ND_NEIGHBOR_ADVERT;
537354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndna_p->defs.nd_na_code = 0;
538354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndna_p->defs.nd_na_cksum = 0;	/* Calculate later */
539354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndna_p->defs.nd_na_target = gateway_p->ip_addr;
540354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndna_p->defs.nd_na_flags_reserved
541354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	    = ND_NA_FLAG_ROUTER | ND_NA_FLAG_SOLICITED | ND_NA_FLAG_OVERRIDE;
542354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndna_p->tla_opt.nd_opt_type = ND_OPT_TARGET_LINKADDR;
543354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndna_p->tla_opt.nd_opt_len = 1;
544354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	memcpy(sndna_p->tgt_laddr, &(gateway_p->hd_addr), ETH_ALEN);
545354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
546354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* Pseudo IPv6 datagram for checksum calculation */
547354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	memset(&p_ip6, '\0', sizeof(struct pseudo_ip6_datagram));
548354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	p_ip6.hdr.p_ip6_src = sndip6_p->hdr.ip6_src;
549354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	p_ip6.hdr.p_ip6_dst = sndip6_p->hdr.ip6_dst;
550354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	p_ip6.hdr.p_ip6_plen = sndip6_p->hdr.ip6_plen;
551354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	p_ip6.hdr.p_ip6_zero1 = 0;
552354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	p_ip6.hdr.p_ip6_zero2 = 0;
553354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	p_ip6.hdr.p_ip6_nxt = sndip6_p->hdr.ip6_nxt;
554354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	memcpy(p_ip6.payload, sndna_p, sizeof(struct neighbor_adv));
555354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
556354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* Calculate checksum */
557354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndna_p->defs.nd_na_cksum = calc_checksum((u_int16_t *) (&p_ip6),
558354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao						  sizeof(struct pseudo_ip6_hdr)
559354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao						  +
560354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao						  sizeof(struct neighbor_adv));
561354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
562354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* Send Neighbor Advertisement reply */
563354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	retval = write(sd, &sndeth, sndeth_size);
564354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (retval != sndeth_size)
565354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		fatal_error("write()");
56697903da2202008733f50e69997029d7a5cfffcb8mreed}
56797903da2202008733f50e69997029d7a5cfffcb8mreed
56897903da2202008733f50e69997029d7a5cfffcb8mreed/*
56997903da2202008733f50e69997029d7a5cfffcb8mreed * Function: return_icmp6_redirect()
57097903da2202008733f50e69997029d7a5cfffcb8mreed *
57197903da2202008733f50e69997029d7a5cfffcb8mreed * Description:
5722c28215423293e443469a07ae7011135d058b671Garrett Cooper *  This function returns an ICMPv6 redirect message
57397903da2202008733f50e69997029d7a5cfffcb8mreed *
57497903da2202008733f50e69997029d7a5cfffcb8mreed * Argument:
57597903da2202008733f50e69997029d7a5cfffcb8mreed *      sd     : socket to send arp reply message
57697903da2202008733f50e69997029d7a5cfffcb8mreed *   rcveth_p  : pointer to ether frame data
57797903da2202008733f50e69997029d7a5cfffcb8mreed *  rcveth_size: size of received ehter frame
57897903da2202008733f50e69997029d7a5cfffcb8mreed *   new_gw_p  : pointer to new IPv4 gateway information
57997903da2202008733f50e69997029d7a5cfffcb8mreed *
58097903da2202008733f50e69997029d7a5cfffcb8mreed * Return value:
58197903da2202008733f50e69997029d7a5cfffcb8mreed *  None
58297903da2202008733f50e69997029d7a5cfffcb8mreed */
58397903da2202008733f50e69997029d7a5cfffcb8mreedvoid
584354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaoreturn_icmp6_redirect(int sd, struct eth_frame *rcveth_p, size_t rcveth_size,
585354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		      struct ip6_gateway_info *new_gw_p)
58697903da2202008733f50e69997029d7a5cfffcb8mreed{
587354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	static struct ip6_gateway_info *gw_p = NULL;	/* pointor to gateway */
588354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
589354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	int retval;
590354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	struct ip6_datagram *rcvip6_p;	/* IPv6 part of receiving frame */
591354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	struct eth_frame sndeth;	/* sending frame */
592354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	size_t sndeth_size;	/* size of sending frame */
593354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	struct ip6_datagram *sndip6_p;	/* IPv6 part of sending frame */
594354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	size_t ip6_payload_size;	/* payload size of IPv6 part */
595354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	struct pseudo_ip6_datagram p_ip6;	/* pseudo header for checksum */
596354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	struct neighbor_redirect *sndrd_p;	/* ICMPv6 part of sending frame */
597354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	size_t redirect_optsize;	/* Option size of ICMPv6 */
598354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
599354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	rcvip6_p = (struct ip6_datagram *)&(rcveth_p->data);
600354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
601354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* If MAC address in received frame is changed, update the gateway info */
602354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (memcmp(rcveth_p->hdr.h_dest, new_gw_p->hd_addr, ETH_ALEN) == 0) {
603354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		if (gw_p == NULL)
604354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			if ((gw_p = malloc(sizeof(struct in6_addr))) == NULL)
605354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				fatal_error("malloc()");
606354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		*gw_p = *new_gw_p;
607354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	} else if (gw_p == NULL
608354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		   || memcmp(rcveth_p->hdr.h_dest, gw_p->hd_addr, ETH_ALEN))
609354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		return;
610354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
611354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* Build a frame to send */
612354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	memset(&sndeth, '\0', sizeof(struct eth_frame));
613354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndip6_p = (struct ip6_datagram *)&(sndeth.data);
614354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndrd_p = (struct neighbor_redirect *)&(sndip6_p->payload);
615354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	redirect_optsize = sizeof(struct nd_opt_rd_hdr)
616354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	    + rcveth_size - sizeof(struct ethhdr);
617354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	redirect_optsize = (redirect_optsize < RDOPT_MAXSIZE)
618354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	    ? redirect_optsize : RDOPT_MAXSIZE;
619354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	ip6_payload_size = sizeof(struct nd_redirect) + redirect_optsize;
620354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndeth_size = sizeof(struct ethhdr) + sizeof(struct ip6_hdr)
621354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	    + ip6_payload_size;
622354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
623354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* Ether */
624354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	memcpy(sndeth.hdr.h_dest, rcveth_p->hdr.h_source, ETH_ALEN);
625354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	memcpy(sndeth.hdr.h_source, gw_p->hd_addr, ETH_ALEN);
626354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndeth.hdr.h_proto = htons(ETH_P_IPV6);
627354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
628354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* IPv6 */
629354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndip6_p->hdr.ip6_vfc = 6 << 4;
630354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndip6_p->hdr.ip6_flow |= 0;
631354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndip6_p->hdr.ip6_plen = htons(ip6_payload_size);
632354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndip6_p->hdr.ip6_nxt = IPPROTO_ICMPV6;
633354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndip6_p->hdr.ip6_hlim = 255;
634354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndip6_p->hdr.ip6_src = gw_p->ip_addr;
635354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndip6_p->hdr.ip6_dst = rcvip6_p->hdr.ip6_src;
636354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
637354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* Rediret Message */
638354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndrd_p->defs.nd_rd_type = ND_REDIRECT;
639354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndrd_p->defs.nd_rd_code = 0;
640354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndrd_p->defs.nd_rd_cksum = 0;	/* Calculate later */
641354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndrd_p->defs.nd_rd_reserved = 0;
642354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndrd_p->defs.nd_rd_target = gw_p->nexthop;
643354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndrd_p->defs.nd_rd_dst = rcvip6_p->hdr.ip6_dst;;
644354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndrd_p->rdopt_hdr.nd_opt_rh_type = ND_OPT_REDIRECTED_HEADER;
645354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndrd_p->rdopt_hdr.nd_opt_rh_len = redirect_optsize / 8;
646354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	memcpy(sndrd_p->rdopt_data, rcvip6_p, redirect_optsize);
647354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
648354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* Pseudo IPv6 datagram for checksum calculation */
649354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	memset(&p_ip6, '\0', sizeof(struct pseudo_ip6_datagram));
650354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	p_ip6.hdr.p_ip6_src = sndip6_p->hdr.ip6_src;
651354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	p_ip6.hdr.p_ip6_dst = sndip6_p->hdr.ip6_dst;
652354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	p_ip6.hdr.p_ip6_plen = sndip6_p->hdr.ip6_plen;
653354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	p_ip6.hdr.p_ip6_zero1 = 0;
654354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	p_ip6.hdr.p_ip6_zero2 = 0;
655354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	p_ip6.hdr.p_ip6_nxt = sndip6_p->hdr.ip6_nxt;
656354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	memcpy(p_ip6.payload, sndrd_p, ip6_payload_size);
657354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
658354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* Calculate checksum */
659354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sndrd_p->defs.nd_rd_cksum = calc_checksum((u_int16_t *) (&p_ip6),
660354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao						  sizeof(struct pseudo_ip6_hdr)
661354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao						  + ip6_payload_size);
662354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
663354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* Send ICMPv6 redirct message */
664354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	retval = write(sd, &sndeth, sndeth_size);
665354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (retval != sndeth_size)
666354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		fatal_error("write()");
66797903da2202008733f50e69997029d7a5cfffcb8mreed}
66897903da2202008733f50e69997029d7a5cfffcb8mreed
66997903da2202008733f50e69997029d7a5cfffcb8mreed/*
67097903da2202008733f50e69997029d7a5cfffcb8mreed * Function: analyze_ip6_datagram()
67197903da2202008733f50e69997029d7a5cfffcb8mreed *
67297903da2202008733f50e69997029d7a5cfffcb8mreed * Description:
67397903da2202008733f50e69997029d7a5cfffcb8mreed *  This function analyze captured IPv6 datagram
67497903da2202008733f50e69997029d7a5cfffcb8mreed *
67597903da2202008733f50e69997029d7a5cfffcb8mreed * Argument:
67697903da2202008733f50e69997029d7a5cfffcb8mreed *       sd      : socket to send arp reply message
67797903da2202008733f50e69997029d7a5cfffcb8mreed *    rcveth_p   : pointer to ether frame data
67897903da2202008733f50e69997029d7a5cfffcb8mreed *   rcveth_size : size of received ehter frame
67997903da2202008733f50e69997029d7a5cfffcb8mreed *    gateway_p  : pointer to IPv6 gateway information
68097903da2202008733f50e69997029d7a5cfffcb8mreed *
68197903da2202008733f50e69997029d7a5cfffcb8mreed * Return value:
68297903da2202008733f50e69997029d7a5cfffcb8mreed *  None
68397903da2202008733f50e69997029d7a5cfffcb8mreed */
68497903da2202008733f50e69997029d7a5cfffcb8mreedvoid
685354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaoanalyze_ip6_datagram(int sd, struct eth_frame *rcveth_p, size_t rcveth_size,
686354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		     struct ip6_gateway_info *gateway_p)
68797903da2202008733f50e69997029d7a5cfffcb8mreed{
688354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	struct ip6_datagram *rcvip6_p;	/* IPv6 Part of receiving frame */
689354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	struct icmp6_segment *rcvicmp6_p;	/* ICMPv6 Part of receiving frame */
690354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	uint8_t nxt_hdr;	/* Next header of IPv6 */
691354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	uint8_t icmp6_type;	/* Type of ICMPv6 */
69297903da2202008733f50e69997029d7a5cfffcb8mreed
693354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	rcvip6_p = (struct ip6_datagram *)&(rcveth_p->data);
694354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	rcvicmp6_p = (struct icmp6_segment *)&(rcvip6_p->payload);
69597903da2202008733f50e69997029d7a5cfffcb8mreed
696354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	nxt_hdr = rcvip6_p->hdr.ip6_nxt;
697354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	switch (nxt_hdr) {
69897903da2202008733f50e69997029d7a5cfffcb8mreed	case IPPROTO_ICMPV6:
699354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		icmp6_type = rcvicmp6_p->hdr.icmp6_type;
700354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		switch (icmp6_type) {
70197903da2202008733f50e69997029d7a5cfffcb8mreed		case ND_NEIGHBOR_SOLICIT:
702354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			if (debug)
703354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				fprintf(stderr, "Received ICMP NS\n");
704354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			return_neigh_adv(sd, rcveth_p, gateway_p);
705354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			break;
70697903da2202008733f50e69997029d7a5cfffcb8mreed
70797903da2202008733f50e69997029d7a5cfffcb8mreed		case ICMP6_ECHO_REQUEST:
708354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			if (debug)
709354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				fprintf(stderr, "Received ICMP Echo Request\n");
710354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			return_icmp6_redirect(sd, rcveth_p, rcveth_size,
711354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					      gateway_p);
712354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			break;
713354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		}
714354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		break;
71597903da2202008733f50e69997029d7a5cfffcb8mreed
71697903da2202008733f50e69997029d7a5cfffcb8mreed	case IPPROTO_UDP:
717354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		if (debug)
718354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			fprintf(stderr, "Received UDP message\n");
719354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		return_icmp6_redirect(sd, rcveth_p, rcveth_size, gateway_p);
720354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		break;
721354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	}
72297903da2202008733f50e69997029d7a5cfffcb8mreed}
72397903da2202008733f50e69997029d7a5cfffcb8mreed
72497903da2202008733f50e69997029d7a5cfffcb8mreed/*
72597903da2202008733f50e69997029d7a5cfffcb8mreed * Function: capture_frames()
72697903da2202008733f50e69997029d7a5cfffcb8mreed *
72797903da2202008733f50e69997029d7a5cfffcb8mreed * Description:
72897903da2202008733f50e69997029d7a5cfffcb8mreed *  This function captures frames
72997903da2202008733f50e69997029d7a5cfffcb8mreed *
73097903da2202008733f50e69997029d7a5cfffcb8mreed * Argument:
73197903da2202008733f50e69997029d7a5cfffcb8mreed *  redirector_p: pointer to data for the redirector information
73297903da2202008733f50e69997029d7a5cfffcb8mreed *
73397903da2202008733f50e69997029d7a5cfffcb8mreed * Return value:
73497903da2202008733f50e69997029d7a5cfffcb8mreed *  socket file descriptor for receiving packets
73597903da2202008733f50e69997029d7a5cfffcb8mreed */
736354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaovoid capture_frames(struct redirector_info *redirector_p)
73797903da2202008733f50e69997029d7a5cfffcb8mreed{
738354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	struct ip4_gateway_info ip4_gateway;	/* IPv4 gateway information */
739354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	struct ip6_gateway_info ip6_gateway;	/* IPv6 gateway information */
740354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	struct eth_frame frame;	/* captured frame data */
741354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	ssize_t frame_size;	/* captured frame size */
742354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	double start_time;	/* capture starting time */
743354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	int sd = redirector_p->sd;	/* socket fd for capture */
744354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
745354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* Initialize gateway information */
746354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	memset(&ip4_gateway, '\0', sizeof(struct ip4_gateway_info));
747354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	memset(&ip6_gateway, '\0', sizeof(struct ip6_gateway_info));
748354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
749354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* Set singal hander for SIGHUP */
750354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	handler.sa_handler = set_signal_flag;
751354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	handler.sa_flags = 0;
752354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (sigfillset(&handler.sa_mask) < 0)
753354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		fatal_error("sigfillset()");
754354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (sigaction(SIGHUP, &handler, NULL) < 0)
755354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		fatal_error("sigfillset()");
756354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
757354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/*
758354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	 * loop for capture
759354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	 */
760354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	start_time = time(NULL);
761354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
762354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	for (;;) {
763354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		frame_size = read(sd, (void *)(&frame), sizeof(frame));
764354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		if (frame_size < 0) {
765354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			if (errno != EAGAIN)
766354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				fatal_error("read()");
767354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		} else {
768354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			switch (ntohs(frame.hdr.h_proto)) {
769354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			case ETH_P_ARP:
770354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				if (debug)
771354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					fprintf(stderr, "Get ARP packet\n");
772354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				return_arp_reply(sd, &frame, &ip4_gateway);
773354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				break;
774354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
775354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			case ETH_P_IP:
776354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				if (debug)
777354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					fprintf(stderr, "Get IPv4 packet\n");
778354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				return_icmp4_redirect(sd, &frame, frame_size,
779354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao						      &ip4_gateway);
780354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				break;
781354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao
782354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			case ETH_P_IPV6:
783354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				if (debug)
784354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao					fprintf(stderr, "Get IPv6 packet\n");
785354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				analyze_ip6_datagram(sd, &frame, frame_size,
786354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao						     &ip6_gateway);
787354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				break;
788354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			}
789354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		}
79097903da2202008733f50e69997029d7a5cfffcb8mreed
791354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		if (redirector_p->timeout)
792354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			if (redirector_p->timeout <
793354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			    difftime(time(NULL), start_time))
794354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao				break;
79597903da2202008733f50e69997029d7a5cfffcb8mreed
796354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		if (catch_sighup)	/* catch SIGHUP */
797354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			break;
798354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	}
79997903da2202008733f50e69997029d7a5cfffcb8mreed}
80097903da2202008733f50e69997029d7a5cfffcb8mreed
80197903da2202008733f50e69997029d7a5cfffcb8mreed/*
80297903da2202008733f50e69997029d7a5cfffcb8mreed *
80397903da2202008733f50e69997029d7a5cfffcb8mreed *  Function: main()
80497903da2202008733f50e69997029d7a5cfffcb8mreed *
80597903da2202008733f50e69997029d7a5cfffcb8mreed */
806354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaoint main(int argc, char *argv[])
80797903da2202008733f50e69997029d7a5cfffcb8mreed{
808354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	struct redirector_info redirector;
809354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	int background = 0;
81097903da2202008733f50e69997029d7a5cfffcb8mreed
811354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	debug = 0;
812354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	program_name = strdup(argv[0]);
813354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	srand(getpid());
81497903da2202008733f50e69997029d7a5cfffcb8mreed
815354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	memset(&redirector, '\0', sizeof(struct redirector_info));
816354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	parse_options(argc, argv, &redirector, &background);
81797903da2202008733f50e69997029d7a5cfffcb8mreed
818354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	redirector.sd = open_socket(redirector.ifname);
81997903da2202008733f50e69997029d7a5cfffcb8mreed
820354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (background)		/* Work in the background */
821354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		if (daemon(0, 0) < 0)
822354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			fatal_error("daemon()");
82397903da2202008733f50e69997029d7a5cfffcb8mreed
824354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	capture_frames(&redirector);
82597903da2202008733f50e69997029d7a5cfffcb8mreed
826354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	close(redirector.sd);
827354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	exit(EXIT_SUCCESS);
828ec6edca7aa42b6affd989ef91b5897f96795e40fChris Dearman}
829