1/*
2 * Copyright (C) NEC Europe Ltd., 2003
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the project nor the names of its contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#include <stdlib.h>
31#include <string.h>
32#include <arpa/inet.h>
33#include <net/if.h>
34
35#include "relay6_socket.h"
36#include "relay6_database.h"
37
38void
39init_socket()
40{
41	recvsock = (struct receive *) malloc(sizeof(struct receive));
42	sendsock = (struct send *) malloc(sizeof(struct send));
43
44	if ((recvsock == NULL) || (sendsock == NULL)) {
45		TRACE(dump, "%s - %s", dhcp6r_clock(),
46		      "init_socket--> ERROR NO MORE MEMORY AVAILABLE\n");
47		exit(1);
48	}
49
50	memset(recvsock, 0, sizeof(struct receive));
51	memset(sendsock, 0, sizeof(struct send));
52
53	recvsock->databuf = (char *) malloc(MAX_DHCP_MSG_LENGTH*sizeof(char));
54	if (recvsock->databuf == NULL) {
55		TRACE(dump, "%s - %s", dhcp6r_clock(),
56		      "init_socket--> ERROR NO MORE MEMORY AVAILABLE\n");
57		exit(1);
58	}
59
60	if ((recvsock->recv_sock_desc = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
61		printf("Failed to get new socket with socket()\n");
62		exit(0);
63	}
64
65	if ((sendsock->send_sock_desc = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
66		printf("Failed to get new socket with socket()\n");
67		exit(0);
68	}
69}
70
71int
72get_recv_data()
73{
74	struct cmsghdr *cm;
75	struct in6_pktinfo *pi;
76	struct sockaddr_in6 dst;
77
78	memset(recvsock->src_addr, 0, sizeof(recvsock->src_addr));
79
80	for(cm = (struct cmsghdr *) CMSG_FIRSTHDR(&recvsock->msg); cm;
81	    cm = (struct cmsghdr *) CMSG_NXTHDR(&recvsock->msg, cm)) {
82		if ((cm->cmsg_level == IPPROTO_IPV6) && (cm->cmsg_type == IPV6_PKTINFO)
83		    && (cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo)))) {
84			pi = (struct in6_pktinfo *)(CMSG_DATA(cm));
85			dst.sin6_addr = pi->ipi6_addr;
86			recvsock->pkt_interface = pi->ipi6_ifindex; /* the interface index
87			                                               the packet got in */
88
89			if (IN6_IS_ADDR_LOOPBACK(&recvsock->from.sin6_addr)) {
90				TRACE(dump, "%s - %s", dhcp6r_clock(),
91				      "get_recv_data()-->SOURCE ADDRESS IS LOOPBACK!\n");
92				return 0;
93			}
94
95			if (inet_ntop(AF_INET6, &recvsock->from.sin6_addr,
96			              recvsock->src_addr, INET6_ADDRSTRLEN) <= 0) {
97				TRACE(dump, "%s - %s", dhcp6r_clock(),
98				      "inet_ntop failed in get_recv_data()\n");
99				return 0;
100       		}
101
102			if (IN6_IS_ADDR_LOOPBACK(&dst.sin6_addr)) {
103				recvsock->dst_addr_type = 1;
104			}
105			else if (IN6_IS_ADDR_MULTICAST(&dst.sin6_addr)) {
106				recvsock->dst_addr_type = 2;
107				if (multicast_off == 1) {
108					TRACE(dump, "%s - %s", dhcp6r_clock(),
109					      "RECEIVED MULTICAST PACKET IS DROPPED, ONLY UNICAST "
110					      "IS ALLOWED!\n");
111					return 0;
112				}
113			}
114			else if (IN6_IS_ADDR_LINKLOCAL(&dst.sin6_addr)) {
115				recvsock->dst_addr_type = 3;
116			}
117			else if (IN6_IS_ADDR_SITELOCAL(&dst.sin6_addr))
118          		recvsock->dst_addr_type = 4;
119
120			return 1;
121		}
122	} /* for */
123
124	return 0;
125}
126
127int
128check_select(void)
129{
130	int i = 0;
131	int flag = 0;
132	struct timeval tv;
133
134	tv.tv_sec  = 0;
135	tv.tv_usec = 0;
136
137	FD_ZERO(&readfd);
138	fdmax = recvsock->recv_sock_desc; /* check the max of them if many
139	                                     desc used */
140	FD_SET(fdmax, &readfd);
141
142	if ((i = select(fdmax+1, &readfd, NULL, NULL, &tv)) == -1) {
143		TRACE(dump, "%s - %s", dhcp6r_clock(), "Failure in select()\n");
144		return 0;
145	}
146
147	if (FD_ISSET(fdmax, &readfd)) {
148		flag = 1;
149	}
150	else{
151		flag = 0;
152	}
153
154	return flag;
155}
156
157int
158set_sock_opt()
159{
160    int on = 1;
161    struct interface *device;
162	int flag;
163	struct cifaces *iface;
164	struct ipv6_mreq  sock_opt;
165
166	if (setsockopt(recvsock->recv_sock_desc, IPPROTO_IPV6, IPV6_PKTINFO,
167	               &on, sizeof(on) ) < 0) {
168		TRACE(dump, "%s - %s", dhcp6r_clock(),
169		      "Failed to set socket for IPV6_PKTINFO\n");
170		return 0;
171	}
172
173	for (device = interface_list.next; device != &interface_list;
174	     device = device->next) {
175		if (cifaces_list.next != &cifaces_list) {
176			flag = 0;
177			for (iface = cifaces_list.next; iface != &cifaces_list;
178			     iface = iface->next) {
179				if (strcmp(device->ifname, iface->ciface) == 0) {
180					flag = 1;
181					break;
182				}
183			}
184			if (flag == 0)
185				continue;
186		}
187
188		sock_opt.ipv6mr_interface = device->devindex;
189
190		if (inet_pton(AF_INET6, ALL_DHCP_RELAY_AND_SERVERS,
191		              &sock_opt.ipv6mr_multiaddr) <= 0) {
192			TRACE(dump, "%s - %s", dhcp6r_clock(),
193			      "Failed to set struct for MULTICAST receive\n");
194			return 0;
195		}
196
197		if (setsockopt(recvsock->recv_sock_desc, IPPROTO_IPV6, IPV6_JOIN_GROUP,
198		               (char *) &sock_opt, sizeof(sock_opt)) < 0) {
199			TRACE(dump, "%s - %s", dhcp6r_clock(),
200			      "Failed to set socket option for IPV6_JOIN_GROUP \n");
201			return 0;
202		}
203	}
204
205	TRACE(dump, "%s - %s", dhcp6r_clock(),
206	      "SOCKET OPTIONS ARE SET............\n");
207	fflush(dump);
208	return 1;
209}
210
211
212int
213fill_addr_struct()
214{
215	bzero((char *)&recvsock->from, sizeof(struct sockaddr_in6));
216	recvsock->from.sin6_family = AF_INET6;
217	recvsock->from.sin6_addr = in6addr_any;
218	recvsock->from.sin6_port = htons(547);
219
220	recvsock->iov[0].iov_base = recvsock->databuf;
221	recvsock->iov[0].iov_len = MAX_DHCP_MSG_LENGTH;
222	recvsock->msg.msg_name = (void *) &recvsock->from;
223	recvsock->msg.msg_namelen = sizeof(recvsock->from);
224	recvsock->msg.msg_iov = &recvsock->iov[0];
225	recvsock->msg.msg_iovlen = 1;
226
227	recvsock->recvmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo));
228	recvsock->recvp = (char *) malloc(recvsock->recvmsglen*sizeof(char));
229	recvsock->msg.msg_control = (void *) recvsock->recvp;
230	recvsock->msg.msg_controllen = recvsock->recvmsglen;
231
232    if (bind(recvsock->recv_sock_desc, (struct sockaddr *)&recvsock->from,
233	         sizeof(recvsock->from)) < 0) {
234		perror("bind");
235		return 0;
236	}
237
238	return 1;
239}
240
241int
242recv_data()
243{
244	int count = -1;
245
246	memset(recvsock->databuf, 0, (MAX_DHCP_MSG_LENGTH*sizeof(char)));
247
248	if ((count = recvmsg(recvsock->recv_sock_desc, &recvsock->msg, 0)) < 0) {
249		TRACE(dump, "%s - %s", dhcp6r_clock(),
250		      "Failed to receive data with recvmsg()-->Receive::recv_data()\n");
251		return -1;
252	}
253
254	recvsock->buflength = count;
255
256	return 1;
257}
258
259int
260get_interface_info()
261{
262	FILE *f;
263	char addr6[40], devname[20];
264	struct sockaddr_in6 sap;
265	int plen, scope, dad_status, if_idx;
266	char addr6p[8][5];
267	char src_addr[INET6_ADDRSTRLEN];
268	struct interface *device = NULL;
269	int opaq = OPAQ;
270	int sw = 0;
271	struct IPv6_address *ipv6addr;
272
273	if ((f = fopen(INTERFACEINFO, "r")) == NULL) {
274		printf("FATAL ERROR-->COULD NOT OPEN FILE: %s\n", INTERFACEINFO);
275		return 0;
276	}
277
278	while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n",
279	              addr6p[0], addr6p[1], addr6p[2], addr6p[3],addr6p[4],
280	              addr6p[5], addr6p[6], addr6p[7], &if_idx, &plen, &scope,
281	              &dad_status, devname) != EOF) {
282		memset(src_addr, 0, INET6_ADDRSTRLEN);
283		sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s", addr6p[0], addr6p[1],
284		        addr6p[2], addr6p[3],addr6p[4], addr6p[5], addr6p[6],
285		        addr6p[7]);
286		sap.sin6_family = AF_INET6;
287		sap.sin6_port = 0;
288
289		if (inet_pton(AF_INET6, addr6, sap.sin6_addr.s6_addr) <= 0)
290			return 0;
291
292		if (inet_ntop(AF_INET6, &sap.sin6_addr, src_addr, sizeof(src_addr)) <=
293		    0)
294			return 0;
295
296		if (IN6_IS_ADDR_LOOPBACK(&sap.sin6_addr))
297			continue;
298
299		sw = 0;
300		for (device = interface_list.next; device != &interface_list;
301		     device = device->next) {
302			if (device->devindex == if_idx) {
303				sw = 1;
304				break;
305			}
306		}
307
308		if (sw == 0) {
309			opaq += 10;
310			device = (struct interface *) malloc(sizeof(struct interface));
311			if (device ==NULL) {
312				TRACE(dump, "%s - %s", dhcp6r_clock(),
313				      "get_interface_info()--> "
314				      "ERROR NO MORE MEMORY AVAILABLE\n");
315				exit(1);
316			}
317			device->opaq = opaq;
318			device->ifname = strdup(devname);
319			device->devindex = if_idx;
320			device->ipv6addr = NULL;
321			device->prev = &interface_list;
322			device->next =  interface_list.next;
323			device->prev->next = device;
324			device->next->prev = device;
325			nr_of_devices += 1;
326		}
327
328		if (IN6_IS_ADDR_LINKLOCAL(&sap.sin6_addr)) {
329			device->link_local = strdup(src_addr);
330			TRACE(dump,"%s %s %s %d %s %s\n",\
331			      "RELAY INTERFACE INFO-> DEVNAME:", devname, "INDEX:", if_idx,
332			      "LINK_LOCAL_ADDRR:", src_addr);
333		}
334		else {
335			ipv6addr = (struct IPv6_address *)
336			           malloc(sizeof(struct IPv6_address));
337			if (ipv6addr ==NULL) {
338				TRACE(dump, "%s - %s", dhcp6r_clock(),
339				      "get_interface_info()--> "
340				      "ERROR NO MORE MEMORY AVAILABLE\n");
341				exit(1);
342			}
343			ipv6addr->gaddr = strdup(src_addr);
344			ipv6addr->next = NULL;
345			if (device->ipv6addr!= NULL)
346				ipv6addr->next = device->ipv6addr;
347
348			device->ipv6addr = ipv6addr;
349		}
350	} /* while */
351
352	fflush(dump);
353	for (device = interface_list.next; device != &interface_list;
354	     device = device->next) {
355		if ( device->ipv6addr == NULL) {
356			TRACE(dump,"%s - ERROR--> ONE MUST ASSIGN SITE SCOPED IPv6 "
357			      "ADDRESS FOR INTERFACE: %s\n", dhcp6r_clock(),
358			      device->ifname);
359			exit(1);
360		}
361	}
362
363	fclose(f);
364	return 1;
365}
366
367int
368send_message()
369{
370	struct sockaddr_in6 sin6;    /* my address information */
371	struct msghdr msg;
372	uint32_t count = 0;
373	struct msg_parser *mesg;
374	struct in6_pktinfo *in6_pkt;
375	struct cmsghdr *cmsgp;
376	char dest_addr[INET6_ADDRSTRLEN];
377	struct IPv6_uniaddr *ipv6uni;
378	struct interface *iface;
379	int hit = 0;
380	struct iovec iov[1];
381	int recvmsglen;
382	char *recvp;
383	struct server *uservers;
384	struct sifaces *si;
385
386	if ((mesg = get_send_messages_out()) == NULL)
387		return 0;
388
389	if (mesg->sent == 1)
390		return 0;
391
392	bzero((char *)&sin6, sizeof(struct sockaddr_in6));
393	sin6.sin6_family = AF_INET6;
394	sin6.sin6_flowinfo = 0;
395	sin6.sin6_scope_id = 0;
396
397	if (mesg->msg_type == RELAY_REPL) {
398		memset(dest_addr, 0, INET6_ADDRSTRLEN);
399		memcpy(dest_addr, mesg->peer_addr , INET6_ADDRSTRLEN);
400
401		recvmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo));
402		recvp = (char *) malloc(recvmsglen*sizeof(char));
403		if (recvp == NULL) {
404			printf("ERROR-->recvp NO MORE MEMORY AVAILABLE \n");
405			exit(1);
406		}
407		memset(recvp, 0, recvmsglen);
408		cmsgp = (struct cmsghdr *) recvp;
409		cmsgp->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
410		cmsgp->cmsg_level = IPPROTO_IPV6;
411		cmsgp->cmsg_type = IPV6_PKTINFO;
412		in6_pkt = (struct in6_pktinfo *) CMSG_DATA(cmsgp);
413		msg.msg_control = (void *) recvp;
414		msg.msg_controllen = recvmsglen;
415
416		/* destination address */
417		if (inet_pton(AF_INET6, dest_addr, &sin6.sin6_addr)<=0) {
418			TRACE(dump, "%s - %s", dhcp6r_clock(),
419			      "send_message()--> inet_pton FAILED \n");
420           exit(1);
421		}
422		sin6.sin6_scope_id = mesg->if_index;
423
424		if (mesg->hop > 0)
425			sin6.sin6_port = htons(SERVER_PORT);
426		else
427			sin6.sin6_port = htons(CLIENT_PORT);
428
429		iface = get_interface(mesg->if_index);
430
431		if (iface != NULL) {
432			if (inet_pton(AF_INET6, iface->ipv6addr->gaddr,
433			              &in6_pkt->ipi6_addr) <= 0) {  /* source address */
434				TRACE(dump, "%s - %s", dhcp6r_clock(),
435				      "inet_pton failed in send_message()\n");
436				exit(1);
437			}
438			TRACE(dump, "%s - SOURCE ADDRESS: %s\n", dhcp6r_clock(),
439			      iface->ipv6addr->gaddr);
440        }
441		else {
442			/* the kernel will choose the source address */
443			memset(&in6_pkt->ipi6_addr, 0, sizeof(in6_pkt->ipi6_addr));
444        }
445
446		/* OUTGOING DEVICE FOR RELAY_REPLY MSG */
447		in6_pkt->ipi6_ifindex = mesg->if_index;
448		TRACE(dump, "%s - OUTGOING DEVICE INDEX: %d\n", dhcp6r_clock(),
449		      in6_pkt->ipi6_ifindex);
450		TRACE(dump, "%s - DESTINATION PORT: %d\n", dhcp6r_clock(),
451		      ntohs(sin6.sin6_port));
452
453		iov[0].iov_base = mesg->buffer;
454		iov[0].iov_len = mesg->datalength;
455		msg.msg_name = (void *) &sin6;
456		msg.msg_namelen = sizeof(sin6);
457		msg.msg_iov = &iov[0];
458		msg.msg_iovlen = 1;
459
460		if ((count = sendmsg(sendsock->send_sock_desc, &msg, 0)) < 0) {
461			perror("sendmsg");
462			return 0;
463		}
464
465		if (count > MAX_DHCP_MSG_LENGTH)
466			perror("bytes in sendmsg");
467
468		TRACE(dump, "%s - *********> RELAY_REPL, SENT TO: %s SENT_BYTES: %d\n",
469		      dhcp6r_clock(), dest_addr, count);
470
471		free(recvp);
472
473		mesg->sent = 1;
474		return 1;
475	}
476
477	if (mesg->msg_type == RELAY_FORW) {
478		for (ipv6uni = IPv6_uniaddr_list.next; ipv6uni != &IPv6_uniaddr_list;
479		     ipv6uni = ipv6uni->next) {
480			bzero((char *)&sin6, sizeof(struct sockaddr_in6));
481			sin6.sin6_family = AF_INET6;
482
483			memset(dest_addr, 0, INET6_ADDRSTRLEN);
484			memcpy(dest_addr, ipv6uni->uniaddr , INET6_ADDRSTRLEN);
485
486			/* destination address */
487			if (inet_pton(AF_INET6, dest_addr, &sin6.sin6_addr) <= 0) {
488				TRACE(dump,"%s - %s",dhcp6r_clock(),
489				      "inet_pton failed in send_message()\n");
490				return 0;
491			}
492
493			recvmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo));
494			recvp = (char *) malloc(recvmsglen*sizeof(char));
495			if (recvp == NULL) {
496				TRACE(dump, "%s - %s", dhcp6r_clock(),
497				      "ERROR-->recvp NO MORE MEMORY AVAILABLE \n");
498				exit(1);
499			}
500			memset(recvp, 0, recvmsglen);
501
502			cmsgp = (struct cmsghdr *) recvp;
503			cmsgp->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
504			cmsgp->cmsg_level = IPPROTO_IPV6;
505			cmsgp->cmsg_type = IPV6_PKTINFO;
506			in6_pkt = (struct in6_pktinfo *) CMSG_DATA(cmsgp);
507			msg.msg_control = (void *) recvp;
508			msg.msg_controllen = recvmsglen;
509
510		 	/* destination address */
511			if (inet_pton(AF_INET6, dest_addr, &sin6.sin6_addr)<=0) {
512				TRACE(dump, "%s - %s", dhcp6r_clock(),
513				      "inet_pton failed in send_message()\n");
514				return 0;
515			}
516			sin6.sin6_scope_id = 0;
517			sin6.sin6_port = htons(SERVER_PORT);
518
519			/* the kernel will choose the source address */
520			memset(&in6_pkt->ipi6_addr, 0, sizeof(in6_pkt->ipi6_addr));
521		 	/* OUTGOING DEVICE FOR RELAY_REPLY MSG */
522			in6_pkt->ipi6_ifindex = 0;
523
524			iov[0].iov_base = mesg->buffer;
525			iov[0].iov_len = mesg->datalength;
526			msg.msg_name = (void *) &sin6;
527			msg.msg_namelen = sizeof(sin6);
528			msg.msg_iov = &iov[0];
529			msg.msg_iovlen = 1;
530
531			if ((count = sendmsg(sendsock->send_sock_desc, &msg, 0)) < 0) {
532				perror("sendmsg");
533				return 0;
534			}
535
536			if (count > MAX_DHCP_MSG_LENGTH)
537				perror("bytes sendmsg");
538
539			TRACE(dump,
540			      "%s - ========> RELAY_FORW, SENT TO: %s SENT_BYTES: %d\n",
541			      dhcp6r_clock(), dest_addr, count);
542			free(recvp);
543			hit = 1;
544		} /* for */
545
546		for (iface = interface_list.next;  iface!= &interface_list;
547	     	 iface = iface->next) {
548			uservers = iface->sname;
549			while (uservers != NULL) {
550				bzero((char *)&sin6, sizeof(struct sockaddr_in6));
551				sin6.sin6_family = AF_INET6;
552
553				memset(dest_addr, 0, INET6_ADDRSTRLEN);
554				memcpy(dest_addr, uservers->serv  , INET6_ADDRSTRLEN);
555
556				/* destination address */
557				if (inet_pton(AF_INET6, dest_addr, &sin6.sin6_addr) <= 0) {
558					TRACE(dump, "%s - %s", dhcp6r_clock(),
559					      "inet_pton failed in send_message()\n");
560					exit(1);
561				}
562
563				recvmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo));
564				recvp = (char *) malloc(recvmsglen*sizeof(char));
565				if (recvp == NULL) {
566					TRACE(dump, "%s - %s", dhcp6r_clock(),
567					      "ERROR-->recvp NO MORE MEMORY AVAILABLE \n");
568					exit(1);
569				}
570				memset(recvp, 0, recvmsglen);
571
572				cmsgp = (struct cmsghdr *) recvp;
573				cmsgp->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
574				cmsgp->cmsg_level = IPPROTO_IPV6;
575				cmsgp->cmsg_type = IPV6_PKTINFO;
576				in6_pkt = (struct in6_pktinfo *) CMSG_DATA(cmsgp);
577				msg.msg_control = (void *) recvp;
578				msg.msg_controllen = recvmsglen;
579
580				/* destination address */
581				if (inet_pton(AF_INET6, dest_addr, &sin6.sin6_addr) <= 0) {
582					TRACE(dump, "%s - %s", dhcp6r_clock(),
583					      "inet_pton failed in send_message()\n");
584					return 0;
585				}
586
587				in6_pkt->ipi6_ifindex = iface->devindex;
588				sin6.sin6_scope_id = in6_pkt->ipi6_ifindex;
589
590				TRACE(dump, "%s - OUTGOING DEVICE INDEX: %d\n", dhcp6r_clock(),
591				      in6_pkt->ipi6_ifindex);
592				if (inet_pton(AF_INET6, iface->ipv6addr->gaddr,
593				              &in6_pkt->ipi6_addr) <= 0) {  /* source address */
594					TRACE(dump,"%s - %s",dhcp6r_clock(),
595					      "inet_pton failed in send_message()\n");
596					exit(1);
597				}
598				TRACE(dump, "%s - SOURCE ADDRESS: %s\n", dhcp6r_clock(),
599				      iface->ipv6addr->gaddr);
600
601				sin6.sin6_port = htons(SERVER_PORT);
602
603				iov[0].iov_base = mesg->buffer;
604				iov[0].iov_len = mesg->datalength;
605				msg.msg_name = (void *) &sin6;
606				msg.msg_namelen = sizeof(sin6);
607				msg.msg_iov = &iov[0];
608				msg.msg_iovlen = 1;
609
610				if ((count = sendmsg(sendsock->send_sock_desc, &msg, 0)) < 0) {
611					perror("sendmsg");
612					return 0;
613				}
614
615				if (count > MAX_DHCP_MSG_LENGTH)
616					perror("bytes sendmsg");
617
618				TRACE(dump,
619				      "%s - ========> RELAY_FORW, SENT TO: %s SENT_BYTES: %d\n",
620				      dhcp6r_clock(), dest_addr, count);
621				free(recvp);
622				uservers = uservers->next;
623				hit = 1;
624			} /* while */
625		} /* Interfaces */
626
627		for (si = sifaces_list.next;  si != &sifaces_list; si = si->next) {
628			*(mesg->hc_pointer)= MAXHOPCOUNT;
629			bzero((char *)&sin6, sizeof(struct sockaddr_in6));
630			sin6.sin6_family = AF_INET6;
631
632			memset(dest_addr, 0, INET6_ADDRSTRLEN);
633			strcpy(dest_addr, ALL_DHCP_SERVERS);
634
635			/* destination address */
636			if (inet_pton(AF_INET6, dest_addr, &sin6.sin6_addr) <= 0) {
637				TRACE(dump, "%s - %s", dhcp6r_clock(),
638				      "inet_pton failed in send_message()\n");
639				return 0;
640			}
641
642			recvmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo));
643			recvp = (char *) malloc(recvmsglen*sizeof(char));
644			if (recvp == NULL) {
645				TRACE(dump, "%s - %s", dhcp6r_clock(),
646				      "ERROR-->recvp NO MORE MEMORY AVAILABLE \n");
647				exit(1);
648			}
649			memset(recvp, 0, recvmsglen);
650
651			cmsgp = (struct cmsghdr *) recvp;
652			cmsgp->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
653			cmsgp->cmsg_level = IPPROTO_IPV6;
654			cmsgp->cmsg_type = IPV6_PKTINFO;
655			in6_pkt = (struct in6_pktinfo *) CMSG_DATA(cmsgp);
656			msg.msg_control = (void *) recvp;
657			msg.msg_controllen = recvmsglen;
658
659			/* destination address */
660			if (inet_pton(AF_INET6, dest_addr, &sin6.sin6_addr) <= 0) {
661				TRACE(dump,"%s - %s",dhcp6r_clock(),
662				      "inet_pton failed in send_message()\n");
663				return 0;
664			}
665
666			in6_pkt->ipi6_ifindex = if_nametoindex(si->siface);
667			sin6.sin6_scope_id = in6_pkt->ipi6_ifindex;
668
669			TRACE(dump, "%s - OUTGOING DEVICE INDEX: %d\n", dhcp6r_clock(),
670			      in6_pkt->ipi6_ifindex);
671			iface = get_interface(in6_pkt->ipi6_ifindex);
672			if (iface == NULL) {
673				TRACE(dump, "%s - %s", dhcp6r_clock(),
674				      "ERROR--> send_message(), NO INTERFACE INFO FOUND\n");
675				exit(0);
676			}
677			if (inet_pton(AF_INET6, iface->ipv6addr->gaddr,
678			              &in6_pkt->ipi6_addr)<=0) {  /* source address */
679             	TRACE(dump, "%s - %s", dhcp6r_clock(),
680				      "inet_pton failed in send_message()\n");
681             	exit(1);
682			}
683			TRACE(dump,"%s - SOURCE ADDRESS: %s\n",dhcp6r_clock(),
684			      iface->ipv6addr->gaddr);
685
686			sin6.sin6_port = htons(SERVER_PORT);
687
688			iov[0].iov_base = mesg->buffer;
689			iov[0].iov_len = mesg->datalength;
690			msg.msg_name = (void *) &sin6;
691			msg.msg_namelen = sizeof(sin6);
692			msg.msg_iov = &iov[0];
693			msg.msg_iovlen = 1;
694
695			if ((count = sendmsg(sendsock->send_sock_desc, &msg, 0)) < 0) {
696				perror("sendmsg");
697				return 0;
698			}
699
700			if (count > MAX_DHCP_MSG_LENGTH)
701				perror("bytes sendmsg");
702
703			TRACE(dump,
704			      "%s - ========> RELAY_FORW, SENT TO: %s SENT_BYTES: %d\n",
705			     dhcp6r_clock(), dest_addr, count);
706
707			free(recvp);
708			hit = 1;
709		} /* for */
710
711		if (hit == 0) {
712			for (iface = interface_list.next;  iface != &interface_list;
713		     	iface = iface->next) {
714				if (mesg->interface_in == iface->devindex)
715					continue;
716
717				*(mesg->hc_pointer)= MAXHOPCOUNT;
718				bzero((char *)&sin6, sizeof(struct sockaddr_in6));
719				sin6.sin6_family = AF_INET6;
720
721				memset(dest_addr, 0, INET6_ADDRSTRLEN);
722				strcpy(dest_addr, ALL_DHCP_SERVERS);
723
724				/* destination address */
725				if (inet_pton(AF_INET6, dest_addr, &sin6.sin6_addr) <= 0) {
726					TRACE(dump, "%s - %s", dhcp6r_clock(),
727					      "inet_pton failed in send_message()\n");
728					return 0;
729				}
730
731				recvmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo));
732				recvp = (char *) malloc(recvmsglen*sizeof(char));
733				if (recvp ==NULL) {
734					TRACE(dump, "%s - %s", dhcp6r_clock(),
735					      "ERROR-->recvp NO MORE MEMORY AVAILABLE \n");
736					exit(1);
737				}
738				memset(recvp, 0, recvmsglen);
739
740				cmsgp = (struct cmsghdr *) recvp;
741				cmsgp->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
742				cmsgp->cmsg_level = IPPROTO_IPV6;
743				cmsgp->cmsg_type = IPV6_PKTINFO;
744				in6_pkt = (struct in6_pktinfo *) CMSG_DATA(cmsgp);
745				msg.msg_control = (void *) recvp;
746				msg.msg_controllen = recvmsglen;
747
748		 		/* destination address */
749				if (inet_pton(AF_INET6, dest_addr, &sin6.sin6_addr) <= 0) {
750					TRACE(dump, "%s - %s", dhcp6r_clock(),
751					      "inet_pton failed in send_message()\n");
752					return 0;
753				}
754				sin6.sin6_port = htons(SERVER_PORT);
755
756				in6_pkt->ipi6_ifindex = iface->devindex;
757				sin6.sin6_scope_id = in6_pkt->ipi6_ifindex;
758
759				TRACE(dump, "%s - OUTGOING DEVICE INDEX: %d\n", dhcp6r_clock(),
760				      in6_pkt->ipi6_ifindex);
761				if (inet_pton(AF_INET6, iface->ipv6addr->gaddr,
762				              &in6_pkt->ipi6_addr)<=0) {  /* source address */
763					TRACE(dump, "%s - %s", dhcp6r_clock(),
764					      "inet_pton failed in send_message()\n");
765					exit(1);
766				}
767
768				TRACE(dump, "%s - SOURCE ADDRESS: %s\n", dhcp6r_clock(),
769				      iface->ipv6addr->gaddr);
770
771				iov[0].iov_base = mesg->buffer;
772				iov[0].iov_len = mesg->datalength;
773				msg.msg_name = (void *) &sin6;
774				msg.msg_namelen = sizeof(sin6);
775				msg.msg_iov = &iov[0];
776				msg.msg_iovlen = 1;
777
778				if ((count = sendmsg(sendsock->send_sock_desc, &msg, 0))< 0) {
779					perror("sendmsg");
780					return 0;
781				}
782
783				if (count > MAX_DHCP_MSG_LENGTH)
784					perror("sendmsg");
785
786				TRACE(dump,
787				      "%s - ========> RELAY_FORW, SENT TO: %s SENT_BYTES: %d\n",
788				      dhcp6r_clock(), dest_addr, count);
789				free(recvp);
790			} /* for */
791		}
792	}
793
794	fflush(dump);
795	mesg->sent = 1;
796	return 1;
797
798
799	TRACE(dump, "%s - %s", dhcp6r_clock(),
800	      "FATAL ERROR--> NO MESSAGE TYPE TO BE SENT!\n");
801	exit(1);
802}
803