ip.c implements the IP interface.

     1  /*
     2  ip.c
       
     3  Copyright 1995 Philip Homburg
     4  */
       
     5  #include "inet.h"
     6  #include "buf.h"
     7  #include "event.h"
     8  #include "type.h"
       
     9  #include "arp.h"
    10  #include "assert.h"
    11  #include "clock.h"
    12  #include "eth.h"
    13  #include "icmp.h"
    14  #include "icmp_lib.h"
    15  #include "io.h"
    16  #include "ip.h"
    17  #include "ip_int.h"
    18  #include "ipr.h"
    19  #include "sr.h"
       
    20  THIS_FILE
       
    21  FORWARD void ip_close ARGS(( int fd ));
    22  FORWARD int ip_cancel ARGS(( int fd, int which_operation ));
       
    23  FORWARD void ip_buffree ARGS(( int priority ));
    24  #ifdef BUF_CONSISTENCY_CHECK
    25  FORWARD void ip_bufcheck ARGS(( void ));
    26  #endif
    27  FORWARD void ip_bad_callback ARGS(( struct ip_port *ip_port ));
       

ip_port_table is the port table for the ip interface.
The ip_port_table is the data structure which stores information for each network
interface. There is a 1-1 correspondence between the network interfaces and the
elements of the ip_port_table. Each network interface in ip_port_table should
belong to a different network.

    28  PUBLIC ip_port_t ip_port_table[IP_PORT_NR];

The ip_port is defined in inet/generic/ip_int.h.

typedef struct ip_port
{
    int ip_flags, ip_dl_type;
    union
    {
        struct
        {
            int de_state;
            int de_flags;
            int de_port;
            int de_fd;
            acc_t *de_frame;
            acc_t *de_q_head;
            acc_t *de_q_tail;
            acc_t *de_arp_head;
            acc_t *de_arp_tail;
        } dl_eth;
        struct
        {
            int ps_port;
            acc_t *ps_send_head;
            acc_t *ps_send_tail;
        } dl_ps;
    } ip_dl;
    int ip_minor;
    ipaddr_t ip_ipaddr;
    ipaddr_t ip_netmask;
    ipaddr_t ip_subnetmask;
    u16_t ip_frame_id;
    u16_t ip_mss;
    ip_dev_t ip_dev_main;
    ip_dev_t ip_dev_set_ipaddr;
    ip_dev_send_t ip_dev_send;
    acc_t *ip_loopb_head;
    acc_t *ip_loopb_tail;
    event_t ip_loopb_event;
    struct ip_fd *ip_proto_any;
    struct ip_fd *ip_proto[IP_PROTO_HASH_NR];
} ip_port_t;

ip_minor: minor device number of ip device.

ip_ipaddr: ip address of the associated network interface.

ip_netmask: net mask of the ip address. The net mask of the ip address is determined
from the class type (class A, B, C, D, E) of the ip address. Which class type determines
which net mask if defined in the proper RFC.

ip_subnetmask: subnet mask of the ip address. Subnet mask define the subnet which the network interface belong to.

ip_frame_id: used as the datagram id number for an outgoing datagram.

ip_mss: maximum segment size - maximum packet size of packet.

ip_dev_main: set by network interface to the appropriate function which does some initialization and other things.

ip_dev_set_ipaddr: pointer to a function which is called when the ip address is set. If any calls are waiting for
an ip address the calls are returned.

ip_dev_send: pointer to a function which is called when writing a packet to be sent.

ip_loopb_head:

ip_loopb_event:

ip_proto_any: head of linked list of fds which receive messages on any protocol.

ip_proto: hash table of fds which receive messages on a particular port.

ip_fd_table is the fd table for the ip interface.

    29  PUBLIC ip_fd_t ip_fd_table[IP_FD_NR];

The ip_ass_table is used to reassemble fragmented packets which are parts of the same datagram.

    30  PUBLIC ip_ass_t ip_ass_table[IP_ASS_NR];

The ip_ass_t is defined in inet/generic/ip_int.h.

typedef struct ip_ass
{
    acc_t *ia_frags;
    int ia_min_ttl;
    ip_port_t *ia_port;
    time_t ia_first_time;
    ipaddr_t ia_srcaddr, ia_dstaddr;
    int ia_proto, ia_id;
} ip_ass_t;

ia_frags: points to a packet which is the head of linked list of packets. The linked list is
a list of packets which are part of the same datagram.

