struct ep by xiaoyounan

VIEWS: 0 PAGES: 26

									                         3.3 Ethernet Definitions
/* ether.h */
#define EPT_LOOP 0x0060               /* type: Loopback           */
#define EPT_ECHO 0x0200               /* type: Echo                       */
#define EPT_PUP              0x0400            /* type: Xerox PUP                  */
#define EPT_IP               0x0800            /* type: Internet Protocol */
#define EPT_ARP              0x0806            /* type: ARP                        */
#define EPT_RARP 0x8035               /* type: Reverse ARP                */

struct    eh {                        /* ethernet header                           */
          Eaddr    eh_dst;            /* destination host address                  */
          Eaddr    eh_src;            /* source host address                       */
          unsigned short     eh_type;/* Ethernet packet type (see below)   */
};

struct    ep        {                 /* complete structure of Ethernet packet*/
          struct    eh ep_eh;         /* the ethernet header                       */
          char      ep_data[EP_DLEN]; /* data in the packet               */
};
#define   ep_dst    ep_eh.eh_dst
#define   ep_src    ep_eh.eh_src
#define   ep_type   ep_eh.eh_type
Demultiplexing Incoming Packets

/* ni_in.c - ni_in */
int ni_in(struct netif *pni, struct ep *pep, unsigned   len)
{
                  switch (pep->ep_type) {
         case EPT_ARP:     rv = arp_in(pni, pep);       break;
         case EPT_RARP:    rv = rarp_in(pni, pep);      break;
         case EPT_IP:      rv = ip_in(pni, pep);        break;
         default:
                  pni->ni_iunkproto++;
                  freebuf(pep);
                  rv = OK;
         }
         return rv;
}
   Address Discovery and Binding (ARP)
ARP binds high-level IP addresses to low-level physical
addresses.
Address binding software forms a boundary between higher layers of
protocol software, which use IP addresses, and lower layers of device driver
software, which use hardware addresses.
ARP is considered residing in the network interface layer.

                 TCP                   UDP


         ICMP                 IP               IGMP


          ARP              Network             RARP
                           Interface
                Network Byte Order
- Big Endian: lowest memory address holds high-order
byte of the integer
-Little Endian: lowest memory address contains low-order
byte of the integer
- Internet standard byte order: integers are sent most
significant byte first (Big Endian style). (p.69, Vol.1)

 0x128c


            n          n+1                   n             n+1
     0x12       0x8c                  0x8c        0x12

          Big endian                     Little endian
           ARP Packet Format
                                   /* arp.h - SHA, SPA, THA, TPA */

                                   #define     AR_HARDWARE 1             /* Ethernet hardware type code       */

   H/W Type                        /* Definitions of codes used in operation field of ARP packet */
                   Protocol Type
                                   #define     AR_REQUEST   1    /* ARP request to resolve address*/
 HLen. PLen. ARP Operation         #define     AR_REPLY     2    /* reply to a resolve request */

                                   #define     RA_REQUEST   3    /* reverse ARP request (RARP packets)*/
      Sender Hardware Address      #define     RA_REPLY     4    /* reply to a reverse request (RARP ")*/

                     Sender        struct      arp          {
                                               u_short      ar_hwtype;   /* hardware type                     */
                                               u_short      ar_prtype;   /* protocol type                     */
Protocol Address      Target                   u_char       ar_hwlen;    /* hardware address length
                                               */
        Hardware Address                       u_char       ar_prlen;    /* protocol address length
                                               */
        Target Protocol Address                u_short      ar_op;      /*   ARP operation (see list above)*/
                                               u_char       ar_addrs[1];/*   sender and target hw & proto addrs*/
                                   /*          char         ar_sha[???]; -   sender's physical hardware address*/
                                   /*          char         ar_spa[???]; -   sender's protocol address (IP addr.)*/
                                   /*          char         ar_tha[???]; -   target's physical hardware address*/
                                   /*          char         ar_tpa[???]; -   target's protocol address (IP)   */
                                   };
                                   #define     SHA(p)       (&p->ar_addrs[0])
                                   #define     SPA(p)       (&p->ar_addrs[p->ar_hwlen])
                                   #define     THA(p)       (&p->ar_addrs[p->ar_hwlen + p->ar_prlen])
                                   #define     TPA(p)       (&p->ar_addrs[(p->ar_hwlen*2) + p->ar_prlen])
