Ejemplo n.º 1
0
        /**
         * Copies data into a single pbuf (not into a pbuf queue!) and updates
         * the checksum while copying
         *
         * @param p the pbuf to copy data into
         * @param start_offset offset of p.payload where to copy the data to
         * @param dataptr data to copy into the pbuf
         * @param len length of data to copy into the pbuf
         * @param chksum pointer to the checksum which is updated
         * @return err_t.ERR_OK if successful, another error if the data does not fit
         *         within the (first) pbuf (no pbuf queues!)
         */
        public static err_t pbuf_fill_chksum(pbuf p, ushort start_offset, pointer dataptr,
						 ushort len, ref ushort chksum)
        {
            uint acc;
            ushort copy_chksum;
            pointer dst_ptr;
            lwip.LWIP_ASSERT("p != null", p != null);
            lwip.LWIP_ASSERT("dataptr != null", dataptr != null);
            //lwip.LWIP_ASSERT("chksum != null", chksum != null);
            lwip.LWIP_ASSERT("len != 0", len != 0);

            if ((start_offset >= p.len) || (start_offset + len > p.len)) {
                return err_t.ERR_ARG;
            }

            dst_ptr = ((pointer)p.payload) + start_offset;
            copy_chksum = lwip.LWIP_CHKSUM_COPY(dst_ptr, dataptr, len);
            if ((start_offset & 1) != 0) {
                copy_chksum = lwip.SWAP_BYTES_IN_WORD(copy_chksum);
            }
            acc = chksum;
            acc += copy_chksum;
            chksum = (ushort)lwip.FOLD_U32T(acc);
            return err_t.ERR_OK;
        }
Ejemplo n.º 2
0
Archivo: ip.cs Proyecto: h7ga40/uITron3
        internal err_t ip_input(pbuf p, ip_addr src, ip_addr dest, byte proto)
        {
            ++lwip_stats.ip.recv;

            /* copy IP addresses to aligned ip_addr */
            ip_addr.ip_addr_copy(current_iphdr_dest, dest);
            ip_addr.ip_addr_copy(current_iphdr_src, src);

            /* broadcast or multicast packet source address? Compliant with RFC 1122: 3.2.1.3 */
            #if IP_ACCEPT_LINK_LAYER_ADDRESSING
            /* DHCP servers need 0.0.0.0 to be allowed as source address (RFC 1.1.2.2: 3.2.1.3/a) */
            if (check_ip_src != 0 && !ip_addr.ip_addr_isany(ip.current_iphdr_src))
            #endif // IP_ACCEPT_LINK_LAYER_ADDRESSING
            {
                if ((ip_addr.ip_addr_isbroadcast(current_iphdr_src, this)) ||
                    (ip_addr.ip_addr_ismulticast(current_iphdr_src))) {
                    /* packet source is not valid */
                    lwip.LWIP_DEBUGF(opt.IP_DEBUG | lwip.LWIP_DBG_TRACE | lwip.LWIP_DBG_LEVEL_WARNING, "ip_input: packet source is not valid.\n");
                    /* free (drop) packet pbufs */
                    pbuf_free(p);
                    ++lwip_stats.ip.drop;
                    //snmp.snmp_inc_ipinaddrerrors();
                    //snmp.snmp_inc_ipindiscards();
                    return err_t.ERR_OK;
                }
            }

            /* send to upper layers */
            lwip.LWIP_DEBUGF(opt.IP_DEBUG, "ip_input: \n");
            #if IP_DEBUG
            ip_debug_print(p);
            #endif
            lwip.LWIP_DEBUGF(opt.IP_DEBUG, "ip_input: p.len {0} p.tot_len {1}\n", p.len, p.tot_len);

            //lwip.current_header = iphdr;

            #if LWIP_RAW
            /* raw input did not eat the packet? */
            if (raw.raw_input(p, inp) == 0)
            #endif // LWIP_RAW
            {
                switch (proto) {
            #if LWIP_UDP
                case lwip.IP_PROTO_UDP:
            #if LWIP_UDPLITE
                case lwip.IP_PROTO_UDPLITE:
            #endif // LWIP_UDPLITE
                    //snmp.snmp_inc_ipindelivers();
                    udp.udp_input(p, this, proto == lwip.IP_PROTO_UDPLITE);
                    break;
            #endif // LWIP_UDP
            #if LWIP_TCP
                case lwip.IP_PROTO_TCP:
                    //snmp.snmp_inc_ipindelivers();
                    tcp.tcp_input(p, this);
                    break;
            #endif // LWIP_TCP
            #if LWIP_ICMP
                case lwip.IP_PROTO_ICMP:
                    //snmp.snmp_inc_ipindelivers();
                    lwip.icmp.icmp_input(p, inp);
                    break;
            #endif // LWIP_ICMP
            #if LWIP_IGMP
                case lwip.IP_PROTO_IGMP:
                    lwip.igmp.igmp_input(p, inp, lwip.current_iphdr_dest);
                    break;
            #endif // LWIP_IGMP
                default:
            #if LWIP_ICMP
                    /* send ICMP destination protocol unreachable unless is was a broadcast */
                    if (!ip_addr.ip_addr_isbroadcast(lwip.current_iphdr_dest, inp) &&
                        !ip_addr.ip_addr_ismulticast(lwip.current_iphdr_dest))
                    {
                        p.payload = iphdr;
                        lwip.icmp.icmp_dest_unreach(p, icmp_dur_type.ICMP_DUR_PROTO);
                    }
            #endif // LWIP_ICMP
                    pbuf_free(p);

                    LWIP_DEBUGF(opt.IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, "Unsupported transport protocol {0}\n", proto);

                    ++lwip_stats.ip.proterr;
                    ++lwip_stats.ip.drop;
                    //snmp.snmp_inc_ipinunknownprotos();
                    break;
                }
            }

            //lwip.current_header = null;
            ip_addr.ip_addr_set_any(current_iphdr_src);
            ip_addr.ip_addr_set_any(current_iphdr_dest);

            return err_t.ERR_OK;
        }
Ejemplo n.º 3
0
Archivo: ip.cs Proyecto: h7ga40/uITron3
        internal err_t output(lwip ip, pbuf p, ip_addr src, ip_addr dest, byte ttl, byte tos, byte proto)
        {
            int pos = 0, rest = p.tot_len;
            byte[] packet = new byte[rest];
            ip_addr srch = new ip_addr(lwip_ntohl(src.addr));
            ip_addr desth = new ip_addr(lwip_ntohl(dest.addr));

            for (pbuf q = p; q != null; q = q.next) {
                int len = rest;
                if (len > q.len)
                    len = q.len;

                Buffer.BlockCopy(q.payload.data, q.payload.offset, packet, pos, len);
                pos += len;
                rest -= len;
            }

            m_output(ip, packet, srch, desth, proto);

            return err_t.ERR_OK;
        }