ia_min_ttl: time to live for datagram. If (ia_first_time + ia_min_ttl) < (time when every
packet for the packet has arrived - and hence can be reassembled) the datagram is dumped.

ia_port: pointer to port in ip_port_table.

ia_first_time: initialized to 0. Time when first packet for the datagram arrived.

ia_srcaddr: source ip address for packet(s) of datagram.

ia_dstaddr: destination ip address for packet(s) of datagram.

ia_proto: protocol of packet(s) of datagram.

ia_id: datagram id number for datagram. Every packet for the same datagram should have the same datagram id number.


       

ip_init() is called in inet.c to perform initialization.

    31  PUBLIC void ip_init()
    32  {
    33          int i, j, result;
    34          ip_ass_t *ip_ass;
    35          ip_fd_t *ip_fd;
    36          ip_port_t *ip_port;
       
    37          assert (BUF_S >= sizeof(struct nwio_ethopt));
    38          assert (BUF_S >= IP_MAX_HDR_SIZE + ETH_HDR_SIZE);
    39          assert (BUF_S >= sizeof(nwio_ipopt_t));
    40          assert (BUF_S >= sizeof(nwio_route_t));
       
    41  #if ZERO
    42          for (i=0, ip_ass= ip_ass_table; i<IP_ASS_NR; i++, ip_ass++)
    43          {
    44                  ip_ass->ia_frags= 0;
    45                  ip_ass->ia_first_time= 0;
    46                  ip_ass->ia_port= 0;
    47          }
       
    48          for (i=0, ip_fd= ip_fd_table; i<IP_FD_NR; i++, ip_fd++)
    49          {
    50                  ip_fd->if_flags= IFF_EMPTY;
    51                  ip_fd->if_rdbuf_head= 0;
    52          }
    53  #endif
       
    54          for (i=0, ip_port= ip_port_table; i<IP_PORT_NR; i++, ip_port++)
    55          {
    56  #if ZERO
    57                  ip_port->ip_flags= IPF_EMPTY;
    58  #endif
    59                  ip_port->ip_dev_main= (ip_dev_t)ip_bad_callback;
    60                  ip_port->ip_dev_set_ipaddr= (ip_dev_t)ip_bad_callback;
    61                  ip_port->ip_dev_send= (ip_dev_send_t)ip_bad_callback;
    62                  ip_port->ip_minor= ip_conf[i].ic_minor;
    63                  ip_port->ip_dl_type= ip_conf[i].ic_devtype;
    64                  ip_port->ip_mss= IP_DEF_MSS;
    65                  switch(ip_port->ip_dl_type)
    66                  {

IPDL_ETH = Ethernet interface.

    67                  case IPDL_ETH:
    68                          ip_port->ip_dl.dl_eth.de_port= ip_conf[i].ic_port;

Calls the function ipeth_init to initialize the functions for the array of ip_port_t
structures (the table is called ip_port) which it uses to send messages and set ip addresses
ie ip_dev_set_ipaddr, ip_dev_send, ip_dev_main.

    69                          result= ipeth_init(ip_port);
    70                          if (result == -1)
    71                                  continue;
    72                          assert(result == NW_OK);
    73                          break;
    74  #if ENABLE_PSIP

IPDL_PSIP = Pseudo-IP interface.

    75                  case IPDL_PSIP:
    76                          ip_port->ip_dl.dl_ps.ps_port= ip_conf[i].ic_port;

Calls the function ipps_init to initialize the functions for the array of ip_port_t
structures (the table is called ip_port) which it uses to send messages and set ip addresses
ie ip_dev_set_ipaddr, ip_dev_send, ip_dev_main.

    77                          result= ipps_init(ip_port);
    78                          if (result == -1)
    79                                  continue;
    80                          assert(result == NW_OK);
    81                          break;
    82  #endif
    83                  default:
    84                          ip_panic(( "unknown ip_dl_type %d",
    85                                                          ip_port->ip_dl_type ));
    86                          break;
    87                  }
    88  #if ZERO
    89                  ip_port->ip_loopb_head= NULL;
    90                  ip_port->ip_loopb_tail= NULL;
    91                  ev_init(&ip_port->ip_loopb_event);
    92  #endif
    93                  ip_port->ip_flags |= IPF_CONFIGURED;
    94  #if ZERO
    95                  ip_port->ip_proto_any= NULL;
    96                  for (j= 0; j<IP_PROTO_HASH_NR; j++)
    97                          ip_port->ip_proto[j]= NULL;
    98  #endif
    99          }
       
   100  #ifndef BUF_CONSISTENCY_CHECK
   101          bf_logon(ip_buffree);
   102  #else
   103          bf_logon(ip_buffree, ip_bufcheck);
   104  #endif
       
   105          icmp_init();
   106          ipr_init();
       
   107          for (i=0, ip_port= ip_port_table; i<IP_PORT_NR; i++, ip_port++)
   108          {
   109                  if (!(ip_port->ip_flags & IPF_CONFIGURED))
   110                          continue;

ip_init initializes the ip_frame_id field with the current time. The ip_frame_id is
used as the datagram id number for the outgoing datagram.

   111                  ip_port->ip_frame_id= (u16_t)get_time();
       

ip_init then calls sr_add_minor to so that the user call ip directly in a system call
by using ip’s minor device number.

   112                  result= sr_add_minor(ip_port->ip_minor,
   113                          ip_port-ip_port_table, ip_open, ip_close,
   114                          ip_read, ip_write, ip_ioctl, ip_cancel);
   115                  assert (result>=0);
       
   116                  (*ip_port->ip_dev_main)(ip_port);
   117          }
   118  }
       

