| #include <ros/common.h> |
| #include <assert.h> |
| #include <socket.h> |
| #include <bits/netinet.h> |
| #include <net.h> |
| #include <net/ip.h> |
| #include <net/udp.h> |
| #include <net/tcp_impl.h> |
| #include <ros/errno.h> |
| #include <net/nic_common.h> |
| |
| /* statically configured next gateway */ |
| const uint8_t GTWAY[6] = {0xda, 0x76, 0xe7, 0x4c, 0xca, 0x7e}; |
| |
| /* TODO: ip id unique for all ip packets? or is it unique for a flow? */ |
| // can do atomic increment at a minimum |
| static uint16_t ip_id = 0; |
| |
| /* TODO: build arp table, and look up */ |
| int eth_send(struct pbuf *p, struct in_addr *dest) { |
| uint32_t bytes_sent; |
| printk("size of pbuf_header movement %d\n", sizeof(struct ethernet_hdr)); |
| if (pbuf_header(p, sizeof(struct ethernet_hdr)) != 0){ |
| warn("eth_send buffer ran out"); |
| /* unsuccessful, needs to allocate */ |
| return -ENOBUFS; |
| } |
| |
| struct ethernet_hdr *ethhdr = (struct ethernet_hdr *)p->payload; |
| // TODO: for now just forward to gateway |
| memcpy(ethhdr->dst_mac, GTWAY, 6); |
| memcpy(ethhdr->src_mac, device_mac, 6); |
| ethhdr->eth_type = htons(IP_ETH_TYPE); |
| /* The reason for not sending to send_nic for each pbuf in the chain |
| * is so that we can send from multi-buffer later. |
| */ |
| if (send_pbuf){ |
| bytes_sent = send_pbuf(p); |
| return bytes_sent; |
| } |
| else { |
| warn("no pbuf send function \n"); |
| return -1; |
| } |
| /* is the address local , if no, search for MAC of the gateway and dest to gateway */ |
| /* if address is local, use arp etc */ |
| |
| } |
| |
| /* while it would be nice to write a generic send_pbuf it is impossible to do so in |
| * efficiently. |
| */ |
| /* Assume no ip options */ |
| int ip_output(struct pbuf *p, struct in_addr *src, struct in_addr *dest, |
| uint8_t ttl, uint8_t tos, uint8_t proto) { |
| struct pbuf *q; |
| struct ip_hdr *iphdr; |
| printk ("ip output reached\n"); |
| /* TODO: Check for IP_HDRINCL */ |
| if (dest->s_addr == IP_HDRINCL) { |
| /*send right away since */ |
| warn("header included in the ip packets"); |
| return -1; |
| } |
| if (pbuf_header(p, IP_HDR_SZ)) { |
| warn("buffer ran out"); |
| /* unsuccessful, needs to allocate */ |
| return -ENOBUFS; |
| } |
| iphdr = (struct ip_hdr *) p->payload; |
| |
| /* successful */ |
| iphdr->version = IPPROTO_IPV4; |
| /* assume no IP options */ |
| iphdr->hdr_len = IP_HDR_SZ >> 2; |
| if (tos != 0) { |
| iphdr->tos = htons(tos); |
| } |
| else { |
| iphdr->tos = 0; |
| } |
| iphdr->packet_len = htons(p->tot_len); |
| // TODO: NET_LOCK |
| iphdr->id = htons (ip_id); // 1 |
| ip_id++; |
| iphdr->flags_frags = htons(0); // 4000 may fragment |
| iphdr->protocol = proto; |
| iphdr->ttl = ttl; //DEFAULT_TTL; |
| /* Eventually if we support more than one device this may change */ |
| printk("src ip %x, dest ip %x \n", src->s_addr, dest->s_addr); |
| iphdr->src_addr = htonl(src->s_addr); |
| iphdr->dst_addr = (dest->s_addr); |
| /* force hardware checksum |
| * TODO: provide option to do both hardware/software checksum |
| */ |
| /* Since the IP header is set already, we can compute the checksum. */ |
| /* TODO: Use the card to calculate the checksum */ |
| iphdr->checksum = 0; |
| iphdr->checksum = ip_checksum(iphdr); //7ab6 |
| if (p->tot_len > DEFAULT_MTU) /*MAX MTU? header included */ |
| return -1;//ip_frag(p, dest); |
| else |
| return eth_send(p, dest); |
| } |
| |
| int ip_input(struct pbuf *p) { |
| uint32_t iphdr_hlen, iphdr_len; |
| struct ip_hdr *iphdr = (struct ip_hdr *)p->payload; |
| //printk("start of ip %p \n", p->payload); |
| //print_pbuf(p); |
| /* use that info to build arp table */ |
| if (iphdr->version != 4) { |
| warn("ip version not 4!\n"); |
| pbuf_free(p); |
| return -1; |
| } |
| iphdr_hlen = iphdr->hdr_len * 4; |
| iphdr_len = ntohs(iphdr->packet_len); |
| // printk("ip input coming from %x of size %d", ntohs(iphdr->dst_addr), iphdr_len); |
| /* header length exceeds first pbuf length, or ip length exceeds total pbuf length? */ |
| if ((iphdr_hlen > p->len) || (iphdr_len > p->tot_len)) { |
| if (iphdr_hlen > p->len) { |
| warn("IP header (len 0x%X) does not fit in first pbuf (len %X), IP packet dropped.\n", |
| iphdr_hlen, p->len); |
| } |
| if (iphdr_len > p->tot_len) { |
| warn("IP (len %X) is longer than pbuf (len %X), IP packet dropped.\n", |
| iphdr_len, p->tot_len); |
| } |
| /* free (drop) packet pbufs */ |
| pbuf_free(p); |
| return -1; |
| } |
| if (ip_checksum(iphdr) != 0) { |
| warn("checksum failed \n"); |
| pbuf_free(p); |
| return -1; |
| } |
| |
| /* check if it is destined for me? */ |
| /* XXX: IP address for the interface is IP_ANY */ |
| if (ntohl(iphdr->dst_addr) != LOCAL_IP_ADDR.s_addr){ |
| printk("dest ip in network order%x\n", ntohl(iphdr->dst_addr)); |
| printk("dest ip in network order%x\n", LOCAL_IP_ADDR.s_addr); |
| warn("ip mismatch \n"); |
| pbuf_free(p); |
| /* TODO:forward packets */ |
| // ip_forward(p, iphdr, inp); |
| } |
| |
| if ((ntohs(iphdr->flags_frags) & (IP_OFFMASK | IP_MF)) != 0){ |
| panic ("ip fragment detected\n"); |
| pbuf_free(p); |
| } |
| |
| //printk ("loc head %p, loc protocol %p\n", iphdr, &iphdr->protocol); |
| /* currently a noop, compared to the memory wasted, cutting out ipheader is not really saving much */ |
| // pbuf_realloc(p, iphdr_len); |
| switch (iphdr->protocol) { |
| case IPPROTO_UDP: |
| return udp_input(p); |
| case IPPROTO_TCP: |
| tcp_input(p); |
| // XXX: error handling for tcp |
| return 0; |
| default: |
| printk("IP protocol type %02x\n", iphdr->protocol); |
| warn("protocol not supported! \n"); |
| } |
| return -1; |
| } |
| |
| void print_ipheader(struct ip_hdr* iph){ |
| |
| |
| } |
| |
| |
| |