udp.c

Go to the documentation of this file.
00001 /*
00002 udp.c
00003 
00004 Copyright 1995 Philip Homburg
00005 */
00006 
00007 #include "inet.h"
00008 #include "type.h"
00009 
00010 #include "assert.h"
00011 #include "buf.h"
00012 #include "clock.h"
00013 #include "icmp_lib.h"
00014 #include "io.h"
00015 #include "ip.h"
00016 #include "sr.h"
00017 #include "udp.h"
00018 #include "udp_int.h"
00019 
00020 THIS_FILE
00021 
00022 FORWARD void read_ip_packets ARGS(( udp_port_t *udp_port ));
00023 FORWARD void udp_buffree ARGS(( int priority ));
00024 #ifdef BUF_CONSISTENCY_CHECK
00025 FORWARD void udp_bufcheck ARGS(( void ));
00026 #endif
00027 FORWARD void udp_main ARGS(( udp_port_t *udp_port ));
00028 FORWARD int udp_select ARGS(( int fd, unsigned operations ));
00029 FORWARD acc_t *udp_get_data ARGS(( int fd, size_t offset, size_t count, 
00030         int for_ioctl ));
00031 FORWARD int udp_put_data ARGS(( int fd, size_t offset, acc_t *data,     
00032         int for_ioctl ));
00033 FORWARD int udp_peek ARGS(( udp_fd_t * ));
00034 FORWARD int udp_sel_read ARGS(( udp_fd_t * ));
00035 FORWARD void udp_restart_write_port ARGS(( udp_port_t *udp_port ));
00036 FORWARD void udp_ip_arrived ARGS(( int port, acc_t *pack, size_t pack_size ));
00037 FORWARD void reply_thr_put ARGS(( udp_fd_t *udp_fd, int reply,
00038         int for_ioctl ));
00039 FORWARD void reply_thr_get ARGS(( udp_fd_t *udp_fd, int reply,
00040         int for_ioctl ));
00041 FORWARD int udp_setopt ARGS(( udp_fd_t *udp_fd ));
00042 FORWARD udpport_t find_unused_port ARGS(( int fd ));
00043 FORWARD int is_unused_port ARGS(( Udpport_t port ));
00044 FORWARD int udp_packet2user ARGS(( udp_fd_t *udp_fd ));
00045 FORWARD void restart_write_fd ARGS(( udp_fd_t *udp_fd ));
00046 FORWARD u16_t pack_oneCsum ARGS(( acc_t *pack ));
00047 FORWARD void udp_rd_enqueue ARGS(( udp_fd_t *udp_fd, acc_t *pack,
00048                                                         clock_t exp_tim ));
00049 FORWARD void hash_fd ARGS(( udp_fd_t *udp_fd ));
00050 FORWARD void unhash_fd ARGS(( udp_fd_t *udp_fd ));
00051 
00052 PUBLIC udp_port_t *udp_port_table;
00053 PUBLIC udp_fd_t udp_fd_table[UDP_FD_NR];
00054 
00055 PUBLIC void udp_prep()
00056 {
00057         udp_port_table= alloc(udp_conf_nr * sizeof(udp_port_table[0]));
00058 }
00059 
00060 PUBLIC void udp_init()
00061 {
00062         udp_fd_t *udp_fd;
00063         udp_port_t *udp_port;
00064         int i, j, ifno;
00065 
00066         assert (BUF_S >= sizeof(struct nwio_ipopt));
00067         assert (BUF_S >= sizeof(struct nwio_ipconf));
00068         assert (BUF_S >= sizeof(struct nwio_udpopt));
00069         assert (BUF_S >= sizeof(struct udp_io_hdr));
00070         assert (UDP_HDR_SIZE == sizeof(udp_hdr_t));
00071         assert (UDP_IO_HDR_SIZE == sizeof(udp_io_hdr_t));
00072 
00073         for (i= 0, udp_fd= udp_fd_table; i<UDP_FD_NR; i++, udp_fd++)
00074         {
00075                 udp_fd->uf_flags= UFF_EMPTY;
00076                 udp_fd->uf_rdbuf_head= NULL;
00077         }
00078 
00079 #ifndef BUF_CONSISTENCY_CHECK
00080         bf_logon(udp_buffree);
00081 #else
00082         bf_logon(udp_buffree, udp_bufcheck);
00083 #endif
00084 
00085         for (i= 0, udp_port= udp_port_table; i<udp_conf_nr; i++, udp_port++)
00086         {
00087                 udp_port->up_ipdev= udp_conf[i].uc_port;
00088 
00089                 udp_port->up_flags= UPF_EMPTY;
00090                 udp_port->up_state= UPS_EMPTY;
00091                 udp_port->up_next_fd= udp_fd_table;
00092                 udp_port->up_write_fd= NULL;
00093                 udp_port->up_wr_pack= NULL;
00094                 udp_port->up_port_any= NULL;
00095                 for (j= 0; j<UDP_PORT_HASH_NR; j++)
00096                         udp_port->up_port_hash[j]= NULL;
00097 
00098                 ifno= ip_conf[udp_port->up_ipdev].ic_ifno;
00099                 sr_add_minor(if2minor(ifno, UDP_DEV_OFF),
00100                         i, udp_open, udp_close, udp_read,
00101                         udp_write, udp_ioctl, udp_cancel, udp_select);
00102 
00103                 udp_main(udp_port);
00104         }
00105 }
00106 
00107 PUBLIC int udp_open (port, srfd, get_userdata, put_userdata, put_pkt,
00108         select_res)
00109 int port;
00110 int srfd;
00111 get_userdata_t get_userdata;
00112 put_userdata_t put_userdata;
00113 put_pkt_t put_pkt;
00114 select_res_t select_res;
00115 {
00116         int i;
00117         udp_fd_t *udp_fd;
00118 
00119         for (i= 0; i<UDP_FD_NR && (udp_fd_table[i].uf_flags & UFF_INUSE);
00120                 i++);
00121 
00122         if (i>= UDP_FD_NR)
00123         {
00124                 DBLOCK(1, printf("out of fds\n"));
00125                 return EAGAIN;
00126         }
00127 
00128         udp_fd= &udp_fd_table[i];
00129 
00130         udp_fd->uf_flags= UFF_INUSE;
00131         udp_fd->uf_port= &udp_port_table[port];
00132         udp_fd->uf_srfd= srfd;
00133         udp_fd->uf_udpopt.nwuo_flags= UDP_DEF_OPT;
00134         udp_fd->uf_get_userdata= get_userdata;
00135         udp_fd->uf_put_userdata= put_userdata;
00136         udp_fd->uf_select_res= select_res;
00137         assert(udp_fd->uf_rdbuf_head == NULL);
00138         udp_fd->uf_port_next= NULL;
00139 
00140         return i;
00141 
00142 }
00143 
00144 PUBLIC int udp_ioctl (fd, req)
00145 int fd;
00146 ioreq_t req;
00147 {
00148         udp_fd_t *udp_fd;
00149         udp_port_t *udp_port;
00150         nwio_udpopt_t *udp_opt;
00151         acc_t *opt_acc;
00152         int result;
00153 
00154         udp_fd= &udp_fd_table[fd];
00155 
00156 assert (udp_fd->uf_flags & UFF_INUSE);
00157 
00158         udp_port= udp_fd->uf_port;
00159         udp_fd->uf_flags |= UFF_IOCTL_IP;
00160         udp_fd->uf_ioreq= req;
00161 
00162         if (udp_port->up_state != UPS_MAIN)
00163                 return NW_SUSPEND;
00164 
00165         switch(req)
00166         {
00167         case NWIOSUDPOPT:
00168                 result= udp_setopt(udp_fd);
00169                 break;
00170         case NWIOGUDPOPT:
00171                 opt_acc= bf_memreq(sizeof(*udp_opt));
00172 assert (opt_acc->acc_length == sizeof(*udp_opt));
00173                 udp_opt= (nwio_udpopt_t *)ptr2acc_data(opt_acc);
00174 
00175                 *udp_opt= udp_fd->uf_udpopt;
00176                 udp_opt->nwuo_locaddr= udp_fd->uf_port->up_ipaddr;
00177                 result= (*udp_fd->uf_put_userdata)(udp_fd->uf_srfd, 0, opt_acc,
00178                         TRUE);
00179                 if (result == NW_OK)
00180                         reply_thr_put(udp_fd, NW_OK, TRUE);
00181                 break;
00182         case NWIOUDPPEEK:
00183                 result= udp_peek(udp_fd);
00184                 break;
00185         default:
00186                 reply_thr_get(udp_fd, EBADIOCTL, TRUE);
00187                 result= NW_OK;
00188                 break;
00189         }
00190         if (result != NW_SUSPEND)
00191                 udp_fd->uf_flags &= ~UFF_IOCTL_IP;
00192         return result;
00193 }
00194 
00195 PUBLIC int udp_read (fd, count)
00196 int fd;
00197 size_t count;
00198 {
00199         udp_fd_t *udp_fd;
00200         acc_t *tmp_acc, *next_acc;
00201 
00202         udp_fd= &udp_fd_table[fd];
00203         if (!(udp_fd->uf_flags & UFF_OPTSET))
00204         {
00205                 reply_thr_put(udp_fd, EBADMODE, FALSE);
00206                 return NW_OK;
00207         }
00208 
00209         udp_fd->uf_rd_count= count;
00210 
00211         if (udp_fd->uf_rdbuf_head)
00212         {
00213                 if (get_time() <= udp_fd->uf_exp_tim)
00214                         return udp_packet2user (udp_fd);
00215                 tmp_acc= udp_fd->uf_rdbuf_head;
00216                 while (tmp_acc)
00217                 {
00218                         next_acc= tmp_acc->acc_ext_link;
00219                         bf_afree(tmp_acc);
00220                         tmp_acc= next_acc;
00221                 }
00222                 udp_fd->uf_rdbuf_head= NULL;
00223         }
00224         udp_fd->uf_flags |= UFF_READ_IP;
00225         return NW_SUSPEND;
00226 }
00227 
00228 PRIVATE void udp_main(udp_port)
00229 udp_port_t *udp_port;
00230 {
00231         udp_fd_t *udp_fd;
00232         int result, i;
00233 
00234         switch (udp_port->up_state)
00235         {
00236         case UPS_EMPTY:
00237                 udp_port->up_state= UPS_SETPROTO;
00238 
00239                 udp_port->up_ipfd= ip_open(udp_port->up_ipdev, 
00240                         udp_port->up_ipdev, udp_get_data, udp_put_data,
00241                         udp_ip_arrived, 0 /* no select_res */);
00242                 if (udp_port->up_ipfd < 0)
00243                 {
00244                         udp_port->up_state= UPS_ERROR;
00245                         DBLOCK(1, printf("%s, %d: unable to open ip port\n",
00246                                 __FILE__, __LINE__));
00247                         return;
00248                 }
00249 
00250                 result= ip_ioctl(udp_port->up_ipfd, NWIOSIPOPT);
00251                 if (result == NW_SUSPEND)
00252                         udp_port->up_flags |= UPF_SUSPEND;
00253                 if (result<0)
00254                 {
00255                         return;
00256                 }
00257                 if (udp_port->up_state != UPS_GETCONF)
00258                         return;
00259                 /* drops through */
00260         case UPS_GETCONF:
00261                 udp_port->up_flags &= ~UPF_SUSPEND;
00262 
00263                 result= ip_ioctl(udp_port->up_ipfd, NWIOGIPCONF);
00264                 if (result == NW_SUSPEND)
00265                         udp_port->up_flags |= UPF_SUSPEND;
00266                 if (result<0)
00267                 {
00268                         return;
00269                 }
00270                 if (udp_port->up_state != UPS_MAIN)
00271                         return;
00272                 /* drops through */
00273         case UPS_MAIN:
00274                 udp_port->up_flags &= ~UPF_SUSPEND;
00275 
00276                 for (i= 0, udp_fd= udp_fd_table; i<UDP_FD_NR; i++, udp_fd++)
00277                 {
00278                         if (!(udp_fd->uf_flags & UFF_INUSE))
00279                                 continue;
00280                         if (udp_fd->uf_port != udp_port)
00281                                 continue;
00282                         if (udp_fd->uf_flags & UFF_IOCTL_IP)
00283                                 udp_ioctl(i, udp_fd->uf_ioreq);
00284                 }
00285                 read_ip_packets(udp_port);
00286                 return;
00287         default:
00288                 DBLOCK(1, printf("udp_port_table[%d].up_state= %d\n",
00289                         udp_port->up_ipdev, udp_port->up_state));
00290                 ip_panic(( "unknown state" ));
00291                 break;
00292         }
00293 }
00294 
00295 PRIVATE int udp_select(fd, operations)
00296 int fd;
00297 unsigned operations;
00298 {
00299         int i;
00300         unsigned resops;
00301         udp_fd_t *udp_fd;
00302 
00303         udp_fd= &udp_fd_table[fd];
00304         assert (udp_fd->uf_flags & UFF_INUSE);
00305 
00306         resops= 0;
00307 
00308         if (operations & SR_SELECT_READ)
00309         {
00310                 if (udp_sel_read(udp_fd))
00311                         resops |= SR_SELECT_READ;
00312                 else if (!(operations & SR_SELECT_POLL))
00313                         udp_fd->uf_flags |= UFF_SEL_READ;
00314         }
00315         if (operations & SR_SELECT_WRITE)
00316         {
00317                 /* Should handle special case when the interface is down */
00318                 resops |= SR_SELECT_WRITE;
00319         }
00320         if (operations & SR_SELECT_EXCEPTION)
00321         {
00322                 printf("udp_select: not implemented for exceptions\n");
00323         }
00324         return resops;
00325 }
00326 
00327 PRIVATE acc_t *udp_get_data (port, offset, count, for_ioctl)
00328 int port;
00329 size_t offset;
00330 size_t count;
00331 int for_ioctl;
00332 {
00333         udp_port_t *udp_port;
00334         udp_fd_t *udp_fd;
00335         int result;
00336 
00337         udp_port= &udp_port_table[port];
00338 
00339         switch(udp_port->up_state)
00340         {
00341         case UPS_SETPROTO:
00342 assert (for_ioctl);
00343                 if (!count)
00344                 {
00345                         result= (int)offset;
00346                         if (result<0)
00347                         {
00348                                 udp_port->up_state= UPS_ERROR;
00349                                 break;
00350                         }
00351                         udp_port->up_state= UPS_GETCONF;
00352                         if (udp_port->up_flags & UPF_SUSPEND)
00353                                 udp_main(udp_port);
00354                         return NULL;
00355                 }
00356                 else
00357                 {
00358                         struct nwio_ipopt *ipopt;
00359                         acc_t *acc;
00360 
00361 assert (!offset);
00362 assert (count == sizeof(*ipopt));
00363 
00364                         acc= bf_memreq(sizeof(*ipopt));
00365                         ipopt= (struct nwio_ipopt *)ptr2acc_data(acc);
00366                         ipopt->nwio_flags= NWIO_COPY | NWIO_EN_LOC | 
00367                                 NWIO_EN_BROAD | NWIO_REMANY | NWIO_PROTOSPEC |
00368                                 NWIO_HDR_O_ANY | NWIO_RWDATALL;
00369                         ipopt->nwio_proto= IPPROTO_UDP;
00370                         return acc;
00371                 }
00372         case UPS_MAIN:
00373 assert (!for_ioctl);
00374 assert (udp_port->up_flags & UPF_WRITE_IP);
00375                 if (!count)
00376                 {
00377                         result= (int)offset;
00378 assert (udp_port->up_wr_pack);
00379                         bf_afree(udp_port->up_wr_pack);
00380                         udp_port->up_wr_pack= 0;
00381                         if (udp_port->up_flags & UPF_WRITE_SP)
00382                         {
00383                                 if (udp_port->up_write_fd)
00384                                 {
00385                                         udp_fd= udp_port->up_write_fd;
00386                                         udp_port->up_write_fd= NULL;
00387                                         udp_fd->uf_flags &= ~UFF_WRITE_IP;
00388                                         reply_thr_get(udp_fd, result, FALSE);
00389                                 }
00390                                 udp_port->up_flags &= ~(UPF_WRITE_SP | 
00391                                         UPF_WRITE_IP);
00392                                 if (udp_port->up_flags & UPF_MORE2WRITE)
00393                                 {
00394                                         udp_restart_write_port(udp_port);
00395                                 }
00396                         }
00397                         else
00398                                 udp_port->up_flags &= ~UPF_WRITE_IP;
00399                 }
00400                 else
00401                 {
00402                         return bf_cut (udp_port->up_wr_pack, offset, count);
00403                 }
00404                 break;
00405         default:
00406                 printf("udp_get_data(%d, 0x%x, 0x%x) called but up_state= 0x%x\n",
00407                         port, offset, count, udp_port->up_state);
00408                 break;
00409         }
00410         return NULL;
00411 }
00412 
00413 PRIVATE int udp_put_data (fd, offset, data, for_ioctl)
00414 int fd;
00415 size_t offset;
00416 acc_t *data;
00417 int for_ioctl;
00418 {
00419         udp_port_t *udp_port;
00420         int result;
00421 
00422         udp_port= &udp_port_table[fd];
00423 
00424         switch (udp_port->up_state)
00425         {
00426         case UPS_GETCONF:
00427                 if (!data)
00428                 {
00429                         result= (int)offset;
00430                         if (result<0)
00431                         {
00432                                 udp_port->up_state= UPS_ERROR;
00433                                 return NW_OK;
00434                         }
00435                         udp_port->up_state= UPS_MAIN;
00436                         if (udp_port->up_flags & UPF_SUSPEND)
00437                                 udp_main(udp_port);
00438                 }
00439                 else
00440                 {
00441                         struct nwio_ipconf *ipconf;
00442 
00443                         data= bf_packIffLess(data, sizeof(*ipconf));
00444                         ipconf= (struct nwio_ipconf *)ptr2acc_data(data);
00445 assert (ipconf->nwic_flags & NWIC_IPADDR_SET);
00446                         udp_port->up_ipaddr= ipconf->nwic_ipaddr;
00447                         bf_afree(data);
00448                 }
00449                 break;
00450         case UPS_MAIN:
00451                 assert(0);
00452 
00453                 assert (udp_port->up_flags & UPF_READ_IP);
00454                 if (!data)
00455                 {
00456                         result= (int)offset;
00457                         compare (result, >=, 0);
00458                         if (udp_port->up_flags & UPF_READ_SP)
00459                         {
00460                                 udp_port->up_flags &= ~(UPF_READ_SP|
00461                                         UPF_READ_IP);
00462                                 read_ip_packets(udp_port);
00463                         }
00464                         else
00465                                 udp_port->up_flags &= ~UPF_READ_IP;
00466                 }
00467                 else
00468                 {
00469 assert (!offset);       /* This isn't a valid assertion but ip sends only
00470                          * whole datagrams up */
00471                         udp_ip_arrived(fd, data, bf_bufsize(data));
00472                 }
00473                 break;
00474         default:
00475                 ip_panic((
00476                 "udp_put_data(%d, 0x%x, %p) called but up_state= 0x%x\n",
00477                                         fd, offset, data, udp_port->up_state ));
00478         }
00479         return NW_OK;
00480 }
00481 
00482 PRIVATE int udp_setopt(udp_fd)
00483 udp_fd_t *udp_fd;
00484 {
00485         udp_fd_t *fd_ptr;
00486         nwio_udpopt_t oldopt, newopt;
00487         acc_t *data;
00488         unsigned int new_en_flags, new_di_flags, old_en_flags, old_di_flags,
00489                 all_flags, flags;
00490         unsigned long new_flags;
00491         int i;
00492 
00493         data= (*udp_fd->uf_get_userdata)(udp_fd->uf_srfd, 0, 
00494                 sizeof(nwio_udpopt_t), TRUE);
00495 
00496         if (!data)
00497                 return EFAULT;
00498 
00499         data= bf_packIffLess(data, sizeof(nwio_udpopt_t));
00500 assert (data->acc_length == sizeof(nwio_udpopt_t));
00501 
00502         newopt= *(nwio_udpopt_t *)ptr2acc_data(data);
00503         bf_afree(data);
00504         oldopt= udp_fd->uf_udpopt;
00505 
00506         old_en_flags= oldopt.nwuo_flags & 0xffff;
00507         old_di_flags= (oldopt.nwuo_flags >> 16) & 0xffff;
00508 
00509         new_en_flags= newopt.nwuo_flags & 0xffff;
00510         new_di_flags= (newopt.nwuo_flags >> 16) & 0xffff;
00511 
00512         if (new_en_flags & new_di_flags)
00513         {
00514                 DBLOCK(1, printf("returning EBADMODE\n"));
00515 
00516                 reply_thr_get(udp_fd, EBADMODE, TRUE);
00517                 return NW_OK;
00518         }
00519 
00520         /* NWUO_ACC_MASK */
00521         if (new_di_flags & NWUO_ACC_MASK)
00522         {
00523                 DBLOCK(1, printf("returning EBADMODE\n"));
00524 
00525                 reply_thr_get(udp_fd, EBADMODE, TRUE);
00526                 return NW_OK;
00527                 /* access modes can't be disabled */
00528         }
00529 
00530         if (!(new_en_flags & NWUO_ACC_MASK))
00531                 new_en_flags |= (old_en_flags & NWUO_ACC_MASK);
00532 
00533         /* NWUO_LOCPORT_MASK */
00534         if (new_di_flags & NWUO_LOCPORT_MASK)
00535         {
00536                 DBLOCK(1, printf("returning EBADMODE\n"));
00537 
00538                 reply_thr_get(udp_fd, EBADMODE, TRUE);
00539                 return NW_OK;
00540                 /* the loc ports can't be disabled */
00541         }
00542         if (!(new_en_flags & NWUO_LOCPORT_MASK))
00543         {
00544                 new_en_flags |= (old_en_flags & NWUO_LOCPORT_MASK);
00545                 newopt.nwuo_locport= oldopt.nwuo_locport;
00546         }
00547         else if ((new_en_flags & NWUO_LOCPORT_MASK) == NWUO_LP_SEL)
00548         {
00549                 newopt.nwuo_locport= find_unused_port(udp_fd-udp_fd_table);
00550         }
00551         else if ((new_en_flags & NWUO_LOCPORT_MASK) == NWUO_LP_SET)
00552         {
00553                 if (!newopt.nwuo_locport)
00554                 {
00555                         DBLOCK(1, printf("returning EBADMODE\n"));
00556 
00557                         reply_thr_get(udp_fd, EBADMODE, TRUE);
00558                         return NW_OK;
00559                 }
00560         }
00561 
00562         /* NWUO_LOCADDR_MASK */
00563         if (!((new_en_flags | new_di_flags) & NWUO_LOCADDR_MASK))
00564         {
00565                 new_en_flags |= (old_en_flags & NWUO_LOCADDR_MASK);
00566                 new_di_flags |= (old_di_flags & NWUO_LOCADDR_MASK);
00567         }
00568 
00569         /* NWUO_BROAD_MASK */
00570         if (!((new_en_flags | new_di_flags) & NWUO_BROAD_MASK))
00571         {
00572                 new_en_flags |= (old_en_flags & NWUO_BROAD_MASK);
00573                 new_di_flags |= (old_di_flags & NWUO_BROAD_MASK);
00574         }
00575 
00576         /* NWUO_REMPORT_MASK */
00577         if (!((new_en_flags | new_di_flags) & NWUO_REMPORT_MASK))
00578         {
00579                 new_en_flags |= (old_en_flags & NWUO_REMPORT_MASK);
00580                 new_di_flags |= (old_di_flags & NWUO_REMPORT_MASK);
00581                 newopt.nwuo_remport= oldopt.nwuo_remport;
00582         }
00583         
00584         /* NWUO_REMADDR_MASK */
00585         if (!((new_en_flags | new_di_flags) & NWUO_REMADDR_MASK))
00586         {
00587                 new_en_flags |= (old_en_flags & NWUO_REMADDR_MASK);
00588                 new_di_flags |= (old_di_flags & NWUO_REMADDR_MASK);
00589                 newopt.nwuo_remaddr= oldopt.nwuo_remaddr;
00590         }
00591 
00592         /* NWUO_RW_MASK */
00593         if (!((new_en_flags | new_di_flags) & NWUO_RW_MASK))
00594         {
00595                 new_en_flags |= (old_en_flags & NWUO_RW_MASK);
00596                 new_di_flags |= (old_di_flags & NWUO_RW_MASK);
00597         }
00598 
00599         /* NWUO_IPOPT_MASK */
00600         if (!((new_en_flags | new_di_flags) & NWUO_IPOPT_MASK))
00601         {
00602                 new_en_flags |= (old_en_flags & NWUO_IPOPT_MASK);
00603                 new_di_flags |= (old_di_flags & NWUO_IPOPT_MASK);
00604         }
00605 
00606         new_flags= ((unsigned long)new_di_flags << 16) | new_en_flags;
00607         if ((new_flags & NWUO_RWDATONLY) && 
00608                 ((new_flags & NWUO_LOCPORT_MASK) == NWUO_LP_ANY || 
00609                 (new_flags & (NWUO_RP_ANY|NWUO_RA_ANY|NWUO_EN_IPOPT))))
00610         {
00611                 DBLOCK(1, printf("returning EBADMODE\n"));
00612 
00613                 reply_thr_get(udp_fd, EBADMODE, TRUE);
00614                 return NW_OK;
00615         }
00616 
00617         /* Check the access modes */
00618         if ((new_flags & NWUO_LOCPORT_MASK) == NWUO_LP_SEL ||
00619                 (new_flags & NWUO_LOCPORT_MASK) == NWUO_LP_SET)
00620         {
00621                 for (i= 0, fd_ptr= udp_fd_table; i<UDP_FD_NR; i++, fd_ptr++)
00622                 {
00623                         if (fd_ptr == udp_fd)
00624                                 continue;
00625                         if (!(fd_ptr->uf_flags & UFF_INUSE))
00626                                 continue;
00627                         if (fd_ptr->uf_port != udp_fd->uf_port)
00628                                 continue;
00629                         flags= fd_ptr->uf_udpopt.nwuo_flags;
00630                         if ((flags & NWUO_LOCPORT_MASK) != NWUO_LP_SEL &&
00631                                 (flags & NWUO_LOCPORT_MASK) != NWUO_LP_SET)
00632                                 continue;
00633                         if (fd_ptr->uf_udpopt.nwuo_locport !=
00634                                 newopt.nwuo_locport)
00635                         {
00636                                 continue;
00637                         }
00638                         if ((flags & NWUO_ACC_MASK) != 
00639                                 (new_flags & NWUO_ACC_MASK))
00640                         {
00641                                 DBLOCK(1, printf(
00642                         "address inuse: new fd= %d, old_fd= %d, port= %u\n",
00643                                         udp_fd-udp_fd_table,
00644                                         fd_ptr-udp_fd_table,
00645                                         newopt.nwuo_locport));
00646 
00647                                 reply_thr_get(udp_fd, EADDRINUSE, TRUE);
00648                                 return NW_OK;
00649                         }
00650                 }
00651         }
00652 
00653         if (udp_fd->uf_flags & UFF_OPTSET)
00654                 unhash_fd(udp_fd);
00655 
00656         newopt.nwuo_flags= new_flags;
00657         udp_fd->uf_udpopt= newopt;
00658 
00659         all_flags= new_en_flags | new_di_flags;
00660         if ((all_flags & NWUO_ACC_MASK) && (all_flags & NWUO_LOCPORT_MASK) &&
00661                 (all_flags & NWUO_LOCADDR_MASK) &&
00662                 (all_flags & NWUO_BROAD_MASK) &&
00663                 (all_flags & NWUO_REMPORT_MASK) &&
00664                 (all_flags & NWUO_REMADDR_MASK) &&
00665                 (all_flags & NWUO_RW_MASK) &&
00666                 (all_flags & NWUO_IPOPT_MASK))
00667                 udp_fd->uf_flags |= UFF_OPTSET;
00668         else
00669         {
00670                 udp_fd->uf_flags &= ~UFF_OPTSET;
00671         }
00672 
00673         if (udp_fd->uf_flags & UFF_OPTSET)
00674                 hash_fd(udp_fd);
00675 
00676         reply_thr_get(udp_fd, NW_OK, TRUE);
00677         return NW_OK;
00678 }
00679 
00680 PRIVATE udpport_t find_unused_port(fd)
00681 int fd;
00682 {
00683         udpport_t port, nw_port;
00684 
00685         for (port= 0x8000+fd; port < 0xffff-UDP_FD_NR; port+= UDP_FD_NR)
00686         {
00687                 nw_port= htons(port);
00688                 if (is_unused_port(nw_port))
00689                         return nw_port;
00690         }
00691         for (port= 0x8000; port < 0xffff; port++)
00692         {
00693                 nw_port= htons(port);
00694                 if (is_unused_port(nw_port))
00695                         return nw_port;
00696         }
00697         ip_panic(( "unable to find unused port (shouldn't occur)" ));
00698         return 0;
00699 }
00700 
00701 /*
00702 reply_thr_put
00703 */
00704 
00705 PRIVATE void reply_thr_put(udp_fd, reply, for_ioctl)
00706 udp_fd_t *udp_fd;
00707 int reply;
00708 int for_ioctl;
00709 {
00710         int result;
00711 
00712         result= (*udp_fd->uf_put_userdata)(udp_fd->uf_srfd, reply,
00713                 (acc_t *)0, for_ioctl);
00714         assert(result == NW_OK);
00715 }
00716 
00717 /*
00718 reply_thr_get
00719 */
00720 
00721 PRIVATE void reply_thr_get(udp_fd, reply, for_ioctl)
00722 udp_fd_t *udp_fd;
00723 int reply;
00724 int for_ioctl;
00725 {
00726         acc_t *result;
00727         result= (*udp_fd->uf_get_userdata)(udp_fd->uf_srfd, reply,
00728                 (size_t)0, for_ioctl);
00729         assert (!result);
00730 }
00731 
00732 PRIVATE int is_unused_port(port)
00733 udpport_t port;
00734 {
00735         int i;
00736         udp_fd_t *udp_fd;
00737 
00738         for (i= 0, udp_fd= udp_fd_table; i<UDP_FD_NR; i++,
00739                 udp_fd++)
00740         {
00741                 if (!(udp_fd->uf_flags & UFF_OPTSET))
00742                         continue;
00743                 if (udp_fd->uf_udpopt.nwuo_locport == port)
00744                         return FALSE;
00745         }
00746         return TRUE;
00747 }
00748 
00749 PRIVATE void read_ip_packets(udp_port)
00750 udp_port_t *udp_port;
00751 {
00752         int result;
00753 
00754         do
00755         {
00756                 udp_port->up_flags |= UPF_READ_IP;
00757                 result= ip_read(udp_port->up_ipfd, UDP_MAX_DATAGRAM);
00758                 if (result == NW_SUSPEND)
00759                 {
00760                         udp_port->up_flags |= UPF_READ_SP;
00761                         return;
00762                 }
00763 assert(result == NW_OK);
00764                 udp_port->up_flags &= ~UPF_READ_IP;
00765         } while(!(udp_port->up_flags & UPF_READ_IP));
00766 }
00767 
00768 
00769 PRIVATE int udp_peek (udp_fd)
00770 udp_fd_t *udp_fd;
00771 {
00772         acc_t *pack, *tmp_acc, *next_acc;
00773         int result;
00774 
00775         if (!(udp_fd->uf_flags & UFF_OPTSET))
00776         {
00777                 udp_fd->uf_flags &= ~UFF_IOCTL_IP;
00778                 reply_thr_put(udp_fd, EBADMODE, TRUE);
00779                 return NW_OK;
00780         }
00781 
00782         if (udp_fd->uf_rdbuf_head)
00783         {
00784                 if (get_time() <= udp_fd->uf_exp_tim)
00785                 {
00786                         pack= bf_cut(udp_fd->uf_rdbuf_head, 0,
00787                                 sizeof(udp_io_hdr_t));
00788                         result= (*udp_fd->uf_put_userdata)(udp_fd->uf_srfd,
00789                                 (size_t)0, pack, TRUE);
00790 
00791                         udp_fd->uf_flags &= ~UFF_IOCTL_IP;
00792                         result= (*udp_fd->uf_put_userdata)(udp_fd->uf_srfd,
00793                                 result, (acc_t *)0, TRUE);
00794                         assert (result == 0);
00795                         return result;
00796                 }
00797                 tmp_acc= udp_fd->uf_rdbuf_head;
00798                 while (tmp_acc)
00799                 {
00800                         next_acc= tmp_acc->acc_ext_link;
00801                         bf_afree(tmp_acc);
00802                         tmp_acc= next_acc;
00803                 }
00804                 udp_fd->uf_rdbuf_head= NULL;
00805         }
00806         udp_fd->uf_flags |= UFF_PEEK_IP;
00807         return NW_SUSPEND;
00808 }
00809 
00810 PRIVATE int udp_sel_read (udp_fd)
00811 udp_fd_t *udp_fd;
00812 {
00813         acc_t *pack, *tmp_acc, *next_acc;
00814         int result;
00815 
00816         if (!(udp_fd->uf_flags & UFF_OPTSET))
00817                 return 1;       /* Read will not block */
00818 
00819         if (udp_fd->uf_rdbuf_head)
00820         {
00821                 if (get_time() <= udp_fd->uf_exp_tim)
00822                         return 1;
00823                 
00824                 tmp_acc= udp_fd->uf_rdbuf_head;
00825                 while (tmp_acc)
00826                 {
00827                         next_acc= tmp_acc->acc_ext_link;
00828                         bf_afree(tmp_acc);
00829                         tmp_acc= next_acc;
00830                 }
00831                 udp_fd->uf_rdbuf_head= NULL;
00832         }
00833         return 0;
00834 }
00835 
00836 PRIVATE int udp_packet2user (udp_fd)
00837 udp_fd_t *udp_fd;
00838 {
00839         acc_t *pack, *tmp_pack;
00840         udp_io_hdr_t *hdr;
00841         int result, hdr_len;
00842         size_t size, transf_size;
00843 
00844         pack= udp_fd->uf_rdbuf_head;
00845         udp_fd->uf_rdbuf_head= pack->acc_ext_link;
00846 
00847         size= bf_bufsize (pack);
00848 
00849         if (udp_fd->uf_udpopt.nwuo_flags & NWUO_RWDATONLY)
00850         {
00851 
00852                 pack= bf_packIffLess (pack, UDP_IO_HDR_SIZE);
00853                 assert (pack->acc_length >= UDP_IO_HDR_SIZE);
00854 
00855                 hdr= (udp_io_hdr_t *)ptr2acc_data(pack);
00856 #if CONF_UDP_IO_NW_BYTE_ORDER
00857                 hdr_len= UDP_IO_HDR_SIZE+NTOHS(hdr->uih_ip_opt_len);
00858 #else
00859                 hdr_len= UDP_IO_HDR_SIZE+hdr->uih_ip_opt_len;
00860 #endif
00861 
00862                 assert (size>= hdr_len);
00863                 size -= hdr_len;
00864                 tmp_pack= bf_cut(pack, hdr_len, size);
00865                 bf_afree(pack);
00866                 pack= tmp_pack;
00867         }
00868 
00869         if (size>udp_fd->uf_rd_count)
00870         {
00871                 tmp_pack= bf_cut (pack, 0, udp_fd->uf_rd_count);
00872                 bf_afree(pack);
00873                 pack= tmp_pack;
00874                 transf_size= udp_fd->uf_rd_count;
00875         }
00876         else
00877                 transf_size= size;
00878 
00879         result= (*udp_fd->uf_put_userdata)(udp_fd->uf_srfd,
00880                 (size_t)0, pack, FALSE);
00881 
00882         if (result >= 0)
00883                 if (size > transf_size)
00884                         result= EPACKSIZE;
00885                 else
00886                         result= transf_size;
00887 
00888         udp_fd->uf_flags &= ~UFF_READ_IP;
00889         result= (*udp_fd->uf_put_userdata)(udp_fd->uf_srfd, result,
00890                         (acc_t *)0, FALSE);
00891         assert (result == 0);
00892 
00893         return result;
00894 }
00895 
00896 PRIVATE void udp_ip_arrived(port, pack, pack_size)
00897 int port;
00898 acc_t *pack;
00899 size_t pack_size;
00900 {
00901         udp_port_t *udp_port;
00902         udp_fd_t *udp_fd, *share_fd;
00903         acc_t *ip_hdr_acc, *udp_acc, *ipopt_pack, *no_ipopt_pack, *tmp_acc;
00904         ip_hdr_t *ip_hdr;
00905         udp_hdr_t *udp_hdr;
00906         udp_io_hdr_t *udp_io_hdr;
00907         size_t ip_hdr_size, udp_size, data_size, opt_size;
00908         ipaddr_t src_addr, dst_addr, ipaddr;
00909         udpport_t src_port, dst_port;
00910         u8_t u16[2];
00911         u16_t chksum;
00912         unsigned long dst_type, flags;
00913         clock_t exp_tim;
00914         int i, delivered, hash;
00915 
00916         udp_port= &udp_port_table[port];
00917 
00918         ip_hdr_acc= bf_cut(pack, 0, IP_MIN_HDR_SIZE);
00919         ip_hdr_acc= bf_packIffLess(ip_hdr_acc, IP_MIN_HDR_SIZE);
00920         ip_hdr= (ip_hdr_t *)ptr2acc_data(ip_hdr_acc);
00921         ip_hdr_size= (ip_hdr->ih_vers_ihl & IH_IHL_MASK) << 2;
00922         if (ip_hdr_size != IP_MIN_HDR_SIZE)
00923         {
00924                 bf_afree(ip_hdr_acc);
00925                 ip_hdr_acc= bf_cut(pack, 0, ip_hdr_size);
00926                 ip_hdr_acc= bf_packIffLess(ip_hdr_acc, ip_hdr_size);
00927                 ip_hdr= (ip_hdr_t *)ptr2acc_data(ip_hdr_acc);
00928         }
00929 
00930         pack_size -= ip_hdr_size;
00931         if (pack_size < UDP_HDR_SIZE)
00932         {
00933                 if (pack_size == 0 && ip_hdr->ih_proto == 0)
00934                 {
00935                         /* IP layer reports new IP address */
00936                         ipaddr= ip_hdr->ih_src;
00937                         udp_port->up_ipaddr= ipaddr;
00938                         DBLOCK(1, printf("udp_ip_arrived: using address ");
00939                                 writeIpAddr(ipaddr); printf("\n"));
00940                 }
00941                 else
00942                         DBLOCK(1, printf("packet too small\n"));
00943 
00944                 bf_afree(ip_hdr_acc);
00945                 bf_afree(pack);
00946                 return;
00947         }
00948 
00949         udp_acc= bf_delhead(pack, ip_hdr_size);
00950         pack= NULL;
00951 
00952 
00953         udp_acc= bf_packIffLess(udp_acc, UDP_HDR_SIZE);
00954         udp_hdr= (udp_hdr_t *)ptr2acc_data(udp_acc);
00955         udp_size= ntohs(udp_hdr->uh_length);
00956         if (udp_size > pack_size)
00957         {
00958                 DBLOCK(1, printf("packet too large\n"));
00959 
00960                 bf_afree(ip_hdr_acc);
00961                 bf_afree(udp_acc);
00962                 return;
00963         }
00964 
00965         src_addr= ip_hdr->ih_src;
00966         dst_addr= ip_hdr->ih_dst;
00967 
00968         if (udp_hdr->uh_chksum)
00969         {
00970                 u16[0]= 0;
00971                 u16[1]= ip_hdr->ih_proto;
00972                 chksum= pack_oneCsum(udp_acc);
00973                 chksum= oneC_sum(chksum, (u16_t *)&src_addr, sizeof(ipaddr_t));
00974                 chksum= oneC_sum(chksum, (u16_t *)&dst_addr, sizeof(ipaddr_t));
00975                 chksum= oneC_sum(chksum, (u16_t *)u16, sizeof(u16));
00976                 chksum= oneC_sum(chksum, (u16_t *)&udp_hdr->uh_length, 
00977                         sizeof(udp_hdr->uh_length));
00978                 if (~chksum & 0xffff)
00979                 {
00980                         DBLOCK(1, printf("checksum error in udp packet\n");
00981                                 printf("src ip_addr= ");
00982                                 writeIpAddr(src_addr);
00983                                 printf(" dst ip_addr= ");
00984                                 writeIpAddr(dst_addr);
00985                                 printf("\n");
00986                                 printf("packet chksum= 0x%x, sum= 0x%x\n",
00987                                         udp_hdr->uh_chksum, chksum));
00988 
00989                         bf_afree(ip_hdr_acc);
00990                         bf_afree(udp_acc);
00991                         return;
00992                 }
00993         }
00994 
00995         exp_tim= get_time() + UDP_READ_EXP_TIME;
00996         src_port= udp_hdr->uh_src_port;
00997         dst_port= udp_hdr->uh_dst_port;
00998 
00999         /* Send an ICMP port unreachable if the packet could not be
01000          * delivered.
01001          */
01002         delivered= 0;
01003 
01004         if (dst_addr == udp_port->up_ipaddr)
01005                 dst_type= NWUO_EN_LOC;
01006         else
01007         {
01008                 dst_type= NWUO_EN_BROAD;
01009 
01010                 /* Don't send ICMP error packets for broadcast packets */
01011                 delivered= 1;
01012         }
01013 
01014         DBLOCK(0x20, printf("udp: got packet from ");
01015                 writeIpAddr(src_addr);
01016                 printf(".%u to ", ntohs(src_port));
01017                 writeIpAddr(dst_addr);
01018                 printf(".%u\n", ntohs(dst_port)));
01019 
01020         no_ipopt_pack= bf_memreq(UDP_IO_HDR_SIZE);
01021         udp_io_hdr= (udp_io_hdr_t *)ptr2acc_data(no_ipopt_pack);
01022         udp_io_hdr->uih_src_addr= src_addr;
01023         udp_io_hdr->uih_dst_addr= dst_addr;
01024         udp_io_hdr->uih_src_port= src_port;
01025         udp_io_hdr->uih_dst_port= dst_port;
01026         data_size = udp_size-UDP_HDR_SIZE;
01027 #if CONF_UDP_IO_NW_BYTE_ORDER
01028         udp_io_hdr->uih_ip_opt_len= HTONS(0);
01029         udp_io_hdr->uih_data_len= htons(data_size);
01030 #else
01031         udp_io_hdr->uih_ip_opt_len= 0;
01032         udp_io_hdr->uih_data_len= data_size;
01033 #endif
01034         no_ipopt_pack->acc_next= bf_cut(udp_acc, UDP_HDR_SIZE, data_size);
01035 
01036         if (ip_hdr_size == IP_MIN_HDR_SIZE)
01037         {
01038                 ipopt_pack= no_ipopt_pack;
01039                 ipopt_pack->acc_linkC++;
01040         }
01041         else
01042         {
01043                 ipopt_pack= bf_memreq(UDP_IO_HDR_SIZE);
01044                 *(udp_io_hdr_t *)ptr2acc_data(ipopt_pack)= *udp_io_hdr;
01045                 udp_io_hdr= (udp_io_hdr_t *)ptr2acc_data(ipopt_pack);
01046                 opt_size = ip_hdr_size-IP_MIN_HDR_SIZE;
01047 #if CONF_UDP_IO_NW_BYTE_ORDER
01048                 udp_io_hdr->uih_ip_opt_len= htons(opt_size);
01049 #else
01050                 udp_io_hdr->uih_ip_opt_len= opt_size;
01051 #endif
01052                 tmp_acc= bf_cut(ip_hdr_acc, (size_t)IP_MIN_HDR_SIZE, opt_size);
01053                 assert(tmp_acc->acc_linkC == 1);
01054                 assert(tmp_acc->acc_next == NULL);
01055                 ipopt_pack->acc_next= tmp_acc;
01056 
01057                 tmp_acc->acc_next= no_ipopt_pack->acc_next;
01058                 if (tmp_acc->acc_next)
01059                         tmp_acc->acc_next->acc_linkC++;
01060         }
01061 
01062         hash= dst_port;
01063         hash ^= (hash >> 8);
01064         hash &= (UDP_PORT_HASH_NR-1);
01065 
01066         for (i= 0; i<2; i++)
01067         {
01068                 share_fd= NULL;
01069 
01070                 udp_fd= (i == 0) ? udp_port->up_port_any :
01071                         udp_port->up_port_hash[hash];
01072                 for (; udp_fd; udp_fd= udp_fd->uf_port_next)
01073                 {
01074                         if (i && udp_fd->uf_udpopt.nwuo_locport != dst_port)
01075                                 continue;
01076                 
01077                         assert(udp_fd->uf_flags & UFF_INUSE);
01078                         assert(udp_fd->uf_flags & UFF_OPTSET);
01079                 
01080                         if (udp_fd->uf_port != udp_port)
01081                                 continue;
01082 
01083                         flags= udp_fd->uf_udpopt.nwuo_flags;
01084                         if (!(flags & dst_type))
01085                                 continue;
01086 
01087                         if ((flags & NWUO_RP_SET) && 
01088                                 udp_fd->uf_udpopt.nwuo_remport != src_port)
01089                         {
01090                                 continue;
01091                         }
01092 
01093                         if ((flags & NWUO_RA_SET) && 
01094                                 udp_fd->uf_udpopt.nwuo_remaddr != src_addr)
01095                         {
01096                                 continue;
01097                         }
01098 
01099                         if (i)
01100                         {
01101                                 /* Packet is considdered to be delivered */
01102                                 delivered= 1;
01103                         }
01104 
01105                         if ((flags & NWUO_ACC_MASK) == NWUO_SHARED &&
01106                                 (!share_fd || !udp_fd->uf_rdbuf_head))
01107                         {
01108                                 share_fd= udp_fd;
01109                                 continue;
01110                         }
01111 
01112                         if (flags & NWUO_EN_IPOPT)
01113                                 pack= ipopt_pack;
01114                         else
01115                                 pack= no_ipopt_pack;
01116 
01117                         pack->acc_linkC++;
01118                         udp_rd_enqueue(udp_fd, pack, exp_tim);
01119                         if (udp_fd->uf_flags & UFF_READ_IP)
01120                                 udp_packet2user(udp_fd);
01121                 }
01122 
01123                 if (share_fd)
01124                 {
01125                         flags= share_fd->uf_udpopt.nwuo_flags;
01126                         if (flags & NWUO_EN_IPOPT)
01127                                 pack= ipopt_pack;
01128                         else
01129                                 pack= no_ipopt_pack;
01130 
01131                         pack->acc_linkC++;
01132                         udp_rd_enqueue(share_fd, pack, exp_tim);
01133                         if (share_fd->uf_flags & UFF_READ_IP)
01134                                 udp_packet2user(share_fd);
01135                 }
01136         }
01137 
01138         if (ipopt_pack)
01139                 bf_afree(ipopt_pack);
01140         if (no_ipopt_pack)
01141                 bf_afree(no_ipopt_pack);
01142 
01143         if (!delivered)
01144         {
01145                 DBLOCK(0x2, printf("udp: could not deliver packet from ");
01146                         writeIpAddr(src_addr);
01147                         printf(".%u to ", ntohs(src_port));
01148                         writeIpAddr(dst_addr);
01149                         printf(".%u\n", ntohs(dst_port)));
01150 
01151                 pack= bf_append(ip_hdr_acc, udp_acc);
01152                 ip_hdr_acc= NULL;
01153                 udp_acc= NULL;
01154                 icmp_snd_unreachable(udp_port->up_ipdev, pack,
01155                         ICMP_PORT_UNRCH);
01156                 return;
01157         }
01158 
01159         assert (ip_hdr_acc);
01160         bf_afree(ip_hdr_acc);
01161         assert (udp_acc);
01162         bf_afree(udp_acc);
01163 }
01164 
01165 PUBLIC void udp_close(fd)
01166 int fd;
01167 {
01168         udp_fd_t *udp_fd;
01169         acc_t *tmp_acc, *next_acc;
01170 
01171         udp_fd= &udp_fd_table[fd];
01172 
01173         assert (udp_fd->uf_flags & UFF_INUSE);
01174 
01175         if (udp_fd->uf_flags & UFF_OPTSET)
01176                 unhash_fd(udp_fd);
01177 
01178         udp_fd->uf_flags= UFF_EMPTY;
01179         tmp_acc= udp_fd->uf_rdbuf_head;
01180         while (tmp_acc)
01181         {
01182                 next_acc= tmp_acc->acc_ext_link;
01183                 bf_afree(tmp_acc);
01184                 tmp_acc= next_acc;
01185         }
01186         udp_fd->uf_rdbuf_head= NULL;
01187 }
01188 
01189 PUBLIC int udp_write(fd, count)
01190 int fd;
01191 size_t count;
01192 {
01193         udp_fd_t *udp_fd;
01194         udp_port_t *udp_port;
01195 
01196         udp_fd= &udp_fd_table[fd];
01197         udp_port= udp_fd->uf_port;
01198 
01199         if (!(udp_fd->uf_flags & UFF_OPTSET))
01200         {
01201                 reply_thr_get (udp_fd, EBADMODE, FALSE);
01202                 return NW_OK;
01203         }
01204 
01205 assert (!(udp_fd->uf_flags & UFF_WRITE_IP));
01206 
01207         udp_fd->uf_wr_count= count;
01208 
01209         udp_fd->uf_flags |= UFF_WRITE_IP;
01210 
01211         restart_write_fd(udp_fd);
01212 
01213         if (udp_fd->uf_flags & UFF_WRITE_IP)
01214         {
01215                 DBLOCK(1, printf("replying NW_SUSPEND\n"));
01216 
01217                 return NW_SUSPEND;
01218         }
01219         else
01220         {
01221                 return NW_OK;
01222         }
01223 }
01224 
01225 PRIVATE void restart_write_fd(udp_fd)
01226 udp_fd_t *udp_fd;
01227 {
01228         udp_port_t *udp_port;
01229         acc_t *pack, *ip_hdr_pack, *udp_hdr_pack, *ip_opt_pack, *user_data;
01230         udp_hdr_t *udp_hdr;
01231         udp_io_hdr_t *udp_io_hdr;
01232         ip_hdr_t *ip_hdr;
01233         size_t ip_opt_size, user_data_size;
01234         unsigned long flags;
01235         u16_t chksum;
01236         u8_t u16[2];
01237         int result;
01238 
01239         udp_port= udp_fd->uf_port;
01240 
01241         if (udp_port->up_flags & UPF_WRITE_IP)
01242         {
01243                 udp_port->up_flags |= UPF_MORE2WRITE;
01244                 return;
01245         }
01246 
01247 assert (udp_fd->uf_flags & UFF_WRITE_IP);
01248         udp_fd->uf_flags &= ~UFF_WRITE_IP;
01249 
01250 assert (!udp_port->up_wr_pack);
01251 
01252         pack= (*udp_fd->uf_get_userdata)(udp_fd->uf_srfd, 0,
01253                 udp_fd->uf_wr_count, FALSE);
01254         if (!pack)
01255         {
01256                 udp_fd->uf_flags &= ~UFF_WRITE_IP;
01257                 reply_thr_get (udp_fd, EFAULT, FALSE);
01258                 return;
01259         }
01260 
01261         flags= udp_fd->uf_udpopt.nwuo_flags;
01262 
01263         ip_hdr_pack= bf_memreq(IP_MIN_HDR_SIZE);
01264         ip_hdr= (ip_hdr_t *)ptr2acc_data(ip_hdr_pack);
01265 
01266         udp_hdr_pack= bf_memreq(UDP_HDR_SIZE);
01267         udp_hdr= (udp_hdr_t *)ptr2acc_data(udp_hdr_pack);
01268 
01269         if (flags & NWUO_RWDATALL)
01270         {
01271                 pack= bf_packIffLess(pack, UDP_IO_HDR_SIZE);
01272                 udp_io_hdr= (udp_io_hdr_t *)ptr2acc_data(pack);
01273 #if CONF_UDP_IO_NW_BYTE_ORDER
01274                 ip_opt_size= ntohs(udp_io_hdr->uih_ip_opt_len);
01275 #else
01276                 ip_opt_size= udp_io_hdr->uih_ip_opt_len;
01277 #endif
01278                 if (UDP_IO_HDR_SIZE+ip_opt_size>udp_fd->uf_wr_count)
01279                 {
01280                         bf_afree(ip_hdr_pack);
01281                         bf_afree(udp_hdr_pack);
01282                         bf_afree(pack);
01283                         reply_thr_get (udp_fd, EINVAL, FALSE);
01284                         return;
01285                 }
01286                 if (ip_opt_size & 3)
01287                 {
01288                         bf_afree(ip_hdr_pack);
01289                         bf_afree(udp_hdr_pack);
01290                         bf_afree(pack);
01291                         reply_thr_get (udp_fd, EFAULT, FALSE);
01292                         return;
01293                 }
01294                 if (ip_opt_size)
01295                         ip_opt_pack= bf_cut(pack, UDP_IO_HDR_SIZE, ip_opt_size);
01296                 else
01297                         ip_opt_pack= 0;
01298                 user_data_size= udp_fd->uf_wr_count-UDP_IO_HDR_SIZE-
01299                         ip_opt_size;
01300                 user_data= bf_cut(pack, UDP_IO_HDR_SIZE+ip_opt_size, 
01301                         user_data_size);
01302                 bf_afree(pack);
01303         }
01304         else
01305         {
01306                 udp_io_hdr= 0;
01307                 ip_opt_size= 0;
01308                 user_data_size= udp_fd->uf_wr_count;
01309                 ip_opt_pack= 0;
01310                 user_data= pack;
01311         }
01312 
01313         ip_hdr->ih_vers_ihl= (IP_MIN_HDR_SIZE+ip_opt_size) >> 2;
01314         ip_hdr->ih_tos= UDP_TOS;
01315         ip_hdr->ih_flags_fragoff= HTONS(UDP_IP_FLAGS);
01316         ip_hdr->ih_ttl= IP_DEF_TTL;
01317         ip_hdr->ih_proto= IPPROTO_UDP;
01318         if (flags & NWUO_RA_SET)
01319         {
01320                 ip_hdr->ih_dst= udp_fd->uf_udpopt.nwuo_remaddr;
01321         }
01322         else
01323         {
01324 assert (udp_io_hdr);
01325                 ip_hdr->ih_dst= udp_io_hdr->uih_dst_addr;
01326         }
01327 
01328         if ((flags & NWUO_LOCPORT_MASK) != NWUO_LP_ANY)
01329                 udp_hdr->uh_src_port= udp_fd->uf_udpopt.nwuo_locport;
01330         else
01331         {
01332 assert (udp_io_hdr);
01333                 udp_hdr->uh_src_port= udp_io_hdr->uih_src_port;
01334         }
01335 
01336         if (flags & NWUO_RP_SET)
01337                 udp_hdr->uh_dst_port= udp_fd->uf_udpopt.nwuo_remport;
01338         else
01339         {
01340 assert (udp_io_hdr);
01341                 udp_hdr->uh_dst_port= udp_io_hdr->uih_dst_port;
01342         }
01343 
01344         udp_hdr->uh_length= htons(UDP_HDR_SIZE+user_data_size);
01345         udp_hdr->uh_chksum= 0;
01346 
01347         udp_hdr_pack->acc_next= user_data;
01348         chksum= pack_oneCsum(udp_hdr_pack);
01349         chksum= oneC_sum(chksum, (u16_t *)&udp_fd->uf_port->up_ipaddr,
01350                 sizeof(ipaddr_t));
01351         chksum= oneC_sum(chksum, (u16_t *)&ip_hdr->ih_dst, sizeof(ipaddr_t));
01352         u16[0]= 0;
01353         u16[1]= IPPROTO_UDP;
01354         chksum= oneC_sum(chksum, (u16_t *)u16, sizeof(u16));
01355         chksum= oneC_sum(chksum, (u16_t *)&udp_hdr->uh_length, sizeof(u16_t));
01356         if (~chksum)
01357                 chksum= ~chksum;
01358         udp_hdr->uh_chksum= chksum;
01359         
01360         if (ip_opt_pack)
01361         {
01362                 ip_opt_pack= bf_packIffLess(ip_opt_pack, ip_opt_size);
01363                 ip_opt_pack->acc_next= udp_hdr_pack;
01364                 udp_hdr_pack= ip_opt_pack;
01365         }
01366         ip_hdr_pack->acc_next= udp_hdr_pack;
01367 
01368 assert (!udp_port->up_wr_pack);
01369 assert (!(udp_port->up_flags & UPF_WRITE_IP));
01370 
01371         udp_port->up_wr_pack= ip_hdr_pack;
01372         udp_port->up_flags |= UPF_WRITE_IP;
01373         result= ip_write(udp_port->up_ipfd, bf_bufsize(ip_hdr_pack));
01374         if (result == NW_SUSPEND)
01375         {
01376                 udp_port->up_flags |= UPF_WRITE_SP;
01377                 udp_fd->uf_flags |= UFF_WRITE_IP;
01378                 udp_port->up_write_fd= udp_fd;
01379         }
01380         else if (result<0)
01381                 reply_thr_get(udp_fd, result, FALSE);
01382         else
01383                 reply_thr_get (udp_fd, udp_fd->uf_wr_count, FALSE);
01384 }
01385 
01386 PRIVATE u16_t pack_oneCsum(pack)
01387 acc_t *pack;
01388 {
01389         u16_t prev;
01390         int odd_byte;
01391         char *data_ptr;
01392         int length;
01393         char byte_buf[2];
01394 
01395         assert (pack);
01396 
01397         prev= 0;
01398 
01399         odd_byte= FALSE;
01400         for (; pack; pack= pack->acc_next)
01401         {
01402                 
01403                 data_ptr= ptr2acc_data(pack);
01404                 length= pack->acc_length;
01405 
01406                 if (!length)
01407                         continue;
01408                 if (odd_byte)
01409                 {
01410                         byte_buf[1]= *data_ptr;
01411                         prev= oneC_sum(prev, (u16_t *)byte_buf, 2);
01412                         data_ptr++;
01413                         length--;
01414                         odd_byte= FALSE;
01415                 }
01416                 if (length & 1)
01417                 {
01418                         odd_byte= TRUE;
01419                         length--;
01420                         byte_buf[0]= data_ptr[length];
01421                 }
01422                 if (!length)
01423                         continue;
01424                 prev= oneC_sum (prev, (u16_t *)data_ptr, length);
01425         }
01426         if (odd_byte)
01427         {
01428                 byte_buf[1]= 0;
01429                 prev= oneC_sum (prev, (u16_t *)byte_buf, 1);
01430         }
01431         return prev;
01432 }
01433 
01434 PRIVATE void udp_restart_write_port(udp_port )
01435 udp_port_t *udp_port;
01436 {
01437         udp_fd_t *udp_fd;
01438         int i;
01439 
01440 assert (!udp_port->up_wr_pack);
01441 assert (!(udp_port->up_flags & (UPF_WRITE_IP|UPF_WRITE_SP)));
01442 
01443         while (udp_port->up_flags & UPF_MORE2WRITE)
01444         {
01445                 udp_port->up_flags &= ~UPF_MORE2WRITE;
01446 
01447                 for (i= 0, udp_fd= udp_port->up_next_fd; i<UDP_FD_NR;
01448                         i++, udp_fd++)
01449                 {
01450                         if (udp_fd == &udp_fd_table[UDP_FD_NR])
01451                                 udp_fd= udp_fd_table;
01452 
01453                         if (!(udp_fd->uf_flags & UFF_INUSE))
01454                                 continue;
01455                         if (!(udp_fd->uf_flags & UFF_WRITE_IP))
01456                                 continue;
01457                         if (udp_fd->uf_port != udp_port)
01458                                 continue;
01459                         restart_write_fd(udp_fd);
01460                         if (udp_port->up_flags & UPF_WRITE_IP)
01461                         {
01462                                 udp_port->up_next_fd= udp_fd+1;
01463                                 udp_port->up_flags |= UPF_MORE2WRITE;
01464                                 return;
01465                         }
01466                 }
01467         }
01468 }
01469 
01470 PUBLIC int udp_cancel(fd, which_operation)
01471 int fd;
01472 int which_operation;
01473 {
01474         udp_fd_t *udp_fd;
01475 
01476         DBLOCK(0x10, printf("udp_cancel(%d, %d)\n", fd, which_operation));
01477 
01478         udp_fd= &udp_fd_table[fd];
01479 
01480         switch (which_operation)
01481         {
01482         case SR_CANCEL_READ:
01483 assert (udp_fd->uf_flags & UFF_READ_IP);
01484                 udp_fd->uf_flags &= ~UFF_READ_IP;
01485                 reply_thr_put(udp_fd, EINTR, FALSE);
01486                 break;
01487         case SR_CANCEL_WRITE:
01488 assert (udp_fd->uf_flags & UFF_WRITE_IP);
01489                 udp_fd->uf_flags &= ~UFF_WRITE_IP;
01490                 if (udp_fd->uf_port->up_write_fd == udp_fd)
01491                         udp_fd->uf_port->up_write_fd= NULL;
01492                 reply_thr_get(udp_fd, EINTR, FALSE);
01493                 break;
01494         case SR_CANCEL_IOCTL:
01495 assert (udp_fd->uf_flags & UFF_IOCTL_IP);
01496                 udp_fd->uf_flags &= ~UFF_IOCTL_IP;
01497                 udp_fd->uf_flags &= ~UFF_PEEK_IP;
01498                 reply_thr_get(udp_fd, EINTR, TRUE);
01499                 break;
01500         default:
01501                 ip_panic(( "got unknown cancel request" ));
01502         }
01503         return NW_OK;
01504 }
01505 
01506 PRIVATE void udp_buffree (priority)
01507 int priority;
01508 {
01509         int i;
01510         udp_fd_t *udp_fd;
01511         acc_t *tmp_acc;
01512 
01513         if (priority ==  UDP_PRI_FDBUFS_EXTRA)
01514         {
01515                 for (i=0, udp_fd= udp_fd_table; i<UDP_FD_NR; i++, udp_fd++)
01516                 {
01517                         while (udp_fd->uf_rdbuf_head &&
01518                                 udp_fd->uf_rdbuf_head->acc_ext_link)
01519                         {
01520                                 tmp_acc= udp_fd->uf_rdbuf_head;
01521                                 udp_fd->uf_rdbuf_head= tmp_acc->acc_ext_link;
01522                                 bf_afree(tmp_acc);
01523                         }
01524                 }
01525         }
01526 
01527         if (priority  == UDP_PRI_FDBUFS)
01528         {
01529                 for (i=0, udp_fd= udp_fd_table; i<UDP_FD_NR; i++, udp_fd++)
01530                 {
01531                         while (udp_fd->uf_rdbuf_head)
01532                         {
01533                                 tmp_acc= udp_fd->uf_rdbuf_head;
01534                                 udp_fd->uf_rdbuf_head= tmp_acc->acc_ext_link;
01535                                 bf_afree(tmp_acc);
01536                         }
01537                 }
01538         }
01539 }
01540 
01541 PRIVATE void udp_rd_enqueue(udp_fd, pack, exp_tim)
01542 udp_fd_t *udp_fd;
01543 acc_t *pack;
01544 clock_t exp_tim;
01545 {
01546         acc_t *tmp_acc;
01547         int result;
01548 
01549         if (pack->acc_linkC != 1)
01550         {
01551                 tmp_acc= bf_dupacc(pack);
01552                 bf_afree(pack);
01553                 pack= tmp_acc;
01554         }
01555         pack->acc_ext_link= NULL;
01556         if (udp_fd->uf_rdbuf_head == NULL)
01557         {
01558                 udp_fd->uf_exp_tim= exp_tim;
01559                 udp_fd->uf_rdbuf_head= pack;
01560         }
01561         else
01562                 udp_fd->uf_rdbuf_tail->acc_ext_link= pack;
01563         udp_fd->uf_rdbuf_tail= pack;
01564 
01565         if (udp_fd->uf_flags & UFF_PEEK_IP)
01566         {
01567                 pack= bf_cut(udp_fd->uf_rdbuf_head, 0,
01568                         sizeof(udp_io_hdr_t));
01569                 result= (*udp_fd->uf_put_userdata)(udp_fd->uf_srfd,
01570                         (size_t)0, pack, TRUE);
01571 
01572                 udp_fd->uf_flags &= ~UFF_IOCTL_IP;
01573                 udp_fd->uf_flags &= ~UFF_PEEK_IP;
01574                 result= (*udp_fd->uf_put_userdata)(udp_fd->uf_srfd,
01575                         result, (acc_t *)0, TRUE);
01576                 assert (result == 0);
01577         }
01578 
01579         if (udp_fd->uf_flags & UFF_SEL_READ)
01580         {
01581                 udp_fd->uf_flags &= ~UFF_SEL_READ;
01582                 if (udp_fd->uf_select_res)
01583                         udp_fd->uf_select_res(udp_fd->uf_srfd, SR_SELECT_READ);
01584                 else
01585                         printf("udp_rd_enqueue: no select_res\n");
01586         }
01587 }
01588 
01589 PRIVATE void hash_fd(udp_fd)
01590 udp_fd_t *udp_fd;
01591 {
01592         udp_port_t *udp_port;
01593         int hash;
01594 
01595         udp_port= udp_fd->uf_port;
01596         if ((udp_fd->uf_udpopt.nwuo_flags & NWUO_LOCPORT_MASK) ==
01597                 NWUO_LP_ANY)
01598         {
01599                 udp_fd->uf_port_next= udp_port->up_port_any;
01600                 udp_port->up_port_any= udp_fd;
01601         }
01602         else
01603         {
01604                 hash= udp_fd->uf_udpopt.nwuo_locport;
01605                 hash ^= (hash >> 8);
01606                 hash &= (UDP_PORT_HASH_NR-1);
01607 
01608                 udp_fd->uf_port_next= udp_port->up_port_hash[hash];
01609                 udp_port->up_port_hash[hash]= udp_fd;
01610         }
01611 }
01612 
01613 PRIVATE void unhash_fd(udp_fd)
01614 udp_fd_t *udp_fd;
01615 {
01616         udp_port_t *udp_port;
01617         udp_fd_t *prev, *curr, **udp_fd_p;
01618         int hash;
01619 
01620         udp_port= udp_fd->uf_port;
01621         if ((udp_fd->uf_udpopt.nwuo_flags & NWUO_LOCPORT_MASK) ==
01622                 NWUO_LP_ANY)
01623         {
01624                 udp_fd_p= &udp_port->up_port_any;
01625         }
01626         else
01627         {
01628                 hash= udp_fd->uf_udpopt.nwuo_locport;
01629                 hash ^= (hash >> 8);
01630                 hash &= (UDP_PORT_HASH_NR-1);
01631 
01632                 udp_fd_p= &udp_port->up_port_hash[hash];
01633         }
01634         for (prev= NULL, curr= *udp_fd_p; curr;
01635                 prev= curr, curr= curr->uf_port_next)
01636         {
01637                 if (curr == udp_fd)
01638                         break;
01639         }
01640         assert(curr);
01641         if (prev)
01642                 prev->uf_port_next= curr->uf_port_next;
01643         else
01644                 *udp_fd_p= curr->uf_port_next;
01645 }
01646 
01647 #ifdef BUF_CONSISTENCY_CHECK
01648 PRIVATE void udp_bufcheck()
01649 {
01650         int i;
01651         udp_port_t *udp_port;
01652         udp_fd_t *udp_fd;
01653         acc_t *tmp_acc;
01654 
01655         for (i= 0, udp_port= udp_port_table; i<udp_conf_nr; i++, udp_port++)
01656         {
01657                 if (udp_port->up_wr_pack)
01658                         bf_check_acc(udp_port->up_wr_pack);
01659         }
01660 
01661         for (i= 0, udp_fd= udp_fd_table; i<UDP_FD_NR; i++, udp_fd++)
01662         {
01663                 for (tmp_acc= udp_fd->uf_rdbuf_head; tmp_acc; 
01664                         tmp_acc= tmp_acc->acc_ext_link)
01665                 {
01666                         bf_check_acc(tmp_acc);
01667                 }
01668         }
01669 }
01670 #endif
01671 
01672 /*
01673  * $PchId: udp.c,v 1.25 2005/06/28 14:14:44 philip Exp $
01674  */

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