Changeset a17356fd in mainline


Ignore:
Timestamp:
2013-07-12T15:33:20Z (11 years ago)
Author:
Martin Decky <martin@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
bb9b0c6
Parents:
f5f79cd
Message:

iplink IPv6 datagram support
rudimentary IPv6 support (sans fragmentation)

Location:
uspace
Files:
18 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/c/generic/iplink.c

    rf5f79cd ra17356fd  
    8686       
    8787        ipc_call_t answer;
    88         aid_t req = async_send_0(exch, IPLINK_SEND, &answer);
    89        
    90         int rc = async_data_write_start(exch, &sdu->src, sizeof(inet_addr_t));
     88        aid_t req = async_send_2(exch, IPLINK_SEND, (sysarg_t) sdu->src,
     89            (sysarg_t) sdu->dest, &answer);
     90       
     91        int rc = async_data_write_start(exch, sdu->data, sdu->size);
     92       
     93        async_exchange_end(exch);
     94       
     95        if (rc != EOK) {
     96                async_forget(req);
     97                return rc;
     98        }
     99       
     100        sysarg_t retval;
     101        async_wait_for(req, &retval);
     102       
     103        return (int) retval;
     104}
     105
     106int iplink_send6(iplink_t *iplink, iplink_sdu6_t *sdu)
     107{
     108        async_exch_t *exch = async_exchange_begin(iplink->sess);
     109       
     110        ipc_call_t answer;
     111        aid_t req = async_send_0(exch, IPLINK_SEND6, &answer);
     112       
     113        int rc = async_data_write_start(exch, &sdu->dest, sizeof(addr48_t));
    91114        if (rc != EOK) {
    92115                async_exchange_end(exch);
     
    95118        }
    96119       
    97         rc = async_data_write_start(exch, &sdu->dest, sizeof(inet_addr_t));
    98         if (rc != EOK) {
    99                 async_exchange_end(exch);
    100                 async_forget(req);
    101                 return rc;
    102         }
    103        
    104120        rc = async_data_write_start(exch, sdu->data, sdu->size);
    105121       
     
    119135int iplink_get_mtu(iplink_t *iplink, size_t *rmtu)
    120136{
     137        async_exch_t *exch = async_exchange_begin(iplink->sess);
     138       
    121139        sysarg_t mtu;
    122         async_exch_t *exch = async_exchange_begin(iplink->sess);
    123 
    124140        int rc = async_req_0_1(exch, IPLINK_GET_MTU, &mtu);
    125         async_exchange_end(exch);
    126 
     141       
     142        async_exchange_end(exch);
     143       
    127144        if (rc != EOK)
    128145                return rc;
    129 
     146       
    130147        *rmtu = mtu;
    131148        return EOK;
     149}
     150
     151int iplink_get_mac48(iplink_t *iplink, addr48_t *mac)
     152{
     153        async_exch_t *exch = async_exchange_begin(iplink->sess);
     154       
     155        ipc_call_t answer;
     156        aid_t req = async_send_0(exch, IPLINK_GET_MAC48, &answer);
     157       
     158        int rc = async_data_read_start(exch, mac, sizeof(addr48_t));
     159       
     160        loc_exchange_end(exch);
     161       
     162        if (rc != EOK) {
     163                async_forget(req);
     164                return rc;
     165        }
     166       
     167        sysarg_t retval;
     168        async_wait_for(req, &retval);
     169       
     170        return (int) retval;
    132171}
    133172
  • uspace/lib/c/generic/iplink_srv.c

    rf5f79cd ra17356fd  
    5050}
    5151
     52static void iplink_get_mac48_srv(iplink_srv_t *srv, ipc_callid_t iid,
     53    ipc_call_t *icall)
     54{
     55        addr48_t mac;
     56        int rc = srv->ops->get_mac48(srv, &mac);
     57        if (rc != EOK) {
     58                async_answer_0(iid, rc);
     59                return;
     60        }
     61       
     62        ipc_callid_t callid;
     63        size_t size;
     64        if (!async_data_read_receive(&callid, &size)) {
     65                async_answer_0(callid, EREFUSED);
     66                async_answer_0(iid, EREFUSED);
     67                return;
     68        }
     69       
     70        if (size != sizeof(addr48_t)) {
     71                async_answer_0(callid, EINVAL);
     72                async_answer_0(iid, EINVAL);
     73                return;
     74        }
     75       
     76        rc = async_data_read_finalize(callid, &mac, size);
     77        if (rc != EOK)
     78                async_answer_0(callid, rc);
     79       
     80        async_answer_0(iid, (sysarg_t) rc);
     81}
     82
    5283static void iplink_addr_add_srv(iplink_srv_t *srv, ipc_callid_t iid,
    5384    ipc_call_t *icall)
     
    111142        iplink_sdu_t sdu;
    112143       
     144        sdu.src = IPC_GET_ARG1(*icall);
     145        sdu.dest = IPC_GET_ARG2(*icall);
     146       
     147        int rc = async_data_write_accept(&sdu.data, false, 0, 0, 0,
     148            &sdu.size);
     149        if (rc != EOK) {
     150                async_answer_0(iid, rc);
     151                return;
     152        }
     153       
     154        rc = srv->ops->send(srv, &sdu);
     155        free(sdu.data);
     156        async_answer_0(iid, rc);
     157}
     158
     159static void iplink_send6_srv(iplink_srv_t *srv, ipc_callid_t iid,
     160    ipc_call_t *icall)
     161{
     162        iplink_sdu6_t sdu;
     163       
    113164        ipc_callid_t callid;
    114165        size_t size;
     
    119170        }
    120171       
    121         if (size != sizeof(inet_addr_t)) {
     172        if (size != sizeof(addr48_t)) {
    122173                async_answer_0(callid, EINVAL);
    123174                async_answer_0(iid, EINVAL);
     
    125176        }
    126177       
    127         int rc = async_data_write_finalize(callid, &sdu.src, size);
     178        int rc = async_data_write_finalize(callid, &sdu.dest, size);
    128179        if (rc != EOK) {
    129180                async_answer_0(callid, (sysarg_t) rc);
     
    131182        }
    132183       
    133         if (!async_data_write_receive(&callid, &size)) {
    134                 async_answer_0(callid, EREFUSED);
    135                 async_answer_0(iid, EREFUSED);
    136                 return;
    137         }
    138        
    139         if (size != sizeof(inet_addr_t)) {
    140                 async_answer_0(callid, EINVAL);
    141                 async_answer_0(iid, EINVAL);
    142                 return;
    143         }
    144        
    145         rc = async_data_write_finalize(callid, &sdu.dest, size);
    146         if (rc != EOK) {
    147                 async_answer_0(callid, (sysarg_t) rc);
    148                 async_answer_0(iid, (sysarg_t) rc);
    149         }
    150        
    151184        rc = async_data_write_accept(&sdu.data, false, 0, 0, 0,
    152185            &sdu.size);
    153         if (rc != EOK)
    154                 return;
    155        
    156         rc = srv->ops->send(srv, &sdu);
     186        if (rc != EOK) {
     187                async_answer_0(iid, rc);
     188                return;
     189        }
     190       
     191        rc = srv->ops->send6(srv, &sdu);
    157192        free(sdu.data);
    158193        async_answer_0(iid, rc);
     
    170205int iplink_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
    171206{
    172         iplink_srv_t *srv = (iplink_srv_t *)arg;
     207        iplink_srv_t *srv = (iplink_srv_t *) arg;
    173208        int rc;
    174209       
     
    214249                        iplink_get_mtu_srv(srv, callid, &call);
    215250                        break;
     251                case IPLINK_GET_MAC48:
     252                        iplink_get_mac48_srv(srv, callid, &call);
     253                        break;
    216254                case IPLINK_SEND:
    217255                        iplink_send_srv(srv, callid, &call);
     256                        break;
     257                case IPLINK_SEND6:
     258                        iplink_send6_srv(srv, callid, &call);
    218259                        break;
    219260                case IPLINK_ADDR_ADD:
  • uspace/lib/c/include/inet/iplink.h

    rf5f79cd ra17356fd  
    4747} iplink_t;
    4848
    49 /** Internet link Service Data Unit */
     49/** IPv4 link Service Data Unit */
    5050typedef struct {
    5151        /** Local source address */
    52         inet_addr_t src;
     52        addr32_t src;
    5353        /** Local destination address */
    54         inet_addr_t dest;
     54        addr32_t dest;
    5555        /** Serialized IP packet */
    5656        void *data;
     
    5858        size_t size;
    5959} iplink_sdu_t;
     60
     61/** IPv6 link Service Data Unit */
     62typedef struct {
     63        /** Local MAC destination address */
     64        addr48_t dest;
     65        /** Serialized IP packet */
     66        void *data;
     67        /** Size of @c data in bytes */
     68        size_t size;
     69} iplink_sdu6_t;
    6070
    6171/** Internet link receive Service Data Unit */
     
    7484extern void iplink_close(iplink_t *);
    7585extern int iplink_send(iplink_t *, iplink_sdu_t *);
     86extern int iplink_send6(iplink_t *, iplink_sdu6_t *);
    7687extern int iplink_addr_add(iplink_t *, inet_addr_t *);
    7788extern int iplink_addr_remove(iplink_t *, inet_addr_t *);
    7889extern int iplink_get_mtu(iplink_t *, size_t *);
     90extern int iplink_get_mac48(iplink_t *, addr48_t *);
    7991
    8092#endif
  • uspace/lib/c/include/inet/iplink_srv.h

    rf5f79cd ra17356fd  
    5757        int (*close)(iplink_srv_t *);
    5858        int (*send)(iplink_srv_t *, iplink_sdu_t *);
     59        int (*send6)(iplink_srv_t *, iplink_sdu6_t *);
    5960        int (*get_mtu)(iplink_srv_t *, size_t *);
     61        int (*get_mac48)(iplink_srv_t *, addr48_t *);
    6062        int (*addr_add)(iplink_srv_t *, inet_addr_t *);
    6163        int (*addr_remove)(iplink_srv_t *, inet_addr_t *);
  • uspace/lib/c/include/ipc/iplink.h

    rf5f79cd ra17356fd  
    4040typedef enum {
    4141        IPLINK_GET_MTU = IPC_FIRST_USER_METHOD,
     42        IPLINK_GET_MAC48,
    4243        IPLINK_SEND,
     44        IPLINK_SEND6,
    4345        IPLINK_ADDR_ADD,
    4446        IPLINK_ADDR_REMOVE
  • uspace/srv/net/ethip/ethip.c

    rf5f79cd ra17356fd  
    5656static int ethip_close(iplink_srv_t *srv);
    5757static int ethip_send(iplink_srv_t *srv, iplink_sdu_t *sdu);
     58static int ethip_send6(iplink_srv_t *srv, iplink_sdu6_t *sdu);
    5859static int ethip_get_mtu(iplink_srv_t *srv, size_t *mtu);
     60static int ethip_get_mac48(iplink_srv_t *srv, addr48_t *mac);
    5961static int ethip_addr_add(iplink_srv_t *srv, inet_addr_t *addr);
    6062static int ethip_addr_remove(iplink_srv_t *srv, inet_addr_t *addr);
     
    6668        .close = ethip_close,
    6769        .send = ethip_send,
     70        .send6 = ethip_send6,
    6871        .get_mtu = ethip_get_mtu,
     72        .get_mac48 = ethip_get_mac48,
    6973        .addr_add = ethip_addr_add,
    7074        .addr_remove = ethip_addr_remove
     
    169173       
    170174        ethip_nic_t *nic = (ethip_nic_t *) srv->arg;
    171        
    172         addr32_t src_v4;
    173         addr128_t src_v6;
    174         uint16_t src_af = inet_addr_get(&sdu->src, &src_v4, &src_v6);
    175        
    176         addr32_t dest_v4;
    177         addr128_t dest_v6;
    178         uint16_t dest_af = inet_addr_get(&sdu->dest, &dest_v4, &dest_v6);
    179        
    180         if (src_af != dest_af)
    181                 return EINVAL;
    182        
    183         int rc;
    184175        eth_frame_t frame;
    185176       
    186         switch (src_af) {
    187         case AF_INET:
    188                 rc = arp_translate(nic, src_v4, dest_v4, frame.dest);
    189                 if (rc != EOK) {
    190                         log_msg(LOG_DEFAULT, LVL_WARN, "Failed to look up IPv4 address 0x%"
    191                             PRIx32, dest_v4);
    192                         return rc;
    193                 }
    194                
    195                 addr48(nic->mac_addr, frame.src);
    196                 frame.etype_len = ETYPE_IP;
    197                 frame.data = sdu->data;
    198                 frame.size = sdu->size;
    199                
    200                 break;
    201         case AF_INET6:
    202                 // FIXME TODO
    203                 return ENOTSUP;
    204         default:
    205                 return EINVAL;
    206         }
     177        int rc = arp_translate(nic, sdu->src, sdu->dest, frame.dest);
     178        if (rc != EOK) {
     179                log_msg(LOG_DEFAULT, LVL_WARN, "Failed to look up IPv4 address 0x%"
     180                    PRIx32, sdu->dest);
     181                return rc;
     182        }
     183       
     184        addr48(nic->mac_addr, frame.src);
     185        frame.etype_len = ETYPE_IP;
     186        frame.data = sdu->data;
     187        frame.size = sdu->size;
    207188       
    208189        void *data;
    209190        size_t size;
    210191        rc = eth_pdu_encode(&frame, &data, &size);
     192        if (rc != EOK)
     193                return rc;
     194       
     195        rc = ethip_nic_send(nic, data, size);
     196        free(data);
     197       
     198        return rc;
     199}
     200
     201static int ethip_send6(iplink_srv_t *srv, iplink_sdu6_t *sdu)
     202{
     203        log_msg(LOG_DEFAULT, LVL_DEBUG, "ethip_send6()");
     204       
     205        ethip_nic_t *nic = (ethip_nic_t *) srv->arg;
     206        eth_frame_t frame;
     207       
     208        addr48(sdu->dest, frame.dest);
     209        addr48(nic->mac_addr, frame.src);
     210        frame.etype_len = ETYPE_IPV6;
     211        frame.data = sdu->data;
     212        frame.size = sdu->size;
     213       
     214        void *data;
     215        size_t size;
     216        int rc = eth_pdu_encode(&frame, &data, &size);
    211217        if (rc != EOK)
    212218                return rc;
     
    268274}
    269275
     276static int ethip_get_mac48(iplink_srv_t *srv, addr48_t *mac)
     277{
     278        log_msg(LOG_DEFAULT, LVL_DEBUG, "ethip_get_mac48()");
     279       
     280        ethip_nic_t *nic = (ethip_nic_t *) srv->arg;
     281        addr48(nic->mac_addr, *mac);
     282       
     283        return EOK;
     284}
     285
    270286static int ethip_addr_add(iplink_srv_t *srv, inet_addr_t *addr)
    271287{
  • uspace/srv/net/inetsrv/Makefile

    rf5f79cd ra17356fd  
    3939        inetping.c \
    4040        inetping6.c \
     41        ndp.c \
     42        ntrans.c \
    4143        pdu.c \
    4244        reass.c \
  • uspace/srv/net/inetsrv/addrobj.c

    rf5f79cd ra17356fd  
    4242#include <stdlib.h>
    4343#include <str.h>
     44#include <net/socket_codes.h>
    4445#include "addrobj.h"
    4546#include "inetsrv.h"
    4647#include "inet_link.h"
     48#include "ndp.h"
    4749
    4850static inet_addrobj_t *inet_addrobj_find_by_name_locked(const char *, inet_link_t *);
     
    214216        inet_naddr_addr(&addr->naddr, &lsrc_addr);
    215217       
    216         return inet_link_send_dgram(addr->ilink, &lsrc_addr, ldest, dgram,
    217             proto, ttl, df);
     218        addr32_t lsrc_v4;
     219        addr128_t lsrc_v6;
     220        uint16_t lsrc_af = inet_addr_get(&lsrc_addr, &lsrc_v4, &lsrc_v6);
     221       
     222        addr32_t ldest_v4;
     223        addr128_t ldest_v6;
     224        uint16_t ldest_af = inet_addr_get(ldest, &ldest_v4, &ldest_v6);
     225       
     226        if (lsrc_af != ldest_af)
     227                return EINVAL;
     228       
     229        int rc;
     230        addr48_t ldest_mac;
     231       
     232        switch (ldest_af) {
     233        case AF_INET:
     234                return inet_link_send_dgram(addr->ilink, lsrc_v4, ldest_v4,
     235                    dgram, proto, ttl, df);
     236        case AF_INET6:
     237                /*
     238                 * Translate local destination IPv6 address.
     239                 */
     240                rc = ndp_translate(lsrc_v6, ldest_v6, ldest_mac, addr->ilink);
     241                if (rc != EOK)
     242                        return rc;
     243               
     244                return inet_link_send_dgram6(addr->ilink, ldest_mac, dgram,
     245                    proto, ttl, df);
     246        }
     247       
     248        return ENOTSUP;
    218249}
    219250
  • uspace/srv/net/inetsrv/icmpv6.c

    rf5f79cd ra17356fd  
    4747#include "pdu.h"
    4848
    49 static int ndp_received(inet_dgram_t *dgram)
    50 {
    51         // FIXME TODO
    52         return ENOTSUP;
    53 }
    54 
    5549static int icmpv6_recv_echo_request(inet_dgram_t *dgram)
    5650{
  • uspace/srv/net/inetsrv/icmpv6_std.h

    rf5f79cd ra17356fd  
    4747#define INET6_HOP_LIMIT_MAX  255
    4848
     49#define NDP_FLAG_ROUTER     0x80
     50#define NDP_FLAG_OVERRIDE   0x40
     51#define NDP_FLAG_SOLICITED  0x20
     52
    4953/** ICMPv6 message type */
    5054enum icmpv6_type {
     
    8387                        uint8_t flags;
    8488                        /** Reserved bytes */
    85                         uint8_t reserved [3];
     89                        uint8_t reserved[3];
    8690                } ndp;
    8791        } un;
     
    9195typedef struct {
    9296        /** Source IPv6 address */
    93         uint8_t src_addr [16];
     97        uint8_t src_addr[16];
    9498        /** Target IPv6 address */
    95         uint8_t dest_addr [16];
     99        uint8_t dest_addr[16];
    96100        /** ICMPv6 length */
    97101        uint32_t length;
    98102        /** Zeroes */
    99         uint8_t zeroes [3];
     103        uint8_t zeroes[3];
    100104        /** Next header */
    101105        uint8_t next;
     
    105109typedef struct {
    106110        /** Target IPv6 address */
    107         uint8_t target_address [16];
     111        uint8_t target_address[16];
    108112        /** Option code */
    109113        uint8_t option;
     
    111115        uint8_t length;
    112116        /** MAC address */
    113         uint8_t mac [6];
     117        uint8_t mac[6];
    114118} ndp_message_t;
    115119
     
    131135        uint32_t reserved;
    132136        /** Prefix */
    133         uint8_t prefix [16];
     137        uint8_t prefix[16];
    134138} ndp_prefix_t;
    135139
  • uspace/srv/net/inetsrv/inet_link.c

    rf5f79cd ra17356fd  
    201201                goto error;
    202202        }
     203       
     204        /*
     205         * Get the MAC address of the link. If the link has a MAC
     206         * address, we assume that it supports NDP.
     207         */
     208        rc = iplink_get_mac48(ilink->iplink, &ilink->mac);
     209        ilink->mac_valid = (rc == EOK);
    203210
    204211        log_msg(LOG_DEFAULT, LVL_DEBUG, "Opened IP link '%s'", ilink->svc_name);
     
    298305}
    299306
    300 /** Send datagram over Internet link */
    301 int inet_link_send_dgram(inet_link_t *ilink, inet_addr_t *lsrc,
    302     inet_addr_t *ldest, inet_dgram_t *dgram, uint8_t proto, uint8_t ttl, int df)
    303 {
     307/** Send IPv4 datagram over Internet link */
     308int inet_link_send_dgram(inet_link_t *ilink, addr32_t lsrc, addr32_t ldest,
     309    inet_dgram_t *dgram, uint8_t proto, uint8_t ttl, int df)
     310{
     311        addr32_t src_v4;
     312        uint16_t src_af = inet_addr_get(&dgram->src, &src_v4, NULL);
     313        if (src_af != AF_INET)
     314                return EINVAL;
     315       
     316        addr32_t dest_v4;
     317        uint16_t dest_af = inet_addr_get(&dgram->dest, &dest_v4, NULL);
     318        if (dest_af != AF_INET)
     319                return EINVAL;
     320       
    304321        /*
    305322         * Fill packet structure. Fragmentation is performed by
    306323         * inet_pdu_encode().
    307324         */
     325       
     326        iplink_sdu_t sdu;
     327       
     328        sdu.src = lsrc;
     329        sdu.dest = ldest;
    308330       
    309331        inet_packet_t packet;
     
    318340        packet.size = dgram->size;
    319341       
    320         iplink_sdu_t sdu;
    321342        size_t offs = 0;
    322343        int rc;
    323        
    324         sdu.src = *lsrc;
    325         sdu.dest = *ldest;
    326344       
    327345        do {
    328346                /* Encode one fragment */
     347               
    329348                size_t roffs;
    330                 rc = inet_pdu_encode(&packet, offs, ilink->def_mtu, &sdu.data,
    331                     &sdu.size, &roffs);
     349                rc = inet_pdu_encode(&packet, src_v4, dest_v4, offs, ilink->def_mtu,
     350                    &sdu.data, &sdu.size, &roffs);
    332351                if (rc != EOK)
    333352                        return rc;
     
    335354                /* Send the PDU */
    336355                rc = iplink_send(ilink->iplink, &sdu);
     356               
    337357                free(sdu.data);
    338                
     358                offs = roffs;
     359        } while (offs < packet.size);
     360       
     361        return rc;
     362}
     363
     364/** Send IPv6 datagram over Internet link */
     365int inet_link_send_dgram6(inet_link_t *ilink, addr48_t ldest,
     366    inet_dgram_t *dgram, uint8_t proto, uint8_t ttl, int df)
     367{
     368        addr128_t src_v6;
     369        uint16_t src_af = inet_addr_get(&dgram->src, NULL, &src_v6);
     370        if (src_af != AF_INET6)
     371                return EINVAL;
     372       
     373        addr128_t dest_v6;
     374        uint16_t dest_af = inet_addr_get(&dgram->dest, NULL, &dest_v6);
     375        if (dest_af != AF_INET6)
     376                return EINVAL;
     377       
     378        iplink_sdu6_t sdu6;
     379        addr48(ldest, sdu6.dest);
     380       
     381        /*
     382         * Fill packet structure. Fragmentation is performed by
     383         * inet_pdu_encode6().
     384         */
     385       
     386        inet_packet_t packet;
     387       
     388        packet.src = dgram->src;
     389        packet.dest = dgram->dest;
     390        packet.tos = dgram->tos;
     391        packet.proto = proto;
     392        packet.ttl = ttl;
     393        packet.df = df;
     394        packet.data = dgram->data;
     395        packet.size = dgram->size;
     396       
     397        int rc;
     398        size_t offs = 0;
     399       
     400        do {
     401                /* Encode one fragment */
     402               
     403                size_t roffs;
     404                rc = inet_pdu_encode6(&packet, src_v6, dest_v6, offs, ilink->def_mtu,
     405                    &sdu6.data, &sdu6.size, &roffs);
     406                if (rc != EOK)
     407                        return rc;
     408               
     409                /* Send the PDU */
     410                rc = iplink_send6(ilink->iplink, &sdu6);
     411               
     412                free(sdu6.data);
    339413                offs = roffs;
    340414        } while (offs < packet.size);
  • uspace/srv/net/inetsrv/inet_link.h

    rf5f79cd ra17356fd  
    4242
    4343extern int inet_link_discovery_start(void);
    44 extern int inet_link_send_dgram(inet_link_t *, inet_addr_t *,
    45     inet_addr_t *, inet_dgram_t *, uint8_t, uint8_t, int);
     44extern int inet_link_send_dgram(inet_link_t *, addr32_t,
     45    addr32_t, inet_dgram_t *, uint8_t, uint8_t, int);
     46extern int inet_link_send_dgram6(inet_link_t *, addr48_t, inet_dgram_t *,
     47    uint8_t, uint8_t, int);
    4648extern inet_link_t *inet_link_get_by_id(sysarg_t);
    4749
  • uspace/srv/net/inetsrv/inetping6.c

    rf5f79cd ra17356fd  
    109109        aid_t req = async_send_1(exch, INETPING6_EV_RECV, sdu->seq_no, &answer);
    110110       
    111         int rc = async_data_write_start(exch, sdu->src, 16);
     111        int rc = async_data_write_start(exch, sdu->src, sizeof(addr128_t));
    112112        if (rc != EOK) {
    113113                async_exchange_end(exch);
     
    116116        }
    117117       
    118         rc = async_data_write_start(exch, sdu->dest, 16);
     118        rc = async_data_write_start(exch, sdu->dest, sizeof(addr128_t));
    119119        if (rc != EOK) {
    120120                async_exchange_end(exch);
  • uspace/srv/net/inetsrv/inetsrv.h

    rf5f79cd ra17356fd  
    141141        iplink_t *iplink;
    142142        size_t def_mtu;
     143        addr48_t mac;
     144        bool mac_valid;
    143145} inet_link_t;
    144146
  • uspace/srv/net/inetsrv/pdu.c

    rf5f79cd ra17356fd  
    8888}
    8989
    90 /** Encode Internet PDU.
     90/** Encode IPv4 PDU.
    9191 *
    9292 * Encode internet packet into PDU (serialized form). Will encode a
     
    9696 * be set in the header, otherwise the offset will equal @a packet->size.
    9797 *
    98  * @param packet        Packet to encode
    99  * @param offs          Offset into packet payload (in bytes)
    100  * @param mtu           MTU (Maximum Transmission Unit) in bytes
    101  * @param rdata         Place to store pointer to allocated data buffer
    102  * @param rsize         Place to store size of allocated data buffer
    103  * @param roffs         Place to store offset of remaning data
    104  */
    105 int inet_pdu_encode(inet_packet_t *packet, size_t offs, size_t mtu,
    106     void **rdata, size_t *rsize, size_t *roffs)
    107 {
    108         addr32_t src_v4;
    109         addr128_t src_v6;
    110         uint16_t src_af = inet_addr_get(&packet->src, &src_v4, &src_v6);
    111        
    112         addr32_t dest_v4;
    113         addr128_t dest_v6;
    114         uint16_t dest_af = inet_addr_get(&packet->dest, &dest_v4, &dest_v6);
    115        
    116         if (src_af != dest_af)
    117                 return EINVAL;
    118        
     98 * @param packet Packet to encode
     99 * @param src    Source address
     100 * @param dest   Destination address
     101 * @param offs   Offset into packet payload (in bytes)
     102 * @param mtu    MTU (Maximum Transmission Unit) in bytes
     103 * @param rdata  Place to store pointer to allocated data buffer
     104 * @param rsize  Place to store size of allocated data buffer
     105 * @param roffs  Place to store offset of remaning data
     106 *
     107 */
     108int inet_pdu_encode(inet_packet_t *packet, addr32_t src, addr32_t dest,
     109   size_t offs, size_t mtu, void **rdata, size_t *rsize, size_t *roffs)
     110{
    119111        /* Upper bound for fragment offset field */
    120112        size_t fragoff_limit = 1 << (FF_FRAGOFF_h - FF_FRAGOFF_l);
     
    124116                return ELIMIT;
    125117       
    126         size_t hdr_size;
    127        
    128         switch (src_af) {
    129         case AF_INET:
    130                 hdr_size = sizeof(ip_header_t);
    131                 break;
    132         case AF_INET6:
    133                 hdr_size = sizeof(ip6_header_t);
    134                 break;
    135         default:
    136                 assert(false);
    137         }
     118        size_t hdr_size = sizeof(ip_header_t);
    138119       
    139120        size_t data_offs = ROUND_UP(hdr_size, 4);
     
    177158       
    178159        /* Encode header fields */
    179         ip_header_t *hdr;
    180         ip6_header_t *hdr6;
    181        
    182         switch (src_af) {
    183         case AF_INET:
    184                 hdr = (ip_header_t *) data;
    185                
    186                 hdr->ver_ihl =
    187                     (4 << VI_VERSION_l) | (hdr_size / sizeof(uint32_t));
    188                 hdr->tos = packet->tos;
    189                 hdr->tot_len = host2uint16_t_be(size);
    190                 hdr->id = host2uint16_t_be(ident);
    191                 hdr->flags_foff = host2uint16_t_be(flags_foff);
    192                 hdr->ttl = packet->ttl;
    193                 hdr->proto = packet->proto;
    194                 hdr->chksum = 0;
    195                 hdr->src_addr = host2uint32_t_be(src_v4);
    196                 hdr->dest_addr = host2uint32_t_be(dest_v4);
    197                
    198                 /* Compute checksum */
    199                 uint16_t chksum = inet_checksum_calc(INET_CHECKSUM_INIT,
    200                     (void *) hdr, hdr_size);
    201                 hdr->chksum = host2uint16_t_be(chksum);
    202                
    203                 break;
    204         case AF_INET6:
    205                 // TODO FIXME: fragmentation
    206                
    207                 hdr6 = (ip6_header_t *) data;
    208                
    209                 hdr6->ver_tc = (6 << (VI_VERSION_l));
    210                 memset(hdr6->tc_fl, 0, 3);
    211                 hdr6->payload_len = host2uint16_t_be(packet->size);
    212                 hdr6->next = packet->proto;
    213                 hdr6->hop_limit = packet->ttl;
    214                
    215                 host2addr128_t_be(src_v6, hdr6->src_addr);
    216                 host2addr128_t_be(dest_v6, hdr6->dest_addr);
    217                
    218                 break;
    219         default:
    220                 assert(false);
    221         }
     160        ip_header_t *hdr = (ip_header_t *) data;
     161       
     162        hdr->ver_ihl =
     163            (4 << VI_VERSION_l) | (hdr_size / sizeof(uint32_t));
     164        hdr->tos = packet->tos;
     165        hdr->tot_len = host2uint16_t_be(size);
     166        hdr->id = host2uint16_t_be(ident);
     167        hdr->flags_foff = host2uint16_t_be(flags_foff);
     168        hdr->ttl = packet->ttl;
     169        hdr->proto = packet->proto;
     170        hdr->chksum = 0;
     171        hdr->src_addr = host2uint32_t_be(src);
     172        hdr->dest_addr = host2uint32_t_be(dest);
     173       
     174        /* Compute checksum */
     175        uint16_t chksum = inet_checksum_calc(INET_CHECKSUM_INIT,
     176            (void *) hdr, hdr_size);
     177        hdr->chksum = host2uint16_t_be(chksum);
     178       
     179        /* Copy payload */
     180        memcpy((uint8_t *) data + data_offs, packet->data + offs, xfer_size);
     181       
     182        *rdata = data;
     183        *rsize = size;
     184        *roffs = rem_offs;
     185       
     186        return EOK;
     187}
     188
     189/** Encode IPv6 PDU.
     190 *
     191 * Encode internet packet into PDU (serialized form). Will encode a
     192 * fragment of the payload starting at offset @a offs. The resulting
     193 * PDU will have at most @a mtu bytes. @a *roffs will be set to the offset
     194 * of remaining payload. If some data is remaining, the MF flag will
     195 * be set in the header, otherwise the offset will equal @a packet->size.
     196 *
     197 * @param packet Packet to encode
     198 * @param src    Source address
     199 * @param dest   Destination address
     200 * @param offs   Offset into packet payload (in bytes)
     201 * @param mtu    MTU (Maximum Transmission Unit) in bytes
     202 * @param rdata  Place to store pointer to allocated data buffer
     203 * @param rsize  Place to store size of allocated data buffer
     204 * @param roffs Place to store offset of remaning data
     205 *
     206 */
     207int inet_pdu_encode6(inet_packet_t *packet, addr128_t src, addr128_t dest,
     208    size_t offs, size_t mtu, void **rdata, size_t *rsize, size_t *roffs)
     209{
     210        /* Upper bound for fragment offset field */
     211        size_t fragoff_limit = 1 << (FF_FRAGOFF_h - FF_FRAGOFF_l);
     212       
     213        /* Verify that total size of datagram is within reasonable bounds */
     214        if (offs + packet->size > FRAG_OFFS_UNIT * fragoff_limit)
     215                return ELIMIT;
     216       
     217        size_t hdr_size = sizeof(ip6_header_t);
     218       
     219        size_t data_offs = ROUND_UP(hdr_size, 4);
     220       
     221        assert(offs % FRAG_OFFS_UNIT == 0);
     222        assert(offs / FRAG_OFFS_UNIT < fragoff_limit);
     223       
     224#if 0
     225        // FIXME TODO fragmentation
     226       
     227        /* Value for the fragment offset field */
     228        uint16_t foff = offs / FRAG_OFFS_UNIT;
     229#endif
     230       
     231        if (hdr_size >= mtu)
     232                return EINVAL;
     233       
     234        /* Amount of space in the PDU available for payload */
     235        size_t spc_avail = mtu - hdr_size;
     236        spc_avail -= (spc_avail % FRAG_OFFS_UNIT);
     237       
     238        /* Amount of data (payload) to transfer */
     239        size_t xfer_size = min(packet->size - offs, spc_avail);
     240       
     241        /* Total PDU size */
     242        size_t size = hdr_size + xfer_size;
     243       
     244        /* Offset of remaining payload */
     245        size_t rem_offs = offs + xfer_size;
     246       
     247#if 0
     248        // FIXME TODO fragmentation
     249       
     250        /* Flags */
     251        uint16_t flags_foff =
     252            (packet->df ? BIT_V(uint16_t, FF_FLAG_DF) : 0) +
     253            (rem_offs < packet->size ? BIT_V(uint16_t, FF_FLAG_MF) : 0) +
     254            (foff << FF_FRAGOFF_l);
     255#endif
     256       
     257        void *data = calloc(size, 1);
     258        if (data == NULL)
     259                return ENOMEM;
     260       
     261#if 0
     262        // FIXME TODO fragmentation
     263       
     264        /* Allocate identifier */
     265        fibril_mutex_lock(&ip_ident_lock);
     266        uint16_t ident = ++ip_ident;
     267        fibril_mutex_unlock(&ip_ident_lock);
     268#endif
     269       
     270        /* Encode header fields */
     271        ip6_header_t *hdr6 = (ip6_header_t *) data;
     272       
     273        hdr6->ver_tc = (6 << (VI_VERSION_l));
     274        memset(hdr6->tc_fl, 0, 3);
     275        hdr6->payload_len = host2uint16_t_be(packet->size);
     276        hdr6->next = packet->proto;
     277        hdr6->hop_limit = packet->ttl;
     278       
     279        host2addr128_t_be(src, hdr6->src_addr);
     280        host2addr128_t_be(dest, hdr6->dest_addr);
    222281       
    223282        /* Copy payload */
     
    257316        if (tot_len > size) {
    258317                log_msg(LOG_DEFAULT, LVL_DEBUG, "Total Length = %zu > PDU size = %zu",
    259                         tot_len, size);
     318                    tot_len, size);
    260319                return EINVAL;
    261320        }
     
    296355int inet_pdu_decode6(void *data, size_t size, inet_packet_t *packet)
    297356{
    298         // FIXME TODO
    299         return ENOTSUP;
     357        log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_pdu_decode6()");
     358       
     359        if (size < sizeof(ip6_header_t)) {
     360                log_msg(LOG_DEFAULT, LVL_DEBUG, "PDU too short (%zu)", size);
     361                return EINVAL;
     362        }
     363       
     364        ip6_header_t *hdr6 = (ip6_header_t *) data;
     365       
     366        uint8_t version = BIT_RANGE_EXTRACT(uint8_t, VI_VERSION_h,
     367            VI_VERSION_l, hdr6->ver_tc);
     368        if (version != 6) {
     369                log_msg(LOG_DEFAULT, LVL_DEBUG, "Version (%d) != 6", version);
     370                return EINVAL;
     371        }
     372       
     373        size_t payload_len = uint16_t_be2host(hdr6->payload_len);
     374        if (payload_len + sizeof(ip6_header_t) > size) {
     375                log_msg(LOG_DEFAULT, LVL_DEBUG, "Total Length = %zu > PDU size = %zu",
     376                    payload_len + sizeof(ip6_header_t), size);
     377                return EINVAL;
     378        }
     379       
     380#if 0
     381        // FIXME TODO fragmentation
     382       
     383        uint16_t ident = uint16_t_be2host(hdr->id);
     384        uint16_t flags_foff = uint16_t_be2host(hdr->flags_foff);
     385        uint16_t foff = BIT_RANGE_EXTRACT(uint16_t, FF_FRAGOFF_h, FF_FRAGOFF_l,
     386            flags_foff);
     387#endif
     388       
     389        /* XXX Checksum */
     390       
     391        addr128_t src;
     392        addr128_t dest;
     393       
     394        addr128_t_be2host(hdr6->src_addr, src);
     395        inet_addr_set6(src, &packet->src);
     396       
     397        addr128_t_be2host(hdr6->dest_addr, dest);
     398        inet_addr_set6(dest, &packet->dest);
     399       
     400        packet->tos = 0;
     401        packet->proto = hdr6->next;
     402        packet->ttl = hdr6->hop_limit;
     403       
     404#if 0
     405        // FIXME TODO fragmentation
     406       
     407        packet->ident = ident;
     408        packet->df = (flags_foff & BIT_V(uint16_t, FF_FLAG_DF)) != 0;
     409        packet->mf = (flags_foff & BIT_V(uint16_t, FF_FLAG_MF)) != 0;
     410        packet->offs = foff * FRAG_OFFS_UNIT;
     411       
     412        /* XXX IP options */
     413        size_t data_offs = sizeof(uint32_t) *
     414            BIT_RANGE_EXTRACT(uint8_t, VI_IHL_h, VI_IHL_l, hdr->ver_ihl);
     415#endif
     416       
     417        packet->ident = 0;
     418        packet->df = 0;
     419        packet->mf = 0;
     420        packet->offs = 0;
     421       
     422        packet->size = payload_len;
     423        packet->data = calloc(packet->size, 1);
     424        if (packet->data == NULL) {
     425                log_msg(LOG_DEFAULT, LVL_WARN, "Out of memory.");
     426                return ENOMEM;
     427        }
     428       
     429        memcpy(packet->data, (uint8_t *) data + sizeof(ip6_header_t), packet->size);
     430       
     431        return EOK;
     432}
     433
     434int ndp_pdu_encode(ndp_packet_t *ndp, inet_dgram_t *dgram)
     435{
     436        inet_addr_set6(ndp->sender_proto_addr, &dgram->src);
     437        inet_addr_set6(ndp->target_proto_addr, &dgram->dest);
     438        dgram->tos = 0;
     439        dgram->size = sizeof(icmpv6_message_t) + sizeof(ndp_message_t);
     440       
     441        dgram->data = calloc(1, dgram->size);
     442        if (dgram->data == NULL)
     443                return ENOMEM;
     444       
     445        icmpv6_message_t *icmpv6 = (icmpv6_message_t *) dgram->data;
     446       
     447        icmpv6->type = ndp->opcode;
     448        icmpv6->code = 0;
     449        memset(icmpv6->un.ndp.reserved, 0, 3);
     450       
     451        ndp_message_t *message = (ndp_message_t *) (icmpv6 + 1);
     452       
     453        if (ndp->opcode == ICMPV6_NEIGHBOUR_SOLICITATION) {
     454                host2addr128_t_be(ndp->solicited_ip, message->target_address);
     455                message->option = 1;
     456                icmpv6->un.ndp.flags = 0;
     457        } else {
     458                host2addr128_t_be(ndp->sender_proto_addr, message->target_address);
     459                message->option = 2;
     460                icmpv6->un.ndp.flags = NDP_FLAG_OVERRIDE | NDP_FLAG_SOLICITED;
     461        }
     462       
     463        message->length = 1;
     464        addr48(ndp->sender_hw_addr, message->mac);
     465       
     466        icmpv6_pseudo_header phdr;
     467       
     468        host2addr128_t_be(ndp->sender_proto_addr, phdr.src_addr);
     469        host2addr128_t_be(ndp->target_proto_addr, phdr.dest_addr);
     470        phdr.length = host2uint32_t_be(dgram->size);
     471        memset(phdr.zeroes, 0, 3);
     472        phdr.next = IP_PROTO_ICMPV6;
     473       
     474        uint16_t cs_phdr =
     475            inet_checksum_calc(INET_CHECKSUM_INIT, &phdr,
     476            sizeof(icmpv6_pseudo_header));
     477       
     478        uint16_t cs_all = inet_checksum_calc(cs_phdr, dgram->data,
     479            dgram->size);
     480       
     481        icmpv6->checksum = host2uint16_t_be(cs_all);
     482       
     483        return EOK;
     484}
     485
     486int ndp_pdu_decode(inet_dgram_t *dgram, ndp_packet_t *ndp)
     487{
     488        uint16_t src_af = inet_addr_get(&dgram->src, NULL,
     489            &ndp->sender_proto_addr);
     490        if (src_af != AF_INET6)
     491                return EINVAL;
     492       
     493        if (dgram->size < sizeof(icmpv6_message_t) + sizeof(ndp_message_t))
     494                return EINVAL;
     495       
     496        icmpv6_message_t *icmpv6 = (icmpv6_message_t *) dgram->data;
     497       
     498        ndp->opcode = icmpv6->type;
     499       
     500        ndp_message_t *message = (ndp_message_t *) (icmpv6 + 1);
     501       
     502        addr128_t_be2host(message->target_address, ndp->target_proto_addr);
     503        addr48(message->mac, ndp->sender_hw_addr);
     504       
     505        return EOK;
    300506}
    301507
  • uspace/srv/net/inetsrv/pdu.h

    rf5f79cd ra17356fd  
    4040#include <sys/types.h>
    4141#include "inetsrv.h"
     42#include "ndp.h"
    4243
    4344#define INET_CHECKSUM_INIT 0xffff
     
    4546extern uint16_t inet_checksum_calc(uint16_t, void *, size_t);
    4647
    47 extern int inet_pdu_encode(inet_packet_t *, size_t, size_t, void **,
    48     size_t *, size_t *);
     48extern int inet_pdu_encode(inet_packet_t *, addr32_t, addr32_t, size_t, size_t,
     49    void **, size_t *, size_t *);
     50extern int inet_pdu_encode6(inet_packet_t *, addr128_t, addr128_t, size_t,
     51    size_t, void **, size_t *, size_t *);
    4952extern int inet_pdu_decode(void *, size_t, inet_packet_t *);
    5053extern int inet_pdu_decode6(void *, size_t, inet_packet_t *);
     54
     55extern int ndp_pdu_decode(inet_dgram_t *, ndp_packet_t *);
     56extern int ndp_pdu_encode(ndp_packet_t *, inet_dgram_t *);
    5157
    5258#endif
  • uspace/srv/net/loopip/loopip.c

    rf5f79cd ra17356fd  
    4040#include <inet/iplink_srv.h>
    4141#include <inet/addr.h>
     42#include <net/socket_codes.h>
    4243#include <io/log.h>
    4344#include <loc.h>
     
    5051static int loopip_close(iplink_srv_t *srv);
    5152static int loopip_send(iplink_srv_t *srv, iplink_sdu_t *sdu);
     53static int loopip_send6(iplink_srv_t *srv, iplink_sdu6_t *sdu);
    5254static int loopip_get_mtu(iplink_srv_t *srv, size_t *mtu);
     55static int loopip_get_mac48(iplink_srv_t *srv, addr48_t *mac);
    5356static int loopip_addr_add(iplink_srv_t *srv, inet_addr_t *addr);
    5457static int loopip_addr_remove(iplink_srv_t *srv, inet_addr_t *addr);
     
    6063        .close = loopip_close,
    6164        .send = loopip_send,
     65        .send6 = loopip_send6,
    6266        .get_mtu = loopip_get_mtu,
     67        .get_mac48 = loopip_get_mac48,
    6368        .addr_add = loopip_addr_add,
    6469        .addr_remove = loopip_addr_remove
     
    162167        log_msg(LOG_DEFAULT, LVL_DEBUG, "loopip_send()");
    163168       
    164         addr32_t src_v4;
    165         addr128_t src_v6;
    166         uint16_t src_af = inet_addr_get(&sdu->src, &src_v4, &src_v6);
    167        
    168         addr32_t dest_v4;
    169         addr128_t dest_v6;
    170         uint16_t dest_af = inet_addr_get(&sdu->dest, &dest_v4, &dest_v6);
    171        
    172         if (src_af != dest_af)
    173                 return EINVAL;
    174        
    175169        rqueue_entry_t *rqe = calloc(1, sizeof(rqueue_entry_t));
    176170        if (rqe == NULL)
     
    180174         * Clone SDU
    181175         */
    182         rqe->af = src_af;
     176        rqe->af = AF_INET;
    183177        rqe->sdu.data = malloc(sdu->size);
    184178        if (rqe->sdu.data == NULL) {
     
    198192}
    199193
     194static int loopip_send6(iplink_srv_t *srv, iplink_sdu6_t *sdu)
     195{
     196        log_msg(LOG_DEFAULT, LVL_DEBUG, "loopip6_send()");
     197       
     198        rqueue_entry_t *rqe = calloc(1, sizeof(rqueue_entry_t));
     199        if (rqe == NULL)
     200                return ENOMEM;
     201       
     202        /*
     203         * Clone SDU
     204         */
     205        rqe->af = AF_INET6;
     206        rqe->sdu.data = malloc(sdu->size);
     207        if (rqe->sdu.data == NULL) {
     208                free(rqe);
     209                return ENOMEM;
     210        }
     211       
     212        memcpy(rqe->sdu.data, sdu->data, sdu->size);
     213        rqe->sdu.size = sdu->size;
     214       
     215        /*
     216         * Insert to receive queue
     217         */
     218        prodcons_produce(&loopip_rcv_queue, &rqe->link);
     219       
     220        return EOK;
     221}
     222
    200223static int loopip_get_mtu(iplink_srv_t *srv, size_t *mtu)
    201224{
     
    203226        *mtu = 1500;
    204227        return EOK;
     228}
     229
     230static int loopip_get_mac48(iplink_srv_t *src, addr48_t *mac)
     231{
     232        log_msg(LOG_DEFAULT, LVL_DEBUG, "loopip_get_mac48()");
     233        return ENOTSUP;
    205234}
    206235
  • uspace/srv/net/slip/slip.c

    rf5f79cd ra17356fd  
    5858static int slip_close(iplink_srv_t *);
    5959static int slip_send(iplink_srv_t *, iplink_sdu_t *);
     60static int slip_send6(iplink_srv_t *, iplink_sdu6_t *);
    6061static int slip_get_mtu(iplink_srv_t *, size_t *);
     62static int slip_get_mac48(iplink_srv_t *, addr48_t *);
    6163static int slip_addr_add(iplink_srv_t *, inet_addr_t *);
    6264static int slip_addr_remove(iplink_srv_t *, inet_addr_t *);
     
    6870        .close = slip_close,
    6971        .send = slip_send,
     72        .send6 = slip_send6,
    7073        .get_mtu = slip_get_mtu,
     74        .get_mac48 = slip_get_mac48,
    7175        .addr_add = slip_addr_add,
    7276        .addr_remove = slip_addr_remove
     
    122126int slip_send(iplink_srv_t *srv, iplink_sdu_t *sdu)
    123127{
     128        log_msg(LOG_DEFAULT, LVL_DEBUG, "slip_send()");
     129       
    124130        async_sess_t *sess = (async_sess_t *) srv->arg;
    125131        uint8_t *data = sdu->data;
    126         unsigned i;
    127 
    128         log_msg(LOG_DEFAULT, LVL_DEBUG, "slip_send()");
    129 
     132       
    130133        /*
    131          * Strictly speaking, this is not prescribed by the RFC, but the RFC
    132          * suggests to start with sending a SLIP_END byte as a synchronization
    133          * measure for dealing with previous possible noise on the line.
    134          */
     134         * Strictly speaking, this is not prescribed by the RFC, but the RFC
     135         * suggests to start with sending a SLIP_END byte as a synchronization
     136         * measure for dealing with previous possible noise on the line.
     137         */
    135138        write_buffered(sess, SLIP_END);
    136 
    137         for (i = 0; i < sdu->size; i++) {
     139       
     140        for (size_t i = 0; i < sdu->size; i++) {
    138141                switch (data[i]) {
    139142                case SLIP_END:
     
    150153                }
    151154        }
     155       
    152156        write_buffered(sess, SLIP_END);
    153157        write_flush(sess);
    154 
    155         return EOK;
     158       
     159        return EOK;
     160}
     161
     162int slip_send6(iplink_srv_t *srv, iplink_sdu6_t *sdu)
     163{
     164        log_msg(LOG_DEFAULT, LVL_DEBUG, "slip_send6()");
     165       
     166        return ENOTSUP;
    156167}
    157168
     
    161172        *mtu = SLIP_MTU;
    162173        return EOK;
     174}
     175
     176int slip_get_mac48(iplink_srv_t *src, addr48_t *mac)
     177{
     178        log_msg(LOG_DEFAULT, LVL_DEBUG, "slip_get_mac48()");
     179        return ENOTSUP;
    163180}
    164181
Note: See TracChangeset for help on using the changeset viewer.