Annotation of embedaddon/mrouted/kern.c, revision 1.1.1.1
1.1 misho 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: int curttl = 0;
13:
14: /*
15: * Open/init the multicast routing in the kernel and sets the
16: * MRT_PIM (aka MRT_ASSERT) flag in the kernel.
17: */
18: void k_init_dvmrp(void)
19: {
20: #ifdef OLD_KERNEL
21: if (setsockopt(igmp_socket, IPPROTO_IP, MRT_INIT, (char *)NULL, 0) < 0) {
22: #else
23: int v = 1;
24:
25: if (setsockopt(igmp_socket, IPPROTO_IP, MRT_INIT, (char *)&v, sizeof(int)) < 0) {
26: #endif
27: if (errno == EADDRINUSE)
28: logit(LOG_ERR, 0, "Another multicast routing application is already running.");
29: else
30: logit(LOG_ERR, errno, "Cannot enable multicast routing in kernel");
31: }
32: }
33:
34:
35: /*
36: * Stops the multicast routing in the kernel and resets the
37: * MRT_PIM (aka MRT_ASSERT) flag in the kernel.
38: */
39: void k_stop_dvmrp(void)
40: {
41: if (setsockopt(igmp_socket, IPPROTO_IP, MRT_DONE, (char *)NULL, 0) < 0)
42: logit(LOG_WARNING, errno, "Cannot disable multicast routing in kernel");
43: }
44:
45:
46: /*
47: * Set the socket receiving buffer. `bufsize` is the preferred size,
48: * `minsize` is the smallest acceptable size.
49: */
50: void k_set_rcvbuf(int bufsize, int minsize)
51: {
52: int delta = bufsize / 2;
53: int iter = 0;
54:
55: /*
56: * Set the socket buffer. If we can't set it as large as we want, search around
57: * to try to find the highest acceptable value. The highest acceptable value
58: * being smaller than minsize is a fatal error.
59: */
60: if (setsockopt(igmp_socket, SOL_SOCKET, SO_RCVBUF, (char *)&bufsize, sizeof(bufsize)) < 0) {
61: bufsize -= delta;
62: while (1) {
63: iter++;
64: if (delta > 1)
65: delta /= 2;
66:
67: if (setsockopt(igmp_socket, SOL_SOCKET, SO_RCVBUF, (char *)&bufsize, sizeof(bufsize)) < 0) {
68: bufsize -= delta;
69: } else {
70: if (delta < 1024)
71: break;
72: bufsize += delta;
73: }
74: }
75: if (bufsize < minsize) {
76: logit(LOG_ERR, 0, "OS-allowed recv buffer size %u < app min %u", bufsize, minsize);
77: /*NOTREACHED*/
78: }
79: }
80: IF_DEBUG(DEBUG_KERN) {
81: logit(LOG_DEBUG, 0, "Got %d byte recv buffer size in %d iterations",
82: bufsize, iter);
83: }
84: }
85:
86:
87: /*
88: * Set/reset the IP_HDRINCL option. My guess is we don't need it for raw
89: * sockets, but having it here won't hurt. Well, unless you are running
90: * an older version of FreeBSD (older than 2.2.2). If the multicast
91: * raw packet is bigger than 208 bytes, then IP_HDRINCL triggers a bug
92: * in the kernel and "panic". The kernel patch for netinet/ip_raw.c
93: * coming with this distribution fixes it.
94: */
95: void k_hdr_include(int bool)
96: {
97: #ifdef IP_HDRINCL
98: if (setsockopt(igmp_socket, IPPROTO_IP, IP_HDRINCL, (char *)&bool, sizeof(bool)) < 0)
99: logit(LOG_ERR, errno, "setsockopt IP_HDRINCL %u", bool);
100: #endif
101: }
102:
103:
104: /*
105: * Set the default TTL for the multicast packets outgoing from this socket.
106: */
107: void k_set_ttl(int t)
108: {
109: u_char ttl;
110:
111: ttl = t;
112: if (setsockopt(igmp_socket, IPPROTO_IP, IP_MULTICAST_TTL, (char *)&ttl, sizeof(ttl)) < 0)
113: logit(LOG_ERR, errno, "setsockopt IP_MULTICAST_TTL %u", ttl);
114:
115: curttl = t;
116: }
117:
118:
119: /*
120: * Set/reset the IP_MULTICAST_LOOP. Set/reset is specified by "flag".
121: */
122: void k_set_loop(int flag)
123: {
124: u_char loop;
125:
126: loop = flag;
127: if (setsockopt(igmp_socket, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&loop, sizeof(loop)) < 0)
128: logit(LOG_ERR, errno, "setsockopt IP_MULTICAST_LOOP %u", loop);
129: }
130:
131:
132: /*
133: * Set the IP_MULTICAST_IF option on local interface ifa.
134: */
135: void k_set_if(u_int32 ifa)
136: {
137: struct in_addr adr;
138:
139: adr.s_addr = ifa;
140: if (setsockopt(igmp_socket, IPPROTO_IP, IP_MULTICAST_IF, (char *)&adr, sizeof(adr)) < 0) {
141: if (errno == EADDRNOTAVAIL || errno == EINVAL)
142: return;
143: logit(LOG_ERR, errno, "setsockopt IP_MULTICAST_IF %s",
144: inet_fmt(ifa, s1, sizeof(s1)));
145: }
146: }
147:
148:
149: /*
150: * Join a multicast group.
151: */
152: void k_join(u_int32 grp, u_int32 ifa)
153: {
154: struct ip_mreq mreq;
155:
156: mreq.imr_multiaddr.s_addr = grp;
157: mreq.imr_interface.s_addr = ifa;
158:
159: if (setsockopt(igmp_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq)) < 0)
160: logit(LOG_WARNING, errno, "Cannot join group %s on interface %s",
161: inet_fmt(grp, s1, sizeof(s1)), inet_fmt(ifa, s2, sizeof(s2)));
162: }
163:
164:
165: /*
166: * Leave a multicast group.
167: */
168: void k_leave(u_int32 grp, u_int32 ifa)
169: {
170: struct ip_mreq mreq;
171:
172: mreq.imr_multiaddr.s_addr = grp;
173: mreq.imr_interface.s_addr = ifa;
174:
175: if (setsockopt(igmp_socket, IPPROTO_IP, IP_DROP_MEMBERSHIP, (char *)&mreq, sizeof(mreq)) < 0)
176: logit(LOG_WARNING, errno, "Cannot leave group %s on interface %s",
177: inet_fmt(grp, s1, sizeof(s1)), inet_fmt(ifa, s2, sizeof(s2)));
178: }
179:
180: /*
181: * Fill struct vifctl using corresponding fields from struct uvif.
182: */
183: static void uvif_to_vifctl(struct vifctl *vc, struct uvif *v)
184: {
185: vc->vifc_flags = v->uv_flags & VIFF_KERNEL_FLAGS;
186: vc->vifc_threshold = v->uv_threshold;
187: vc->vifc_rate_limit = v->uv_rate_limit;
188: vc->vifc_lcl_addr.s_addr = v->uv_lcl_addr;
189: vc->vifc_rmt_addr.s_addr = v->uv_rmt_addr;
190: }
191:
192: /*
193: * Add a virtual interface in the kernel.
194: */
195: void k_add_vif(vifi_t vifi, struct uvif *v)
196: {
197: struct vifctl vc;
198:
199: vc.vifc_vifi = vifi;
200: uvif_to_vifctl(&vc, v);
201: if (setsockopt(igmp_socket, IPPROTO_IP, MRT_ADD_VIF, (char *)&vc, sizeof(vc)) < 0)
202: logit(LOG_ERR, errno, "setsockopt MRT_ADD_VIF on vif %d", vifi);
203: }
204:
205:
206: /*
207: * Delete a virtual interface in the kernel.
208: */
209: void k_del_vif(vifi_t vifi, struct uvif UNUSED *v)
210: {
211: /*
212: * Unfortunately Linux setsocopt MRT_DEL_VIF API differs a bit from the *BSD one.
213: * It expects to receive a pointer to struct vifctl that corresponds to the VIF
214: * we're going to delete. *BSD systems on the other hand exepect only the index
215: * of that VIF.
216: */
217: #ifdef __linux__
218: struct vifctl vc;
219:
220: vc.vifc_vifi = vifi;
221: uvif_to_vifctl(&vc, v);
222:
223: if (setsockopt(igmp_socket, IPPROTO_IP, MRT_DEL_VIF, (char *)&vc, sizeof(vc)) < 0)
224: #else /* *BSD et al. */
225: if (setsockopt(igmp_socket, IPPROTO_IP, MRT_DEL_VIF, (char *)&vifi, sizeof(vifi)) < 0)
226: #endif /* !__linux__ */
227: {
228: if (errno == EADDRNOTAVAIL || errno == EINVAL)
229: return;
230:
231: logit(LOG_ERR, errno, "setsockopt MRT_DEL_VIF on vif %d", vifi);
232: }
233: }
234:
235:
236: /*
237: * Adds a (source, mcastgrp) entry to the kernel
238: */
239: void k_add_rg(u_int32 origin, struct gtable *g)
240: {
241: struct mfcctl mc;
242: vifi_t i;
243:
244: #ifdef DEBUG_MFC
245: md_log(MD_ADD, origin, g->gt_mcastgrp);
246: #endif
247: /* copy table values so that setsockopt can process it */
248: mc.mfcc_origin.s_addr = origin;
249: #ifdef OLD_KERNEL
250: mc.mfcc_originmask.s_addr = 0xffffffff;
251: #endif
252: mc.mfcc_mcastgrp.s_addr = g->gt_mcastgrp;
253: mc.mfcc_parent = g->gt_route ? g->gt_route->rt_parent : NO_VIF;
254: for (i = 0; i < numvifs; i++)
255: mc.mfcc_ttls[i] = g->gt_ttls[i];
256:
257: /* write to kernel space */
258: if (setsockopt(igmp_socket, IPPROTO_IP, MRT_ADD_MFC,
259: (char *)&mc, sizeof(mc)) < 0) {
260: #ifdef DEBUG_MFC
261: md_log(MD_ADD_FAIL, origin, g->gt_mcastgrp);
262: #endif
263: logit(LOG_WARNING, errno, "setsockopt MRT_ADD_MFC",
264: inet_fmt(origin, s1, sizeof(s1)), inet_fmt(g->gt_mcastgrp, s2, sizeof(s2)));
265: }
266: }
267:
268:
269: /*
270: * Deletes a (source, mcastgrp) entry from the kernel
271: */
272: int k_del_rg(u_int32 origin, struct gtable *g)
273: {
274: struct mfcctl mc;
275:
276: #ifdef DEBUG_MFC
277: md_log(MD_DEL, origin, g->gt_mcastgrp);
278: #endif
279: /* copy table values so that setsockopt can process it */
280: mc.mfcc_origin.s_addr = origin;
281: #ifdef OLD_KERNEL
282: mc.mfcc_originmask.s_addr = 0xffffffff;
283: #endif
284: mc.mfcc_mcastgrp.s_addr = g->gt_mcastgrp;
285:
286: /* write to kernel space */
287: if (setsockopt(igmp_socket, IPPROTO_IP, MRT_DEL_MFC, (char *)&mc, sizeof(mc)) < 0) {
288: #ifdef DEBUG_MFC
289: md_log(MD_DEL_FAIL, origin, g->gt_mcastgrp);
290: #endif
291: logit(LOG_WARNING, errno, "setsockopt MRT_DEL_MFC of (%s %s)",
292: inet_fmt(origin, s1, sizeof(s1)), inet_fmt(g->gt_mcastgrp, s2, sizeof(s2)));
293:
294: return -1;
295: }
296:
297: return 0;
298: }
299:
300: /*
301: * Get the kernel's idea of what version of mrouted needs to run with it.
302: */
303: int k_get_version(void)
304: {
305: #ifdef OLD_KERNEL
306: return -1;
307: #else
308: int vers;
309: socklen_t len = sizeof(vers);
310:
311: if (getsockopt(igmp_socket, IPPROTO_IP, MRT_VERSION, (char *)&vers, &len) < 0)
312: logit(LOG_ERR, errno, "getsockopt MRT_VERSION: perhaps your kernel is too old?");
313:
314: return vers;
315: #endif
316: }
317:
318: #if 0
319: /*
320: * Get packet counters
321: */
322: int k_get_vif_count(vifi_t vifi, int *icount, int *ocount, int *ibytes, int *obytes)
323: {
324: struct sioc_vif_req vreq;
325: int retval = 0;
326:
327: vreq.vifi = vifi;
328: if (ioctl(udp_socket, SIOCGETVIFCNT, (char *)&vreq) < 0) {
329: logit(LOG_WARNING, errno, "SIOCGETVIFCNT on vif %d", vifi);
330: vreq.icount = vreq.ocount = vreq.ibytes =
331: vreq.obytes = 0xffffffff;
332: retval = 1;
333: }
334: if (icount)
335: *icount = vreq.icount;
336: if (ocount)
337: *ocount = vreq.ocount;
338: if (ibytes)
339: *ibytes = vreq.ibytes;
340: if (obytes)
341: *obytes = vreq.obytes;
342: return retval;
343: }
344:
345: /*
346: * Get counters for a desired source and group.
347: */
348: int k_get_sg_count(u_int32 src, u_int32 grp, int *pktcnt, int *bytecnt, int *wrong_if)
349: {
350: struct sioc_sg_req sgreq;
351: int retval = 0;
352:
353: sgreq.src.s_addr = src;
354: sgreq.grp.s_addr = grp;
355: if (ioctl(udp_socket, SIOCGETSGCNT, (char *)&sgreq) < 0) {
356: logit(LOG_WARNING, errno, "SIOCGETSGCNT on (%s %s)",
357: inet_fmt(src, s1, sizeof(s1)), inet_fmt(grp, s2, sizeof(s2)));
358: sgreq.pktcnt = sgreq.bytecnt = sgreq.wrong_if = 0xffffffff;
359: return 1;
360: }
361: if (pktcnt)
362: *pktcnt = sgreq.pktcnt;
363: if (bytecnt)
364: *bytecnt = sgreq.bytecnt;
365: if (wrong_if)
366: *wrong_if = sgreq.wrong_if;
367:
368: return retval;
369: }
370: #endif
371:
372: /**
373: * Local Variables:
374: * version-control: t
375: * indent-tabs-mode: t
376: * c-file-style: "ellemtel"
377: * c-basic-offset: 4
378: * End:
379: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>