ip_cancel() cancels a system call on a IP device.

   119  PRIVATE int ip_cancel (fd, which_operation)
   120  int fd;
   121  int which_operation;
   122  {
   123          ip_fd_t *ip_fd;
   124          acc_t *repl_res;
   125          int result;
       
   126          ip_fd= &ip_fd_table[fd];
       
   127          switch (which_operation)
   128          {
   129          case SR_CANCEL_IOCTL:
   130                  assert (ip_fd->if_flags & IFF_GIPCONF_IP);
   131                  ip_fd->if_flags &= ~IFF_GIPCONF_IP;
   132                  repl_res= (*ip_fd->if_get_userdata)(ip_fd->if_srfd,
   133                          (size_t)EINTR, (size_t)0, TRUE);
   134                  assert (!repl_res);
   135                  break;
   136          case SR_CANCEL_READ:
   137                  assert (ip_fd->if_flags & IFF_READ_IP);
   138                  ip_fd->if_flags &= ~IFF_READ_IP;
   139                  result= (*ip_fd->if_put_userdata)(ip_fd->if_srfd,
   140                          (size_t)EINTR, (acc_t *)0, FALSE);
   141                  assert (!result);
   142                  break;
   143  #if 0
   144          case SR_CANCEL_WRITE:
   145                  assert(0);
   146                  assert (ip_fd->if_flags & IFF_WRITE_MASK);
   147                  ip_fd->if_flags &= ~IFF_WRITE_MASK;
   148                  repl_res= (*ip_fd->if_get_userdata)(ip_fd->if_srfd,
   149                          (size_t)EINTR, (size_t)0, FALSE);
   150                  assert (!repl_res);
   151                  break;
   152  #endif
   153          default:
   154                  ip_panic(( "unknown cancel request" ));
   155                  break;
   156          }
   157          return NW_OK;
   158  }
       
       

ip_open() implements the open system call on a IP device.
ip_open() is used in 2 differene ways: 1) by sr.c to get protocol specific information
for the ip channel if the ip device was opened directly by the user ie (eg by calling
Open(“/dev/ip”, whatever_mode_you_want) 2) by another protocol using the ip protocol
(eg udp) calling it eg ip_open being called in udp_main by the udp protocol. ip_open
returns an index in to the ip fd table array for the ip channel.

   159  PUBLIC int ip_open (port, srfd, get_userdata, put_userdata, put_pkt)
   160  int port;
   161  int srfd;
   162  get_userdata_t get_userdata;
   163  put_userdata_t put_userdata;
   164  put_pkt_t put_pkt;
   165  {
   166          int i;
   167          ip_fd_t *ip_fd;
   168          ip_port_t *ip_port;
       
   169          ip_port= &ip_port_table[port];
   170          if (!(ip_port->ip_flags & IPF_CONFIGURED))
   171                  return ENXIO;
       
   172          for (i=0; i<IP_FD_NR && (ip_fd_table[i].if_flags & IFF_INUSE);
   173                  i++);
       
   174          if (i>=IP_FD_NR)
   175          {
   176                  DBLOCK(1, printf("out of fds\n"));
   177                  return EOUTOFBUFS;
   178          }
       
   179          ip_fd= &ip_fd_table[i];
       
   180          ip_fd->if_flags= IFF_INUSE;
       
   181          ip_fd->if_ipopt.nwio_flags= NWIO_DEFAULT;
   182          ip_fd->if_ipopt.nwio_tos= 0;
   183          ip_fd->if_ipopt.nwio_df= FALSE;
   184          ip_fd->if_ipopt.nwio_ttl= 255;
   185          ip_fd->if_ipopt.nwio_hdropt.iho_opt_siz= 0;
       
   186          ip_fd->if_port= ip_port;
   187          ip_fd->if_srfd= srfd;
   188          assert(ip_fd->if_rdbuf_head == NULL);
   189          ip_fd->if_get_userdata= get_userdata;
   190          ip_fd->if_put_userdata= put_userdata;
   191          ip_fd->if_put_pkt= put_pkt;
   192          return i;
   193  }
       

