source: asp3_tinet_ecnl_arm/trunk/ntshell/echonet/echonet_udp_task.c@ 364

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

TINETとSocket APIなどを更新

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 21.0 KB
Line 
1/*
2 * TOPPERS ECHONET Lite Communication Middleware
3 *
4 * Copyright (C) 2014 Cores Co., Ltd. Japan
5 *
6 * 上記著作権者は,以下の(1)~(4)の条件を満たす場合に限り,本ソフトウェ
7 * ア(本ソフトウェアを改変したものを含む.以下同じ)を使用・複製・改
8 * 変・再配布(以下,利用と呼ぶ)することを無償で許諾する.
9 * (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作
10 * 権表示,この利用条件および下記の無保証規定が,そのままの形でソー
11 * スコード中に含まれていること.
12 * (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使
13 * 用できる形で再配布する場合には,再配布に伴うドキュメント(利用
14 * 者マニュアルなど)に,上記の著作権表示,この利用条件および下記
15 * の無保証規定を掲載すること.
16 * (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使
17 * 用できない形で再配布する場合には,次のいずれかの条件を満たすこ
18 * と.
19 * (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著
20 * 作権表示,この利用条件および下記の無保証規定を掲載すること.
21 * (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに
22 * 報告すること.
23 * (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
24 * 害からも,上記著作権者およびTOPPERSプロジェクトを免責すること.
25 * また,本ソフトウェアのユーザまたはエンドユーザからのいかなる理
26 * 由に基づく請求からも,上記著作権者およびTOPPERSプロジェクトを
27 * 免責すること.
28 *
29 * 本ソフトウェアは,無保証で提供されているものである.上記著作権者お
30 * よびTOPPERSプロジェクトは,本ソフトウェアに関して,特定の使用目的
31 * に対する適合性も含めて,いかなる保証も行わない.また,本ソフトウェ
32 * アの利用により直接的または間接的に生じたいかなる損害に関しても,そ
33 * の責任を負わない.
34 *
35 * @(#) $Id$
36 */
37
38/*
39 * ECHONET Lite UDP通信処理タスク
40 */
41#ifdef SUPPORT_INET4
42
43#include <kernel.h>
44#include <string.h>
45#include <stdio.h>
46#include <stdlib.h>
47#include <t_syslog.h>
48#include <t_stdlib.h>
49#include <sil.h>
50
51#include "syssvc/serial.h"
52#include "syssvc/syslog.h"
53#include "echonet.h"
54
55#include <tinet_config.h>
56#include <tinet_defs.h>
57#include <netinet/in.h>
58#include <netinet/in_var.h>
59#include <net/ethernet.h>
60#include <net/if.h>
61#include <net/if_var.h>
62#include <net/net.h>
63#include <netinet/in_itron.h>
64#include <netinet/udp_var.h>
65#include <netinet/ip_igmp.h>
66
67#include "echonet_task.h"
68#include "echonet_lcl_task.h"
69#include "echonet_dbg.h"
70
71#ifndef ECHONET_UDP_TASK_GET_TIMER
72#define ECHONET_UDP_TASK_GET_TIMER TMO_FEVR
73#endif /* ECHONET_UDP_TASK_GET_TIMER */
74
75#ifndef ECHONET_UDP_TASK_PROGRESS
76#define ECHONET_UDP_TASK_PROGRESS(timer)
77#endif /* ECHONET_UDP_TASK_PROGRESS */
78
79#ifndef ECHONET_UDP_TASK_TIMEOUT
80#define ECHONET_UDP_TASK_TIMEOUT
81#endif /* ECHONET_UDP_TASK_TIMEOUT */
82
83#ifndef ECHONET_UDP_SEND_TO_MBX
84#define ECHONET_UDP_SEND_TO_MBX
85#endif /* ECHONET_UDP_SEND_TO_MBX */
86
87#ifndef ECHONET_NODE_MATCH
88#define ECHONET_NODE_MATCH(enodcb, edata, ipaddr, portno) is_match(enodcb, edata, ipaddr, portno)
89#endif /* ECHONET_NODE_MATCH */
90
91static ECN_ENOD_ID udp_get_id(T_EDATA *edata, const T_IN4_ADDR ipaddr, uint16_t portno);
92static int udp_get_ip(T_IPV4EP *fp_ipep, ECN_ENOD_ID fa_enodid);
93void _ecn_int_msg(ECN_FBS_ID fbs_id, ECN_FBS_SSIZE_T a_snd_len);
94void _ecn_esv_msg(ECN_FBS_ID fbs_id);
95
96/*
97 * 受信したUDPデータをMAILBOXに送る
98 */
99ER _ecn_udp2dtq(const uint8_t *buffer, size_t fa_len, const T_IPV4EP *dst);
100ER _ecn_udp2dtq(const uint8_t *buffer, size_t fa_len, const T_IPV4EP *dst)
101{
102 ECN_FBS_ID a_fbs_id = { 0 };
103 ER a_ret = E_OK;
104 ECN_ENOD_ID a_enod_id;
105 union
106 {
107 const uint8_t *buffer;
108 const T_ECN_EDT_HDR *t_esv;
109 } a_rcv_pkt;
110
111 a_rcv_pkt.buffer = buffer;
112 if ( a_rcv_pkt.t_esv->ecn_hdr.ehd1 != ECN_EDH1_ECHONET_LITE /* ECHONET Lite規格 */
113 || a_rcv_pkt.t_esv->ecn_hdr.ehd2 != ECN_EDH2_FORMAT_1 /* 電文形式1 */) {
114 ECN_DBG_PUT_2("[UDP ECHO SRV] illegal type (0x%02X,0x%02X)", a_rcv_pkt.t_esv->ecn_hdr.ehd1, a_rcv_pkt.t_esv->ecn_hdr.ehd2);
115 return E_PAR;
116 }
117
118#ifdef ECN_DBG_PUT_ENA
119 _ecn_dbg_bindmp(buffer, fa_len);
120#endif
121
122 a_ret = _ecn_fbs_cre(fa_len, &a_fbs_id);
123 if (a_ret != E_OK) {
124 ECN_DBG_PUT_2("[UDP ECHO SRV] _ecn_fbs_cre() result = %d:%s", a_ret, itron_strerror(a_ret));
125 return a_ret;
126 }
127 a_ret = _ecn_fbs_add_data_ex(a_fbs_id, buffer, fa_len);
128 if (a_ret) {
129 ECN_DBG_PUT_2("[UDP ECHO SRV] _ecn_fbs_add_data_ex() result = %d:%s", a_ret, itron_strerror(a_ret));
130 goto lb_except;
131 }
132 a_fbs_id.ptr->hdr.type = ECN_MSG_ECHONET;
133 a_fbs_id.ptr->hdr.target.id = ENOD_LOCAL_ID;
134 a_fbs_id.ptr->hdr.sender.id = ENOD_NOT_MATCH_ID;
135
136 /* IPアドレスからリモートECHONETノードへ変換 */
137 a_enod_id = udp_get_id((T_EDATA *)a_fbs_id.ptr, dst->ipaddr, dst->portno);
138 if (a_enod_id < 0 || tnum_enodadr <= a_enod_id) {
139 ECN_DBG_PUT_1("[UDP ECHO SRV] udp src(%s) echonet-node not found.",
140 ip2str(NULL, &dst->ipaddr));
141 } else {
142 /* 送信元ECHONETノードを記録 */
143 a_fbs_id.ptr->hdr.sender.id = a_enod_id;
144 }
145 a_fbs_id.ptr->hdr.reply.id = a_fbs_id.ptr->hdr.sender.id;
146
147 /* echonet_taskに送る */
148 a_ret = snd_dtq(ecn_svc_dataqueueid, (intptr_t)a_fbs_id.ptr);
149 if (a_ret != E_OK) {
150 ECN_DBG_PUT_2("[UDP ECHO SRV] snd_dtq(ecn_svc_dataqueueid) result = %d:%s", a_ret, itron_strerror(a_ret));
151 goto lb_except;
152 }
153 return a_ret;
154lb_except:
155 _ecn_fbs_del(a_fbs_id);
156 return a_ret;
157}
158
159/*
160 * ECHONET UDP通信処理タスク
161 */
162void echonet_udp_task(intptr_t exinf)
163{
164 T_IN4_ADDR a_src;
165 ER a_ret, a_ret2;
166 ID tskid;
167 ECN_FBS_SSIZE_T a_snd_len;
168 union
169 {
170 T_MSG *p_msg;
171 ECN_FBS_ID fbs_id;
172 } a_mdt;
173 SYSTIM a_prev, a_now;
174 int a_timer;
175 T_IP_MREQ a_mreq;
176
177 get_tid(&tskid);
178 memcpy(&a_src, in4_get_ifaddr(0), sizeof(T_IN4_ADDR));
179 ECN_DBG_PUT_4("[UDP TSK:%d,%d] started, IP Address: %s ether_max_len: %u",
180 tskid, exinf,
181 ip2str(NULL, &a_src),
182 ETHER_MAX_LEN);
183 memcpy(enodadrb_table[ENOD_LOCAL_ID].ipaddr, &a_src, sizeof(T_IN4_ADDR));
184
185 a_mreq.imr_interface = IPV4_ADDRANY;
186 a_mreq.imr_multiaddr = MAKE_IPV4_ADDR(224, 0, 23, 0);
187
188 a_ret = udp_set_opt(ecn_udp_cepid, IP_ADD_MEMBERSHIP, (char *)&a_mreq, sizeof(a_mreq));
189 if (a_ret != E_OK) {
190 printf("setsockopt %d", a_ret);
191 return;
192 }
193
194 syscall(act_tsk(ecn_svc_taskid));
195
196 a_ret = get_tim(&a_now);
197 if (a_ret != E_OK) {
198 ECN_DBG_PUT_2("get_tim() result = %d:%s", a_ret, itron_strerror(a_ret));
199 return;
200 }
201
202 /* メッセージループ */
203 for (;;) {
204 a_prev = a_now;
205
206 a_timer = ECHONET_UDP_TASK_GET_TIMER;
207
208 a_ret = trcv_dtq(ecn_udp_dataqueueid, (intptr_t *)&a_mdt.p_msg, a_timer);
209 if ((a_ret != E_OK) && (a_ret != E_TMOUT)) {
210 ECN_DBG_PUT_2("trcv_dtq() result = %d:%s", a_ret, itron_strerror(a_ret));
211 break;
212 }
213
214 a_ret2 = get_tim(&a_now);
215 if (a_ret2 != E_OK) {
216 ECN_DBG_PUT_2("get_tim() result = %d:%s", a_ret2, itron_strerror(a_ret2));
217 break;
218 }
219
220 a_timer = a_now - a_prev;
221 ECHONET_UDP_TASK_PROGRESS(a_timer);
222
223 if (a_ret == E_OK) {
224 /* 送信データ長を取得 */
225 a_snd_len = _ecn_fbs_get_datalen(a_mdt.fbs_id);
226
227 ECN_DBG_PUT_1("[UDP TSK] trcv_dtq() dtq recv (%d byte)", _ecn_fbs_get_datalen(a_mdt.fbs_id));
228
229 if (0 < a_snd_len) {
230 switch(a_mdt.fbs_id.ptr->hdr.type){
231 case ECN_MSG_INTERNAL:
232 _ecn_int_msg(a_mdt.fbs_id, a_snd_len);
233 break;
234 case ECN_MSG_ECHONET:
235 _ecn_esv_msg(a_mdt.fbs_id);
236 break;
237 }
238 }
239
240 _ecn_fbs_del(a_mdt.fbs_id);
241 }
242
243 ECHONET_UDP_TASK_TIMEOUT;
244 }
245}
246
247/* 応答電文用fbs設定(sender/targetの設定) */
248static ER _ecn_udp_cre_req_fbs(ID sender, uint8_t cmd, ECN_FBS_ID *pk_req)
249{
250 ER ret;
251 ECN_FBS_ID req;
252
253 ret = _ecn_fbs_cre(1, &req);
254 if (ret != E_OK) {
255 ECN_DBG_PUT_2("_ecn_udp_cre_req_fbs() : _ecn_fbs_cre() result = %d:%s", ret, itron_strerror(ret));
256 return ret;
257 }
258
259 ret = _ecn_fbs_add_data(req, &cmd, sizeof(cmd));
260 if (ret != E_OK) {
261 _ecn_fbs_del(req);
262 ECN_DBG_PUT_2("_ecn_udp_cre_req_fbs() : _ecn_fbs_add_data() result = %d:%s", ret, itron_strerror(ret));
263 return ret;
264 }
265
266 req.ptr->hdr.type = ECN_MSG_INTERNAL;
267 req.ptr->hdr.sender.dtqid = sender;
268 req.ptr->hdr.target.dtqid = ecn_udp_dataqueueid;
269 req.ptr->hdr.reply.dtqid = sender;
270
271 *pk_req = req;
272
273 return E_OK;
274}
275
276/* 応答電文用fbs設定(sender/targetの設定) */
277static ER _ecn_udp_cre_res_fbs(ECN_FBS_ID req, uint8_t cmd, ECN_FBS_ID *pk_res)
278{
279 ER ret;
280 ECN_FBS_ID res;
281
282 ret = _ecn_fbs_cre(1, &res);
283 if (ret != E_OK) {
284 ECN_DBG_PUT_2("_ecn_udp_cre_res_fbs() : _ecn_fbs_cre() result = %d:%s", ret, itron_strerror(ret));
285 return ret;
286 }
287
288 ret = _ecn_fbs_add_data(res, &cmd, sizeof(cmd));
289 if (ret != E_OK) {
290 _ecn_fbs_del(res);
291 ECN_DBG_PUT_2("_ecn_udp_cre_res_fbs() : _ecn_fbs_add_data() result = %d:%s", ret, itron_strerror(ret));
292 return ret;
293 }
294
295 res.ptr->hdr.type = ECN_MSG_INTERNAL;
296 res.ptr->hdr.sender.dtqid = ecn_udp_dataqueueid;
297 res.ptr->hdr.target.dtqid = req.ptr->hdr.reply.dtqid;
298 res.ptr->hdr.reply.dtqid = ecn_udp_dataqueueid;
299
300 *pk_res = res;
301
302 return E_OK;
303}
304
305/*
306 * 内部メッセージ受信処理
307 */
308void _ecn_int_msg(ECN_FBS_ID fbs_id, ECN_FBS_SSIZE_T a_snd_len)
309{
310 ER result = E_OK, a_ret;
311 ecn_udp_msg_get_ipaddr_req_t msg;
312 ecn_udp_msg_get_ipaddr_error_t err;
313 ECN_FBS_SSIZE_T len;
314 ECN_FBS_ID buf;
315 uint8_t cmd;
316
317 a_ret = _ecn_fbs_get_data(fbs_id, &cmd, 1, &len);
318 if (a_ret != E_OK) {
319 ECN_DBG_PUT_2("[UDP TSK] _ecn_fbs_get_data() result = %d:%s", a_ret, itron_strerror(a_ret));
320 return;
321 }
322
323 switch(cmd){
324 // IPアドレスを返信
325 case ECN_UDP_MSG_GET_IPADDR_REQ:
326 if (a_snd_len < sizeof(msg)) {
327 result = E_PAR;
328 break;
329 }
330
331 a_snd_len = 0;
332 a_ret = _ecn_fbs_get_data(fbs_id, &msg, sizeof(msg), &a_snd_len);
333 if (a_ret != E_OK) {
334 ECN_DBG_PUT_2("[UDP TSK] _ecn_fbs_get_data() result = %d:%s", a_ret, itron_strerror(a_ret));
335 }
336
337 if ((msg.enodid < 0) && (msg.enodid >= tnum_enodadr)) {
338 result = E_PAR;
339 break;
340 }
341
342 a_ret = _ecn_udp_cre_res_fbs(fbs_id, ECN_UDP_MSG_GET_IPADDR_RES, &buf);
343 if (a_ret != E_OK) {
344 return;
345 }
346
347 a_ret = _ecn_fbs_add_data_ex(buf, &msg.requestid, offsetof(ecn_udp_msg_get_ipaddr_res_t, enodadrb));
348 if (a_ret != E_OK) {
349 _ecn_fbs_del(buf);
350 ECN_DBG_PUT_2("_ecn_int_msg() : _ecn_fbs_add_data_ex() result = %d:%s", a_ret, itron_strerror(a_ret));
351 return;
352 }
353
354 a_ret = _ecn_fbs_add_data_ex(buf, &enodadrb_table[msg.enodid], sizeof(enodadrb_table[msg.enodid]));
355 if (a_ret != E_OK) {
356 _ecn_fbs_del(buf);
357 ECN_DBG_PUT_2("_ecn_int_msg() : _ecn_fbs_add_data_ex() result = %d:%s", a_ret, itron_strerror(a_ret));
358 return;
359 }
360
361 a_ret = psnd_dtq(buf.ptr->hdr.target.dtqid, (intptr_t)buf.ptr);
362 if (a_ret != E_OK) {
363 _ecn_fbs_del(buf);
364 ECN_DBG_PUT_2("_ecn_int_msg() : psnd_dtq() result = %d:%s", a_ret, itron_strerror(a_ret));
365 return;
366 }
367 return;
368 }
369
370 a_ret = _ecn_udp_cre_res_fbs(fbs_id, ECN_UDP_MSG_GET_IPADDR_ERROR, &buf);
371 if (a_ret != E_OK) {
372 return;
373 }
374
375 err.requestid = msg.requestid;
376 err.error = result;
377 a_ret = _ecn_fbs_add_data_ex(buf, &err, sizeof(err));
378 if (a_ret != E_OK) {
379 _ecn_fbs_del(buf);
380 ECN_DBG_PUT_2("_ecn_int_msg() : _ecn_fbs_add_data_ex() result = %d:%s", a_ret, itron_strerror(a_ret));
381 return;
382 }
383
384 a_ret = psnd_dtq(buf.ptr->hdr.target.dtqid, (intptr_t)buf.ptr);
385 if (a_ret != E_OK) {
386 _ecn_fbs_del(buf);
387 ECN_DBG_PUT_2("_ecn_int_msg() : psnd_dtq() result = %d:%s", a_ret, itron_strerror(a_ret));
388 return;
389 }
390}
391
392/*
393 * ECHONET 電文受信処理
394 */
395void _ecn_esv_msg(ECN_FBS_ID fbs_id)
396{
397 /* UDP出力領域(暫定) */
398 static uint_t buffer[(ETHER_MAX_LEN) / sizeof(uint_t) + 1];
399 T_IPV4EP a_dst;
400 ER a_ret;
401 ECN_FBS_SSIZE_T a_snd_len;
402
403 a_dst.ipaddr = 0;
404 a_dst.portno = 0;
405 /* 送信先IPアドレス */
406 a_ret = udp_get_ip(&a_dst, fbs_id.ptr->hdr.target.id);
407 if (!a_ret) {
408 ECN_DBG_PUT_4("[UDP TSK] echonet-node 0x%02X-0x%02X-0x%02X → udp dest(%s)",
409 ((T_EDATA *)fbs_id.ptr)->hdr.edata.deoj.eojx1,
410 ((T_EDATA *)fbs_id.ptr)->hdr.edata.deoj.eojx2,
411 ((T_EDATA *)fbs_id.ptr)->hdr.edata.deoj.eojx3,
412 ip2str(NULL, &a_dst.ipaddr));
413
414 /* fbsから出力領域にデータを抽出 */
415 a_snd_len = 0;
416 a_ret = _ecn_fbs_get_data(fbs_id, buffer, sizeof(buffer), &a_snd_len);
417 if (a_ret != E_OK) {
418 ECN_DBG_PUT_2("[UDP TSK] _ecn_fbs_get_data() result = %d:%s", a_ret, itron_strerror(a_ret));
419 }
420 else if (a_dst.ipaddr == MAKE_IPV4_ADDR(127,0,0,1)) {
421 /* 送信先が127.0.0.1 → dtqに転送 */
422 ECN_DBG_PUT_1("redirect ecn_udp_dataqueueid → ecn_svc_dataqueueid (esv:0x%02X)",
423 ((T_EDATA *)fbs_id.ptr)->hdr.edata.esv);
424
425 a_ret = _ecn_udp2dtq((const uint8_t *)buffer, a_snd_len, &a_dst);
426 if (a_ret != E_OK) {
427 syslog(LOG_WARNING, "_ecn_esv_msg() : _ecn_udp2dtq() result = %d:%s", a_ret, itron_strerror(a_ret));
428 }
429 }
430 else {
431 ECN_DBG_PUT_2("[UDP TSK] udp_snd_dat() to:%s %ubyte(s)",
432 ip2str(NULL, &a_dst.ipaddr), a_snd_len);
433#ifdef ECN_DBG_PUT_ENA
434 _ecn_dbg_bindmp((const uint8_t *)buffer, a_snd_len);
435#endif
436 /* UDP送信 */
437 a_ret = udp_snd_dat(ecn_udp_cepid, &a_dst, buffer, a_snd_len, TMO_FEVR);
438 if (a_ret < 0) {
439 ECN_DBG_PUT_1("[UDP TSK] send, error: %s", itron_strerror(a_ret));
440 }
441 }
442
443 /* データが長すぎて1パケットに収まらなかった場合 */
444 if (_ecn_fbs_exist_data(fbs_id)) {
445 ECN_DBG_PUT_1("[UDP TSK] send, data so long: %dbyte(s)", _ecn_fbs_get_datalen(fbs_id));
446 }
447 } else {
448 ECN_DBG_PUT_3("[UDP TSK] echonet-node 0x%02X-0x%02X-0x%02X not found.",
449 ((T_EDATA *)fbs_id.ptr)->hdr.edata.deoj.eojx1,
450 ((T_EDATA *)fbs_id.ptr)->hdr.edata.deoj.eojx2,
451 ((T_EDATA *)fbs_id.ptr)->hdr.edata.deoj.eojx3);
452 }
453}
454
455/*
456 * ノンブロッキングコールのコールバック関数
457 */
458ER callback_nblk_udp(ID cepid, FN fncd, void *p_parblk)
459{
460 ER error = E_OK;
461
462 static uint8_t buffer[(ETHER_MAX_LEN) / sizeof(uint_t) + 1];
463
464 T_IPV4EP dst;
465 int a_len;
466
467 switch (fncd) {
468 case TEV_UDP_RCV_DAT:
469 case TFN_UDP_RCV_DAT:
470 /* ECN_CAP_PUT("[UDP ECHO SRV] callback_nblk_udp() recv: %u", *(int *)p_parblk); */
471 memset(buffer, 0, sizeof(buffer));
472 if ((a_len = udp_rcv_dat(cepid, &dst, buffer, sizeof(buffer) - 1, 20 * 1000)) < 0) {
473 syslog(LOG_WARNING, "[UDP ECHO SRV] recv, error: %s", itron_strerror(a_len));
474 return a_len;
475 }
476#ifdef _MSC_VER
477 /* (開発用) ECHONET用パケット以外は読み捨てる */
478 if (buffer[0] != 0x10 || buffer[1] != 0x81) {
479 return E_OK;
480 }
481#endif
482 ECN_CAP_PUT_4("[UDP ECHO SRV] recv, addr: %s:%d, len: %d, msg: '%s'",
483 ip2str(NULL, &dst.ipaddr), dst.portno, a_len, buffer);
484 if ((int)sizeof(buffer) <= a_len)
485 a_len = (int)sizeof(buffer) - 1;
486 if (0 < a_len) {
487 ECHONET_UDP_SEND_TO_MBX;
488
489 _ecn_udp2dtq(buffer, a_len, &dst);
490 }
491
492 return E_OK;
493
494 case TFN_UDP_CRE_CEP:
495 case TFN_UDP_SND_DAT:
496 break;
497 default:
498 ECN_CAP_PUT_2("[UDP ECHO SRV] fncd:0x%04X(%s)", -fncd,
499 (fncd == TEV_UDP_RCV_DAT ? "TEV_UDP_RCV_DAT" :
500 (fncd == TFN_UDP_CRE_CEP ? "TFN_UDP_CRE_CEP" :
501 (fncd == TFN_UDP_RCV_DAT ? "TFN_UDP_RCV_DAT" :
502 (fncd == TFN_UDP_SND_DAT ? "TFN_UDP_SND_DAT" : "undef")))));
503
504 error = E_PAR;
505 break;
506 }
507 return error;
508}
509
510/*
511 * リモートECHONETノードの適合確認
512 */
513bool_t is_match(const EOBJCB *enodcb, T_EDATA *edata, const void *_ipaddr, uint16_t portno)
514{
515 /*T_IN4_ADDR *ipaddr = (T_IN4_ADDR *)_ipaddr;*/
516 ER ret;
517 T_ENUM_EPC enm;
518 uint8_t epc;
519 uint8_t pdc;
520 uint8_t p_edt[256];
521 int i, j, k;
522 int count;
523 const EOBJINIB *p_eobj;
524 bool_t match;
525
526 if (!edata)
527 return false;
528
529 /* ノードスタート時インスタンスリスト通知以外は除外 */
530 if ( edata->hdr.edata.esv != ESV_INF
531 || edata->hdr.edata.deoj.eojx1 != EOJ_X1_PROFILE
532 || edata->hdr.edata.deoj.eojx2 != EOJ_X2_NODE_PROFILE
533 || edata->hdr.edata.deoj.eojx3 != 0x01
534 || edata->hdr.edata.seoj.eojx1 != EOJ_X1_PROFILE
535 || edata->hdr.edata.seoj.eojx2 != EOJ_X2_NODE_PROFILE
536 || ( edata->hdr.edata.seoj.eojx3 != 0x01
537 && edata->hdr.edata.seoj.eojx3 != 0x02)) {
538 return false;
539 }
540
541 ret = ecn_itr_ini(&enm, edata);
542 if (ret) {
543 syslog(LOG_WARNING, "is_match(): ecn_itr_ini() result = %d:%s", ret, itron_strerror(ret));
544 return false;
545 }
546 while ((ret = ecn_itr_nxt(&enm, &epc, &pdc, p_edt)) == E_OK) {
547 if (enm.is_eof) {
548 break;
549 }
550 ECN_DBG_PUT_2("is_match(): ecn_itr_nxt() result: epc=0x%02X, pdc=%d", epc, pdc);
551 /* インスタンスリスト通知または自ノードインスタンスリストS以外は除外 */
552 if ((epc != 0xD5) && (epc != 0xD6)) {
553 continue;
554 }
555
556 /* 2バイト目以降にeojが列挙されている */
557 count = (pdc - 1) / sizeof(T_ECN_EOJ);
558
559 /* ノード内の機器オブジェクトを検索 */
560 for (k = 0; k < enodcb->eobjcnt; k++) {
561 p_eobj = enodcb->eobjs[k];
562
563 /* インスタンスリストを確認 */
564 match = false;
565 for (i = 0, j = 1; i < count; i++, j += sizeof(T_ECN_EOJ)) {
566 if (p_eobj->eojx1 != p_edt[j])
567 continue;
568 if (p_eobj->eojx2 != p_edt[j + 1])
569 continue;
570 if (p_eobj->eojx3 != p_edt[j + 2])
571 continue;
572
573 match = true;
574 break;
575 }
576
577 if (!match)
578 return false;
579 }
580
581 /* すべて揃っていたら適合(インスタンスリストの方が多くてもいいこととする) */
582 return true;
583 }
584
585 return false;
586}
587
588/*
589 * IPアドレスからリモートECHONETノードへ変換
590 */
591ECN_ENOD_ID udp_get_id(T_EDATA *edata, const T_IN4_ADDR ipaddr, uint16_t portno)
592{
593 T_ENOD_ADDR *ea;
594 int i;
595
596 if (ipaddr == MAKE_IPV4_ADDR(127,0,0,1))
597 return ENOD_LOCAL_ID;
598 if (ipaddr == MAKE_IPV4_ADDR(224,0,23,0))
599 return ENOD_MULTICAST_ID;
600
601 /* IPアドレスの同じものを検索 */
602 for (i = 0, ea = enodadrb_table; i < tnum_enodadr; i++, ea++) {
603 if (!ea->inuse)
604 continue;
605 if (*((T_IN4_ADDR *)ea->ipaddr) != ipaddr)
606 continue;
607
608 ECN_CAP_PUT_2("udp_get_id(): ip-found remote(%d) = %s",
609 i - ENOD_REMOTE_ID, ip2str(NULL, &ipaddr));
610 return (ECN_ENOD_ID)i;
611 }
612
613 /* 対応するリモートノードを検索 */
614 for (i = ENOD_REMOTE_ID, ea = &enodadrb_table[ENOD_REMOTE_ID]; i < tnum_enodadr; i++, ea++) {
615 if (!ea->inuse)
616 continue;
617 if ((i - ENOD_REMOTE_ID + 1) >= tnum_enodid)
618 break;
619 if (*((T_IN4_ADDR *)ea->ipaddr) != 0)
620 continue;
621 if (!ECHONET_NODE_MATCH(&eobjcb_table[i - ENOD_REMOTE_ID + 1], edata, &ipaddr, portno))
622 continue;
623
624 /* 対応するリモートノードがあればIPアドレスを設定 */
625 *((T_IN4_ADDR *)ea->ipaddr) = ipaddr;
626
627 ECN_CAP_PUT_2("udp_get_id(): enod-found remote(%d) = %s",
628 i - ENOD_REMOTE_ID, ip2str(NULL, &ipaddr));
629 return (ECN_ENOD_ID)i;
630 }
631
632 /* 空き領域を探して自動登録 */
633 for (i = ENOD_REMOTE_ID, ea = &enodadrb_table[ENOD_REMOTE_ID]; i < tnum_enodadr; i++, ea++) {
634 if (ea->inuse)
635 continue;
636
637 ea->inuse = true;
638 *((T_IN4_ADDR *)ea->ipaddr) = ipaddr;
639
640 ECN_CAP_PUT_2("udp_get_id(): empty-found remote(%d) = %s",
641 i - ENOD_REMOTE_ID, ip2str(NULL, &ipaddr));
642 return (ECN_ENOD_ID)i;
643 }
644
645 return ENOD_NOT_MATCH_ID;
646}
647
648/*
649 * リモートECHONETノードからIPアドレスへ変換
650 */
651int udp_get_ip(T_IPV4EP *fp_ipep, ECN_ENOD_ID fa_enodid)
652{
653 T_ENOD_ADDR *ea;
654
655 if (!fp_ipep)
656 return -1; /* NG */
657
658 fp_ipep->portno = 3610;
659
660 if (fa_enodid == ENOD_MULTICAST_ID) {
661 /* targetがENOD_MULTICAST_IDの場合、マルチキャストを行う */
662 fp_ipep->ipaddr = MAKE_IPV4_ADDR(224,0,23,0);
663 return 0; /* ok */
664 }
665
666 if (fa_enodid < ENOD_REMOTE_ID) {
667 /* targetが未定義・LOCAL・APIの場合、ローカル配送を行う */
668 fp_ipep->ipaddr = MAKE_IPV4_ADDR(127,0,0,1);
669 return 0; /* ok */
670 }
671
672 if (fa_enodid >= tnum_enodadr)
673 return -1; /* NG */
674
675 ea = &enodadrb_table[fa_enodid];
676 if (!ea->inuse)
677 return -1; /* NG */
678
679 if (*((T_IN4_ADDR *)ea->ipaddr) == 0)
680 return -1; /* NG */
681
682 fp_ipep->ipaddr = *((T_IN4_ADDR *)ea->ipaddr);
683 return 0; /* ok */
684}
685
686ER ecn_udp_get_ipaddr(ID sender, int requestid, ECN_ENOD_ID enodid, ECN_FBS_ID *pk_req)
687{
688 ER a_ret;
689 ECN_FBS_ID req;
690
691 a_ret = _ecn_udp_cre_req_fbs(sender, ECN_UDP_MSG_GET_IPADDR_REQ, &req);
692 if (a_ret != E_OK) {
693 return a_ret;
694 }
695
696 a_ret = _ecn_fbs_add_data_ex(req, &requestid, sizeof(((ecn_udp_msg_get_ipaddr_res_t *)0)->requestid));
697 if (a_ret != E_OK) {
698 _ecn_fbs_del(req);
699 ECN_DBG_PUT_2("ecn_udp_get_ipaddr() : _ecn_fbs_add_data_ex() result = %d:%s", a_ret, itron_strerror(a_ret));
700 return a_ret;
701 }
702
703 a_ret = _ecn_fbs_add_data_ex(req, &enodid, sizeof(((ecn_udp_msg_get_ipaddr_res_t *)0)->enodid));
704 if (a_ret != E_OK) {
705 _ecn_fbs_del(req);
706 ECN_DBG_PUT_2("ecn_udp_get_ipaddr() : _ecn_fbs_add_data_ex() result = %d:%s", a_ret, itron_strerror(a_ret));
707 return a_ret;
708 }
709
710 a_ret = _ecn_fbs_add_data_ex(req, &enodadrb_table[enodid], sizeof(((ecn_udp_msg_get_ipaddr_res_t *)0)->enodadrb));
711 if (a_ret != E_OK) {
712 _ecn_fbs_del(req);
713 ECN_DBG_PUT_2("ecn_udp_get_ipaddr() : _ecn_fbs_add_data_ex() result = %d:%s", a_ret, itron_strerror(a_ret));
714 return a_ret;
715 }
716
717 *pk_req = req;
718
719 return E_OK;
720}
721
722char *ipaddr2str(char *buf, int bubsz, uint8_t *ipaddr)
723{
724 return ip2str(buf, (T_IN4_ADDR *)ipaddr);
725}
726
727#endif
Note: See TracBrowser for help on using the repository browser.