source: asp3_tinet_ecnl_rx/trunk/asp3_dcre/tinet/netinet/ip_igmp.c@ 337

Last change on this file since 337 was 337, checked in by coas-nagasima, 6 years ago

ASP3版ECNLを追加

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 9.6 KB
Line 
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* 上記著作権者は,以下の (1)~(4) の条件か,Free Software Foundation
8* によって公表されている GNU General Public License の Version 2 に記
9* 述されている条件を満たす場合に限り,本ソフトウェア(本ソフトウェア
10* を改変したものを含む.以下同じ)を使用・複製・改変・再配布(以下,
11* 利用と呼ぶ)することを無償で許諾する.
12* (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作
13* 権表示,この利用条件および下記の無保証規定が,そのままの形でソー
14* スコード中に含まれていること.
15* (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使
16* 用できる形で再配布する場合には,再配布に伴うドキュメント(利用
17* 者マニュアルなど)に,上記の著作権表示,この利用条件および下記
18* の無保証規定を掲載すること.
19* (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使
20* 用できない形で再配布する場合には,次の条件を満たすこと.
21* (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著
22* 作権表示,この利用条件および下記の無保証規定を掲載すること.
23* (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
24* 害からも,上記著作権者およびTOPPERSプロジェクトを免責すること.
25*
26* 本ソフトウェアは,無保証で提供されているものである.上記著作権者お
27* よびTOPPERSプロジェクトは,本ソフトウェアに関して,その適用可能性も
28* 含めて,いかなる保証も行わない.また,本ソフトウェアの利用により直
29* 接的または間接的に生じたいかなる損害に関しても,その責任を負わない.
30*
31* @(#) $Id$
32*/
33
34#include <string.h>
35
36#ifdef TARGET_KERNEL_ASP
37
38#include <kernel.h>
39#include <sil.h>
40#include <t_syslog.h>
41#include "kernel_cfg.h"
42#include "tinet_cfg.h"
43
44#endif /* of #ifdef TARGET_KERNEL_ASP */
45
46#ifdef TARGET_KERNEL_JSP
47
48#include <s_services.h>
49#include <t_services.h>
50#include "tinet_id.h"
51
52#endif /* of #ifdef TARGET_KERNEL_JSP */
53
54#include <tinet_defs.h>
55#include <tinet_config.h>
56
57#include <net/if.h>
58#include <net/if_loop.h>
59#include <net/if_ppp.h>
60#include <net/ethernet.h>
61#include <net/ppp_ipcp.h>
62#include <net/net.h>
63#include <net/net_endian.h>
64#include <net/net_buf.h>
65#include <net/net_timer.h>
66#include <net/net_count.h>
67
68#include <netinet/in.h>
69#include <netinet/in_var.h>
70#include <netinet/ip.h>
71#include <netinet/ip_var.h>
72#include <netinet/tcp.h>
73#include <netinet/tcp_var.h>
74#include <netinet/udp_var.h>
75#include <netinet/ip_igmp.h>
76
77#include <net/if_var.h>
78#include <net/net_var.h>
79
80#ifdef SUPPORT_IGMP
81
82static T_IGMP_ENTRY igmp_groups[NUM_IGMP_ENTRY];
83static T_IN4_ADDR igmp_send_addrs[NUM_IGMP_ENTRY];
84
85static bool_t igmp_send_report_v2(T_IN4_ADDR dst);
86static int16_t igmp_get_timer(T_IGMP_ENTRY *entry);
87
88ER igmp_set_loop(T_UDP_CEP *cep, uint8_t optval)
89{
90 switch (optval) {
91 case 0:
92 cep->igmp_loopback = false;
93 return E_OK;
94 case 1:
95 cep->igmp_loopback = true;
96 return E_OK;
97 }
98
99 return E_PAR;
100}
101
102ER igmp_get_loop(T_UDP_CEP *cep, uint8_t *optval)
103{
104 if (optval == NULL)
105 return E_PAR;
106
107 *optval = cep->igmp_loopback ? 1 : 0;
108
109 return E_OK;
110}
111
112ER igmp_set_ttl(T_UDP_CEP *cep, uint8_t optval)
113{
114 cep->igmp_ttl = optval;
115
116 return E_OK;
117}
118
119ER igmp_get_ttl(T_UDP_CEP *cep, uint8_t *optval)
120{
121 if (optval == NULL)
122 return E_PAR;
123
124 *optval = cep->igmp_ttl;
125
126 return E_OK;
127}
128
129ER igmp_set_if(T_UDP_CEP *cep, T_IN4_ADDR *optval)
130{
131 if (optval == NULL)
132 return E_PAR;
133
134 cep->igmp_mcaddr = *optval;
135
136 return E_OK;
137}
138
139ER igmp_get_if(T_UDP_CEP *cep, T_IN4_ADDR *optval)
140{
141 if (optval == NULL)
142 return E_PAR;
143
144 *optval = cep->igmp_mcaddr;
145
146 return E_OK;
147}
148
149ER igmp_add_membership(T_UDP_CEP *cep, T_IP_MREQ *optval)
150{
151 T_IGMP_ENTRY *entry = NULL;
152 int i;
153 T_IFNET *ifp = IF_GET_IFNET();
154 ER ret = E_NOMEM;
155
156 if ((optval->imr_interface != IPV4_ADDRANY)
157 && (optval->imr_interface != ifp->in4_ifaddr.addr))
158 return E_PAR;
159
160 syscall(wai_sem(SEM_IGMP_GROUP_LOCK));
161
162 for (i = 0; i < NUM_IGMP_ENTRY; i++) {
163 entry = &igmp_groups[i];
164 if (entry->timer == -1) {
165 entry->timer = 0;
166 entry->ip_addr = optval->imr_multiaddr;
167 ret = E_OK;
168 break;
169 }
170 }
171
172 syscall(sig_sem(SEM_IGMP_GROUP_LOCK));
173
174 return ret;
175}
176
177ER igmp_drop_membership(T_UDP_CEP *cep, T_IP_MREQ *optval)
178{
179 T_IGMP_ENTRY *entry = NULL;
180 int i;
181 ER ret = E_PAR;
182 T_IFNET *ifp = IF_GET_IFNET();
183
184 if ((optval->imr_interface != IPV4_ADDRANY)
185 && (optval->imr_interface != ifp->in4_ifaddr.addr))
186 return E_PAR;
187
188 syscall(wai_sem(SEM_IGMP_GROUP_LOCK));
189
190 for (i = 0; i < NUM_IGMP_ENTRY; i++) {
191 entry = &igmp_groups[i];
192 if ((entry->timer >= 0) && (entry->ip_addr == optval->imr_multiaddr)) {
193 entry->timer = -1;
194 entry->ip_addr = 0;
195 ret = E_OK;
196 break;
197 }
198 }
199
200 syscall(sig_sem(SEM_IGMP_GROUP_LOCK));
201
202 return ret;
203}
204
205ER igmp_set_ip_msfilter(T_UDP_CEP *cep, const T_IP_MSFILTER *optval)
206{
207 return E_PAR;
208}
209
210ER igmp_get_ip_msfilter(T_UDP_CEP *cep, T_IP_MSFILTER *optval)
211{
212 return E_PAR;
213}
214
215uint_t igmp_input(T_NET_BUF **inputp, uint_t *offp, uint_t *nextp)
216{
217 T_NET_BUF *input = *inputp;
218 T_IGMPV2_HDR *igmph;
219 uint_t len, align;
220 T_IP4_HDR *ip4h;
221 int i;
222 T_IGMP_ENTRY *entry;
223 bool_t ret;
224
225 NET_COUNT_IGMP(net_count_igmp.in_octets,
226 input->len - GET_IF_IP4_HDR_SIZE(input));
227 NET_COUNT_IGMP(net_count_igmp.in_packets, 1);
228
229 /* ICMP ヘッダの長さをチェックする。*/
230 if (input->len < IF_IP4_IGMP_HDR_SIZE) {
231 NET_COUNT_IGMP(net_count_igmp.in_err_packets, 1);
232 NET_COUNT_MIB(igmp_stats.igmpInErrors, 1);
233 goto buf_rel;
234 }
235
236 igmph = (T_IGMPV2_HDR *)(input->buf + *offp);
237
238 /* 4 オクテット境界のデータ長 */
239 len = input->len - *offp;
240 align = (len + 3) >> 2 << 2;
241
242 /* 4 オクテット境界までパディングで埋める。*/
243 if (align > len)
244 memset((uint8_t*)input->buf + input->len, 0, (size_t)(align - len));
245
246 /* チェックサムを計算する。*/
247 if (in_cksum(igmph, align) != 0) {
248 NET_COUNT_IGMP(net_count_igmp.in_err_packets, 1);
249 goto buf_rel;
250 }
251
252 /* メッセージの型により分岐する。*/
253 switch (igmph->type) {
254 case IGMP_MEMBERSHIP_QUERY:
255 ip4h = GET_IP4_HDR(input);
256 ret = false;
257
258 /* 参加中のグループアドレスからのクエリーの場合 */
259 syscall(wai_sem(SEM_IGMP_GROUP_LOCK));
260
261 for (i = 0; i < NUM_IGMP_ENTRY; i++) {
262 entry = &igmp_groups[i];
263 if ((entry->timer >= 0) && (entry->ip_addr == igmph->addr)) {
264 entry->resptime = igmph->time;
265 ret = true;
266 break;
267 }
268 }
269
270 syscall(sig_sem(SEM_IGMP_GROUP_LOCK));
271
272 if (ret) {
273 /* メンバーシップリポートを送信 */
274 igmp_send_report_v2(ip4h->src);
275 }
276 break;
277 }
278
279buf_rel:
280 syscall(rel_net_buf(input));
281 return IPPROTO_DONE;
282}
283
284static bool_t igmp_send_report_v2(T_IN4_ADDR dst)
285{
286 T_IGMPV2_HDR *igmph;
287 T_NET_BUF *output;
288 uint_t len = 0, align;
289
290 if (in4_get_datagram(&output, (uint_t)(IF_IP4_IGMP_HDR_SIZE + len), 0,
291 &dst, NULL, IPPROTO_IGMP, IP4_DEFTTL,
292 NBA_SEARCH_ASCENT, TMO_IGMP_OUTPUT) != E_OK)
293 return false;
294
295 /* IGMP ヘッダを設定する。*/
296 igmph = GET_IGMPV2_HDR(output, IF_IP4_IGMP_HDR_OFFSET);
297 igmph->type = IGMP_MEMBERSHIP_REPORT_V2;
298 igmph->time = 0;
299 igmph->addr = dst;
300
301 /* 4 オクテット境界のデータ長 */
302 align = (len + 3) >> 2 << 2;
303
304 /* 4 オクテット境界までパディングで埋める。*/
305 if (align > len)
306 memset((uint8_t*)GET_IGMP_SDU(output, IF_IP4_IGMP_HDR_OFFSET) + len,
307 0, (size_t)(align - len));
308
309 /* チェックサムを計算する。*/
310 igmph->sum = 0;
311 igmph->sum = in_cksum(igmph, (uint_t)(IGMP_HDR_SIZE + align));
312
313 /* 送信する。*/
314 NET_COUNT_IGMP(net_count_igmp.out_octets,
315 output->len - GET_IF_IP4_HDR_SIZE(output));
316 NET_COUNT_IGMP(net_count_igmp.out_packets, 1);
317 NET_COUNT_MIB(icmp_stats.icmpOutMsgs, 1);
318 NET_COUNT_MIB(icmp_stats.icmpOutDestUnreachs, 1);
319 ip_output(output, TMO_IGMP_OUTPUT);
320
321 return true;
322}
323
324/*
325* igmp_timer -- IGMP 共通タイマー
326*/
327static void igmp_timer(void *ignore)
328{
329 T_IGMP_ENTRY *entry = NULL;
330 int i, j = 0;
331
332 /* memset(igmp_send_addrs, 0, sizeof(igmp_send_addrs)); */
333
334 syscall(wai_sem(SEM_IGMP_GROUP_LOCK));
335
336 for (i = 0; i < NUM_IGMP_ENTRY; i++) {
337 entry = &igmp_groups[i];
338 if (entry->timer > 0)
339 entry->timer--;
340 if (entry->timer == 0) {
341 entry->timer = igmp_get_timer(entry);
342 igmp_send_addrs[j++] = entry->ip_addr;
343 }
344 }
345
346 syscall(sig_sem(SEM_IGMP_GROUP_LOCK));
347
348 for (i = 0; i < j; i++) {
349 igmp_send_report_v2(igmp_send_addrs[i]);
350 }
351
352 timeout(igmp_timer, NULL, NET_TIMER_HZ / 1);
353}
354
355/*
356* igmp_init -- IGMP 機能を初期化する。
357*/
358
359void igmp_init(void)
360{
361 int i;
362
363 for (i = 0; i < NUM_IGMP_ENTRY; i++) {
364 igmp_groups[i].timer = -1;
365 }
366
367 timeout(igmp_timer, NULL, NET_TIMER_HZ / 1);
368}
369
370bool_t igmp_is_joined_group(T_IN4_ADDR addr)
371{
372 T_IGMP_ENTRY *entry = NULL;
373 int i;
374 bool_t ret = false;
375
376 syscall(wai_sem(SEM_IGMP_GROUP_LOCK));
377
378 for (i = 0; i < NUM_IGMP_ENTRY; i++) {
379 entry = &igmp_groups[i];
380 if ((entry->timer >= 0) && (entry->ip_addr == addr)) {
381 ret = true;
382 break;
383 }
384 }
385
386 syscall(sig_sem(SEM_IGMP_GROUP_LOCK));
387
388 return ret;
389}
390
391int16_t igmp_get_timer(T_IGMP_ENTRY *entry)
392{
393 int16_t time = entry->resptime;
394
395 if (time == 0)
396 time = 590;
397
398 return (int16_t)(net_rand() % time) + 10;
399}
400
401#endif /* of #ifdef SUPPORT_IGMP */
Note: See TracBrowser for help on using the repository browser.