/*** * common reply function */ static void rt_icmp_send_reply(struct icmp_bxm *icmp_param, struct rtskb *skb) { struct dest_route rt; int err; icmp_param->head.icmph.checksum = 0; icmp_param->csum = 0; /* route back to the source address via the incoming device */ if (rt_ip_route_output(&rt, skb->nh.iph->saddr, skb->rtdev->local_ip) != 0) return; rt_socket_reference(icmp_socket); err = rt_ip_build_xmit(icmp_socket, rt_icmp_glue_reply_bits, icmp_param, sizeof(struct icmphdr) + icmp_param->data_len, &rt, MSG_DONTWAIT); if (err) rt_socket_dereference(icmp_socket); rtdev_dereference(rt.rtdev); RTNET_ASSERT(err == 0, rtdm_printk("RTnet: %s() error in xmit\n", __FUNCTION__););
/* ************************************************************************ * This functions runs in rtai context. * It is called from rtnetproxy_user_srq whenever there is frame to sent out * Copy the standard linux sk_buff buffer to a rtnet buffer and send it out * using rtnet functions. * ************************************************************************ */ static inline void send_data_out(struct sk_buff *skb) { struct rtskb *rtskb; struct rt_rtable *rt; struct skb_data_format { struct ethhdr ethhdr; char reserved[12]; /* Ugly but it works... All the not-interesting header bytes */ u32 ip_src; u32 ip_dst; } __attribute__ ((packed)); /* Important to have this structure packed! * It represents the ethernet frame on the line and * thus no spaces are allowed! */ struct skb_data_format *pData; int rc; /* Copy the data from the standard sk_buff to the realtime sk_buff: * Both have the same length. */ rtskb = alloc_rtskb(skb->len); if (NULL == rtskb) { return; } memcpy(rtskb->data, skb->data, skb->len); rtskb->len = skb->len; pData = (struct skb_data_format*) rtskb->data; /* Determine the device to use: Only ip routing is used here. * Non-ip protocols are not supported... */ rc = rt_ip_route_output(&rt, pData->ip_dst, pData->ip_src); if (rc == 0) { struct rtnet_device *rtdev = rt->rt_dev; rtskb->dst = rt; rtskb->rtdev = rt->rt_dev; /* Fill in the ethernet headers: There is already space for the header * but they contain zeros only => Fill it */ memcpy(pData->ethhdr.h_source, rtdev->dev_addr, rtdev->addr_len); memcpy(pData->ethhdr.h_dest, rt->rt_dst_mac_addr, rtdev->addr_len); /* Call the actual transmit function (this function is semaphore * protected): */ rtdev_xmit(rtskb); /* The rtskb is freed somewhere deep in the driver... * No need to do it here. */ } else { /* Routing failed => Free rtskb here... */ kfree_rtskb(rtskb); } }
/*** * common reply function */ static void rt_icmp_send_reply(struct icmp_bxm *icmp_param, struct rtskb *skb) { struct dest_route rt; u32 daddr; int err; daddr = skb->nh.iph->saddr; icmp_param->head.icmph.checksum = 0; icmp_param->csum = 0; if (rt_ip_route_output(&rt, daddr) != 0) return; err = rt_ip_build_xmit(&icmp_socket, rt_icmp_glue_reply_bits, icmp_param, sizeof(struct icmphdr) + icmp_param->data_len, &rt, MSG_DONTWAIT); rtdev_dereference(rt.rtdev); RTNET_ASSERT(err == 0, rtos_print("RTnet: %s() error in xmit\n", __FUNCTION__););
/*** * rt_udp_sendmsg */ ssize_t rt_udp_sendmsg(struct rtdm_dev_context *context, int call_flags, const struct msghdr *msg, int msg_flags) { struct rtsocket *sock = (struct rtsocket *)&context->dev_private; size_t len = rt_iovec_len(msg->msg_iov, msg->msg_iovlen); int ulen = len + sizeof(struct udphdr); struct sockaddr_in *usin; struct udpfakehdr ufh; struct dest_route rt; u32 saddr; u32 daddr; u16 dport; int err; unsigned long flags; if ((len < 0) || (len > 0xFFFF-sizeof(struct iphdr)-sizeof(struct udphdr))) return -EMSGSIZE; if (msg_flags & MSG_OOB) /* Mirror BSD error message compatibility */ return -EOPNOTSUPP; if (msg_flags & ~(MSG_DONTROUTE|MSG_DONTWAIT) ) return -EINVAL; if ((msg->msg_name) && (msg->msg_namelen==sizeof(struct sockaddr_in))) { usin = (struct sockaddr_in*) msg->msg_name; if ((usin->sin_family != AF_INET) && (usin->sin_family != AF_UNSPEC)) return -EINVAL; daddr = usin->sin_addr.s_addr; dport = usin->sin_port; rtos_spin_lock_irqsave(&sock->param_lock, flags); } else { rtos_spin_lock_irqsave(&sock->param_lock, flags); if (sock->prot.inet.state != TCP_ESTABLISHED) return -ENOTCONN; daddr = sock->prot.inet.daddr; dport = sock->prot.inet.dport; } saddr = sock->prot.inet.saddr; ufh.uh.source = sock->prot.inet.sport; rtos_spin_unlock_irqrestore(&sock->param_lock, flags); if ((daddr | dport) == 0) return -EINVAL; /* get output route */ err = rt_ip_route_output(&rt, daddr); if (err) return err; /* check if specified source address fits */ if ((saddr != INADDR_ANY) && (saddr != rt.rtdev->local_ip)) { rtdev_dereference(rt.rtdev); return -EHOSTUNREACH; } /* we found a route, remember the routing dest-addr could be the netmask */ ufh.saddr = rt.rtdev->local_ip; ufh.daddr = daddr; ufh.uh.dest = dport; ufh.uh.len = htons(ulen); ufh.uh.check = 0; ufh.iov = msg->msg_iov; ufh.iovlen = msg->msg_iovlen; ufh.wcheck = 0; err = rt_ip_build_xmit(sock, rt_udp_getfrag, &ufh, ulen, &rt, msg_flags); rtdev_dereference(rt.rtdev); if (!err) return len; else return err; }
/*** * rt_udp_sendmsg */ int rt_udp_sendmsg(struct rtsocket *s, const struct msghdr *msg, size_t len, int flags) { int ulen = len + sizeof(struct udphdr); struct udpfakehdr ufh; struct rt_rtable *rt = NULL; u32 daddr; u16 dport; int err; if ((len < 0) || (len > 0xFFFF-sizeof(struct iphdr)-sizeof(struct udphdr))) return -EMSGSIZE; if (flags & MSG_OOB) /* Mirror BSD error message compatibility */ return -EOPNOTSUPP; if (flags & ~(MSG_DONTROUTE|MSG_DONTWAIT) ) return -EINVAL; if ((msg->msg_name) && (msg->msg_namelen==sizeof(struct sockaddr_in))) { struct sockaddr_in *usin = (struct sockaddr_in*) msg->msg_name; if ((usin->sin_family!=AF_INET) && (usin->sin_family!=AF_UNSPEC)) return -EINVAL; daddr = usin->sin_addr.s_addr; dport = usin->sin_port; } else { if (s->state != TCP_ESTABLISHED) return -ENOTCONN; daddr = s->prot.inet.daddr; dport = s->prot.inet.dport; } #ifdef DEBUG rtos_print("sendmsg to %x:%d\n", ntohl(daddr), ntohs(dport)); #endif if ((daddr==0) || (dport==0)) return -EINVAL; err = rt_ip_route_output(&rt, daddr, s->prot.inet.saddr); if (err) goto out; /* we found a route, remember the routing dest-addr could be the netmask */ ufh.saddr = rt->rt_src; ufh.daddr = daddr; ufh.uh.source = s->prot.inet.sport; ufh.uh.dest = dport; ufh.uh.len = htons(ulen); ufh.uh.check = 0; ufh.iov = msg->msg_iov; ufh.iovlen = msg->msg_iovlen; ufh.wcheck = 0; err = rt_ip_build_xmit(s, rt_udp_getfrag, &ufh, ulen, rt, flags); out: if (!err) return len; else return err; }