Ejemplo n.º 4
0
        /**
         * The initial input processing of TCP. It verifies the TCP header, demultiplexes
         * the segment between the PCBs and passes it on to tcp_process(), which implements
         * the TCP finite state machine. This function is called by the IP layer (in
         * ip_input()).
         *
         * @param p received TCP segment to process (p.payload pointing to the IP header)
         * @param inp network interface on which this segment was received
         */
        public void tcp_input(pbuf p, lwip inp)
        {
            tcp_pcb pcb, prev;
            tcp_pcb_listen lpcb;
            #if SO_REUSE
            tcp_pcb_listen lpcb_prev = null;
            tcp_pcb_listen lpcb_any = null;
            #endif // SO_REUSE
            byte hdrlen;
            err_t err;

            //PERF_START;

            ++lwip.lwip_stats.tcp.recv;
            ////snmp.snmp_inc_tcpinsegs();

            tcphdr = new tcp_hdr(p.payload);

            #if TCP_INPUT_DEBUG
            tcp_debug_print(tcphdr);
            #endif

            /* Don't even process incoming broadcasts/multicasts. */
            if (ip_addr.ip_addr_isbroadcast(lwip.current_iphdr_dest, inp) ||
                ip_addr.ip_addr_ismulticast(lwip.current_iphdr_dest)) {
                ++lwip.lwip_stats.tcp.proterr;
                goto dropped;
            }

            #if CHECKSUM_CHECK_TCP
            /* Verify TCP checksum. */
            if (lwip.inet_chksum_pseudo(p, lwip.ip_current_src_addr(), lwip.ip_current_dest_addr(),
                lwip.IP_PROTO_TCP, p.tot_len) != 0) {
                lwip.LWIP_DEBUGF(opt.TCP_INPUT_DEBUG, "tcp_input: packet discarded due to failing checksum 0x{0:X4}\n",
                    lwip.inet_chksum_pseudo(p, lwip.ip_current_src_addr(), lwip.ip_current_dest_addr(),
                    lwip.IP_PROTO_TCP, p.tot_len));
            #if TCP_DEBUG
                tcp_debug_print(tcphdr);
            #endif // TCP_DEBUG
                ++lwip.lwip_stats.tcp.chkerr;
                goto dropped;
            }
            #endif

            /* Move the payload pointer in the pbuf so that it points to the
               TCP data instead of the TCP header. */
            hdrlen = (byte)tcp_hdr.TCPH_HDRLEN(tcphdr);
            if (lwip.pbuf_header(p, (short)-(hdrlen * 4)) != 0) {
                /* drop short packets */
                lwip.LWIP_DEBUGF(opt.TCP_INPUT_DEBUG, "tcp_input: short packet\n");
                ++lwip.lwip_stats.tcp.lenerr;
                goto dropped;
            }

            /* Convert fields in TCP header to host byte order. */
            tcphdr.src = lwip.lwip_ntohs(tcphdr.src);
            tcphdr.dest = lwip.lwip_ntohs(tcphdr.dest);
            seqno = tcphdr.seqno = lwip.lwip_ntohl(tcphdr.seqno);
            ackno = tcphdr.ackno = lwip.lwip_ntohl(tcphdr.ackno);
            tcphdr.wnd = lwip.lwip_ntohs(tcphdr.wnd);

            flags = tcp_hdr.TCPH_FLAGS(tcphdr);
            tcplen = (ushort)(p.tot_len + (((flags & (tcp.TCP_FIN | tcp.TCP_SYN)) != 0) ? 1 : 0));

            /* Demultiplex an incoming segment. First, we check if it is destined
               for an active connection. */
            prev = null;

            for (pcb = tcp_active_pcbs; pcb != null; pcb = (tcp_pcb)pcb.next) {
                lwip.LWIP_ASSERT("tcp_input: active pcb.state != tcp_state.CLOSED", pcb.state != tcp_state.CLOSED);
                lwip.LWIP_ASSERT("tcp_input: active pcb.state != TIME-WAIT", pcb.state != tcp_state.TIME_WAIT);
                lwip.LWIP_ASSERT("tcp_input: active pcb.state != tcp_state.LISTEN", pcb.state != tcp_state.LISTEN);
                if (pcb.remote_port == tcphdr.src &&
                    pcb.local_port == tcphdr.dest &&
                    ip_addr.ip_addr_cmp(pcb.remote_ip, lwip.current_iphdr_src) &&
                    ip_addr.ip_addr_cmp(pcb.local_ip, lwip.current_iphdr_dest)) {

                    /* Move this PCB to the front of the list so that subsequent
                       lookups will be faster (we exploit locality in TCP segment
                       arrivals). */
                    lwip.LWIP_ASSERT("tcp_input: pcb.next != pcb (before cache)", pcb.next != pcb);
                    if (prev != null) {
                        prev.next = pcb.next;
                        pcb.next = tcp_active_pcbs;
                        tcp_active_pcbs = pcb;
                    }
                    lwip.LWIP_ASSERT("tcp_input: pcb.next != pcb (after cache)", pcb.next != pcb);
                    break;
                }
                prev = pcb;
            }

            if (pcb == null) {
                /* If it did not go to an active connection, we check the connections
                   in the TIME-WAIT state. */
                for (pcb = tcp_tw_pcbs; pcb != null; pcb = (tcp_pcb)pcb.next) {
                    lwip.LWIP_ASSERT("tcp_input: TIME-WAIT pcb.state == TIME-WAIT", pcb.state == tcp_state.TIME_WAIT);
                    if (pcb.remote_port == tcphdr.src &&
                        pcb.local_port == tcphdr.dest &&
                        ip_addr.ip_addr_cmp(pcb.remote_ip, lwip.current_iphdr_src) &&
                        ip_addr.ip_addr_cmp(pcb.local_ip, lwip.current_iphdr_dest)) {
                        /* We don't really care enough to move this PCB to the front
                           of the list since we are not very likely to receive that
                           many segments for connections in TIME-WAIT. */
                        lwip.LWIP_DEBUGF(opt.TCP_INPUT_DEBUG, "tcp_input: packed for tcp_state.TIME_WAITing connection.\n");
                        tcp_timewait_input(pcb);
                        lwip.pbuf_free(p);
                        return;
                    }
                }

                /* Finally, if we still did not get a match, we check all PCBs that
                   are tcp_state.LISTENing for incoming connections. */
                tcp_pcb_listen lprev = null;
                for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != null; lpcb = (tcp_pcb_listen)lpcb.next) {
                    if (lpcb.local_port == tcphdr.dest) {
            #if SO_REUSE
                        if (ip_addr.ip_addr_cmp(lpcb.local_ip, lwip.current_iphdr_dest)) {
                            /* found an exact match */
                            break;
                        }
                        else if (ip_addr.ip_addr_isany(lpcb.local_ip)) {
                            /* found an ANY-match */
                            lpcb_any = lpcb;
                            lpcb_prev = lprev;
                        }
            #else // SO_REUSE
                        if (ip_addr.ip_addr_cmp(lpcb.local_ip, lwip.current_iphdr_dest) ||
                            ip_addr.ip_addr_isany(lpcb.local_ip))
                        {
                            /* found a match */
                            break;
                        }
            #endif // SO_REUSE
                    }
                    lprev = lpcb;
                }
            #if SO_REUSE
                /* first try specific local IP */
                if (lpcb == null) {
                    /* only pass to ANY if no specific local IP has been found */
                    lpcb = lpcb_any;
                    lprev = lpcb_prev;
                }
            #endif // SO_REUSE
                if (lpcb != null) {
                    /* Move this PCB to the front of the list so that subsequent
                       lookups will be faster (we exploit locality in TCP segment
                       arrivals). */
                    if (lprev != null) {
                        ((tcp_pcb_listen)lprev).next = lpcb.next;
                        /* our successor is the remainder of the listening list */
                        lpcb.next = tcp_listen_pcbs.listen_pcbs;
                        /* put this listening pcb at the head of the listening list */
                        tcp_listen_pcbs.listen_pcbs = lpcb;
                    }

                    lwip.LWIP_DEBUGF(opt.TCP_INPUT_DEBUG, "tcp_input: packed for tcp_state.LISTENing connection.\n");
                    tcp_listen_input(lpcb);
                    lwip.pbuf_free(p);
                    return;
                }
            }

            #if TCP_INPUT_DEBUG
            lwip.LWIP_DEBUGF(opt.TCP_INPUT_DEBUG, "+-+-+-+-+-+-+-+-+-+-+-+-+-+- tcp_input: flags ");
            tcp_debug_print_flags(tcp_hdr.TCPH_FLAGS(tcphdr));
            lwip.LWIP_DEBUGF(opt.TCP_INPUT_DEBUG, "-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n");
            #endif // TCP_INPUT_DEBUG

            if (pcb != null) {
                /* The incoming segment belongs to a connection. */
            #if TCP_INPUT_DEBUG
            #if TCP_DEBUG
                tcp_debug_print_state(pcb.state);
            #endif // TCP_DEBUG
            #endif // TCP_INPUT_DEBUG

                /* Set up a tcp_seg structure. */
                inseg.next = null;
                inseg.len = p.tot_len;
                inseg.p = p;
                inseg.tcphdr = tcphdr;

                recv_data = null;
                recv_flags = 0;

                if ((flags & tcp.TCP_PSH) != 0) {
                    p.flags |= pbuf.PBUF_FLAG_PUSH;
                }

                /* If there is data which was previously "refused" by upper layer */
                if (pcb.refused_data != null) {
                    if ((tcp_process_refused_data(pcb) == err_t.ERR_ABRT) ||
                      ((pcb.refused_data != null) && (tcplen > 0))) {
                        /* pcb has been aborted or refused data is still refused and the new
                           segment contains data */
                        ++lwip.lwip_stats.tcp.drop;
                        //snmp.snmp_inc_tcpinerrs();
                        goto aborted;
                    }
                }
                tcp_input_pcb = pcb;
                err = tcp_process(pcb);
                /* A return value of err_t.ERR_ABRT means that tcp.tcp_abort() was called
                   and that the pcb has been freed. If so, we don't do anything. */
                if (err != err_t.ERR_ABRT) {
                    if ((recv_flags & tcp.TF_RESET) != 0) {
                        /* TF_RESET means that the connection was reset by the other
                           end. We then call the error callback to inform the
                           application that the connection is dead before we
                           deallocate the PCB. */
                        TCP_EVENT_ERR(pcb.errf, pcb.callback_arg, err_t.ERR_RST);
                        tcp_pcb_remove(tcp_active_pcbs, pcb);
                        lwip.memp_free(memp_t.MEMP_TCP_PCB, pcb);
                    }
                    else if ((recv_flags & tcp.TF_CLOSED) != 0) {
                        /* The connection has been closed and we will deallocate the
                           PCB. */
                        if ((pcb.flags & tcp_pcb.TF_RXCLOSED) == 0) {
                            /* Connection closed although the application has only shut down the
                               tx side: call the PCB's err callback and indicate the closure to
                               ensure the application doesn't continue using the PCB. */
                            TCP_EVENT_ERR(pcb.errf, pcb.callback_arg, err_t.ERR_CLSD);
                        }
                        tcp_pcb_remove(tcp_active_pcbs, pcb);
                        lwip.memp_free(memp_t.MEMP_TCP_PCB, pcb);
                    }
                    else {
                        err = err_t.ERR_OK;
                        /* If the application has registered a "sent" function to be
                           called when new send buffer space is available, we call it
                           now. */
                        if (pcb.acked > 0) {
                            TCP_EVENT_SENT(pcb, pcb.acked, out err);
                            if (err == err_t.ERR_ABRT) {
                                goto aborted;
                            }
                        }

                        if (recv_data != null) {
                            lwip.LWIP_ASSERT("pcb.refused_data == null", pcb.refused_data == null);
                            if ((pcb.flags & tcp_pcb.TF_RXCLOSED) != 0) {
                                /* received data although already closed . abort (send RST) to
                                   notify the remote host that not all data has been processed */
                                lwip.pbuf_free(recv_data);
                                tcp_abort(pcb);
                                goto aborted;
                            }

                            /* Notify application that data has been received. */
                            TCP_EVENT_RECV(pcb, recv_data, err_t.ERR_OK, out err);
                            if (err == err_t.ERR_ABRT) {
                                goto aborted;
                            }

                            /* If the upper layer can't receive this data, store it */
                            if (err != err_t.ERR_OK) {
                                pcb.refused_data = recv_data;
                                lwip.LWIP_DEBUGF(opt.TCP_INPUT_DEBUG, "tcp_input: keep incoming packet, because pcb is \"full\"\n");
                            }
                        }

                        /* If a FIN segment was received, we call the callback
                           function with a null buffer to indicate EOF. */
                        if ((recv_flags & TF_GOT_FIN) != 0) {
                            if (pcb.refused_data != null) {
                                /* Delay this if we have refused data. */
                                pcb.refused_data.flags |= pbuf.PBUF_FLAG_TCP_FIN;
                            }
                            else {
                                /* correct rcv_wnd as the application won't call tcp_recved()
                                   for the FIN's seqno */
                                if (pcb.rcv_wnd != opt.TCP_WND) {
                                    pcb.rcv_wnd++;
                                }
                                TCP_EVENT_CLOSED(pcb, out err);
                                if (err == err_t.ERR_ABRT) {
                                    goto aborted;
                                }
                            }
                        }

                        tcp_input_pcb = null;
                        /* Try to send something out. */
                        tcp_output(pcb);
            #if TCP_INPUT_DEBUG
            #if TCP_DEBUG
                        tcp_debug_print_state(pcb.state);
            #endif // TCP_DEBUG
            #endif // TCP_INPUT_DEBUG
                    }
                }
            /* Jump target if pcb has been aborted in a callback (by calling tcp.tcp_abort()).
               Below this line, 'pcb' may not be dereferenced! */
            aborted:
                tcp_input_pcb = null;
                recv_data = null;

                /* give up our reference to inseg.p */
                if (inseg.p != null) {
                    lwip.pbuf_free(inseg.p);
                    inseg.p = null;
                }
            }
            else {

                /* If no matching PCB was found, send a TCP RST (reset) to the
                   sender. */
                lwip.LWIP_DEBUGF(opt.TCP_RST_DEBUG, "tcp_input: no PCB match found, resetting.\n");
                if ((tcp_hdr.TCPH_FLAGS(tcphdr) & tcp.TCP_RST) == 0) {
                    ++lwip.lwip_stats.tcp.proterr;
                    ++lwip.lwip_stats.tcp.drop;
                    tcp_rst(ackno, seqno + tcplen,
                        lwip.ip_current_dest_addr(), lwip.ip_current_src_addr(),
                        tcphdr.dest, tcphdr.src);
                }
                lwip.pbuf_free(p);
            }

            lwip.LWIP_ASSERT("tcp_input: tcp_pcbs_sane()", tcp_pcbs_sane() != 0);
            //PERF_STOP("tcp_input");
            return;
            dropped:
            ++lwip.lwip_stats.tcp.drop;
            //snmp.snmp_inc_tcpinerrs();
            lwip.pbuf_free(p);
        }
Ejemplo n.º 5
0
 internal void copy_from(tcp_seg seg)
 {
     this.next = seg.next;
     this.p = seg.p;
     this.len = seg.len;
     #if TCP_OVERSIZE_DBGCHECK
     this.oversize_left = seg.oversize_left;
     #endif // TCP_OVERSIZE_DBGCHECK
     #if TCP_CHECKSUM_ON_COPY
     this.chksum = seg.chksum;
     this.chksum_swapped = seg.chksum_swapped;
     #endif // TCP_CHECKSUM_ON_COPY
     this.flags = seg.flags;
     this.tcphdr = seg.tcphdr;
 }
Ejemplo n.º 6
0
		/* lwip.inet_chksum_pseudo:
		 *
		 * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.
		 * IP addresses are expected to be in network byte order.
		 *
		 * @param p chain of pbufs over that a checksum should be calculated (ip data part)
		 * @param src source ip address (used for checksum of pseudo header)
		 * @param dst destination ip address (used for checksum of pseudo header)
		 * @param proto ip protocol (used for checksum of pseudo header)
		 * @param proto_len length of the ip data part (used for checksum of pseudo header)
		 * @return checksum (as ushort) to be saved directly in the protocol header
		 */
		public static ushort inet_chksum_pseudo(pbuf p, ip_addr src, ip_addr dest,
			byte proto, ushort proto_len)
		{
			uint acc;
			uint addr;
			pbuf q;
			byte swapped;

			acc = 0;
			swapped = 0;
			/* iterate through all pbuf in chain */
			for (q = p; q != null; q = q.next) {
				lwip.LWIP_DEBUGF(opt.INET_DEBUG, "inet_chksum_pseudo(): checksumming pbuf {0} (has next {1}) \n",
				  q, q.next);
				acc += LWIP_CHKSUM(q.payload, q.len);
				/*lwip.LWIP_DEBUGF(opt.INET_DEBUG, "inet_chksum_pseudo(): unwrapped lwip_chksum()={0} \n", acc);*/
				/* just executing this next line is probably faster that the if statement needed
				   to check whether we really need to execute it, and does no harm */
				acc = FOLD_U32T(acc);
				if (q.len % 2 != 0) {
					swapped = (byte)(1 - swapped);
					acc = SWAP_BYTES_IN_WORD((ushort)acc);
				}
				/*lwip.LWIP_DEBUGF(opt.INET_DEBUG, "inet_chksum_pseudo(): wrapped lwip_chksum()={0} \n", acc);*/
			}

			if (swapped != 0) {
				acc = SWAP_BYTES_IN_WORD((ushort)acc);
			}
			addr = ip_addr.ip4_addr_get_u32(src);
			acc += (addr & 0xffffU);
			acc += ((addr >> 16) & 0xffffU);
			addr = ip_addr.ip4_addr_get_u32(dest);
			acc += (addr & 0xffffU);
			acc += ((addr >> 16) & 0xffffU);
			acc += (uint)lwip.lwip_htons((ushort)proto);
			acc += (uint)lwip.lwip_htons(proto_len);

			/* Fold 32-bit sum to 16 bits
			   calling this twice is propably faster than if statements... */
			acc = FOLD_U32T(acc);
			acc = FOLD_U32T(acc);
			lwip.LWIP_DEBUGF(opt.INET_DEBUG, "inet_chksum_pseudo(): pbuf chain lwip_chksum()={0}\n", acc);
			return (ushort)~(acc & 0xffffU);
		}
Ejemplo n.º 7
0
		/**
		 * Calculate a checksum over a chain of pbufs (without pseudo-header, much like
		 * lwip.inet_chksum only pbufs are used).
		 *
		 * @param p pbuf chain over that the checksum should be calculated
		 * @return checksum (as ushort) to be saved directly in the protocol header
		 */
		public static ushort inet_chksum_pbuf(pbuf p)
		{
			uint acc;
			pbuf q;
			byte swapped;

			acc = 0;
			swapped = 0;
			for (q = p; q != null; q = q.next) {
				acc += LWIP_CHKSUM(q.payload, q.len);
				acc = FOLD_U32T(acc);
				if (q.len % 2 != 0) {
					swapped = (byte)(1 - swapped);
					acc = SWAP_BYTES_IN_WORD((ushort)acc);
				}
			}

			if (swapped != 0) {
				acc = SWAP_BYTES_IN_WORD((ushort)acc);
			}
			return (ushort)~(acc & 0xffffUL);
		}
