1 /*
2  * The mrouted program is covered by the license in the accompanying file
3  * named "LICENSE".  Use of the mrouted program represents acceptance of
4  * the terms and conditions listed in that file.
5  *
6  * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
7  * Leland Stanford Junior University.
8  */
9 
10 #include "defs.h"
11 
12 /*
13  * Exported variables.
14  */
15 #ifdef notyet
16 int		raw_socket;		    /* socket for raw network I/O  */
17 #endif
18 /*
19  *XXX For now, we just use the IGMP socket to send packets.
20  * This is legal in BSD, because the protocol # is not checked
21  * on raw sockets.  The k_* interfaces need to gain a socket
22  * argument so that we can call them on the raw_socket also.
23  */
24 #define	raw_socket	igmp_socket
25 
26 /*
27  * Private variables.
28  */
29 static int rawid = 0;
30 
31 /*
32  * Open and initialize the raw socket.
33  */
init_ipip(void)34 void init_ipip(void)
35 {
36 #ifdef notyet
37     if ((raw_socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
38 	logit(LOG_ERR, errno, "Raw IP socket");
39 #endif
40 }
41 
42 /*
43  * Allocate and fill in static IP header for encapsulating on a tunnel.
44  */
init_ipip_on_vif(struct uvif * v)45 void init_ipip_on_vif(struct uvif *v)
46 {
47     struct ip *ip;
48 
49     ip = v->uv_encap_hdr = (struct ip *)malloc(sizeof(struct ip));
50     if (!ip) {
51 	logit(LOG_ERR, errno, "Out of memory when setting up IPIP tunnel");
52 	return;			/* Never reached */
53     }
54 
55     /*
56      * Fields zeroed that aren't filled in later:
57      * - IP ID (let the kernel fill it in)
58      * - Offset (we don't send fragments)
59      * - Checksum (let the kernel fill it in)
60      */
61     memset(ip, 0, sizeof(struct ip));
62     ip->ip_v   = IPVERSION;
63     ip->ip_hl  = sizeof(struct ip) >> 2;
64     ip->ip_tos = 0xc0;		/* Internet Control */
65     ip->ip_ttl = MAXTTL;	/* applies to unicasts only */
66     ip->ip_p   = IPPROTO_IPIP;
67     ip->ip_src.s_addr = v->uv_lcl_addr;
68     ip->ip_dst.s_addr = v->uv_rmt_addr;
69 }
70 
71 /*
72  * Call build_igmp() to build an IGMP message in the output packet buffer.
73  * Then fill in the fields of the IP packet that build_igmp() left for the
74  * kernel to fill in, and encapsulate the original packet with the
75  * pre-created ip header for this vif.
76  */
send_ipip(uint32_t src,uint32_t dst,int type,int code,uint32_t group,int datalen,struct uvif * v)77 void send_ipip(uint32_t src, uint32_t dst, int type, int code, uint32_t group, int datalen, struct uvif *v)
78 {
79     struct msghdr msg;
80     struct iovec iov[2];
81     struct sockaddr_in sdst;
82     struct ip *ip;
83 
84     build_igmp(src, dst, type, code, group, datalen);
85     ip = (struct ip *)send_buf;
86     ip->ip_id = htons(rawid++);
87     ip->ip_sum = 0;
88     ip->ip_sum = inet_cksum((uint16_t *)ip, ip->ip_hl << 2);
89 
90     ip = v->uv_encap_hdr;
91     ip->ip_len = 2 * MIN_IP_HEADER_LEN + IGMP_MINLEN + datalen;
92 #ifndef HAVE_IP_HDRINCL_BSD_ORDER
93     ip->ip_len = htons(ip->ip_len);
94 #endif
95 
96     memset(&sdst, 0, sizeof(sdst));
97     sdst.sin_family = AF_INET;
98 #ifdef HAVE_SA_LEN
99     sdst.sin_len = sizeof(sdst);
100 #endif
101     sdst.sin_addr = ip->ip_dst;
102 
103     iov[0].iov_base = (caddr_t)v->uv_encap_hdr;
104     iov[0].iov_len = sizeof(struct ip);
105     iov[1].iov_base = (caddr_t)send_buf;
106     iov[1].iov_len = MIN_IP_HEADER_LEN + IGMP_MINLEN + datalen;
107 
108     memset(&msg, 0, sizeof(msg));
109     msg.msg_name = (caddr_t)&sdst;
110     msg.msg_namelen = sizeof(sdst);
111     msg.msg_iov = iov;
112     msg.msg_iovlen = 2;
113     if (sendmsg(raw_socket, &msg, 0) < 0) {
114 	if (errno == ENETDOWN)
115 	    check_vif_state();
116 	else
117 	    logit(LOG_WARNING, errno,
118 		"sendmsg to %s on %s",
119 		inet_fmt(sdst.sin_addr.s_addr, s1, sizeof(s1)), inet_fmt(src, s2, sizeof(s2)));
120     }
121 
122     IF_DEBUG(DEBUG_PKT|igmp_debug_kind(type, code))
123     logit(LOG_DEBUG, 0, "SENT %s from %-15s to %s encaped to %s",
124 	igmp_packet_kind(type, code), src == INADDR_ANY ? "INADDR_ANY" :
125 				 inet_fmt(src, s1, sizeof(s1)), inet_fmt(dst, s2, sizeof(s2)),
126 				 inet_fmt(sdst.sin_addr.s_addr, s3, sizeof(s3)));
127 }
128 
129 /**
130  * Local Variables:
131  *  version-control: t
132  *  indent-tabs-mode: t
133  *  c-file-style: "ellemtel"
134  *  c-basic-offset: 4
135  * End:
136  */
137