ARP Cache Table
   struct     arpentry {               /* format of entry in ARP cache*/
              short        ae_state;/* state of this entry (see below)*/
              int          ae_queue; /* queue of packets for this address*/
              int          ae_attempts;/* number of retries so far */
              int          ae_ttl;     /* time to live          */
              u_char       ae_hwa[MAXHWALEN];                   /* Hardware address*/
              u_char       ae_pra[MAXPRALEN];                   /* Protocol address */
   };

   #define    AS_FREE 0               /* Entry is unused (initial value)*/
   #define    AS_PENDING              1           /* Entry is used but incomplete*/
   #define    AS_RESOLVED             2           /* Entry has been resolved*/

   /* ARP variables */

   extern struct           arpentry   arptable[ARP_TSIZE];

   /* ARP function declarations */
                                   ARP Input Processing
arp_in( )
{ translate the big endian to little endian;
     pae=arpfind(using SA-IP);
  if(arp-table have the entry of the SA-IP of incoming ARP
data}
             {update entry; update entry timer;}
  if (ARP.target IP =! My IP)
             freebuf(pep); return(ok);
  if(pae ==0)
             arpadd( );
   if(pae->state == AS_PENDING)                 #if         BYTE_ORDER == LITTLE_ENDIAN
             {pae->state = AS_RESOLVED; #define hs2net(x) (unsigned) ((((x)>>8) &0xff) | (((x) & 0xff)<<8))
               arpqsend();                      #define     net2hs(x) hs2net(x)
             }
    if(receive an ARP Request)                  #define hl2net(x)         (((((x)& 0xff)<<24) | ((x)>>24) & 0xff) | \
                                                            (((x) & 0xff0000)>>8) | (((x) & 0xff00)<<8))
             { to form a ARP Reply packet;      #define net2hl(x) hl2net(x)
                send an ARP Reply;              #endif
             }
}                                               #if         BYTE_ORDER == BIG_ENDIAN
                                                   #define hs2net(x) (x)
                                                   #define net2hs(x) (x)
                                                   #define hl2net(x) (x)
                                                   #define net2hl(x) (x)
                                                   #endif
/* arpfind.c - arpfind */

#include <conf.h>
#include <kernel.h>
#include <network.h>
/*------------------------------------------------------------------------
  * arpfind - find an ARP entry given a protocol address and interface
  *------------------------------------------------------------------------
  */