Ejemplo n.º 8
0
        /**
         * Adjusts the payload pointer to hide or reveal headers in the payload.
         *
         * Adjusts the .payload pointer so that space for a header
         * (dis)appears in the pbuf payload.
         *
         * The .payload, .tot_len and .len fields are adjusted.
         *
         * @param p pbuf to change the header size.
         * @param header_size_increment Number of bytes to increment header size which
         * increases the size of the pbuf. New space is on the front.
         * (Using a negative value decreases the header size.)
         * If hdr_size_inc is 0, this function does nothing and returns succesful.
         *
         * pbuf_type.PBUF_ROM and pbuf_type.PBUF_REF type buffers cannot have their sizes increased, so
         * the call will fail. A check is made that the increase in header size does
         * not move the payload pointer in front of the start of the buffer.
         * @return non-zero on failure, zero on success.
         *
         */
        public static byte pbuf_header(pbuf p, short header_size_increment)
        {
            pbuf_type type;
            pointer payload;
            short increment_magnitude;

            lwip.LWIP_ASSERT("p != null", p != null);
            if ((header_size_increment == 0) || (p == null)) {
                return 0;
            }

            if (header_size_increment < 0) {
                increment_magnitude = (short)-header_size_increment;
                /* Check that we aren't going to move off the end of the pbuf */
                if (lwip.LWIP_ERROR("increment_magnitude <= p.len", (increment_magnitude <= p.len))) return 1;
            }
            else {
                increment_magnitude = header_size_increment;
            #if false
                /* Can't assert these as some callers speculatively call
                   pbuf_header() to see if it's OK.  Will return 1 below instead. */
                /* Check that we've got the correct type of pbuf to work with */
                lwip.LWIP_ASSERT("p.type == pbuf_type.PBUF_RAM || p.type == pbuf_type.PBUF_POOL",
                            p.type == pbuf_type.PBUF_RAM || p.type == pbuf_type.PBUF_POOL);
                /* Check that we aren't going to move off the beginning of the pbuf */
                lwip.LWIP_ASSERT("p.payload - increment_magnitude >= p + SIZEOF_STRUCT_PBUF",
                            p.payload - increment_magnitude >= p + SIZEOF_STRUCT_PBUF);
            #endif
            }

            type = p.type;
            /* remember current payload pointer */
            payload = p.payload;

            /* pbuf types containing payloads? */
            if (type == pbuf_type.PBUF_RAM || type == pbuf_type.PBUF_POOL) {
                /* set new payload pointer */
                p.payload = p.payload - header_size_increment;
                /* boundary check fails? */
                if (p.payload < p + pbuf.SIZEOF_STRUCT_PBUF) {
                    lwip.LWIP_DEBUGF(opt.PBUF_DEBUG | lwip.LWIP_DBG_LEVEL_SERIOUS,
                      "pbuf_header: failed as {0} < {1} (not enough space for new header size)\n",
                      p.payload, (p + 1));
                    /* restore old payload pointer */
                    p.payload = payload;
                    /* bail out unsuccesfully */
                    return 1;
                }
                /* pbuf types refering to external payloads? */
            }
            else if (type == pbuf_type.PBUF_REF || type == pbuf_type.PBUF_ROM) {
                /* hide a header in the payload? */
                if ((header_size_increment < 0) && (increment_magnitude <= p.len)) {
                    /* increase payload pointer */
                    p.payload = p.payload - header_size_increment;
                }
                else {
                    /* cannot expand payload to front (yet!)
                     * bail out unsuccesfully */
                    return 1;
                }
            }
            else {
                /* Unknown type */
                lwip.LWIP_ASSERT("bad pbuf type", false);
                return 1;
            }
            /* modify pbuf length fields */
            p.len += (ushort)header_size_increment;
            p.tot_len += (ushort)header_size_increment;

            lwip.LWIP_DEBUGF(opt.PBUF_DEBUG | lwip.LWIP_DBG_TRACE, "pbuf_header: old {0} new {1} ({2})\n",
                payload, p.payload, header_size_increment);

            return 0;
        }
Ejemplo n.º 9
0
        /** Compare pbuf contents at specified offset with memory s2, both of length n
         *
         * @param p pbuf to compare
         * @param offset offset into p at wich to start comparing
         * @param s2 buffer to compare
         * @param n length of buffer to compare
         * @return zero if equal, nonzero otherwise
         *         (0xffff if p is too short, diffoffset+1 otherwise)
         */
        public static ushort pbuf_memcmp(pbuf p, ushort offset, pointer s2, ushort n)
        {
            ushort start = offset;
            pbuf q = p;

            /* get the correct pbuf */
            while ((q != null) && (q.len <= start)) {
                start -= q.len;
                q = q.next;
            }
            /* return requested data if pbuf is OK */
            if ((q != null) && (q.len > start)) {
                ushort i;
                for (i = 0; i < n; i++) {
                    byte a = pbuf_get_at(q, (ushort)(start + i));
                    byte b = (s2)[i];
                    if (a != b) {
                        return (ushort)(i + 1);
                    }
                }
                return 0;
            }
            return 0xffff;
        }
Ejemplo n.º 10
0
        /**
         * Copy (part of) the contents of a packet buffer
         * to an application supplied buffer.
         *
         * @param buf the pbuf from which to copy data
         * @param dataptr the application supplied buffer
         * @param len length of data to copy (dataptr must be big enough). No more
         * than buf.tot_len will be copied, irrespective of len
         * @param offset offset into the packet buffer from where to begin copying len bytes
         * @return the number of bytes copied, or 0 on failure
         */
        public static ushort pbuf_copy_partial(pbuf buf, pointer dataptr, ushort len, ushort offset)
        {
            pbuf p;
            ushort left;
            ushort buf_copy_len;
            ushort copied_total = 0;

            if (lwip.LWIP_ERROR("pbuf_copy_partial: invalid buf", (buf != null))) return 0;
            if (lwip.LWIP_ERROR("pbuf_copy_partial: invalid dataptr", (dataptr != null))) return 0;

            left = 0;

            if ((buf == null) || (dataptr == null)) {
                return 0;
            }

            /* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */
            for (p = buf; len != 0 && p != null; p = p.next) {
                if ((offset != 0) && (offset >= p.len)) {
                    /* don't copy from this buffer . on to the next */
                    offset -= p.len;
                }
                else {
                    /* copy from this buffer. maybe only partially. */
                    buf_copy_len = (ushort)(p.len - offset);
                    if (buf_copy_len > len)
                        buf_copy_len = len;
                    /* copy the necessary parts of the buffer */
                    opt.MEMCPY(dataptr + left, p.payload + offset, buf_copy_len);
                    copied_total += buf_copy_len;
                    left += buf_copy_len;
                    len -= buf_copy_len;
                    offset = 0;
                }
            }
            return copied_total;
        }
Ejemplo n.º 11
0
        /** Get one byte from the specified position in a pbuf
         * WARNING: returns zero for offset >= p.tot_len
         *
         * @param p pbuf to parse
         * @param offset offset into p of the byte to return
         * @return byte at an offset into p OR ZERO IF 'offset' >= p.tot_len
         */
        public static byte pbuf_get_at(pbuf p, ushort offset)
        {
            ushort copy_from = offset;
            pbuf q = p;

            /* get the correct pbuf */
            while ((q != null) && (q.len <= copy_from)) {
                copy_from -= q.len;
                q = q.next;
            }
            /* return requested data if pbuf is OK */
            if ((q != null) && (q.len > copy_from)) {
                return (q.payload)[copy_from];
            }
            return 0;
        }
Ejemplo n.º 12
0
        /**
         *
         * Create pbuf_type.PBUF_RAM copies of pbufs.
         *
         * Used to queue packets on behalf of the lwIP stack, such as
         * ARP based queueing.
         *
         * @note You MUST explicitly use p = pbuf_take(p);
         *
         * @note Only one packet is copied, no packet queue!
         *
         * @param p_to pbuf destination of the copy
         * @param p_from pbuf source of the copy
         *
         * @return err_t.ERR_OK if pbuf was copied
         *         err_t.ERR_ARG if one of the pbufs is null or p_to is not big
         *                 enough to hold p_from
         */
        public static err_t pbuf_copy(pbuf p_to, pbuf p_from)
        {
            ushort offset_to = 0, offset_from = 0, len;

            lwip.LWIP_DEBUGF(opt.PBUF_DEBUG | lwip.LWIP_DBG_TRACE, "pbuf_copy({0}, {1})\n",
              p_to, p_from);

            /* is the target big enough to hold the source? */
            if (lwip.LWIP_ERROR("pbuf_copy: target not big enough to hold source", ((p_to != null) &&
                       (p_from != null) && (p_to.tot_len >= p_from.tot_len))))
                return err_t.ERR_ARG;

            /* iterate through pbuf chain */
            do {
                /* copy one part of the original chain */
                if ((p_to.len - offset_to) >= (p_from.len - offset_from)) {
                    /* complete current p_from fits into current p_to */
                    len = (ushort)(p_from.len - offset_from);
                }
                else {
                    /* current p_from does not fit into current p_to */
                    len = (ushort)(p_to.len - offset_to);
                }
                opt.MEMCPY(p_to.payload + offset_to, p_from.payload + offset_from, len);
                offset_to += len;
                offset_from += len;
                lwip.LWIP_ASSERT("offset_to <= p_to.len", offset_to <= p_to.len);
                lwip.LWIP_ASSERT("offset_from <= p_from.len", offset_from <= p_from.len);
                if (offset_from >= p_from.len) {
                    /* on to next p_from (if any) */
                    offset_from = 0;
                    p_from = p_from.next;
                }
                if (offset_to == p_to.len) {
                    /* on to next p_to (if any) */
                    offset_to = 0;
                    p_to = p_to.next;
                    if (lwip.LWIP_ERROR("p_to != null", (p_to != null) || (p_from == null))) return err_t.ERR_ARG;
                }

                if ((p_from != null) && (p_from.len == p_from.tot_len)) {
                    /* don't copy more than one packet! */
                    if (lwip.LWIP_ERROR("pbuf_copy() does not allow packet queues!\n",
                        (p_from.next == null)))
                        return err_t.ERR_VAL;
                }
                if ((p_to != null) && (p_to.len == p_to.tot_len)) {
                    /* don't copy more than one packet! */
                    if (lwip.LWIP_ERROR("pbuf_copy() does not allow packet queues!\n",
                        (p_to.next == null)))
                        return err_t.ERR_VAL;
                }
            } while (p_from != null);
            lwip.LWIP_DEBUGF(opt.PBUF_DEBUG | lwip.LWIP_DBG_TRACE, "pbuf_copy: end of chain reached.\n");
            return err_t.ERR_OK;
        }
Ejemplo n.º 13
0
        /**
         * Count number of pbufs in a chain
         *
         * @param p first pbuf of chain
         * @return the number of pbufs in a chain
         */
        public static byte pbuf_clen(pbuf p)
        {
            byte len;

            len = 0;
            while (p != null) {
                ++len;
                p = p.next;
            }
            return len;
        }
Ejemplo n.º 14
0
        /**
         * Concatenate two pbufs (each may be a pbuf chain) and take over
         * the caller's reference of the tail pbuf.
         *
         * @note The caller MAY NOT reference the tail pbuf afterwards.
         * Use pbuf_chain() for that purpose.
         *
         * @see pbuf_chain()
         */
        public static void pbuf_cat(pbuf h, pbuf t)
        {
            pbuf p;

            if (lwip.LWIP_ERROR("(h != null) && (t != null) (programmer violates API)",
                       ((h != null) && (t != null))))
                return;

            /* proceed to last pbuf of chain */
            for (p = h; p.next != null; p = p.next) {
                /* add total length of second chain to all totals of first chain */
                p.tot_len += t.tot_len;
            }
            /* { p is last pbuf of first h chain, p.next == null } */
            lwip.LWIP_ASSERT("p.tot_len == p.len (of last pbuf in chain)", p.tot_len == p.len);
            lwip.LWIP_ASSERT("p.next == null", p.next == null);
            /* add total length of second chain to last pbuf total of first chain */
            p.tot_len += t.tot_len;
            /* chain last pbuf of head (p) with first of tail (t) */
            p.next = t;
            /* p.next now references t, but the caller will drop its reference to t,
             * so netto there is no change to the reference count of t.
             */
        }