ip_close implements the close system call on a ip file descriptor fd.

   194  PRIVATE void ip_close (fd)
   195  int fd;
   196  {
   197          ip_fd_t *ip_fd;
   198          acc_t *pack;
       
   199          ip_fd= &ip_fd_table[fd];
       
   200          assert ((ip_fd->if_flags & IFF_INUSE) &&
   201                  !(ip_fd->if_flags & IFF_BUSY));
       
   202          if (ip_fd->if_flags & IFF_OPTSET)

Removes the ip channell from the ip fd table.

   203                  ip_unhash_proto(ip_fd);
   204          while (ip_fd->if_rdbuf_head)
   205          {
   206                  pack= ip_fd->if_rdbuf_head;
   207                  ip_fd->if_rdbuf_head= pack->acc_ext_link;
   208                  bf_afree(pack);
   209          }
   210          ip_fd->if_flags= IFF_EMPTY;
   211  }
       

ip_buffree is used by buf.c to release buffers.

   212  PRIVATE void ip_buffree(priority)
   213  int priority;
   214  {
   215          int i;
   216          ip_port_t *ip_port;
   217          ip_fd_t *ip_fd;
   218          ip_ass_t *ip_ass;
   219          acc_t *pack, *next_pack;
       
   220          for (i= 0, ip_port= ip_port_table; i<IP_PORT_NR; i++, ip_port++)
   221          {
   222                  if (ip_port->ip_dl_type == IPDL_ETH)
   223                  {
   224                          /* Can't free de_frame.
   225                           * bf_check_acc(ip_port->ip_dl.dl_eth.de_frame);
   226                           */
   227                          if (priority == IP_PRI_PORTBUFS)
   228                          {
   229                                  next_pack= ip_port->ip_dl.dl_eth.de_arp_head;
   230                                  while(next_pack != NULL)
   231                                  {
   232                                          pack= next_pack;
   233                                          next_pack= pack->acc_ext_link;
   234                                          bf_afree(pack);
   235                                  }
   236                                  ip_port->ip_dl.dl_eth.de_arp_head= next_pack;
       
   237                                  next_pack= ip_port->ip_dl.dl_eth.de_q_head;
   238                                  while(next_pack != NULL)
   239                                  {
   240                                          pack= next_pack;
   241                                          next_pack= pack->acc_ext_link;
   242                                          bf_afree(pack);
   243                                  }
   244                                  ip_port->ip_dl.dl_eth.de_q_head= next_pack;
   245                          }
   246                  }
   247                  else if (ip_port->ip_dl_type == IPDL_PSIP)
   248                  {
   249                          if (priority == IP_PRI_PORTBUFS)
   250                          {
   251                                  next_pack= ip_port->ip_dl.dl_ps.ps_send_head;
   252                                  while(next_pack != NULL)
   253                                  {
   254                                          pack= next_pack;
   255                                          next_pack= pack->acc_ext_link;
   256                                          bf_afree(pack);
   257                                  }
   258                                  ip_port->ip_dl.dl_ps.ps_send_head= next_pack;
   259                          }
   260                  }
   261                  if (priority == IP_PRI_PORTBUFS)
   262                  {
   263                          next_pack= ip_port->ip_loopb_head;
   264                          while(next_pack && next_pack->acc_ext_link)
   265                          {
   266                                  pack= next_pack;
   267                                  next_pack= pack->acc_ext_link;
   268                                  bf_afree(pack);
   269                          }
   270                          if (next_pack)
   271                          {
   272                                  if (ev_in_queue(&ip_port->ip_loopb_event))
   273                                  {
   274  #if !CRAMPED
   275                                          printf(
   276  "not freeing ip_loopb_head, ip_loopb_event enqueued\n");
   277  #endif
   278                                  }
   279                                  else
   280                                  {
   281                                          bf_afree(next_pack);
   282                                          next_pack= NULL;
   283                                  }
   284                          }
   285                          ip_port->ip_loopb_head= next_pack;
   286                  }
   287          }
   288          if (priority == IP_PRI_FDBUFS_EXTRA)
   289          {
   290                  for (i= 0, ip_fd= ip_fd_table; i<IP_FD_NR; i++, ip_fd++)
   291                  {
   292                          while (ip_fd->if_rdbuf_head &&
   293                                  ip_fd->if_rdbuf_head->acc_ext_link)
   294                          {
   295                                  pack= ip_fd->if_rdbuf_head;
   296                                  ip_fd->if_rdbuf_head= pack->acc_ext_link;
   297                                  bf_afree(pack);
   298                          }
   299                  }
   300          }
   301          if (priority == IP_PRI_FDBUFS)
   302          {
   303                  for (i= 0, ip_fd= ip_fd_table; i<IP_FD_NR; i++, ip_fd++)
   304                  {
   305                          while (ip_fd->if_rdbuf_head)
   306                          {
   307                                  pack= ip_fd->if_rdbuf_head;
   308                                  ip_fd->if_rdbuf_head= pack->acc_ext_link;
   309                                  bf_afree(pack);
   310                          }
   311                  }
   312          }
   313          if (priority == IP_PRI_ASSBUFS)
   314          {
   315                  for (i= 0, ip_ass= ip_ass_table; i<IP_ASS_NR; i++, ip_ass++)
   316                  {
   317                          next_pack= ip_ass->ia_frags;
   318                          while(ip_ass->ia_frags != NULL)
   319                          {
   320                                  pack= ip_ass->ia_frags;
   321                                  ip_ass->ia_frags= pack->acc_ext_link;
   322                                  bf_afree(pack);
   323                          }
   324                          ip_ass->ia_first_time= 0;
   325                  }
   326          }
   327  }
       
   328  #ifdef BUF_CONSISTENCY_CHECK
   329  PRIVATE void ip_bufcheck()
   330  {
   331          int i;
   332          ip_port_t *ip_port;
   333          ip_fd_t *ip_fd;
   334          ip_ass_t *ip_ass;
   335          acc_t *pack;
       
   336          for (i= 0, ip_port= ip_port_table; i<IP_PORT_NR; i++, ip_port++)
   337          {
   338                  if (ip_port->ip_dl_type == IPDL_ETH)
   339                  {
   340                          bf_check_acc(ip_port->ip_dl.dl_eth.de_frame);
   341                          for (pack= ip_port->ip_dl.dl_eth.de_q_head; pack;
   342                                  pack= pack->acc_ext_link)
   343                          {
   344                                  bf_check_acc(pack);
   345                          }
   346                          for (pack= ip_port->ip_dl.dl_eth.de_arp_head; pack;
   347                                  pack= pack->acc_ext_link)
   348                          {
   349                                  bf_check_acc(pack);
   350                          }
   351                  }
   352                  else if (ip_port->ip_dl_type == IPDL_PSIP)
   353                  {
   354                          for (pack= ip_port->ip_dl.dl_ps.ps_send_head; pack;
   355                                  pack= pack->acc_ext_link)
   356                          {
   357                                  bf_check_acc(pack);
   358                          }
   359                  }
   360                  for (pack= ip_port->ip_loopb_head; pack;
   361                          pack= pack->acc_ext_link)
   362                  {
   363                          bf_check_acc(pack);
   364                  }
   365          }
   366          for (i= 0, ip_fd= ip_fd_table; i<IP_FD_NR; i++, ip_fd++)
   367          {
   368                  for (pack= ip_fd->if_rdbuf_head; pack;
   369                          pack= pack->acc_ext_link)
   370                  {
   371                          bf_check_acc(pack);
   372                  }
   373          }
   374          for (i= 0, ip_ass= ip_ass_table; i<IP_ASS_NR; i++, ip_ass++)
   375          {
   376                  for (pack= ip_ass->ia_frags; pack; pack= pack->acc_ext_link)
   377                          bf_check_acc(pack);
   378          }
   379  }
   380  #endif /* BUF_CONSISTENCY_CHECK */
       
   381  PRIVATE void ip_bad_callback(ip_port)
   382  struct ip_port *ip_port;
   383  {
   384          ip_panic(( "no callback filled in for port %d",
   385                                                  ip_port-ip_port_table ));
   386  }
       
   387  /*
   388   * $PchId: ip.c,v 1.7 1996/12/17 07:54:47 philip Exp $
   389   */