Changeset 1812a0d in mainline for uspace/srv/net/tl/tcp/tcp.c


Ignore:
Timestamp:
2011-11-23T19:06:15Z (12 years ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
762b48a
Parents:
6896409c
Message:

Hook TCP into network stack IP layer.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/srv/net/tl/tcp/tcp.c

    r6896409c r1812a0d  
    3636
    3737#include <async.h>
     38#include <byteorder.h>
    3839#include <errno.h>
    3940#include <io/log.h>
     
    4142#include <task.h>
    4243
     44#include <icmp_remote.h>
     45#include <ip_client.h>
     46#include <ip_interface.h>
     47#include <ipc/services.h>
     48#include <ipc/tl.h>
     49#include <tl_common.h>
     50#include <tl_skel.h>
     51#include <packet_client.h>
     52#include <packet_remote.h>
     53
     54#include "header.h"
    4355#include "ncsim.h"
    4456#include "rqueue.h"
     57#include "std.h"
     58#include "tcp.h"
    4559#include "test.h"
    4660
    4761#define NAME       "tcp"
     62
     63static async_sess_t *net_sess;
     64static async_sess_t *icmp_sess;
     65static async_sess_t *ip_sess;
     66static packet_dimensions_t pkt_dims;
     67
     68static void tcp_received_pdu(tcp_pdu_t *pdu);
     69
     70/* Pull up packets into a single memory block. */
     71static int pq_pullup(packet_t *packet, void **data, size_t *dsize)
     72{
     73        packet_t *npacket;
     74        size_t tot_len;
     75        int length;
     76
     77        npacket = packet;
     78        tot_len = 0;
     79        do {
     80                length = packet_get_data_length(packet);
     81                if (length <= 0)
     82                        return EINVAL;
     83
     84                tot_len += length;
     85        } while ((npacket = pq_next(npacket)) != NULL);
     86
     87        uint8_t *buf;
     88        uint8_t *dp;
     89
     90        buf = calloc(tot_len, 1);
     91        if (buf == NULL) {
     92                free(buf);
     93                return ENOMEM;
     94        }
     95
     96        npacket = packet;
     97        dp = buf;
     98        do {
     99                length = packet_get_data_length(packet);
     100                if (length <= 0) {
     101                        free(buf);
     102                        return EINVAL;
     103                }
     104
     105                memcpy(dp, packet_get_data(packet), length);
     106                dp += length;
     107        } while ((npacket = pq_next(npacket)) != NULL);
     108
     109        *data = buf;
     110        *dsize = tot_len;
     111        return EOK;
     112}
     113
     114/** Process packet received from network layer. */
     115static int tcp_received_msg(device_id_t device_id, packet_t *packet,
     116    services_t error)
     117{
     118        int rc;
     119        size_t offset;
     120        int length;
     121        struct sockaddr_in *src_addr;
     122        struct sockaddr_in *dest_addr;
     123        size_t addr_len;
     124
     125        log_msg(LVL_DEBUG, "tcp_received_msg()");
     126
     127        switch (error) {
     128        case SERVICE_NONE:
     129                break;
     130        case SERVICE_ICMP:
     131        default:
     132                log_msg(LVL_WARN, "Unsupported service number %u",
     133                    (unsigned)error);
     134                pq_release_remote(net_sess, packet_get_id(packet));
     135                return ENOTSUP;
     136        }
     137
     138        /* Process and trim off IP header */
     139        log_msg(LVL_DEBUG, "tcp_received_msg() - IP header");
     140
     141        rc = ip_client_process_packet(packet, NULL, NULL, NULL, NULL, NULL);
     142        if (rc < 0) {
     143                log_msg(LVL_WARN, "ip_client_process_packet() failed");
     144                pq_release_remote(net_sess, packet_get_id(packet));
     145                return rc;
     146        }
     147
     148        offset = (size_t)rc;
     149        length = packet_get_data_length(packet);
     150
     151        if (length < 0 || (size_t)length < offset) {
     152                log_msg(LVL_WARN, "length=%d, dropping.", length);
     153                pq_release_remote(net_sess, packet_get_id(packet));
     154                return EINVAL;
     155        }
     156
     157        addr_len = packet_get_addr(packet, (uint8_t **)&src_addr,
     158            (uint8_t **)&dest_addr);
     159        if (addr_len <= 0) {
     160                log_msg(LVL_WARN, "Failed to get packet address.");
     161                pq_release_remote(net_sess, packet_get_id(packet));
     162                return EINVAL;
     163        }
     164
     165        if (addr_len != sizeof(struct sockaddr_in)) {
     166                log_msg(LVL_WARN, "Unsupported address size %zu (!= %zu)",
     167                    addr_len, sizeof(struct sockaddr_in));
     168                pq_release_remote(net_sess, packet_get_id(packet));
     169                return EINVAL;
     170        }
     171
     172        rc = packet_trim(packet, offset, 0);
     173        if (rc != EOK) {
     174                log_msg(LVL_WARN, "Failed to trim packet.");
     175                pq_release_remote(net_sess, packet_get_id(packet));
     176                return rc;
     177        }
     178
     179        /* Pull up packets into a single memory block, pdu_raw. */
     180        log_msg(LVL_DEBUG, "tcp_received_msg() - pull up");
     181        uint8_t *pdu_raw;
     182        size_t pdu_raw_size = 0;
     183
     184        pq_pullup(packet, (void **)&pdu_raw, &pdu_raw_size);
     185
     186        /* Split into header and payload. */
     187
     188        log_msg(LVL_DEBUG, "tcp_received_msg() - split header/payload");
     189
     190        tcp_pdu_t *pdu;
     191        size_t hdr_size;
     192
     193        /* XXX Header options */
     194        hdr_size = sizeof(tcp_header_t);
     195
     196        if (pdu_raw_size < hdr_size) {
     197                log_msg(LVL_WARN, "pdu_raw_size = %zu < hdr_size = %zu",
     198                    pdu_raw_size, hdr_size);
     199                pq_release_remote(net_sess, packet_get_id(packet));
     200                return EINVAL;
     201        }
     202
     203        log_msg(LVL_DEBUG, "pdu_raw_size=%zu, hdr_size=%zu",
     204            pdu_raw_size, hdr_size);
     205        pdu = tcp_pdu_create(pdu_raw, hdr_size, pdu_raw + hdr_size,
     206            pdu_raw_size - hdr_size);
     207        if (pdu == NULL) {
     208                log_msg(LVL_WARN, "Failed creating PDU. Dropped.");
     209                return ENOMEM;
     210        }
     211
     212        free(pdu_raw);
     213
     214        pdu->src_addr.ipv4 = uint32_t_be2host(src_addr->sin_addr.s_addr);
     215        pdu->dest_addr.ipv4 = uint32_t_be2host(dest_addr->sin_addr.s_addr);
     216        log_msg(LVL_DEBUG, "src: 0x%08x, dest: 0x%08x",
     217            pdu->src_addr.ipv4, pdu->dest_addr.ipv4);
     218
     219        tcp_received_pdu(pdu);
     220        tcp_pdu_delete(pdu);
     221
     222        return EOK;
     223}
     224
     225/** Receive packets from network layer. */
     226static void tcp_receiver(ipc_callid_t iid, ipc_call_t *icall, void *arg)
     227{
     228        packet_t *packet;
     229        int rc;
     230
     231        log_msg(LVL_DEBUG, "tcp_receiver()");
     232
     233        while (true) {
     234                switch (IPC_GET_IMETHOD(*icall)) {
     235                case NET_TL_RECEIVED:
     236                        log_msg(LVL_DEBUG, "method = NET_TL_RECEIVED");
     237                        rc = packet_translate_remote(net_sess, &packet,
     238                            IPC_GET_PACKET(*icall));
     239                        if (rc != EOK) {
     240                                log_msg(LVL_DEBUG, "Error %d translating packet.", rc);
     241                                async_answer_0(iid, (sysarg_t)rc);
     242                                break;
     243                        }
     244                        rc = tcp_received_msg(IPC_GET_DEVICE(*icall), packet,
     245                            IPC_GET_ERROR(*icall));
     246                        async_answer_0(iid, (sysarg_t)rc);
     247                        break;
     248                default:
     249                        log_msg(LVL_DEBUG, "method = %u",
     250                            (unsigned)IPC_GET_IMETHOD(*icall));
     251                        async_answer_0(iid, ENOTSUP);
     252                        break;
     253                }
     254
     255                iid = async_get_call(icall);
     256        }
     257}
     258
     259/** Transmit PDU over network layer. */
     260void tcp_transmit_pdu(tcp_pdu_t *pdu)
     261{
     262        struct sockaddr_in dest;
     263        device_id_t dev_id;
     264        void *phdr;
     265        size_t phdr_len;
     266        packet_dimension_t *pkt_dim;
     267        int rc;
     268        packet_t *packet;
     269        void *pkt_data;
     270        size_t pdu_size;
     271
     272        dest.sin_family = AF_INET;
     273        dest.sin_port = 0; /* not needed */
     274        dest.sin_addr.s_addr = host2uint32_t_be(pdu->dest_addr.ipv4);
     275
     276        /* Find route. Obtained pseudo-header is not used. */
     277        rc = ip_get_route_req(ip_sess, IPPROTO_TCP, (struct sockaddr *)&dest,
     278            sizeof(dest), &dev_id, &phdr, &phdr_len);
     279        if (rc != EOK) {
     280                log_msg(LVL_DEBUG, "tcp_transmit_pdu: Failed to find route.");
     281                return;
     282        }
     283
     284        rc = tl_get_ip_packet_dimension(ip_sess, &pkt_dims, dev_id, &pkt_dim);
     285        if (rc != EOK) {
     286                log_msg(LVL_DEBUG, "tcp_transmit_pdu: Failed to get dimension.");
     287                return;
     288        }
     289
     290        pdu_size = pdu->header_size + pdu->text_size;
     291
     292        packet = packet_get_4_remote(net_sess, pdu_size, pkt_dim->addr_len,
     293            pkt_dim->prefix, pkt_dim->suffix);
     294        if (!packet) {
     295                log_msg(LVL_DEBUG, "tcp_transmit_pdu: Failed to get packet.");
     296                return;
     297        }
     298
     299        pkt_data = packet_suffix(packet, pdu_size);
     300        if (!pkt_data) {
     301                log_msg(LVL_DEBUG, "tcp_transmit_pdu: Failed to get pkt_data ptr.");
     302                pq_release_remote(net_sess, packet_get_id(packet));
     303                return;
     304        }
     305
     306        rc = ip_client_prepare_packet(packet, IPPROTO_TCP, 0, 0, 0, 0);
     307        if (rc != EOK) {
     308                log_msg(LVL_DEBUG, "tcp_transmit_pdu: Failed to prepare IP packet part.");
     309                pq_release_remote(net_sess, packet_get_id(packet));
     310                return;
     311        }
     312
     313        rc = packet_set_addr(packet, NULL, (uint8_t *)&dest, sizeof(dest));
     314        if (rc != EOK) {
     315                log_msg(LVL_DEBUG, "tcp_transmit_pdu: Failed to set packet address.");
     316                pq_release_remote(net_sess, packet_get_id(packet));
     317                return;
     318        }
     319
     320        /* Copy PDU data to packet */
     321        memcpy(pkt_data, pdu->header, pdu->header_size);
     322        memcpy((uint8_t *)pkt_data + pdu->header_size, pdu->text,
     323            pdu->text_size);
     324
     325        /* Transmit packet. XXX Transfers packet ownership to IP? */
     326        ip_send_msg(ip_sess, dev_id, packet, SERVICE_TCP, 0);
     327}
     328
     329/** Process received PDU. */
     330static void tcp_received_pdu(tcp_pdu_t *pdu)
     331{
     332        tcp_segment_t *dseg;
     333        tcp_sockpair_t rident;
     334
     335        log_msg(LVL_DEBUG, "tcp_received_pdu()");
     336
     337        if (tcp_pdu_decode(pdu, &rident, &dseg) != EOK) {
     338                log_msg(LVL_WARN, "Not enough memory. PDU dropped.");
     339                return;
     340        }
     341
     342        /* Insert decoded segment into rqueue */
     343        tcp_rqueue_insert_seg(&rident, dseg);
     344}
     345
     346/* Called from libnet */
     347void tl_connection(void)
     348{
     349        log_msg(LVL_DEBUG, "tl_connection()");
     350}
     351
     352/* Called from libnet */
     353int tl_message(ipc_callid_t callid, ipc_call_t *call, ipc_call_t *answer,
     354    size_t *answer_count)
     355{
     356        log_msg(LVL_DEBUG, "tl_message()");
     357        return ENOTSUP;
     358}
     359
     360/* Called from libnet */
     361int tl_initialize(async_sess_t *sess)
     362{
     363        int rc;
     364
     365        net_sess = sess;
     366        icmp_sess = icmp_connect_module();
     367
     368        log_msg(LVL_DEBUG, "tl_initialize()");
     369
     370        ip_sess = ip_bind_service(SERVICE_IP, IPPROTO_TCP, SERVICE_TCP,
     371            tcp_receiver);
     372        if (ip_sess == NULL)
     373                return ENOENT;
     374
     375        rc = packet_dimensions_initialize(&pkt_dims);
     376        if (rc != EOK)
     377                return rc;
     378
     379        return EOK;
     380}
    48381
    49382int main(int argc, char **argv)
     
    59392        }
    60393
    61         printf(NAME ": Accepting connections\n");
     394//      printf(NAME ": Accepting connections\n");
    62395//      task_retval(0);
    63396
     
    69402
    70403        tcp_test();
    71 
     404/*
    72405        async_manager();
     406*/
     407        tl_module_start(SERVICE_TCP);
    73408
    74409        /* Not reached */
Note: See TracChangeset for help on using the changeset viewer.