Ejemplo n.º 15
0
        /**
         * Dereference a pbuf chain or queue and deallocate any no-longer-used
         * pbufs at the head of this chain or queue.
         *
         * Decrements the pbuf reference count. If it reaches zero, the pbuf is
         * deallocated.
         *
         * For a pbuf chain, this is repeated for each pbuf in the chain,
         * up to the first pbuf which has a non-zero reference count after
         * decrementing. So, when all reference counts are one, the whole
         * chain is free'd.
         *
         * @param p The pbuf (chain) to be dereferenced.
         *
         * @return the number of pbufs that were de-allocated
         * from the head of the chain.
         *
         * @note MUST NOT be called on a packet queue (Not verified to work yet).
         * @note the reference counter of a pbuf equals the number of pointers
         * that refer to the pbuf (or into the pbuf).
         *
         * @internal examples:
         *
         * Assuming existing chains a.b.c with the following reference
         * counts, calling lwip.pbuf_free(a) results in:
         *
         * 1.2.3 becomes ...1.3
         * 3.3.3 becomes 2.3.3
         * 1.1.2 becomes ......1
         * 2.1.1 becomes 1.1.1
         * 1.1.1 becomes .......
         *
         */
        public byte pbuf_free(pbuf p)
        {
            pbuf_type type;
            pbuf q;
            byte count;

            if (p == null) {
                lwip.LWIP_ASSERT("p != null", p != null);
                /* if assertions are disabled, proceed with debug output */
                lwip.LWIP_DEBUGF(opt.PBUF_DEBUG | lwip.LWIP_DBG_LEVEL_SERIOUS,
                  ("pbuf_free(p == null) was called.\n"));
                return 0;
            }
            lwip.LWIP_DEBUGF(opt.PBUF_DEBUG | lwip.LWIP_DBG_TRACE, "pbuf_free({0})\n", p);

            //PERF_START;

            lwip.LWIP_ASSERT("pbuf_free: sane type",
              p.type == pbuf_type.PBUF_RAM || p.type == pbuf_type.PBUF_ROM ||
              p.type == pbuf_type.PBUF_REF || p.type == pbuf_type.PBUF_POOL);

            count = 0;
            /* de-allocate all consecutive pbufs from the head of the chain that
             * obtain a zero reference count after decrementing*/
            while (p != null) {
                ushort @ref;
                sys.SYS_ARCH_DECL_PROTECT(sys.old_level);
                /* Since decrementing @ref cannot be guaranteed to be a single machine operation
                 * we must protect it. We put the new @ref into a local variable to prevent
                 * further protection. */
                sys.SYS_ARCH_PROTECT(sys.old_level);
                /* all pbufs in a chain are referenced at least once */
                lwip.LWIP_ASSERT("pbuf_free: p.@ref > 0", p.@ref > 0);
                /* decrease reference count (number of pointers to pbuf) */
                @ref = --(p.@ref);
                sys.SYS_ARCH_UNPROTECT(sys.old_level);
                /* this pbuf is no longer referenced to? */
                if (@ref == 0) {
                    /* remember next pbuf in chain for next iteration */
                    q = p.next;
                    lwip.LWIP_DEBUGF(opt.PBUF_DEBUG | lwip.LWIP_DBG_TRACE, "pbuf_free: deallocating {0}\n", p);
                    type = p.type;
            #if LWIP_SUPPORT_CUSTOM_PBUF
                    /* is this a custom pbuf? */
                    if ((p.flags & PBUF_FLAG_IS_CUSTOM) != 0) {
                        pbuf_custom pc = (pbuf_custom)p;
                        lwip.LWIP_ASSERT("pc.custom_free_function != null", pc.custom_free_function != null);
                        pc.custom_free_function(p);
                    } else
            #endif // LWIP_SUPPORT_CUSTOM_PBUF
                    {
                        /* is this a pbuf from the pool? */
                        if (type == pbuf_type.PBUF_POOL) {
                            memp_free(mempb_t.MEMP_PBUF_POOL, p);
                            /* is this a ROM or RAM referencing pbuf? */
                        }
                        else if (type == pbuf_type.PBUF_ROM || type == pbuf_type.PBUF_REF) {
                            memp_free(mempb_t.MEMP_PBUF, p);
                            /* type == pbuf_type.PBUF_RAM */
                        }
                        else {
                            mem_free(p);
                        }
                    }
                    count++;
                    /* proceed to next pbuf */
                    p = q;
                    /* p.@ref > 0, this pbuf is still referenced to */
                    /* (and so the remaining pbufs in chain as well) */
                }
                else {
                    lwip.LWIP_DEBUGF(opt.PBUF_DEBUG | lwip.LWIP_DBG_TRACE, "pbuf_free: {0} has @ref {1}, ending here.\n", p, @ref);
                    /* stop walking through the chain */
                    p = null;
                }
            }
            //PERF_STOP("pbuf_free");
            /* return number of de-allocated pbufs */
            return count;
        }
Ejemplo n.º 16
0
 /** Find occurrence of mem (with length mem_len) in pbuf p, starting at offset
  * start_offset.
  *
  * @param p pbuf to search, maximum length is 0xFFFE since 0xFFFF is used as
  *        return value 'not found'
  * @param mem search for the contents of this buffer
  * @param mem_len length of 'mem'
  * @param start_offset offset into p at which to start searching
  * @return 0xFFFF if substr was not found in p or the index where it was found
  */
 public static ushort pbuf_memfind(pbuf p, pointer mem, ushort mem_len, ushort start_offset)
 {
     ushort i;
     ushort max = (ushort)(p.tot_len - mem_len);
     if (p.tot_len >= mem_len + start_offset) {
         for (i = start_offset; i <= max;) {
             ushort plus = pbuf_memcmp(p, i, mem, mem_len);
             if (plus == 0) {
                 return i;
             }
             else {
                 i += plus;
             }
         }
     }
     return 0xFFFF;
 }
Ejemplo n.º 17
0
 public err_t lwip_tcp_event(object arg, tcp_pcb pcb, lwip_event e, pbuf p, ushort size, err_t err)
 {
     return _lwip_tcp_event(arg, pcb, e, p, size, err);
 }
Ejemplo n.º 18
0
 /** Find occurrence of substr with length substr_len in pbuf p, start at offset
  * start_offset
  * WARNING: in contrast to strstr(), this one does not stop at the first \0 in
  * the pbuf/source pointer!
  *
  * @param p pbuf to search, maximum length is 0xFFFE since 0xFFFF is used as
  *        return value 'not found'
  * @param substr pointer to search for in p, maximum length is 0xFFFE
  * @return 0xFFFF if substr was not found in p or the index where it was found
  */
 public static ushort pbuf_strstr(pbuf p, pointer substr)
 {
     int substr_len;
     if ((substr == null) || (substr[0] == 0) || (p.tot_len == 0xFFFF)) {
         return 0xFFFF;
     }
     substr_len = pointer.strlen(substr);
     if (substr_len >= 0xFFFF) {
         return 0xFFFF;
     }
     return pbuf_memfind(p, substr, (ushort)substr_len, 0);
 }
Ejemplo n.º 19
0
		/* lwip.inet_chksum_pseudo:
		 *
		 * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.
		 * IP addresses are expected to be in network byte order.
		 *
		 * @param p chain of pbufs over that a checksum should be calculated (ip data part)
		 * @param src source ip address (used for checksum of pseudo header)
		 * @param dst destination ip address (used for checksum of pseudo header)
		 * @param proto ip protocol (used for checksum of pseudo header)
		 * @param proto_len length of the ip data part (used for checksum of pseudo header)
		 * @return checksum (as ushort) to be saved directly in the protocol header
		 */
		public static ushort inet_chksum_pseudo_partial(pbuf p,
			   ip_addr src, ip_addr dest,
			   byte proto, ushort proto_len, ushort chksum_len)
		{
			uint acc;
			uint addr;
			pbuf q;
			byte swapped;
			ushort chklen;

			acc = 0;
			swapped = 0;
			/* iterate through all pbuf in chain */
			for (q = p; (q != null) && (chksum_len > 0); q = q.next) {
				lwip.LWIP_DEBUGF(opt.INET_DEBUG, "inet_chksum_pseudo(): checksumming pbuf {0} (has next {1}) \n",
					q, q.next);
				chklen = q.len;
				if (chklen > chksum_len) {
					chklen = chksum_len;
				}
				acc += LWIP_CHKSUM(q.payload, chklen);
				chksum_len -= chklen;
				lwip.LWIP_ASSERT("delete me", chksum_len < 0x7fff);
				/*lwip.LWIP_DEBUGF(opt.INET_DEBUG, "inet_chksum_pseudo(): unwrapped lwip_chksum()={0} \n", acc);*/
				/* fold the upper bit down */
				acc = FOLD_U32T(acc);
				if (q.len % 2 != 0) {
					swapped = (byte)(1 - swapped);
					acc = SWAP_BYTES_IN_WORD((ushort)acc);
				}
				/*lwip.LWIP_DEBUGF(opt.INET_DEBUG, "inet_chksum_pseudo(): wrapped lwip_chksum()={0} \n", acc);*/
			}

			if (swapped != 0) {
				acc = SWAP_BYTES_IN_WORD((ushort)acc);
			}
			addr = ip_addr.ip4_addr_get_u32(src);
			acc += (addr & 0xffffU);
			acc += ((addr >> 16) & 0xffffU);
			addr = ip_addr.ip4_addr_get_u32(dest);
			acc += (addr & 0xffffU);
			acc += ((addr >> 16) & 0xffffU);
			acc += (uint)lwip.lwip_htons((ushort)proto);
			acc += (uint)lwip.lwip_htons(proto_len);

			/* Fold 32-bit sum to 16 bits
			   calling this twice is propably faster than if statements... */
			acc = FOLD_U32T(acc);
			acc = FOLD_U32T(acc);
			lwip.LWIP_DEBUGF(opt.INET_DEBUG, "inet_chksum_pseudo(): pbuf chain lwip_chksum()={0}\n", acc);
			return (ushort)~(acc & 0xffffUL);
		}
Ejemplo n.º 20
0
        /**
         * Copy application supplied data into a pbuf.
         * This function can only be used to copy the equivalent of buf.tot_len data.
         *
         * @param buf pbuf to fill with data
         * @param dataptr application supplied data buffer
         * @param len length of the application supplied data buffer
         *
         * @return err_t.ERR_OK if successful, err_t.ERR_MEM if the pbuf is not big enough
         */
        public static err_t pbuf_take(pbuf buf, pointer dataptr, ushort len)
        {
            pbuf p;
            ushort buf_copy_len;
            ushort total_copy_len = len;
            ushort copied_total = 0;

            if (lwip.LWIP_ERROR("pbuf_take: invalid buf", (buf != null))) return 0;
            if (lwip.LWIP_ERROR("pbuf_take: invalid dataptr", (dataptr != null))) return 0;

            if ((buf == null) || (dataptr == null) || (buf.tot_len < len)) {
                return err_t.ERR_ARG;
            }

            /* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */
            for (p = buf; total_copy_len != 0; p = p.next) {
                lwip.LWIP_ASSERT("pbuf_take: invalid pbuf", p != null);
                buf_copy_len = total_copy_len;
                if (buf_copy_len > p.len) {
                    /* this pbuf cannot hold all remaining data */
                    buf_copy_len = p.len;
                }
                /* copy the necessary parts of the buffer */
                opt.MEMCPY(p.payload, dataptr + copied_total, buf_copy_len);
                total_copy_len -= buf_copy_len;
                copied_total += buf_copy_len;
            }
            lwip.LWIP_ASSERT("did not copy all data", total_copy_len == 0 && copied_total == len);
            return err_t.ERR_OK;
        }
Ejemplo n.º 21
0
		public static ushort inet6_chksum_pseudo(pbuf p, ip6_addr src, ip6_addr dest, byte proto, ushort proto_len)
		{
			uint acc;
			pbuf q;
			byte swapped;

			acc = 0;
			swapped = 0;
			/* iterate through all pbuf in chain */
			for (q = p; q != null; q = q.next) {
				lwip.LWIP_DEBUGF(opt.INET_DEBUG, "_inet_chksum.inet_chksum_pseudo(): checksumming pbuf {0} (has next {1}) \n",
					q.GetHashCode(), q.next == null ? 0 : q.next.GetHashCode());
				acc += LWIP_CHKSUM(q, q.len);
				/*lwip.LWIP_DEBUGF(opt.INET_DEBUG, "_inet_chksum.inet_chksum_pseudo(): unwrapped lwip_chksum()={0} \n", acc);*/
				/* just executing this next line is probably faster that the if statement needed
				   to check whether we really need to execute it, and does no harm */
				acc = FOLD_U32T(acc);
				if (q.len % 2 != 0) {
					swapped = (byte)(1 - swapped);
					acc = SWAP_BYTES_IN_WORD((ushort)acc);
				}
				/*lwip.LWIP_DEBUGF(opt.INET_DEBUG, "_inet_chksum.inet_chksum_pseudo(): wrapped lwip_chksum()={0} \n", acc);*/
			}

			if (swapped != 0) {
				acc = SWAP_BYTES_IN_WORD((ushort)acc);
			}
			for (int i = 0; i < 8; i++) {
				acc += lwip_htons(src.saddr[i]);
				acc += lwip_htons(dest.saddr[i]);
				while ((acc >> 16) != 0) {
					acc = (acc & 0xffff) + (acc >> 16);
				}
			}
			acc += (uint)lwip_htons((ushort)proto);
			acc += (uint)lwip_htons(proto_len);

			/* Fold 32-bit sum to 16 bits
			   calling this twice is propably faster than if statements... */
			acc = FOLD_U32T(acc);
			acc = FOLD_U32T(acc);
			lwip.LWIP_DEBUGF(opt.INET_DEBUG, "_inet_chksum.inet_chksum_pseudo(): pbuf chain lwip_chksum()={0}\n", acc);
			return (ushort)~(acc & 0xffffU);
		}
