/*** * * rtcfg/rtcfg_frame.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 #include static unsigned int num_rtskbs = 32; module_param(num_rtskbs, uint, 0444); MODULE_PARM_DESC(num_rtskbs, "Number of realtime socket buffers used by RTcfg"); static struct rtskb_pool rtcfg_pool; static rtdm_task_t rx_task; static rtdm_event_t rx_event; static struct rtskb_queue rx_queue; void rtcfg_thread_signal(void) { rtdm_event_signal(&rx_event); } static int rtcfg_rx_handler(struct rtskb *rtskb, struct rtpacket_type *pt) { if (rtskb_acquire(rtskb, &rtcfg_pool) == 0) { rtskb_queue_tail(&rx_queue, rtskb); rtcfg_thread_signal(); } else kfree_rtskb(rtskb); return 0; } static void rtcfg_rx_task(void *arg) { struct rtskb *rtskb; struct rtcfg_frm_head *frm_head; struct rtnet_device *rtdev; while (!rtdm_task_should_stop()) { if (rtdm_event_wait(&rx_event) < 0) break; while ((rtskb = rtskb_dequeue(&rx_queue))) { rtdev = rtskb->rtdev; if (rtskb->pkt_type == PACKET_OTHERHOST) { kfree_rtskb(rtskb); continue; } if (rtskb->len < sizeof(struct rtcfg_frm_head)) { RTCFG_DEBUG( 1, "RTcfg: %s() received an invalid frame\n", __FUNCTION__); kfree_rtskb(rtskb); continue; } frm_head = (struct rtcfg_frm_head *)rtskb->data; if (rtcfg_do_main_event(rtskb->rtdev->ifindex, frm_head->id + RTCFG_FRM_STAGE_1_CFG, rtskb) < 0) kfree_rtskb(rtskb); } rtcfg_timer_run(); } } int rtcfg_send_frame(struct rtskb *rtskb, struct rtnet_device *rtdev, u8 *dest_addr) { int ret; rtskb->rtdev = rtdev; rtskb->priority = RTCFG_SKB_PRIO; if (rtdev->hard_header) { ret = rtdev->hard_header(rtskb, rtdev, ETH_RTCFG, dest_addr, rtdev->dev_addr, rtskb->len); if (ret < 0) goto err; } if ((rtdev->flags & IFF_UP) != 0) { ret = 0; if (rtdev_xmit(rtskb) != 0) ret = -EAGAIN; } else { ret = -ENETDOWN; goto err; } rtdev_dereference(rtdev); return ret; err: kfree_rtskb(rtskb); rtdev_dereference(rtdev); return ret; } int rtcfg_send_stage_1(struct rtcfg_connection *conn) { struct rtnet_device *rtdev; struct rtskb *rtskb; unsigned int rtskb_size; struct rtcfg_frm_stage_1_cfg *stage_1_frm; rtdev = rtdev_get_by_index(conn->ifindex); if (rtdev == NULL) return -ENODEV; rtskb_size = rtdev->hard_header_len + sizeof(struct rtcfg_frm_stage_1_cfg) + conn->stage1_size + #if IS_ENABLED(CONFIG_XENO_DRIVERS_NET_RTIPV4) (((conn->addr_type & RTCFG_ADDR_MASK) == RTCFG_ADDR_IP) ? 2 * RTCFG_ADDRSIZE_IP : 0); #else /* !CONFIG_XENO_DRIVERS_NET_RTIPV4 */ 0; #endif /* CONFIG_XENO_DRIVERS_NET_RTIPV4 */ rtskb = alloc_rtskb(rtskb_size, &rtcfg_pool); if (rtskb == NULL) { rtdev_dereference(rtdev); return -ENOBUFS; } rtskb_reserve(rtskb, rtdev->hard_header_len); stage_1_frm = (struct rtcfg_frm_stage_1_cfg *)rtskb_put( rtskb, sizeof(struct rtcfg_frm_stage_1_cfg)); stage_1_frm->head.id = RTCFG_ID_STAGE_1_CFG; stage_1_frm->head.version = 0; stage_1_frm->addr_type = conn->addr_type & RTCFG_ADDR_MASK; #if IS_ENABLED(CONFIG_XENO_DRIVERS_NET_RTIPV4) if (stage_1_frm->addr_type == RTCFG_ADDR_IP) { rtskb_put(rtskb, 2 * RTCFG_ADDRSIZE_IP); memcpy(stage_1_frm->client_addr, &(conn->addr.ip_addr), 4); stage_1_frm = (struct rtcfg_frm_stage_1_cfg *)(((u8 *)stage_1_frm) + RTCFG_ADDRSIZE_IP); memcpy(stage_1_frm->server_addr, &(rtdev->local_ip), 4); stage_1_frm = (struct rtcfg_frm_stage_1_cfg *)(((u8 *)stage_1_frm) + RTCFG_ADDRSIZE_IP); } #endif /* CONFIG_XENO_DRIVERS_NET_RTIPV4 */ stage_1_frm->burstrate = device[conn->ifindex].burstrate; stage_1_frm->cfg_len = htons(conn->stage1_size); memcpy(rtskb_put(rtskb, conn->stage1_size), conn->stage1_data, conn->stage1_size); return rtcfg_send_frame(rtskb, rtdev, conn->mac_addr); } int rtcfg_send_stage_2(struct rtcfg_connection *conn, int send_data) { struct rtnet_device *rtdev; struct rtcfg_device *rtcfg_dev = &device[conn->ifindex]; struct rtskb *rtskb; unsigned int rtskb_size; struct rtcfg_frm_stage_2_cfg *stage_2_frm; size_t total_size; size_t frag_size; rtdev = rtdev_get_by_index(conn->ifindex); if (rtdev == NULL) return -ENODEV; if (send_data) { total_size = conn->stage2_file->size; frag_size = MIN(rtdev->get_mtu(rtdev, RTCFG_SKB_PRIO) - sizeof(struct rtcfg_frm_stage_2_cfg), total_size); } else { total_size = 0; frag_size = 0; } rtskb_size = rtdev->hard_header_len + sizeof(struct rtcfg_frm_stage_2_cfg) + frag_size; rtskb = alloc_rtskb(rtskb_size, &rtcfg_pool); if (rtskb == NULL) { rtdev_dereference(rtdev); return -ENOBUFS; } rtskb_reserve(rtskb, rtdev->hard_header_len); stage_2_frm = (struct rtcfg_frm_stage_2_cfg *)rtskb_put( rtskb, sizeof(struct rtcfg_frm_stage_2_cfg)); stage_2_frm->head.id = RTCFG_ID_STAGE_2_CFG; stage_2_frm->head.version = 0; stage_2_frm->flags = rtcfg_dev->flags; stage_2_frm->stations = htonl(rtcfg_dev->other_stations); stage_2_frm->heartbeat_period = htons(rtcfg_dev->spec.srv.heartbeat); stage_2_frm->cfg_len = htonl(total_size); if (send_data) memcpy(rtskb_put(rtskb, frag_size), conn->stage2_file->buffer, frag_size); conn->cfg_offs = frag_size; return rtcfg_send_frame(rtskb, rtdev, conn->mac_addr); } int rtcfg_send_stage_2_frag(struct rtcfg_connection *conn) { struct rtnet_device *rtdev; struct rtskb *rtskb; unsigned int rtskb_size; struct rtcfg_frm_stage_2_cfg_frag *stage_2_frm; size_t frag_size; rtdev = rtdev_get_by_index(conn->ifindex); if (rtdev == NULL) return -ENODEV; frag_size = MIN(rtdev->get_mtu(rtdev, RTCFG_SKB_PRIO) - sizeof(struct rtcfg_frm_stage_2_cfg_frag), conn->stage2_file->size - conn->cfg_offs); rtskb_size = rtdev->hard_header_len + sizeof(struct rtcfg_frm_stage_2_cfg_frag) + frag_size; rtskb = alloc_rtskb(rtskb_size, &rtcfg_pool); if (rtskb == NULL) { rtdev_dereference(rtdev); return -ENOBUFS; } rtskb_reserve(rtskb, rtdev->hard_header_len); stage_2_frm = (struct rtcfg_frm_stage_2_cfg_frag *)rtskb_put( rtskb, sizeof(struct rtcfg_frm_stage_2_cfg_frag)); stage_2_frm->head.id = RTCFG_ID_STAGE_2_CFG_FRAG; stage_2_frm->head.version = 0; stage_2_frm->frag_offs = htonl(conn->cfg_offs); memcpy(rtskb_put(rtskb, frag_size), conn->stage2_file->buffer + conn->cfg_offs, frag_size); conn->cfg_offs += frag_size; return rtcfg_send_frame(rtskb, rtdev, conn->mac_addr); } int rtcfg_send_announce_new(int ifindex) { struct rtcfg_device *rtcfg_dev = &device[ifindex]; struct rtnet_device *rtdev; struct rtskb *rtskb; unsigned int rtskb_size; struct rtcfg_frm_announce *announce_new; rtdev = rtdev_get_by_index(ifindex); if (rtdev == NULL) return -ENODEV; rtskb_size = rtdev->hard_header_len + sizeof(struct rtcfg_frm_announce) + #if IS_ENABLED(CONFIG_XENO_DRIVERS_NET_RTIPV4) (((rtcfg_dev->spec.clt.addr_type & RTCFG_ADDR_MASK) == RTCFG_ADDR_IP) ? RTCFG_ADDRSIZE_IP : 0); #else /* !CONFIG_XENO_DRIVERS_NET_RTIPV4 */ 0; #endif /* CONFIG_XENO_DRIVERS_NET_RTIPV4 */ rtskb = alloc_rtskb(rtskb_size, &rtcfg_pool); if (rtskb == NULL) { rtdev_dereference(rtdev); return -ENOBUFS; } rtskb_reserve(rtskb, rtdev->hard_header_len); announce_new = (struct rtcfg_frm_announce *)rtskb_put( rtskb, sizeof(struct rtcfg_frm_announce)); announce_new->head.id = RTCFG_ID_ANNOUNCE_NEW; announce_new->head.version = 0; announce_new->addr_type = rtcfg_dev->spec.clt.addr_type; #if IS_ENABLED(CONFIG_XENO_DRIVERS_NET_RTIPV4) if (announce_new->addr_type == RTCFG_ADDR_IP) { rtskb_put(rtskb, RTCFG_ADDRSIZE_IP); memcpy(announce_new->addr, &(rtdev->local_ip), 4); announce_new = (struct rtcfg_frm_announce *)(((u8 *)announce_new) + RTCFG_ADDRSIZE_IP); } #endif /* CONFIG_XENO_DRIVERS_NET_RTIPV4 */ announce_new->flags = rtcfg_dev->flags; announce_new->burstrate = rtcfg_dev->burstrate; return rtcfg_send_frame(rtskb, rtdev, rtdev->broadcast); } int rtcfg_send_announce_reply(int ifindex, u8 *dest_mac_addr) { struct rtcfg_device *rtcfg_dev = &device[ifindex]; struct rtnet_device *rtdev; struct rtskb *rtskb; unsigned int rtskb_size; struct rtcfg_frm_announce *announce_rpl; rtdev = rtdev_get_by_index(ifindex); if (rtdev == NULL) return -ENODEV; rtskb_size = rtdev->hard_header_len + sizeof(struct rtcfg_frm_announce) + #if IS_ENABLED(CONFIG_XENO_DRIVERS_NET_RTIPV4) ((rtcfg_dev->spec.clt.addr_type == RTCFG_ADDR_IP) ? RTCFG_ADDRSIZE_IP : 0); #else /* !CONFIG_XENO_DRIVERS_NET_RTIPV4 */ 0; #endif /* CONFIG_XENO_DRIVERS_NET_RTIPV4 */ rtskb = alloc_rtskb(rtskb_size, &rtcfg_pool); if (rtskb == NULL) { rtdev_dereference(rtdev); return -ENOBUFS; } rtskb_reserve(rtskb, rtdev->hard_header_len); announce_rpl = (struct rtcfg_frm_announce *)rtskb_put( rtskb, sizeof(struct rtcfg_frm_announce)); announce_rpl->head.id = RTCFG_ID_ANNOUNCE_REPLY; announce_rpl->head.version = 0; announce_rpl->addr_type = rtcfg_dev->spec.clt.addr_type; #if IS_ENABLED(CONFIG_XENO_DRIVERS_NET_RTIPV4) if (announce_rpl->addr_type == RTCFG_ADDR_IP) { rtskb_put(rtskb, RTCFG_ADDRSIZE_IP); memcpy(announce_rpl->addr, &(rtdev->local_ip), 4); announce_rpl = (struct rtcfg_frm_announce *)(((u8 *)announce_rpl) + RTCFG_ADDRSIZE_IP); } #endif /* CONFIG_XENO_DRIVERS_NET_RTIPV4 */ announce_rpl->flags = rtcfg_dev->flags & _RTCFG_FLAG_READY; announce_rpl->burstrate = 0; /* padding field */ return rtcfg_send_frame(rtskb, rtdev, dest_mac_addr); } int rtcfg_send_ack(int ifindex) { struct rtnet_device *rtdev; struct rtskb *rtskb; unsigned int rtskb_size; struct rtcfg_frm_ack_cfg *ack_frm; rtdev = rtdev_get_by_index(ifindex); if (rtdev == NULL) return -ENODEV; rtskb_size = rtdev->hard_header_len + sizeof(struct rtcfg_frm_ack_cfg); rtskb = alloc_rtskb(rtskb_size, &rtcfg_pool); if (rtskb == NULL) { rtdev_dereference(rtdev); return -ENOBUFS; } rtskb_reserve(rtskb, rtdev->hard_header_len); ack_frm = (struct rtcfg_frm_ack_cfg *)rtskb_put( rtskb, sizeof(struct rtcfg_frm_ack_cfg)); ack_frm->head.id = RTCFG_ID_ACK_CFG; ack_frm->head.version = 0; ack_frm->ack_len = htonl(device[ifindex].spec.clt.cfg_offs); return rtcfg_send_frame(rtskb, rtdev, device[ifindex].spec.clt.srv_mac_addr); } int rtcfg_send_simple_frame(int ifindex, int frame_id, u8 *dest_addr) { struct rtnet_device *rtdev; struct rtskb *rtskb; unsigned int rtskb_size; struct rtcfg_frm_simple *simple_frm; rtdev = rtdev_get_by_index(ifindex); if (rtdev == NULL) return -ENODEV; rtskb_size = rtdev->hard_header_len + sizeof(struct rtcfg_frm_simple); rtskb = alloc_rtskb(rtskb_size, &rtcfg_pool); if (rtskb == NULL) { rtdev_dereference(rtdev); return -ENOBUFS; } rtskb_reserve(rtskb, rtdev->hard_header_len); simple_frm = (struct rtcfg_frm_simple *)rtskb_put( rtskb, sizeof(struct rtcfg_frm_simple)); simple_frm->head.id = frame_id; simple_frm->head.version = 0; return rtcfg_send_frame(rtskb, rtdev, (dest_addr) ? dest_addr : rtdev->broadcast); } int rtcfg_send_dead_station(struct rtcfg_connection *conn) { struct rtnet_device *rtdev; struct rtskb *rtskb; unsigned int rtskb_size; struct rtcfg_frm_dead_station *dead_station_frm; rtdev = rtdev_get_by_index(conn->ifindex); if (rtdev == NULL) return -ENODEV; rtskb_size = rtdev->hard_header_len + sizeof(struct rtcfg_frm_dead_station) + #if IS_ENABLED(CONFIG_XENO_DRIVERS_NET_RTIPV4) (((conn->addr_type & RTCFG_ADDR_MASK) == RTCFG_ADDR_IP) ? RTCFG_ADDRSIZE_IP : 0); #else /* !CONFIG_XENO_DRIVERS_NET_RTIPV4 */ 0; #endif /* CONFIG_XENO_DRIVERS_NET_RTIPV4 */ rtskb = alloc_rtskb(rtskb_size, &rtcfg_pool); if (rtskb == NULL) { rtdev_dereference(rtdev); return -ENOBUFS; } rtskb_reserve(rtskb, rtdev->hard_header_len); dead_station_frm = (struct rtcfg_frm_dead_station *)rtskb_put( rtskb, sizeof(struct rtcfg_frm_dead_station)); dead_station_frm->head.id = RTCFG_ID_DEAD_STATION; dead_station_frm->head.version = 0; dead_station_frm->addr_type = conn->addr_type & RTCFG_ADDR_MASK; #if IS_ENABLED(CONFIG_XENO_DRIVERS_NET_RTIPV4) if (dead_station_frm->addr_type == RTCFG_ADDR_IP) { rtskb_put(rtskb, RTCFG_ADDRSIZE_IP); memcpy(dead_station_frm->logical_addr, &(conn->addr.ip_addr), 4); dead_station_frm = (struct rtcfg_frm_dead_station *)(((u8 *)dead_station_frm) + RTCFG_ADDRSIZE_IP); } #endif /* CONFIG_XENO_DRIVERS_NET_RTIPV4 */ /* Ethernet-specific! */ memcpy(dead_station_frm->physical_addr, conn->mac_addr, ETH_ALEN); memset(&dead_station_frm->physical_addr[ETH_ALEN], 0, sizeof(dead_station_frm->physical_addr) - ETH_ALEN); return rtcfg_send_frame(rtskb, rtdev, rtdev->broadcast); } static struct rtpacket_type rtcfg_packet_type = { .type = __constant_htons( ETH_RTCFG), .handler = rtcfg_rx_handler }; int __init rtcfg_init_frames(void) { int ret; if (rtskb_module_pool_init(&rtcfg_pool, num_rtskbs) < num_rtskbs) return -ENOMEM; rtskb_queue_init(&rx_queue); rtdm_event_init(&rx_event, 0); ret = rtdm_task_init(&rx_task, "rtcfg-rx", rtcfg_rx_task, 0, RTDM_TASK_LOWEST_PRIORITY, 0); if (ret < 0) { rtdm_event_destroy(&rx_event); goto error1; } ret = rtdev_add_pack(&rtcfg_packet_type); if (ret < 0) goto error2; return 0; error2: rtdm_event_destroy(&rx_event); rtdm_task_destroy(&rx_task); error1: rtskb_pool_release(&rtcfg_pool); return ret; } void rtcfg_cleanup_frames(void) { struct rtskb *rtskb; rtdev_remove_pack(&rtcfg_packet_type); rtdm_event_destroy(&rx_event); rtdm_task_destroy(&rx_task); while ((rtskb = rtskb_dequeue(&rx_queue)) != NULL) { kfree_rtskb(rtskb); } rtskb_pool_release(&rtcfg_pool); }