source: UsbWattMeter/trunk/ecnl_lwip/echonet_udp_task.c@ 473

Last change on this file since 473 was 167, checked in by coas-nagasima, 8 years ago

MIMEにSJISを設定

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
  • Property svn:mime-type set to text/x-csrc; charset=SHIFT_JIS
File size: 20.8 KB
RevLine 
[164]1/*
2 * TOPPERS ECHONET Lite Communication Middleware
3 *
4 * Copyright (C) 2014-2016 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: echonet_udp_task.c 167 2016-03-08 11:37:45Z coas-nagasima $
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#ifdef _MSC_VER
56#pragma warning(disable : 4005)
57#endif
58#include <lwip/udp.h>
59#include <lwip/igmp.h>
60#ifdef _MSC_VER
61#pragma warning(default : 4005)
62#endif
63
64#include "echonet_task.h"
65#include "echonet_lcl_task.h"
66#include "echonet_dbg.h"
67
68#ifndef ECHONET_UDP_TASK_GET_TIMER
69#define ECHONET_UDP_TASK_GET_TIMER TMO_FEVR
70#endif /* ECHONET_UDP_TASK_GET_TIMER */
71
72#ifndef ECHONET_UDP_TASK_PROGRESS
73#define ECHONET_UDP_TASK_PROGRESS(timer)
74#endif /* ECHONET_UDP_TASK_PROGRESS */
75
76#ifndef ECHONET_UDP_TASK_TIMEOUT
77#define ECHONET_UDP_TASK_TIMEOUT
78#endif /* ECHONET_UDP_TASK_TIMEOUT */
79
80#ifndef ECHONET_UDP_SEND_TO_MBX
81#define ECHONET_UDP_SEND_TO_MBX
82#endif /* ECHONET_UDP_SEND_TO_MBX */
83
84#ifndef ECHONET_NODE_MATCH
85#define ECHONET_NODE_MATCH(enodcb, edata, ipaddr, portno) is_match(enodcb, edata, ipaddr, portno)
86#endif /* ECHONET_NODE_MATCH */
87
88static ip_addr_t localhost;
89static ip_addr_t multicast;
90static ip_addr_t zeroaddr;
91struct udp_pcb *UDP_CEPID;
92
93typedef struct ipv4ep_t {
94 ip_addr_t ipaddr;
95 uint16_t portno;
96} T_IPV4EP;
97
98static ECN_ENOD_ID udp_get_id(T_EDATA *edata, const ip_addr_t *ipaddr, uint16_t portno);
99static int udp_get_ip(T_IPV4EP *fp_ipep, ECN_ENOD_ID fa_enodid);
100void _ecn_int_msg(ECN_FBS_ID fbs_id, ECN_FBS_SSIZE_T a_snd_len);
101void _ecn_esv_msg(ECN_FBS_ID fbs_id);
102static void callback_nblk_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port);
103
104/*
105 * 受信したUDPデータをMAILBOXに送る
106 */
107ER _ecn_udp2mbx(ECN_FBS_ID fbs_id, const T_IPV4EP *dst);
108ER _ecn_udp2mbx(ECN_FBS_ID fbs_id, const T_IPV4EP *dst)
109{
110 ER a_ret = E_OK;
111 ECN_ENOD_ID a_enod_id;
112 const T_ECN_EDT_HDR *t_esv;
113
114 t_esv = (const T_ECN_EDT_HDR *)fbs_id.ptr->payload;
115 if (t_esv->ecn_hdr.ehd1 != ECN_EDH1_ECHONET_LITE /* ECHONET Lite規格 */
116 || t_esv->ecn_hdr.ehd2 != ECN_EDH2_FORMAT_1 /* 電文形式1 */) {
117 ECN_DBG_PUT("[UDP ECHO SRV] illegal type (0x%02X,0x%02X)", t_esv->ecn_hdr.ehd1, t_esv->ecn_hdr.ehd2);
118 return E_PAR;
119 }
120
121#ifdef ECN_DBG_PUT_ENA
122 _ecn_dbg_bindmp(fbs_id.ptr, fbs_id.ptr->hdr.length);
123#endif
124
125 fbs_id.ptr->hdr.type = ECN_MSG_ECHONET;
126 fbs_id.ptr->hdr.target.id = ENOD_LOCAL_ID;
127 fbs_id.ptr->hdr.sender.id = ENOD_NOT_MATCH_ID;
128
129 /* IPアドレスからリモートECHONETノードへ変換 */
130 a_enod_id = udp_get_id((T_EDATA *)fbs_id.ptr, &dst->ipaddr, dst->portno);
131 if (a_enod_id < 0 || tnum_enodadr <= a_enod_id) {
132 ECN_DBG_PUT("[UDP ECHO SRV] udp src(%s) echonet-node not found.",
133 ipaddr_ntoa(&dst->ipaddr));
134 }
135 else {
136 /* 送信元ECHONETノードを記録 */
137 fbs_id.ptr->hdr.sender.id = a_enod_id;
138 }
139 fbs_id.ptr->hdr.reply.id = fbs_id.ptr->hdr.sender.id;
140
141 /* echonet_taskに送る */
142 a_ret = snd_mbx(ecn_svc_mailboxid, (T_MSG *)fbs_id.ptr);
143 if (a_ret != E_OK) {
144 ECN_DBG_PUT("[UDP ECHO SRV] snd_mbx(ecn_svc_mailboxid) result = %d:%s", a_ret, itron_strerror(a_ret));
145 goto lb_except;
146 }
147 return a_ret;
148lb_except:
149 _ecn_fbs_del(fbs_id);
150 return a_ret;
151}
152
153/*
154 * ECHONET UDP通信処理タスク
155 */
156void echonet_udp_task(intptr_t exinf)
157{
158 ip_addr_t a_src;
159 ER a_ret, a_ret2;
160 ID tskid;
161 ECN_FBS_SSIZE_T a_snd_len;
162 union {
163 T_MSG *p_msg;
164 ECN_FBS_ID fbs_id;
165 } a_mdt;
166 SYSTIM a_prev, a_now;
167 TMO a_timer;
168 err_t err;
169
170 IP4_ADDR(&localhost, 127, 0, 0, 1);
171 IP4_ADDR(&multicast, 224, 0, 23, 0);
172 IP4_ADDR(&zeroaddr, 0, 0, 0, 0);
173
174 get_tid(&tskid);
175 memcpy(&a_src, &netif_default->ip_addr, sizeof(ip_addr_t));
176 ECN_DBG_PUT("[UDP TSK:%d,%d] started, IP Address: %s",
177 tskid, exinf,
178 ipaddr_ntoa(&a_src));
179 memcpy(enodadrb_table[ENOD_LOCAL_ID].ipaddr, &a_src, sizeof(ip_addr_t));
180
181 UDP_CEPID = udp_new();
182 if (UDP_CEPID == NULL) {
183 ECN_DBG_PUT("udp_new()");
184 return;
185 }
186
187 err = udp_bind(UDP_CEPID, &a_src, 3610);
188 if (err != ERR_OK) {
189 ECN_DBG_PUT("udp_bind()");
190 return;
191 }
192
193 udp_recv(UDP_CEPID, callback_nblk_udp, NULL);
194
195 err = igmp_joingroup(&a_src, &multicast);
196 if (err != ERR_OK) {
197 ECN_DBG_PUT("igmp_joingroup()");
198 return;
199 }
200
201 a_ret = act_tsk(ecn_svc_taskid);
202 if (a_ret != E_OK) {
203 ECN_DBG_PUT("act_tsk(%d) result = %d:%s", ecn_svc_taskid, a_ret, itron_strerror(a_ret));
204 return;
205 }
206
207 a_ret = get_tim(&a_now);
208 if (a_ret != E_OK) {
209 ECN_DBG_PUT("get_tim() result = %d:%s", a_ret, itron_strerror(a_ret));
210 return;
211 }
212
213 /* メッセージループ */
214 for (;;) {
215 a_prev = a_now;
216
217 a_timer = ECHONET_UDP_TASK_GET_TIMER;
218
219 a_ret = trcv_mbx(ecn_udp_mailboxid, &a_mdt.p_msg, a_timer);
220 if ((a_ret != E_OK) && (a_ret != E_TMOUT)) {
221 ECN_DBG_PUT("trcv_mbx() result = %d:%s", a_ret, itron_strerror(a_ret));
222 break;
223 }
224
225 a_ret2 = get_tim(&a_now);
226 if (a_ret2 != E_OK) {
227 ECN_DBG_PUT("get_tim() result = %d:%s", a_ret2, itron_strerror(a_ret2));
228 break;
229 }
230
231 a_timer = a_now - a_prev;
232 ECHONET_UDP_TASK_PROGRESS(a_timer);
233
234 if (a_ret == E_OK) {
235 /* 送信データ長を取得 */
236 a_snd_len = _ecn_fbs_get_datalen(a_mdt.fbs_id);
237
238 ECN_DBG_PUT("[UDP TSK] trcv_mbx() mbx recv (%d byte)", _ecn_fbs_get_datalen(a_mdt.fbs_id));
239
240 if (0 < a_snd_len) {
241 switch (a_mdt.fbs_id.ptr->hdr.type) {
242 case ECN_MSG_INTERNAL:
243 _ecn_int_msg(a_mdt.fbs_id, a_snd_len);
244 break;
245 case ECN_MSG_ECHONET:
246 _ecn_esv_msg(a_mdt.fbs_id);
247 break;
248 }
249 }
250
251 _ecn_fbs_del(a_mdt.fbs_id);
252 }
253
254 ECHONET_UDP_TASK_TIMEOUT;
255 }
256}
257
258/* 応答電文用fbs設定(sender/targetの設定) */
259static ER _ecn_udp_cre_req_fbs(ID sender, uint8_t cmd, ECN_FBS_ID *pk_req)
260{
261 ER ret;
262 ECN_FBS_ID req;
263
264 ret = _ecn_fbs_cre(1, &req);
265 if (ret != E_OK) {
266 ECN_DBG_PUT("_ecn_udp_cre_req_fbs() : _ecn_fbs_cre() result = %d:%s", ret, itron_strerror(ret));
267 return ret;
268 }
269
270 ret = _ecn_fbs_add_data(req, &cmd, sizeof(cmd));
271 if (ret != E_OK) {
272 _ecn_fbs_del(req);
273 ECN_DBG_PUT("_ecn_udp_cre_req_fbs() : _ecn_fbs_add_data() result = %d:%s", ret, itron_strerror(ret));
274 return ret;
275 }
276
277 req.ptr->hdr.type = ECN_MSG_INTERNAL;
278 req.ptr->hdr.sender.mbxid = sender;
279 req.ptr->hdr.target.mbxid = ecn_udp_mailboxid;
280 req.ptr->hdr.reply.mbxid = sender;
281
282 *pk_req = req;
283
284 return E_OK;
285}
286
287/* 応答電文用fbs設定(sender/targetの設定) */
288static ER _ecn_udp_cre_res_fbs(ECN_FBS_ID req, uint8_t cmd, ECN_FBS_ID *pk_res)
289{
290 ER ret;
291 ECN_FBS_ID res;
292
293 ret = _ecn_fbs_cre(1, &res);
294 if (ret != E_OK) {
295 ECN_DBG_PUT("_ecn_udp_cre_res_fbs() : _ecn_fbs_cre() result = %d:%s", ret, itron_strerror(ret));
296 return ret;
297 }
298
299 ret = _ecn_fbs_add_data(res, &cmd, sizeof(cmd));
300 if (ret != E_OK) {
301 _ecn_fbs_del(res);
302 ECN_DBG_PUT("_ecn_udp_cre_res_fbs() : _ecn_fbs_add_data() result = %d:%s", ret, itron_strerror(ret));
303 return ret;
304 }
305
306 res.ptr->hdr.type = ECN_MSG_INTERNAL;
307 res.ptr->hdr.sender.mbxid = ecn_udp_mailboxid;
308 res.ptr->hdr.target.mbxid = req.ptr->hdr.reply.mbxid;
309 res.ptr->hdr.reply.mbxid = ecn_udp_mailboxid;
310
311 *pk_res = res;
312
313 return E_OK;
314}
315
316/*
317 * 内部メッセージ受信処理
318 */
319void _ecn_int_msg(ECN_FBS_ID fbs_id, ECN_FBS_SSIZE_T a_snd_len)
320{
321 ER result = E_OK, a_ret;
322 ecn_udp_msg_get_ipaddr_req_t msg;
323 ecn_udp_msg_get_ipaddr_error_t err;
324 ECN_FBS_SSIZE_T len;
325 ECN_FBS_ID buf;
326 uint8_t cmd;
327 unsigned int requestid = 0;
328
329 a_ret = _ecn_fbs_get_data(fbs_id, &cmd, 1, &len);
330 if (a_ret != E_OK) {
331 ECN_DBG_PUT("[UDP TSK] _ecn_fbs_get_data() result = %d:%s", a_ret, itron_strerror(a_ret));
332 return;
333 }
334
335 switch (cmd) {
336 // IPアドレスを返信
337 case ECN_UDP_MSG_GET_IPADDR_REQ:
338 if (a_snd_len < sizeof(msg)) {
339 result = E_PAR;
340 break;
341 }
342
343 a_snd_len = 0;
344 a_ret = _ecn_fbs_get_data(fbs_id, &msg, sizeof(msg), &a_snd_len);
345 if (a_ret != E_OK) {
346 ECN_DBG_PUT("[UDP TSK] _ecn_fbs_get_data() result = %d:%s", a_ret, itron_strerror(a_ret));
347 }
348 requestid = msg.requestid;
349
350 if ((msg.enodid < 0) && (msg.enodid >= tnum_enodadr)) {
351 result = E_PAR;
352 break;
353 }
354
355 a_ret = _ecn_udp_cre_res_fbs(fbs_id, ECN_UDP_MSG_GET_IPADDR_RES, &buf);
356 if (a_ret != E_OK) {
357 return;
358 }
359
360 a_ret = _ecn_fbs_add_data_ex(buf, &msg.requestid, offsetof(ecn_udp_msg_get_ipaddr_res_t, enodadrb));
361 if (a_ret != E_OK) {
362 _ecn_fbs_del(buf);
363 ECN_DBG_PUT("_ecn_int_msg() : _ecn_fbs_add_data_ex() result = %d:%s", a_ret, itron_strerror(a_ret));
364 return;
365 }
366
367 a_ret = _ecn_fbs_add_data_ex(buf, &enodadrb_table[msg.enodid], sizeof(enodadrb_table[msg.enodid]));
368 if (a_ret != E_OK) {
369 _ecn_fbs_del(buf);
370 ECN_DBG_PUT("_ecn_int_msg() : _ecn_fbs_add_data_ex() result = %d:%s", a_ret, itron_strerror(a_ret));
371 return;
372 }
373
374 a_ret = psnd_dtq(buf.ptr->hdr.target.mbxid, (intptr_t)buf.ptr);
375 if (a_ret != E_OK) {
376 _ecn_fbs_del(buf);
377 ECN_DBG_PUT("_ecn_int_msg() : psnd_dtq() result = %d:%s", a_ret, itron_strerror(a_ret));
378 return;
379 }
380 return;
381 default:
382 a_ret = _ecn_fbs_get_data(fbs_id, &requestid, sizeof(requestid), &len);
383 if (a_ret != E_OK) {
384 ECN_DBG_PUT("[UDP TSK] _ecn_fbs_get_data() result = %d:%s", a_ret, itron_strerror(a_ret));
385 return;
386 }
387 break;
388 }
389
390 if (requestid == 0)
391 return;
392
393 a_ret = _ecn_udp_cre_res_fbs(fbs_id, ECN_UDP_MSG_GET_IPADDR_ERROR, &buf);
394 if (a_ret != E_OK) {
395 return;
396 }
397
398 err.requestid = requestid;
399 err.error = result;
400 a_ret = _ecn_fbs_add_data_ex(buf, &err, sizeof(err));
401 if (a_ret != E_OK) {
402 _ecn_fbs_del(buf);
403 ECN_DBG_PUT("_ecn_int_msg() : _ecn_fbs_add_data_ex() result = %d:%s", a_ret, itron_strerror(a_ret));
404 return;
405 }
406
407 a_ret = psnd_dtq(buf.ptr->hdr.target.mbxid, (intptr_t)buf.ptr);
408 if (a_ret != E_OK) {
409 _ecn_fbs_del(buf);
410 ECN_DBG_PUT("_ecn_int_msg() : psnd_dtq() result = %d:%s", a_ret, itron_strerror(a_ret));
411 return;
412 }
413}
414
415/*
416 * ECHONET 電文受信処理
417 */
418void _ecn_esv_msg(ECN_FBS_ID fbs_id)
419{
420 struct pbuf *p, *q;
421 T_IPV4EP a_dst;
422 ER a_ret;
423 ECN_FBS_SSIZE_T a_snd_len = fbs_id.ptr->hdr.length;
424
425 IP4_ADDR(&a_dst.ipaddr, 0, 0, 0, 0);
426 a_dst.portno = 0;
427 /* 送信先IPアドレス */
428 a_ret = udp_get_ip(&a_dst, fbs_id.ptr->hdr.target.id);
429 if (!a_ret) {
430 ECN_DBG_PUT("[UDP TSK] echonet-node 0x%02X-0x%02X-0x%02X → udp dest(%s)",
431 ((T_EDATA *)fbs_id.ptr)->hdr.edata.deoj.eojx1,
432 ((T_EDATA *)fbs_id.ptr)->hdr.edata.deoj.eojx2,
433 ((T_EDATA *)fbs_id.ptr)->hdr.edata.deoj.eojx3,
434 ipaddr_ntoa(&a_dst.ipaddr));
435
436 if (ip_addr_cmp(&a_dst.ipaddr, &localhost)) {
437 /* 送信先が127.0.0.1 → mbxに転送 */
438 ECN_DBG_PUT("redirect ecn_udp_mailboxid → ecn_svc_mailboxid (esv:0x%02X)",
439 ((T_EDATA *)fbs_id.ptr)->hdr.edata.esv);
440
441 a_ret = _ecn_udp2mbx(fbs_id, &a_dst);
442 if (a_ret != E_OK) {
443 syslog(LOG_WARNING, "_ecn_esv_msg() : _ecn_udp2mbx() result = %d:%s", a_ret, itron_strerror(a_ret));
444 }
445 }
446 else {
447 ECN_DBG_PUT("[UDP TSK] udp_snd_dat() to:%s %ubyte(s)",
448 ipaddr_ntoa(&a_dst.ipaddr), a_snd_len);
449#ifdef ECN_DBG_PUT_ENA
450 _ecn_dbg_bindmp(fbs_id.ptr, a_snd_len);
451#endif
452 p = pbuf_alloc(PBUF_TRANSPORT, _ecn_fbs_get_datalen(fbs_id), PBUF_POOL);
453 if (p == NULL) {
454 ECN_DBG_PUT("[UDP TSK] pbuf_alloc()");
455 return;
456 }
457
458 /* fbsから出力領域にデータを抽出 */
459 a_snd_len = 0;
460 for (q = p; q != NULL; q = q->next) {
461 ECN_FBS_SSIZE_T a_len;
462 a_ret = _ecn_fbs_get_data(fbs_id, q->payload, q->len, &a_len);
463 if (a_ret != E_OK) {
464 ECN_DBG_PUT("[UDP TSK] _ecn_fbs_get_data() result = %d:%s", a_ret, itron_strerror(a_ret));
465 pbuf_free(p);
466 return;
467 }
468 a_snd_len += a_len;
469 }
470
471 /* UDP送信 */
472 a_ret = udp_sendto(UDP_CEPID, p, &a_dst.ipaddr, 3610);
473 if (a_ret < 0) {
474 ECN_DBG_PUT("[UDP TSK] send, error: %s", itron_strerror(a_ret));
475 }
476 pbuf_free(p);
477 }
478
479 /* データが長すぎて1パケットに収まらなかった場合 */
480 if (_ecn_fbs_exist_data(fbs_id)) {
481 ECN_DBG_PUT("[UDP TSK] send, data so long: %dbyte(s)", _ecn_fbs_get_datalen(fbs_id));
482 }
483 }
484 else {
485 ECN_DBG_PUT("[UDP TSK] echonet-node 0x%02X-0x%02X-0x%02X not found.",
486 ((T_EDATA *)fbs_id.ptr)->hdr.edata.deoj.eojx1,
487 ((T_EDATA *)fbs_id.ptr)->hdr.edata.deoj.eojx2,
488 ((T_EDATA *)fbs_id.ptr)->hdr.edata.deoj.eojx3);
489 }
490}
491
492/*
493 * ノンブロッキングコールのコールバック関数
494 */
495static void
496callback_nblk_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
497{
498 ECN_FBS_ID a_fbs_id = {0};
499 ER a_ret = E_OK;
500 ECN_ENOD_ID a_enod_id;
501 const T_ECN_EDT_HDR *t_esv;
502 struct pbuf *q;
503
504 a_ret = _ecn_fbs_cre(p->tot_len, &a_fbs_id);
505 if (a_ret != E_OK) {
506 ECN_DBG_PUT("[UDP ECHO SRV] _ecn_fbs_cre() result = %d:%s", a_ret, itron_strerror(a_ret));
507 pbuf_free(p);
508 return;
509 }
510
511 for (q = p; q != NULL; q = q->next) {
512 a_ret = _ecn_fbs_add_data_ex(a_fbs_id, q->payload, q->len);
513 if (a_ret) {
514 ECN_DBG_PUT("[UDP ECHO SRV] _ecn_fbs_add_data_ex() result = %d:%s", a_ret, itron_strerror(a_ret));
515 pbuf_free(p);
516 goto lb_except;
517 }
518 }
519
520 pbuf_free(p);
521
522 t_esv = (const T_ECN_EDT_HDR *)a_fbs_id.ptr->payload;
523 if (t_esv->ecn_hdr.ehd1 != ECN_EDH1_ECHONET_LITE /* ECHONET Lite規格 */
524 || t_esv->ecn_hdr.ehd2 != ECN_EDH2_FORMAT_1 /* 電文形式1 */) {
525 ECN_DBG_PUT("[UDP ECHO SRV] illegal type (0x%02X,0x%02X)", t_esv->ecn_hdr.ehd1, t_esv->ecn_hdr.ehd2);
526 goto lb_except;
527 }
528
529#ifdef ECN_DBG_PUT_ENA
530 _ecn_dbg_bindmp(a_fbs_id.ptr, a_fbs_id.ptr->hdr.length);
531#endif
532
533 a_fbs_id.ptr->hdr.type = ECN_MSG_ECHONET;
534 a_fbs_id.ptr->hdr.target.id = ENOD_LOCAL_ID;
535 a_fbs_id.ptr->hdr.sender.id = ENOD_NOT_MATCH_ID;
536
537 /* IPアドレスからリモートECHONETノードへ変換 */
538 a_enod_id = udp_get_id((T_EDATA *)a_fbs_id.ptr, addr, port);
539 if (a_enod_id < 0 || tnum_enodadr <= a_enod_id) {
540 ECN_DBG_PUT("[UDP ECHO SRV] udp src(%s) echonet-node not found.",
541 ipaddr_ntoa(addr));
542 }
543 else {
544 /* 送信元ECHONETノードを記録 */
545 a_fbs_id.ptr->hdr.sender.id = a_enod_id;
546 }
547 a_fbs_id.ptr->hdr.reply.id = a_fbs_id.ptr->hdr.sender.id;
548
549 /* echonet_taskに送る */
550 a_ret = snd_mbx(ecn_svc_mailboxid, (T_MSG *)a_fbs_id.ptr);
551 if (a_ret != E_OK) {
552 ECN_DBG_PUT("[UDP ECHO SRV] snd_mbx(ecn_svc_mailboxid) result = %d:%s", a_ret, itron_strerror(a_ret));
553 goto lb_except;
554 }
555 return;
556lb_except:
557 _ecn_fbs_del(a_fbs_id);
558 return;
559}
560
561/*
562 * リモートECHONETノードの適合確認
563 */
564bool_t is_match(const EOBJCB *enodcb, T_EDATA *edata, const void *_ipaddr, uint16_t portno)
565{
566 /*ip_addr_t *ipaddr = (ip_addr_t *)_ipaddr;*/
567 ER ret;
568 T_ENUM_EPC enm;
569 uint8_t epc;
570 uint8_t pdc;
571 uint8_t p_edt[256];
572 int i, j, k;
573 int count;
574 const EOBJINIB *p_eobj;
575 bool_t match;
576
577 if (!edata)
578 return false;
579
580 /* ノードスタート時インスタンスリスト通知以外は除外 */
581 if (edata->hdr.edata.esv != ESV_INF
582 || edata->hdr.edata.deoj.eojx1 != EOJ_X1_PROFILE
583 || edata->hdr.edata.deoj.eojx2 != EOJ_X2_NODE_PROFILE
584 || edata->hdr.edata.deoj.eojx3 != 0x01
585 || edata->hdr.edata.seoj.eojx1 != EOJ_X1_PROFILE
586 || edata->hdr.edata.seoj.eojx2 != EOJ_X2_NODE_PROFILE
587 || (edata->hdr.edata.seoj.eojx3 != 0x01
588 && edata->hdr.edata.seoj.eojx3 != 0x02)) {
589 return false;
590 }
591
592 ret = ecn_itr_ini(&enm, edata);
593 if (ret) {
594 syslog(LOG_WARNING, "is_match(): ecn_itr_ini() result = %d:%s", ret, itron_strerror(ret));
595 return false;
596 }
597 while ((ret = ecn_itr_nxt(&enm, &epc, &pdc, p_edt)) == E_OK) {
598 if (enm.is_eof) {
599 break;
600 }
601 ECN_DBG_PUT("is_match(): ecn_itr_nxt() result: epc=0x%02X, pdc=%d", epc, pdc);
602 /* インスタンスリスト通知または自ノードインスタンスリストS以外は除外 */
603 if ((epc != 0xD5) && (epc != 0xD6)) {
604 continue;
605 }
606
607 /* 2バイト目以降にeojが列挙されている */
608 count = (pdc - 1) / sizeof(T_ECN_EOJ);
609
610 /* ノード内の機器オブジェクトを検索 */
611 for (k = 0; k < enodcb->eobjcnt; k++) {
612 p_eobj = enodcb->eobjs[k];
613
614 /* インスタンスリストを確認 */
615 match = false;
616 for (i = 0, j = 1; i < count; i++, j += sizeof(T_ECN_EOJ)) {
617 if (p_eobj->eojx1 != p_edt[j])
618 continue;
619 if (p_eobj->eojx2 != p_edt[j + 1])
620 continue;
621 if (p_eobj->eojx3 != p_edt[j + 2])
622 continue;
623
624 match = true;
625 break;
626 }
627
628 if (!match)
629 return false;
630 }
631
632 /* すべて揃っていたら適合(インスタンスリストの方が多くてもいいこととする) */
633 return true;
634 }
635
636 return false;
637}
638
639/*
640 * IPアドレスからリモートECHONETノードへ変換
641 */
642ECN_ENOD_ID udp_get_id(T_EDATA *edata, const ip_addr_t *ipaddr, uint16_t portno)
643{
644 T_ENOD_ADDR *ea;
645 int i;
646
647 if (ip_addr_cmp(ipaddr, &localhost))
648 return ENOD_LOCAL_ID;
649 if (ip_addr_cmp(ipaddr, &multicast))
650 return ENOD_MULTICAST_ID;
651
652 /* IPアドレスの同じものを検索 */
653 for (i = 0, ea = enodadrb_table; i < tnum_enodadr; i++, ea++) {
654 if (!ea->inuse)
655 continue;
656 if (!ip_addr_cmp((ip_addr_t *)ea->ipaddr, ipaddr))
657 continue;
658
659 ECN_CAP_PUT("udp_get_id(): ip-found remote(%d) = %s",
660 i - ENOD_REMOTE_ID, ipaddr_ntoa(ipaddr));
661 return (ECN_ENOD_ID)i;
662 }
663
664 /* 対応するリモートノードを検索 */
665 for (i = ENOD_REMOTE_ID, ea = &enodadrb_table[ENOD_REMOTE_ID]; i < tnum_enodadr; i++, ea++) {
666 if (!ea->inuse)
667 continue;
668 if ((i - ENOD_REMOTE_ID + 1) >= tnum_enodid)
669 break;
670 if (ip_addr_cmp((ip_addr_t *)&ea->ipaddr, &zeroaddr))
671 continue;
672 if (!ECHONET_NODE_MATCH(&eobjcb_table[i - ENOD_REMOTE_ID + 1], edata, ipaddr, portno))
673 continue;
674
675 /* 対応するリモートノードがあればIPアドレスを設定 */
676 *((ip_addr_t *)ea->ipaddr) = *ipaddr;
677
678 ECN_CAP_PUT("udp_get_id(): enod-found remote(%d) = %s",
679 i - ENOD_REMOTE_ID, ipaddr_ntoa(ipaddr));
680 return (ECN_ENOD_ID)i;
681 }
682
683 /* 空き領域を探して自動登録 */
684 for (i = ENOD_REMOTE_ID, ea = &enodadrb_table[ENOD_REMOTE_ID]; i < tnum_enodadr; i++, ea++) {
685 if (ea->inuse)
686 continue;
687
688 ea->inuse = true;
689 *((ip_addr_t *)ea->ipaddr) = *ipaddr;
690
691 ECN_CAP_PUT("udp_get_id(): empty-found remote(%d) = %s",
692 i - ENOD_REMOTE_ID, ipaddr_ntoa(ipaddr));
693 return (ECN_ENOD_ID)i;
694 }
695
696 return ENOD_NOT_MATCH_ID;
697}
698
699/*
700 * リモートECHONETノードからIPアドレスへ変換
701 */
702int udp_get_ip(T_IPV4EP *fp_ipep, ECN_ENOD_ID fa_enodid)
703{
704 T_ENOD_ADDR *ea;
705
706 if (!fp_ipep)
707 return -1; /* NG */
708
709 fp_ipep->portno = 3610;
710
711 if (fa_enodid == ENOD_MULTICAST_ID) {
712 /* targetがENOD_MULTICAST_IDの場合、マルチキャストを行う */
713 ip_addr_copy(fp_ipep->ipaddr, multicast);
714 return 0; /* ok */
715 }
716
717 if (fa_enodid < ENOD_REMOTE_ID) {
718 /* targetが未定義・LOCAL・APIの場合、ローカル配送を行う */
719 ip_addr_copy(fp_ipep->ipaddr, localhost);
720 return 0; /* ok */
721 }
722
723 if (fa_enodid >= tnum_enodadr)
724 return -1; /* NG */
725
726 ea = &enodadrb_table[fa_enodid];
727 if (!ea->inuse)
728 return -1; /* NG */
729
730 if (ip_addr_cmp((ip_addr_t *)&ea->ipaddr, &zeroaddr))
731 return -1; /* NG */
732
733 fp_ipep->ipaddr = *((ip_addr_t *)ea->ipaddr);
734 return 0; /* ok */
735}
736
737ER ecn_udp_get_ipaddr(ID sender, int requestid, ECN_ENOD_ID enodid, ECN_FBS_ID *pk_req)
738{
739 ER a_ret;
740 ECN_FBS_ID req;
741
742 a_ret = _ecn_udp_cre_req_fbs(sender, ECN_UDP_MSG_GET_IPADDR_REQ, &req);
743 if (a_ret != E_OK) {
744 return a_ret;
745 }
746
747 a_ret = _ecn_fbs_add_data_ex(req, &requestid, sizeof(((ecn_udp_msg_get_ipaddr_res_t *)0)->requestid));
748 if (a_ret != E_OK) {
749 _ecn_fbs_del(req);
750 ECN_DBG_PUT("ecn_udp_get_ipaddr() : _ecn_fbs_add_data_ex() result = %d:%s", a_ret, itron_strerror(a_ret));
751 return a_ret;
752 }
753
754 a_ret = _ecn_fbs_add_data_ex(req, &enodid, sizeof(((ecn_udp_msg_get_ipaddr_res_t *)0)->enodid));
755 if (a_ret != E_OK) {
756 _ecn_fbs_del(req);
757 ECN_DBG_PUT("ecn_udp_get_ipaddr() : _ecn_fbs_add_data_ex() result = %d:%s", a_ret, itron_strerror(a_ret));
758 return a_ret;
759 }
760
761 a_ret = _ecn_fbs_add_data_ex(req, &enodadrb_table[enodid], sizeof(((ecn_udp_msg_get_ipaddr_res_t *)0)->enodadrb));
762 if (a_ret != E_OK) {
763 _ecn_fbs_del(req);
764 ECN_DBG_PUT("ecn_udp_get_ipaddr() : _ecn_fbs_add_data_ex() result = %d:%s", a_ret, itron_strerror(a_ret));
765 return a_ret;
766 }
767
768 *pk_req = req;
769
770 return E_OK;
771}
772
773char *ipaddr2str(char *buf, int bubsz, uint8_t *ipaddr)
774{
775 return ipaddr_ntoa_r((ip_addr_t *)ipaddr, buf, bubsz);
776}
777
778#endif
Note: See TracBrowser for help on using the repository browser.