Ejemplo n.º 22
0
        /**
         * Allocates a pbuf of the given type (possibly a chain for pbuf_type.PBUF_POOL type).
         *
         * The actual memory allocated for the pbuf is determined by the
         * layer at which the pbuf is allocated and the requested size
         * (from the size parameter).
         *
         * @param layer flag to define header size
         * @param length size of the pbuf's payload
         * @param type this parameter decides how and where the pbuf
         * should be allocated as follows:
         *
         * - pbuf_type.PBUF_RAM: buffer memory for pbuf is allocated as one large
         *             chunk. This includes protocol headers as well.
         * - pbuf_type.PBUF_ROM: no buffer memory is allocated for the pbuf, even for
         *             protocol headers. Additional headers must be prepended
         *             by allocating another pbuf and chain in to the front of
         *             the ROM pbuf. It is assumed that the memory used is really
         *             similar to ROM in that it is immutable and will not be
         *             changed. Memory which is dynamic should generally not
         *             be attached to pbuf_type.PBUF_ROM pbufs. Use pbuf_type.PBUF_REF instead.
         * - pbuf_type.PBUF_REF: no buffer memory is allocated for the pbuf, even for
         *             protocol headers. It is assumed that the pbuf is only
         *             being used in a single thread. If the pbuf gets queued,
         *             then pbuf_take should be called to copy the buffer.
         * - pbuf_type.PBUF_POOL: the pbuf is allocated as a pbuf chain, with pbufs from
         *              the pbuf pool that is allocated during pbuf_init().
         *
         * @return the allocated pbuf. If multiple pbufs where allocated, this
         * is the first pbuf of a pbuf chain.
         */
        public pbuf pbuf_alloc(pbuf_layer layer, ushort length, pbuf_type type)
        {
            pbuf p, q, r;
            ushort offset;
            int rem_len; /* remaining length */
            lwip.LWIP_DEBUGF(opt.PBUF_DEBUG | lwip.LWIP_DBG_TRACE, "pbuf_alloc(length={0})\n", length);

            /* determine header offset */
            switch (layer) {
            case pbuf_layer.PBUF_TRANSPORT:
                /* add room for transport (often TCP) layer header */
                offset = opt.PBUF_LINK_HLEN + pbuf.PBUF_IP_HLEN + pbuf.PBUF_TRANSPORT_HLEN;
                break;
            case pbuf_layer.PBUF_IP:
                /* add room for IP layer header */
                offset = opt.PBUF_LINK_HLEN + pbuf.PBUF_IP_HLEN;
                break;
            case pbuf_layer.PBUF_LINK:
                /* add room for link layer header */
                offset = opt.PBUF_LINK_HLEN;
                break;
            case pbuf_layer.PBUF_RAW:
                offset = 0;
                break;
            default:
                lwip.LWIP_ASSERT("pbuf_alloc: bad pbuf layer", false);
                return null;
            }

            switch (type) {
            case pbuf_type.PBUF_POOL:
                /* allocate head of pbuf chain into p */
                p = new pbuf(this, memp_malloc(mempb_t.MEMP_PBUF_POOL));
                lwip.LWIP_DEBUGF(opt.PBUF_DEBUG | lwip.LWIP_DBG_TRACE, "pbuf_alloc: allocated pbuf {0}\n", p);
                if (p == null) {
                    PBUF_POOL_IS_EMPTY();
                    return null;
                }
                p.type = type;
                p.next = null;

                /* make the payload pointer point 'offset' bytes into pbuf data memory */
                p.payload = lwip.LWIP_MEM_ALIGN((p + (pbuf.SIZEOF_STRUCT_PBUF + offset)));
                lwip.LWIP_ASSERT("pbuf_alloc: pbuf p.payload properly aligned",
                        (p.payload.offset % opt.MEM_ALIGNMENT) == 0);
                /* the total length of the pbuf chain is the requested size */
                p.tot_len = length;
                /* set the length of the first pbuf in the chain */
                p.len = Math.Min(length, (ushort)(pbuf.PBUF_POOL_BUFSIZE_ALIGNED - lwip.LWIP_MEM_ALIGN_SIZE(offset)));
                lwip.LWIP_ASSERT("check p.payload + p.len does not overflow pbuf",
                            (p.payload + p.len <=
                             p + pbuf.SIZEOF_STRUCT_PBUF + pbuf.PBUF_POOL_BUFSIZE_ALIGNED));
                lwip.LWIP_ASSERT("PBUF_POOL_BUFSIZE must be bigger than opt.MEM_ALIGNMENT",
                  (pbuf.PBUF_POOL_BUFSIZE_ALIGNED - lwip.LWIP_MEM_ALIGN_SIZE(offset)) > 0);
                /* set reference count (needed here in case we fail) */
                p.@ref = 1;

                /* now allocate the tail of the pbuf chain */

                /* remember first pbuf for linkage in next iteration */
                r = p;
                /* remaining length to be allocated */
                rem_len = length - p.len;
                /* any remaining pbufs to be allocated? */
                while (rem_len > 0) {
                    q = new pbuf(this, memp_malloc(mempb_t.MEMP_PBUF_POOL));
                    if (q == null) {
                        PBUF_POOL_IS_EMPTY();
                        /* free chain so far allocated */
                        pbuf_free(p);
                        /* bail out unsuccesfully */
                        return null;
                    }
                    q.type = type;
                    q.flags = 0;
                    q.next = null;
                    /* make previous pbuf point to this pbuf */
                    r.next = q;
                    /* set total length of this pbuf and next in chain */
                    lwip.LWIP_ASSERT("rem_len < max_u16_t", rem_len < 0xffff);
                    q.tot_len = (ushort)rem_len;
                    /* this pbuf length is pool size, unless smaller sized tail */
                    q.len = Math.Min((ushort)rem_len, (ushort)pbuf.PBUF_POOL_BUFSIZE_ALIGNED);
                    q.payload = (q + pbuf.SIZEOF_STRUCT_PBUF);
                    lwip.LWIP_ASSERT("pbuf_alloc: pbuf q.payload properly aligned",
                            (q.payload.offset % opt.MEM_ALIGNMENT) == 0);
                    lwip.LWIP_ASSERT("check p.payload + p.len does not overflow pbuf",
                                (p.payload + p.len <=
                                 p + pbuf.SIZEOF_STRUCT_PBUF + pbuf.PBUF_POOL_BUFSIZE_ALIGNED));
                    q.@ref = 1;
                    /* calculate remaining length to be allocated */
                    rem_len -= q.len;
                    /* remember this pbuf for linkage in next iteration */
                    r = q;
                }
                /* end of chain */
                /*r.next = null;*/

                break;
            case pbuf_type.PBUF_RAM:
                /* If pbuf is to be allocated in RAM, allocate memory for it. */
                p = new pbuf(this, mem_malloc(lwip.LWIP_MEM_ALIGN_SIZE((ushort)(pbuf.SIZEOF_STRUCT_PBUF + offset)) + lwip.LWIP_MEM_ALIGN_SIZE(length)));
                if (p == null) {
                    return null;
                }
                /* Set up internal structure of the pbuf. */
                p.payload = lwip.LWIP_MEM_ALIGN((p + pbuf.SIZEOF_STRUCT_PBUF + offset));
                p.len = p.tot_len = length;
                p.next = null;
                p.type = type;

                lwip.LWIP_ASSERT("pbuf_alloc: pbuf.payload properly aligned",
                       (p.payload.offset % opt.MEM_ALIGNMENT) == 0);
                break;
            /* pbuf references existing (non-volatile static constant) ROM payload? */
            case pbuf_type.PBUF_ROM:
            /* pbuf references existing (externally allocated) RAM payload? */
            case pbuf_type.PBUF_REF:
                /* only allocate memory for the pbuf structure */
                p = new pbuf(this, memp_malloc(mempb_t.MEMP_PBUF));
                if (p == null) {
                    lwip.LWIP_DEBUGF(opt.PBUF_DEBUG | lwip.LWIP_DBG_LEVEL_SERIOUS,
                                "pbuf_alloc: Could not allocate MEMP_PBUF for PBUF_{0}.\n",
                                (type == pbuf_type.PBUF_ROM) ? "ROM" : "REF");
                    return null;
                }
                /* caller must set this field properly, afterwards */
                p.payload = null;
                p.len = p.tot_len = length;
                p.next = null;
                p.type = type;
                break;
            default:
                lwip.LWIP_ASSERT("pbuf_alloc: erroneous type", false);
                return null;
            }
            /* set reference count */
            p.@ref = 1;
            /* set flags */
            p.flags = 0;
            lwip.LWIP_DEBUGF(opt.PBUF_DEBUG | lwip.LWIP_DBG_TRACE, "pbuf_alloc(length={0}) == {1}\n", length, p);
            return p;
        }
