psip.c

Go to the documentation of this file.
00001 /*
00002 generic/psip.c
00003 
00004 Implementation of a pseudo IP device.
00005 
00006 Created:        Apr 22, 1993 by Philip Homburg
00007 
00008 Copyright 1995 Philip Homburg
00009 */
00010 
00011 #include "inet.h"
00012 #include "assert.h"
00013 #include "buf.h"
00014 #include "event.h"
00015 #include "type.h"
00016 #include "ip_int.h"
00017 #include "psip.h"
00018 #include "sr.h"
00019 
00020 THIS_FILE
00021 
00022 typedef struct psip_port
00023 {
00024         int pp_flags;
00025         int pp_ipdev;
00026         int pp_opencnt;
00027         struct psip_fd *pp_rd_head;
00028         struct psip_fd *pp_rd_tail;
00029         acc_t *pp_promisc_head;
00030         acc_t *pp_promisc_tail;
00031 } psip_port_t;
00032 
00033 #define PPF_EMPTY       0
00034 #define PPF_CONFIGURED  1
00035 #define PPF_ENABLED     2
00036 #define PPF_PROMISC     4
00037 
00038 #define PSIP_FD_NR      (1*IP_PORT_MAX)
00039 
00040 typedef struct psip_fd
00041 {
00042         int pf_flags;
00043         int pf_srfd;
00044         psip_port_t *pf_port;
00045         get_userdata_t pf_get_userdata;
00046         put_userdata_t pf_put_userdata;
00047         struct psip_fd *pf_rd_next;
00048         size_t pf_rd_count;
00049         nwio_psipopt_t pf_psipopt;
00050 } psip_fd_t;
00051 
00052 #define PFF_EMPTY       0
00053 #define PFF_INUSE       1
00054 #define PFF_READ_IP     2
00055 #define PFF_PROMISC     4
00056 #define PFF_NEXTHOP     8
00057 
00058 PRIVATE psip_port_t *psip_port_table;
00059 PRIVATE psip_fd_t psip_fd_table[PSIP_FD_NR];
00060 
00061 FORWARD int psip_open ARGS(( int port, int srfd,
00062         get_userdata_t get_userdata, put_userdata_t put_userdata,
00063         put_pkt_t pkt_pkt, select_res_t select_res ));
00064 FORWARD int psip_ioctl ARGS(( int fd, ioreq_t req ));
00065 FORWARD int psip_read ARGS(( int fd, size_t count ));
00066 FORWARD int psip_write ARGS(( int fd, size_t count ));
00067 FORWARD int psip_select ARGS(( int port_nr, unsigned operations ));
00068 FORWARD void psip_close ARGS(( int fd ));
00069 FORWARD int psip_cancel ARGS(( int fd, int which_operation ));
00070 FORWARD void promisc_restart_read ARGS(( psip_port_t *psip_port ));
00071 FORWARD int psip_setopt ARGS(( psip_fd_t *psip_fd, nwio_psipopt_t *newoptp ));
00072 FORWARD void psip_buffree ARGS(( int priority ));
00073 FORWARD void check_promisc ARGS(( psip_port_t *psip_port ));
00074 #ifdef BUF_CONSISTENCY_CHECK
00075 FORWARD void psip_bufcheck ARGS(( void ));
00076 #endif
00077 FORWARD void reply_thr_put ARGS(( psip_fd_t *psip_fd, int reply,
00078         int for_ioctl ));
00079 FORWARD void reply_thr_get ARGS(( psip_fd_t *psip_fd, int reply,
00080         int for_ioctl ));
00081 
00082 PUBLIC void psip_prep()
00083 {
00084         psip_port_table= alloc(psip_conf_nr * sizeof(psip_port_table[0]));
00085 }
00086 
00087 PUBLIC void psip_init()
00088 {
00089         int i;
00090         psip_port_t *psip_port;
00091         psip_fd_t *psip_fd;
00092 
00093         for (i=0, psip_port= psip_port_table; i<psip_conf_nr; i++, psip_port++)
00094                 psip_port->pp_flags= PPF_EMPTY;
00095 
00096         for (i=0, psip_fd= psip_fd_table; i<PSIP_FD_NR; i++, psip_fd++)
00097                 psip_fd->pf_flags= PFF_EMPTY;
00098 
00099         for (i=0, psip_port= psip_port_table; i<psip_conf_nr; i++, psip_port++)
00100         {
00101                 psip_port->pp_flags |= PPF_CONFIGURED;
00102                 psip_port->pp_opencnt= 0;
00103                 psip_port->pp_rd_head= NULL;
00104                 psip_port->pp_promisc_head= NULL;
00105         }
00106 
00107 #ifndef BUF_CONSISTENCY_CHECK
00108         bf_logon(psip_buffree);
00109 #else
00110         bf_logon(psip_buffree, psip_bufcheck);
00111 #endif
00112 }
00113 
00114 PUBLIC int psip_enable(port_nr, ip_port_nr)
00115 int port_nr;
00116 int ip_port_nr;
00117 {
00118         psip_port_t *psip_port;
00119 
00120         assert(port_nr >= 0);
00121         if (port_nr >= psip_conf_nr)
00122                 return -1;
00123 
00124         psip_port= &psip_port_table[port_nr];
00125         if (!(psip_port->pp_flags &PPF_CONFIGURED))
00126                 return -1;
00127 
00128         psip_port->pp_ipdev= ip_port_nr;
00129         psip_port->pp_flags |= PPF_ENABLED;
00130 
00131         sr_add_minor(if2minor(psip_conf[port_nr].pc_ifno, PSIP_DEV_OFF),
00132                 port_nr, psip_open, psip_close, psip_read,
00133                 psip_write, psip_ioctl, psip_cancel, psip_select);
00134 
00135         return NW_OK;
00136 }
00137 
00138 PUBLIC int psip_send(port_nr, dest, pack)
00139 int port_nr;
00140 ipaddr_t dest;
00141 acc_t *pack;
00142 {
00143         psip_port_t *psip_port;
00144         psip_fd_t *psip_fd, *mark_fd;
00145         int i, result, result1;
00146         size_t buf_size, extrasize;
00147         acc_t *hdr_pack, *acc;
00148         psip_io_hdr_t *hdr;
00149 
00150         assert(port_nr >= 0 && port_nr < psip_conf_nr);
00151         psip_port= &psip_port_table[port_nr];
00152 
00153         if (psip_port->pp_opencnt == 0)
00154         {
00155                 bf_afree(pack);
00156                 return NW_OK;
00157         }
00158 
00159         for(;;)
00160         {
00161                 mark_fd= psip_port->pp_rd_tail;
00162 
00163                 for(i= 0; i<PSIP_FD_NR; i++)
00164                 {
00165                         psip_fd= psip_port->pp_rd_head;
00166                         if (!psip_fd)
00167                                 return NW_SUSPEND;
00168                         psip_port->pp_rd_head= psip_fd->pf_rd_next;
00169                         if (!(psip_fd->pf_flags & PFF_PROMISC))
00170                                 break;
00171                         psip_fd->pf_rd_next= NULL;
00172                         if (psip_port->pp_rd_head == NULL)
00173                                 psip_port->pp_rd_head= psip_fd;
00174                         else
00175                                 psip_port->pp_rd_tail->pf_rd_next= psip_fd;
00176                         psip_port->pp_rd_tail= psip_fd;
00177                         if (psip_fd == mark_fd)
00178                                 return NW_SUSPEND;
00179                 }
00180                 if (i == PSIP_FD_NR)
00181                         ip_panic(( "psip_send: loop" ));
00182 
00183                 assert(psip_fd->pf_flags & PFF_READ_IP);
00184                 psip_fd->pf_flags &= ~PFF_READ_IP;
00185 
00186                 if (psip_fd->pf_flags & PFF_NEXTHOP)
00187                         extrasize= sizeof(dest);
00188                 else
00189                         extrasize= 0;
00190 
00191                 buf_size= bf_bufsize(pack);
00192                 if (buf_size+extrasize <= psip_fd->pf_rd_count)
00193                 {
00194                         if (psip_port->pp_flags & PPF_PROMISC)
00195                         {
00196                                 /* Deal with promiscuous mode. */
00197                                 hdr_pack= bf_memreq(sizeof(*hdr));
00198                                 hdr= (psip_io_hdr_t *)ptr2acc_data(hdr_pack);
00199                                 memset(hdr, '\0', sizeof(*hdr));
00200                                 hdr->pih_flags |= PF_LOC2REM;
00201                                 hdr->pih_nexthop= dest;
00202 
00203                                 pack->acc_linkC++;
00204                                 hdr_pack->acc_next= pack;
00205                                 hdr_pack->acc_ext_link= NULL;
00206                                 if (psip_port->pp_promisc_head)
00207                                 {
00208                                         /* Append at the end. */
00209                                         psip_port->pp_promisc_tail->
00210                                                 acc_ext_link= hdr_pack;
00211                                         psip_port->pp_promisc_tail= hdr_pack;
00212                                 }
00213                                 else
00214                                 {
00215                                         /* First packet. */
00216                                         psip_port->pp_promisc_head= hdr_pack;
00217                                         psip_port->pp_promisc_tail= hdr_pack;
00218                                         if (psip_port->pp_rd_head)
00219                                             promisc_restart_read(psip_port);
00220                                 }
00221                         }
00222 
00223                         if (extrasize)
00224                         {
00225                                 /* Prepend nexthop address */
00226                                 acc= bf_memreq(sizeof(dest));
00227                                 *(ipaddr_t *)(ptr2acc_data(acc))= dest;
00228                                 acc->acc_next= pack;
00229                                 pack= acc; acc= NULL;
00230                                 buf_size += extrasize;
00231                         }
00232 
00233                         result= (*psip_fd->pf_put_userdata)(psip_fd->pf_srfd, 
00234                                 (size_t)0, pack, FALSE);
00235                         if (result == NW_OK)
00236                                 result= buf_size;
00237                 }
00238                 else
00239                         result= EPACKSIZE;
00240 
00241                 result1= (*psip_fd->pf_put_userdata)(psip_fd->pf_srfd,
00242                                 (size_t)result, NULL, FALSE);
00243                 assert(result1 == NW_OK);
00244                 if (result == EPACKSIZE)
00245                         continue;
00246                 return NW_OK;
00247         }
00248         return NW_SUSPEND;
00249 }
00250 
00251 PRIVATE int psip_open(port, srfd, get_userdata, put_userdata, put_pkt,
00252         select_res)
00253 int port;
00254 int srfd;
00255 get_userdata_t get_userdata;
00256 put_userdata_t put_userdata;
00257 put_pkt_t put_pkt;
00258 select_res_t select_res;
00259 {
00260         psip_port_t *psip_port;
00261         psip_fd_t *psip_fd;
00262         int i;
00263 
00264         assert(port >= 0 && port < psip_conf_nr);
00265         psip_port= &psip_port_table[port];
00266 
00267         if (!(psip_port->pp_flags & PPF_ENABLED))
00268                 return ENXIO;
00269 
00270         for (i= 0, psip_fd= psip_fd_table; i<PSIP_FD_NR; i++, psip_fd++)
00271         {
00272                 if (psip_fd->pf_flags & PFF_INUSE)
00273                         continue;
00274                 break;
00275         }
00276         if (i == PSIP_FD_NR)
00277                 return ENFILE;
00278         psip_fd->pf_flags |= PFF_INUSE;
00279         psip_fd->pf_srfd= srfd;
00280         psip_fd->pf_port= psip_port;
00281         psip_fd->pf_get_userdata= get_userdata;
00282         psip_fd->pf_put_userdata= put_userdata;
00283         psip_port->pp_opencnt++;
00284 
00285         return i;
00286 }
00287 
00288 PRIVATE int psip_ioctl(fd, req)
00289 int fd;
00290 ioreq_t req;
00291 {
00292         int result;
00293         psip_fd_t *psip_fd;
00294         acc_t *data;
00295         nwio_ipconf_t *ipconfp;
00296         nwio_psipopt_t *psip_opt, *newoptp;
00297 
00298         assert(fd >= 0 && fd < PSIP_FD_NR);
00299         psip_fd= &psip_fd_table[fd];
00300 
00301         switch(req)
00302         {
00303         case NWIOSIPCONF:
00304                 data= (*psip_fd->pf_get_userdata)(psip_fd->pf_srfd, 0, 
00305                         sizeof(*ipconfp), TRUE);
00306                 if (!data)
00307                 {
00308                         result= EFAULT;
00309                         break;
00310                 }
00311                 data= bf_packIffLess(data, sizeof(*ipconfp));
00312                 assert (data->acc_length == sizeof(*ipconfp));
00313 
00314                 ipconfp= (nwio_ipconf_t *)ptr2acc_data(data);
00315                 result= ip_setconf(psip_fd->pf_port->pp_ipdev, ipconfp);
00316                 bf_afree(data);
00317                 reply_thr_get(psip_fd, result, TRUE);
00318                 break;
00319         case NWIOSPSIPOPT:
00320                 data= (*psip_fd->pf_get_userdata)(psip_fd->pf_srfd, 0, 
00321                         sizeof(*psip_opt), TRUE);
00322                 if (!data)
00323                 {
00324                         result= EFAULT;
00325                         break;
00326                 }
00327                 data= bf_packIffLess(data, sizeof(*psip_opt));
00328                 assert (data->acc_length == sizeof(*psip_opt));
00329 
00330                 newoptp= (nwio_psipopt_t *)ptr2acc_data(data);
00331                 result= psip_setopt(psip_fd, newoptp);
00332                 bf_afree(data);
00333                 if (result == NW_OK)
00334                 {
00335                         if (psip_fd->pf_psipopt.nwpo_flags & NWPO_EN_PROMISC)
00336                         {
00337                                 psip_fd->pf_flags |= PFF_PROMISC;
00338                                 psip_fd->pf_port->pp_flags |= PPF_PROMISC;
00339                         }
00340                         else
00341                         {
00342                                 psip_fd->pf_flags &= ~PFF_PROMISC;
00343                                 check_promisc(psip_fd->pf_port);
00344                         }
00345                         if (psip_fd->pf_psipopt.nwpo_flags & NWPO_EN_NEXTHOP)
00346                         {
00347                                 psip_fd->pf_flags |= PFF_NEXTHOP;
00348                         }
00349                         else
00350                         {
00351                                 psip_fd->pf_flags &= ~PFF_NEXTHOP;
00352                         }
00353                 }
00354                 reply_thr_get(psip_fd, result, TRUE);
00355                 break;
00356         case NWIOGPSIPOPT:
00357                 data= bf_memreq(sizeof(*psip_opt));
00358                 psip_opt= (nwio_psipopt_t *)ptr2acc_data(data);
00359 
00360                 *psip_opt= psip_fd->pf_psipopt;
00361                 result= (*psip_fd->pf_put_userdata)(psip_fd->pf_srfd, 0,
00362                         data, TRUE);
00363                 if (result == NW_OK)
00364                         reply_thr_put(psip_fd, NW_OK, TRUE);
00365                 break;
00366         default:
00367                 reply_thr_put(psip_fd, ENOTTY, TRUE);
00368                 break;
00369         }
00370         return NW_OK;
00371 }
00372 
00373 PRIVATE int psip_read(fd, count)
00374 int fd;
00375 size_t count;
00376 {
00377         psip_port_t *psip_port;
00378         psip_fd_t *psip_fd;
00379         acc_t *pack;
00380         size_t buf_size;
00381         int result, result1;
00382 
00383         assert(fd >= 0 && fd < PSIP_FD_NR);
00384         psip_fd= &psip_fd_table[fd];
00385         psip_port= psip_fd->pf_port;
00386 
00387         if ((psip_fd->pf_flags & PFF_PROMISC) && psip_port->pp_promisc_head)
00388         {
00389                 /* Deliver a queued packet. */
00390                 pack= psip_port->pp_promisc_head;
00391                 buf_size= bf_bufsize(pack);
00392                 if (buf_size <= count)
00393                 {
00394                         psip_port->pp_promisc_head= pack->acc_ext_link;
00395                         result= (*psip_fd->pf_put_userdata)(psip_fd->pf_srfd, 
00396                                 (size_t)0, pack, FALSE);
00397                         if (result == NW_OK)
00398                                 result= buf_size;
00399                 }
00400                 else
00401                         result= EPACKSIZE;
00402 
00403                 result1= (*psip_fd->pf_put_userdata)(psip_fd->pf_srfd,
00404                                 (size_t)result, NULL, FALSE);
00405                 assert(result1 == NW_OK);
00406                 return NW_OK;
00407         }
00408 
00409         psip_fd->pf_rd_count= count;
00410         if (psip_port->pp_rd_head == NULL)
00411                 psip_port->pp_rd_head= psip_fd;
00412         else
00413                 psip_port->pp_rd_tail->pf_rd_next= psip_fd;
00414         psip_fd->pf_rd_next= NULL;
00415         psip_port->pp_rd_tail= psip_fd;
00416 
00417         psip_fd->pf_flags |= PFF_READ_IP;
00418         if (!(psip_fd->pf_flags & PFF_PROMISC))
00419                 ipps_get(psip_port->pp_ipdev);
00420         if (psip_fd->pf_flags & PFF_READ_IP)
00421                 return NW_SUSPEND;
00422         return NW_OK;
00423 }
00424 
00425 PRIVATE int psip_write(fd, count)
00426 int fd;
00427 size_t count;
00428 {
00429         psip_port_t *psip_port;
00430         psip_fd_t *psip_fd;
00431         acc_t *pack, *hdr_pack;
00432         psip_io_hdr_t *hdr;
00433         size_t pack_len;
00434         ipaddr_t nexthop;
00435 
00436         assert(fd >= 0 && fd < PSIP_FD_NR);
00437         psip_fd= &psip_fd_table[fd];
00438         psip_port= psip_fd->pf_port;
00439 
00440         pack= (*psip_fd->pf_get_userdata)(psip_fd->pf_srfd, (size_t)0,
00441                 count, FALSE);
00442         if (pack == NULL)
00443         {
00444                 pack= (*psip_fd->pf_get_userdata)(psip_fd->pf_srfd, 
00445                         (size_t)EFAULT, (size_t)0, FALSE);
00446                 assert(pack == NULL);
00447                 return NW_OK;
00448         }
00449 
00450         if (psip_fd->pf_flags & PFF_NEXTHOP)
00451         {
00452                 pack_len= bf_bufsize(pack);
00453                 if (pack_len <= sizeof(nexthop))
00454                 {
00455                         /* Something strange */
00456                         bf_afree(pack); pack= NULL;
00457                         pack= (*psip_fd->pf_get_userdata)(psip_fd->pf_srfd,
00458                                 (size_t)EPACKSIZE, (size_t)0, FALSE);
00459                         assert(pack == NULL);
00460                         return NW_OK;
00461                 }
00462                 pack= bf_packIffLess(pack, sizeof(nexthop));
00463                 nexthop= *(ipaddr_t *)ptr2acc_data(pack);
00464                 pack= bf_delhead(pack, sizeof(nexthop));
00465 
00466                 /* Map multicast to broadcast */
00467                 if ((nexthop & HTONL(0xE0000000)) == HTONL(0xE0000000))
00468                         nexthop= HTONL(0xffffffff);
00469         }
00470         else
00471         {
00472                 /* Assume point to point */
00473                 nexthop= HTONL(0x00000000);
00474         }
00475 
00476         if (psip_port->pp_flags & PPF_PROMISC)
00477         {
00478                 /* Deal with promiscuous mode. */
00479                 hdr_pack= bf_memreq(sizeof(*hdr));
00480                 hdr= (psip_io_hdr_t *)ptr2acc_data(hdr_pack);
00481                 memset(hdr, '\0', sizeof(*hdr));
00482                 hdr->pih_flags |= PF_REM2LOC;
00483                 hdr->pih_nexthop= nexthop;
00484 
00485                 pack->acc_linkC++;
00486                 hdr_pack->acc_next= pack;
00487                 hdr_pack->acc_ext_link= NULL;
00488                 if (psip_port->pp_promisc_head)
00489                 {
00490                         /* Append at the end. */
00491                         psip_port->pp_promisc_tail->acc_ext_link= hdr_pack;
00492                         psip_port->pp_promisc_tail= hdr_pack;
00493                 }
00494                 else
00495                 {
00496                         /* First packet. */
00497                         psip_port->pp_promisc_head= hdr_pack;
00498                         psip_port->pp_promisc_tail= hdr_pack;
00499                         if (psip_port->pp_rd_head)
00500                                 promisc_restart_read(psip_port);
00501                 }
00502         }
00503         ipps_put(psip_port->pp_ipdev, nexthop, pack);
00504         pack= (*psip_fd->pf_get_userdata)(psip_fd->pf_srfd, (size_t)count,
00505                 (size_t)0, FALSE);
00506         assert(pack == NULL);
00507         return NW_OK;
00508 }
00509 
00510 PRIVATE int psip_select(fd, operations)
00511 int fd;
00512 unsigned operations;
00513 {
00514         printf("psip_select: not implemented\n");
00515         return 0;
00516 }
00517 
00518 PRIVATE void psip_close(fd)
00519 int fd;
00520 {
00521         psip_port_t *psip_port;
00522         psip_fd_t *psip_fd;
00523 
00524         assert(fd >= 0 && fd < PSIP_FD_NR);
00525         psip_fd= &psip_fd_table[fd];
00526         psip_port= psip_fd->pf_port;
00527 
00528         if (psip_fd->pf_flags & PFF_PROMISC)
00529         {
00530                 /* Check if the port should still be in promiscuous mode.
00531                  */
00532                 psip_fd->pf_flags &= ~PFF_PROMISC;
00533                 check_promisc(psip_fd->pf_port);
00534         }
00535 
00536         assert(psip_port->pp_opencnt >0);
00537         psip_port->pp_opencnt--;
00538         psip_fd->pf_flags= PFF_EMPTY;
00539         ipps_get(psip_port->pp_ipdev);
00540 
00541 }
00542 
00543 PRIVATE int psip_cancel(fd, which_operation)
00544 int fd;
00545 int which_operation;
00546 {
00547         psip_port_t *psip_port;
00548         psip_fd_t *psip_fd, *prev_fd, *tmp_fd;
00549         int result;
00550 
00551         DBLOCK(1, printf("psip_cancel(%d, %d)\n", fd, which_operation));
00552 
00553         assert(fd >= 0 && fd < PSIP_FD_NR);
00554         psip_fd= &psip_fd_table[fd];
00555         psip_port= psip_fd->pf_port;
00556 
00557         switch(which_operation)
00558         {
00559         case SR_CANCEL_IOCTL:
00560                 ip_panic(( "should not be here" ));
00561         case SR_CANCEL_READ:
00562                 assert(psip_fd->pf_flags & PFF_READ_IP);
00563                 for (prev_fd= NULL, tmp_fd= psip_port->pp_rd_head; tmp_fd;
00564                         prev_fd= tmp_fd, tmp_fd= tmp_fd->pf_rd_next)
00565                 {
00566                         if (tmp_fd == psip_fd)
00567                                 break;
00568                 }
00569                 if (tmp_fd == NULL)
00570                         ip_panic(( "unable to find to request to cancel" ));
00571                 if (prev_fd == NULL)
00572                         psip_port->pp_rd_head= psip_fd->pf_rd_next;
00573                 else
00574                         prev_fd->pf_rd_next= psip_fd->pf_rd_next;
00575                 if (psip_fd->pf_rd_next == NULL)
00576                         psip_port->pp_rd_tail= prev_fd;
00577                 psip_fd->pf_flags &= ~PFF_READ_IP;
00578                 result= (*psip_fd->pf_put_userdata)(psip_fd->pf_srfd,
00579                                                 (size_t)EINTR, NULL, FALSE);
00580                 assert(result == NW_OK);
00581                 break;
00582         case SR_CANCEL_WRITE:
00583                 ip_panic(( "should not be here" ));
00584         default:
00585                 ip_panic(( "invalid operation for cancel" ));
00586         }
00587         return NW_OK;
00588 }
00589 
00590 PRIVATE void promisc_restart_read(psip_port)
00591 psip_port_t *psip_port;
00592 {
00593         psip_fd_t *psip_fd, *prev, *next;
00594         acc_t *pack;
00595         size_t buf_size;
00596         int result, result1;
00597 
00598         /* Overkill at the moment: just one reader in promiscious mode is
00599          * allowed.
00600          */
00601         pack= psip_port->pp_promisc_head;
00602         if (!pack)
00603                 return;
00604         assert(pack->acc_ext_link == NULL);
00605 
00606         for(psip_fd= psip_port->pp_rd_head, prev= NULL; psip_fd;
00607                 prev= psip_fd, psip_fd= psip_fd->pf_rd_next)
00608         {
00609 again:
00610                 if (!(psip_fd->pf_flags & PFF_PROMISC))
00611                         continue;
00612                 next= psip_fd->pf_rd_next;
00613                 if (prev)
00614                         prev->pf_rd_next= next;
00615                 else
00616                         psip_port->pp_rd_head= next;
00617                 if (!next)
00618                         psip_port->pp_rd_tail= prev;
00619 
00620                 assert(psip_fd->pf_flags & PFF_READ_IP);
00621                 psip_fd->pf_flags &= ~PFF_READ_IP;
00622 
00623                 buf_size= bf_bufsize(pack);
00624                 if (buf_size <= psip_fd->pf_rd_count)
00625                 {
00626                         psip_port->pp_promisc_head= pack->acc_ext_link;
00627                         result= (*psip_fd->pf_put_userdata)(psip_fd->pf_srfd, 
00628                                 (size_t)0, pack, FALSE);
00629                         if (result == NW_OK)
00630                                 result= buf_size;
00631                 }
00632                 else
00633                         result= EPACKSIZE;
00634 
00635                 result1= (*psip_fd->pf_put_userdata)(psip_fd->pf_srfd,
00636                                 (size_t)result, NULL, FALSE);
00637                 assert(result1 == NW_OK);
00638 
00639                 if (psip_port->pp_promisc_head)
00640                 {
00641                         /* Restart from the beginning */
00642                         assert(result == EPACKSIZE);
00643                         psip_fd= psip_port->pp_rd_head;
00644                         prev= NULL;
00645                         goto again;
00646                 }
00647                 break;
00648         }
00649 }
00650 
00651 PRIVATE int psip_setopt(psip_fd, newoptp)
00652 psip_fd_t *psip_fd;
00653 nwio_psipopt_t *newoptp;
00654 {
00655         nwio_psipopt_t oldopt;
00656         unsigned int new_en_flags, new_di_flags, old_en_flags, old_di_flags;
00657         unsigned long new_flags;
00658 
00659         oldopt= psip_fd->pf_psipopt;
00660 
00661         old_en_flags= oldopt.nwpo_flags & 0xffff;
00662         old_di_flags= (oldopt.nwpo_flags >> 16) & 0xffff;
00663 
00664         new_en_flags= newoptp->nwpo_flags & 0xffff;
00665         new_di_flags= (newoptp->nwpo_flags >> 16) & 0xffff;
00666 
00667         if (new_en_flags & new_di_flags)
00668                 return EBADMODE;
00669 
00670         /* NWUO_LOCADDR_MASK */
00671         if (!((new_en_flags | new_di_flags) & NWPO_PROMISC_MASK))
00672         {
00673                 new_en_flags |= (old_en_flags & NWPO_PROMISC_MASK);
00674                 new_di_flags |= (old_di_flags & NWPO_PROMISC_MASK);
00675         }
00676 
00677         new_flags= ((unsigned long)new_di_flags << 16) | new_en_flags;
00678         if ((new_flags & NWPO_EN_PROMISC) &&
00679                 (psip_fd->pf_port->pp_flags & PPF_PROMISC))
00680         {
00681                 printf("psip_setopt: EBUSY for port %d, flags 0x%x\n",
00682                         psip_fd->pf_port - psip_port_table,
00683                         psip_fd->pf_port->pp_flags);
00684                 /* We can support only one at a time. */
00685                 return EBUSY;
00686         }
00687 
00688         psip_fd->pf_psipopt= *newoptp;
00689         psip_fd->pf_psipopt.nwpo_flags= new_flags;
00690 
00691         return NW_OK;
00692 }
00693 
00694 PRIVATE void check_promisc(psip_port)
00695 psip_port_t *psip_port;
00696 {
00697         int i;
00698         psip_fd_t *psip_fd;
00699         acc_t *acc, *acc_next;
00700 
00701         /* Check if the port should still be in promiscuous mode.  Overkill
00702          * at the moment.
00703          */
00704         if (!(psip_port->pp_flags & PPF_PROMISC))
00705                 return;
00706 
00707         psip_port->pp_flags &= ~PPF_PROMISC;
00708         for (i= 0, psip_fd= psip_fd_table; i<PSIP_FD_NR; i++, psip_fd++)
00709         {
00710                 if ((psip_fd->pf_flags & (PFF_INUSE|PFF_PROMISC)) !=
00711                         (PFF_INUSE|PFF_PROMISC))
00712                 {
00713                         continue;
00714                 }
00715                 if (psip_fd->pf_port != psip_port)
00716                         continue;
00717                 printf("check_promisc: setting PROMISC for port %d\n",
00718                         psip_port-psip_port_table);
00719                 psip_port->pp_flags |= PPF_PROMISC;
00720                 break;
00721         }
00722         if (!(psip_port->pp_flags & PPF_PROMISC))
00723         {
00724                 /* Delete queued packets. */
00725                 acc= psip_port->pp_promisc_head;
00726                 psip_port->pp_promisc_head= NULL;
00727                 while (acc)
00728                 {
00729                         acc_next= acc->acc_ext_link;
00730                         bf_afree(acc);
00731                         acc= acc_next;
00732                 }
00733         }
00734 }
00735 
00736 PRIVATE void psip_buffree (priority)
00737 int priority;
00738 {
00739         int i;
00740         psip_port_t *psip_port;
00741         acc_t *tmp_acc, *next_acc;
00742 
00743         if (priority == PSIP_PRI_EXP_PROMISC)
00744         {
00745                 for (i=0, psip_port= psip_port_table; i<psip_conf_nr;
00746                         i++, psip_port++)
00747                 {
00748                         if (!(psip_port->pp_flags & PPF_CONFIGURED) )
00749                                 continue;
00750                         if (psip_port->pp_promisc_head)
00751                         {
00752                                 tmp_acc= psip_port->pp_promisc_head;
00753                                 while(tmp_acc)
00754                                 {
00755                                         next_acc= tmp_acc->acc_ext_link;
00756                                         bf_afree(tmp_acc);
00757                                         tmp_acc= next_acc;
00758                                 }
00759                                 psip_port->pp_promisc_head= NULL;
00760                         }
00761                 }
00762         }
00763 }
00764 
00765 #ifdef BUF_CONSISTENCY_CHECK
00766 PRIVATE void psip_bufcheck()
00767 {
00768         int i;
00769         psip_port_t *psip_port;
00770         acc_t *tmp_acc;
00771 
00772         for (i= 0, psip_port= psip_port_table; i<psip_conf_nr;
00773                 i++, psip_port++)
00774         {
00775                 for (tmp_acc= psip_port->pp_promisc_head; tmp_acc; 
00776                         tmp_acc= tmp_acc->acc_ext_link)
00777                 {
00778                         bf_check_acc(tmp_acc);
00779                 }
00780         }
00781 }
00782 #endif
00783 
00784 /*
00785 reply_thr_put
00786 */
00787 
00788 PRIVATE void reply_thr_put(psip_fd, reply, for_ioctl)
00789 psip_fd_t *psip_fd;
00790 int reply;
00791 int for_ioctl;
00792 {
00793         int result;
00794 
00795         result= (*psip_fd->pf_put_userdata)(psip_fd->pf_srfd, reply,
00796                 (acc_t *)0, for_ioctl);
00797         assert(result == NW_OK);
00798 }
00799 
00800 /*
00801 reply_thr_get
00802 */
00803 
00804 PRIVATE void reply_thr_get(psip_fd, reply, for_ioctl)
00805 psip_fd_t *psip_fd;
00806 int reply;
00807 int for_ioctl;
00808 {
00809         acc_t *result;
00810         result= (*psip_fd->pf_get_userdata)(psip_fd->pf_srfd, reply,
00811                 (size_t)0, for_ioctl);
00812         assert (!result);
00813 }
00814 
00815 
00816 /*
00817  * $PchId: psip.c,v 1.15 2005/06/28 14:19:29 philip Exp $
00818  */

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