+++ /dev/null
-#include <kernel.h>
-#include <net.h>
-
-static void icmp_echo(void)
-{
- ip_mirror(&iph); /* Flip the source and destination into oiph*/
- icmph.type = ICMP_ECHOREPLY;
- icmph.code = 0;
- icmph.checksum = 0;
- icmph.checksum = ip_compute_csum_data(&icmph, sizeof(icmph), pkt_next, pkt_left);
- ip_output(&icmph, sizeof(icmph), pkt_next, pkt_left) ;
- SNMP(icmp_out_echoreply);
-}
-
-static void icmp_unreach(void)
-{
- /* Get the header of the packet that caused the problem */
- if (!pkt_pull(&iph2, sizeof(struct iphdr)))
- return;
- if (iph2.protocol == IPROTO_TCP)
- tcp_unreach();
-}
-
-/*
- * We handle the various unreachables and echo (ping) but as per
- * usual practice we don't touch broadcasts and we don't listen
- * to redirects and the like.
- */
-void icmp_rcv(void)
-{
- uint16_t mask;
- SNMP(icmp_in);
- if (pkt_type != PKT_HOST)
- return;
- if (pkt_left < sizeof(struct icmphdr) || ip_compute_csum(pkt_next, pkt_left)) {
- SNMP(icmp_in_error);
- return;
- }
- pkt_pull(&icmph, sizeof(struct icmphdr));
- if (icmph.type > ICMP_ADDRESREPLY)
- return;
- SNMP(icmp_in_type[icmph.type]);
- mask = 1 << icmph.type;
- if (mask & ICMP_UNREACH_MASK)
- icmp_unreach();
- else if (icmph.type == ICMP_ECHO)
- icmp_echo();
-}
-
-/* Used by upper layers to send ICMP messages responding to frames. iph holds
- the original ip header, pkt_ip points to the ip header in the data block */
-
-void icmp_send_unreach(uint8_t type, uint8_t code)
-{
- len = iph.len << 2 + 8;
- ip_mirror(&iph);
- icmph.type = type;
- icmph.code = code;
- icmph.checksum = 0;
- /* FIXME: better to send more for modern stacks */
- icmph.checksum = ip_compute_csum_data(&icmph, sizeof(icmph), pkt_ip, len);
- ip_output(&icmph, sizeof(icmph), pkt_ip, len);
- SNMP(icmp_out_unreach);
-}
-
+++ /dev/null
-#include "kernel.h"
-#include "net.h"
-
-void ip_mirror(void)
-{
- memcpy(&oiph, &iph, sizeof(iph));
- if (pkt_type != PKT_HOST)
- oiph.saddr = ip_addr;
- else
- oiph.saddr = iph.daddr;
- oiph.daddr = iph.saddr;
- oiph.check = 0;
- oiph.ihl = 5;
- oiph.frag_off = 0;
-}
-
-void ip_prepare(struct socket *s, uint16_t len)
-{
- oiph.saddr = s->saddr;
- oiph.daddr = s->daddr;
- oiph.tot_len = htons(len);
- oiph.protocol = s->proto;
- oiph.ihl = 5;
- oiph.check = 0;
- oiph.frag_off = 0;
- oiph.tos = 0;
-}
-
-int ip_output(void *pbuf, uint16_t plen, void *dbuf, uint16_t dlen)
-{
- oiph.id = htons_inc(ip_id);
- oiph.ttl = IP_TTL;
- oiph.check = 0;
- oiph.version = 4;
- /* Options not supported */
- oiph.ihl = 5;
- oiph.check = ip_checksum(&oiph, sizeof(oiph));
-
- output_begin(); /* Set up output buffer (space left for header) */
- output_add(&oiph, 4 * oiph.ihl);
- output_add(pbuf, plen);
- ouput_add(dbuf, dlen);
- if (LOOPBACK(oiph.daddr) || oiph.daddr == ip_addr)
- return loopback_queue();
- else
- return mac_queue();
- /* We do blocking writes, when this code returns the buffer is on the
- wire and we don't have to fret about re-use. Does mean slip has to be
- careful to buffer the receive side while queueing output */
-}
-
-static int ip_outions(void)
-{
- return 0;
-}
-
-void ip_rcv(void)
-{
- uint16_t len = pkt_left;
- SNMP(ip_in_receives);
- if (!pkt_pull(&iph, sizeof(struct iphdr)))
- return;
- plen = ntohs(iph.tot_len);
- /* FIXME: for speed fold ihl/version and be smarter */
- if (iph.ihl < 5 || iph.version != 4 || len < plen) {
- SNMP(ip_in_hdr_errors);
- return;
- }
- plen -= sizeof(struct iphdr));
- if (pkt_len > plen)
- pkt_len = plen;
-
- /* FIXME: checksum */
- if (iph.ihl != 5)
- if (ip_options())
- return;
- /* No frags for now (memory limits on 8bit) */
- if (iph.frag_off) /* FIXME: check MF and FO */
- return;
- if (iph.daddr == 0xFFFFFFFF)
- pkt_type = PKT_BROADCAST;
- else if (MULTICAST(iph.daddr))
- pkt_type = PKT_MULTICAST;
- else if (iph.daddr == ip_addr || LOOPBACK(iph.daddr))
- pkt_type = PKT_HOST;
- else
- /* No forwarding so we don't have to worry about martians either */
- return;
-
- /* FIXME: raw sockets ?? */
- if (iph.protocol == IPPROTO_TCP)
- tcp_rcv();
- else if (iph.protocol == IPPROTO_UDP)
- udp_rcv();
- else if (iph.protocol == IPPROTO_ICMP)
- icmp_rcv();
- else
- icmp_send_unreach(ICMP_DEST_UNREACH, ICMP_PROT_UNREACH);
-}
+++ /dev/null
-#include "kernel.h"
-#include "net.h"
-
-/*
- * We copy headers into fixed target locations so that
- * processors with poor indexing generate references to
- * link time resolved static memory addresses.
- */
-
-int pkt_pull(void *ptr, uint16_t len)
-{
- if (len > pkt_left)
- return -1;
- memcpy(ptr, pkt_buf, len);
- pkt_buf += len;
- pkt_left -= len;
- return 0;
-}
+++ /dev/null
-
-static void tcp_fix_endian(void)
-{
- ntohl_insitu(&tcph.seq);
- ntohl_insitu(&tcph.ack_seq);
-}
-
-static void tcp_tx_reset(void)
-{
- tcp_fix_endian(); /* Reverse the fixes of endianness */
- ip_mirror(); /* Going back where it came from */
- /* Now concoct a tcp reset frame and send it */
- /* FIXME */
-}
-
-static int tcp_sequence(struct sock *sk)
-{
- /* We share next_seq with tcp_queue */
- next_seq = pkt_left - 4 *tcph.doff;
- if (tcph.fin)
- next_seq++;
- next_seq += tcph.seq;
- /* We don't do out of order - if it doesn't overlap or directly follow
- then we kick it out */
- if (after(tcph.seq, s->acked_seq) || /* Off the start */
- !after(next_seq, s->acked_seq)) { /* Already consumed */
- if (tcph.rst)
- return 0;
- if (s->pstate == TCP_SYN_SENT || s->pstate == TCP_SYN_RECV) {
- tcp_tx_reset();
- return 1;
- }
- /* Tell the other end we are out of sync */
- tcp_send_ack(s);
- }
- /* Ok data is relevant */
- return 1;
-}
-
-/* We don't accept data + SYN together. This code assumes that as it doesn't
- factor tcph.syn into the maths */
-
-static void tcp_queue(struct sock *s)
-{
- uint8_t fin = tcph.fin;
- /* We know this is 16bit safe */
- uint16_t usable = next_seq - sk->acked_seq;
- uint8_t *dptr;
-
- if (fin) /* FIN isn't a data byte */
- usable--;
- /* First byte of data to consume */
- dptr = pkt_next + pkt_left - usable;
- /* Might be nicer to allow a FIN anyway if all data fitted ? */
- if (usable > s->window)
- usable = s->window;
- fin = 0;
- }
- if (usable) {
- if (s->shutdown & RCV_SHUTDOWN) {
- tcp_tx_reset();
- return;
- }
- /* Queue the data */
- dgram_init();
- dgram.sport = tcph.src;
- dgram.dport = tcph.dst;
- queue_stream(s->inode, dptr, usable);
- /* Our ack position moves on */
- s->acked_seq += usable;
- }
- if (fin) { /* We have accepted the FIN */
- s->acked_seq++;
- tcp_fin_recv(s);
- }
- /* Queue an ack. More likely we'll actually do the ack when the user
- consumes the data */
- tcp_queue_ack(s);
-}
-
-void tcp_rcv(void)
-{
- struct socket *s;
- uint16_t len = pkt_left;
- void *thp = pkt_next;
- SNMP(tcp_in_segs);
- if (pkt_type != PKT_HOST)
- return;
- if (!pkt_pull(&tcph, sizeof(tcph)))
- return;
- tcp_fix_endian(); /* Cheaper to do it once */
- if (ip_compute_csum(thp, pkt_left) || tcph.doff < sizeof(tcph) / 4)
- return;
- if (tcph.doff != sizeof(tcph) / 4)
- if (!tcp_options())
- return;
- s = tcp_find();
-
- if (s == NULL) {
- goto reset;
- }
-
- if (s->pstate != TCP_ESTABLISHED) {
- /* New connection check */
- if (s->pstate == TCP_LISTEN) {
- if (thp.ack || thp.ack || !thp.syn)
- goto reset;
- tcp_create(s);
- return;
- }
- /* Duplicate SYN */
- if (s->pstate == TCP_SYN_RECV && tcph.syn && tcph->seq + 1 == sk->ack_seq)
- return;
- if (s->pstate == TCP_SYN_SENT) {
- if (tcph.ack) {
- if (!tcp_valid_ack(s))
- goto reset;
- if (tcph.rst) {
- tcp_rx_reset(s); /* Reset the socket */
- return;
- }
- if (!tcph.syn)
- return;
- s->acked_seq = tcph.seq + 1;
- s->fin_seq = tcp.seq;
- s->pstate = TCP_ESTABLISHED;
- s->copied_seq = s->acked_seq;
- tcp_established(s);
- if (sk->max_window == 0)
- s->max_window = 32;
- s->mss = min(s->max_window, s->mtu);
- }
- } else {
- /* Not an ACK */
- if (tcph.syn && !tcph.rst) {
- if (iph.saddr == iph.daddr && tcph.source == tcph.dest)
- goto reset;
- s->pstate = TCP_SYN_RECV;
- /* Check: SYN|ACK reply needed ? */
- }
- return;
- }
- goto rfc_step6;
- }
- }
- /* Established states. Everything must be in window to be valid */
- if (!tcp_sequence(s))
- return;
- if (tcph.rst) {
- tcp_rx_reset(s);
- return;
- }
- if (tcph.syn && !syn_ok)
- goto reset;
- if (tcph.ack && !tcp_ack(s))
- if (s->pstate == TCP_SYN_RECV)
- goto reset;
-rfc_step6:
- /* Urgent data - skipping for now */
- s->bytes_rcv += pkt_left;
- /* Empty probe */
- if (pkt_left == 0 && !tcph.fin) }
- if (!tcph.ack)
- tcp_send_ack(s);
- return;
- }
- /* Queue data */
- tcp_queue(s);
- return;
-
-reset:
- tcp_tx_reset();
-}
+++ /dev/null
-#include <kernel.h>
-#include <net.h>
-
-static struct socket *udp_find(void)
-{
- return sock_find(udph.src, udph.dst);
-}
-
-void udp_rcv(void)
-{
- struct socket *s;
- SNMP(ip_in_delivers);
- if (!pkt_pull(&udph, sizeof(struct udphdr)) ||
- udph.csum && ip_compute_csum_data(&udph, sizeof(udph), pkt_next, pkt_left))) {
- SNMP(udp_in_errors);
- return;
- }
-
- s = udp_find();
- if (s == NULL)
- icmp_send_unreach(ICMP_DEST_UNREACH, ICMP_PORT_UNREACH);
- else {
- dgram_init();/* msg.len = pkt_left, msg.ptr = pkt_next, sets src/dst ip */
- dgram.sport = udph.src;
- dgram.dport = udph.dst;
- queue_dgram(s->inode);
- }
-}
-
-int udp_send(struct socket *s, void *buf, uint16_t len)
-{
- udph.src = s->sport;
- udph.dst = s->dport;
- udph.len = htons(len);
- udph.check = 0;
- len += sizeof(struct udphdr);
- ip_prepare(s, IPPROTO_UDP, len);
- udph.check = ip_compute_csum_data(&udph, sizeof(udph), buf, len);
- len += sizeof(struct iphdr);
- if (len > MAX_IP)
- return -EMSGSIZE;
- return ip_output(&udph, sizeof(udph), buf, len);
-}