Ejemplo n.º 23
0
        /**
         * Called by tcp_process. Checks if the given segment is an ACK for outstanding
         * data, and if so frees the memory of the buffered data. Next, is places the
         * segment on any of the receive queues (pcb.recved or pcb.ooseq). If the segment
         * is buffered, the pbuf is referenced by lwip.pbuf_ref so that it will not be freed until
         * it has been removed from the buffer.
         *
         * If the incoming segment constitutes an ACK for a segment that was used for RTT
         * estimation, the RTT is estimated here as well.
         *
         * Called from tcp_process().
         */
        private void tcp_receive(tcp_pcb pcb)
        {
            tcp_seg next;
            #if TCP_QUEUE_OOSEQ
            tcp_seg prev, cseg;
            #endif // TCP_QUEUE_OOSEQ
            pbuf p;
            int off;
            short m;
            uint right_wnd_edge;
            ushort new_tot_len;
            int found_dupack = 0;
            #if TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS
            uint ooseq_blen;
            ushort ooseq_qlen;
            #endif // TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS

            lwip.LWIP_ASSERT("tcp_receive: wrong state", pcb.state >= tcp_state.ESTABLISHED);

            if ((flags & tcp.TCP_ACK) != 0) {
                right_wnd_edge = pcb.snd_wnd + pcb.snd_wl2;

                /* Update window. */
                if (tcp.TCP_SEQ_LT(pcb.snd_wl1, seqno) ||
                    (pcb.snd_wl1 == seqno && tcp.TCP_SEQ_LT(pcb.snd_wl2, ackno)) ||
                    (pcb.snd_wl2 == ackno && tcphdr.wnd > pcb.snd_wnd)) {
                    pcb.snd_wnd = tcphdr.wnd;
                    /* keep track of the biggest window announced by the remote host to calculate
                       the maximum segment size */
                    if (pcb.snd_wnd_max < tcphdr.wnd) {
                        pcb.snd_wnd_max = tcphdr.wnd;
                    }
                    pcb.snd_wl1 = seqno;
                    pcb.snd_wl2 = ackno;
                    if (pcb.snd_wnd == 0) {
                        if (pcb.persist_backoff == 0) {
                            /* start persist timer */
                            pcb.persist_cnt = 0;
                            pcb.persist_backoff = 1;
                        }
                    }
                    else if (pcb.persist_backoff > 0) {
                        /* stop persist timer */
                        pcb.persist_backoff = 0;
                    }
                    lwip.LWIP_DEBUGF(opt.TCP_WND_DEBUG, "tcp_receive: window update {0}\n", pcb.snd_wnd);
            #if TCP_WND_DEBUG
                }
                else {
                    if (pcb.snd_wnd != tcphdr.wnd) {
                        lwip.LWIP_DEBUGF(opt.TCP_WND_DEBUG,
                                    "tcp_receive: no window update lastack {0} ackno {1} wl1 {2} seqno {3} wl2 {4}\n",
                                     pcb.lastack, ackno, pcb.snd_wl1, seqno, pcb.snd_wl2);
                    }
            #endif // TCP_WND_DEBUG
                }

                /* (From Stevens TCP/IP Illustrated Vol II, p970.) Its only a
                 * duplicate ack if:
                 * 1) It doesn't ACK new data
                 * 2) length of received packet is zero (i.e. no payload)
                 * 3) the advertised window hasn't changed
                 * 4) There is outstanding unacknowledged data (retransmission timer running)
                 * 5) The ACK is == biggest ACK sequence number so far seen (snd_una)
                 *
                 * If it passes all five, should process as a dupack:
                 * a) dupacks < 3: do nothing
                 * b) dupacks == 3: fast retransmit
                 * c) dupacks > 3: increase cwnd
                 *
                 * If it only passes 1-3, should reset dupack counter (and add to
                 * stats, which we don't do in lwIP)
                 *
                 * If it only passes 1, should reset dupack counter
                 *
                 */

                /* Clause 1 */
                if (tcp.TCP_SEQ_LEQ(ackno, pcb.lastack)) {
                    pcb.acked = 0;
                    /* Clause 2 */
                    if (tcplen == 0) {
                        /* Clause 3 */
                        if (pcb.snd_wl2 + pcb.snd_wnd == right_wnd_edge) {
                            /* Clause 4 */
                            if (pcb.rtime >= 0) {
                                /* Clause 5 */
                                if (pcb.lastack == ackno) {
                                    found_dupack = 1;
                                    if ((byte)(pcb.dupacks + 1) > pcb.dupacks) {
                                        ++pcb.dupacks;
                                    }
                                    if (pcb.dupacks > 3) {
                                        /* Inflate the congestion window, but not if it means that
                                           the value overflows. */
                                        if ((ushort)(pcb.cwnd + pcb.mss) > pcb.cwnd) {
                                            pcb.cwnd += pcb.mss;
                                        }
                                    }
                                    else if (pcb.dupacks == 3) {
                                        /* Do fast retransmit */
                                        tcp.tcp_rexmit_fast(pcb);
                                    }
                                }
                            }
                        }
                    }
                    /* If Clause (1) or more is true, but not a duplicate ack, reset
                     * count of consecutive duplicate acks */
                    if (found_dupack == 0) {
                        pcb.dupacks = 0;
                    }
                }
                else if (tcp.TCP_SEQ_BETWEEN(ackno, pcb.lastack + 1, pcb.snd_nxt)) {
                    /* We come here when the ACK acknowledges new data. */

                    /* Reset the "IN Fast Retransmit" flag, since we are no longer
                       in fast retransmit. Also reset the congestion window to the
                       slow start threshold. */
                    if ((pcb.flags & tcp_pcb.TF_INFR) != 0) {
                        pcb.flags &= unchecked((byte)~tcp_pcb.TF_INFR);
                        pcb.cwnd = pcb.ssthresh;
                    }

                    /* Reset the number of retransmissions. */
                    pcb.nrtx = 0;

                    /* Reset the retransmission time-out. */
                    pcb.rto = (short)((pcb.sa >> 3) + pcb.sv);

                    /* Update the send buffer space. Diff between the two can never exceed 64K? */
                    pcb.acked = (ushort)(ackno - pcb.lastack);

                    pcb.snd_buf += pcb.acked;

                    /* Reset the fast retransmit variables. */
                    pcb.dupacks = 0;
                    pcb.lastack = ackno;

                    /* Update the congestion control variables (cwnd and
                       ssthresh). */
                    if (pcb.state >= tcp_state.ESTABLISHED) {
                        if (pcb.cwnd < pcb.ssthresh) {
                            if ((ushort)(pcb.cwnd + pcb.mss) > pcb.cwnd) {
                                pcb.cwnd += pcb.mss;
                            }
                            lwip.LWIP_DEBUGF(opt.TCP_CWND_DEBUG, "tcp_receive: slow start cwnd {0}\n", pcb.cwnd);
                        }
                        else {
                            ushort new_cwnd = (ushort)(pcb.cwnd + pcb.mss * pcb.mss / pcb.cwnd);
                            if (new_cwnd > pcb.cwnd) {
                                pcb.cwnd = new_cwnd;
                            }
                            lwip.LWIP_DEBUGF(opt.TCP_CWND_DEBUG, "tcp_receive: congestion avoidance cwnd {0}\n", pcb.cwnd);
                        }
                    }
                    lwip.LWIP_DEBUGF(opt.TCP_INPUT_DEBUG, "tcp_receive: ACK for {0}, unacked.seqno {1}:{2}\n",
                                                  ackno,
                                                  pcb.unacked != null ?
                                                  lwip.lwip_ntohl(pcb.unacked.tcphdr.seqno) : 0,
                                                  pcb.unacked != null ?
                                                  lwip.lwip_ntohl(pcb.unacked.tcphdr.seqno) + tcp_hdr.TCP_TCPLEN(pcb.unacked) : 0);

                    /* Remove segment from the unacknowledged list if the incoming
                       ACK acknowlegdes them. */
                    while (pcb.unacked != null &&
                           tcp.TCP_SEQ_LEQ(lwip.lwip_ntohl(pcb.unacked.tcphdr.seqno) +
                                       (uint)tcp_hdr.TCP_TCPLEN(pcb.unacked), ackno)) {
                        lwip.LWIP_DEBUGF(opt.TCP_INPUT_DEBUG, "tcp_receive: removing {0}:{1} from pcb.unacked\n",
                                                      lwip.lwip_ntohl(pcb.unacked.tcphdr.seqno),
                                                      lwip.lwip_ntohl(pcb.unacked.tcphdr.seqno) +
                                                      tcp_hdr.TCP_TCPLEN(pcb.unacked));

                        next = pcb.unacked;
                        pcb.unacked = pcb.unacked.next;

                        lwip.LWIP_DEBUGF(opt.TCP_QLEN_DEBUG, "tcp_receive: queuelen {0} ... ", (ushort)pcb.snd_queuelen);
                        lwip.LWIP_ASSERT("pcb.snd_queuelen >= pbuf_clen(next.p)", (pcb.snd_queuelen >= lwip.pbuf_clen(next.p)));
                        /* Prevent ACK for FIN to generate a sent event */
                        if ((pcb.acked != 0) && ((tcp_hdr.TCPH_FLAGS(next.tcphdr) & tcp.TCP_FIN) != 0)) {
                            pcb.acked--;
                        }

                        pcb.snd_queuelen -= lwip.pbuf_clen(next.p);
                        tcp_seg_free(next);

                        lwip.LWIP_DEBUGF(opt.TCP_QLEN_DEBUG, "{0} (after freeing unacked)\n", (ushort)pcb.snd_queuelen);
                        if (pcb.snd_queuelen != 0) {
                            lwip.LWIP_ASSERT("tcp_receive: valid queue length", pcb.unacked != null ||
                                        pcb.unsent != null);
                        }
                    }

                    /* If there's nothing left to acknowledge, stop the retransmit
                       timer, otherwise reset it to start again */
                    if (pcb.unacked == null)
                        pcb.rtime = -1;
                    else
                        pcb.rtime = 0;

                    pcb.polltmr = 0;
                }
                else {
                    /* Fix bug bug #21582: out of sequence ACK, didn't really ack anything */
                    pcb.acked = 0;
                }

                /* We go through the .unsent list to see if any of the segments
                   on the list are acknowledged by the ACK. This may seem
                   strange since an "unsent" segment shouldn't be acked. The
                   rationale is that lwIP puts all outstanding segments on the
                   .unsent list after a retransmission, so these segments may
                   in fact have been sent once. */
                while (pcb.unsent != null &&
                       tcp.TCP_SEQ_BETWEEN(ackno, lwip.lwip_ntohl(pcb.unsent.tcphdr.seqno) +
                                       (uint)tcp_hdr.TCP_TCPLEN(pcb.unsent), pcb.snd_nxt)) {
                    lwip.LWIP_DEBUGF(opt.TCP_INPUT_DEBUG, "tcp_receive: removing %{0}:{1} from pcb.unsent\n",
                                                  lwip.lwip_ntohl(pcb.unsent.tcphdr.seqno), lwip.lwip_ntohl(pcb.unsent.tcphdr.seqno) +
                                                  tcp_hdr.TCP_TCPLEN(pcb.unsent));

                    next = pcb.unsent;
                    pcb.unsent = pcb.unsent.next;
            #if TCP_OVERSIZE
                    if (pcb.unsent == null) {
                        pcb.unsent_oversize = 0;
                    }
            #endif // TCP_OVERSIZE
                    lwip.LWIP_DEBUGF(opt.TCP_QLEN_DEBUG, "tcp_receive: queuelen {0} ... ", (ushort)pcb.snd_queuelen);
                    lwip.LWIP_ASSERT("pcb.snd_queuelen >= pbuf_clen(next.p)", (pcb.snd_queuelen >= lwip.pbuf_clen(next.p)));
                    /* Prevent ACK for FIN to generate a sent event */
                    if ((pcb.acked != 0) && ((tcp_hdr.TCPH_FLAGS(next.tcphdr) & tcp.TCP_FIN) != 0)) {
                        pcb.acked--;
                    }
                    pcb.snd_queuelen -= lwip.pbuf_clen(next.p);
                    tcp_seg_free(next);
                    lwip.LWIP_DEBUGF(opt.TCP_QLEN_DEBUG, "{0} (after freeing unsent)\n", (ushort)pcb.snd_queuelen);
                    if (pcb.snd_queuelen != 0) {
                        lwip.LWIP_ASSERT("tcp_receive: valid queue length",
                          pcb.unacked != null || pcb.unsent != null);
                    }
                }
                /* End of ACK for new data processing. */

                lwip.LWIP_DEBUGF(opt.TCP_RTO_DEBUG, "tcp_receive: pcb.rttest {0} rtseq {1} ackno {2}\n",
                                            pcb.rttest, pcb.rtseq, ackno);

                /* RTT estimation calculations. This is done by checking if the
                   incoming segment acknowledges the segment we use to take a
                   round-trip time measurement. */
                if (pcb.rttest != 0 && tcp.TCP_SEQ_LT(pcb.rtseq, ackno)) {
                    /* diff between this shouldn't exceed 32K since this are tcp timer ticks
                       and a round-trip shouldn't be that long... */
                    m = (short)(tcp_ticks - pcb.rttest);

                    lwip.LWIP_DEBUGF(opt.TCP_RTO_DEBUG, "tcp_receive: experienced rtt {0} ticks ({1} msec).\n",
                                                m, m * tcp.TCP_SLOW_INTERVAL);

                    /* This is taken directly from VJs original code in his paper */
                    m = (short)(m - (pcb.sa >> 3));
                    pcb.sa += m;
                    if (m < 0) {
                        m = (short)-m;
                    }
                    m = (short)(m - (pcb.sv >> 2));
                    pcb.sv += m;
                    pcb.rto = (short)((pcb.sa >> 3) + pcb.sv);

                    lwip.LWIP_DEBUGF(opt.TCP_RTO_DEBUG, "tcp_receive: RTO {0} ({1} milliseconds)\n",
                                                pcb.rto, pcb.rto * tcp.TCP_SLOW_INTERVAL);

                    pcb.rttest = 0;
                }
            }

            /* If the incoming segment contains data, we must process it
               further unless the pcb already received a FIN.
               (RFC 793, chapeter 3.9, "SEGMENT ARRIVES" in states CLOSE-WAIT, tcp_state.CLOSING,
               LAST-ACK and TIME-WAIT: "Ignore the segment text.") */
            if ((tcplen > 0) && (pcb.state < tcp_state.CLOSE_WAIT)) {
                /* This code basically does three things:

                +) If the incoming segment contains data that is the next
                in-sequence data, this data is passed to the application. This
                might involve trimming the first edge of the data. The rcv_nxt
                variable and the advertised window are adjusted.

                +) If the incoming segment has data that is above the next
                sequence number expected (.rcv_nxt), the segment is placed on
                the .ooseq queue. This is done by finding the appropriate
                place in the .ooseq queue (which is ordered by sequence
                number) and trim the segment in both ends if needed. An
                immediate ACK is sent to indicate that we received an
                out-of-sequence segment.

                +) Finally, we check if the first segment on the .ooseq queue
                now is in sequence (i.e., if rcv_nxt >= ooseq.seqno). If
                rcv_nxt > ooseq.seqno, we must trim the first edge of the
                segment on .ooseq before we adjust rcv_nxt. The data in the
                segments that are now on sequence are chained onto the
                incoming segment so that we only need to call the application
                once.
                */

                /* First, we check if we must trim the first edge. We have to do
                   this if the sequence number of the incoming segment is less
                   than rcv_nxt, and the sequence number plus the length of the
                   segment is larger than rcv_nxt. */
                /*    if (tcp.TCP_SEQ_LT(seqno, pcb.rcv_nxt)){
                      if (tcp.TCP_SEQ_LT(pcb.rcv_nxt, seqno + tcplen)) {*/
                if (tcp.TCP_SEQ_BETWEEN(pcb.rcv_nxt, seqno + 1, seqno + tcplen - 1)) {
                    /* Trimming the first edge is done by pushing the payload
                       pointer in the pbuf downwards. This is somewhat tricky since
                       we do not want to discard the full contents of the pbuf up to
                       the new starting point of the data since we have to keep the
                       TCP header which is present in the first pbuf in the chain.

                       What is done is really quite a nasty hack: the first pbuf in
                       the pbuf chain is pointed to by inseg.p. Since we need to be
                       able to deallocate the whole pbuf, we cannot change this
                       inseg.p pointer to point to any of the later pbufs in the
                       chain. Instead, we point the .payload pointer in the first
                       pbuf to data in one of the later pbufs. We also set the
                       inseg.data pointer to point to the right place. This way, the
                       .p pointer will still point to the first pbuf, but the
                       .p.payload pointer will point to data in another pbuf.

                       After we are done with adjusting the pbuf pointers we must
                       adjust the .data pointer in the seg and the segment
                       length.*/

                    off = (int)(pcb.rcv_nxt - seqno);
                    p = inseg.p;
                    lwip.LWIP_ASSERT("inseg.p != null", inseg.p != null);
                    lwip.LWIP_ASSERT("insane offset!", (off < 0x7fff));
                    if (inseg.p.len < off) {
                        lwip.LWIP_ASSERT("pbuf too short!", (((int)inseg.p.tot_len) >= off));
                        new_tot_len = (ushort)(inseg.p.tot_len - off);
                        while (p.len < off) {
                            off -= p.len;
                            /* KJM following line changed (with addition of new_tot_len var)
                               to fix bug #9076
                               inseg.p.tot_len -= p.len; */
                            p.tot_len = new_tot_len;
                            p.len = 0;
                            p = p.next;
                        }
                        if (lwip.pbuf_header(p, (short)-off) != 0) {
                            /* Do we need to cope with this failing?  Assert for now */
                            lwip.LWIP_ASSERT("pbuf_header failed", false);
                        }
                    }
                    else {
                        if (lwip.pbuf_header(inseg.p, (short)-off) != 0) {
                            /* Do we need to cope with this failing?  Assert for now */
                            lwip.LWIP_ASSERT("pbuf_header failed", false);
                        }
                    }
                    inseg.len -= (ushort)(pcb.rcv_nxt - seqno);
                    inseg.tcphdr.seqno = seqno = pcb.rcv_nxt;
                }
                else {
                    if (tcp.TCP_SEQ_LT(seqno, pcb.rcv_nxt)) {
                        /* the whole segment is < rcv_nxt */
                        /* must be a duplicate of a packet that has already been correctly handled */

                        lwip.LWIP_DEBUGF(opt.TCP_INPUT_DEBUG, "tcp_receive: duplicate seqno {0}\n", seqno);
                        tcp.tcp_ack_now(pcb);
                    }
                }

                /* The sequence number must be within the window (above rcv_nxt
                   and below rcv_nxt + rcv_wnd) in order to be further
                   processed. */
                if (tcp.TCP_SEQ_BETWEEN(seqno, pcb.rcv_nxt,
                                    pcb.rcv_nxt + pcb.rcv_wnd - 1)) {
                    if (pcb.rcv_nxt == seqno) {
                        /* The incoming segment is the next in sequence. We check if
                           we have to trim the end of the segment and update rcv_nxt
                           and pass the data to the application. */
                        tcplen = (ushort)tcp_hdr.TCP_TCPLEN(inseg);

                        if (tcplen > pcb.rcv_wnd) {
                            lwip.LWIP_DEBUGF(opt.TCP_INPUT_DEBUG,
                                        "tcp_receive: other end overran receive window"
                                         + "seqno {0} len {1} right edge {2}\n",
                                         seqno, tcplen, pcb.rcv_nxt + pcb.rcv_wnd);
                            if ((tcp_hdr.TCPH_FLAGS(inseg.tcphdr) & tcp.TCP_FIN) != 0) {
                                /* Must remove the FIN from the header as we're trimming
                                 * that byte of sequence-space from the packet */
                                tcp_hdr.TCPH_FLAGS_SET(inseg.tcphdr, (ushort)(tcp_hdr.TCPH_FLAGS(inseg.tcphdr) & ~tcp.TCP_FIN));
                            }
                            /* Adjust length of segment to fit in the window. */
                            inseg.len = pcb.rcv_wnd;
                            if ((tcp_hdr.TCPH_FLAGS(inseg.tcphdr) & tcp.TCP_SYN) != 0) {
                                inseg.len -= 1;
                            }
                            lwip.pbuf_realloc(inseg.p, inseg.len);
                            tcplen = (ushort)tcp_hdr.TCP_TCPLEN(inseg);
                            lwip.LWIP_ASSERT("tcp_receive: segment not trimmed correctly to rcv_wnd\n",
                                        (seqno + tcplen) == (pcb.rcv_nxt + pcb.rcv_wnd));
                        }
            #if TCP_QUEUE_OOSEQ
                        /* Received in-sequence data, adjust ooseq data if:
                           - FIN has been received or
                           - inseq overlaps with ooseq */
                        if (pcb.ooseq != null) {
                            if ((tcp_hdr.TCPH_FLAGS(inseg.tcphdr) & tcp.TCP_FIN) != 0) {
                                lwip.LWIP_DEBUGF(opt.TCP_INPUT_DEBUG,
                                            ("tcp_receive: received in-order FIN, binning ooseq queue\n"));
                                /* Received in-order FIN means anything that was received
                                 * out of order must now have been received in-order, so
                                 * bin the ooseq queue */
                                while (pcb.ooseq != null) {
                                    tcp_seg old_ooseq = pcb.ooseq;
                                    pcb.ooseq = pcb.ooseq.next;
                                    tcp_seg_free(old_ooseq);
                                }
                            }
                            else {
                                next = pcb.ooseq;
                                /* Remove all segments on ooseq that are covered by inseg already.
                                 * FIN is copied from ooseq to inseg if present. */
                                while ((next != null) &&
                                    TCP_SEQ_GEQ(seqno + tcplen, next.tcphdr.seqno + next.len)) {
                                    /* inseg cannot have FIN here (already processed above) */
                                    if ((tcp_hdr.TCPH_FLAGS(next.tcphdr) & tcp.TCP_FIN) != 0 &&
                                        (tcp_hdr.TCPH_FLAGS(inseg.tcphdr) & tcp.TCP_SYN) == 0) {
                                        tcp_hdr.TCPH_SET_FLAG(inseg.tcphdr, tcp.TCP_FIN);
                                        tcplen = (ushort)tcp_hdr.TCP_TCPLEN(inseg);
                                    }
                                    prev = next;
                                    next = next.next;
                                    tcp_seg_free(prev);
                                }
                                /* Now trim right side of inseg if it overlaps with the first
                                 * segment on ooseq */
                                if ((next != null) &&
                                    TCP_SEQ_GT(seqno + tcplen, next.tcphdr.seqno)) {
                                    /* inseg cannot have FIN here (already processed above) */
                                    inseg.len = (ushort)(next.tcphdr.seqno - seqno);
                                    if ((tcp_hdr.TCPH_FLAGS(inseg.tcphdr) & tcp.TCP_SYN) != 0) {
                                        inseg.len -= 1;
                                    }
                                    lwip.pbuf_realloc(inseg.p, inseg.len);
                                    tcplen = (ushort)tcp_hdr.TCP_TCPLEN(inseg);
                                    lwip.LWIP_ASSERT("tcp_receive: segment not trimmed correctly to ooseq queue\n",
                                                (seqno + tcplen) == next.tcphdr.seqno);
                                }
                                pcb.ooseq = next;
                            }
                        }
            #endif // TCP_QUEUE_OOSEQ

                        pcb.rcv_nxt = seqno + tcplen;

                        /* Update the receiver's (our) window. */
                        lwip.LWIP_ASSERT("tcp_receive: tcplen > rcv_wnd\n", pcb.rcv_wnd >= tcplen);
                        pcb.rcv_wnd -= tcplen;

                        tcp.tcp_update_rcv_ann_wnd(pcb);

                        /* If there is data in the segment, we make preparations to
                           pass this up to the application. The .recv_data variable
                           is used for holding the pbuf that goes to the
                           application. The code for reassembling out-of-sequence data
                           chains its data on this pbuf as well.

                           If the segment was a FIN, we set the TF_GOT_FIN flag that will
                           be used to indicate to the application that the remote side has
                           closed its end of the connection. */
                        if (inseg.p.tot_len > 0) {
                            recv_data = inseg.p;
                            /* Since this pbuf now is the responsibility of the
                               application, we delete our reference to it so that we won't
                               (mistakingly) deallocate it. */
                            inseg.p = null;
                        }
                        if ((tcp_hdr.TCPH_FLAGS(inseg.tcphdr) & tcp.TCP_FIN) != 0) {
                            lwip.LWIP_DEBUGF(opt.TCP_INPUT_DEBUG, "tcp_receive: received FIN.\n");
                            recv_flags |= tcp.TF_GOT_FIN;
                        }

            #if TCP_QUEUE_OOSEQ
                        /* We now check if we have segments on the .ooseq queue that
                           are now in sequence. */
                        while (pcb.ooseq != null &&
                               pcb.ooseq.tcphdr.seqno == pcb.rcv_nxt) {

                            cseg = pcb.ooseq;
                            seqno = pcb.ooseq.tcphdr.seqno;

                            pcb.rcv_nxt += (uint)tcp_hdr.TCP_TCPLEN(cseg);
                            lwip.LWIP_ASSERT("tcp_receive: ooseq tcplen > rcv_wnd\n",
                                        pcb.rcv_wnd >= tcp_hdr.TCP_TCPLEN(cseg));
                            pcb.rcv_wnd -= (ushort)tcp_hdr.TCP_TCPLEN(cseg);

                            tcp.tcp_update_rcv_ann_wnd(pcb);

                            if (cseg.p.tot_len > 0) {
                                /* Chain this pbuf onto the pbuf that we will pass to
                                   the application. */
                                if (recv_data != null) {
                                    lwip.pbuf_cat(recv_data, cseg.p);
                                }
                                else {
                                    recv_data = cseg.p;
                                }
                                cseg.p = null;
                            }
                            if ((tcp_hdr.TCPH_FLAGS(cseg.tcphdr) & tcp.TCP_FIN) != 0) {
                                lwip.LWIP_DEBUGF(opt.TCP_INPUT_DEBUG, "tcp_receive: dequeued FIN.\n");
                                recv_flags |= tcp.TF_GOT_FIN;
                                if (pcb.state == tcp_state.ESTABLISHED) { /* force passive close or we can move to active close */
                                    pcb.state = tcp_state.CLOSE_WAIT;
                                }
                            }

                            pcb.ooseq = cseg.next;
                            tcp_seg_free(cseg);
                        }
            #endif // TCP_QUEUE_OOSEQ

                        /* Acknowledge the segment(s). */
                        tcp.tcp_ack(pcb);

                    }
                    else {
                        /* We get here if the incoming segment is out-of-sequence. */
                        tcp_send_empty_ack(pcb);
            #if TCP_QUEUE_OOSEQ
                        /* We queue the segment on the .ooseq queue. */
                        if (pcb.ooseq == null) {
                            pcb.ooseq = tcp_seg_copy(inseg);
                        }
                        else {
                            /* If the queue is not empty, we walk through the queue and
                               try to find a place where the sequence number of the
                               incoming segment is between the sequence numbers of the
                               previous and the next segment on the .ooseq queue. That is
                               the place where we put the incoming segment. If needed, we
                               trim the second edges of the previous and the incoming
                               segment so that it will fit into the sequence.

                               If the incoming segment has the same sequence number as a
                               segment on the .ooseq queue, we discard the segment that
                               contains less data. */

                            prev = null;
                            for (next = pcb.ooseq; next != null; next = next.next) {
                                if (seqno == next.tcphdr.seqno) {
                                    /* The sequence number of the incoming segment is the
                                       same as the sequence number of the segment on
                                       .ooseq. We check the lengths to see which one to
                                       discard. */
                                    if (inseg.len > next.len) {
                                        /* The incoming segment is larger than the old
                                           segment. We replace some segments with the new
                                           one. */
                                        cseg = tcp_seg_copy(inseg);
                                        if (cseg != null) {
                                            if (prev != null) {
                                                prev.next = cseg;
                                            }
                                            else {
                                                pcb.ooseq = cseg;
                                            }
                                            tcp_oos_insert_segment(cseg, next);
                                        }
                                        break;
                                    }
                                    else {
                                        /* Either the lenghts are the same or the incoming
                                           segment was smaller than the old one; in either
                                           case, we ditch the incoming segment. */
                                        break;
                                    }
                                }
                                else {
                                    if (prev == null) {
                                        if (tcp.TCP_SEQ_LT(seqno, next.tcphdr.seqno)) {
                                            /* The sequence number of the incoming segment is lower
                                               than the sequence number of the first segment on the
                                               queue. We put the incoming segment first on the
                                               queue. */
                                            cseg = tcp_seg_copy(inseg);
                                            if (cseg != null) {
                                                pcb.ooseq = cseg;
                                                tcp_oos_insert_segment(cseg, next);
                                            }
                                            break;
                                        }
                                    }
                                    else {
                                        /*if (tcp.TCP_SEQ_LT(prev.tcphdr.seqno, seqno) &&
                                          tcp.TCP_SEQ_LT(seqno, next.tcphdr.seqno)) {*/
                                        if (tcp.TCP_SEQ_BETWEEN(seqno, prev.tcphdr.seqno + 1, next.tcphdr.seqno - 1)) {
                                            /* The sequence number of the incoming segment is in
                                               between the sequence numbers of the previous and
                                               the next segment on .ooseq. We trim trim the previous
                                               segment, delete next segments that included in received segment
                                               and trim received, if needed. */
                                            cseg = tcp_seg_copy(inseg);
                                            if (cseg != null) {
                                                if (TCP_SEQ_GT(prev.tcphdr.seqno + prev.len, seqno)) {
                                                    /* We need to trim the prev segment. */
                                                    prev.len = (ushort)(seqno - prev.tcphdr.seqno);
                                                    lwip.pbuf_realloc(prev.p, prev.len);
                                                }
                                                prev.next = cseg;
                                                tcp_oos_insert_segment(cseg, next);
                                            }
                                            break;
                                        }
                                    }
                                    /* If the "next" segment is the last segment on the
                                       ooseq queue, we add the incoming segment to the end
                                       of the list. */
                                    if (next.next == null &&
                                        TCP_SEQ_GT(seqno, next.tcphdr.seqno)) {
                                        if ((tcp_hdr.TCPH_FLAGS(next.tcphdr) & tcp.TCP_FIN) != 0) {
                                            /* segment "next" already contains all data */
                                            break;
                                        }
                                        next.next = tcp_seg_copy(inseg);
                                        if (next.next != null) {
                                            if (TCP_SEQ_GT(next.tcphdr.seqno + next.len, seqno)) {
                                                /* We need to trim the last segment. */
                                                next.len = (ushort)(seqno - next.tcphdr.seqno);
                                                lwip.pbuf_realloc(next.p, next.len);
                                            }
                                            /* check if the remote side overruns our receive window */
                                            if ((uint)tcplen + seqno > pcb.rcv_nxt + (uint)pcb.rcv_wnd) {
                                                lwip.LWIP_DEBUGF(opt.TCP_INPUT_DEBUG,
                                                            "tcp_receive: other end overran receive window"
                                                             + "seqno {0} len {1} right edge {2}\n",
                                                             seqno, tcplen, pcb.rcv_nxt + pcb.rcv_wnd);
                                                if ((tcp_hdr.TCPH_FLAGS(next.next.tcphdr) & tcp.TCP_FIN) != 0) {
                                                    /* Must remove the FIN from the header as we're trimming
                                                     * that byte of sequence-space from the packet */
                                                    tcp_hdr.TCPH_FLAGS_SET(next.next.tcphdr, (ushort)(tcp_hdr.TCPH_FLAGS(next.next.tcphdr) & ~tcp.TCP_FIN));
                                                }
                                                /* Adjust length of segment to fit in the window. */
                                                next.next.len = (ushort)(pcb.rcv_nxt + pcb.rcv_wnd - seqno);
                                                lwip.pbuf_realloc(next.next.p, next.next.len);
                                                tcplen = (ushort)tcp_hdr.TCP_TCPLEN(next.next);
                                                lwip.LWIP_ASSERT("tcp_receive: segment not trimmed correctly to rcv_wnd\n",
                                                            (seqno + tcplen) == (pcb.rcv_nxt + pcb.rcv_wnd));
                                            }
                                        }
                                        break;
                                    }
                                }
                                prev = next;
                            }
                        }
            #if TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS
                        /* Check that the data on ooseq doesn't exceed one of the limits
                           and throw away everything above that limit. */
                        ooseq_blen = 0;
                        ooseq_qlen = 0;
                        prev = null;
                        for (next = pcb.ooseq; next != null; prev = next, next = next.next) {
                            pbuf p1 = next.p;
                            ooseq_blen += p1.tot_len;
                            ooseq_qlen += lwip.pbuf_clen(p1);
                            if ((ooseq_blen > opt.TCP_OOSEQ_MAX_BYTES) ||
                                (ooseq_qlen > opt.TCP_OOSEQ_MAX_PBUFS)) {
                                /* too much ooseq data, dump this and everything after it */
                                tcp_segs_free(next);
                                if (prev == null) {
                                    /* first ooseq segment is too much, dump the whole queue */
                                    pcb.ooseq = null;
                                }
                                else {
                                    /* just dump 'next' and everything after it */
                                    prev.next = null;
                                }
                                break;
                            }
                        }
            #endif // TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS
            #endif // TCP_QUEUE_OOSEQ
                    }
                }
                else {
                    /* The incoming segment is not withing the window. */
                    tcp_send_empty_ack(pcb);
                }
            }
            else {
                /* Segments with length 0 is taken care of here. Segments that
                   fall out of the window are ACKed. */
                /*if (TCP_SEQ_GT(pcb.rcv_nxt, seqno) ||
                  TCP_SEQ_GEQ(seqno, pcb.rcv_nxt + pcb.rcv_wnd)) {*/
                if (!tcp.TCP_SEQ_BETWEEN(seqno, pcb.rcv_nxt, pcb.rcv_nxt + pcb.rcv_wnd - 1)) {
                    tcp.tcp_ack_now(pcb);
                }
            }
        }
