1 | /*
|
---|
2 | * TINET (TCP/IP Protocol Stack)
|
---|
3 | *
|
---|
4 | * Copyright (C) 2001-2012 by Dep. of Computer Science and Engineering
|
---|
5 | * Tomakomai National College of Technology, JAPAN
|
---|
6 | *
|
---|
7 | * ãLì ÒÍCÈºÌ (1)`(4) Ìð©CFree Software Foundation
|
---|
8 | * ÉæÁÄö\³êÄ¢é GNU General Public License Ì Version 2 ÉL
|
---|
9 | * q³êÄ¢éðð½·êÉÀèC{\tgEFAi{\tgEFA
|
---|
10 | * ðüϵ½àÌðÜÞDȺ¯¶jðgpE¡»EüÏEÄzziȺC
|
---|
11 | * pÆÄÔj·é±Æð³Åø·éD
|
---|
12 | * (1) {\tgEFAð\[XR[hÌ`Åp·éêÉÍCãLÌì
|
---|
13 | * \¦C±Ìpð¨æѺL̳ÛØKèªC»ÌÜÜÌ`Å\[
|
---|
14 | * XR[hÉÜÜêÄ¢é±ÆD
|
---|
15 | * (2) {\tgEFAðCCu`®ÈÇC¼Ì\tgEFAJÉg
|
---|
16 | * pÅ«é`ÅÄzz·éêÉÍCÄzzɺ¤hL
|
---|
17 | gip
|
---|
18 | * Ò}j
|
---|
19 | AÈÇjÉCãLÌì \¦C±Ìpð¨æѺL
|
---|
20 | * ̳ÛØKèðfÚ·é±ÆD
|
---|
21 | * (3) {\tgEFAðC@íÉgÝÞÈÇC¼Ì\tgEFAJÉg
|
---|
22 | * pÅ«È¢`ÅÄzz·éêÉÍCÌðð½·±ÆD
|
---|
23 | * (a) Äzzɺ¤hL
|
---|
24 | gipÒ}j
|
---|
25 | AÈÇjÉCãLÌ
|
---|
26 | * ì \¦C±Ìpð¨æѺL̳ÛØKèðfÚ·é±ÆD
|
---|
27 | * (4) {\tgEFAÌpÉæè¼ÚIܽÍÔÚIɶ¶é¢©Èé¹
|
---|
28 | * Q©çàCãLì Ò¨æÑTOPPERSvWFNgðÆÓ·é±ÆD
|
---|
29 | *
|
---|
30 | * {\tgEFAÍC³ÛØÅñ³êÄ¢éàÌÅ éDãLì Ò¨
|
---|
31 | * æÑTOPPERSvWFNgÍC{\tgEFAÉÖµÄC»ÌKpÂ\«à
|
---|
32 | * ÜßÄC¢©ÈéÛØàsíÈ¢DܽC{\tgEFAÌpÉæè¼
|
---|
33 | * ÚIܽÍÔÚIɶ¶½¢©Èé¹QÉÖµÄàC»ÌÓCðíÈ¢D
|
---|
34 | *
|
---|
35 | * @(#) $Id$
|
---|
36 | */
|
---|
37 |
|
---|
38 | #include <string.h>
|
---|
39 |
|
---|
40 | #ifdef TARGET_KERNEL_ASP
|
---|
41 |
|
---|
42 | #include <kernel.h>
|
---|
43 | #include <sil.h>
|
---|
44 | #include <t_syslog.h>
|
---|
45 | #include "kernel_cfg.h"
|
---|
46 | #include "tinet_cfg.h"
|
---|
47 |
|
---|
48 | #endif /* of #ifdef TARGET_KERNEL_ASP */
|
---|
49 |
|
---|
50 | #ifdef TARGET_KERNEL_JSP
|
---|
51 |
|
---|
52 | #include <s_services.h>
|
---|
53 | #include <t_services.h>
|
---|
54 | #include "tinet_id.h"
|
---|
55 |
|
---|
56 | #endif /* of #ifdef TARGET_KERNEL_JSP */
|
---|
57 |
|
---|
58 | #include <tinet_defs.h>
|
---|
59 | #include <tinet_config.h>
|
---|
60 |
|
---|
61 | #include <net/if.h>
|
---|
62 | #include <net/if_loop.h>
|
---|
63 | #include <net/if_ppp.h>
|
---|
64 | #include <net/ethernet.h>
|
---|
65 | #include <net/ppp_ipcp.h>
|
---|
66 | #include <net/net.h>
|
---|
67 | #include <net/net_endian.h>
|
---|
68 | #include <net/net_buf.h>
|
---|
69 | #include <net/net_timer.h>
|
---|
70 | #include <net/net_count.h>
|
---|
71 |
|
---|
72 | #include <netinet/in.h>
|
---|
73 | #include <netinet/in_var.h>
|
---|
74 | #include <netinet/ip.h>
|
---|
75 | #include <netinet/ip_var.h>
|
---|
76 | #include <netinet/tcp.h>
|
---|
77 | #include <netinet/tcp_var.h>
|
---|
78 | #include <netinet/udp_var.h>
|
---|
79 | #include <netinet/ip_igmp.h>
|
---|
80 |
|
---|
81 | #include <net/if_var.h>
|
---|
82 | #include <net/net_var.h>
|
---|
83 |
|
---|
84 | #ifdef SUPPORT_IGMP
|
---|
85 |
|
---|
86 | static T_IGMP_ENTRY igmp_groups[NUM_IGMP_ENTRY];
|
---|
87 | static T_IN4_ADDR igmp_send_addrs[NUM_IGMP_ENTRY];
|
---|
88 |
|
---|
89 | static bool_t igmp_send_report_v2(T_IN4_ADDR dst);
|
---|
90 | static uint16_t igmp_get_timer(T_IGMP_ENTRY *entry);
|
---|
91 |
|
---|
92 | ER igmp_set_loop(T_UDP_CEP *cep, uint8_t optval)
|
---|
93 | {
|
---|
94 | switch (optval) {
|
---|
95 | case 0:
|
---|
96 | cep->igmp_loopback = false;
|
---|
97 | return E_OK;
|
---|
98 | case 1:
|
---|
99 | cep->igmp_loopback = true;
|
---|
100 | return E_OK;
|
---|
101 | }
|
---|
102 |
|
---|
103 | return E_PAR;
|
---|
104 | }
|
---|
105 |
|
---|
106 | ER igmp_get_loop(T_UDP_CEP *cep, uint8_t *optval)
|
---|
107 | {
|
---|
108 | if (optval == NULL)
|
---|
109 | return E_PAR;
|
---|
110 |
|
---|
111 | *optval = cep->igmp_loopback ? 1 : 0;
|
---|
112 |
|
---|
113 | return E_OK;
|
---|
114 | }
|
---|
115 |
|
---|
116 | ER igmp_set_ttl(T_UDP_CEP *cep, uint8_t optval)
|
---|
117 | {
|
---|
118 | cep->igmp_ttl = optval;
|
---|
119 |
|
---|
120 | return E_OK;
|
---|
121 | }
|
---|
122 |
|
---|
123 | ER igmp_get_ttl(T_UDP_CEP *cep, uint8_t *optval)
|
---|
124 | {
|
---|
125 | if (optval == NULL)
|
---|
126 | return E_PAR;
|
---|
127 |
|
---|
128 | *optval = cep->igmp_ttl;
|
---|
129 |
|
---|
130 | return E_OK;
|
---|
131 | }
|
---|
132 |
|
---|
133 | ER igmp_set_if(T_UDP_CEP *cep, T_IN4_ADDR *optval)
|
---|
134 | {
|
---|
135 | if (optval == NULL)
|
---|
136 | return E_PAR;
|
---|
137 |
|
---|
138 | cep->igmp_mcaddr = *optval;
|
---|
139 |
|
---|
140 | return E_OK;
|
---|
141 | }
|
---|
142 |
|
---|
143 | ER igmp_get_if(T_UDP_CEP *cep, T_IN4_ADDR *optval)
|
---|
144 | {
|
---|
145 | if (optval == NULL)
|
---|
146 | return E_PAR;
|
---|
147 |
|
---|
148 | *optval = cep->igmp_mcaddr;
|
---|
149 |
|
---|
150 | return E_OK;
|
---|
151 | }
|
---|
152 |
|
---|
153 | ER igmp_add_membership(T_UDP_CEP *cep, T_IP_MREQ *optval)
|
---|
154 | {
|
---|
155 | T_IGMP_ENTRY *entry = NULL;
|
---|
156 | int i;
|
---|
157 | uint16_t min;
|
---|
158 | T_IFNET *ifp = IF_GET_IFNET();
|
---|
159 | ER ret = E_NOMEM;
|
---|
160 |
|
---|
161 | if ((optval->imr_interface != IPV4_ADDRANY)
|
---|
162 | && (optval->imr_interface != ifp->in4_ifaddr.addr))
|
---|
163 | return E_PAR;
|
---|
164 |
|
---|
165 | syscall(wai_sem(SEM_IGMP_GROUP_LOCK));
|
---|
166 |
|
---|
167 | for (i = 0; i < NUM_IGMP_ENTRY; i++) {
|
---|
168 | entry = &igmp_groups[i];
|
---|
169 | if (entry->timer == -1) {
|
---|
170 | entry->timer = igmp_get_timer(entry);
|
---|
171 | entry->ip_addr = optval->imr_multiaddr;
|
---|
172 | ret = E_OK;
|
---|
173 | break;
|
---|
174 | }
|
---|
175 | }
|
---|
176 |
|
---|
177 | syscall(sig_sem(SEM_IGMP_GROUP_LOCK));
|
---|
178 |
|
---|
179 | return ret;
|
---|
180 | }
|
---|
181 |
|
---|
182 | ER igmp_drop_membership(T_UDP_CEP *cep, T_IP_MREQ *optval)
|
---|
183 | {
|
---|
184 | T_IGMP_ENTRY *entry = NULL;
|
---|
185 | int i;
|
---|
186 | uint16_t min;
|
---|
187 | ER ret = E_PAR;
|
---|
188 | T_IFNET *ifp = IF_GET_IFNET();
|
---|
189 |
|
---|
190 | if ((optval->imr_interface != IPV4_ADDRANY)
|
---|
191 | && (optval->imr_interface != ifp->in4_ifaddr.addr))
|
---|
192 | return E_PAR;
|
---|
193 |
|
---|
194 | syscall(wai_sem(SEM_IGMP_GROUP_LOCK));
|
---|
195 |
|
---|
196 | for (i = 0; i < NUM_IGMP_ENTRY; i++) {
|
---|
197 | entry = &igmp_groups[i];
|
---|
198 | if ((entry->timer >= 0) && (entry->ip_addr == optval->imr_multiaddr)) {
|
---|
199 | entry->timer = -1;
|
---|
200 | entry->ip_addr = 0;
|
---|
201 | ret = E_OK;
|
---|
202 | break;
|
---|
203 | }
|
---|
204 | }
|
---|
205 |
|
---|
206 | syscall(sig_sem(SEM_IGMP_GROUP_LOCK));
|
---|
207 |
|
---|
208 | return ret;
|
---|
209 | }
|
---|
210 |
|
---|
211 | ER igmp_set_ip_msfilter(T_UDP_CEP *cep, const T_IP_MSFILTER *optval)
|
---|
212 | {
|
---|
213 | return E_PAR;
|
---|
214 | }
|
---|
215 |
|
---|
216 | ER igmp_get_ip_msfilter(T_UDP_CEP *cep, T_IP_MSFILTER *optval)
|
---|
217 | {
|
---|
218 | return E_PAR;
|
---|
219 | }
|
---|
220 |
|
---|
221 | uint_t igmp_input(T_NET_BUF **inputp, uint_t *offp, uint_t *nextp)
|
---|
222 | {
|
---|
223 | T_NET_BUF *input = *inputp;
|
---|
224 | T_IGMPV2_HDR *igmph;
|
---|
225 | T_IN4_ADDR addr;
|
---|
226 | uint_t len, align;
|
---|
227 | T_IP4_HDR *ip4h;
|
---|
228 | int i;
|
---|
229 | T_IGMP_ENTRY *entry;
|
---|
230 | bool_t ret;
|
---|
231 |
|
---|
232 | NET_COUNT_IGMP(net_count_igmp.in_octets,
|
---|
233 | input->len - GET_IF_IP4_HDR_SIZE(input));
|
---|
234 | NET_COUNT_IGMP(net_count_igmp.in_packets, 1);
|
---|
235 |
|
---|
236 | /* ICMP wb_Ì·³ð`FbN·éB*/
|
---|
237 | if (input->len < IF_IP4_IGMP_HDR_SIZE) {
|
---|
238 | NET_COUNT_IGMP(net_count_igmp.in_err_packets, 1);
|
---|
239 | NET_COUNT_MIB(igmp_stats.igmpInErrors, 1);
|
---|
240 | goto buf_rel;
|
---|
241 | }
|
---|
242 |
|
---|
243 | igmph = (T_IGMPV2_HDR *)(input->buf + *offp);
|
---|
244 |
|
---|
245 | /* 4 INebg«EÌf[^· */
|
---|
246 | len = input->len - *offp;
|
---|
247 | align = (len + 3) >> 2 << 2;
|
---|
248 |
|
---|
249 | /* 4 INebg«EÜÅpfBOÅßéB*/
|
---|
250 | if (align > len)
|
---|
251 | memset((uint8_t*)input->buf + input->len, 0, (size_t)(align - len));
|
---|
252 |
|
---|
253 | /* `FbNTðvZ·éB*/
|
---|
254 | if (in_cksum(igmph, align) != 0) {
|
---|
255 | NET_COUNT_IGMP(net_count_igmp.in_err_packets, 1);
|
---|
256 | goto buf_rel;
|
---|
257 | }
|
---|
258 |
|
---|
259 | /* bZ[WÌ^Éæèªò·éB*/
|
---|
260 | switch (igmph->type) {
|
---|
261 | case IGMP_MEMBERSHIP_QUERY:
|
---|
262 | ip4h = GET_IP4_HDR(input);
|
---|
263 | ret = false;
|
---|
264 |
|
---|
265 | /* QÁÌO[vAhX©çÌNG[Ìê */
|
---|
266 | syscall(wai_sem(SEM_IGMP_GROUP_LOCK));
|
---|
267 |
|
---|
268 | for (i = 0; i < NUM_IGMP_ENTRY; i++) {
|
---|
269 | entry = &igmp_groups[i];
|
---|
270 | if ((entry->timer >= 0) && (entry->ip_addr == addr)) {
|
---|
271 | entry->resptime = igmph->time;
|
---|
272 | ret = true;
|
---|
273 | break;
|
---|
274 | }
|
---|
275 | }
|
---|
276 |
|
---|
277 | syscall(sig_sem(SEM_IGMP_GROUP_LOCK));
|
---|
278 |
|
---|
279 | if (ret) {
|
---|
280 | /* o[Vbv|[gðM */
|
---|
281 | igmp_send_report_v2(ip4h->src);
|
---|
282 | }
|
---|
283 | break;
|
---|
284 | }
|
---|
285 |
|
---|
286 | buf_rel:
|
---|
287 | syscall(rel_net_buf(input));
|
---|
288 | return IPPROTO_DONE;
|
---|
289 | }
|
---|
290 |
|
---|
291 | static bool_t igmp_send_report_v2(T_IN4_ADDR dst)
|
---|
292 | {
|
---|
293 | T_IGMPV2_HDR *igmph;
|
---|
294 | T_NET_BUF *output;
|
---|
295 | uint_t len, align;
|
---|
296 |
|
---|
297 | if (in4_get_datagram(&output, (uint_t)(IF_IP4_IGMP_HDR_SIZE + len), 0,
|
---|
298 | &dst, NULL, IPPROTO_IGMP, IP4_DEFTTL,
|
---|
299 | NBA_SEARCH_ASCENT, TMO_IGMP_OUTPUT) != E_OK)
|
---|
300 | return false;
|
---|
301 |
|
---|
302 | /* IGMP wb_ðÝè·éB*/
|
---|
303 | igmph = GET_IGMPV2_HDR(output, IF_IP4_IGMP_HDR_OFFSET);
|
---|
304 | igmph->type = IGMP_MEMBERSHIP_REPORT_V2;
|
---|
305 | igmph->time = 0;
|
---|
306 | igmph->addr = dst;
|
---|
307 |
|
---|
308 | /* 4 INebg«EÌf[^· */
|
---|
309 | align = (len + 3) >> 2 << 2;
|
---|
310 |
|
---|
311 | /* 4 INebg«EÜÅpfBOÅßéB*/
|
---|
312 | if (align > len)
|
---|
313 | memset((uint8_t*)GET_IGMP_SDU(output, IF_IP4_IGMP_HDR_OFFSET) + IP4_HDR_SIZE + len,
|
---|
314 | 0, (size_t)(align - len));
|
---|
315 |
|
---|
316 | /* `FbNTðvZ·éB*/
|
---|
317 | igmph->sum = 0;
|
---|
318 | igmph->sum = in_cksum(igmph, (uint_t)(IF_IP4_IGMP_HDR_SIZE + align));
|
---|
319 |
|
---|
320 | /* M·éB*/
|
---|
321 | NET_COUNT_IGMP(net_count_igmp.out_octets,
|
---|
322 | output->len - GET_IF_IP4_HDR_SIZE(output));
|
---|
323 | NET_COUNT_IGMP(net_count_igmp.out_packets, 1);
|
---|
324 | NET_COUNT_MIB(icmp_stats.icmpOutMsgs, 1);
|
---|
325 | NET_COUNT_MIB(icmp_stats.icmpOutDestUnreachs, 1);
|
---|
326 | ip_output(output, TMO_IGMP_OUTPUT);
|
---|
327 |
|
---|
328 | return true;
|
---|
329 | }
|
---|
330 |
|
---|
331 | /*
|
---|
332 | * igmp_timer -- IGMP ¤Ê^C}[
|
---|
333 | */
|
---|
334 | static void igmp_timer(void *ignore)
|
---|
335 | {
|
---|
336 | T_IGMP_ENTRY *entry = NULL;
|
---|
337 | int i, j = 0;
|
---|
338 |
|
---|
339 | /* memset(igmp_send_addrs, 0, sizeof(igmp_send_addrs)); */
|
---|
340 |
|
---|
341 | syscall(wai_sem(SEM_IGMP_GROUP_LOCK));
|
---|
342 |
|
---|
343 | for (i = 0; i < NUM_IGMP_ENTRY; i++) {
|
---|
344 | entry = &igmp_groups[i];
|
---|
345 | if (entry->timer > 0)
|
---|
346 | entry->timer--;
|
---|
347 | if (entry->timer == 0) {
|
---|
348 | entry->timer = igmp_get_timer(entry);
|
---|
349 | igmp_send_addrs[j++] = entry->ip_addr;
|
---|
350 | }
|
---|
351 | }
|
---|
352 |
|
---|
353 | syscall(sig_sem(SEM_IGMP_GROUP_LOCK));
|
---|
354 |
|
---|
355 | for (i = 0; i < j; i++) {
|
---|
356 | igmp_send_report_v2(igmp_send_addrs[i]);
|
---|
357 | }
|
---|
358 |
|
---|
359 | timeout(igmp_timer, NULL, NET_TIMER_HZ / 1);
|
---|
360 | }
|
---|
361 |
|
---|
362 | /*
|
---|
363 | * igmp_init -- IGMP @\ðú»·éB
|
---|
364 | */
|
---|
365 |
|
---|
366 | void igmp_init(void)
|
---|
367 | {
|
---|
368 | T_IGMP_ENTRY *entry = NULL;
|
---|
369 | int i;
|
---|
370 |
|
---|
371 | for (i = 0; i < NUM_IGMP_ENTRY; i++) {
|
---|
372 | igmp_groups[i].timer = -1;
|
---|
373 | }
|
---|
374 |
|
---|
375 | timeout(igmp_timer, NULL, NET_TIMER_HZ / 1);
|
---|
376 | }
|
---|
377 |
|
---|
378 | bool_t igmp_is_joined_group(T_IN4_ADDR addr)
|
---|
379 | {
|
---|
380 | T_IGMP_ENTRY *entry = NULL;
|
---|
381 | int i;
|
---|
382 | bool_t ret = false;
|
---|
383 |
|
---|
384 | syscall(wai_sem(SEM_IGMP_GROUP_LOCK));
|
---|
385 |
|
---|
386 | for (i = 0; i < NUM_IGMP_ENTRY; i++) {
|
---|
387 | entry = &igmp_groups[i];
|
---|
388 | if ((entry->timer >= 0) && (entry->ip_addr == addr)) {
|
---|
389 | ret = true;
|
---|
390 | break;
|
---|
391 | }
|
---|
392 | }
|
---|
393 |
|
---|
394 | syscall(sig_sem(SEM_IGMP_GROUP_LOCK));
|
---|
395 |
|
---|
396 | return ret;
|
---|
397 | }
|
---|
398 |
|
---|
399 | uint16_t igmp_get_timer(T_IGMP_ENTRY *entry)
|
---|
400 | {
|
---|
401 | uint16_t time = entry->resptime;
|
---|
402 |
|
---|
403 | if (time == 0)
|
---|
404 | time = 10;
|
---|
405 |
|
---|
406 | return net_rand() / (0x7fffffff / time);
|
---|
407 | }
|
---|
408 |
|
---|
409 | #endif /* of #ifdef SUPPORT_IGMP */
|
---|