eth.c

Go to the documentation of this file.
00001 /*
00002 eth.c
00003 
00004 Copyright 1995 Philip Homburg
00005 */
00006 
00007 #include "inet.h"
00008 #include "buf.h"
00009 #include "clock.h"
00010 #include "event.h"
00011 #include "osdep_eth.h"
00012 #include "type.h"
00013 
00014 #include "assert.h"
00015 #include "buf.h"
00016 #include "eth.h"
00017 #include "eth_int.h"
00018 #include "io.h"
00019 #include "sr.h"
00020 
00021 THIS_FILE
00022 
00023 #define ETH_FD_NR       (4*IP_PORT_MAX)
00024 #define EXPIRE_TIME     60*HZ   /* seconds */
00025 
00026 typedef struct eth_fd
00027 {
00028         int ef_flags;
00029         nwio_ethopt_t ef_ethopt;
00030         eth_port_t *ef_port;
00031         struct eth_fd *ef_type_next;
00032         struct eth_fd *ef_send_next;
00033         int ef_srfd;
00034         acc_t *ef_rdbuf_head;
00035         acc_t *ef_rdbuf_tail;
00036         get_userdata_t ef_get_userdata;
00037         put_userdata_t ef_put_userdata;
00038         put_pkt_t ef_put_pkt;
00039         time_t ef_exp_time;
00040         size_t ef_write_count;
00041         ioreq_t ef_ioctl_req;
00042 } eth_fd_t;
00043 
00044 #define EFF_FLAGS       0xf
00045 #       define EFF_EMPTY        0x0
00046 #       define EFF_INUSE        0x1
00047 #       define EFF_BUSY         0xE
00048 #               define  EFF_READ_IP     0x2
00049 #               define  EFF_WRITE_IP    0x4
00050 #               define  EFF_IOCTL_IP    0x8
00051 #       define EFF_OPTSET       0x10
00052 
00053 /* Note that the vh_type field is normally considered part of the ethernet
00054  * header.
00055  */
00056 typedef struct 
00057 {
00058         u16_t vh_type;
00059         u16_t vh_vlan;
00060 } vlan_hdr_t;
00061 
00062 FORWARD int eth_checkopt ARGS(( eth_fd_t *eth_fd ));
00063 FORWARD void hash_fd ARGS(( eth_fd_t *eth_fd ));
00064 FORWARD void unhash_fd ARGS(( eth_fd_t *eth_fd ));
00065 FORWARD void eth_buffree ARGS(( int priority ));
00066 #ifdef BUF_CONSISTENCY_CHECK
00067 FORWARD void eth_bufcheck ARGS(( void ));
00068 #endif
00069 FORWARD void packet2user ARGS(( eth_fd_t *fd, acc_t *pack, time_t exp_time ));
00070 FORWARD void reply_thr_get ARGS(( eth_fd_t *eth_fd,
00071         size_t result, int for_ioctl ));
00072 FORWARD void reply_thr_put ARGS(( eth_fd_t *eth_fd,
00073         size_t result, int for_ioctl ));
00074 FORWARD void do_rec_conf ARGS(( eth_port_t *eth_port ));
00075 FORWARD u32_t compute_rec_conf ARGS(( eth_port_t *eth_port ));
00076 FORWARD acc_t *insert_vlan_hdr ARGS(( eth_port_t *eth_port, acc_t *pack ));
00077 
00078 PUBLIC eth_port_t *eth_port_table;
00079 PUBLIC int no_ethWritePort= 0;
00080 
00081 PRIVATE eth_fd_t eth_fd_table[ETH_FD_NR];
00082 PRIVATE ether_addr_t broadcast= { { 255, 255, 255, 255, 255, 255 } };
00083 
00084 PUBLIC void eth_prep()
00085 {
00086         eth_port_table= alloc(eth_conf_nr * sizeof(eth_port_table[0]));
00087 }
00088 
00089 PUBLIC void eth_init()
00090 {
00091         int i, j;
00092 
00093         assert (BUF_S >= sizeof(nwio_ethopt_t));
00094         assert (BUF_S >= ETH_HDR_SIZE); /* these are in fact static assertions,
00095                                            thus a good compiler doesn't
00096                                            generate any code for this */
00097 
00098 
00099         for (i=0; i<ETH_FD_NR; i++)
00100                 eth_fd_table[i].ef_flags= EFF_EMPTY;
00101         for (i=0; i<eth_conf_nr; i++)
00102         {
00103                 eth_port_table[i].etp_flags= EFF_EMPTY;
00104                 eth_port_table[i].etp_sendq_head= NULL;
00105                 eth_port_table[i].etp_sendq_tail= NULL;
00106                 eth_port_table[i].etp_type_any= NULL;
00107                 ev_init(&eth_port_table[i].etp_sendev);
00108                 for (j= 0; j<ETH_TYPE_HASH_NR; j++)
00109                         eth_port_table[i].etp_type[j]= NULL;
00110                 for (j= 0; j<ETH_VLAN_HASH_NR; j++)
00111                         eth_port_table[i].etp_vlan_tab[j]= NULL;
00112         }
00113 
00114 #ifndef BUF_CONSISTENCY_CHECK
00115         bf_logon(eth_buffree);
00116 #else
00117         bf_logon(eth_buffree, eth_bufcheck);
00118 #endif
00119 
00120         osdep_eth_init();
00121 }
00122 
00123 PUBLIC int eth_open(port, srfd, get_userdata, put_userdata, put_pkt,
00124         select_res)
00125 int port, srfd;
00126 get_userdata_t get_userdata;
00127 put_userdata_t put_userdata;
00128 put_pkt_t put_pkt;
00129 select_res_t select_res;
00130 {
00131         int i;
00132         eth_port_t *eth_port;
00133         eth_fd_t *eth_fd;
00134 
00135         DBLOCK(0x20, printf("eth_open (%d, %d, %lx, %lx)\n", port, srfd, 
00136                 (unsigned long)get_userdata, (unsigned long)put_userdata));
00137         eth_port= &eth_port_table[port];
00138         if (!(eth_port->etp_flags & EPF_ENABLED))
00139                 return EGENERIC;
00140 
00141         for (i=0; i<ETH_FD_NR && (eth_fd_table[i].ef_flags & EFF_INUSE);
00142                 i++);
00143 
00144         if (i>=ETH_FD_NR)
00145         {
00146                 DBLOCK(1, printf("out of fds\n"));
00147                 return EAGAIN;
00148         }
00149 
00150         eth_fd= &eth_fd_table[i];
00151 
00152         eth_fd->ef_flags= EFF_INUSE;
00153         eth_fd->ef_ethopt.nweo_flags=NWEO_DEFAULT;
00154         eth_fd->ef_port= eth_port;
00155         eth_fd->ef_srfd= srfd;
00156         assert(eth_fd->ef_rdbuf_head == NULL);
00157         eth_fd->ef_get_userdata= get_userdata;
00158         eth_fd->ef_put_userdata= put_userdata;
00159         eth_fd->ef_put_pkt= put_pkt;
00160 
00161         return i;
00162 }
00163 
00164 PUBLIC int eth_ioctl(fd, req)
00165 int fd;
00166 ioreq_t req;
00167 {
00168         acc_t *data;
00169         eth_fd_t *eth_fd;
00170         eth_port_t *eth_port;
00171 
00172         DBLOCK(0x20, printf("eth_ioctl (%d, 0x%lx)\n", fd, (unsigned long)req));
00173         eth_fd= &eth_fd_table[fd];
00174         eth_port= eth_fd->ef_port;
00175 
00176         assert (eth_fd->ef_flags & EFF_INUSE);
00177 
00178         switch (req)
00179         {
00180         case NWIOSETHOPT:
00181                 {
00182                         nwio_ethopt_t *ethopt;
00183                         nwio_ethopt_t oldopt, newopt;
00184                         int result;
00185                         u32_t new_en_flags, new_di_flags,
00186                                 old_en_flags, old_di_flags;
00187 
00188                         data= (*eth_fd->ef_get_userdata)(eth_fd->
00189                                 ef_srfd, 0, sizeof(nwio_ethopt_t), TRUE);
00190 
00191                         ethopt= (nwio_ethopt_t *)ptr2acc_data(data);
00192                         oldopt= eth_fd->ef_ethopt;
00193                         newopt= *ethopt;
00194 
00195                         old_en_flags= oldopt.nweo_flags & 0xffff;
00196                         old_di_flags= (oldopt.nweo_flags >> 16) & 0xffff;
00197                         new_en_flags= newopt.nweo_flags & 0xffff;
00198                         new_di_flags= (newopt.nweo_flags >> 16) & 0xffff;
00199                         if (new_en_flags & new_di_flags)
00200                         {
00201                                 bf_afree(data);
00202                                 reply_thr_get (eth_fd, EBADMODE, TRUE);
00203                                 return NW_OK;
00204                         }       
00205 
00206                         /* NWEO_ACC_MASK */
00207                         if (new_di_flags & NWEO_ACC_MASK)
00208                         {
00209                                 bf_afree(data);
00210                                 reply_thr_get (eth_fd, EBADMODE, TRUE);
00211                                 return NW_OK;
00212                         }       
00213                                         /* you can't disable access modes */
00214 
00215                         if (!(new_en_flags & NWEO_ACC_MASK))
00216                                 new_en_flags |= (old_en_flags & NWEO_ACC_MASK);
00217 
00218 
00219                         /* NWEO_LOC_MASK */
00220                         if (!((new_en_flags | new_di_flags) & NWEO_LOC_MASK))
00221                         {
00222                                 new_en_flags |= (old_en_flags & NWEO_LOC_MASK);
00223                                 new_di_flags |= (old_di_flags & NWEO_LOC_MASK);
00224                         }
00225 
00226                         /* NWEO_BROAD_MASK */
00227                         if (!((new_en_flags | new_di_flags) & NWEO_BROAD_MASK))
00228                         {
00229                                 new_en_flags |= (old_en_flags & NWEO_BROAD_MASK);
00230                                 new_di_flags |= (old_di_flags & NWEO_BROAD_MASK);
00231                         }
00232 
00233                         /* NWEO_MULTI_MASK */
00234                         if (!((new_en_flags | new_di_flags) & NWEO_MULTI_MASK))
00235                         {
00236                                 new_en_flags |= (old_en_flags & NWEO_MULTI_MASK);
00237                                 new_di_flags |= (old_di_flags & NWEO_MULTI_MASK);
00238                                 newopt.nweo_multi= oldopt.nweo_multi;
00239                         }
00240 
00241                         /* NWEO_PROMISC_MASK */
00242                         if (!((new_en_flags | new_di_flags) & NWEO_PROMISC_MASK))
00243                         {
00244                                 new_en_flags |= (old_en_flags & NWEO_PROMISC_MASK);
00245                                 new_di_flags |= (old_di_flags & NWEO_PROMISC_MASK);
00246                         }
00247 
00248                         /* NWEO_REM_MASK */
00249                         if (!((new_en_flags | new_di_flags) & NWEO_REM_MASK))
00250                         {
00251                                 new_en_flags |= (old_en_flags & NWEO_REM_MASK);
00252                                 new_di_flags |= (old_di_flags & NWEO_REM_MASK);
00253                                 newopt.nweo_rem= oldopt.nweo_rem;
00254                         }
00255 
00256                         /* NWEO_TYPE_MASK */
00257                         if (!((new_en_flags | new_di_flags) & NWEO_TYPE_MASK))
00258                         {
00259                                 new_en_flags |= (old_en_flags & NWEO_TYPE_MASK);
00260                                 new_di_flags |= (old_di_flags & NWEO_TYPE_MASK);
00261                                 newopt.nweo_type= oldopt.nweo_type;
00262                         }
00263 
00264                         /* NWEO_RW_MASK */
00265                         if (!((new_en_flags | new_di_flags) & NWEO_RW_MASK))
00266                         {
00267                                 new_en_flags |= (old_en_flags & NWEO_RW_MASK);
00268                                 new_di_flags |= (old_di_flags & NWEO_RW_MASK);
00269                         }
00270 
00271                         if (eth_fd->ef_flags & EFF_OPTSET)
00272                                 unhash_fd(eth_fd);
00273 
00274                         newopt.nweo_flags= ((unsigned long)new_di_flags << 16) |
00275                                 new_en_flags;
00276                         eth_fd->ef_ethopt= newopt;
00277 
00278                         result= eth_checkopt(eth_fd);
00279 
00280                         if (result<0)
00281                                 eth_fd->ef_ethopt= oldopt;
00282                         else
00283                         {
00284                                 unsigned long opt_flags;
00285                                 unsigned changes;
00286                                 opt_flags= oldopt.nweo_flags ^
00287                                         eth_fd->ef_ethopt.nweo_flags;
00288                                 changes= ((opt_flags >> 16) | opt_flags) &
00289                                         0xffff;
00290                                 if (changes & (NWEO_BROAD_MASK |
00291                                         NWEO_MULTI_MASK | NWEO_PROMISC_MASK))
00292                                 {
00293                                         do_rec_conf(eth_port);
00294                                 }
00295                         }
00296 
00297                         if (eth_fd->ef_flags & EFF_OPTSET)
00298                                 hash_fd(eth_fd);
00299 
00300                         bf_afree(data);
00301                         reply_thr_get (eth_fd, result, TRUE);
00302                         return NW_OK;   
00303                 }
00304 
00305         case NWIOGETHOPT:
00306                 {
00307                         nwio_ethopt_t *ethopt;
00308                         acc_t *acc;
00309                         int result;
00310 
00311                         acc= bf_memreq(sizeof(nwio_ethopt_t));
00312 
00313                         ethopt= (nwio_ethopt_t *)ptr2acc_data(acc);
00314 
00315                         *ethopt= eth_fd->ef_ethopt;
00316 
00317                         result= (*eth_fd->ef_put_userdata)(eth_fd->
00318                                 ef_srfd, 0, acc, TRUE);
00319                         if (result >= 0)
00320                                 reply_thr_put(eth_fd, NW_OK, TRUE);
00321                         return result;
00322                 }
00323         case NWIOGETHSTAT:
00324                 {
00325                         nwio_ethstat_t *ethstat;
00326                         acc_t *acc;
00327                         int result;
00328 
00329                         assert (sizeof(nwio_ethstat_t) <= BUF_S);
00330 
00331                         eth_port= eth_fd->ef_port;
00332                         if (!(eth_port->etp_flags & EPF_ENABLED))
00333                         {
00334                                 reply_thr_put(eth_fd, EGENERIC, TRUE);
00335                                 return NW_OK;
00336                         }
00337 
00338                         if (!(eth_port->etp_flags & EPF_GOT_ADDR))
00339                         {
00340                                 printf(
00341                                 "eth_ioctl: suspending NWIOGETHSTAT ioctl\n");
00342 
00343                                 eth_fd->ef_ioctl_req= req;
00344                                 assert(!(eth_fd->ef_flags & EFF_IOCTL_IP));
00345                                 eth_fd->ef_flags |= EFF_IOCTL_IP;
00346                                 return NW_SUSPEND;
00347                         }
00348 
00349                         acc= bf_memreq(sizeof(nwio_ethstat_t));
00350                         compare (bf_bufsize(acc), ==, sizeof(*ethstat));
00351 
00352                         ethstat= (nwio_ethstat_t *)ptr2acc_data(acc);
00353                         ethstat->nwes_addr= eth_port->etp_ethaddr;
00354 
00355                         if (!eth_port->etp_vlan)
00356                         {
00357                                 result= eth_get_stat(eth_port,
00358                                         &ethstat->nwes_stat);
00359                                 if (result != NW_OK)
00360                                 {
00361                                         bf_afree(acc);
00362                                         reply_thr_put(eth_fd, result, TRUE);
00363                                         return NW_OK;
00364                                 }
00365                         }
00366                         else
00367                         {
00368                                 /* No statistics */
00369                                 memset(&ethstat->nwes_stat, '\0',
00370                                         sizeof(ethstat->nwes_stat));
00371                         }
00372 
00373                         result= (*eth_fd->ef_put_userdata)(eth_fd->
00374                                 ef_srfd, 0, acc, TRUE);
00375                         if (result >= 0)
00376                                 reply_thr_put(eth_fd, NW_OK, TRUE);
00377                         return result;
00378                 }
00379         default:
00380                 break;
00381         }
00382         reply_thr_put(eth_fd, EBADIOCTL, TRUE);
00383         return NW_OK;
00384 }
00385 
00386 PUBLIC int eth_write(fd, count)
00387 int fd;
00388 size_t count;
00389 {
00390         eth_fd_t *eth_fd;
00391         eth_port_t *eth_port, *rep;
00392         acc_t *user_data;
00393         int r;
00394 
00395         eth_fd= &eth_fd_table[fd];
00396         eth_port= eth_fd->ef_port;
00397 
00398         if (!(eth_fd->ef_flags & EFF_OPTSET))
00399         {
00400                 reply_thr_get (eth_fd, EBADMODE, FALSE);
00401                 return NW_OK;
00402         }
00403 
00404         assert (!(eth_fd->ef_flags & EFF_WRITE_IP));
00405 
00406         eth_fd->ef_write_count= count;
00407         if (eth_fd->ef_ethopt.nweo_flags & NWEO_RWDATONLY)
00408                 count += ETH_HDR_SIZE;
00409 
00410         if (count<ETH_MIN_PACK_SIZE || count>ETH_MAX_PACK_SIZE)
00411         {
00412                 DBLOCK(1, printf("illegal packetsize (%d)\n",count));
00413                 reply_thr_get (eth_fd, EPACKSIZE, FALSE);
00414                 return NW_OK;
00415         }
00416         eth_fd->ef_flags |= EFF_WRITE_IP;
00417 
00418         /* Enqueue at the real ethernet port */
00419         rep= eth_port->etp_vlan_port;
00420         if (!rep)
00421                 rep= eth_port;
00422         if (rep->etp_wr_pack)
00423         {
00424                 eth_fd->ef_send_next= NULL;
00425                 if (rep->etp_sendq_head)
00426                         rep->etp_sendq_tail->ef_send_next= eth_fd;
00427                 else
00428                         rep->etp_sendq_head= eth_fd;
00429                 rep->etp_sendq_tail= eth_fd;
00430                 return NW_SUSPEND;
00431         }
00432 
00433         user_data= (*eth_fd->ef_get_userdata)(eth_fd->ef_srfd, 0,
00434                 eth_fd->ef_write_count, FALSE);
00435         if (!user_data)
00436         {
00437                 eth_fd->ef_flags &= ~EFF_WRITE_IP;
00438                 reply_thr_get (eth_fd, EFAULT, FALSE);
00439                 return NW_OK;
00440         }
00441         r= eth_send(fd, user_data, eth_fd->ef_write_count);
00442         assert(r == NW_OK);
00443 
00444         eth_fd->ef_flags &= ~EFF_WRITE_IP;
00445         reply_thr_get(eth_fd, eth_fd->ef_write_count, FALSE);
00446         return NW_OK;
00447 }
00448 
00449 PUBLIC int eth_send(fd, data, data_len)
00450 int fd;
00451 acc_t *data;
00452 size_t data_len;
00453 {
00454         eth_fd_t *eth_fd;
00455         eth_port_t *eth_port, *rep;
00456         eth_hdr_t *eth_hdr;
00457         acc_t *eth_pack;
00458         unsigned long nweo_flags;
00459         size_t count;
00460         ev_arg_t ev_arg;
00461 
00462         eth_fd= &eth_fd_table[fd];
00463         eth_port= eth_fd->ef_port;
00464 
00465         if (!(eth_fd->ef_flags & EFF_OPTSET))
00466                 return EBADMODE;
00467 
00468         count= data_len;
00469         if (eth_fd->ef_ethopt.nweo_flags & NWEO_RWDATONLY)
00470                 count += ETH_HDR_SIZE;
00471 
00472         if (count<ETH_MIN_PACK_SIZE || count>ETH_MAX_PACK_SIZE)
00473         {
00474                 DBLOCK(1, printf("illegal packetsize (%d)\n",count));
00475                 return EPACKSIZE;
00476         }
00477         rep= eth_port->etp_vlan_port;
00478         if (!rep)
00479                 rep= eth_port;
00480 
00481         if (rep->etp_wr_pack)
00482                 return NW_WOULDBLOCK;
00483         
00484         nweo_flags= eth_fd->ef_ethopt.nweo_flags;
00485         if (nweo_flags & NWEO_RWDATONLY)
00486         {
00487                 eth_pack= bf_memreq(ETH_HDR_SIZE);
00488                 eth_pack->acc_next= data;
00489         }
00490         else
00491                 eth_pack= bf_packIffLess(data, ETH_HDR_SIZE);
00492 
00493         eth_hdr= (eth_hdr_t *)ptr2acc_data(eth_pack);
00494 
00495         if (nweo_flags & NWEO_REMSPEC)
00496                 eth_hdr->eh_dst= eth_fd->ef_ethopt.nweo_rem;
00497 
00498         if (!(eth_port->etp_flags & EPF_GOT_ADDR))
00499         {
00500                 /* No device, discard packet */
00501                 bf_afree(eth_pack);
00502                 return NW_OK;
00503         }
00504 
00505         if (!(nweo_flags & NWEO_EN_PROMISC))
00506                 eth_hdr->eh_src= eth_port->etp_ethaddr;
00507 
00508         if (nweo_flags & NWEO_TYPESPEC)
00509                 eth_hdr->eh_proto= eth_fd->ef_ethopt.nweo_type;
00510 
00511         if (eth_addrcmp(eth_hdr->eh_dst, eth_port->etp_ethaddr) == 0)
00512         {
00513                 /* Local loopback. */
00514                 eth_port->etp_wr_pack= eth_pack;
00515                 ev_arg.ev_ptr= eth_port;
00516                 ev_enqueue(&eth_port->etp_sendev, eth_loop_ev, ev_arg);
00517                 return NW_OK;
00518         }
00519 
00520         if (rep != eth_port)
00521         {
00522                 eth_pack= insert_vlan_hdr(eth_port, eth_pack);
00523                 if (!eth_pack)
00524                 {
00525                         /* Packet is silently discarded */
00526                         return NW_OK;
00527                 }
00528         }
00529 
00530         eth_write_port(rep, eth_pack);
00531         return NW_OK;
00532 }
00533 
00534 PUBLIC int eth_read (fd, count)
00535 int fd;
00536 size_t count;
00537 {
00538         eth_fd_t *eth_fd;
00539         acc_t *pack;
00540 
00541         eth_fd= &eth_fd_table[fd];
00542         if (!(eth_fd->ef_flags & EFF_OPTSET))
00543         {
00544                 reply_thr_put(eth_fd, EBADMODE, FALSE);
00545                 return NW_OK;
00546         }
00547         if (count < ETH_MAX_PACK_SIZE)
00548         {
00549                 reply_thr_put(eth_fd, EPACKSIZE, FALSE);
00550                 return NW_OK;
00551         }
00552 
00553         assert(!(eth_fd->ef_flags & EFF_READ_IP));
00554         eth_fd->ef_flags |= EFF_READ_IP;
00555 
00556         while (eth_fd->ef_rdbuf_head)
00557         {
00558                 pack= eth_fd->ef_rdbuf_head;
00559                 eth_fd->ef_rdbuf_head= pack->acc_ext_link;
00560                 if (get_time() <= eth_fd->ef_exp_time)
00561                 {
00562                         packet2user(eth_fd, pack, eth_fd->ef_exp_time);
00563                         if (!(eth_fd->ef_flags & EFF_READ_IP))
00564                                 return NW_OK;
00565                 }
00566                 else
00567                         bf_afree(pack);
00568         }
00569         return NW_SUSPEND;
00570 }
00571 
00572 PUBLIC int eth_cancel(fd, which_operation)
00573 int fd;
00574 int which_operation;
00575 {
00576         eth_fd_t *eth_fd, *prev, *loc_fd;
00577         eth_port_t *eth_port;
00578 
00579         DBLOCK(2, printf("eth_cancel (%d)\n", fd));
00580         eth_fd= &eth_fd_table[fd];
00581 
00582         switch (which_operation)
00583         {
00584         case SR_CANCEL_READ:
00585                 assert (eth_fd->ef_flags & EFF_READ_IP);
00586                 eth_fd->ef_flags &= ~EFF_READ_IP;
00587                 reply_thr_put(eth_fd, EINTR, FALSE);
00588                 break;
00589         case SR_CANCEL_WRITE:
00590                 assert (eth_fd->ef_flags & EFF_WRITE_IP);
00591                 eth_fd->ef_flags &= ~EFF_WRITE_IP;
00592 
00593                 /* Remove fd from send queue */
00594                 eth_port= eth_fd->ef_port;
00595                 if (eth_port->etp_vlan_port)
00596                         eth_port= eth_port->etp_vlan_port;
00597                 for (prev= 0, loc_fd= eth_port->etp_sendq_head; loc_fd != NULL;
00598                         prev= loc_fd, loc_fd= loc_fd->ef_send_next)
00599                 {
00600                         if (loc_fd == eth_fd)
00601                                 break;
00602                 }
00603                 assert(loc_fd == eth_fd);
00604                 if (prev == NULL)
00605                         eth_port->etp_sendq_head= loc_fd->ef_send_next;
00606                 else
00607                         prev->ef_send_next= loc_fd->ef_send_next;
00608                 if (loc_fd->ef_send_next == NULL)
00609                         eth_port->etp_sendq_tail= prev;
00610                         
00611                 reply_thr_get(eth_fd, EINTR, FALSE);
00612                 break;
00613         case SR_CANCEL_IOCTL:
00614                 assert (eth_fd->ef_flags & EFF_IOCTL_IP);
00615                 eth_fd->ef_flags &= ~EFF_IOCTL_IP;
00616                 reply_thr_get(eth_fd, EINTR, TRUE);
00617                 break;
00618         default:
00619                 ip_panic(( "got unknown cancel request" ));
00620         }
00621         return NW_OK;
00622 }
00623 
00624 PUBLIC int eth_select(fd, operations)
00625 int fd;
00626 unsigned operations;
00627 {
00628         printf("eth_select: not implemented\n");
00629         return 0;
00630 }
00631 
00632 PUBLIC void eth_close(fd)
00633 int fd;
00634 {
00635         eth_fd_t *eth_fd;
00636         eth_port_t *eth_port;
00637         acc_t *pack;
00638 
00639         eth_fd= &eth_fd_table[fd];
00640 
00641         assert ((eth_fd->ef_flags & EFF_INUSE) &&
00642                 !(eth_fd->ef_flags & EFF_BUSY));
00643 
00644         if (eth_fd->ef_flags & EFF_OPTSET)
00645                 unhash_fd(eth_fd);
00646         while (eth_fd->ef_rdbuf_head != NULL)
00647         {
00648                 pack= eth_fd->ef_rdbuf_head;
00649                 eth_fd->ef_rdbuf_head= pack->acc_ext_link;
00650                 bf_afree(pack);
00651         }
00652         eth_fd->ef_flags= EFF_EMPTY;
00653 
00654         eth_port= eth_fd->ef_port;
00655         do_rec_conf(eth_port);
00656 }
00657 
00658 PUBLIC void eth_loop_ev(ev, ev_arg)
00659 event_t *ev;
00660 ev_arg_t ev_arg;
00661 {
00662         acc_t *pack;
00663         eth_port_t *eth_port;
00664 
00665         eth_port= ev_arg.ev_ptr;
00666         assert(ev == &eth_port->etp_sendev);
00667 
00668         pack= eth_port->etp_wr_pack;
00669 
00670         assert(!no_ethWritePort);
00671         no_ethWritePort= 1;
00672         eth_arrive(eth_port, pack, bf_bufsize(pack));
00673         assert(no_ethWritePort);
00674         no_ethWritePort= 0;
00675 
00676         eth_port->etp_wr_pack= NULL;
00677         eth_restart_write(eth_port);
00678 }
00679 
00680 PRIVATE int eth_checkopt (eth_fd)
00681 eth_fd_t *eth_fd;
00682 {
00683 /* bug: we don't check access modes yet */
00684 
00685         unsigned long flags;
00686         unsigned int en_di_flags;
00687         eth_port_t *eth_port;
00688         acc_t *pack;
00689 
00690         eth_port= eth_fd->ef_port;
00691         flags= eth_fd->ef_ethopt.nweo_flags;
00692         en_di_flags= (flags >>16) | (flags & 0xffff);
00693 
00694         if ((en_di_flags & NWEO_ACC_MASK) &&
00695                 (en_di_flags & NWEO_LOC_MASK) &&
00696                 (en_di_flags & NWEO_BROAD_MASK) &&
00697                 (en_di_flags & NWEO_MULTI_MASK) &&
00698                 (en_di_flags & NWEO_PROMISC_MASK) &&
00699                 (en_di_flags & NWEO_REM_MASK) &&
00700                 (en_di_flags & NWEO_TYPE_MASK) &&
00701                 (en_di_flags & NWEO_RW_MASK))
00702         {
00703                 eth_fd->ef_flags |= EFF_OPTSET;
00704         }
00705         else
00706                 eth_fd->ef_flags &= ~EFF_OPTSET;
00707 
00708         while (eth_fd->ef_rdbuf_head != NULL)
00709         {
00710                 pack= eth_fd->ef_rdbuf_head;
00711                 eth_fd->ef_rdbuf_head= pack->acc_ext_link;
00712                 bf_afree(pack);
00713         }
00714 
00715         return NW_OK;
00716 }
00717 
00718 PRIVATE void hash_fd(eth_fd)
00719 eth_fd_t *eth_fd;
00720 {
00721         eth_port_t *eth_port;
00722         int hash;
00723 
00724         eth_port= eth_fd->ef_port;
00725         if (eth_fd->ef_ethopt.nweo_flags & NWEO_TYPEANY)
00726         {
00727                 eth_fd->ef_type_next= eth_port->etp_type_any;
00728                 eth_port->etp_type_any= eth_fd;
00729         }
00730         else
00731         {
00732                 hash= eth_fd->ef_ethopt.nweo_type;
00733                 hash ^= (hash >> 8);
00734                 hash &= (ETH_TYPE_HASH_NR-1);
00735 
00736                 eth_fd->ef_type_next= eth_port->etp_type[hash];
00737                 eth_port->etp_type[hash]= eth_fd;
00738         }
00739 }
00740 
00741 PRIVATE void unhash_fd(eth_fd)
00742 eth_fd_t *eth_fd;
00743 {
00744         eth_port_t *eth_port;
00745         eth_fd_t *prev, *curr, **eth_fd_p;
00746         int hash;
00747 
00748         eth_port= eth_fd->ef_port;
00749         if (eth_fd->ef_ethopt.nweo_flags & NWEO_TYPEANY)
00750         {
00751                 eth_fd_p= &eth_port->etp_type_any;
00752         }
00753         else
00754         {
00755                 hash= eth_fd->ef_ethopt.nweo_type;
00756                 hash ^= (hash >> 8);
00757                 hash &= (ETH_TYPE_HASH_NR-1);
00758 
00759                 eth_fd_p= &eth_port->etp_type[hash];
00760         }
00761         for (prev= NULL, curr= *eth_fd_p; curr;
00762                 prev= curr, curr= curr->ef_type_next)
00763         {
00764                 if (curr == eth_fd)
00765                         break;
00766         }
00767         assert(curr);
00768         if (prev)
00769                 prev->ef_type_next= curr->ef_type_next;
00770         else
00771                 *eth_fd_p= curr->ef_type_next;
00772 }
00773 
00774 PUBLIC void eth_restart_write(eth_port)
00775 eth_port_t *eth_port;
00776 {
00777         eth_fd_t *eth_fd;
00778         int r;
00779 
00780         assert(eth_port->etp_wr_pack == NULL);
00781         while (eth_fd= eth_port->etp_sendq_head, eth_fd != NULL)
00782         {
00783                 if (eth_port->etp_wr_pack)
00784                         return;
00785                 eth_port->etp_sendq_head= eth_fd->ef_send_next;
00786 
00787                 assert(eth_fd->ef_flags & EFF_WRITE_IP);
00788                 eth_fd->ef_flags &= ~EFF_WRITE_IP;
00789                 r= eth_write(eth_fd-eth_fd_table, eth_fd->ef_write_count);
00790                 assert(r == NW_OK);
00791         }
00792 }
00793 
00794 PUBLIC void eth_arrive (eth_port, pack, pack_size)
00795 eth_port_t *eth_port;
00796 acc_t *pack;
00797 size_t pack_size;
00798 {
00799 
00800         eth_hdr_t *eth_hdr;
00801         ether_addr_t *dst_addr;
00802         int pack_stat;
00803         ether_type_t type;
00804         eth_fd_t *eth_fd, *first_fd, *share_fd;
00805         int hash, i;
00806         u16_t vlan, temp;
00807         time_t exp_time;
00808         acc_t *vlan_pack, *hdr_acc, *tmp_acc;
00809         eth_port_t *vp;
00810         vlan_hdr_t vh;
00811         u32_t *p;
00812 
00813         exp_time= get_time() + EXPIRE_TIME;
00814 
00815         pack= bf_packIffLess(pack, ETH_HDR_SIZE);
00816 
00817         eth_hdr= (eth_hdr_t*)ptr2acc_data(pack);
00818         dst_addr= &eth_hdr->eh_dst;
00819 
00820         DIFBLOCK(0x20, dst_addr->ea_addr[0] != 0xFF &&
00821                 (dst_addr->ea_addr[0] & 0x1),
00822                 printf("got multicast packet\n"));
00823 
00824         if (dst_addr->ea_addr[0] & 0x1)
00825         {
00826                 /* multi cast or broadcast */
00827                 if (eth_addrcmp(*dst_addr, broadcast) == 0)
00828                         pack_stat= NWEO_EN_BROAD;
00829                 else
00830                         pack_stat= NWEO_EN_MULTI;
00831         }
00832         else
00833         {
00834                 assert(eth_port->etp_flags & EPF_GOT_ADDR);
00835                 if (eth_addrcmp (*dst_addr, eth_port->etp_ethaddr) == 0)
00836                         pack_stat= NWEO_EN_LOC;
00837                 else
00838                         pack_stat= NWEO_EN_PROMISC;
00839         }
00840         type= eth_hdr->eh_proto;
00841         hash= type;
00842         hash ^= (hash >> 8);
00843         hash &= (ETH_TYPE_HASH_NR-1);
00844 
00845         if (type == HTONS(ETH_VLAN_PROTO))
00846         {
00847                 /* VLAN packet. Extract original ethernet packet */
00848 
00849                 vlan_pack= pack;
00850                 vlan_pack->acc_linkC++;
00851                 hdr_acc= bf_cut(vlan_pack, 0, 2*sizeof(ether_addr_t));
00852                 vlan_pack= bf_delhead(vlan_pack, 2*sizeof(ether_addr_t));
00853                 vlan_pack= bf_packIffLess(vlan_pack, sizeof(vh));
00854                 vh= *(vlan_hdr_t *)ptr2acc_data(vlan_pack);
00855                 vlan_pack= bf_delhead(vlan_pack, sizeof(vh));
00856                 hdr_acc= bf_append(hdr_acc, vlan_pack);
00857                 vlan_pack= hdr_acc; hdr_acc= NULL;
00858                 if (bf_bufsize(vlan_pack) < ETH_MIN_PACK_SIZE)
00859                 {
00860                         tmp_acc= bf_memreq(sizeof(vh));
00861 
00862                         /* Clear padding */
00863                         assert(sizeof(vh) <= sizeof(*p));
00864                         p= (u32_t *)ptr2acc_data(tmp_acc);
00865                         *p= 0xdeadbeef;
00866 
00867                         vlan_pack= bf_append(vlan_pack, tmp_acc);
00868                         tmp_acc= NULL;
00869                 }
00870                 vlan= ntohs(vh.vh_vlan);
00871                 if (vlan & ETH_TCI_CFI)
00872                 {
00873                         /* No support for extended address formats */
00874                         bf_afree(vlan_pack); vlan_pack= NULL;
00875                 }
00876                 vlan &= ETH_TCI_VLAN_MASK;
00877         }
00878         else
00879         {
00880                 /* No VLAN processing */
00881                 vlan_pack= NULL;
00882                 vlan= 0;        /* lint */
00883         }
00884 
00885         first_fd= NULL;
00886         for (i= 0; i<2; i++)
00887         {
00888                 share_fd= NULL;
00889 
00890                 eth_fd= (i == 0) ? eth_port->etp_type_any :
00891                         eth_port->etp_type[hash];
00892                 for (; eth_fd; eth_fd= eth_fd->ef_type_next)
00893                 {
00894                         if (i && eth_fd->ef_ethopt.nweo_type != type)
00895                                 continue;
00896                         if (!(eth_fd->ef_ethopt.nweo_flags & pack_stat))
00897                                 continue;
00898                         if (eth_fd->ef_ethopt.nweo_flags & NWEO_REMSPEC &&
00899                                 eth_addrcmp(eth_hdr->eh_src,
00900                                 eth_fd->ef_ethopt.nweo_rem) != 0)
00901                         {
00902                                         continue;
00903                         }
00904                         if ((eth_fd->ef_ethopt.nweo_flags & NWEO_ACC_MASK) ==
00905                                 NWEO_SHARED)
00906                         {
00907                                 if (!share_fd)
00908                                 {
00909                                         share_fd= eth_fd;
00910                                         continue;
00911                                 }
00912                                 if (!eth_fd->ef_rdbuf_head)
00913                                         share_fd= eth_fd;
00914                                 continue;
00915                         }
00916                         if (!first_fd)
00917                         {
00918                                 first_fd= eth_fd;
00919                                 continue;
00920                         }
00921                         pack->acc_linkC++;
00922                         packet2user(eth_fd, pack, exp_time);
00923                 }
00924                 if (share_fd)
00925                 {
00926                         pack->acc_linkC++;
00927                         packet2user(share_fd, pack, exp_time);
00928                 }
00929         }
00930         if (first_fd)
00931         {
00932                 if (first_fd->ef_put_pkt &&
00933                         (first_fd->ef_flags & EFF_READ_IP) &&
00934                         !(first_fd->ef_ethopt.nweo_flags & NWEO_RWDATONLY))
00935                 {
00936                         (*first_fd->ef_put_pkt)(first_fd->ef_srfd, pack,
00937                                 pack_size);
00938                 }
00939                 else
00940                         packet2user(first_fd, pack, exp_time);
00941         }
00942         else
00943         {
00944                 if (pack_stat == NWEO_EN_LOC)
00945                 {
00946                         DBLOCK(0x01,
00947                         printf("eth_arrive: dropping packet for proto 0x%x\n",
00948                                 ntohs(type)));
00949                 }
00950                 else
00951                 {
00952                         DBLOCK(0x20, printf("dropping packet for proto 0x%x\n",
00953                                 ntohs(type)));
00954                 }                       
00955                 bf_afree(pack);
00956         }
00957         if (vlan_pack)
00958         {
00959                 hash= ETH_HASH_VLAN(vlan, temp);
00960                 for (vp= eth_port->etp_vlan_tab[hash]; vp;
00961                         vp= vp->etp_vlan_next)
00962                 {
00963                         if (vp->etp_vlan == vlan)
00964                                 break;
00965                 }
00966                 if (vp)
00967                 {
00968                         eth_arrive(vp, vlan_pack, pack_size-sizeof(vh));
00969                         vlan_pack= NULL;
00970                 }
00971                 else
00972                 {
00973                         /* No device for VLAN */
00974                         bf_afree(vlan_pack);
00975                         vlan_pack= NULL;
00976                 }
00977         }
00978 }
00979 
00980 PUBLIC void eth_reg_vlan(eth_port, vlan_port)
00981 eth_port_t *eth_port;
00982 eth_port_t *vlan_port;
00983 {
00984         u16_t t, vlan;
00985         int h;
00986 
00987         vlan= vlan_port->etp_vlan;
00988         h= ETH_HASH_VLAN(vlan, t);
00989         vlan_port->etp_vlan_next= eth_port->etp_vlan_tab[h];
00990         eth_port->etp_vlan_tab[h]= vlan_port;
00991 }
00992 
00993 PUBLIC void eth_restart_ioctl(eth_port)
00994 eth_port_t *eth_port;
00995 {
00996         int i;
00997         eth_fd_t *eth_fd;
00998 
00999         for (i= 0, eth_fd= eth_fd_table; i<ETH_FD_NR; i++, eth_fd++)
01000         {
01001                 if (!(eth_fd->ef_flags & EFF_INUSE))
01002                         continue;
01003                 if (eth_fd->ef_port != eth_port)
01004                         continue;
01005                 if (!(eth_fd->ef_flags & EFF_IOCTL_IP))
01006                         continue;
01007                 if (eth_fd->ef_ioctl_req != NWIOGETHSTAT)
01008                         continue;
01009 
01010                 eth_fd->ef_flags &= ~EFF_IOCTL_IP;
01011                 eth_ioctl(i, eth_fd->ef_ioctl_req);
01012         }
01013 }
01014 
01015 PRIVATE void packet2user (eth_fd, pack, exp_time)
01016 eth_fd_t *eth_fd;
01017 acc_t *pack;
01018 time_t exp_time;
01019 {
01020         int result;
01021         acc_t *tmp_pack;
01022         size_t size;
01023 
01024         assert (eth_fd->ef_flags & EFF_INUSE);
01025         if (!(eth_fd->ef_flags & EFF_READ_IP))
01026         {
01027                 if (pack->acc_linkC != 1)
01028                 {
01029                         tmp_pack= bf_dupacc(pack);
01030                         bf_afree(pack);
01031                         pack= tmp_pack;
01032                         tmp_pack= NULL;
01033                 }
01034                 pack->acc_ext_link= NULL;
01035                 if (eth_fd->ef_rdbuf_head == NULL)
01036                 {
01037                         eth_fd->ef_rdbuf_head= pack;
01038                         eth_fd->ef_exp_time= exp_time;
01039                 }
01040                 else
01041                         eth_fd->ef_rdbuf_tail->acc_ext_link= pack;
01042                 eth_fd->ef_rdbuf_tail= pack;
01043                 return;
01044         }
01045 
01046         if (eth_fd->ef_ethopt.nweo_flags & NWEO_RWDATONLY)
01047                 pack= bf_delhead(pack, ETH_HDR_SIZE);
01048 
01049         size= bf_bufsize(pack);
01050 
01051         if (eth_fd->ef_put_pkt)
01052         {
01053                 (*eth_fd->ef_put_pkt)(eth_fd->ef_srfd, pack, size);
01054                 return;
01055         }
01056 
01057         eth_fd->ef_flags &= ~EFF_READ_IP;
01058         result= (*eth_fd->ef_put_userdata)(eth_fd->ef_srfd, (size_t)0, pack,
01059                 FALSE);
01060         if (result >=0)
01061                 reply_thr_put(eth_fd, size, FALSE);
01062         else
01063                 reply_thr_put(eth_fd, result, FALSE);
01064 }
01065 
01066 PRIVATE void eth_buffree (priority)
01067 int priority;
01068 {
01069         int i;
01070         eth_fd_t *eth_fd;
01071         acc_t *pack;
01072 
01073         if (priority == ETH_PRI_FDBUFS_EXTRA)
01074         {
01075                 for (i= 0, eth_fd= eth_fd_table; i<ETH_FD_NR; i++, eth_fd++)
01076                 {
01077                         while (eth_fd->ef_rdbuf_head &&
01078                                 eth_fd->ef_rdbuf_head->acc_ext_link)
01079                         {
01080                                 pack= eth_fd->ef_rdbuf_head;
01081                                 eth_fd->ef_rdbuf_head= pack->acc_ext_link;
01082                                 bf_afree(pack);
01083                         }
01084                 }
01085         }
01086         if (priority == ETH_PRI_FDBUFS)
01087         {
01088                 for (i= 0, eth_fd= eth_fd_table; i<ETH_FD_NR; i++, eth_fd++)
01089                 {
01090                         while (eth_fd->ef_rdbuf_head)
01091                         {
01092                                 pack= eth_fd->ef_rdbuf_head;
01093                                 eth_fd->ef_rdbuf_head= pack->acc_ext_link;
01094                                 bf_afree(pack);
01095                         }
01096                 }
01097         }
01098 }
01099 
01100 #ifdef BUF_CONSISTENCY_CHECK
01101 PRIVATE void eth_bufcheck()
01102 {
01103         int i;
01104         eth_fd_t *eth_fd;
01105         acc_t *pack;
01106 
01107         for (i= 0; i<eth_conf_nr; i++)
01108         {
01109                 bf_check_acc(eth_port_table[i].etp_rd_pack);
01110                 bf_check_acc(eth_port_table[i].etp_wr_pack);
01111         }
01112         for (i= 0, eth_fd= eth_fd_table; i<ETH_FD_NR; i++, eth_fd++)
01113         {
01114                 for (pack= eth_fd->ef_rdbuf_head; pack;
01115                         pack= pack->acc_ext_link)
01116                 {
01117                         bf_check_acc(pack);
01118                 }
01119         }
01120 }
01121 #endif
01122 
01123 PRIVATE void do_rec_conf(eth_port)
01124 eth_port_t *eth_port;
01125 {
01126         int i;
01127         u32_t flags;
01128         eth_port_t *vp;
01129 
01130         if (eth_port->etp_vlan)
01131         {
01132                 /* Configure underlying device */
01133                 eth_port= eth_port->etp_vlan_port;
01134         }
01135         flags= compute_rec_conf(eth_port);
01136         for (i= 0; i<ETH_VLAN_HASH_NR; i++)
01137         {
01138                 for (vp= eth_port->etp_vlan_tab[i]; vp; vp= vp->etp_vlan_next)
01139                         flags |= compute_rec_conf(vp);
01140         }
01141         eth_set_rec_conf(eth_port, flags);
01142 }
01143 
01144 PRIVATE u32_t compute_rec_conf(eth_port)
01145 eth_port_t *eth_port;
01146 {
01147         eth_fd_t *eth_fd;
01148         u32_t flags;
01149         int i;
01150 
01151         flags= NWEO_NOFLAGS;
01152         for (i=0, eth_fd= eth_fd_table; i<ETH_FD_NR; i++, eth_fd++)
01153         {
01154                 if ((eth_fd->ef_flags & (EFF_INUSE|EFF_OPTSET)) !=
01155                         (EFF_INUSE|EFF_OPTSET))
01156                 {
01157                         continue;
01158                 }
01159                 if (eth_fd->ef_port != eth_port)
01160                         continue;
01161                 flags |= eth_fd->ef_ethopt.nweo_flags;
01162         }
01163         return flags;
01164 }
01165 
01166 PRIVATE void reply_thr_get (eth_fd, result, for_ioctl)
01167 eth_fd_t *eth_fd;
01168 size_t result;
01169 int for_ioctl;
01170 {
01171         acc_t *data;
01172 
01173         data= (*eth_fd->ef_get_userdata)(eth_fd->ef_srfd, result, 0, for_ioctl);
01174         assert (!data); 
01175 }
01176 
01177 PRIVATE void reply_thr_put (eth_fd, result, for_ioctl)
01178 eth_fd_t *eth_fd;
01179 size_t result;
01180 int for_ioctl;
01181 {
01182         int error;
01183 
01184         error= (*eth_fd->ef_put_userdata)(eth_fd->ef_srfd, result, (acc_t *)0,
01185                 for_ioctl);
01186         assert(error == NW_OK);
01187 }
01188 
01189 PRIVATE acc_t *insert_vlan_hdr(eth_port, pack)
01190 eth_port_t *eth_port;
01191 acc_t *pack;
01192 {
01193         acc_t *head_acc, *vh_acc;
01194         u16_t type, vlan;
01195         vlan_hdr_t *vp;
01196 
01197         head_acc= bf_cut(pack, 0, 2*sizeof(ether_addr_t));
01198         pack= bf_delhead(pack, 2*sizeof(ether_addr_t));
01199         pack= bf_packIffLess(pack, sizeof(type));
01200         type= *(u16_t *)ptr2acc_data(pack);
01201         if (type == HTONS(ETH_VLAN_PROTO))
01202         {
01203                 /* Packeted is already tagged. Should update vlan number.
01204                  * For now, just discard packet.
01205                  */
01206                 printf("insert_vlan_hdr: discarding vlan packet\n");
01207                 bf_afree(head_acc); head_acc= NULL;
01208                 bf_afree(pack); pack= NULL;
01209                 return NULL;
01210         }
01211         vlan= eth_port->etp_vlan;       /* priority and CFI are zero */
01212 
01213         vh_acc= bf_memreq(sizeof(vlan_hdr_t));
01214         vp= (vlan_hdr_t *)ptr2acc_data(vh_acc);
01215         vp->vh_type= HTONS(ETH_VLAN_PROTO);
01216         vp->vh_vlan= htons(vlan);
01217 
01218         head_acc= bf_append(head_acc, vh_acc); vh_acc= NULL;
01219         head_acc= bf_append(head_acc, pack); pack= NULL;
01220         pack= head_acc; head_acc= NULL;
01221         return pack;
01222 }
01223 
01224 /*
01225  * $PchId: eth.c,v 1.23 2005/06/28 14:15:58 philip Exp $
01226  */

Generated on Fri Apr 14 22:57:30 2006 for minix by  doxygen 1.4.6