Ejemplo n.º 24
0
 /**
  * Chain two pbufs (or pbuf chains) together.
  *
  * The caller MUST call lwip.pbuf_free(t) once it has stopped
  * using it. Use pbuf_cat() instead if you no longer use t.
  *
  * @param h head pbuf (chain)
  * @param t tail pbuf (chain)
  * @note The pbufs MUST belong to the same packet.
  * @note MAY NOT be called on a packet queue.
  *
  * The .tot_len fields of all pbufs of the head chain are adjusted.
  * The .next field of the last pbuf of the head chain is adjusted.
  * The .@ref field of the first pbuf of the tail chain is adjusted.
  *
  */
 public void pbuf_chain(pbuf h, pbuf t)
 {
     pbuf_cat(h, t);
     /* t is now referenced by h */
     pbuf_ref(t);
     lwip.LWIP_DEBUGF(opt.PBUF_DEBUG | lwip.LWIP_DBG_TRACE, "pbuf_chain: {0} references {1}\n", h, t);
 }
Ejemplo n.º 25
0
        /**
         * Create a TCP segment with prefilled header.
         *
         * Called by tcp_write and tcp_enqueue_flags.
         *
         * @param pcb Protocol control block for the TCP connection.
         * @param p pbuf that is used to hold the TCP header.
         * @param flags TCP flags for header.
         * @param seqno TCP sequence number of this packet
         * @param optflags options to include in TCP header
         * @return a new tcp_seg pointing to p, or null.
         * The TCP header is filled in except ackno and wnd.
         * p is freed on failure.
         */
        private tcp_seg tcp_create_segment(tcp_pcb pcb, pbuf p, byte flags, uint seqno, byte optflags)
        {
            tcp_seg seg;
            byte optlen = (byte)tcp_seg.LWIP_TCP_OPT_LENGTH(optflags);

            if ((seg = (tcp_seg)lwip.memp_malloc(memp_t.MEMP_TCP_SEG)) == null) {
                lwip.LWIP_DEBUGF(opt.TCP_OUTPUT_DEBUG | 2, "tcp_create_segment: no memory.\n");
                lwip.pbuf_free(p);
                return null;
            }
            seg.flags = optflags;
            seg.next = null;
            seg.p = p;
            seg.len = (ushort)(p.tot_len - optlen);
            #if TCP_OVERSIZE_DBGCHECK
            seg.oversize_left = 0;
            #endif // TCP_OVERSIZE_DBGCHECK
            #if TCP_CHECKSUM_ON_COPY
            seg.chksum = 0;
            seg.chksum_swapped = false;
            /* check optflags */
            lwip.LWIP_ASSERT("invalid optflags passed: TF_SEG_DATA_CHECKSUMMED",
                        (optflags & tcp_seg.TF_SEG_DATA_CHECKSUMMED) == 0);
            #endif // TCP_CHECKSUM_ON_COPY

            /* build TCP header */
            if (lwip.pbuf_header(p, TCP_HLEN) != 0) {
                lwip.LWIP_DEBUGF(opt.TCP_OUTPUT_DEBUG | 2, "tcp_create_segment: no room for TCP header in pbuf.\n");
                ++lwip.lwip_stats.tcp.err;
                tcp_seg_free(seg);
                return null;
            }
            seg.tcphdr = new tcp_hdr(seg.p.payload);
            seg.tcphdr.src = lwip.lwip_htons(pcb.local_port);
            seg.tcphdr.dest = lwip.lwip_htons(pcb.remote_port);
            seg.tcphdr.seqno = lwip.lwip_htonl(seqno);
            /* ackno is set in tcp.tcp_output */
            tcp_hdr.TCPH_HDRLEN_FLAGS_SET(seg.tcphdr, (5 + optlen / 4), flags);
            /* wnd and chksum are set in tcp.tcp_output */
            seg.tcphdr.urgp = 0;
            return seg;
        }
