/*** * * rtcfg/rtcfg_conn_event.c * * Real-Time Configuration Distribution Protocol * * Copyright (C) 2003-2005 Jan Kiszka * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include #include #include #include #include #include /****************************** states ***************************************/ static int rtcfg_conn_state_searching(struct rtcfg_connection *conn, RTCFG_EVENT event_id, void *event_data); static int rtcfg_conn_state_stage_1(struct rtcfg_connection *conn, RTCFG_EVENT event_id, void *event_data); static int rtcfg_conn_state_stage_2(struct rtcfg_connection *conn, RTCFG_EVENT event_id, void *event_data); static int rtcfg_conn_state_ready(struct rtcfg_connection *conn, RTCFG_EVENT event_id, void *event_data); static int rtcfg_conn_state_dead(struct rtcfg_connection *conn, RTCFG_EVENT event_id, void *event_data); #ifdef CONFIG_XENO_DRIVERS_NET_RTCFG_DEBUG const char *rtcfg_conn_state[] = { "RTCFG_CONN_SEARCHING", "RTCFG_CONN_STAGE_1", "RTCFG_CONN_STAGE_2", "RTCFG_CONN_READY", "RTCFG_CONN_DEAD" }; #endif /* CONFIG_XENO_DRIVERS_NET_RTCFG_DEBUG */ static void rtcfg_conn_recv_announce_new(struct rtcfg_connection *conn, struct rtskb *rtskb); static void rtcfg_conn_check_cfg_timeout(struct rtcfg_connection *conn); static void rtcfg_conn_check_heartbeat(struct rtcfg_connection *conn); static int (*state[])(struct rtcfg_connection *conn, RTCFG_EVENT event_id, void *event_data) = { rtcfg_conn_state_searching, rtcfg_conn_state_stage_1, rtcfg_conn_state_stage_2, rtcfg_conn_state_ready, rtcfg_conn_state_dead }; int rtcfg_do_conn_event(struct rtcfg_connection *conn, RTCFG_EVENT event_id, void *event_data) { int conn_state = conn->state; RTCFG_DEBUG(3, "RTcfg: %s() conn=%p, event=%s, state=%s\n", __FUNCTION__, conn, rtcfg_event[event_id], rtcfg_conn_state[conn_state]); return (*state[conn_state])(conn, event_id, event_data); } static void rtcfg_next_conn_state(struct rtcfg_connection *conn, RTCFG_CONN_STATE state) { RTCFG_DEBUG(4, "RTcfg: next connection state=%s \n", rtcfg_conn_state[state]); conn->state = state; } static int rtcfg_conn_state_searching(struct rtcfg_connection *conn, RTCFG_EVENT event_id, void *event_data) { struct rtcfg_device *rtcfg_dev = &device[conn->ifindex]; struct rtskb *rtskb = (struct rtskb *)event_data; switch (event_id) { case RTCFG_FRM_ANNOUNCE_NEW: rtcfg_conn_recv_announce_new(conn, rtskb); break; case RTCFG_FRM_ANNOUNCE_REPLY: conn->last_frame = rtskb->time_stamp; rtcfg_next_conn_state(conn, RTCFG_CONN_READY); rtcfg_dev->stations_found++; rtcfg_dev->stations_ready++; rtcfg_dev->spec.srv.clients_configured++; if (rtcfg_dev->spec.srv.clients_configured == rtcfg_dev->other_stations) rtcfg_complete_cmd(conn->ifindex, RTCFG_CMD_WAIT, 0); break; default: RTCFG_DEBUG(1, "RTcfg: unknown event %s for conn %p in %s()\n", rtcfg_event[event_id], conn, __FUNCTION__); return -EINVAL; } return 0; } static int rtcfg_conn_state_stage_1(struct rtcfg_connection *conn, RTCFG_EVENT event_id, void *event_data) { struct rtskb *rtskb = (struct rtskb *)event_data; struct rtcfg_device *rtcfg_dev = &device[conn->ifindex]; struct rtcfg_frm_ack_cfg *ack_cfg; int packets; switch (event_id) { case RTCFG_FRM_ACK_CFG: conn->last_frame = rtskb->time_stamp; ack_cfg = (struct rtcfg_frm_ack_cfg *)rtskb->data; conn->cfg_offs = ntohl(ack_cfg->ack_len); if ((conn->flags & _RTCFG_FLAG_STAGE_2_DATA) != 0) { if (conn->cfg_offs >= conn->stage2_file->size) { rtcfg_dev->spec.srv.clients_configured++; if (rtcfg_dev->spec.srv.clients_configured == rtcfg_dev->other_stations) rtcfg_complete_cmd(conn->ifindex, RTCFG_CMD_WAIT, 0); rtcfg_next_conn_state( conn, ((conn->flags & _RTCFG_FLAG_READY) != 0) ? RTCFG_CONN_READY : RTCFG_CONN_STAGE_2); } else { packets = conn->burstrate; while ((conn->cfg_offs < conn->stage2_file->size) && (packets > 0)) { rtcfg_send_stage_2_frag(conn); packets--; } } } else { rtcfg_dev->spec.srv.clients_configured++; if (rtcfg_dev->spec.srv.clients_configured == rtcfg_dev->other_stations) rtcfg_complete_cmd(conn->ifindex, RTCFG_CMD_WAIT, 0); rtcfg_next_conn_state( conn, ((conn->flags & _RTCFG_FLAG_READY) != 0) ? RTCFG_CONN_READY : RTCFG_CONN_STAGE_2); } break; case RTCFG_TIMER: rtcfg_conn_check_cfg_timeout(conn); break; default: RTCFG_DEBUG(1, "RTcfg: unknown event %s for conn %p in %s()\n", rtcfg_event[event_id], conn, __FUNCTION__); return -EINVAL; } return 0; } static int rtcfg_conn_state_stage_2(struct rtcfg_connection *conn, RTCFG_EVENT event_id, void *event_data) { struct rtskb *rtskb = (struct rtskb *)event_data; struct rtcfg_device *rtcfg_dev = &device[conn->ifindex]; switch (event_id) { case RTCFG_FRM_READY: conn->last_frame = rtskb->time_stamp; rtcfg_next_conn_state(conn, RTCFG_CONN_READY); conn->flags |= _RTCFG_FLAG_READY; rtcfg_dev->stations_ready++; if (rtcfg_dev->stations_ready == rtcfg_dev->other_stations) rtcfg_complete_cmd(conn->ifindex, RTCFG_CMD_READY, 0); break; case RTCFG_TIMER: rtcfg_conn_check_cfg_timeout(conn); break; default: RTCFG_DEBUG(1, "RTcfg: unknown event %s for conn %p in %s()\n", rtcfg_event[event_id], conn, __FUNCTION__); return -EINVAL; } return 0; } static int rtcfg_conn_state_ready(struct rtcfg_connection *conn, RTCFG_EVENT event_id, void *event_data) { struct rtskb *rtskb = (struct rtskb *)event_data; switch (event_id) { case RTCFG_TIMER: rtcfg_conn_check_heartbeat(conn); break; case RTCFG_FRM_HEARTBEAT: conn->last_frame = rtskb->time_stamp; break; default: RTCFG_DEBUG(1, "RTcfg: unknown event %s for conn %p in %s()\n", rtcfg_event[event_id], conn, __FUNCTION__); return -EINVAL; } return 0; } static int rtcfg_conn_state_dead(struct rtcfg_connection *conn, RTCFG_EVENT event_id, void *event_data) { switch (event_id) { case RTCFG_FRM_ANNOUNCE_NEW: rtcfg_conn_recv_announce_new(conn, (struct rtskb *)event_data); break; case RTCFG_FRM_ANNOUNCE_REPLY: /* Spec to-do: signal station that it is assumed to be dead (=> reboot command?) */ default: RTCFG_DEBUG(1, "RTcfg: unknown event %s for conn %p in %s()\n", rtcfg_event[event_id], conn, __FUNCTION__); return -EINVAL; } return 0; } static void rtcfg_conn_recv_announce_new(struct rtcfg_connection *conn, struct rtskb *rtskb) { struct rtcfg_device *rtcfg_dev = &device[conn->ifindex]; struct rtcfg_frm_announce *announce_new; int packets; conn->last_frame = rtskb->time_stamp; announce_new = (struct rtcfg_frm_announce *)rtskb->data; conn->flags = announce_new->flags; if (announce_new->burstrate < conn->burstrate) conn->burstrate = announce_new->burstrate; rtcfg_next_conn_state(conn, RTCFG_CONN_STAGE_1); rtcfg_dev->stations_found++; if ((conn->flags & _RTCFG_FLAG_READY) != 0) rtcfg_dev->stations_ready++; if (((conn->flags & _RTCFG_FLAG_STAGE_2_DATA) != 0) && (conn->stage2_file != NULL)) { packets = conn->burstrate - 1; rtcfg_send_stage_2(conn, 1); while ((conn->cfg_offs < conn->stage2_file->size) && (packets > 0)) { rtcfg_send_stage_2_frag(conn); packets--; } } else { rtcfg_send_stage_2(conn, 0); conn->flags &= ~_RTCFG_FLAG_STAGE_2_DATA; } } static void rtcfg_conn_check_cfg_timeout(struct rtcfg_connection *conn) { struct rtcfg_device *rtcfg_dev; if (!conn->cfg_timeout) return; if (rtdm_clock_read() >= conn->last_frame + conn->cfg_timeout) { rtcfg_dev = &device[conn->ifindex]; rtcfg_dev->stations_found--; if (conn->state == RTCFG_CONN_STAGE_2) rtcfg_dev->spec.srv.clients_configured--; rtcfg_next_conn_state(conn, RTCFG_CONN_SEARCHING); conn->cfg_offs = 0; conn->flags = 0; #if IS_ENABLED(CONFIG_XENO_DRIVERS_NET_RTIPV4) if (conn->addr_type == RTCFG_ADDR_IP) { struct rtnet_device *rtdev; /* MAC address yet unknown -> use broadcast address */ rtdev = rtdev_get_by_index(conn->ifindex); if (rtdev == NULL) return; memcpy(conn->mac_addr, rtdev->broadcast, MAX_ADDR_LEN); rtdev_dereference(rtdev); } #endif /* CONFIG_XENO_DRIVERS_NET_RTIPV4 */ } } static void rtcfg_conn_check_heartbeat(struct rtcfg_connection *conn) { u64 timeout; struct rtcfg_device *rtcfg_dev; timeout = device[conn->ifindex].spec.srv.heartbeat_timeout; if (!timeout) return; if (rtdm_clock_read() >= conn->last_frame + timeout) { rtcfg_dev = &device[conn->ifindex]; rtcfg_dev->stations_found--; rtcfg_dev->stations_ready--; rtcfg_dev->spec.srv.clients_configured--; rtcfg_send_dead_station(conn); rtcfg_next_conn_state(conn, RTCFG_CONN_DEAD); conn->cfg_offs = 0; conn->flags = 0; #if IS_ENABLED(CONFIG_XENO_DRIVERS_NET_RTIPV4) if ((conn->addr_type & RTCFG_ADDR_MASK) == RTCFG_ADDR_IP) { struct rtnet_device *rtdev = rtdev_get_by_index(conn->ifindex); rt_ip_route_del_host(conn->addr.ip_addr, rtdev); if (rtdev == NULL) return; if (!(conn->addr_type & FLAG_ASSIGN_ADDR_BY_MAC)) /* MAC address yet unknown -> use broadcast address */ memcpy(conn->mac_addr, rtdev->broadcast, MAX_ADDR_LEN); rtdev_dereference(rtdev); } #endif /* CONFIG_XENO_DRIVERS_NET_RTIPV4 */ } }