struct arpentry *
arpfind(u_char *pra, u_short prtype, struct netif *pni)
{
           struct arpentry      *pae;
           int                  i;

          for (i=0; i<ARP_TSIZE; ++i) {
                    pae = &arptable[i];
                    if (pae->ae_state == AS_FREE)
                               continue;
                    if (pae->ae_prtype == prtype &&
                        pae->ae_pni == pni &&
                        BLKEQU(pae->ae_pra, pra, pae->ae_prlen))
                               return pae;
          }
          return 0;
}
/* arpsend.c - arpsend */
int arpsend(struct arpentry *pae)
{
          struct     netif     *pni = pae->ae_pni;
          struct     ep        *pep;
          struct     arp       *parp;
          int                  arplen;
          pep = (struct ep *) getbuf(Net.netpool);
          if ((int)pep == SYSERR)
                     return SYSERR;
          memcpy(pep->ep_dst, pni->ni_hwb.ha_addr, pae->ae_hwlen);
          pep->ep_type = EPT_ARP;
          pep->ep_order = EPO_NET;
          parp = (struct arp *) pep->ep_data;
          parp->ar_hwtype = hs2net(pae->ae_hwtype);
          parp->ar_prtype = hs2net(pae->ae_prtype);
          parp->ar_hwlen = pae->ae_hwlen;
          parp->ar_prlen = pae->ae_prlen;
          parp->ar_op = hs2net(AR_REQUEST);
          memcpy(SHA(parp), pni->ni_hwa.ha_addr, pae->ae_hwlen);
          memcpy(SPA(parp), &pni->ni_ip, pae->ae_prlen);
          memset(THA(parp), 0, pae->ae_hwlen);
          memcpy(TPA(parp), pae->ae_pra, pae->ae_prlen);
          arplen = ARP_HLEN + 2*(parp->ar_hwlen + parp->ar_prlen);
          write(pni->ni_dev, pep, EP_HLEN+arplen);
          return OK;
}
/* arpadd.c - arpadd */
struct arpentry *arpalloc(void);
/*------------------------------------------------------------------------
 * arpadd - Add a RESOLVED entry to the ARP cache
 *           N.B. Assumes interrupts disabled
 *------------------------------------------------------------------------
 */
struct       arpentry *
arpadd(struct netif *pni, struct arp *parp)
{
             struct        arpentry *pae;

             pae = arpalloc();

             pae->ae_hwtype = parp->ar_hwtype;
             pae->ae_prtype = parp->ar_prtype;
             pae->ae_hwlen = parp->ar_hwlen;
             pae->ae_prlen = parp->ar_prlen;
             pae->ae_pni = pni;
             pae->ae_queue = EMPTY;
             memcpy(pae->ae_hwa, SHA(parp), parp->ar_hwlen);
             memcpy(pae->ae_pra, SPA(parp), parp->ar_prlen);
             pae->ae_ttl = ARP_TIMEOUT;
             pae->ae_state = AS_RESOLVED;
             return pae;
}
/* arpqsend.c - arpqsend */
int netwrite(struct netif *, struct ep *, unsigned);

/*------------------------------------------------------------------------
  * arpqsend - write packets queued waiting for an ARP resolution
  *------------------------------------------------------------------------
  */
void
arpqsend(struct arpentry *pae)
{
          struct   ep       *pep;
          struct   netif    *pni;

         if (pae->ae_queue == EMPTY)
                  return;

         pni = pae->ae_pni;
         while (pep = (struct ep *)deq(pae->ae_queue))
                  netwrite(pni, pep, pep->ep_len);
         freeq(pae->ae_queue);
         pae->ae_queue = EMPTY;
}
ARP Output Processing

                    netwrite( )
                    {
                    if (DA_IP is broadcast)
                                { DA_MAC = NIC’s H/W broadcast address ;
                                     write ( );
                                     return ok; }
                    pae = arpfind();
                        if (pae && AS_RESOLVED)
                            { DA_MAC = ARP_entry’s_H/W address;
                               return write( );
                             }
                       if (pae == 0)
                           { arpalloc ( );
                                arpsend ( );
                            }

                      enq(pae->ae_queue, pep, 0)
                    return OK;
                    }
          IP GLOBAL Software Organization

                                                       Datagrams
                      Message queue
                                                       sent to IP
                                                       from local host
                                         IP
                                       Process




Queues for
packets sent
to IP                      ….
               Interface              Interface   Interface
               for Net 1              for Net N   for local host
    Policy for Selecting Incoming Datagrams
• The IP code that choose a datagram to route implements an
  important policy: it decides the relative priorities of the
  datagram sources.
• Local vs. network in priority assignment.
• Round-robin is fair. /* implemented using static type */
• ipgetp /* message queue is used for process synchronization, not as
   a FIFO */

• When all input queues are empty, the IP process blocks in
  a call to procedure ipgetp.