Ejemplo n.º 26
0
 /**
  * Creates a single pbuf out of a queue of pbufs.
  *
  * @remark: Either the source pbuf 'p' is freed by this function or the original
  *          pbuf 'p' is returned, therefore the caller has to check the result!
  *
  * @param p the source pbuf
  * @param layer pbuf_layer of the new pbuf
  *
  * @return a new, single pbuf (p.next is null)
  *         or the old pbuf if allocation fails
  */
 public pbuf pbuf_coalesce(pbuf p, pbuf_layer layer)
 {
     pbuf q;
     err_t err;
     if (p.next == null) {
         return p;
     }
     q = pbuf_alloc(layer, p.tot_len, pbuf_type.PBUF_RAM);
     if (q == null) {
         /* @todo: what do we do now? */
         return p;
     }
     err = pbuf_copy(q, p);
     lwip.LWIP_ASSERT("pbuf_copy failed", err == err_t.ERR_OK);
     pbuf_free(p);
     return q;
 }
Ejemplo n.º 27
0
Archivo: ip.cs Proyecto: h7ga40/uITron3
        internal err_t ip_output_if(pbuf p, ip_addr src, ip_addr dest, byte ttl, byte tos, byte proto)
        {
            /* pbufs passed to IP must have a @ref-count of 1 as their payload pointer
             gets altered as the packet is passed down the stack */
            lwip.LWIP_ASSERT("p.ref == 1", p.@ref == 1);

            ++lwip_stats.ip.xmit;

            return output(this, p, src, dest, ttl, tos, proto);
        }
Ejemplo n.º 28
0
 /**
  * Dechains the first pbuf from its succeeding pbufs in the chain.
  *
  * Makes p.tot_len field equal to p.len.
  * @param p pbuf to dechain
  * @return remainder of the pbuf chain, or null if it was de-allocated.
  * @note May not be called on a packet queue.
  */
 public pbuf pbuf_dechain(pbuf p)
 {
     pbuf q;
     byte tail_gone = 1;
     /* tail */
     q = p.next;
     /* pbuf has successor in chain? */
     if (q != null) {
         /* assert tot_len invariant: (p.tot_len == p.len + (p.next? p.next.tot_len: 0) */
         lwip.LWIP_ASSERT("p.tot_len == p.len + q.tot_len", q.tot_len == p.tot_len - p.len);
         /* enforce invariant if assertion is disabled */
         q.tot_len = (ushort)(p.tot_len - p.len);
         /* decouple pbuf from remainder */
         p.next = null;
         /* total length of pbuf p is its own length only */
         p.tot_len = p.len;
         /* q is no longer referenced by p, free it */
         lwip.LWIP_DEBUGF(opt.PBUF_DEBUG | lwip.LWIP_DBG_TRACE, "pbuf_dechain: unreferencing {0}\n", q);
         tail_gone = pbuf_free(q);
         if (tail_gone > 0) {
             lwip.LWIP_DEBUGF(opt.PBUF_DEBUG | lwip.LWIP_DBG_TRACE,
                         "pbuf_dechain: deallocated {0} (as it is no longer referenced)\n", q);
         }
         /* return remaining tail or null if deallocated */
     }
     /* assert tot_len invariant: (p.tot_len == p.len + (p.next? p.next.tot_len: 0) */
     lwip.LWIP_ASSERT("p.tot_len == p.len", p.tot_len == p.len);
     return ((tail_gone > 0) ? null : q);
 }
Ejemplo n.º 29
0
Archivo: ip.cs Proyecto: h7ga40/uITron3
        /** Like ip.ip_output, but takes and addr_hint pointer that is passed on to netif.addr_hint
         *  before calling ip_output_if.
         *
         * @param p the packet to send (p.payload points to the data, e.g. next
                    protocol header; if dest == ip.IP_HDRINCL, p already includes an IP
                    header and p.payload points to that IP header)
         * @param src the source IP address to send from (if src == IP_ADDR_ANY, the
         *         IP  address of the netif used to send is used as source address)
         * @param dest the destination IP address to send the packet to
         * @param ttl the TTL value to be set in the IP header
         * @param tos the TOS value to be set in the IP header
         * @param proto the PROTOCOL to be set in the IP header
         * @param addr_hint address hint pointer set to netif.addr_hint before
         *        calling ip_output_if()
         *
         * @return err_t.ERR_RTE if no route is found
         *         see ip_output_if() for more return values
         */
        public err_t ip_output_hinted(pbuf p, ip_addr src, ip_addr dest,
			byte ttl, byte tos, byte proto, object addr_hint)
        {
            err_t err;

            /* pbufs passed to IP must have a @ref-count of 1 as their payload pointer
               gets altered as the packet is passed down the stack */
            lwip.LWIP_ASSERT("p.ref == 1", p.@ref == 1);

            err = ip_output_if(p, src, dest, ttl, tos, proto);

            return err;
        }
Ejemplo n.º 30
0
 /**
  * Increment the reference count of the pbuf.
  *
  * @param p pbuf to increase reference counter of
  *
  */
 public void pbuf_ref(pbuf p)
 {
     sys.SYS_ARCH_DECL_PROTECT(sys.old_level);
     /* pbuf given? */
     if (p != null) {
         sys.SYS_ARCH_PROTECT(sys.old_level);
         ++(p.@ref);
         sys.SYS_ARCH_UNPROTECT(sys.old_level);
     }
 }