/* ipgetp.c - ipgetp */
static    int      ifnext = NI_LOCAL;
/*------------------------------------------------------------------------
  * ipgetp -- choose next IP input queue and extract a packet
  *----------------------------------------------------------------------*/
struct ep *
ipgetp(int *pifnum)
{
          struct   ep       *pep;
          int               i;

         recvclr();        /* make sure no old messages are waiting */
         while (TRUE) {
                  for (i=0; i < Net.nif; ++i, ++ifnext) {
                           if (ifnext >= Net.nif)
                                    ifnext = 0;
                           if (nif[ifnext].ni_state == NIS_DOWN)
                                    continue;
                           if (pep = NIGET(ifnext)) {
                                    *pifnum = ifnext;
                                    return pep;
                           }
                  }
                  ifnext = receive();
         }
         /* can't reach here */
}
/* ipproc.c - ipproc */
struct   ep        *ipgetp(int *);
struct   route     *rtget(IPaddr, Bool);
PROCESS ipproc(void)
{
         struct    ep       *pep;
         struct    ip       *pip;
         struct    route    *prt;
         Bool               nonlocal;
         int                ifnum;
         while (TRUE) {
             pep = ipgetp(&ifnum); //ifnum and pep are return values
             pip = (struct ip *)pep->ep_data; // change the structure
             if ((pip->ip_verlen>>4) != IP_VERSION) { not ipv4, continue}
             if (cksum((WORD *)pip, IP_HLEN(pip))) { checksum error continue;   }
             ipnet2h(pip); //big endian to little endian
              ipputp(prt->rt_ifnum, pip->ip_dst, pep);
          }
           Checksum Computation


/* cksum.c - cksum */
unsigned short cksum(buf, nwords)
unsigned short     *buf;
int                nwords;
{
         unsigned long       sum;
         for (sum=0; nwords>0; nwords--)
                   sum += *buf++;
         sum = (sum >> 16) + (sum & 0xffff);   /* add in carry */
         sum += (sum >> 16);                   /* maybe one more */
         return (unsigned short)~sum;
}
                     Byte Ordering
• Before sending a datagram, the host must convert all integers
  from the local machine byte order to standard network byte
  order; upon receiving a datagram, the host must convert
  integers from standard network byte order to the local
  machine byte order
• To optimize processing time, store all IP addresses in network
  byte order.
• typedef unsigned long Ipaddr;
  #if BYTE_ORDER == LITTLE_ENDIAN
   IPaddr ip_loopback =0x0100007f;
   #else /* BYTE-ORDER */
   IPaddr ip_loopback = 0x7f000001;
   #endif
     Sending a Datagram to IP for local host
• ipsend : given a locally generated datagram and an IP
  destination address, ipsend fills in the IP header and
  enqueues the datagram on the local host interface, where IP
  process will extract and send it.
• ip_in: sending incoming IP datagram from network to IP
  process.
/* ipsend.c - ipsend */
static ipackid = 1;
int ipsend(IPaddr faddr, struct ep *pep, unsigned datalen,
        u_char proto, u_char ptos, u_char ttl)
{
        struct ip *pip = (struct ip *) pep->ep_data;
        pep->ep_type = EPT_IP;
        pep->ep_order |= EPO_IP|EPO_NET;
        pip->ip_verlen = (IP_VERSION<<4) | IP_MINHLEN;
        pip->ip_tos = ptos;
        pip->ip_len = datalen+IP_HLEN(pip);
        pip->ip_id = ipackid++;
        pip->ip_fragoff = 0;
        pip->ip_ttl = ttl;
        pip->ip_proto = proto;
        pip->ip_dst = faddr;
        if (pip->ip_proto != IPT_ICMP)
                pip->ip_src = ip_anyaddr;
        if (enq(nif[NI_LOCAL].ni_ipinq, pep, 0) < 0) {
                freebuf(pep);
                IpOutDiscards++;
        }
        send(ippid, NI_LOCAL);
}
/* ICMP packet format (following the IP header)                */
struct icmp      {                         /* ICMP packet             */
        char     ic_type;         /* type of message (ICT_* above)*/
        char     ic_code;         /* code (ICC_* above)        */
        short    ic_cksum;                 /* checksum of ICMP header+data*/
        union {
                 struct {
                          int     ic1_id:16; /* echo type, a message id    */
                          int     ic1_seq:16;/* echo type, a seq. number*/
                 } ic1;
                 IPaddr ic2_gw;            /* for redirect, gateway*/
                 struct {
                          char    ic3_ptr;/* pointer, for ICT_PARAMP*/
                          char    ic3_pad[IC_PADLEN];
                 } ic3;
                 int      ic4_mbz;         /* must be zero            */
        } icu;
        char     ic_data[1];               /* data area of ICMP message*/
};
/* format 1 */
#define        ic_id icu.ic1.ic1_id
#define ic_seq icu.ic1.ic1_seq

/* format 2 */
#define        ic_gw icu.ic2_gw

/* format 3 */
#define ic_ptr icu.ic3.ic3_ptr
#define ic_pad icu.ic3.ic3_pad

/* format 4 */
#define ic_mbz        icu.ic4_mbz
8.4 handling Incoming ICMP messages
    When receive an ICMP message, Net-Interface => IP => icmp_in

 /*-------------------------------------------------------
  *icmp_in - handle ICMP packet coming in from the network
  *------------------------------------------------------*/
 int icmp_in(struct netif *pni, struct ep *pep)
 {          struct ip            *pip;
            struct icmp          *pic;
            int                  i, len;
            pip = (struct ip *)pep->ep_data;
            pic = (struct icmp *) pip->ip_data;

         len = pip->ip_len - IP_HLEN(pip);
         if (cksum((WORD *)pic, len)) {
                  IcmpInErrors++;
                  freebuf(pep);
                  return SYSERR; }
         IcmpInMsgs++;
switch(pic->ic_type) {
       case ICT_ECHORQ:
              IcmpInEchos++;
              return icmp(ICT_ECHORP, 0, pip->ip_src, pep, 0);
       case ICT_MASKRQ:
              IcmpInAddrMasks++;
              if (!gateway) {
                       freebuf(pep);
                       return OK;
              }
              pic->ic_type = (char) ICT_MASKRP;
              *(IPaddr *)pic->ic_data = netmask(pip->ip_dst);
              break;
case ICT_MASKRP:
                IcmpInAddrMaskReps++;
                for (i=0; i<Net.nif; ++i)
                          if (nif[i].ni_ip == pip->ip_dst)
                                     break;
                if (i != Net.nif) {
                          setmask(i, *(IPaddr *)pic->ic_data);
                          send(pic->ic_id, ICT_MASKRP); }
                freebuf(pep);
                return OK;
        case ICT_ECHORP:
                IcmpInEchoReps++;
                if (send(pic->ic_id, (int)pep) != OK)
                          freebuf(pep);
                return OK;
        case ICT_REDIRECT:
                IcmpInRedirects++;
                icredirect(pep);
                return OK;
case ICT_DESTUR: IcmpInDestUnreachs++;
                         freebuf(pep); return OK;
case ICT_SRCQ: IcmpInSrcQuenchs++;
                         freebuf(pep); return OK;
case ICT_TIMEX: IcmpInTimeExcds++;
                         freebuf(pep); return OK;
case ICT_PARAMP: IcmpInParmProbs++;
                         freebuf(pep); return OK;
case ICT_TIMERQ: IcmpInTimestamps++;
                         freebuf(pep); return OK;
case ICT_TIMERP: IcmpInTimestampReps++;
                         freebuf(pep); return OK;
default:
         IcmpInErrors++;
         freebuf(pep);
         return OK;
}

								
To top